Re: [PATCH 7/7] vdpa: Use ring hwaddr at vhost_vdpa_svq_unmap_ring

2022-08-22 Thread Jason Wang



在 2022/8/20 00:53, Eugenio Pérez 写道:

Reduce code duplication.

Signed-off-by: Eugenio Pérez 



Acked-by: Jason Wang 

(In the future, we need to look for other cases where a function may use 
only a partial of DMAMap.)


Thanks



---
  hw/virtio/vhost-vdpa.c | 17 -
  1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
index 07d00f5284..45d6e86b45 100644
--- a/hw/virtio/vhost-vdpa.c
+++ b/hw/virtio/vhost-vdpa.c
@@ -884,10 +884,12 @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev,
  /**
   * Unmap a SVQ area in the device
   */
-static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v,
-  const DMAMap *needle)
+static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, hwaddr addr)
  {
-const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, needle);
+const DMAMap needle = {
+.translated_addr = addr,
+};
+const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, &needle);
  hwaddr size;
  int r;
  
@@ -908,17 +910,14 @@ static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v,

  static void vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev,
 const VhostShadowVirtqueue *svq)
  {
-DMAMap needle = {};
  struct vhost_vdpa *v = dev->opaque;
  struct vhost_vring_addr svq_addr;
  
  vhost_svq_get_vring_addr(svq, &svq_addr);
  
-needle.translated_addr = svq_addr.desc_user_addr;

-vhost_vdpa_svq_unmap_ring(v, &needle);
+vhost_vdpa_svq_unmap_ring(v, svq_addr.desc_user_addr);
  
-needle.translated_addr = svq_addr.used_user_addr;

-vhost_vdpa_svq_unmap_ring(v, &needle);
+vhost_vdpa_svq_unmap_ring(v, svq_addr.used_user_addr);
  }
  
  /**

@@ -996,7 +995,7 @@ static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev,
  ok = vhost_vdpa_svq_map_ring(v, &device_region, errp);
  if (unlikely(!ok)) {
  error_prepend(errp, "Cannot create vq device region: ");
-vhost_vdpa_svq_unmap_ring(v, &driver_region);
+vhost_vdpa_svq_unmap_ring(v, driver_region.translated_addr);
  }
  addr->used_user_addr = device_region.iova;
  





Re: [PATCH v9 11/12] vdpa: Add virtio-net mac address via CVQ at start

2022-08-22 Thread Jason Wang



在 2022/8/20 01:00, Eugenio Pérez 写道:

This is needed so the destination vdpa device see the same state a the
guest set in the source.

Signed-off-by: Eugenio Pérez 



Acked-by: Jason Wang 



---
v9:
* Use guest acked features instead of device's.
* Constify vhost_vdpa and VirtIONet variables.
* Delete unneeded increment of cursor.

v8:
* Delete unneeded copy from device's in buffer.

v6:
* Map and unmap command buffers at the start and end of device usage.

v5:
* Rename s/start/load/
* Use independent NetClientInfo to only add load callback on cvq.
---
  net/vhost-vdpa.c | 40 
  1 file changed, 40 insertions(+)

diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
index ebf76d1034..8fad31a5fd 100644
--- a/net/vhost-vdpa.c
+++ b/net/vhost-vdpa.c
@@ -363,11 +363,51 @@ static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, 
size_t out_len,
  return vhost_svq_poll(svq);
  }
  
+static int vhost_vdpa_net_load(NetClientState *nc)

+{
+VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc);
+const struct vhost_vdpa *v = &s->vhost_vdpa;
+const VirtIONet *n;
+uint64_t features;
+
+assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
+
+if (!v->shadow_vqs_enabled) {
+return 0;
+}
+
+n = VIRTIO_NET(v->dev->vdev);
+features = n->parent_obj.guest_features;
+if (features & BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR)) {
+const struct virtio_net_ctrl_hdr ctrl = {
+.class = VIRTIO_NET_CTRL_MAC,
+.cmd = VIRTIO_NET_CTRL_MAC_ADDR_SET,
+};
+char *cursor = s->cvq_cmd_out_buffer;
+ssize_t dev_written;
+
+memcpy(cursor, &ctrl, sizeof(ctrl));
+cursor += sizeof(ctrl);
+memcpy(cursor, n->mac, sizeof(n->mac));
+
+dev_written = vhost_vdpa_net_cvq_add(s, sizeof(ctrl) + sizeof(n->mac),
+ sizeof(virtio_net_ctrl_ack));
+if (unlikely(dev_written < 0)) {
+return dev_written;
+}
+
+return *((virtio_net_ctrl_ack *)s->cvq_cmd_in_buffer) != VIRTIO_NET_OK;
+}
+
+return 0;
+}
+
  static NetClientInfo net_vhost_vdpa_cvq_info = {
  .type = NET_CLIENT_DRIVER_VHOST_VDPA,
  .size = sizeof(VhostVDPAState),
  .receive = vhost_vdpa_receive,
  .start = vhost_vdpa_net_cvq_start,
+.load = vhost_vdpa_net_load,
  .stop = vhost_vdpa_net_cvq_stop,
  .cleanup = vhost_vdpa_cleanup,
  .has_vnet_hdr = vhost_vdpa_has_vnet_hdr,





Re: [PATCH 4/7] vdpa: Remove SVQ vring from iova_tree at shutdown

2022-08-22 Thread Jason Wang



在 2022/8/20 00:53, Eugenio Pérez 写道:

Although the device will be reset before usage, the right thing to do is
to clean it.

Reported-by: Lei Yang 
Fixes: 34e3c94eda ("vdpa: Add custom IOTLB translations to SVQ")
Signed-off-by: Eugenio Pérez 
---
  hw/virtio/vhost-vdpa.c | 7 ++-
  1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
index 7e28d2f674..943799c17c 100644
--- a/hw/virtio/vhost-vdpa.c
+++ b/hw/virtio/vhost-vdpa.c
@@ -898,7 +898,12 @@ static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v,
  
  size = ROUND_UP(result->size, qemu_real_host_page_size());

  r = vhost_vdpa_dma_unmap(v, result->iova, size);
-return r == 0;
+if (unlikely(r < 0)) {
+return false;



vhost-vdpa_svq_map_ring() will call error_report() here, should we do 
the same?


    if (unlikely(r != 0)) {
    error_setg_errno(errp, -r, "Cannot map region to device");

(Btw the error is not very informative, we should dump the map it self 
at least?)


Thanks



+}
+
+vhost_iova_tree_remove(v->iova_tree, result);
+return 0;
  }
  
  static bool vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev,





Re: [PATCH 6/7] vhost: Always store new kick fd on vhost_svq_set_svq_kick_fd

2022-08-22 Thread Jason Wang



在 2022/8/20 00:53, Eugenio Pérez 写道:

We can unbind twice a file descriptor if we call twice
vhost_svq_set_svq_kick_fd because of this. Since it comes from vhost and
not from SVQ, that file descriptor could be a different thing that
guest's vhost notifier.

Likewise, it can happens the same if a guest start and stop the device
multiple times.

Reported-by: Lei Yang 
Fixes: dff4426fa6 ("vhost: Add Shadow VirtQueue kick forwarding capabilities")
Signed-off-by: Eugenio Pérez 
---



Acked-by: Jason Wang 



  hw/virtio/vhost-shadow-virtqueue.c | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/virtio/vhost-shadow-virtqueue.c 
b/hw/virtio/vhost-shadow-virtqueue.c
index e4956728dd..82a784d250 100644
--- a/hw/virtio/vhost-shadow-virtqueue.c
+++ b/hw/virtio/vhost-shadow-virtqueue.c
@@ -602,13 +602,13 @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, 
int svq_kick_fd)
  event_notifier_set_handler(svq_kick, NULL);
  }
  
+event_notifier_init_fd(svq_kick, svq_kick_fd);

  /*
   * event_notifier_set_handler already checks for guest's notifications if
   * they arrive at the new file descriptor in the switch, so there is no
   * need to explicitly check for them.
   */
  if (poll_start) {
-event_notifier_init_fd(svq_kick, svq_kick_fd);
  event_notifier_set(svq_kick);
  event_notifier_set_handler(svq_kick, 
vhost_handle_guest_kick_notifier);
  }
@@ -655,7 +655,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, 
VirtIODevice *vdev,
   */
  void vhost_svq_stop(VhostShadowVirtqueue *svq)
  {
-event_notifier_set_handler(&svq->svq_kick, NULL);
+vhost_svq_set_svq_kick_fd(svq, VHOST_FILE_UNBIND);
  g_autofree VirtQueueElement *next_avail_elem = NULL;
  
  if (!svq->vq) {





Re: [PATCH 5/7] vdpa: Make SVQ vring unmapping return void

2022-08-22 Thread Jason Wang



在 2022/8/20 00:53, Eugenio Pérez 写道:

Nothing actually reads the return value, but an error in cleaning some
entries could cause device stop to abort, making a restart impossible.
Better ignore explicitely the return value.

Reported-by: Lei Yang 
Fixes: 34e3c94eda ("vdpa: Add custom IOTLB translations to SVQ")
Signed-off-by: Eugenio Pérez 



Acked-by: Jason Wang 



---
  hw/virtio/vhost-vdpa.c | 32 ++--
  1 file changed, 10 insertions(+), 22 deletions(-)

diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
index 943799c17c..07d00f5284 100644
--- a/hw/virtio/vhost-vdpa.c
+++ b/hw/virtio/vhost-vdpa.c
@@ -884,7 +884,7 @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev,
  /**
   * Unmap a SVQ area in the device
   */
-static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v,
+static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v,
const DMAMap *needle)
  {
  const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, needle);
@@ -893,37 +893,32 @@ static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa 
*v,
  
  if (unlikely(!result)) {

  error_report("Unable to find SVQ address to unmap");
-return false;
+return;
  }
  
  size = ROUND_UP(result->size, qemu_real_host_page_size());

  r = vhost_vdpa_dma_unmap(v, result->iova, size);
  if (unlikely(r < 0)) {
-return false;
+return;
  }
  
  vhost_iova_tree_remove(v->iova_tree, result);

-return 0;
  }
  
-static bool vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev,

+static void vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev,
 const VhostShadowVirtqueue *svq)
  {
  DMAMap needle = {};
  struct vhost_vdpa *v = dev->opaque;
  struct vhost_vring_addr svq_addr;
-bool ok;
  
  vhost_svq_get_vring_addr(svq, &svq_addr);
  
  needle.translated_addr = svq_addr.desc_user_addr;

-ok = vhost_vdpa_svq_unmap_ring(v, &needle);
-if (unlikely(!ok)) {
-return false;
-}
+vhost_vdpa_svq_unmap_ring(v, &needle);
  
  needle.translated_addr = svq_addr.used_user_addr;

-return vhost_vdpa_svq_unmap_ring(v, &needle);
+vhost_vdpa_svq_unmap_ring(v, &needle);
  }
  
  /**

@@ -1094,26 +1089,22 @@ err:
  return false;
  }
  
-static bool vhost_vdpa_svqs_stop(struct vhost_dev *dev)

+static void vhost_vdpa_svqs_stop(struct vhost_dev *dev)
  {
  struct vhost_vdpa *v = dev->opaque;
  
  if (!v->shadow_vqs) {

-return true;
+return;
  }
  
  for (unsigned i = 0; i < v->shadow_vqs->len; ++i) {

  VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i);
-bool ok = vhost_vdpa_svq_unmap_rings(dev, svq);
-if (unlikely(!ok)) {
-return false;
-}
+vhost_vdpa_svq_unmap_rings(dev, svq);
  }
  
  if (v->migration_blocker) {

  migrate_del_blocker(v->migration_blocker);
  }
-return true;
  }
  
  static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)

@@ -1130,10 +1121,7 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, 
bool started)
  }
  vhost_vdpa_set_vring_ready(dev);
  } else {
-ok = vhost_vdpa_svqs_stop(dev);
-if (unlikely(!ok)) {
-return -1;
-}
+vhost_vdpa_svqs_stop(dev);
  vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
  }
  





Re: [PATCH 3/7] util: make a copy of iova_tree_remove_parameter

2022-08-22 Thread Jason Wang



在 2022/8/20 00:53, Eugenio Pérez 写道:

It's convenient to call iova_tree_remove from a map returned from
iova_tree_find or iova_tree_find_iova.



The looks like a hint of the defect of current API.



  With the current code this is not
possible, since we will free it, and then we will try to search for it
again.

Fix it making a copy of the argument. Not applying a fixes tag, since
there is no use like that at the moment.

Signed-off-by: Eugenio Pérez 
---
  util/iova-tree.c | 4 +++-
  1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/util/iova-tree.c b/util/iova-tree.c
index fee530a579..713e3edd7b 100644
--- a/util/iova-tree.c
+++ b/util/iova-tree.c
@@ -166,9 +166,11 @@ void iova_tree_foreach(IOVATree *tree, iova_tree_iterator 
iterator)
  
  void iova_tree_remove(IOVATree *tree, const DMAMap *map)

  {
+/* Just in case caller is calling iova_tree_remove from a result of find */
+const DMAMap needle = *map;



Then let's simply make iova_tree_remove() accept const DMAMap instead of 
the pointer to it.




  const DMAMap *overlap;
  
-while ((overlap = iova_tree_find(tree, map))) {

+while ((overlap = iova_tree_find(tree, &needle))) {
  g_tree_remove(tree->tree, overlap);
  }



So we had following in iova_tree_insert():

    /* We don't allow to insert range that overlaps with existings */
    if (iova_tree_find(tree, map)) {
    return IOVA_ERR_OVERLAP;
    }

I wonder how overlap can happen?

Thanks




  }





[PATCH v4 4/4] hw/ssi: ibex_spi: update reg addr

2022-08-22 Thread Wilfred Mallawa
From: Wilfred Mallawa 

Updates the `EVENT_ENABLE` register to offset `0x34` as per
OpenTitan spec [1].

[1] https://docs.opentitan.org/hw/ip/spi_host/doc/#Reg_event_enable

Signed-off-by: Wilfred Mallawa 
Reviewed-by: Alistair Francis 
---
 hw/ssi/ibex_spi_host.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/ssi/ibex_spi_host.c b/hw/ssi/ibex_spi_host.c
index 40d401ad47..0becad34e0 100644
--- a/hw/ssi/ibex_spi_host.c
+++ b/hw/ssi/ibex_spi_host.c
@@ -93,7 +93,7 @@ REG32(ERROR_STATUS, 0x30)
 FIELD(ERROR_STATUS, CMDINVAL, 3, 1)
 FIELD(ERROR_STATUS, CSIDINVAL, 4, 1)
 FIELD(ERROR_STATUS, ACCESSINVAL, 5, 1)
-REG32(EVENT_ENABLE, 0x30)
+REG32(EVENT_ENABLE, 0x34)
 FIELD(EVENT_ENABLE, RXFULL, 0, 1)
 FIELD(EVENT_ENABLE, TXEMPTY, 1, 1)
 FIELD(EVENT_ENABLE, RXWM, 2, 1)
-- 
2.37.2




[PATCH v4 3/4] hw/ssi: ibex_spi: fixup/add rw1c functionality

2022-08-22 Thread Wilfred Mallawa
From: Wilfred Mallawa 

This patch adds the `rw1c` functionality to the respective
registers. The status fields are cleared when the respective
field is set.

Signed-off-by: Wilfred Mallawa 
Reviewed-by: Alistair Francis 
---
 hw/ssi/ibex_spi_host.c | 34 --
 include/hw/ssi/ibex_spi_host.h |  4 ++--
 2 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/hw/ssi/ibex_spi_host.c b/hw/ssi/ibex_spi_host.c
index d52b193a1a..40d401ad47 100644
--- a/hw/ssi/ibex_spi_host.c
+++ b/hw/ssi/ibex_spi_host.c
@@ -352,7 +352,17 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr,
 
 switch (addr) {
 /* Skipping any R/O registers */
-case IBEX_SPI_HOST_INTR_STATE...IBEX_SPI_HOST_INTR_ENABLE:
+case IBEX_SPI_HOST_INTR_STATE:
+/* rw1c status register */
+if (FIELD_EX32(val32, INTR_STATE, ERROR)) {
+data = FIELD_DP32(data, INTR_STATE, ERROR, 0);
+}
+if (FIELD_EX32(val32, INTR_STATE, SPI_EVENT)) {
+data = FIELD_DP32(data, INTR_STATE, SPI_EVENT, 0);
+}
+s->regs[addr] = data;
+break;
+case IBEX_SPI_HOST_INTR_ENABLE:
 s->regs[addr] = val32;
 break;
 case IBEX_SPI_HOST_INTR_TEST:
@@ -495,7 +505,27 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr,
  *  When an error occurs, the corresponding bit must be cleared
  *  here before issuing any further commands
  */
-s->regs[addr] = val32;
+status = s->regs[addr];
+/* rw1c status register */
+if (FIELD_EX32(val32, ERROR_STATUS, CMDBUSY)) {
+status = FIELD_DP32(status, ERROR_STATUS, CMDBUSY, 0);
+}
+if (FIELD_EX32(val32, ERROR_STATUS, OVERFLOW)) {
+status = FIELD_DP32(status, ERROR_STATUS, OVERFLOW, 0);
+}
+if (FIELD_EX32(val32, ERROR_STATUS, UNDERFLOW)) {
+status = FIELD_DP32(status, ERROR_STATUS, UNDERFLOW, 0);
+}
+if (FIELD_EX32(val32, ERROR_STATUS, CMDINVAL)) {
+status = FIELD_DP32(status, ERROR_STATUS, CMDINVAL, 0);
+}
+if (FIELD_EX32(val32, ERROR_STATUS, CSIDINVAL)) {
+status = FIELD_DP32(status, ERROR_STATUS, CSIDINVAL, 0);
+}
+if (FIELD_EX32(val32, ERROR_STATUS, ACCESSINVAL)) {
+status = FIELD_DP32(status, ERROR_STATUS, ACCESSINVAL, 0);
+}
+s->regs[addr] = status;
 break;
 case IBEX_SPI_HOST_EVENT_ENABLE:
 /* Controls which classes of SPI events raise an interrupt. */
diff --git a/include/hw/ssi/ibex_spi_host.h b/include/hw/ssi/ibex_spi_host.h
index 3fedcb6805..1f6d077766 100644
--- a/include/hw/ssi/ibex_spi_host.h
+++ b/include/hw/ssi/ibex_spi_host.h
@@ -40,7 +40,7 @@
 OBJECT_CHECK(IbexSPIHostState, (obj), TYPE_IBEX_SPI_HOST)
 
 /* SPI Registers */
-#define IBEX_SPI_HOST_INTR_STATE (0x00 / 4)  /* rw */
+#define IBEX_SPI_HOST_INTR_STATE (0x00 / 4)  /* rw1c */
 #define IBEX_SPI_HOST_INTR_ENABLE(0x04 / 4)  /* rw */
 #define IBEX_SPI_HOST_INTR_TEST  (0x08 / 4)  /* wo */
 #define IBEX_SPI_HOST_ALERT_TEST (0x0c / 4)  /* wo */
@@ -54,7 +54,7 @@
 #define IBEX_SPI_HOST_TXDATA (0x28 / 4)
 
 #define IBEX_SPI_HOST_ERROR_ENABLE   (0x2c / 4)  /* rw */
-#define IBEX_SPI_HOST_ERROR_STATUS   (0x30 / 4)  /* rw */
+#define IBEX_SPI_HOST_ERROR_STATUS   (0x30 / 4)  /* rw1c */
 #define IBEX_SPI_HOST_EVENT_ENABLE   (0x34 / 4)  /* rw */
 
 /* FIFO Len in Bytes */
-- 
2.37.2




[PATCH v4 1/4] hw/ssi: ibex_spi: fixup typos in ibex_spi_host

2022-08-22 Thread Wilfred Mallawa
From: Wilfred Mallawa 

This patch fixes up minor typos in ibex_spi_host

Signed-off-by: Wilfred Mallawa 
Reviewed-by: Alistair Francis 
Reviewed-by: Andrew Jones 
---
 hw/ssi/ibex_spi_host.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/hw/ssi/ibex_spi_host.c b/hw/ssi/ibex_spi_host.c
index d14580b409..601041d719 100644
--- a/hw/ssi/ibex_spi_host.c
+++ b/hw/ssi/ibex_spi_host.c
@@ -172,7 +172,7 @@ static void ibex_spi_host_irq(IbexSPIHostState *s)
 & R_INTR_STATE_SPI_EVENT_MASK;
 int err_irq = 0, event_irq = 0;
 
-/* Error IRQ enabled and Error IRQ Cleared*/
+/* Error IRQ enabled and Error IRQ Cleared */
 if (error_en && !err_pending) {
 /* Event enabled, Interrupt Test Error */
 if (s->regs[IBEX_SPI_HOST_INTR_TEST] & R_INTR_TEST_ERROR_MASK) {
@@ -434,7 +434,7 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr,
 case IBEX_SPI_HOST_TXDATA:
 /*
  * This is a hardware `feature` where
- * the first word written TXDATA after init is omitted entirely
+ * the first word written to TXDATA after init is omitted entirely
  */
 if (s->init_status) {
 s->init_status = false;
@@ -487,7 +487,7 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr,
 break;
 case IBEX_SPI_HOST_ERROR_STATUS:
 /*
- *  Indicates that any errors that have occurred.
+ *  Indicates any errors that have occurred.
  *  When an error occurs, the corresponding bit must be cleared
  *  here before issuing any further commands
  */
-- 
2.37.2




[PATCH v4 2/4] hw/ssi: ibex_spi: fixup coverity issue

2022-08-22 Thread Wilfred Mallawa
From: Wilfred Mallawa 

This patch addresses the coverity issues specified in [1],
as suggested, `FIELD_DP32()`/`FIELD_EX32()` macros have been
implemented to clean up the code.

[1] https://www.mail-archive.com/qemu-devel@nongnu.org/msg887713.html

Fixes: Coverity CID 1488107

Signed-off-by: Wilfred Mallawa 
Reviewed-by: Alistair Francis 
Reviewed-by: Andrew Jones 
---
 hw/ssi/ibex_spi_host.c | 132 +
 1 file changed, 68 insertions(+), 64 deletions(-)

diff --git a/hw/ssi/ibex_spi_host.c b/hw/ssi/ibex_spi_host.c
index 601041d719..d52b193a1a 100644
--- a/hw/ssi/ibex_spi_host.c
+++ b/hw/ssi/ibex_spi_host.c
@@ -108,18 +108,22 @@ static inline uint8_t div4_round_up(uint8_t dividend)
 
 static void ibex_spi_rxfifo_reset(IbexSPIHostState *s)
 {
+uint32_t data = s->regs[IBEX_SPI_HOST_STATUS];
 /* Empty the RX FIFO and assert RXEMPTY */
 fifo8_reset(&s->rx_fifo);
-s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_RXFULL_MASK;
-s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_RXEMPTY_MASK;
+data = FIELD_DP32(data, STATUS, RXFULL, 0);
+data = FIELD_DP32(data, STATUS, RXEMPTY, 1);
+s->regs[IBEX_SPI_HOST_STATUS] = data;
 }
 
 static void ibex_spi_txfifo_reset(IbexSPIHostState *s)
 {
+uint32_t data = s->regs[IBEX_SPI_HOST_STATUS];
 /* Empty the TX FIFO and assert TXEMPTY */
 fifo8_reset(&s->tx_fifo);
-s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_TXFULL_MASK;
-s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_TXEMPTY_MASK;
+data = FIELD_DP32(data, STATUS, TXFULL, 0);
+data = FIELD_DP32(data, STATUS, TXEMPTY, 1);
+s->regs[IBEX_SPI_HOST_STATUS] = data;
 }
 
 static void ibex_spi_host_reset(DeviceState *dev)
@@ -162,37 +166,38 @@ static void ibex_spi_host_reset(DeviceState *dev)
  */
 static void ibex_spi_host_irq(IbexSPIHostState *s)
 {
-bool error_en = s->regs[IBEX_SPI_HOST_INTR_ENABLE]
-& R_INTR_ENABLE_ERROR_MASK;
-bool event_en = s->regs[IBEX_SPI_HOST_INTR_ENABLE]
-& R_INTR_ENABLE_SPI_EVENT_MASK;
-bool err_pending = s->regs[IBEX_SPI_HOST_INTR_STATE]
-& R_INTR_STATE_ERROR_MASK;
-bool status_pending = s->regs[IBEX_SPI_HOST_INTR_STATE]
-& R_INTR_STATE_SPI_EVENT_MASK;
+uint32_t intr_test_reg = s->regs[IBEX_SPI_HOST_INTR_TEST];
+uint32_t intr_en_reg = s->regs[IBEX_SPI_HOST_INTR_ENABLE];
+uint32_t intr_state_reg = s->regs[IBEX_SPI_HOST_INTR_STATE];
+
+uint32_t err_en_reg = s->regs[IBEX_SPI_HOST_ERROR_ENABLE];
+uint32_t event_en_reg = s->regs[IBEX_SPI_HOST_EVENT_ENABLE];
+uint32_t err_status_reg = s->regs[IBEX_SPI_HOST_ERROR_STATUS];
+uint32_t status_reg = s->regs[IBEX_SPI_HOST_STATUS];
+
+
+bool error_en = FIELD_EX32(intr_en_reg, INTR_ENABLE, ERROR);
+bool event_en = FIELD_EX32(intr_en_reg, INTR_ENABLE, SPI_EVENT);
+bool err_pending = FIELD_EX32(intr_state_reg, INTR_STATE, ERROR);
+bool status_pending = FIELD_EX32(intr_state_reg, INTR_STATE, SPI_EVENT);
+
 int err_irq = 0, event_irq = 0;
 
 /* Error IRQ enabled and Error IRQ Cleared */
 if (error_en && !err_pending) {
 /* Event enabled, Interrupt Test Error */
-if (s->regs[IBEX_SPI_HOST_INTR_TEST] & R_INTR_TEST_ERROR_MASK) {
+if (FIELD_EX32(intr_test_reg, INTR_TEST,  ERROR)) {
 err_irq = 1;
-} else if ((s->regs[IBEX_SPI_HOST_ERROR_ENABLE]
-&  R_ERROR_ENABLE_CMDBUSY_MASK) &&
-s->regs[IBEX_SPI_HOST_ERROR_STATUS]
-& R_ERROR_STATUS_CMDBUSY_MASK) {
+} else if (FIELD_EX32(err_en_reg, ERROR_ENABLE,  CMDBUSY) &&
+   FIELD_EX32(err_status_reg, ERROR_STATUS,  CMDBUSY)) {
 /* Wrote to COMMAND when not READY */
 err_irq = 1;
-} else if ((s->regs[IBEX_SPI_HOST_ERROR_ENABLE]
-&  R_ERROR_ENABLE_CMDINVAL_MASK) &&
-s->regs[IBEX_SPI_HOST_ERROR_STATUS]
-& R_ERROR_STATUS_CMDINVAL_MASK) {
+} else if (FIELD_EX32(err_en_reg, ERROR_ENABLE,  CMDINVAL)  &&
+   FIELD_EX32(err_status_reg, ERROR_STATUS,  CMDINVAL)) {
 /* Invalid command segment */
 err_irq = 1;
-} else if ((s->regs[IBEX_SPI_HOST_ERROR_ENABLE]
-& R_ERROR_ENABLE_CSIDINVAL_MASK) &&
-s->regs[IBEX_SPI_HOST_ERROR_STATUS]
-& R_ERROR_STATUS_CSIDINVAL_MASK) {
+} else if (FIELD_EX32(err_en_reg, ERROR_ENABLE,  CSIDINVAL) &&
+   FIELD_EX32(err_status_reg, ERROR_STATUS,  CSIDINVAL)) {
 /* Invalid value for CSID */
 err_irq = 1;
 }
@@ -204,22 +209,19 @@ static void ibex_spi_host_irq(IbexSPIHostState *s)
 
 /* Event IRQ Enabled and Event IRQ Cleared */
 if (event_en && !status_pending) {
-if (s->regs[IBEX_SPI_HOST_INTR_TEST] & R_INTR_TEST_SPI_EVENT_MASK) {
+if (FIELD_EX32(intr_test_reg, INTR_STATE,  SPI_EVEN

[PATCH v4 0/4] hw/ssi: ibex_spi: cleanup and fixup bugs

2022-08-22 Thread Wilfred Mallawa
From: Wilfred Mallawa 

Patch V4 fixes up:
- Fixup missing register field clearing on tx/rx_fifo_reset() in [2/4]

Testing:
- Tested with Opentitan unit tests for TockOS...[OK]

Wilfred Mallawa (4):
  hw/ssi: ibex_spi: fixup typos in ibex_spi_host
  hw/ssi: ibex_spi: fixup coverity issue
  hw/ssi: ibex_spi: fixup/add rw1c functionality
  hw/ssi: ibex_spi: update reg addr

 hw/ssi/ibex_spi_host.c | 174 -
 include/hw/ssi/ibex_spi_host.h |   4 +-
 2 files changed, 106 insertions(+), 72 deletions(-)

-- 
2.37.2




[PATCH] vhost: reduce the set_mem_table call frenquency

2022-08-22 Thread Li Feng
If the vhost memory layout doesn't change, don't need to call the vhost
backend.
The set_mem_table is time consuming when sending to vhost-user backend.

On aarch64, the edk2 uefi firmware will write the pflash which will
trigger the vhost_commit hundreds of times.

Signed-off-by: Li Feng 
---
 hw/virtio/vhost.c | 14 ++
 include/hw/virtio/vhost.h |  2 ++
 2 files changed, 16 insertions(+)

diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index f758f177bb..848d2f20d6 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -523,6 +523,11 @@ static void vhost_commit(MemoryListener *listener)
 /* Rebuild the regions list from the new sections list */
 regions_size = offsetof(struct vhost_memory, regions) +
dev->n_mem_sections * sizeof dev->mem->regions[0];
+if (dev->mem && dev->started) {
+g_free(dev->old_mem);
+dev->old_mem = dev->mem;
+dev->mem = NULL;
+}
 dev->mem = g_realloc(dev->mem, regions_size);
 dev->mem->nregions = dev->n_mem_sections;
 used_memslots = dev->mem->nregions;
@@ -542,6 +547,12 @@ static void vhost_commit(MemoryListener *listener)
 goto out;
 }
 
+if (dev->old_mem && dev->regions_size == regions_size &&
+memcmp(dev->mem, dev->old_mem, dev->regions_size) == 0) {
+goto out;
+}
+
+dev->regions_size = regions_size;
 for (i = 0; i < dev->mem->nregions; i++) {
 if (vhost_verify_ring_mappings(dev,
(void *)(uintptr_t)dev->mem->regions[i].userspace_addr,
@@ -1445,6 +1456,8 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
 hdev->mem = g_malloc0(offsetof(struct vhost_memory, regions));
 hdev->n_mem_sections = 0;
 hdev->mem_sections = NULL;
+hdev->old_mem = NULL;
+hdev->regions_size = 0;
 hdev->log = NULL;
 hdev->log_size = 0;
 hdev->log_enabled = false;
@@ -1491,6 +1504,7 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
 }
 g_free(hdev->mem);
 g_free(hdev->mem_sections);
+g_free(hdev->old_mem);
 if (hdev->vhost_ops) {
 hdev->vhost_ops->vhost_backend_cleanup(hdev);
 }
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index a346f23d13..b1d7287099 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -73,6 +73,8 @@ struct vhost_dev {
 MemoryListener memory_listener;
 MemoryListener iommu_listener;
 struct vhost_memory *mem;
+struct vhost_memory *old_mem;
+int regions_size;
 int n_mem_sections;
 MemoryRegionSection *mem_sections;
 int n_tmp_sections;
-- 
2.37.2




[PATCH] target/avr: Support probe argument to tlb_fill

2022-08-22 Thread Richard Henderson
While there are no target-specific nonfaulting probes,
generic code may grow some uses at some point.

Note that the attrs argument was incorrect -- it should have
been MEMTXATTRS_UNSPECIFIED. Just use the simpler interface.

Signed-off-by: Richard Henderson 
---
 target/avr/helper.c | 46 -
 1 file changed, 29 insertions(+), 17 deletions(-)

diff --git a/target/avr/helper.c b/target/avr/helper.c
index db76452f9a..82284f8997 100644
--- a/target/avr/helper.c
+++ b/target/avr/helper.c
@@ -102,38 +102,50 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int 
size,
   MMUAccessType access_type, int mmu_idx,
   bool probe, uintptr_t retaddr)
 {
-int prot = 0;
-MemTxAttrs attrs = {};
+int prot, page_size = TARGET_PAGE_SIZE;
 uint32_t paddr;
 
 address &= TARGET_PAGE_MASK;
 
 if (mmu_idx == MMU_CODE_IDX) {
-/* access to code in flash */
+/* Access to code in flash. */
 paddr = OFFSET_CODE + address;
 prot = PAGE_READ | PAGE_EXEC;
-if (paddr + TARGET_PAGE_SIZE > OFFSET_DATA) {
+if (paddr >= OFFSET_DATA) {
+/*
+ * This should not be possible via any architectural operations.
+ * There is certainly not an exception that we can deliver.
+ * Accept probing that might come from generic code.
+ */
+if (probe) {
+return false;
+}
 error_report("execution left flash memory");
 abort();
 }
-} else if (address < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) {
-/*
- * access to CPU registers, exit and rebuilt this TB to use full access
- * incase it touches specially handled registers like SREG or SP
- */
-AVRCPU *cpu = AVR_CPU(cs);
-CPUAVRState *env = &cpu->env;
-env->fullacc = 1;
-cpu_loop_exit_restore(cs, retaddr);
 } else {
-/* access to memory. nothing special */
+/* Access to memory. */
 paddr = OFFSET_DATA + address;
 prot = PAGE_READ | PAGE_WRITE;
+if (address < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) {
+/*
+ * Access to CPU registers, exit and rebuilt this TB to use
+ * full access in case it touches specially handled registers
+ * like SREG or SP.  For probing, set page_size = 1, in order
+ * to force tlb_fill to be called for the next access.
+ */
+if (probe) {
+page_size = 1;
+} else {
+AVRCPU *cpu = AVR_CPU(cs);
+CPUAVRState *env = &cpu->env;
+env->fullacc = 1;
+cpu_loop_exit_restore(cs, retaddr);
+}
+}
 }
 
-tlb_set_page_with_attrs(cs, address, paddr, attrs, prot,
-mmu_idx, TARGET_PAGE_SIZE);
-
+tlb_set_page(cs, address, paddr, prot, mmu_idx, page_size);
 return true;
 }
 
-- 
2.34.1




Re: [PATCH v7 2/8] file-posix: introduce get_sysfs_str_val for device zoned model

2022-08-22 Thread Sam Li
Stefan Hajnoczi  于2022年8月23日周二 07:05写道:
>
> On Tue, Aug 16, 2022 at 02:25:16PM +0800, Sam Li wrote:
> > +static int hdev_get_max_segments(int fd, struct stat *st) {
> > +int ret;
> > +if (S_ISCHR(st->st_mode)) {
> > +if (ioctl(fd, SG_GET_SG_TABLESIZE, &ret) == 0) {
>
> The ioctl must be within #ifdef CONFIG_LINUX since SG_GET_SG_TABLESIZE
> will be undefined on other operating systems and a compiler error will
> be encountered. Maybe keep the #ifdef around the entire body of this
> hdev_get_max_segments().
>
> > +return ret;
> > +}
> > +return -ENOTSUP;
> >  }
> > -g_free(sysfspath);
> > -return ret;
> > -#else
> > -return -ENOTSUP;
> > -#endif
> > +return get_sysfs_long_val(st, "max_segments");
>
> Where is get_sysfs_long_val() defined? Maybe in a later patch? The code
> must compile after each patch. You can test this with "git rebase -i
> origin/master" and then adding "x make" lines after each commit in the
> interactive rebase file. When rebase runs it will execute make after
> each commit and will stop if make fails.

Explained in the next patch. I will make sure the patches compile in future.



Re: [PATCH v7 6/8] config: add check to block layer

2022-08-22 Thread Sam Li
Stefan Hajnoczi  于2022年8月23日周二 08:54写道:
>
> On Tue, Aug 16, 2022 at 02:25:20PM +0800, Sam Li wrote:
> > Putting zoned/non-zoned BlockDrivers on top of each other is not
> > allowed.
> >
> > Signed-off-by: Sam Li 
> > Reviewed-by: Stefan Hajnoczi 
> > ---
> >  block.c  | 14 ++
> >  block/raw-format.c   |  1 +
> >  include/block/block_int-common.h |  5 +
> >  3 files changed, 20 insertions(+)
> >
> > diff --git a/block.c b/block.c
> > index bc85f46eed..affe6c597e 100644
> > --- a/block.c
> > +++ b/block.c
> > @@ -7947,6 +7947,20 @@ void bdrv_add_child(BlockDriverState *parent_bs, 
> > BlockDriverState *child_bs,
> >  return;
> >  }
> >
> > +/*
> > + * Non-zoned block drivers do not follow zoned storage constraints
> > + * (i.e. sequential writes to zones). Refuse mixing zoned and non-zoned
> > + * drivers in a graph.
> > + */
> > +if (!parent_bs->drv->supports_zoned_children &&
> > +child_bs->bl.zoned != BLK_Z_HM) {
>

Should be:
+if (!parent_bs->drv->supports_zoned_children &&
+child_bs->bl.zoned == BLK_Z_HM)

> Is this logical expression correct:
>
>   If the parent does not support zoned children and the child is not
>   zoned, fail with an error.
>
> ?

No. It should be:

If the parent does not support zoned children and the child is zoned,
fail with an error.  It should handle the case where a filter node is
inserted above a raw block driver with a zoned_host_device child.

There are some QEMU command-line constraints for the zoned devices. I
was wondering where to add such support so that it can print an error
message for users:
1. cache.direct= setting
2. mix zoned/non-zoned drivers

>
> > +error_setg(errp, "Cannot add a %s child to a %s parent",
> > +   child_bs->bl.zoned == BLK_Z_HM ? "zoned" : "non-zoned",
> > +   parent_bs->drv->supports_zoned_children ?
> > +   "support zoned children" : "not support zoned 
> > children");
> > +return;
> > +}
> > +
> >  if (!QLIST_EMPTY(&child_bs->parents)) {
> >  error_setg(errp, "The node %s already has a parent",
> > child_bs->node_name);
> > diff --git a/block/raw-format.c b/block/raw-format.c
> > index 6b20bd22ef..9441536819 100644
> > --- a/block/raw-format.c
> > +++ b/block/raw-format.c
> > @@ -614,6 +614,7 @@ static void raw_child_perm(BlockDriverState *bs, 
> > BdrvChild *c,
> >  BlockDriver bdrv_raw = {
> >  .format_name  = "raw",
> >  .instance_size= sizeof(BDRVRawState),
> > +.supports_zoned_children = true,
> >  .bdrv_probe   = &raw_probe,
> >  .bdrv_reopen_prepare  = &raw_reopen_prepare,
> >  .bdrv_reopen_commit   = &raw_reopen_commit,
> > diff --git a/include/block/block_int-common.h 
> > b/include/block/block_int-common.h
> > index de44c7b6f4..4c44592b59 100644
> > --- a/include/block/block_int-common.h
> > +++ b/include/block/block_int-common.h
> > @@ -126,6 +126,11 @@ struct BlockDriver {
> >   */
> >  bool is_format;
> >
> > +/*
> > + * Set to true if the BlockDriver supports zoned children.
> > + */
> > +bool supports_zoned_children;
> > +
> >  /*
> >   * Drivers not implementing bdrv_parse_filename nor bdrv_open should 
> > have
> >   * this field set to true, except ones that are defined only by their
> > --
> > 2.37.1
> >



Re: [PATCH v7 4/8] block: add block layer APIs resembling Linux ZonedBlockDevice ioctls

2022-08-22 Thread Sam Li
Stefan Hajnoczi  于2022年8月23日周二 08:49写道:
>
> On Tue, Aug 16, 2022 at 02:25:18PM +0800, Sam Li wrote:
> > By adding zone management operations in BlockDriver, storage controller
> > emulation can use the new block layer APIs including Report Zone and
> > four zone management operations (open, close, finish, reset).
> >
> > Add zoned storage commands of the device: zone_report(zrp), zone_open(zo),
> > zone_close(zc), zone_reset(zrs), zone_finish(zf).
> >
> > For example, to test zone_report, use following command:
> > $ ./build/qemu-io --image-opts driver=zoned_host_device, 
> > filename=/dev/nullb0
> > -c "zrp offset nr_zones"
> >
> > Signed-off-by: Sam Li 
> > Reviewed-by: Hannes Reinecke 
> > ---
> >  block/block-backend.c |  50 +
> >  block/file-posix.c| 341 +-
> >  block/io.c|  41 
> >  include/block/block-common.h  |   1 -
> >  include/block/block-io.h  |  13 ++
> >  include/block/block_int-common.h  |  22 +-
> >  include/block/raw-aio.h   |   6 +-
> >  include/sysemu/block-backend-io.h |   6 +
> >  meson.build   |   1 +
> >  qapi/block-core.json  |   8 +-
> >  qemu-io-cmds.c| 143 +
> >  11 files changed, 625 insertions(+), 7 deletions(-)
> >
> > diff --git a/block/block-backend.c b/block/block-backend.c
> > index d4a5df2ac2..fc639b0cd7 100644
> > --- a/block/block-backend.c
> > +++ b/block/block-backend.c
> > @@ -1775,6 +1775,56 @@ int coroutine_fn blk_co_flush(BlockBackend *blk)
> >  return ret;
> >  }
> >
> > +/*
> > + * Send a zone_report command.
> > + * offset is a byte offset from the start of the device. No alignment
> > + * required for offset.
> > + * nr_zones represents IN maximum and OUT actual.
> > + */
> > +int coroutine_fn blk_co_zone_report(BlockBackend *blk, int64_t offset,
> > +unsigned int *nr_zones,
> > +BlockZoneDescriptor *zones)
> > +{
> > +int ret;
> > +IO_CODE();
> > +
> > +blk_inc_in_flight(blk); /* increase before waiting */
> > +blk_wait_while_drained(blk);
> > +if (!blk_is_available(blk)) {
> > +blk_dec_in_flight(blk);
> > +return -ENOMEDIUM;
> > +}
> > +ret = bdrv_co_zone_report(blk_bs(blk), offset, nr_zones, zones);
> > +blk_dec_in_flight(blk);
> > +return ret;
> > +}
> > +
> > +/*
> > + * Send a zone_management command.
> > + * offset is the starting zone specified as a sector offset.
> > + * len is the maximum number of sectors the command should operate on.
> > + */
> > +int coroutine_fn blk_co_zone_mgmt(BlockBackend *blk, BlockZoneOp op,
> > +int64_t offset, int64_t len)
> > +{
> > +int ret;
> > +IO_CODE();
> > +
> > +ret = blk_check_byte_request(blk, offset, len);
> > +if (ret < 0) {
> > +return ret;
> > +}
>
> blk_check_byte_request() calls blk_is_available() and returns -ENOMEDIUM
> when it fails. You can therefore move this down and replace "if
> (!blk_is_available(blk)) {".
>
> > +blk_inc_in_flight(blk);
> > +blk_wait_while_drained(blk);
> > +if (!blk_is_available(blk)) {
> > +blk_dec_in_flight(blk);
> > +return -ENOMEDIUM;
> > +}
> > +ret = bdrv_co_zone_mgmt(blk_bs(blk), op, offset, len);
> > +blk_dec_in_flight(blk);
> > +return ret;
> > +}
> > +
> >  void blk_drain(BlockBackend *blk)
> >  {
> >  BlockDriverState *bs = blk_bs(blk);
> > diff --git a/block/file-posix.c b/block/file-posix.c
> > index 727389488c..29f67082d9 100644
> > --- a/block/file-posix.c
> > +++ b/block/file-posix.c
> > @@ -67,6 +67,9 @@
> >  #include 
> >  #include 
> >  #include 
> > +#if defined(CONFIG_BLKZONED)
> > +#include 
> > +#endif
> >  #include 
> >  #include 
> >  #include 
> > @@ -216,6 +219,13 @@ typedef struct RawPosixAIOData {
> >  PreallocMode prealloc;
> >  Error **errp;
> >  } truncate;
> > +struct {
> > +unsigned int *nr_zones;
> > +BlockZoneDescriptor *zones;
> > +} zone_report;
> > +struct {
> > +unsigned long ioctl_op;
> > +} zone_mgmt;
> >  };
> >  } RawPosixAIOData;
> >
> > @@ -1328,7 +1338,7 @@ static void raw_refresh_limits(BlockDriverState *bs, 
> > Error **errp)
> >  #endif
> >
> >  if (bs->sg || S_ISBLK(st.st_mode)) {
> > -int ret = hdev_get_max_hw_transfer(s->fd, &st);
> > +ret = hdev_get_max_hw_transfer(s->fd, &st);
> >
> >  if (ret > 0 && ret <= BDRV_REQUEST_MAX_BYTES) {
> >  bs->bl.max_hw_transfer = ret;
> > @@ -1340,11 +1350,32 @@ static void raw_refresh_limits(BlockDriverState 
> > *bs, Error **errp)
> >  }
> >  }
> >
> > -ret = get_sysfs_zoned_model(s->fd, &st, &zoned);
> > +ret = get_sysfs_zoned_model(&st, &zoned);
> >  if (ret < 0) {
> >  zoned = BLK_Z_NONE;
> >  }
> >  bs->bl.zoned = zoned;
> > +   

Re: [RFC 5/8] vdpa: Add vdpa memory listener

2022-08-22 Thread Jason Wang
On Fri, Aug 19, 2022 at 6:35 PM Eugenio Perez Martin
 wrote:
>
> On Fri, Aug 19, 2022 at 11:01 AM Jason Wang  wrote:
> >
> > On Fri, Aug 19, 2022 at 4:30 PM Eugenio Perez Martin
> >  wrote:
> > >
> > > On Fri, Aug 19, 2022 at 8:29 AM Jason Wang  wrote:
> > > >
> > > > On Thu, Aug 11, 2022 at 2:42 AM Eugenio Pérez  
> > > > wrote:
> > > > >
> > > > > This enable net/vdpa to restart the full device when a migration is
> > > > > started or stopped.
> > > > >
> > > > > Signed-off-by: Eugenio Pérez 
> > > >
> > > > I have the following questions
> > > >
> > > > 1) any reason that we need to make this net specific? The dirty page
> > > > tracking via shadow virtqueue is pretty general. And the net specific
> > > > part was done via NetClientInfo anyhow.
> > >
> > > The listener is only used to know when migration is started / stopped,
> > > no need for actual memory tracking. Maybe there is a better way to do
> > > so?
> >
> > Not sure, SaveVMHandlers?
> >
>
> I'm fine with investigating this, but the only entry in the doc says
> it's the "legacy way". I assume the "modern way" is through
> VMStateDescription, which is in virtio-net.

Right.

>
> The "pre_save" member already assumes the vhost backend is stopped, so
> I'm not sure if this way is valid.

I wonder if we can

1) new VhostOps
2) call that ops in vhost_log_gloabal_start/stop?

Thanks




RE: [PATCH V5] net/colo.c: Fix the pointer issue reported by Coverity.

2022-08-22 Thread Zhang, Chen


> -Original Message-
> From: Jason Wang 
> Sent: Tuesday, August 23, 2022 10:03 AM
> To: Zhang, Chen 
> Cc: Peter Maydell ; Li Zhijian
> ; qemu-dev 
> Subject: Re: [PATCH V5] net/colo.c: Fix the pointer issue reported by 
> Coverity.
> 
> On Mon, Aug 22, 2022 at 4:29 PM Zhang Chen  wrote:
> >
> > When enabled the virtio-net-pci, guest network packet will load the
> > vnet_hdr. In COLO status, the primary VM's network packet maybe
> > redirect to another VM, it needs filter-redirect enable the vnet_hdr
> > flag at the same time, COLO-proxy will correctly parse the original
> > network packet. If have any misconfiguration here, the vnet_hdr_len is
> > wrong for parse the packet, the data+offset will point to wrong place.
> >
> > Signed-off-by: Zhang Chen 
> 
> Not sure it's worth 7.1. So I queued this for 7.2.

It's fine for me.

Thanks
Chen

> 
> Thanks
> 
> > ---
> >  net/colo.c   | 25 -
> >  net/colo.h   |  1 +
> >  net/trace-events |  2 +-
> >  3 files changed, 18 insertions(+), 10 deletions(-)
> >
> > diff --git a/net/colo.c b/net/colo.c
> > index 6b0ff562ad..fb2c36a026 100644
> > --- a/net/colo.c
> > +++ b/net/colo.c
> > @@ -44,21 +44,28 @@ int parse_packet_early(Packet *pkt)  {
> >  int network_length;
> >  static const uint8_t vlan[] = {0x81, 0x00};
> > -uint8_t *data = pkt->data + pkt->vnet_hdr_len;
> > +uint8_t *data = pkt->data;
> >  uint16_t l3_proto;
> >  ssize_t l2hdr_len;
> >
> > -if (data == NULL) {
> > -trace_colo_proxy_main_vnet_info("This packet is not parsed 
> > correctly, "
> > -"pkt->vnet_hdr_len", 
> > pkt->vnet_hdr_len);
> > +assert(data);
> > +
> > +/* Check the received vnet_hdr_len then add the offset */
> > +if ((pkt->vnet_hdr_len > sizeof(struct virtio_net_hdr_v1_hash)) ||
> > +(pkt->size < sizeof(struct eth_header) + sizeof(struct 
> > vlan_header) +
> > +pkt->vnet_hdr_len)) {
> > +/*
> > + * The received remote packet maybe misconfiguration here,
> > + * Please enable/disable filter module's the vnet_hdr flag at
> > + * the same time.
> > + */
> > +trace_colo_proxy_main_vnet_info("This received packet load wrong ",
> > +pkt->vnet_hdr_len,
> > + pkt->size);
> >  return 1;
> >  }
> > -l2hdr_len = eth_get_l2_hdr_length(data);
> > +data += pkt->vnet_hdr_len;
> >
> > -if (pkt->size < ETH_HLEN + pkt->vnet_hdr_len) {
> > -trace_colo_proxy_main("pkt->size < ETH_HLEN");
> > -return 1;
> > -}
> > +l2hdr_len = eth_get_l2_hdr_length(data);
> >
> >  /*
> >   * TODO: support vlan.
> > diff --git a/net/colo.h b/net/colo.h
> > index 8b3e8d5a83..22fc3031f7 100644
> > --- a/net/colo.h
> > +++ b/net/colo.h
> > @@ -18,6 +18,7 @@
> >  #include "qemu/jhash.h"
> >  #include "qemu/timer.h"
> >  #include "net/eth.h"
> > +#include "standard-headers/linux/virtio_net.h"
> >
> >  #define HASHTABLE_MAX_SIZE 16384
> >
> > diff --git a/net/trace-events b/net/trace-events index
> > 6af927b4b9..823a071bdc 100644
> > --- a/net/trace-events
> > +++ b/net/trace-events
> > @@ -9,7 +9,7 @@ vhost_user_event(const char *chr, int event) "chr: %s got
> event: %d"
> >
> >  # colo.c
> >  colo_proxy_main(const char *chr) ": %s"
> > -colo_proxy_main_vnet_info(const char *sta, int size) ": %s = %d"
> > +colo_proxy_main_vnet_info(const char *sta, uint32_t vnet_hdr, int size)
> ": %s pkt->vnet_hdr_len = %u, pkt->size = %d"
> >
> >  # colo-compare.c
> >  colo_compare_main(const char *chr) ": %s"
> > --
> > 2.25.1
> >



Re: [PATCH 00/14] target/i386: Use atomic operations for pte updates

2022-08-22 Thread Richard Henderson

On 8/22/22 16:57, Richard Henderson wrote:

This patch set does two things:

(1) Remove assert(!probe) from the x86 tlb_fill

 It turns out that this is a prerequisite for
 [PATCH v6 00/21] linux-user: Fix siginfo_t contents when jumping
 to non-readable pages

 because of a new use of probe_access(..., nonfault)
 when comparing TBs that cross a page boundary.


Turns out this was a bug in the v6 patch set. We don't require nonfault probes on 
PROT_EXEC at all; v7 will fix this.


But it's still nice that non-faulting probes now work...


r~



Re: [PATCH V5] net/colo.c: Fix the pointer issue reported by Coverity.

2022-08-22 Thread Jason Wang
On Mon, Aug 22, 2022 at 4:29 PM Zhang Chen  wrote:
>
> When enabled the virtio-net-pci, guest network packet will
> load the vnet_hdr. In COLO status, the primary VM's network
> packet maybe redirect to another VM, it needs filter-redirect
> enable the vnet_hdr flag at the same time, COLO-proxy will
> correctly parse the original network packet. If have any
> misconfiguration here, the vnet_hdr_len is wrong for parse
> the packet, the data+offset will point to wrong place.
>
> Signed-off-by: Zhang Chen 

Not sure it's worth 7.1. So I queued this for 7.2.

Thanks

> ---
>  net/colo.c   | 25 -
>  net/colo.h   |  1 +
>  net/trace-events |  2 +-
>  3 files changed, 18 insertions(+), 10 deletions(-)
>
> diff --git a/net/colo.c b/net/colo.c
> index 6b0ff562ad..fb2c36a026 100644
> --- a/net/colo.c
> +++ b/net/colo.c
> @@ -44,21 +44,28 @@ int parse_packet_early(Packet *pkt)
>  {
>  int network_length;
>  static const uint8_t vlan[] = {0x81, 0x00};
> -uint8_t *data = pkt->data + pkt->vnet_hdr_len;
> +uint8_t *data = pkt->data;
>  uint16_t l3_proto;
>  ssize_t l2hdr_len;
>
> -if (data == NULL) {
> -trace_colo_proxy_main_vnet_info("This packet is not parsed 
> correctly, "
> -"pkt->vnet_hdr_len", 
> pkt->vnet_hdr_len);
> +assert(data);
> +
> +/* Check the received vnet_hdr_len then add the offset */
> +if ((pkt->vnet_hdr_len > sizeof(struct virtio_net_hdr_v1_hash)) ||
> +(pkt->size < sizeof(struct eth_header) + sizeof(struct vlan_header) +
> +pkt->vnet_hdr_len)) {
> +/*
> + * The received remote packet maybe misconfiguration here,
> + * Please enable/disable filter module's the vnet_hdr flag at
> + * the same time.
> + */
> +trace_colo_proxy_main_vnet_info("This received packet load wrong ",
> +pkt->vnet_hdr_len, pkt->size);
>  return 1;
>  }
> -l2hdr_len = eth_get_l2_hdr_length(data);
> +data += pkt->vnet_hdr_len;
>
> -if (pkt->size < ETH_HLEN + pkt->vnet_hdr_len) {
> -trace_colo_proxy_main("pkt->size < ETH_HLEN");
> -return 1;
> -}
> +l2hdr_len = eth_get_l2_hdr_length(data);
>
>  /*
>   * TODO: support vlan.
> diff --git a/net/colo.h b/net/colo.h
> index 8b3e8d5a83..22fc3031f7 100644
> --- a/net/colo.h
> +++ b/net/colo.h
> @@ -18,6 +18,7 @@
>  #include "qemu/jhash.h"
>  #include "qemu/timer.h"
>  #include "net/eth.h"
> +#include "standard-headers/linux/virtio_net.h"
>
>  #define HASHTABLE_MAX_SIZE 16384
>
> diff --git a/net/trace-events b/net/trace-events
> index 6af927b4b9..823a071bdc 100644
> --- a/net/trace-events
> +++ b/net/trace-events
> @@ -9,7 +9,7 @@ vhost_user_event(const char *chr, int event) "chr: %s got 
> event: %d"
>
>  # colo.c
>  colo_proxy_main(const char *chr) ": %s"
> -colo_proxy_main_vnet_info(const char *sta, int size) ": %s = %d"
> +colo_proxy_main_vnet_info(const char *sta, uint32_t vnet_hdr, int size) ": 
> %s pkt->vnet_hdr_len = %u, pkt->size = %d"
>
>  # colo-compare.c
>  colo_compare_main(const char *chr) ": %s"
> --
> 2.25.1
>




Re: [PATCH 00/24] Support VIRTIO_F_RING_RESET for virtio-net, vhost-user, vhost-kernel in virtio pci-modern

2022-08-22 Thread Kangjie Xu
Forgot to append changelog for v2 in the cover letter, so I add it in 
this email.



changelog:

1. Add support for vhost-net scenario

2. Add a new vhost-user message VHOST_USER_RESET_VRING

3. Add migration compatibility for virtqueue reset


Looking forward to your review and comments to this patch set, thanks. :)


Best regards,

Kangjie

在 2022/8/16 09:06, Kangjie Xu 写道:

The virtio queue reset function has already been defined in the virtio spec 1.2.
The relevant virtio spec information is here:

 https://github.com/oasis-tcs/virtio-spec/issues/124
 https://github.com/oasis-tcs/virtio-spec/issues/139

This patch set is to support this function in QEMU. It consists of several 
parts:
1. Patches 1-7 are the basic interfaces for vq reset in virtio and virtio-pci.
2. Patches 8-12 support vq stop and vq restart for vhost-kernel.
3. Patches 13-19 support vq stop and vq restart for vhost-user.
4. Patches 20-22 support vq reset and re-enable for virtio-net.
5. Patches 23-24 enable the vq reset feature for vhost-kernel and vhost-user.

The process of virtqueue reset can be concluded as:
1. The virtqueue is disabled when VIRTIO_PCI_COMMON_Q_RESET is written.
2. Then the virtqueue can be optionally restarted(re-enabled).

Since this patch set involves multiple modules and seems a bit messy, we 
briefly describe the
calling process for different modes below.
virtio-net:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
 -> virtio_queue_reset() [virtio]
 -> virtio_net_queue_reset() [virtio-net]
 -> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
 -> set enabled, reset status of vq.

vhost-kernel:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
 -> virtio_queue_reset() [virtio]
 -> virtio_net_queue_reset() [virtio-net]
 -> vhost_net_virtqueue_stop() [vhost-net]
 -> vhost_net_set_backend() [vhost]
 -> vhost_dev_virtqueue_stop()
 -> vhost_virtqueue_unmap()
 -> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
 -> virtio_queue_enable() [virtio]
 -> virtio_net_queue_enable() [virtio-net]
 -> vhost_net_virtqueue_restart() [vhost-net]
 -> vhost_dev_virtqueue_restart() [vhost]
 -> vhost_virtqueue_start()
 -> vhost_net_set_backend()
 -> set enabled, reset status of vq.

vhost-user:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
 -> virtio_queue_reset() [virtio]
 -> virtio_net_queue_reset() [virtio-net]
 -> vhost_net_virtqueue_stop() [vhost-net]
 -> vhost_dev_virtqueue_stop() [vhost]
 -> vhost_user_reset_vring() [vhost-user]
 -> send VHOST_USER_RESET_VRING to the device
 -> vhost_virtqueue_unmap()
 -> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
 -> virtio_queue_enable() [virtio]
 -> virtio_net_queue_enable() [virtio-net]
 -> vhost_net_virtqueue_restart() [vhost-net]
 -> vhost_dev_virtqueue_restart() [vhost]
 -> vhost_virtqueue_start()
 -> vhost_user_set_single_vring_enable [vhost-user]
 -> send VHOST_USER_SET_VRING_ENABLE to the device
 -> set enabled, reset status of vq.


Test environment:
 Host: 5.19.0-rc3 (With vq reset support)
 Qemu: QEMU emulator version 7.0.50
 Guest: 5.19.0-rc3 (With vq reset support)
 DPDK: 22.07-rc1 (With vq reset support)
 Test Cmd: ethtool -g eth1; ethtool -G eth1 rx $1 tx $2; ethtool -g eth1;

 The drvier can resize the virtio queue, then virtio queue reset function 
should
 be triggered.

 The default is split mode, modify Qemu virtio-net to add PACKED feature to
 test packed mode.

Guest Kernel Patch:
 
https://lore.kernel.org/bpf/20220801063902.129329-1-xuanz...@linux.alibaba.com/

DPDK Patch:
 
https://github.com/middaywords/dpdk/compare/72206323a5dd3182b13f61b25a64abdddfee595c...eabadfac7953da66bc10ffb8284b490d09bb7ec7

Host Kernel Patch:
 
https://github.com/middaywords/linux/commit/19a91e0d7167b2031e46078c6215c213b89cb2c3

Looking forward to your review and comments. Thanks.

Kangjie Xu (19):
   virtio: introduce virtio_queue_enable()
   virtio: core: vq reset feature negotation support
   virtio-pci: support queue enable
   vhost: extract the logic of unmapping the vrings and desc
   vhost: introduce vhost_dev_virtqueue_stop()
   vhost: introduce vhost_dev_virtqueue_restart()
   vhost-net: vhost-kernel: introduce vhost_net_virtqueue_stop()
   vhost-net: vhost-kernel: introduce vhost_net_virtqueue_restart()
   docs: vhost-user: add VHOST_USER_RESET_VRING message
   vhost-user: introduce vhost_reset_vring() interface
   vhost-user: add op to enable or disable a single vring
   vhost: vhost-user: update vhost_dev_virtqueue_stop()

Re: [PATCH v7 00/14] KVM: mm: fd-based approach for supporting KVM guest private memory

2022-08-22 Thread Isaku Yamahata
On Wed, Aug 17, 2022 at 10:27:19AM -0500,
Michael Roth  wrote:

> > I think the best approach is to turn KVM_TDX_INIT_MEM_REGION into a generic
> > vCPU-scoped ioctl() that allows userspace to pre-map guest memory.  
> > Supporting
> > initializing guest private memory with a source page can be implemented via 
> > a
> > flag.  That also gives KVM line of sight to in-place "conversion", e.g. 
> > another
> > flag could be added to say that the dest is also the source.
> 
> So is this proposed ioctl only intended to handle the initial encrypted
> payload, and the KVM_MEMORY_ENCRYPT_{REG,UNREG}_REGION ioctls would
> still be used for conversions post-boot?

Yes.  It is called before running any vcpu.  At run time (after running vcpus),
KVM_MEMORY_ENCRYPT_{REG,UNREG}_REGION is used.
-- 
Isaku Yamahata 



Re: [PATCH v7 6/8] config: add check to block layer

2022-08-22 Thread Stefan Hajnoczi
On Tue, Aug 16, 2022 at 02:25:20PM +0800, Sam Li wrote:
> Putting zoned/non-zoned BlockDrivers on top of each other is not
> allowed.
> 
> Signed-off-by: Sam Li 
> Reviewed-by: Stefan Hajnoczi 
> ---
>  block.c  | 14 ++
>  block/raw-format.c   |  1 +
>  include/block/block_int-common.h |  5 +
>  3 files changed, 20 insertions(+)
> 
> diff --git a/block.c b/block.c
> index bc85f46eed..affe6c597e 100644
> --- a/block.c
> +++ b/block.c
> @@ -7947,6 +7947,20 @@ void bdrv_add_child(BlockDriverState *parent_bs, 
> BlockDriverState *child_bs,
>  return;
>  }
>  
> +/*
> + * Non-zoned block drivers do not follow zoned storage constraints
> + * (i.e. sequential writes to zones). Refuse mixing zoned and non-zoned
> + * drivers in a graph.
> + */
> +if (!parent_bs->drv->supports_zoned_children &&
> +child_bs->bl.zoned != BLK_Z_HM) {

Is this logical expression correct:

  If the parent does not support zoned children and the child is not
  zoned, fail with an error.

?

> +error_setg(errp, "Cannot add a %s child to a %s parent",
> +   child_bs->bl.zoned == BLK_Z_HM ? "zoned" : "non-zoned",
> +   parent_bs->drv->supports_zoned_children ?
> +   "support zoned children" : "not support zoned children");
> +return;
> +}
> +
>  if (!QLIST_EMPTY(&child_bs->parents)) {
>  error_setg(errp, "The node %s already has a parent",
> child_bs->node_name);
> diff --git a/block/raw-format.c b/block/raw-format.c
> index 6b20bd22ef..9441536819 100644
> --- a/block/raw-format.c
> +++ b/block/raw-format.c
> @@ -614,6 +614,7 @@ static void raw_child_perm(BlockDriverState *bs, 
> BdrvChild *c,
>  BlockDriver bdrv_raw = {
>  .format_name  = "raw",
>  .instance_size= sizeof(BDRVRawState),
> +.supports_zoned_children = true,
>  .bdrv_probe   = &raw_probe,
>  .bdrv_reopen_prepare  = &raw_reopen_prepare,
>  .bdrv_reopen_commit   = &raw_reopen_commit,
> diff --git a/include/block/block_int-common.h 
> b/include/block/block_int-common.h
> index de44c7b6f4..4c44592b59 100644
> --- a/include/block/block_int-common.h
> +++ b/include/block/block_int-common.h
> @@ -126,6 +126,11 @@ struct BlockDriver {
>   */
>  bool is_format;
>  
> +/*
> + * Set to true if the BlockDriver supports zoned children.
> + */
> +bool supports_zoned_children;
> +
>  /*
>   * Drivers not implementing bdrv_parse_filename nor bdrv_open should have
>   * this field set to true, except ones that are defined only by their
> -- 
> 2.37.1
> 


signature.asc
Description: PGP signature


Re: [PATCH v7 4/8] block: add block layer APIs resembling Linux ZonedBlockDevice ioctls

2022-08-22 Thread Stefan Hajnoczi
On Tue, Aug 16, 2022 at 02:25:18PM +0800, Sam Li wrote:
> By adding zone management operations in BlockDriver, storage controller
> emulation can use the new block layer APIs including Report Zone and
> four zone management operations (open, close, finish, reset).
> 
> Add zoned storage commands of the device: zone_report(zrp), zone_open(zo),
> zone_close(zc), zone_reset(zrs), zone_finish(zf).
> 
> For example, to test zone_report, use following command:
> $ ./build/qemu-io --image-opts driver=zoned_host_device, filename=/dev/nullb0
> -c "zrp offset nr_zones"
> 
> Signed-off-by: Sam Li 
> Reviewed-by: Hannes Reinecke 
> ---
>  block/block-backend.c |  50 +
>  block/file-posix.c| 341 +-
>  block/io.c|  41 
>  include/block/block-common.h  |   1 -
>  include/block/block-io.h  |  13 ++
>  include/block/block_int-common.h  |  22 +-
>  include/block/raw-aio.h   |   6 +-
>  include/sysemu/block-backend-io.h |   6 +
>  meson.build   |   1 +
>  qapi/block-core.json  |   8 +-
>  qemu-io-cmds.c| 143 +
>  11 files changed, 625 insertions(+), 7 deletions(-)
> 
> diff --git a/block/block-backend.c b/block/block-backend.c
> index d4a5df2ac2..fc639b0cd7 100644
> --- a/block/block-backend.c
> +++ b/block/block-backend.c
> @@ -1775,6 +1775,56 @@ int coroutine_fn blk_co_flush(BlockBackend *blk)
>  return ret;
>  }
>  
> +/*
> + * Send a zone_report command.
> + * offset is a byte offset from the start of the device. No alignment
> + * required for offset.
> + * nr_zones represents IN maximum and OUT actual.
> + */
> +int coroutine_fn blk_co_zone_report(BlockBackend *blk, int64_t offset,
> +unsigned int *nr_zones,
> +BlockZoneDescriptor *zones)
> +{
> +int ret;
> +IO_CODE();
> +
> +blk_inc_in_flight(blk); /* increase before waiting */
> +blk_wait_while_drained(blk);
> +if (!blk_is_available(blk)) {
> +blk_dec_in_flight(blk);
> +return -ENOMEDIUM;
> +}
> +ret = bdrv_co_zone_report(blk_bs(blk), offset, nr_zones, zones);
> +blk_dec_in_flight(blk);
> +return ret;
> +}
> +
> +/*
> + * Send a zone_management command.
> + * offset is the starting zone specified as a sector offset.
> + * len is the maximum number of sectors the command should operate on.
> + */
> +int coroutine_fn blk_co_zone_mgmt(BlockBackend *blk, BlockZoneOp op,
> +int64_t offset, int64_t len)
> +{
> +int ret;
> +IO_CODE();
> +
> +ret = blk_check_byte_request(blk, offset, len);
> +if (ret < 0) {
> +return ret;
> +}

blk_check_byte_request() calls blk_is_available() and returns -ENOMEDIUM
when it fails. You can therefore move this down and replace "if
(!blk_is_available(blk)) {".

> +blk_inc_in_flight(blk);
> +blk_wait_while_drained(blk);
> +if (!blk_is_available(blk)) {
> +blk_dec_in_flight(blk);
> +return -ENOMEDIUM;
> +}
> +ret = bdrv_co_zone_mgmt(blk_bs(blk), op, offset, len);
> +blk_dec_in_flight(blk);
> +return ret;
> +}
> +
>  void blk_drain(BlockBackend *blk)
>  {
>  BlockDriverState *bs = blk_bs(blk);
> diff --git a/block/file-posix.c b/block/file-posix.c
> index 727389488c..29f67082d9 100644
> --- a/block/file-posix.c
> +++ b/block/file-posix.c
> @@ -67,6 +67,9 @@
>  #include 
>  #include 
>  #include 
> +#if defined(CONFIG_BLKZONED)
> +#include 
> +#endif
>  #include 
>  #include 
>  #include 
> @@ -216,6 +219,13 @@ typedef struct RawPosixAIOData {
>  PreallocMode prealloc;
>  Error **errp;
>  } truncate;
> +struct {
> +unsigned int *nr_zones;
> +BlockZoneDescriptor *zones;
> +} zone_report;
> +struct {
> +unsigned long ioctl_op;
> +} zone_mgmt;
>  };
>  } RawPosixAIOData;
>  
> @@ -1328,7 +1338,7 @@ static void raw_refresh_limits(BlockDriverState *bs, 
> Error **errp)
>  #endif
>  
>  if (bs->sg || S_ISBLK(st.st_mode)) {
> -int ret = hdev_get_max_hw_transfer(s->fd, &st);
> +ret = hdev_get_max_hw_transfer(s->fd, &st);
>  
>  if (ret > 0 && ret <= BDRV_REQUEST_MAX_BYTES) {
>  bs->bl.max_hw_transfer = ret;
> @@ -1340,11 +1350,32 @@ static void raw_refresh_limits(BlockDriverState *bs, 
> Error **errp)
>  }
>  }
>  
> -ret = get_sysfs_zoned_model(s->fd, &st, &zoned);
> +ret = get_sysfs_zoned_model(&st, &zoned);
>  if (ret < 0) {
>  zoned = BLK_Z_NONE;
>  }
>  bs->bl.zoned = zoned;
> +if (zoned != BLK_Z_NONE) {
> +ret = get_sysfs_long_val(&st, "chunk_sectors");
> +if (ret > 0) {
> +bs->bl.zone_sectors = ret;
> +}
> +
> +ret = get_sysfs_long_val(&st, "zone_append_max_bytes");
> +if (ret > 0) {
> +bs->bl.zone_append_max_bytes = ret;
> +

Re: [PATCH 7/9] hw/isa/vt82c686: QOM'ify ac97 and mc97 creation

2022-08-22 Thread BALATON Zoltan

On Tue, 23 Aug 2022, Bernhard Beschow wrote:

Resolves duplicate code in the boards.

Signed-off-by: Bernhard Beschow 
---
hw/isa/vt82c686.c   | 16 
hw/mips/fuloong2e.c |  4 
hw/ppc/pegasos2.c   |  4 
3 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index b964d1a760..47f2fd2669 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -549,6 +549,8 @@ struct ViaISAState {
PCIIDEState ide;
UHCIState uhci[2];
ViaPMState pm;
+PCIDevice ac97;
+PCIDevice mc97;
};

static const VMStateDescription vmstate_via = {
@@ -568,6 +570,8 @@ static void via_isa_init(Object *obj)
object_initialize_child(obj, "ide", &s->ide, "via-ide");
object_initialize_child(obj, "uhci1", &s->uhci[0], "vt82c686b-usb-uhci");
object_initialize_child(obj, "uhci2", &s->uhci[1], "vt82c686b-usb-uhci");
+object_initialize_child(obj, "ac97", &s->ac97, TYPE_VIA_AC97);
+object_initialize_child(obj, "mc97", &s->mc97, TYPE_VIA_MC97);
}

static const TypeInfo via_isa_info = {
@@ -644,6 +648,18 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
if (!qdev_realize(DEVICE(&s->pm), BUS(pci_bus), errp)) {
return;
}
+
+/* Function 5: AC97 Audio */
+qdev_prop_set_int32(DEVICE(&s->ac97), "addr", d->devfn + 5);
+if (!qdev_realize(DEVICE(&s->ac97), BUS(pci_bus), errp)) {
+return;
+}
+
+/* Function 6: AC97 Modem */
+qdev_prop_set_int32(DEVICE(&s->mc97), "addr", d->devfn + 6);
+if (!qdev_realize(DEVICE(&s->mc97), BUS(pci_bus), errp)) {
+return;
+}
}

/* TYPE_VT82C686B_ISA */
diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c
index f05474348f..ea1aef3049 100644
--- a/hw/mips/fuloong2e.c
+++ b/hw/mips/fuloong2e.c
@@ -207,10 +207,6 @@ static void vt82c686b_southbridge_init(PCIBus *pci_bus, 
int slot, qemu_irq intc,

dev = PCI_DEVICE(object_resolve_path_component(OBJECT(dev), "pm"));
*i2c_bus = I2C_BUS(qdev_get_child_bus(DEVICE(dev), "i2c"));
-
-/* Audio support */
-pci_create_simple(pci_bus, PCI_DEVFN(slot, 5), TYPE_VIA_AC97);
-pci_create_simple(pci_bus, PCI_DEVFN(slot, 6), TYPE_VIA_MC97);
}

/* Network support */
diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c
index 4e29e42fba..89ef4aed8b 100644
--- a/hw/ppc/pegasos2.c
+++ b/hw/ppc/pegasos2.c
@@ -171,10 +171,6 @@ static void pegasos2_init(MachineState *machine)
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);
-


This removes the last function created here so the comment above saying:
/* VT8231 function 0: PCI-to-ISA Bridge */
is now stale and may be removed as well.

Regards,
BALATON Zoltan


/* other PC hardware */
pci_vga_init(pci_bus);






Re: [PATCH v13 3/6] target/riscv: Add few cache related PMU events

2022-08-22 Thread Alistair Francis
On Wed, Aug 17, 2022 at 9:24 AM Atish Patra  wrote:
>
> From: Atish Patra 
>
> Qemu can monitor the following cache related PMU events through
> tlb_fill functions.
>
> 1. DTLB load/store miss
> 3. ITLB prefetch miss
>
> Increment the PMU counter in tlb_fill function.
>
> Reviewed-by: Alistair Francis 
> Tested-by: Heiko Stuebner 
> Signed-off-by: Atish Patra 
> Signed-off-by: Atish Patra 

This patch causes a number of test failures.

On some boots I see lots of these errors printed:

qemu-system-riscv64: GLib: g_hash_table_lookup: assertion 'hash_table
!= NULL' failed

and I'm unable to boot Linux.

The command line is:

qemu-system-riscv64 \
-machine sifive_u \
-serial mon:stdio -serial null -nographic \
-append "root=/dev/ram rw highres=off console=ttySIF0 ip=dhcp
earlycon=sbi" \
-smp 5 \
-d guest_errors \
-kernel ./images/qemuriscv64/Image \
-initrd ./images/qemuriscv64/buildroot/rootfs.cpio \
-bios default -m 256M

I see that faiulre with the 5.19-rc7 kernel and OpenSBI 1.1.

I also see the same messages on other machines when running baremetal
code. I'm going to drop these patches from my tree

Alistair

> ---
>  target/riscv/cpu_helper.c | 25 +
>  1 file changed, 25 insertions(+)
>
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 1e4faa84e839..81948b37dd9a 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -21,11 +21,13 @@
>  #include "qemu/log.h"
>  #include "qemu/main-loop.h"
>  #include "cpu.h"
> +#include "pmu.h"
>  #include "exec/exec-all.h"
>  #include "instmap.h"
>  #include "tcg/tcg-op.h"
>  #include "trace.h"
>  #include "semihosting/common-semi.h"
> +#include "cpu_bits.h"
>
>  int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
>  {
> @@ -1188,6 +1190,28 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr 
> addr,
>  cpu_loop_exit_restore(cs, retaddr);
>  }
>
> +
> +static void pmu_tlb_fill_incr_ctr(RISCVCPU *cpu, MMUAccessType access_type)
> +{
> +enum riscv_pmu_event_idx pmu_event_type;
> +
> +switch (access_type) {
> +case MMU_INST_FETCH:
> +pmu_event_type = RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS;
> +break;
> +case MMU_DATA_LOAD:
> +pmu_event_type = RISCV_PMU_EVENT_CACHE_DTLB_READ_MISS;
> +break;
> +case MMU_DATA_STORE:
> +pmu_event_type = RISCV_PMU_EVENT_CACHE_DTLB_WRITE_MISS;
> +break;
> +default:
> +return;
> +}
> +
> +riscv_pmu_incr_ctr(cpu, pmu_event_type);
> +}
> +
>  bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>  MMUAccessType access_type, int mmu_idx,
>  bool probe, uintptr_t retaddr)
> @@ -1286,6 +1310,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, 
> int size,
>  }
>  }
>  } else {
> +pmu_tlb_fill_incr_ctr(cpu, access_type);
>  /* Single stage lookup */
>  ret = get_physical_address(env, &pa, &prot, address, NULL,
> access_type, mmu_idx, true, false, false);
> --
> 2.25.1
>
>



Re: [PATCH 1/9] hw/isa/vt82c686: QOM'ify Super I/O creation

2022-08-22 Thread BALATON Zoltan

On Tue, 23 Aug 2022, Bernhard Beschow wrote:

The object creation now happens in chip-specific init methods which
allows the realize methods to be consolidated into one method. Shifting
the logic into the init methods has the addidional advantage that the
parent object's init methods are called implicitly.


This and later patches titled "QOM'ify" don't do what I understand on 
QOMifying which is turining an old device model into a QOM object. These 
devices are already QOMified, what's really done here is that they are 
moved to the ViaISAState or embedded into it and created as part of the 
south bridge rather then individually by the boards. Either my 
understanding of what QOMify means is wrong or these patches are misnamed.


Technically via_isa_realize() is the realize method of the abstract 
TYPE_VIA_ISA class which were overriden by the subclasses but since QOM 
does not call overridden methods implicitly this had to be explicitly 
called in the overriding realize methods of the subclasses. Now that we 
don't have to ovverride the method maybe it could be set once on the 
VIA_ISA class then it may work that way but as it's done here is also OK 
maybe as a reminder that this super class method should be called by any 
overriding method if one's added in the future for some reason.


Regards,
BALATON Zoltan


Signed-off-by: Bernhard Beschow 
---
hw/isa/vt82c686.c | 33 ++---
1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index 8f656251b8..0217c98fe4 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -544,7 +544,7 @@ struct ViaISAState {
qemu_irq cpu_intr;
qemu_irq *isa_irqs;
ISABus *isa_bus;
-ViaSuperIOState *via_sio;
+ViaSuperIOState via_sio;
};

static const VMStateDescription vmstate_via = {
@@ -602,6 +602,11 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
d->wmask[i] = 0;
}
}
+
+/* Super I/O */
+if (!qdev_realize(DEVICE(&s->via_sio), BUS(s->isa_bus), errp)) {
+return;
+}
}

/* TYPE_VT82C686B_ISA */
@@ -615,7 +620,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 */
-via_superio_io_enable(s->via_sio, val & BIT(1));
+via_superio_io_enable(&s->via_sio, val & BIT(1));
}
}

@@ -639,13 +644,11 @@ static void vt82c686b_isa_reset(DeviceState *dev)
pci_conf[0x77] = 0x10; /* GPIO Control 1/2/3/4 */
}

-static void vt82c686b_realize(PCIDevice *d, Error **errp)
+static void vt82c686b_init(Object *obj)
{
-ViaISAState *s = VIA_ISA(d);
+ViaISAState *s = VIA_ISA(obj);

-via_isa_realize(d, errp);
-s->via_sio = VIA_SUPERIO(isa_create_simple(s->isa_bus,
-   TYPE_VT82C686B_SUPERIO));
+object_initialize_child(obj, "sio", &s->via_sio, TYPE_VT82C686B_SUPERIO);
}

static void vt82c686b_class_init(ObjectClass *klass, void *data)
@@ -653,7 +656,7 @@ static void vt82c686b_class_init(ObjectClass *klass, void 
*data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);

-k->realize = vt82c686b_realize;
+k->realize = via_isa_realize;
k->config_write = vt82c686b_write_config;
k->vendor_id = PCI_VENDOR_ID_VIA;
k->device_id = PCI_DEVICE_ID_VIA_82C686B_ISA;
@@ -670,6 +673,7 @@ static const TypeInfo vt82c686b_isa_info = {
.name  = TYPE_VT82C686B_ISA,
.parent= TYPE_VIA_ISA,
.instance_size = sizeof(ViaISAState),
+.instance_init = vt82c686b_init,
.class_init= vt82c686b_class_init,
};

@@ -684,7 +688,7 @@ static void vt8231_write_config(PCIDevice *d, uint32_t addr,
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));
+via_superio_io_enable(&s->via_sio, val & BIT(2));
}
}

@@ -703,13 +707,11 @@ static void vt8231_isa_reset(DeviceState *dev)
pci_conf[0x6b] = 0x01; /* Fast IR I/O Base */
}

-static void vt8231_realize(PCIDevice *d, Error **errp)
+static void vt8231_init(Object *obj)
{
-ViaISAState *s = VIA_ISA(d);
+ViaISAState *s = VIA_ISA(obj);

-via_isa_realize(d, errp);
-s->via_sio = VIA_SUPERIO(isa_create_simple(s->isa_bus,
-   TYPE_VT8231_SUPERIO));
+object_initialize_child(obj, "sio", &s->via_sio, TYPE_VT8231_SUPERIO);
}

static void vt8231_class_init(ObjectClass *klass, void *data)
@@ -717,7 +719,7 @@ 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->realize = via_isa_realize;
k->config_write = vt8231_write_config;
k->vendor_id = PCI_VENDOR_ID_VIA;
k->device_i

[PATCH 12/14] target/i386: Use MMU_NESTED_IDX for vmload/vmsave

2022-08-22 Thread Richard Henderson
Use MMU_NESTED_IDX for each memory access, rather than
just a single translation to physical.  Adjust svm_save_seg
and svm_load_seg to pass in mmu_idx.

This removes the last use of get_hphys so remove it.

Signed-off-by: Richard Henderson 
---
 target/i386/cpu.h|   2 -
 target/i386/tcg/sysemu/excp_helper.c |  31 
 target/i386/tcg/sysemu/svm_helper.c  | 231 +++
 3 files changed, 126 insertions(+), 138 deletions(-)

diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 9a40b54ae5..10a5e79774 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2381,8 +2381,6 @@ static inline bool ctl_has_irq(CPUX86State *env)
 return (env->int_ctl & V_IRQ_MASK) && (int_prio >= tpr);
 }
 
-hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type,
-int *prot);
 #if defined(TARGET_X86_64) && \
 defined(CONFIG_USER_ONLY) && \
 defined(CONFIG_LINUX)
diff --git a/target/i386/tcg/sysemu/excp_helper.c 
b/target/i386/tcg/sysemu/excp_helper.c
index f771d25f32..11f64e5965 100644
--- a/target/i386/tcg/sysemu/excp_helper.c
+++ b/target/i386/tcg/sysemu/excp_helper.c
@@ -413,37 +413,6 @@ static G_NORETURN void raise_stage2(CPUX86State *env, 
TranslateFault *err,
 cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, retaddr);
 }
 
-hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type,
- int *prot)
-{
-CPUX86State *env = cs->env_ptr;
-
-if (likely(!(env->hflags2 & HF2_NPT_MASK))) {
-return gphys;
-} else {
-TranslateParams in = {
-.addr = gphys,
-.cr3 = env->nested_cr3,
-.pg_mode = env->nested_pg_mode,
-.mmu_idx = MMU_USER_IDX,
-.access_type = access_type,
-.use_stage2 = false,
-};
-TranslateResult out;
-TranslateFault err;
-
-if (!mmu_translate(env, &in, &out, &err)) {
-err.stage2 = prot ? SVM_NPTEXIT_GPA : SVM_NPTEXIT_GPT;
-raise_stage2(env, &err, env->retaddr);
-}
-
-if (prot) {
-*prot &= out.prot;
-}
-return out.paddr;
-}
-}
-
 static bool get_physical_address(CPUX86State *env, vaddr addr,
  MMUAccessType access_type, int mmu_idx,
  TranslateResult *out, TranslateFault *err)
diff --git a/target/i386/tcg/sysemu/svm_helper.c 
b/target/i386/tcg/sysemu/svm_helper.c
index 85b7741d94..8e88567399 100644
--- a/target/i386/tcg/sysemu/svm_helper.c
+++ b/target/i386/tcg/sysemu/svm_helper.c
@@ -27,19 +27,19 @@
 
 /* Secure Virtual Machine helpers */
 
-static inline void svm_save_seg(CPUX86State *env, hwaddr addr,
-const SegmentCache *sc)
+static void svm_save_seg(CPUX86State *env, int mmu_idx, hwaddr addr,
+ const SegmentCache *sc)
 {
-CPUState *cs = env_cpu(env);
-
-x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, selector),
- sc->selector);
-x86_stq_phys(cs, addr + offsetof(struct vmcb_seg, base),
- sc->base);
-x86_stl_phys(cs, addr + offsetof(struct vmcb_seg, limit),
- sc->limit);
-x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, attrib),
- ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
+cpu_stw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, selector),
+  sc->selector, mmu_idx, 0);
+cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, base),
+  sc->base, mmu_idx, 0);
+cpu_stl_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, limit),
+  sc->limit, mmu_idx, 0);
+cpu_stw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, attrib),
+  ((sc->flags >> 8) & 0xff)
+  | ((sc->flags >> 12) & 0x0f00),
+  mmu_idx, 0);
 }
 
 /*
@@ -52,29 +52,36 @@ static inline void svm_canonicalization(CPUX86State *env, 
target_ulong *seg_base
 *seg_base = long) *seg_base) << shift_amt) >> shift_amt);
 }
 
-static inline void svm_load_seg(CPUX86State *env, hwaddr addr,
-SegmentCache *sc)
+static void svm_load_seg(CPUX86State *env, int mmu_idx, hwaddr addr,
+ SegmentCache *sc)
 {
-CPUState *cs = env_cpu(env);
 unsigned int flags;
 
-sc->selector = x86_lduw_phys(cs,
- addr + offsetof(struct vmcb_seg, selector));
-sc->base = x86_ldq_phys(cs, addr + offsetof(struct vmcb_seg, base));
-sc->limit = x86_ldl_phys(cs, addr + offsetof(struct vmcb_seg, limit));
-flags = x86_lduw_phys(cs, addr + offsetof(struct vmcb_seg, attrib));
+sc->selector =
+cpu_lduw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, selector),
+   mmu_idx, 0);
+sc->base =
+cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, base),
+  mmu_idx, 0);
+sc->limit =
+

Re: [PATCH 8/9] hw/isa/vt82c686: QOM'ify RTC creation

2022-08-22 Thread BALATON Zoltan

On Tue, 23 Aug 2022, Bernhard Beschow wrote:

Signed-off-by: Bernhard Beschow 
---
hw/isa/vt82c686.c | 12 +++-
1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index 47f2fd2669..ee745d5d49 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -546,6 +546,7 @@ struct ViaISAState {
qemu_irq cpu_intr;
qemu_irq *isa_irqs;
ViaSuperIOState via_sio;
+RTCState rtc;
PCIIDEState ide;
UHCIState uhci[2];
ViaPMState pm;
@@ -567,6 +568,7 @@ static void via_isa_init(Object *obj)
{
ViaISAState *s = VIA_ISA(obj);

+object_initialize_child(obj, "rtc", &s->rtc, TYPE_MC146818_RTC);
object_initialize_child(obj, "ide", &s->ide, "via-ide");
object_initialize_child(obj, "uhci1", &s->uhci[0], "vt82c686b-usb-uhci");
object_initialize_child(obj, "uhci2", &s->uhci[1], "vt82c686b-usb-uhci");
@@ -615,7 +617,15 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
isa_bus_irqs(isa_bus, s->isa_irqs);
i8254_pit_init(isa_bus, 0x40, 0, NULL);
i8257_dma_init(isa_bus, 0);
-mc146818_rtc_init(isa_bus, 2000, NULL);
+
+/* RTC */
+qdev_prop_set_int32(DEVICE(&s->rtc), "base_year", 2000);
+if (!qdev_realize(DEVICE(&s->rtc), BUS(isa_bus), errp)) {
+return;
+}
+object_property_add_alias(qdev_get_machine(), "rtc-time", OBJECT(&s->rtc),
+  "date");
+isa_connect_gpio_out(ISA_DEVICE(&s->rtc), 0, s->rtc.isairq);

for (i = 0; i < PCI_CONFIG_HEADER_SIZE; i++) {
if (i < PCI_COMMAND || i >= PCI_REVISION_ID) {



This actually introduces code duplication as all other places except piix4 
seem to still use the init function (probably to ensure that the rtc-rime 
alias on the machine is properly set) so I'd keep this the same as 
everything else and drop this patch until this init function is removed 
from all other places as well.


Regards,
BALATON Zoltan



[PATCH 07/14] target/i386: Use MMUAccessType across excp_helper.c

2022-08-22 Thread Richard Henderson
Replace int is_write1 and magic numbers with the proper
MMUAccessType access_type and enumerators.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/sysemu/excp_helper.c | 28 +++-
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/target/i386/tcg/sysemu/excp_helper.c 
b/target/i386/tcg/sysemu/excp_helper.c
index 48feba7e75..414d8032de 100644
--- a/target/i386/tcg/sysemu/excp_helper.c
+++ b/target/i386/tcg/sysemu/excp_helper.c
@@ -30,8 +30,10 @@ 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, hwaddr addr, MMUTranslateFunc 
get_hphys_func,
- uint64_t cr3, int is_write1, int mmu_idx, int pg_mode,
+static int mmu_translate(CPUState *cs, hwaddr addr,
+ MMUTranslateFunc get_hphys_func,
+ uint64_t cr3, MMUAccessType access_type,
+ int mmu_idx, int pg_mode,
  hwaddr *xlat, int *page_size, int *prot)
 {
 X86CPU *cpu = X86_CPU(cs);
@@ -40,13 +42,13 @@ static int mmu_translate(CPUState *cs, hwaddr addr, 
MMUTranslateFunc get_hphys_f
 int32_t a20_mask;
 target_ulong pde_addr, pte_addr;
 int error_code = 0;
-int is_dirty, is_write, is_user;
+bool is_dirty, is_write, is_user;
 uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits);
 uint32_t page_offset;
 uint32_t pkr;
 
 is_user = (mmu_idx == MMU_USER_IDX);
-is_write = is_write1 & 1;
+is_write = (access_type == MMU_DATA_STORE);
 a20_mask = x86_get_a20_mask(env);
 
 if (!(pg_mode & PG_MODE_NXE)) {
@@ -264,14 +266,14 @@ do_check_protect_pse36:
 }
 
 *prot &= pkr_prot;
-if ((pkr_prot & (1 << is_write1)) == 0) {
-assert(is_write1 != 2);
+if ((pkr_prot & (1 << access_type)) == 0) {
+assert(access_type != MMU_INST_FETCH);
 error_code |= PG_ERROR_PK_MASK;
 goto do_fault_protect;
 }
 }
 
-if ((*prot & (1 << is_write1)) == 0) {
+if ((*prot & (1 << access_type)) == 0) {
 goto do_fault_protect;
 }
 
@@ -297,7 +299,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, access_type, prot);
 return PG_ERROR_OK;
 
  do_fault_rsvd:
@@ -308,7 +310,7 @@ do_check_protect_pse36:
 error_code |= (is_write << PG_ERROR_W_BIT);
 if (is_user)
 error_code |= PG_ERROR_U_MASK;
-if (is_write1 == 2 &&
+if (access_type == MMU_INST_FETCH &&
 ((pg_mode & PG_MODE_NXE) || (pg_mode & PG_MODE_SMEP)))
 error_code |= PG_ERROR_I_D_MASK;
 return error_code;
@@ -353,7 +355,7 @@ hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType 
access_type,
  * 1  = generate PF fault
  */
 static int handle_mmu_fault(CPUState *cs, vaddr addr, int size,
-int is_write1, int mmu_idx)
+MMUAccessType access_type, int mmu_idx)
 {
 X86CPU *cpu = X86_CPU(cs);
 CPUX86State *env = &cpu->env;
@@ -365,7 +367,7 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int 
size,
 
 #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);
+   addr, access_type, mmu_idx, env->eip);
 #endif
 
 if (!(env->cr[0] & CR0_PG_MASK)) {
@@ -393,7 +395,7 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int 
size,
 }
 }
 
-error_code = mmu_translate(cs, addr, get_hphys, env->cr[3], is_write1,
+error_code = mmu_translate(cs, addr, get_hphys, env->cr[3], 
access_type,
mmu_idx, pg_mode,
&paddr, &page_size, &prot);
 }
@@ -404,7 +406,7 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int 
size,
 vaddr = addr & TARGET_PAGE_MASK;
 paddr &= TARGET_PAGE_MASK;
 
-assert(prot & (1 << is_write1));
+assert(prot & (1 << access_type));
 tlb_set_page_with_attrs(cs, vaddr, paddr, cpu_get_mem_attrs(env),
 prot, mmu_idx, page_size);
 return 0;
-- 
2.34.1




[PATCH 08/14] target/i386: Direct call get_hphys from mmu_translate

2022-08-22 Thread Richard Henderson
Use a boolean to control the call to get_hphys instead
of passing a null function pointer.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/sysemu/excp_helper.c | 12 
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/target/i386/tcg/sysemu/excp_helper.c 
b/target/i386/tcg/sysemu/excp_helper.c
index 414d8032de..ea195f7a28 100644
--- a/target/i386/tcg/sysemu/excp_helper.c
+++ b/target/i386/tcg/sysemu/excp_helper.c
@@ -24,14 +24,10 @@
 
 #define PG_ERROR_OK (-1)
 
-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)
+   (use_stage2 ? get_hphys(cs, gpa, access_type, prot) : gpa)
 
-static int mmu_translate(CPUState *cs, hwaddr addr,
- MMUTranslateFunc get_hphys_func,
+static int mmu_translate(CPUState *cs, hwaddr addr, bool use_stage2,
  uint64_t cr3, MMUAccessType access_type,
  int mmu_idx, int pg_mode,
  hwaddr *xlat, int *page_size, int *prot)
@@ -329,7 +325,7 @@ hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType 
access_type,
 return gphys;
 }
 
-exit_info_1 = mmu_translate(cs, gphys, NULL, env->nested_cr3,
+exit_info_1 = mmu_translate(cs, gphys, false, env->nested_cr3,
access_type, MMU_USER_IDX, env->nested_pg_mode,
&hphys, &page_size, &next_prot);
 if (exit_info_1 == PG_ERROR_OK) {
@@ -395,7 +391,7 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int 
size,
 }
 }
 
-error_code = mmu_translate(cs, addr, get_hphys, env->cr[3], 
access_type,
+error_code = mmu_translate(cs, addr, true, env->cr[3], access_type,
mmu_idx, pg_mode,
&paddr, &page_size, &prot);
 }
-- 
2.34.1




[PATCH 06/14] include/exec: Introduce TARGET_PAGE_ENTRY_EXTRA

2022-08-22 Thread Richard Henderson
Allow the target to cache items from the guest page tables.

Signed-off-by: Richard Henderson 
---
 include/exec/cpu-defs.h | 9 +
 1 file changed, 9 insertions(+)

diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
index 5e12cc1854..67239b4e5e 100644
--- a/include/exec/cpu-defs.h
+++ b/include/exec/cpu-defs.h
@@ -163,6 +163,15 @@ typedef struct CPUTLBEntryFull {
 
 /* @lg_page_size contains the log2 of the page size. */
 uint8_t lg_page_size;
+
+/*
+ * Allow target-specific additions to this structure.
+ * This may be used to cache items from the guest cpu
+ * page tables for later use by the implementation.
+ */
+#ifdef TARGET_PAGE_ENTRY_EXTRA
+TARGET_PAGE_ENTRY_EXTRA
+#endif
 } CPUTLBEntryFull;
 
 /*
-- 
2.34.1




[PATCH 13/14] target/i386: Combine 5 sets of variables in mmu_translate

2022-08-22 Thread Richard Henderson
We don't need one variable set per translation level,
which requires copying into pte/pte_addr for huge pages.
Standardize on pte/pte_addr for all levels.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/sysemu/excp_helper.c | 178 ++-
 1 file changed, 91 insertions(+), 87 deletions(-)

diff --git a/target/i386/tcg/sysemu/excp_helper.c 
b/target/i386/tcg/sysemu/excp_helper.c
index 11f64e5965..e5d9ff138e 100644
--- a/target/i386/tcg/sysemu/excp_helper.c
+++ b/target/i386/tcg/sysemu/excp_helper.c
@@ -82,7 +82,7 @@ static bool mmu_translate(CPUX86State *env, const 
TranslateParams *in,
 const bool is_user = (in->mmu_idx == MMU_USER_IDX);
 const MMUAccessType access_type = in->access_type;
 uint64_t ptep, pte;
-hwaddr pde_addr, pte_addr;
+hwaddr pte_addr;
 uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits);
 uint32_t pkr;
 int page_size;
@@ -92,116 +92,122 @@ static bool mmu_translate(CPUX86State *env, const 
TranslateParams *in,
 }
 
 if (pg_mode & PG_MODE_PAE) {
-uint64_t pde, pdpe;
-target_ulong pdpe_addr;
-
 #ifdef TARGET_X86_64
 if (pg_mode & PG_MODE_LMA) {
-bool la57 = pg_mode & PG_MODE_LA57;
-uint64_t pml5e_addr, pml5e;
-uint64_t pml4e_addr, pml4e;
-
-if (la57) {
-pml5e_addr = ((in->cr3 & ~0xfff) +
-(((addr >> 48) & 0x1ff) << 3)) & a20_mask;
-PTE_HPHYS(pml5e_addr);
-pml5e = x86_ldq_phys(cs, pml5e_addr);
-if (!(pml5e & PG_PRESENT_MASK)) {
+if (pg_mode & PG_MODE_LA57) {
+/*
+ * Page table level 5
+ */
+pte_addr = ((in->cr3 & ~0xfff) +
+(((addr >> 48) & 0x1ff) << 3)) & a20_mask;
+PTE_HPHYS(pte_addr);
+pte = x86_ldq_phys(cs, pte_addr);
+if (!(pte & PG_PRESENT_MASK)) {
 goto do_fault;
 }
-if (pml5e & (rsvd_mask | PG_PSE_MASK)) {
+if (pte & (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);
+if (!(pte & PG_ACCESSED_MASK)) {
+pte |= PG_ACCESSED_MASK;
+x86_stl_phys_notdirty(cs, pte_addr, pte);
 }
-ptep = pml5e ^ PG_NX_MASK;
+ptep = pte ^ PG_NX_MASK;
 } else {
-pml5e = in->cr3;
+pte = in->cr3;
 ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
 }
 
-pml4e_addr = ((pml5e & PG_ADDRESS_MASK) +
-(((addr >> 39) & 0x1ff) << 3)) & a20_mask;
-PTE_HPHYS(pml4e_addr);
-pml4e = x86_ldq_phys(cs, pml4e_addr);
-if (!(pml4e & PG_PRESENT_MASK)) {
+/*
+ * Page table level 4
+ */
+pte_addr = ((pte & PG_ADDRESS_MASK) +
+(((addr >> 39) & 0x1ff) << 3)) & a20_mask;
+PTE_HPHYS(pte_addr);
+pte = x86_ldq_phys(cs, pte_addr);
+if (!(pte & PG_PRESENT_MASK)) {
 goto do_fault;
 }
-if (pml4e & (rsvd_mask | PG_PSE_MASK)) {
+if (pte & (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);
+if (!(pte & PG_ACCESSED_MASK)) {
+pte |= PG_ACCESSED_MASK;
+x86_stl_phys_notdirty(cs, pte_addr, pte);
 }
-ptep &= pml4e ^ PG_NX_MASK;
-pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) 
<< 3)) &
-a20_mask;
-PTE_HPHYS(pdpe_addr);
-pdpe = x86_ldq_phys(cs, pdpe_addr);
-if (!(pdpe & PG_PRESENT_MASK)) {
+ptep &= pte ^ PG_NX_MASK;
+
+/*
+ * Page table level 3
+ */
+pte_addr = ((pte & PG_ADDRESS_MASK) +
+(((addr >> 30) & 0x1ff) << 3)) & a20_mask;
+PTE_HPHYS(pte_addr);
+pte = x86_ldq_phys(cs, pte_addr);
+if (!(pte & PG_PRESENT_MASK)) {
 goto do_fault;
 }
-if (pdpe & rsvd_mask) {
+if (pte & 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);
+ptep &= pte ^ PG_NX_MASK;
+if (!(pte & PG_ACCESSED_MAS

[PATCH 05/14] accel/tcg: Introduce tlb_set_page_full

2022-08-22 Thread Richard Henderson
Now that we have collected all of the page data into
CPUTLBEntryFull, provide an interface to record that
all in one go, instead of using 4 arguments.  This interface
allows CPUTLBEntryFull to be extended without having to
change the number of arguments.

Signed-off-by: Richard Henderson 
---
 include/exec/cpu-defs.h | 14 ++
 include/exec/exec-all.h | 22 +++
 accel/tcg/cputlb.c  | 62 -
 3 files changed, 78 insertions(+), 20 deletions(-)

diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
index f70f54d850..5e12cc1854 100644
--- a/include/exec/cpu-defs.h
+++ b/include/exec/cpu-defs.h
@@ -148,7 +148,21 @@ typedef struct CPUTLBEntryFull {
  * + the offset within the target MemoryRegion (otherwise)
  */
 hwaddr xlat_section;
+
+/*
+ * @phys_addr contains the physical address in the address space
+ * given by cpu_asidx_from_attrs(cpu, @attrs).
+ */
+hwaddr phys_addr;
+
+/* @attrs contains the memory transaction attributes for the page. */
 MemTxAttrs attrs;
+
+/* @prot contains the complete protections for the page. */
+uint8_t prot;
+
+/* @lg_page_size contains the log2 of the page size. */
+uint8_t lg_page_size;
 } CPUTLBEntryFull;
 
 /*
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index e366b5c1ba..e7b54e8e5c 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -258,6 +258,28 @@ void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState 
*cpu,
uint16_t idxmap,
unsigned bits);
 
+/**
+ * tlb_set_page_full:
+ * @cpu: CPU context
+ * @mmu_idx: mmu index of the tlb to modify
+ * @vaddr: virtual address of the entry to add
+ * @full: the details of the tlb entry
+ *
+ * Add an entry to @cpu tlb index @mmu_idx.  All of the fields of
+ * @full must be filled, except for xlat_section, and constitute
+ * the complete description of the translated page.
+ *
+ * This is generally called by the target tlb_fill function after
+ * having performed a successful page table walk to find the physical
+ * address and attributes for the translation.
+ *
+ * At most one entry for a given virtual address is permitted. Only a
+ * single TARGET_PAGE_SIZE region is mapped; @full->ld_page_size is only
+ * used by tlb_flush_page.
+ */
+void tlb_set_page_full(CPUState *cpu, int mmu_idx, target_ulong vaddr,
+   CPUTLBEntryFull *full);
+
 /**
  * tlb_set_page_with_attrs:
  * @cpu: CPU to add this TLB entry for
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 1c59e701e6..a93d715e42 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1095,16 +1095,16 @@ static void tlb_add_large_page(CPUArchState *env, int 
mmu_idx,
 env_tlb(env)->d[mmu_idx].large_page_mask = lp_mask;
 }
 
-/* Add a new TLB entry. At most one entry for a given virtual address
+/*
+ * Add a new TLB entry. At most one entry for a given virtual address
  * is permitted. Only a single TARGET_PAGE_SIZE region is mapped, the
  * supplied size is only used by tlb_flush_page.
  *
  * Called from TCG-generated code, which is under an RCU read-side
  * critical section.
  */
-void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
- hwaddr paddr, MemTxAttrs attrs, int prot,
- int mmu_idx, target_ulong size)
+void tlb_set_page_full(CPUState *cpu, int mmu_idx,
+   target_ulong vaddr, CPUTLBEntryFull *full)
 {
 CPUArchState *env = cpu->env_ptr;
 CPUTLB *tlb = env_tlb(env);
@@ -1117,35 +1117,36 @@ void tlb_set_page_with_attrs(CPUState *cpu, 
target_ulong vaddr,
 CPUTLBEntry *te, tn;
 hwaddr iotlb, xlat, sz, paddr_page;
 target_ulong vaddr_page;
-int asidx = cpu_asidx_from_attrs(cpu, attrs);
-int wp_flags;
+int asidx, wp_flags, prot;
 bool is_ram, is_romd;
 
 assert_cpu_is_self(cpu);
 
-if (size <= TARGET_PAGE_SIZE) {
+if (full->lg_page_size <= TARGET_PAGE_BITS) {
 sz = TARGET_PAGE_SIZE;
 } else {
-tlb_add_large_page(env, mmu_idx, vaddr, size);
-sz = size;
+sz = (hwaddr)1 << full->lg_page_size;
+tlb_add_large_page(env, mmu_idx, vaddr, sz);
 }
 vaddr_page = vaddr & TARGET_PAGE_MASK;
-paddr_page = paddr & TARGET_PAGE_MASK;
+paddr_page = full->phys_addr & TARGET_PAGE_MASK;
 
+prot = full->prot;
+asidx = cpu_asidx_from_attrs(cpu, full->attrs);
 section = address_space_translate_for_iotlb(cpu, asidx, paddr_page,
-&xlat, &sz, attrs, &prot);
+&xlat, &sz, full->attrs, 
&prot);
 assert(sz >= TARGET_PAGE_SIZE);
 
 tlb_debug("vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx
   " prot=%x idx=%d\n",
-  vaddr, paddr, prot, mmu_idx);
+  vaddr, full->phys_addr, prot

[PATCH 00/14] target/i386: Use atomic operations for pte updates

2022-08-22 Thread Richard Henderson
This patch set does two things:

(1) Remove assert(!probe) from the x86 tlb_fill

It turns out that this is a prerequisite for
[PATCH v6 00/21] linux-user: Fix siginfo_t contents when jumping
to non-readable pages

because of a new use of probe_access(..., nonfault)
when comparing TBs that cross a page boundary.

Patches 7-10 are sufficient to fix this.

After auditing all of the targets, Sparc has a similar assert,
and AVR simply doesn't check probe at all.  Both will need fixing.

(2) Use atomic operations for pte updates, which is a long-standing
bug since our conversion to MTTCG.

For simplicity, patches 1-6 are from the middle of 
("[PATCH v2 00/66] target/arm: Implement FEAT_HAFDBS")


r~


Richard Henderson (14):
  accel/tcg: Rename CPUIOTLBEntry to CPUTLBEntryFull
  accel/tcg: Drop addr member from SavedIOTLB
  accel/tcg: Suppress auto-invalidate in probe_access_internal
  accel/tcg: Introduce probe_access_full
  accel/tcg: Introduce tlb_set_page_full
  include/exec: Introduce TARGET_PAGE_ENTRY_EXTRA
  target/i386: Use MMUAccessType across excp_helper.c
  target/i386: Direct call get_hphys from mmu_translate
  target/i386: Introduce structures for mmu_translate
  target/i386: Reorg GET_HPHYS
  target/i386: Add MMU_PHYS_IDX and MMU_NESTED_IDX
  target/i386: Use MMU_NESTED_IDX for vmload/vmsave
  target/i386: Combine 5 sets of variables in mmu_translate
  target/i386: Use atomic operations for pte updates

 include/exec/cpu-defs.h  |  45 +-
 include/exec/exec-all.h  |  33 ++
 include/hw/core/cpu.h|   1 -
 target/i386/cpu-param.h  |   2 +-
 target/i386/cpu.h|   5 +-
 accel/tcg/cputlb.c   | 215 +
 target/arm/mte_helper.c  |  14 +-
 target/arm/sve_helper.c  |   4 +-
 target/arm/translate-a64.c   |   2 +-
 target/i386/tcg/sysemu/excp_helper.c | 692 +--
 target/i386/tcg/sysemu/svm_helper.c  | 234 +
 target/s390x/tcg/mem_helper.c|   4 -
 12 files changed, 772 insertions(+), 479 deletions(-)

-- 
2.34.1




[PATCH 04/14] accel/tcg: Introduce probe_access_full

2022-08-22 Thread Richard Henderson
Add an interface to return the CPUTLBEntryFull struct
that goes with the lookup.  The result is not intended
to be valid across multiple lookups, so the user must
use the results immediately.

Signed-off-by: Richard Henderson 
---
 include/exec/exec-all.h | 11 +++
 accel/tcg/cputlb.c  | 44 +
 2 files changed, 38 insertions(+), 17 deletions(-)

diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 311e5fb422..e366b5c1ba 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -435,6 +435,17 @@ int probe_access_flags(CPUArchState *env, target_ulong 
addr,
MMUAccessType access_type, int mmu_idx,
bool nonfault, void **phost, uintptr_t retaddr);
 
+#ifndef CONFIG_USER_ONLY
+/**
+ * probe_access_full:
+ * Like probe_access_flags, except also return into @pfull.
+ */
+int probe_access_full(CPUArchState *env, target_ulong addr,
+  MMUAccessType access_type, int mmu_idx,
+  bool nonfault, void **phost,
+  CPUTLBEntryFull **pfull, uintptr_t retaddr);
+#endif
+
 #define CODE_GEN_ALIGN   16 /* must be >= of the size of a icache line 
*/
 
 /* Estimated block size for TB allocation.  */
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 5359113e8d..1c59e701e6 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1579,7 +1579,8 @@ static void notdirty_write(CPUState *cpu, vaddr 
mem_vaddr, unsigned size,
 static int probe_access_internal(CPUArchState *env, target_ulong addr,
  int fault_size, MMUAccessType access_type,
  int mmu_idx, bool nonfault,
- void **phost, uintptr_t retaddr)
+ void **phost, CPUTLBEntryFull **pfull,
+ uintptr_t retaddr)
 {
 uintptr_t index = tlb_index(env, mmu_idx, addr);
 CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
@@ -1613,10 +1614,12 @@ static int probe_access_internal(CPUArchState *env, 
target_ulong addr,
mmu_idx, nonfault, retaddr)) {
 /* Non-faulting page table read failed.  */
 *phost = NULL;
+*pfull = NULL;
 return TLB_INVALID_MASK;
 }
 
 /* TLB resize via tlb_fill may have moved the entry.  */
+index = tlb_index(env, mmu_idx, addr);
 entry = tlb_entry(env, mmu_idx, addr);
 
 /*
@@ -1630,6 +1633,8 @@ static int probe_access_internal(CPUArchState *env, 
target_ulong addr,
 }
 flags &= tlb_addr;
 
+*pfull = &env_tlb(env)->d[mmu_idx].fulltlb[index];
+
 /* Fold all "mmio-like" bits into TLB_MMIO.  This is not RAM.  */
 if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY))) {
 *phost = NULL;
@@ -1641,37 +1646,44 @@ static int probe_access_internal(CPUArchState *env, 
target_ulong addr,
 return flags;
 }
 
-int probe_access_flags(CPUArchState *env, target_ulong addr,
-   MMUAccessType access_type, int mmu_idx,
-   bool nonfault, void **phost, uintptr_t retaddr)
+int probe_access_full(CPUArchState *env, target_ulong addr,
+  MMUAccessType access_type, int mmu_idx,
+  bool nonfault, void **phost, CPUTLBEntryFull **pfull,
+  uintptr_t retaddr)
 {
-int flags;
-
-flags = probe_access_internal(env, addr, 0, access_type, mmu_idx,
-  nonfault, phost, retaddr);
+int flags = probe_access_internal(env, addr, 0, access_type, mmu_idx,
+  nonfault, phost, pfull, retaddr);
 
 /* Handle clean RAM pages.  */
 if (unlikely(flags & TLB_NOTDIRTY)) {
-uintptr_t index = tlb_index(env, mmu_idx, addr);
-CPUTLBEntryFull *full = &env_tlb(env)->d[mmu_idx].fulltlb[index];
-
-notdirty_write(env_cpu(env), addr, 1, full, retaddr);
+notdirty_write(env_cpu(env), addr, 1, *pfull, retaddr);
 flags &= ~TLB_NOTDIRTY;
 }
 
 return flags;
 }
 
+int probe_access_flags(CPUArchState *env, target_ulong addr,
+   MMUAccessType access_type, int mmu_idx,
+   bool nonfault, void **phost, uintptr_t retaddr)
+{
+CPUTLBEntryFull *full;
+
+return probe_access_full(env, addr, access_type, mmu_idx,
+ nonfault, phost, &full, retaddr);
+}
+
 void *probe_access(CPUArchState *env, target_ulong addr, int size,
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
 {
+CPUTLBEntryFull *full;
 void *host;
 int flags;
 
 g_assert(-(addr | TARGET_PAGE_MASK) >= size);
 
 flags = probe_access_internal(env, addr, size, access_type, mmu_idx,
-  false, &host, retaddr);
+  fa

[PATCH 11/14] target/i386: Add MMU_PHYS_IDX and MMU_NESTED_IDX

2022-08-22 Thread Richard Henderson
These new mmu indexes will be helpful for improving
paging and code throughout the target.

Signed-off-by: Richard Henderson 
---
 target/i386/cpu-param.h  |  2 +-
 target/i386/cpu.h|  3 +
 target/i386/tcg/sysemu/excp_helper.c | 82 ++--
 target/i386/tcg/sysemu/svm_helper.c  |  3 +
 4 files changed, 60 insertions(+), 30 deletions(-)

diff --git a/target/i386/cpu-param.h b/target/i386/cpu-param.h
index 9740bd7abd..abad52af20 100644
--- a/target/i386/cpu-param.h
+++ b/target/i386/cpu-param.h
@@ -23,6 +23,6 @@
 # define TARGET_VIRT_ADDR_SPACE_BITS  32
 #endif
 #define TARGET_PAGE_BITS 12
-#define NB_MMU_MODES 3
+#define NB_MMU_MODES 5
 
 #endif
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 82004b65b9..9a40b54ae5 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2144,6 +2144,9 @@ uint64_t cpu_get_tsc(CPUX86State *env);
 #define MMU_KSMAP_IDX   0
 #define MMU_USER_IDX1
 #define MMU_KNOSMAP_IDX 2
+#define MMU_NESTED_IDX  3
+#define MMU_PHYS_IDX4
+
 static inline int cpu_mmu_index(CPUX86State *env, bool ifetch)
 {
 return (env->hflags & HF_CPL_MASK) == 3 ? MMU_USER_IDX :
diff --git a/target/i386/tcg/sysemu/excp_helper.c 
b/target/i386/tcg/sysemu/excp_helper.c
index e9adaa3dad..f771d25f32 100644
--- a/target/i386/tcg/sysemu/excp_helper.c
+++ b/target/i386/tcg/sysemu/excp_helper.c
@@ -448,41 +448,65 @@ static bool get_physical_address(CPUX86State *env, vaddr 
addr,
  MMUAccessType access_type, int mmu_idx,
  TranslateResult *out, TranslateFault *err)
 {
-if (!(env->cr[0] & CR0_PG_MASK)) {
-out->paddr = addr & x86_get_a20_mask(env);
+TranslateParams in;
+bool use_stage2 = env->hflags2 & HF2_NPT_MASK;
 
-#ifdef TARGET_X86_64
-if (!(env->hflags & HF_LMA_MASK)) {
-/* Without long mode we can only address 32bits in real mode */
-out->paddr = (uint32_t)out->paddr;
-}
-#endif
-out->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
-out->page_size = TARGET_PAGE_SIZE;
-return true;
-} else {
-TranslateParams in = {
-.addr = addr,
-.cr3 = env->cr[3],
-.pg_mode = get_pg_mode(env),
-.mmu_idx = mmu_idx,
-.access_type = access_type,
-.use_stage2 = env->hflags2 & HF2_NPT_MASK,
-};
+in.addr = addr;
+in.access_type = access_type;
 
-if (in.pg_mode & PG_MODE_LMA) {
-/* test virtual address sign extension */
-int shift = in.pg_mode & PG_MODE_LA57 ? 56 : 47;
-int64_t sext = (int64_t)addr >> shift;
-if (sext != 0 && sext != -1) {
-err->exception_index = EXCP0D_GPF;
-err->error_code = 0;
-err->cr2 = addr;
+switch (mmu_idx) {
+case MMU_PHYS_IDX:
+break;
+
+case MMU_NESTED_IDX:
+if (likely(use_stage2)) {
+in.cr3 = env->nested_cr3;
+in.pg_mode = env->nested_pg_mode;
+in.mmu_idx = MMU_USER_IDX;
+in.use_stage2 = false;
+
+if (!mmu_translate(env, &in, out, err)) {
+err->stage2 = S2_GPA;
 return false;
 }
+return true;
 }
-return mmu_translate(env, &in, out, err);
+break;
+
+default:
+in.cr3 = env->cr[3];
+in.mmu_idx = mmu_idx;
+in.use_stage2 = use_stage2;
+in.pg_mode = get_pg_mode(env);
+
+if (likely(in.pg_mode)) {
+if (in.pg_mode & PG_MODE_LMA) {
+/* test virtual address sign extension */
+int shift = in.pg_mode & PG_MODE_LA57 ? 56 : 47;
+int64_t sext = (int64_t)addr >> shift;
+if (sext != 0 && sext != -1) {
+err->exception_index = EXCP0D_GPF;
+err->error_code = 0;
+err->cr2 = addr;
+return false;
+}
+}
+return mmu_translate(env, &in, out, err);
+}
+break;
 }
+
+/* Translation disabled. */
+out->paddr = addr & x86_get_a20_mask(env);
+#ifdef TARGET_X86_64
+if (!(env->hflags & HF_LMA_MASK)) {
+/* Without long mode we can only address 32bits in real mode */
+out->paddr = (uint32_t)out->paddr;
+}
+#endif
+out->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+out->page_size = TARGET_PAGE_SIZE;
+return true;
 }
 
 bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
diff --git a/target/i386/tcg/sysemu/svm_helper.c 
b/target/i386/tcg/sysemu/svm_helper.c
index 2b6f450af9..85b7741d94 100644
--- a/target/i386/tcg/sysemu/svm_helper.c
+++ b/target/i386/tcg/sysemu/svm_helper.c
@@ -271,6 +271,8 @@ void helper_vmrun(CPUX86State *env, int aflag, int 
next_eip_addend)
 env->hflags2 |= HF2_NPT_MASK;
 
 env->nested_pg_mode = get_pg_mode(env) & PG_MODE_SVM_MA

[PATCH 11/22] target/i386: Remove cur_eip, next_eip arguments to gen_repz*

2022-08-22 Thread Richard Henderson
All callers pass s->base.pc_next and s->pc, which we can just
as well compute within the functions.  Pull out common helpers
and reduce the amount of code under macros.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 116 ++--
 1 file changed, 57 insertions(+), 59 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index ee8e87a617..38f4589fd2 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -736,7 +736,7 @@ static bool gen_check_io(DisasContext *s, MemOp ot, 
TCGv_i32 port,
 #endif
 }
 
-static inline void gen_movs(DisasContext *s, MemOp ot)
+static void gen_movs(DisasContext *s, MemOp ot)
 {
 gen_string_movl_A0_ESI(s);
 gen_op_ld_v(s, ot, s->T0, s->A0);
@@ -1156,18 +1156,18 @@ static inline void gen_jcc1(DisasContext *s, int b, 
TCGLabel *l1)
 
 /* XXX: does not work with gdbstub "ice" single step - not a
serious problem */
-static TCGLabel *gen_jz_ecx_string(DisasContext *s, target_ulong next_eip)
+static TCGLabel *gen_jz_ecx_string(DisasContext *s)
 {
 TCGLabel *l1 = gen_new_label();
 TCGLabel *l2 = gen_new_label();
 gen_op_jnz_ecx(s, s->aflag, l1);
 gen_set_label(l2);
-gen_jmp_tb(s, next_eip, 1);
+gen_jmp_tb(s, s->pc - s->cs_base, 1);
 gen_set_label(l1);
 return l2;
 }
 
-static inline void gen_stos(DisasContext *s, MemOp ot)
+static void gen_stos(DisasContext *s, MemOp ot)
 {
 gen_op_mov_v_reg(s, MO_32, s->T0, R_EAX);
 gen_string_movl_A0_EDI(s);
@@ -1176,7 +1176,7 @@ static inline void gen_stos(DisasContext *s, MemOp ot)
 gen_op_add_reg_T0(s, s->aflag, R_EDI);
 }
 
-static inline void gen_lods(DisasContext *s, MemOp ot)
+static void gen_lods(DisasContext *s, MemOp ot)
 {
 gen_string_movl_A0_ESI(s);
 gen_op_ld_v(s, ot, s->T0, s->A0);
@@ -1185,7 +1185,7 @@ static inline void gen_lods(DisasContext *s, MemOp ot)
 gen_op_add_reg_T0(s, s->aflag, R_ESI);
 }
 
-static inline void gen_scas(DisasContext *s, MemOp ot)
+static void gen_scas(DisasContext *s, MemOp ot)
 {
 gen_string_movl_A0_EDI(s);
 gen_op_ld_v(s, ot, s->T1, s->A0);
@@ -1194,7 +1194,7 @@ static inline void gen_scas(DisasContext *s, MemOp ot)
 gen_op_add_reg_T0(s, s->aflag, R_EDI);
 }
 
-static inline void gen_cmps(DisasContext *s, MemOp ot)
+static void gen_cmps(DisasContext *s, MemOp ot)
 {
 gen_string_movl_A0_EDI(s);
 gen_op_ld_v(s, ot, s->T1, s->A0);
@@ -1222,7 +1222,7 @@ static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, 
int ot)
 }
 }
 
-static inline void gen_ins(DisasContext *s, MemOp ot)
+static void gen_ins(DisasContext *s, MemOp ot)
 {
 gen_string_movl_A0_EDI(s);
 /* Note: we must do this dummy write first to be restartable in
@@ -1238,7 +1238,7 @@ static inline void gen_ins(DisasContext *s, MemOp ot)
 gen_bpt_io(s, s->tmp2_i32, ot);
 }
 
-static inline void gen_outs(DisasContext *s, MemOp ot)
+static void gen_outs(DisasContext *s, MemOp ot)
 {
 gen_string_movl_A0_ESI(s);
 gen_op_ld_v(s, ot, s->T0, s->A0);
@@ -1252,42 +1252,49 @@ static inline void gen_outs(DisasContext *s, MemOp ot)
 gen_bpt_io(s, s->tmp2_i32, ot);
 }
 
-/* same method as Valgrind : we generate jumps to current or next
-   instruction */
-#define GEN_REPZ(op)  \
-static inline void gen_repz_ ## op(DisasContext *s, MemOp ot,  \
- target_ulong cur_eip, target_ulong next_eip) \
-{ \
-TCGLabel *l2; \
-gen_update_cc_op(s);  \
-l2 = gen_jz_ecx_string(s, next_eip);  \
-gen_ ## op(s, ot);\
-gen_op_add_reg_im(s, s->aflag, R_ECX, -1);\
-/* a loop would cause two single step exceptions if ECX = 1   \
-   before rep string_insn */  \
-if (s->repz_opt)  \
-gen_op_jz_ecx(s, s->aflag, l2);   \
-gen_jmp(s, cur_eip);  \
+/* Generate jumps to current or next instruction */
+static void gen_repz(DisasContext *s, MemOp ot,
+ void (*fn)(DisasContext *s, MemOp ot))
+{
+TCGLabel *l2;
+gen_update_cc_op(s);
+l2 = gen_jz_ecx_string(s);
+fn(s, ot);
+gen_op_add_reg_im(s, s->aflag, R_ECX, -1);
+/*
+ * A loop would cause two single step exceptions if ECX = 1
+ * before rep string_insn
+ */
+if (s->repz_opt) {
+gen_op_jz_ecx(s, s->aflag, l2);
+}
+gen_jmp(s, s->base.pc_next - s->cs_base);
 }
 
-#define GEN_REPZ2(op)   

[PATCH 03/14] accel/tcg: Suppress auto-invalidate in probe_access_internal

2022-08-22 Thread Richard Henderson
When PAGE_WRITE_INV is set when calling tlb_set_page,
we immediately set TLB_INVALID_MASK in order to force
tlb_fill to be called on the next lookup.  Here in
probe_access_internal, we have just called tlb_fill
and eliminated true misses, thus the lookup must be valid.

This allows us to remove a warning comment from s390x.
There doesn't seem to be a reason to change the code though.

Cc: David Hildenbrand 
Signed-off-by: Richard Henderson 
---
 accel/tcg/cputlb.c| 10 +-
 target/s390x/tcg/mem_helper.c |  4 
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 1509df96b4..5359113e8d 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1602,6 +1602,7 @@ static int probe_access_internal(CPUArchState *env, 
target_ulong addr,
 }
 tlb_addr = tlb_read_ofs(entry, elt_ofs);
 
+flags = TLB_FLAGS_MASK;
 page_addr = addr & TARGET_PAGE_MASK;
 if (!tlb_hit_page(tlb_addr, page_addr)) {
 if (!victim_tlb_hit(env, mmu_idx, index, elt_ofs, page_addr)) {
@@ -1617,10 +1618,17 @@ static int probe_access_internal(CPUArchState *env, 
target_ulong addr,
 
 /* TLB resize via tlb_fill may have moved the entry.  */
 entry = tlb_entry(env, mmu_idx, addr);
+
+/*
+ * With PAGE_WRITE_INV, we set TLB_INVALID_MASK immediately,
+ * to force the next access through tlb_fill.  We've just
+ * called tlb_fill, so we know that this entry *is* valid.
+ */
+flags &= ~TLB_INVALID_MASK;
 }
 tlb_addr = tlb_read_ofs(entry, elt_ofs);
 }
-flags = tlb_addr & TLB_FLAGS_MASK;
+flags &= tlb_addr;
 
 /* Fold all "mmio-like" bits into TLB_MMIO.  This is not RAM.  */
 if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY))) {
diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c
index fc52aa128b..3758b9e688 100644
--- a/target/s390x/tcg/mem_helper.c
+++ b/target/s390x/tcg/mem_helper.c
@@ -148,10 +148,6 @@ static int s390_probe_access(CPUArchState *env, 
target_ulong addr, int size,
 #else
 int flags;
 
-/*
- * For !CONFIG_USER_ONLY, we cannot rely on TLB_INVALID_MASK or haddr==NULL
- * to detect if there was an exception during tlb_fill().
- */
 env->tlb_fill_exc = 0;
 flags = probe_access_flags(env, addr, access_type, mmu_idx, nonfault, 
phost,
ra);
-- 
2.34.1




[PATCH 14/14] target/i386: Use atomic operations for pte updates

2022-08-22 Thread Richard Henderson
Use probe_access_full in order to resolve to a host address,
which then lets us use a host cmpxchg to update the pte.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/279
Signed-off-by: Richard Henderson 
---
 target/i386/tcg/sysemu/excp_helper.c | 242 +++
 1 file changed, 168 insertions(+), 74 deletions(-)

diff --git a/target/i386/tcg/sysemu/excp_helper.c 
b/target/i386/tcg/sysemu/excp_helper.c
index e5d9ff138e..74a76cf883 100644
--- a/target/i386/tcg/sysemu/excp_helper.c
+++ b/target/i386/tcg/sysemu/excp_helper.c
@@ -27,8 +27,8 @@ typedef struct TranslateParams {
 target_ulong cr3;
 int pg_mode;
 int mmu_idx;
+int ptw_idx;
 MMUAccessType access_type;
-bool use_stage2;
 } TranslateParams;
 
 typedef struct TranslateResult {
@@ -50,43 +50,106 @@ typedef struct TranslateFault {
 TranslateFaultStage2 stage2;
 } TranslateFault;
 
-#define PTE_HPHYS(ADDR) \
-do {\
-if (in->use_stage2) {   \
-nested_in.addr = (ADDR);\
-if (!mmu_translate(env, &nested_in, out, err)) {\
-err->stage2 = S2_GPT;   \
-return false;   \
-}   \
-(ADDR) = out->paddr;\
-}   \
-} while (0)
+typedef struct PTETranslate {
+CPUX86State *env;
+TranslateFault *err;
+int ptw_idx;
+void *haddr;
+hwaddr gaddr;
+} PTETranslate;
+
+static bool ptw_translate(PTETranslate *inout, hwaddr addr)
+{
+CPUTLBEntryFull *full;
+int flags;
+
+inout->gaddr = addr;
+flags = probe_access_full(inout->env, addr, MMU_DATA_STORE,
+  inout->ptw_idx, true, &inout->haddr, &full, 0);
+
+if (unlikely(flags & TLB_INVALID_MASK)) {
+TranslateFault *err = inout->err;
+
+assert(inout->ptw_idx == MMU_NESTED_IDX);
+err->exception_index = 0; /* unused */
+err->error_code = inout->env->error_code;
+err->cr2 = addr;
+err->stage2 = S2_GPT;
+return false;
+}
+return true;
+}
+
+static inline uint32_t ptw_ldl(const PTETranslate *in)
+{
+if (likely(in->haddr)) {
+return ldl_p(in->haddr);
+}
+return cpu_ldl_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, 0);
+}
+
+static inline uint64_t ptw_ldq(const PTETranslate *in)
+{
+if (likely(in->haddr)) {
+return ldq_p(in->haddr);
+}
+return cpu_ldq_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, 0);
+}
+
+/*
+ * Note that we can use a 32-bit cmpxchg for all page table entries,
+ * even 64-bit ones, because PG_PRESENT_MASK, PG_ACCESSED_MASK and
+ * PG_DIRTY_MASK are all in the low 32 bits.
+ */
+static bool ptw_setl_slow(const PTETranslate *in, uint32_t old, uint32_t new)
+{
+uint32_t cmp;
+
+/* Does x86 really perform a rmw cycle on mmio for ptw? */
+start_exclusive();
+cmp = cpu_ldl_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, 0);
+if (cmp == old) {
+cpu_stl_mmuidx_ra(in->env, in->gaddr, new, in->ptw_idx, 0);
+}
+end_exclusive();
+return cmp == old;
+}
+
+static inline bool ptw_setl(const PTETranslate *in, uint32_t old, uint32_t set)
+{
+if (set & ~old) {
+uint32_t new = old | set;
+if (likely(in->haddr)) {
+old = cpu_to_le32(old);
+new = cpu_to_le32(new);
+return qatomic_cmpxchg((uint32_t *)in->haddr, old, new) == old;
+}
+return ptw_setl_slow(in, old, new);
+}
+return true;
+}
 
 static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
   TranslateResult *out, TranslateFault *err)
 {
-TranslateParams nested_in = {
-/* Use store for page table entries, to allow A/D flag updates. */
-.access_type = MMU_DATA_STORE,
-.cr3 = env->nested_cr3,
-.pg_mode = env->nested_pg_mode,
-.mmu_idx = MMU_USER_IDX,
-.use_stage2 = false,
-};
-
-CPUState *cs = env_cpu(env);
-X86CPU *cpu = env_archcpu(env);
 const int32_t a20_mask = x86_get_a20_mask(env);
 const target_ulong addr = in->addr;
 const int pg_mode = in->pg_mode;
 const bool is_user = (in->mmu_idx == MMU_USER_IDX);
 const MMUAccessType access_type = in->access_type;
-uint64_t ptep, pte;
+uint64_t ptep, pte, rsvd_mask;
+PTETranslate pte_trans = {
+.env = env,
+.err = err,
+.ptw_idx = in->ptw_idx,
+};
 hwaddr pte_addr;
-uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits);
 uint32_t pkr;
 int page_size;
 
+ restart_all:
+rsvd_mask = ~MAKE_64BIT_MASK(0, env_archcpu(env)->phys_bits);
+rsvd_mask &= PG_ADDRESS_MASK;
 if (!

[PATCH 09/14] target/i386: Introduce structures for mmu_translate

2022-08-22 Thread Richard Henderson
Create TranslateParams for inputs, TranslateResults for successful
outputs, and TranslateFault for error outputs; return true on success.

Move stage1 error paths from handle_mmu_fault to x86_cpu_tlb_fill;
reorg the rest of handle_mmu_fault into get_physical_address.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/sysemu/excp_helper.c | 322 ++-
 1 file changed, 171 insertions(+), 151 deletions(-)

diff --git a/target/i386/tcg/sysemu/excp_helper.c 
b/target/i386/tcg/sysemu/excp_helper.c
index ea195f7a28..a6b7562bf3 100644
--- a/target/i386/tcg/sysemu/excp_helper.c
+++ b/target/i386/tcg/sysemu/excp_helper.c
@@ -22,30 +22,45 @@
 #include "exec/exec-all.h"
 #include "tcg/helper-tcg.h"
 
-#define PG_ERROR_OK (-1)
+typedef struct TranslateParams {
+target_ulong addr;
+target_ulong cr3;
+int pg_mode;
+int mmu_idx;
+MMUAccessType access_type;
+bool use_stage2;
+} TranslateParams;
+
+typedef struct TranslateResult {
+hwaddr paddr;
+int prot;
+int page_size;
+} TranslateResult;
+
+typedef struct TranslateFault {
+int exception_index;
+int error_code;
+target_ulong cr2;
+} TranslateFault;
 
 #define GET_HPHYS(cs, gpa, access_type, prot)  \
-   (use_stage2 ? get_hphys(cs, gpa, access_type, prot) : gpa)
+   (in->use_stage2 ? get_hphys(cs, gpa, access_type, prot) : gpa)
 
-static int mmu_translate(CPUState *cs, hwaddr addr, bool use_stage2,
- uint64_t cr3, MMUAccessType access_type,
- int mmu_idx, int pg_mode,
- hwaddr *xlat, int *page_size, int *prot)
+static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
+  TranslateResult *out, TranslateFault *err)
 {
-X86CPU *cpu = X86_CPU(cs);
-CPUX86State *env = &cpu->env;
+CPUState *cs = env_cpu(env);
+X86CPU *cpu = env_archcpu(env);
+const int32_t a20_mask = x86_get_a20_mask(env);
+const target_ulong addr = in->addr;
+const int pg_mode = in->pg_mode;
+const bool is_user = (in->mmu_idx == MMU_USER_IDX);
+const MMUAccessType access_type = in->access_type;
 uint64_t ptep, pte;
-int32_t a20_mask;
-target_ulong pde_addr, pte_addr;
-int error_code = 0;
-bool is_dirty, is_write, is_user;
+hwaddr pde_addr, pte_addr;
 uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits);
-uint32_t page_offset;
 uint32_t pkr;
-
-is_user = (mmu_idx == MMU_USER_IDX);
-is_write = (access_type == MMU_DATA_STORE);
-a20_mask = x86_get_a20_mask(env);
+int page_size;
 
 if (!(pg_mode & PG_MODE_NXE)) {
 rsvd_mask |= PG_NX_MASK;
@@ -62,7 +77,7 @@ static int mmu_translate(CPUState *cs, hwaddr addr, bool 
use_stage2,
 uint64_t pml4e_addr, pml4e;
 
 if (la57) {
-pml5e_addr = ((cr3 & ~0xfff) +
+pml5e_addr = ((in->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);
@@ -78,7 +93,7 @@ static int mmu_translate(CPUState *cs, hwaddr addr, bool 
use_stage2,
 }
 ptep = pml5e ^ PG_NX_MASK;
 } else {
-pml5e = cr3;
+pml5e = in->cr3;
 ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
 }
 
@@ -114,7 +129,7 @@ static int mmu_translate(CPUState *cs, hwaddr addr, bool 
use_stage2,
 }
 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;
@@ -123,7 +138,7 @@ static int mmu_translate(CPUState *cs, hwaddr addr, bool 
use_stage2,
 #endif
 {
 /* XXX: load them when cr3 is loaded ? */
-pdpe_addr = ((cr3 & ~0x1f) + ((addr >> 27) & 0x18)) &
+pdpe_addr = ((in->cr3 & ~0x1f) + ((addr >> 27) & 0x18)) &
 a20_mask;
 pdpe_addr = GET_HPHYS(cs, pdpe_addr, MMU_DATA_STORE, NULL);
 pdpe = x86_ldq_phys(cs, pdpe_addr);
@@ -150,7 +165,7 @@ static int mmu_translate(CPUState *cs, hwaddr addr, bool 
use_stage2,
 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;
@@ -172,12 +187,12 @@ static int mmu_translate(CPUState *cs, hwaddr addr, bool 
use_stage2,
 }
 /* combine pde and pte nx, user and rw protections */
 ptep &= pte ^ PG_NX_MASK;
-*page_size = 4096;
+page_size = 4096;
 } else {
 uint32_t pde;
 
 /* page directory entry */
-pde_

[PATCH 17/22] target/i386: Use gen_jmp_rel for loop and jecxz insns

2022-08-22 Thread Richard Henderson
With gen_jmp_rel, we may chain to the next tb
instead of merely writing to eip and exiting.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 21 ++---
 1 file changed, 6 insertions(+), 15 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 0a2ec85972..59e7596629 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -7242,24 +7242,18 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 case 0xe2: /* loop */
 case 0xe3: /* jecxz */
 {
-TCGLabel *l1, *l2, *l3;
-
-tval = (int8_t)insn_get(env, s, MO_8);
-tval += s->pc - s->cs_base;
-if (dflag == MO_16) {
-tval &= 0x;
-}
+TCGLabel *l1, *l2;
+int diff = (int8_t)insn_get(env, s, MO_8);
 
 l1 = gen_new_label();
 l2 = gen_new_label();
-l3 = gen_new_label();
 gen_update_cc_op(s);
 b &= 3;
 switch(b) {
 case 0: /* loopnz */
 case 1: /* loopz */
 gen_op_add_reg_im(s, s->aflag, R_ECX, -1);
-gen_op_jz_ecx(s, s->aflag, l3);
+gen_op_jz_ecx(s, s->aflag, l2);
 gen_jcc1(s, (JCC_Z << 1) | (b ^ 1), l1);
 break;
 case 2: /* loop */
@@ -7272,14 +7266,11 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 break;
 }
 
-gen_set_label(l3);
-gen_update_eip_next(s);
-tcg_gen_br(l2);
+gen_set_label(l2);
+gen_jmp_rel(s, MO_32, 0, 1);
 
 gen_set_label(l1);
-gen_jmp_im(s, tval);
-gen_set_label(l2);
-s->base.is_jmp = DISAS_EOB_ONLY;
+gen_jmp_rel(s, dflag, diff, 0);
 }
 break;
 case 0x130: /* wrmsr */
-- 
2.34.1




[PATCH 12/22] target/i386: Introduce DISAS_JUMP

2022-08-22 Thread Richard Henderson
Drop the unused dest argument to gen_jr().
Remove most of the calls to gen_jr, and use DISAS_JUMP.
Remove some unused loads of eip for lcall and ljmp.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 24 +---
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 38f4589fd2..367a7a335a 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -135,6 +135,7 @@ typedef struct DisasContext {
 #define DISAS_EOB_ONLY DISAS_TARGET_0
 #define DISAS_EOB_NEXT DISAS_TARGET_1
 #define DISAS_EOB_INHIBIT_IRQ  DISAS_TARGET_2
+#define DISAS_JUMP DISAS_TARGET_3
 
 /* The environment in which user-only runs is constrained. */
 #ifdef CONFIG_USER_ONLY
@@ -222,7 +223,7 @@ STUB_HELPER(wrmsr, TCGv_env env)
 #endif
 
 static void gen_eob(DisasContext *s);
-static void gen_jr(DisasContext *s, TCGv dest);
+static void gen_jr(DisasContext *s);
 static void gen_jmp(DisasContext *s, target_ulong eip);
 static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num);
 static void gen_op(DisasContext *s1, int op, MemOp ot, int d);
@@ -2360,7 +2361,7 @@ static void gen_goto_tb(DisasContext *s, int tb_num, 
target_ulong eip)
 } else {
 /* jump to another page */
 gen_jmp_im(s, eip);
-gen_jr(s, s->tmp0);
+gen_jr(s);
 }
 }
 
@@ -2729,7 +2730,7 @@ static void gen_eob(DisasContext *s)
 }
 
 /* Jump to register */
-static void gen_jr(DisasContext *s, TCGv dest)
+static void gen_jr(DisasContext *s)
 {
 do_gen_eob_worker(s, false, false, true);
 }
@@ -5171,7 +5172,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_push_v(s, s->T1);
 gen_op_jmp_v(s->T0);
 gen_bnd_jmp(s);
-gen_jr(s, s->T0);
+s->base.is_jmp = DISAS_JUMP;
 break;
 case 3: /* lcall Ev */
 if (mod == 3) {
@@ -5192,8 +5193,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
   tcg_const_i32(dflag - 1),
   tcg_const_i32(s->pc - s->cs_base));
 }
-tcg_gen_ld_tl(s->tmp4, cpu_env, offsetof(CPUX86State, eip));
-gen_jr(s, s->tmp4);
+s->base.is_jmp = DISAS_JUMP;
 break;
 case 4: /* jmp Ev */
 if (dflag == MO_16) {
@@ -5201,7 +5201,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 gen_op_jmp_v(s->T0);
 gen_bnd_jmp(s);
-gen_jr(s, s->T0);
+s->base.is_jmp = DISAS_JUMP;
 break;
 case 5: /* ljmp Ev */
 if (mod == 3) {
@@ -5219,8 +5219,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_op_movl_seg_T0_vm(s, R_CS);
 gen_op_jmp_v(s->T1);
 }
-tcg_gen_ld_tl(s->tmp4, cpu_env, offsetof(CPUX86State, eip));
-gen_jr(s, s->tmp4);
+s->base.is_jmp = DISAS_JUMP;
 break;
 case 6: /* push Ev */
 gen_push_v(s, s->T0);
@@ -6660,7 +6659,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 /* Note that gen_pop_T0 uses a zero-extending load.  */
 gen_op_jmp_v(s->T0);
 gen_bnd_jmp(s);
-gen_jr(s, s->T0);
+s->base.is_jmp = DISAS_JUMP;
 break;
 case 0xc3: /* ret */
 ot = gen_pop_T0(s);
@@ -6668,7 +6667,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 /* Note that gen_pop_T0 uses a zero-extending load.  */
 gen_op_jmp_v(s->T0);
 gen_bnd_jmp(s);
-gen_jr(s, s->T0);
+s->base.is_jmp = DISAS_JUMP;
 break;
 case 0xca: /* lret im */
 val = x86_ldsw_code(env, s);
@@ -8698,6 +8697,9 @@ static void i386_tr_tb_stop(DisasContextBase *dcbase, 
CPUState *cpu)
 gen_update_eip_cur(dc);
 gen_eob_inhibit_irq(dc, true);
 break;
+case DISAS_JUMP:
+gen_jr(dc);
+break;
 default:
 g_assert_not_reached();
 }
-- 
2.34.1




[PATCH 01/14] accel/tcg: Rename CPUIOTLBEntry to CPUTLBEntryFull

2022-08-22 Thread Richard Henderson
This structure will shortly contain more than just
data for accessing MMIO.  Rename the 'addr' member
to 'xlat_section' to more clearly indicate its purpose.

Signed-off-by: Richard Henderson 
---
 include/exec/cpu-defs.h|  22 
 accel/tcg/cputlb.c | 102 +++--
 target/arm/mte_helper.c|  14 ++---
 target/arm/sve_helper.c|   4 +-
 target/arm/translate-a64.c |   2 +-
 5 files changed, 73 insertions(+), 71 deletions(-)

diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
index ba3cd32a1e..f70f54d850 100644
--- a/include/exec/cpu-defs.h
+++ b/include/exec/cpu-defs.h
@@ -108,6 +108,7 @@ typedef uint64_t target_ulong;
 #  endif
 # endif
 
+/* Minimalized TLB entry for use by TCG fast path. */
 typedef struct CPUTLBEntry {
 /* bit TARGET_LONG_BITS to TARGET_PAGE_BITS : virtual address
bit TARGET_PAGE_BITS-1..4  : Nonzero for accesses that should not
@@ -131,14 +132,14 @@ typedef struct CPUTLBEntry {
 
 QEMU_BUILD_BUG_ON(sizeof(CPUTLBEntry) != (1 << CPU_TLB_ENTRY_BITS));
 
-/* The IOTLB is not accessed directly inline by generated TCG code,
- * so the CPUIOTLBEntry layout is not as critical as that of the
- * CPUTLBEntry. (This is also why we don't want to combine the two
- * structs into one.)
+/*
+ * The full TLB entry, which is not accessed by generated TCG code,
+ * so the layout is not as critical as that of CPUTLBEntry. This is
+ * also why we don't want to combine the two structs.
  */
-typedef struct CPUIOTLBEntry {
+typedef struct CPUTLBEntryFull {
 /*
- * @addr contains:
+ * @xlat_section contains:
  *  - in the lower TARGET_PAGE_BITS, a physical section number
  *  - with the lower TARGET_PAGE_BITS masked off, an offset which
  *must be added to the virtual address to obtain:
@@ -146,9 +147,9 @@ typedef struct CPUIOTLBEntry {
  *   number is PHYS_SECTION_NOTDIRTY or PHYS_SECTION_ROM)
  * + the offset within the target MemoryRegion (otherwise)
  */
-hwaddr addr;
+hwaddr xlat_section;
 MemTxAttrs attrs;
-} CPUIOTLBEntry;
+} CPUTLBEntryFull;
 
 /*
  * Data elements that are per MMU mode, minus the bits accessed by
@@ -172,9 +173,8 @@ typedef struct CPUTLBDesc {
 size_t vindex;
 /* The tlb victim table, in two parts.  */
 CPUTLBEntry vtable[CPU_VTLB_SIZE];
-CPUIOTLBEntry viotlb[CPU_VTLB_SIZE];
-/* The iotlb.  */
-CPUIOTLBEntry *iotlb;
+CPUTLBEntryFull vfulltlb[CPU_VTLB_SIZE];
+CPUTLBEntryFull *fulltlb;
 } CPUTLBDesc;
 
 /*
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index a46f3a654d..a37275bf8e 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -200,13 +200,13 @@ static void tlb_mmu_resize_locked(CPUTLBDesc *desc, 
CPUTLBDescFast *fast,
 }
 
 g_free(fast->table);
-g_free(desc->iotlb);
+g_free(desc->fulltlb);
 
 tlb_window_reset(desc, now, 0);
 /* desc->n_used_entries is cleared by the caller */
 fast->mask = (new_size - 1) << CPU_TLB_ENTRY_BITS;
 fast->table = g_try_new(CPUTLBEntry, new_size);
-desc->iotlb = g_try_new(CPUIOTLBEntry, new_size);
+desc->fulltlb = g_try_new(CPUTLBEntryFull, new_size);
 
 /*
  * If the allocations fail, try smaller sizes. We just freed some
@@ -215,7 +215,7 @@ static void tlb_mmu_resize_locked(CPUTLBDesc *desc, 
CPUTLBDescFast *fast,
  * allocations to fail though, so we progressively reduce the allocation
  * size, aborting if we cannot even allocate the smallest TLB we support.
  */
-while (fast->table == NULL || desc->iotlb == NULL) {
+while (fast->table == NULL || desc->fulltlb == NULL) {
 if (new_size == (1 << CPU_TLB_DYN_MIN_BITS)) {
 error_report("%s: %s", __func__, strerror(errno));
 abort();
@@ -224,9 +224,9 @@ static void tlb_mmu_resize_locked(CPUTLBDesc *desc, 
CPUTLBDescFast *fast,
 fast->mask = (new_size - 1) << CPU_TLB_ENTRY_BITS;
 
 g_free(fast->table);
-g_free(desc->iotlb);
+g_free(desc->fulltlb);
 fast->table = g_try_new(CPUTLBEntry, new_size);
-desc->iotlb = g_try_new(CPUIOTLBEntry, new_size);
+desc->fulltlb = g_try_new(CPUTLBEntryFull, new_size);
 }
 }
 
@@ -258,7 +258,7 @@ static void tlb_mmu_init(CPUTLBDesc *desc, CPUTLBDescFast 
*fast, int64_t now)
 desc->n_used_entries = 0;
 fast->mask = (n_entries - 1) << CPU_TLB_ENTRY_BITS;
 fast->table = g_new(CPUTLBEntry, n_entries);
-desc->iotlb = g_new(CPUIOTLBEntry, n_entries);
+desc->fulltlb = g_new(CPUTLBEntryFull, n_entries);
 tlb_mmu_flush_locked(desc, fast);
 }
 
@@ -299,7 +299,7 @@ void tlb_destroy(CPUState *cpu)
 CPUTLBDescFast *fast = &env_tlb(env)->f[i];
 
 g_free(fast->table);
-g_free(desc->iotlb);
+g_free(desc->fulltlb);
 }
 }
 
@@ -1219,7 +1219,7 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong 
vaddr,
 
 /* Evict the old entry into the victim tlb.  */
 copy_tlb_helper_locke

[PATCH 19/22] target/i386: Use gen_jmp_rel for gen_repz*

2022-08-22 Thread Richard Henderson
Subtract cur_insn_len to restart the current insn.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 10 ++
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 6d6c751c10..67c803263b 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -224,7 +224,6 @@ STUB_HELPER(wrmsr, TCGv_env env)
 
 static void gen_eob(DisasContext *s);
 static void gen_jr(DisasContext *s);
-static void gen_jmp(DisasContext *s, target_ulong eip);
 static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num);
 static void gen_jmp_rel(DisasContext *s, MemOp ot, int diff, int tb_num);
 static void gen_op(DisasContext *s1, int op, MemOp ot, int d);
@@ -1277,7 +1276,7 @@ static void gen_repz(DisasContext *s, MemOp ot,
 if (s->repz_opt) {
 gen_op_jz_ecx(s, s->aflag, l2);
 }
-gen_jmp(s, s->base.pc_next - s->cs_base);
+gen_jmp_rel(s, MO_32, -cur_insn_len(s), 0);
 }
 
 #define GEN_REPZ(op) \
@@ -1297,7 +1296,7 @@ static void gen_repz2(DisasContext *s, MemOp ot, int nz,
 if (s->repz_opt) {
 gen_op_jz_ecx(s, s->aflag, l2);
 }
-gen_jmp(s, s->base.pc_next - s->cs_base);
+gen_jmp_rel(s, MO_32, -cur_insn_len(s), 0);
 }
 
 #define GEN_REPZ2(op) \
@@ -2751,11 +2750,6 @@ static void gen_jmp_rel(DisasContext *s, MemOp ot, int 
diff, int tb_num)
 gen_jmp_tb(s, dest, tb_num);
 }
 
-static void gen_jmp(DisasContext *s, target_ulong eip)
-{
-gen_jmp_tb(s, eip, 0);
-}
-
 static inline void gen_ldq_env_A0(DisasContext *s, int offset)
 {
 tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEUQ);
-- 
2.34.1




[PATCH 10/14] target/i386: Reorg GET_HPHYS

2022-08-22 Thread Richard Henderson
Replace with PTE_HPHYS for the page table walk, and a direct call
to mmu_translate for the final stage2 translation.  Hoist the check
for HF2_NPT_MASK out to get_physical_address, which avoids the
recursive call when stage2 is disabled.

We can now return all the way out to x86_cpu_tlb_fill before raising
an exception, which means probe works.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/sysemu/excp_helper.c | 123 +--
 1 file changed, 95 insertions(+), 28 deletions(-)

diff --git a/target/i386/tcg/sysemu/excp_helper.c 
b/target/i386/tcg/sysemu/excp_helper.c
index a6b7562bf3..e9adaa3dad 100644
--- a/target/i386/tcg/sysemu/excp_helper.c
+++ b/target/i386/tcg/sysemu/excp_helper.c
@@ -37,18 +37,43 @@ typedef struct TranslateResult {
 int page_size;
 } TranslateResult;
 
+typedef enum TranslateFaultStage2 {
+S2_NONE,
+S2_GPA,
+S2_GPT,
+} TranslateFaultStage2;
+
 typedef struct TranslateFault {
 int exception_index;
 int error_code;
 target_ulong cr2;
+TranslateFaultStage2 stage2;
 } TranslateFault;
 
-#define GET_HPHYS(cs, gpa, access_type, prot)  \
-   (in->use_stage2 ? get_hphys(cs, gpa, access_type, prot) : gpa)
+#define PTE_HPHYS(ADDR) \
+do {\
+if (in->use_stage2) {   \
+nested_in.addr = (ADDR);\
+if (!mmu_translate(env, &nested_in, out, err)) {\
+err->stage2 = S2_GPT;   \
+return false;   \
+}   \
+(ADDR) = out->paddr;\
+}   \
+} while (0)
 
 static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
   TranslateResult *out, TranslateFault *err)
 {
+TranslateParams nested_in = {
+/* Use store for page table entries, to allow A/D flag updates. */
+.access_type = MMU_DATA_STORE,
+.cr3 = env->nested_cr3,
+.pg_mode = env->nested_pg_mode,
+.mmu_idx = MMU_USER_IDX,
+.use_stage2 = false,
+};
+
 CPUState *cs = env_cpu(env);
 X86CPU *cpu = env_archcpu(env);
 const int32_t a20_mask = x86_get_a20_mask(env);
@@ -79,7 +104,7 @@ static bool mmu_translate(CPUX86State *env, const 
TranslateParams *in,
 if (la57) {
 pml5e_addr = ((in->cr3 & ~0xfff) +
 (((addr >> 48) & 0x1ff) << 3)) & a20_mask;
-pml5e_addr = GET_HPHYS(cs, pml5e_addr, MMU_DATA_STORE, NULL);
+PTE_HPHYS(pml5e_addr);
 pml5e = x86_ldq_phys(cs, pml5e_addr);
 if (!(pml5e & PG_PRESENT_MASK)) {
 goto do_fault;
@@ -99,7 +124,7 @@ static bool mmu_translate(CPUX86State *env, const 
TranslateParams *in,
 
 pml4e_addr = ((pml5e & PG_ADDRESS_MASK) +
 (((addr >> 39) & 0x1ff) << 3)) & a20_mask;
-pml4e_addr = GET_HPHYS(cs, pml4e_addr, MMU_DATA_STORE, NULL);
+PTE_HPHYS(pml4e_addr);
 pml4e = x86_ldq_phys(cs, pml4e_addr);
 if (!(pml4e & PG_PRESENT_MASK)) {
 goto do_fault;
@@ -114,7 +139,7 @@ static bool mmu_translate(CPUX86State *env, const 
TranslateParams *in,
 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);
+PTE_HPHYS(pdpe_addr);
 pdpe = x86_ldq_phys(cs, pdpe_addr);
 if (!(pdpe & PG_PRESENT_MASK)) {
 goto do_fault;
@@ -140,7 +165,7 @@ static bool mmu_translate(CPUX86State *env, const 
TranslateParams *in,
 /* XXX: load them when cr3 is loaded ? */
 pdpe_addr = ((in->cr3 & ~0x1f) + ((addr >> 27) & 0x18)) &
 a20_mask;
-pdpe_addr = GET_HPHYS(cs, pdpe_addr, MMU_DATA_STORE, NULL);
+PTE_HPHYS(pdpe_addr);
 pdpe = x86_ldq_phys(cs, pdpe_addr);
 if (!(pdpe & PG_PRESENT_MASK)) {
 goto do_fault;
@@ -154,7 +179,7 @@ static bool mmu_translate(CPUX86State *env, const 
TranslateParams *in,
 
 pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) &
 a20_mask;
-pde_addr = GET_HPHYS(cs, pde_addr, MMU_DATA_STORE, NULL);
+PTE_HPHYS(pde_addr);
 pde = x86_ldq_phys(cs, pde_addr);
 if (!(pde & PG_PRESENT_MASK)) {
 goto do_fault;
@@ -177,7 +202,7 @@ static bool mmu_translate(CPUX86State *env, const 
TranslateParams *in,
 }
 pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) &
 a20_mask;
-pte_addr

[PATCH 16/22] target/i386: Create gen_jmp_rel

2022-08-22 Thread Richard Henderson
Create a common helper for pc-relative branches.
The jmp jb insn was missing a mask for CODE32.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 57 ++---
 1 file changed, 27 insertions(+), 30 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index cacd52c50f..0a2ec85972 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -226,6 +226,7 @@ static void gen_eob(DisasContext *s);
 static void gen_jr(DisasContext *s);
 static void gen_jmp(DisasContext *s, target_ulong eip);
 static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num);
+static void gen_jmp_rel(DisasContext *s, MemOp ot, int diff, int tb_num);
 static void gen_op(DisasContext *s1, int op, MemOp ot, int d);
 static void gen_exception_gpf(DisasContext *s);
 
@@ -1173,7 +1174,7 @@ static TCGLabel *gen_jz_ecx_string(DisasContext *s)
 TCGLabel *l2 = gen_new_label();
 gen_op_jnz_ecx(s, s->aflag, l1);
 gen_set_label(l2);
-gen_jmp_tb(s, s->pc - s->cs_base, 1);
+gen_jmp_rel(s, MO_32, 0, 1);
 gen_set_label(l1);
 return l2;
 }
@@ -2756,6 +2757,18 @@ static void gen_jmp_tb(DisasContext *s, target_ulong 
eip, int tb_num)
 }
 }
 
+static void gen_jmp_rel(DisasContext *s, MemOp ot, int diff, int tb_num)
+{
+target_ulong dest = s->pc - s->cs_base + diff;
+
+if (ot == MO_16) {
+dest &= 0x;
+} else if (!CODE64(s)) {
+dest &= 0x;
+}
+gen_jmp_tb(s, dest, tb_num);
+}
+
 static void gen_jmp(DisasContext *s, target_ulong eip)
 {
 gen_jmp_tb(s, eip, 0);
@@ -6703,20 +6716,12 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 break;
 case 0xe8: /* call im */
 {
-if (dflag != MO_16) {
-tval = (int32_t)insn_get(env, s, MO_32);
-} else {
-tval = (int16_t)insn_get(env, s, MO_16);
-}
-tval += s->pc - s->cs_base;
-if (dflag == MO_16) {
-tval &= 0x;
-} else if (!CODE64(s)) {
-tval &= 0x;
-}
+int diff = (dflag != MO_16
+? (int32_t)insn_get(env, s, MO_32)
+: (int16_t)insn_get(env, s, MO_16));
 gen_push_v(s, eip_next_tl(s));
 gen_bnd_jmp(s);
-gen_jmp(s, tval);
+gen_jmp_rel(s, dflag, diff, 0);
 }
 break;
 case 0x9a: /* lcall im */
@@ -6734,19 +6739,13 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 goto do_lcall;
 case 0xe9: /* jmp im */
-if (dflag != MO_16) {
-tval = (int32_t)insn_get(env, s, MO_32);
-} else {
-tval = (int16_t)insn_get(env, s, MO_16);
+{
+int diff = (dflag != MO_16
+? (int32_t)insn_get(env, s, MO_32)
+: (int16_t)insn_get(env, s, MO_16));
+gen_bnd_jmp(s);
+gen_jmp_rel(s, dflag, diff, 0);
 }
-tval += s->pc - s->cs_base;
-if (dflag == MO_16) {
-tval &= 0x;
-} else if (!CODE64(s)) {
-tval &= 0x;
-}
-gen_bnd_jmp(s);
-gen_jmp(s, tval);
 break;
 case 0xea: /* ljmp im */
 {
@@ -6763,12 +6762,10 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 goto do_ljmp;
 case 0xeb: /* jmp Jb */
-tval = (int8_t)insn_get(env, s, MO_8);
-tval += s->pc - s->cs_base;
-if (dflag == MO_16) {
-tval &= 0x;
+{
+int diff = (int8_t)insn_get(env, s, MO_8);
+gen_jmp_rel(s, dflag, diff, 0);
 }
-gen_jmp(s, tval);
 break;
 case 0x70 ... 0x7f: /* jcc Jb */
 tval = (int8_t)insn_get(env, s, MO_8);
-- 
2.34.1




[PATCH 15/22] target/i386: Use DISAS_TOO_MANY to exit after gen_io_start

2022-08-22 Thread Richard Henderson
We can set is_jmp early, using only one if, and let that
be overwritten by gen_repz_* etc.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 42 +
 1 file changed, 10 insertions(+), 32 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 47d6cd2fce..cacd52c50f 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -5492,14 +5492,12 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
+s->base.is_jmp = DISAS_TOO_MANY;
 }
 gen_helper_rdrand(s->T0, cpu_env);
 rm = (modrm & 7) | REX_B(s);
 gen_op_mov_reg_v(s, dflag, rm, s->T0);
 set_cc_op(s, CC_OP_EFLAGS);
-if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
-gen_jmp(s, s->pc - s->cs_base);
-}
 break;
 
 default:
@@ -6545,15 +6543,12 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
+s->base.is_jmp = DISAS_TOO_MANY;
 }
 if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
 gen_repz_ins(s, ot);
-/* jump generated by gen_repz_ins */
 } else {
 gen_ins(s, ot);
-if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
-gen_jmp(s, s->pc - s->cs_base);
-}
 }
 break;
 case 0x6e: /* outsS */
@@ -6566,15 +6561,12 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
+s->base.is_jmp = DISAS_TOO_MANY;
 }
 if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
 gen_repz_outs(s, ot);
-/* jump generated by gen_repz_outs */
 } else {
 gen_outs(s, ot);
-if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
-gen_jmp(s, s->pc - s->cs_base);
-}
 }
 break;
 
@@ -6591,13 +6583,11 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
+s->base.is_jmp = DISAS_TOO_MANY;
 }
 gen_helper_in_func(ot, s->T1, s->tmp2_i32);
 gen_op_mov_reg_v(s, ot, R_EAX, s->T1);
 gen_bpt_io(s, s->tmp2_i32, ot);
-if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
-gen_jmp(s, s->pc - s->cs_base);
-}
 break;
 case 0xe6:
 case 0xe7:
@@ -6609,14 +6599,12 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
+s->base.is_jmp = DISAS_TOO_MANY;
 }
 gen_op_mov_v_reg(s, ot, s->T1, R_EAX);
 tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1);
 gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32);
 gen_bpt_io(s, s->tmp2_i32, ot);
-if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
-gen_jmp(s, s->pc - s->cs_base);
-}
 break;
 case 0xec:
 case 0xed:
@@ -6628,13 +6616,11 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
+s->base.is_jmp = DISAS_TOO_MANY;
 }
 gen_helper_in_func(ot, s->T1, s->tmp2_i32);
 gen_op_mov_reg_v(s, ot, R_EAX, s->T1);
 gen_bpt_io(s, s->tmp2_i32, ot);
-if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
-gen_jmp(s, s->pc - s->cs_base);
-}
 break;
 case 0xee:
 case 0xef:
@@ -6646,14 +6632,12 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
+s->base.is_jmp = DISAS_TOO_MANY;
 }
 gen_op_mov_v_reg(s, ot, s->T1, R_EAX);
 tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1);
 gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32);
 gen_bpt_io(s, s->tmp2_i32, ot);
-if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
-gen_jmp(s, s->pc - s->cs_base);
-}
 break;
 
 //
@@ -7319,11 +7303,9 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_update_eip_cur(s);
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
+s->base.is_jmp = DISAS_TOO_MANY;
 }
 gen_helper_rdtsc(cpu_env);
-if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
-gen_jmp(s, s->pc - s->cs_base);
-}
 break;
 case 0x133: /* rdpmc */
 gen_update_cc_op(s);
@@ -7780,11 +7762,9 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_up

[PATCH 02/14] accel/tcg: Drop addr member from SavedIOTLB

2022-08-22 Thread Richard Henderson
This field is only written, not read; remove it.

Signed-off-by: Richard Henderson 
---
 include/hw/core/cpu.h | 1 -
 accel/tcg/cputlb.c| 7 +++
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 500503da13..9e47184513 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -218,7 +218,6 @@ struct CPUWatchpoint {
  * the memory regions get moved around  by io_writex.
  */
 typedef struct SavedIOTLB {
-hwaddr addr;
 MemoryRegionSection *section;
 hwaddr mr_offset;
 } SavedIOTLB;
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index a37275bf8e..1509df96b4 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1386,12 +1386,11 @@ static uint64_t io_readx(CPUArchState *env, 
CPUTLBEntryFull *full,
  * This is read by tlb_plugin_lookup if the fulltlb entry doesn't match
  * because of the side effect of io_writex changing memory layout.
  */
-static void save_iotlb_data(CPUState *cs, hwaddr addr,
-MemoryRegionSection *section, hwaddr mr_offset)
+static void save_iotlb_data(CPUState *cs, MemoryRegionSection *section,
+hwaddr mr_offset)
 {
 #ifdef CONFIG_PLUGIN
 SavedIOTLB *saved = &cs->saved_iotlb;
-saved->addr = addr;
 saved->section = section;
 saved->mr_offset = mr_offset;
 #endif
@@ -1420,7 +1419,7 @@ static void io_writex(CPUArchState *env, CPUTLBEntryFull 
*full,
  * The memory_region_dispatch may trigger a flush/resize
  * so for plugins we save the iotlb_data just in case.
  */
-save_iotlb_data(cpu, full->xlat_section, section, mr_offset);
+save_iotlb_data(cpu, section, mr_offset);
 
 if (!qemu_mutex_iothread_locked()) {
 qemu_mutex_lock_iothread();
-- 
2.34.1




[PATCH 20/22] target/i386: Use gen_jmp_rel for DISAS_TOO_MANY

2022-08-22 Thread Richard Henderson
With gen_jmp_rel, we may chain between two translation blocks
which may only be separated because of TB size limits.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 67c803263b..846040c1ab 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -8627,6 +8627,9 @@ static void i386_tr_tb_stop(DisasContextBase *dcbase, 
CPUState *cpu)
 case DISAS_NORETURN:
 break;
 case DISAS_TOO_MANY:
+gen_update_cc_op(dc);
+gen_jmp_rel(dc, MO_32, 0, 0);
+break;
 case DISAS_EOB_NEXT:
 gen_update_cc_op(dc);
 gen_update_eip_cur(dc);
-- 
2.34.1




[PATCH 09/22] target/i386: USe DISAS_EOB_ONLY

2022-08-22 Thread Richard Henderson
Replace lone calls to gen_eob() with the new enumerator.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 73e4330fc0..1dc3ff67ae 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -6687,7 +6687,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 /* add stack offset */
 gen_stack_update(s, val + (2 << dflag));
 }
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_ONLY;
 break;
 case 0xcb: /* lret */
 val = 0;
@@ -6705,7 +6705,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
   tcg_const_i32(s->pc - s->cs_base));
 }
 set_cc_op(s, CC_OP_EFLAGS);
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_ONLY;
 break;
 case 0xe8: /* call im */
 {
@@ -7291,7 +7291,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_set_label(l1);
 gen_jmp_im(s, tval);
 gen_set_label(l2);
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_ONLY;
 }
 break;
 case 0x130: /* wrmsr */
@@ -7332,7 +7332,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_exception_gpf(s);
 } else {
 gen_helper_sysenter(cpu_env);
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_ONLY;
 }
 break;
 case 0x135: /* sysexit */
@@ -7343,7 +7343,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_exception_gpf(s);
 } else {
 gen_helper_sysexit(cpu_env, tcg_const_i32(dflag - 1));
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_ONLY;
 }
 break;
 #ifdef TARGET_X86_64
@@ -8426,7 +8426,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_update_eip_next(s);
 gen_helper_rsm(cpu_env);
 #endif /* CONFIG_USER_ONLY */
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_ONLY;
 break;
 case 0x1b8: /* SSE4.2 popcnt */
 if ((prefixes & (PREFIX_REPZ | PREFIX_LOCK | PREFIX_REPNZ)) !=
-- 
2.34.1




[PATCH 22/22] target/i386: Enable TARGET_TB_PCREL

2022-08-22 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/i386/cpu-param.h |  1 +
 target/i386/tcg/tcg-cpu.c   |  8 ++--
 target/i386/tcg/translate.c | 86 ++---
 3 files changed, 77 insertions(+), 18 deletions(-)

diff --git a/target/i386/cpu-param.h b/target/i386/cpu-param.h
index 9740bd7abd..51a3f153bf 100644
--- a/target/i386/cpu-param.h
+++ b/target/i386/cpu-param.h
@@ -24,5 +24,6 @@
 #endif
 #define TARGET_PAGE_BITS 12
 #define NB_MMU_MODES 3
+#define TARGET_TB_PCREL 1
 
 #endif
diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c
index 76989a5a9d..74333247c5 100644
--- a/target/i386/tcg/tcg-cpu.c
+++ b/target/i386/tcg/tcg-cpu.c
@@ -49,9 +49,11 @@ static void x86_cpu_exec_exit(CPUState *cs)
 static void x86_cpu_synchronize_from_tb(CPUState *cs,
 const TranslationBlock *tb)
 {
-X86CPU *cpu = X86_CPU(cs);
-
-cpu->env.eip = tb_pc(tb) - tb->cs_base;
+/* The instruction pointer is always up to date with TARGET_TB_PCREL. */
+if (!TARGET_TB_PCREL) {
+CPUX86State *env = cs->env_ptr;
+env->eip = tb_pc(tb) - tb->cs_base;
+}
 }
 
 #ifndef CONFIG_USER_ONLY
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 6192a3e30e..5e252f26b2 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -64,6 +64,7 @@
 
 /* global register indexes */
 static TCGv cpu_cc_dst, cpu_cc_src, cpu_cc_src2;
+static TCGv cpu_eip;
 static TCGv_i32 cpu_cc_op;
 static TCGv cpu_regs[CPU_NB_REGS];
 static TCGv cpu_seg_base[6];
@@ -77,6 +78,7 @@ typedef struct DisasContext {
 
 target_ulong pc;   /* pc = eip + cs_base */
 target_ulong cs_base;  /* base of CS segment */
+target_ulong pc_save;
 
 MemOp aflag;
 MemOp dflag;
@@ -481,7 +483,7 @@ static void gen_add_A0_im(DisasContext *s, int val)
 
 static inline void gen_op_jmp_v(TCGv dest)
 {
-tcg_gen_st_tl(dest, cpu_env, offsetof(CPUX86State, eip));
+tcg_gen_mov_tl(cpu_eip, dest);
 }
 
 static inline
@@ -516,24 +518,36 @@ static inline void gen_op_st_rm_T0_A0(DisasContext *s, 
int idx, int d)
 }
 }
 
-static TCGv gen_eip_cur(DisasContext *s)
+static void gen_jmp_im(DisasContext *s, target_ulong eip)
 {
-return tcg_constant_tl(s->base.pc_next - s->cs_base);
-}
-
-static void gen_jmp_im(DisasContext *s, target_ulong pc)
-{
-gen_op_jmp_v(tcg_constant_tl(pc));
+if (TARGET_TB_PCREL) {
+target_ulong eip_save = s->pc_save - s->cs_base;
+tcg_gen_addi_tl(cpu_eip, cpu_eip, eip - eip_save);
+} else {
+tcg_gen_movi_tl(cpu_eip, eip);
+}
 }
 
 static void gen_update_eip_cur(DisasContext *s)
 {
 gen_jmp_im(s, s->base.pc_next - s->cs_base);
+s->pc_save = s->base.pc_next;
 }
 
 static void gen_update_eip_next(DisasContext *s)
 {
 gen_jmp_im(s, s->pc - s->cs_base);
+s->pc_save = s->pc;
+}
+
+static TCGv gen_eip_cur(DisasContext *s)
+{
+if (TARGET_TB_PCREL) {
+gen_update_eip_cur(s);
+return cpu_eip;
+} else {
+return tcg_constant_tl(s->base.pc_next - s->cs_base);
+}
 }
 
 static int cur_insn_len(DisasContext *s)
@@ -548,12 +562,25 @@ static TCGv_i32 cur_insn_len_i32(DisasContext *s)
 
 static TCGv_i32 eip_next_i32(DisasContext *s)
 {
-return tcg_constant_i32(s->pc - s->cs_base);
+if (TARGET_TB_PCREL) {
+TCGv_i32 ret = tcg_temp_new_i32();
+tcg_gen_trunc_tl_i32(ret, cpu_eip);
+tcg_gen_addi_i32(ret, ret, s->pc - s->pc_save);
+return ret;
+} else {
+return tcg_constant_i32(s->pc - s->cs_base);
+}
 }
 
 static TCGv eip_next_tl(DisasContext *s)
 {
-return tcg_constant_tl(s->pc - s->cs_base);
+if (TARGET_TB_PCREL) {
+TCGv ret = tcg_temp_new();
+tcg_gen_addi_tl(ret, cpu_eip, s->pc - s->pc_save);
+return ret;
+} else {
+return tcg_constant_tl(s->pc - s->cs_base);
+}
 }
 
 /* Compute SEG:REG into A0.  SEG is selected from the override segment
@@ -2252,7 +2279,12 @@ static TCGv gen_lea_modrm_1(DisasContext *s, 
AddressParts a)
 ea = cpu_regs[a.base];
 }
 if (!ea) {
-tcg_gen_movi_tl(s->A0, a.disp);
+if (TARGET_TB_PCREL && a.base == -2) {
+/* With cpu_eip ~= pc_save, the expression is pc-relative. */
+tcg_gen_addi_tl(s->A0, cpu_eip, a.disp - s->pc_save);
+} else {
+tcg_gen_movi_tl(s->A0, a.disp);
+}
 ea = s->A0;
 } else if (a.disp != 0) {
 tcg_gen_addi_tl(s->A0, ea, a.disp);
@@ -2366,8 +2398,13 @@ static void gen_goto_tb(DisasContext *s, int tb_num, 
target_ulong eip)
 
 if (translator_use_goto_tb(&s->base, pc))  {
 /* jump to same page: we can use a direct jump */
-tcg_gen_goto_tb(tb_num);
-gen_jmp_im(s, eip);
+if (TARGET_TB_PCREL) {
+gen_jmp_im(s, eip);
+tcg_gen_goto_tb(tb_num);
+} else {
+tcg_gen_goto_tb(tb_num);
+gen_jmp_im(s, eip);
+}

[PATCH 14/22] target/i386: Create eip_next_*

2022-08-22 Thread Richard Henderson
Create helpers for loading the address of the next insn.
Use tcg_constant_* in adjacent code where convenient.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 44 +++--
 1 file changed, 23 insertions(+), 21 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 13577f5d7b..47d6cd2fce 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -541,6 +541,16 @@ static TCGv_i32 cur_insn_len_i32(DisasContext *s)
 return tcg_constant_i32(cur_insn_len(s));
 }
 
+static TCGv_i32 eip_next_i32(DisasContext *s)
+{
+return tcg_constant_i32(s->pc - s->cs_base);
+}
+
+static TCGv eip_next_tl(DisasContext *s)
+{
+return tcg_constant_tl(s->pc - s->cs_base);
+}
+
 /* Compute SEG:REG into A0.  SEG is selected from the override segment
(OVR_SEG) and the default segment (DEF_SEG).  OVR_SEG may be -1 to
indicate no override.  */
@@ -1213,12 +1223,9 @@ static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, 
int ot)
 /* 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);
-
+TCGv_i32 t_size = tcg_constant_i32(1 << ot);
+TCGv t_next = eip_next_tl(s);
 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 */
 }
 }
@@ -5167,9 +5174,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 if (dflag == MO_16) {
 tcg_gen_ext16u_tl(s->T0, s->T0);
 }
-next_eip = s->pc - s->cs_base;
-tcg_gen_movi_tl(s->T1, next_eip);
-gen_push_v(s, s->T1);
+gen_push_v(s, eip_next_tl(s));
 gen_op_jmp_v(s->T0);
 gen_bnd_jmp(s);
 s->base.is_jmp = DISAS_JUMP;
@@ -5185,14 +5190,14 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 if (PE(s) && !VM86(s)) {
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 gen_helper_lcall_protected(cpu_env, s->tmp2_i32, s->T1,
-   tcg_const_i32(dflag - 1),
-   tcg_const_tl(s->pc - s->cs_base));
+   tcg_constant_i32(dflag - 1),
+   eip_next_tl(s));
 } else {
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1);
 gen_helper_lcall_real(cpu_env, s->tmp2_i32, s->tmp3_i32,
-  tcg_const_i32(dflag - 1),
-  tcg_const_i32(s->pc - s->cs_base));
+  tcg_constant_i32(dflag - 1),
+  eip_next_i32(s));
 }
 s->base.is_jmp = DISAS_JUMP;
 break;
@@ -5215,7 +5220,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 if (PE(s) && !VM86(s)) {
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 gen_helper_ljmp_protected(cpu_env, s->tmp2_i32, s->T1,
-  tcg_const_tl(s->pc - s->cs_base));
+  eip_next_tl(s));
 } else {
 gen_op_movl_seg_T0_vm(s, R_CS);
 gen_op_jmp_v(s->T1);
@@ -6706,8 +6711,8 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 gen_helper_iret_real(cpu_env, tcg_const_i32(dflag - 1));
 } else {
-gen_helper_iret_protected(cpu_env, tcg_const_i32(dflag - 1),
-  tcg_const_i32(s->pc - s->cs_base));
+gen_helper_iret_protected(cpu_env, tcg_constant_i32(dflag - 1),
+  eip_next_i32(s));
 }
 set_cc_op(s, CC_OP_EFLAGS);
 s->base.is_jmp = DISAS_EOB_ONLY;
@@ -6719,15 +6724,13 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 } else {
 tval = (int16_t)insn_get(env, s, MO_16);
 }
-next_eip = s->pc - s->cs_base;
-tval += next_eip;
+tval += s->pc - s->cs_base;
 if (dflag == MO_16) {
 tval &= 0x;
 } else if (!CODE64(s)) {
 tval &= 0x;
 }
-tcg_gen_movi_tl(s->T0, next_eip);
-gen_push_v(s, s->T0);
+gen_push_v(s, eip_next_tl(s));
 gen_bnd_jmp(s);
 gen_jmp(s, tval);
 }
@@ -7261,8 +7264,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 TCGLabel *l1, *l2, *l3;
 
 tval = (int8_t)insn_get(env, s, MO_8);
-next_eip = s->pc - s->cs_base;
-tval += next_eip;
+tval

[PATCH 10/22] target/i386: Create cur_insn_len, cur_insn_len_i32

2022-08-22 Thread Richard Henderson
Create common routines for computing the length of the insn.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 31 +++
 1 file changed, 19 insertions(+), 12 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 1dc3ff67ae..ee8e87a617 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -530,6 +530,16 @@ static void gen_update_eip_next(DisasContext *s)
 gen_jmp_im(s, s->pc - s->cs_base);
 }
 
+static int cur_insn_len(DisasContext *s)
+{
+return s->pc - s->base.pc_next;
+}
+
+static TCGv_i32 cur_insn_len_i32(DisasContext *s)
+{
+return tcg_constant_i32(cur_insn_len(s));
+}
+
 /* Compute SEG:REG into A0.  SEG is selected from the override segment
(OVR_SEG) and the default segment (DEF_SEG).  OVR_SEG may be -1 to
indicate no override.  */
@@ -712,9 +722,6 @@ static bool gen_check_io(DisasContext *s, MemOp ot, 
TCGv_i32 port,
 gen_helper_check_io(cpu_env, port, tcg_constant_i32(1 << ot));
 }
 if (GUEST(s)) {
-target_ulong cur_eip = s->base.pc_next - s->cs_base;
-target_ulong next_eip = s->pc - s->cs_base;
-
 gen_update_cc_op(s);
 gen_update_eip_cur(s);
 if (s->prefix & (PREFIX_REPZ | PREFIX_REPNZ)) {
@@ -723,7 +730,7 @@ static bool gen_check_io(DisasContext *s, MemOp ot, 
TCGv_i32 port,
 svm_flags |= 1 << (SVM_IOIO_SIZE_SHIFT + ot);
 gen_helper_svm_check_io(cpu_env, port,
 tcg_constant_i32(svm_flags),
-tcg_constant_i32(next_eip - cur_eip));
+cur_insn_len_i32(s));
 }
 return true;
 #endif
@@ -2028,7 +2035,7 @@ static uint64_t advance_pc(CPUX86State *env, DisasContext 
*s, int num_bytes)
 }
 
 s->pc += num_bytes;
-if (unlikely(s->pc - s->base.pc_next > X86_MAX_INSN_LENGTH)) {
+if (unlikely(cur_insn_len(s) > X86_MAX_INSN_LENGTH)) {
 /* If the instruction's 16th byte is on a different page than the 1st, 
a
  * page fault on the second page wins over the general protection fault
  * caused by the instruction being too long.
@@ -2622,7 +2629,7 @@ static void gen_interrupt(DisasContext *s, int intno)
 gen_update_cc_op(s);
 gen_update_eip_cur(s);
 gen_helper_raise_interrupt(cpu_env, tcg_constant_i32(intno),
-   tcg_constant_i32(s->pc - s->base.pc_next));
+   cur_insn_len_i32(s));
 s->base.is_jmp = DISAS_NORETURN;
 }
 
@@ -7166,7 +7173,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 if (prefixes & PREFIX_REPZ) {
 gen_update_cc_op(s);
 gen_update_eip_cur(s);
-gen_helper_pause(cpu_env, tcg_const_i32(s->pc - s->base.pc_next));
+gen_helper_pause(cpu_env, cur_insn_len_i32(s));
 s->base.is_jmp = DISAS_NORETURN;
 }
 break;
@@ -7192,7 +7199,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 goto illegal_op;
 gen_update_cc_op(s);
 gen_update_eip_cur(s);
-gen_helper_into(cpu_env, tcg_const_i32(s->pc - s->base.pc_next));
+gen_helper_into(cpu_env, cur_insn_len_i32(s));
 break;
 #ifdef WANT_ICEBP
 case 0xf1: /* icebp (undocumented, exits to external debugger) */
@@ -7351,7 +7358,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 /* XXX: is it usable in real mode ? */
 gen_update_cc_op(s);
 gen_update_eip_cur(s);
-gen_helper_syscall(cpu_env, tcg_const_i32(s->pc - s->base.pc_next));
+gen_helper_syscall(cpu_env, cur_insn_len_i32(s));
 /* TF handling for the syscall insn is different. The TF bit is  
checked
after the syscall insn completes. This allows #DB to not be
generated after one has entered CPL0 if TF is set in FMASK.  */
@@ -7383,7 +7390,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 if (check_cpl0(s)) {
 gen_update_cc_op(s);
 gen_update_eip_cur(s);
-gen_helper_hlt(cpu_env, tcg_const_i32(s->pc - s->base.pc_next));
+gen_helper_hlt(cpu_env, cur_insn_len_i32(s));
 s->base.is_jmp = DISAS_NORETURN;
 }
 break;
@@ -7492,7 +7499,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 gen_update_cc_op(s);
 gen_update_eip_cur(s);
-gen_helper_mwait(cpu_env, tcg_const_i32(s->pc - s->base.pc_next));
+gen_helper_mwait(cpu_env, cur_insn_len_i32(s));
 s->base.is_jmp = DISAS_NORETURN;
 break;
 
@@ -7568,7 +7575,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_update_cc_op(s);
 gen_update_eip_cur(s);
 gen_helper_vmrun(cpu_env, tcg_const_i32(s->aflag - 1),
- tcg_const_i32(s->pc - s->base.pc_next));
+ cur_

[PATCH 01/22] target/i386: Return bool from disas_insn

2022-08-22 Thread Richard Henderson
Instead of returning the new pc, which is present in
DisasContext, return true if an insn was translated.
This is false when we detect a page crossing and must
undo the insn under translation.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 42 +++--
 1 file changed, 22 insertions(+), 20 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index a9a9a9de6e..2bdbfc6ddf 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -4552,7 +4552,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b)
 
 /* convert one instruction. s->base.is_jmp is set if the translation must
be stopped. Return the next pc value */
-static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
+static bool disas_insn(DisasContext *s, CPUState *cpu)
 {
 CPUX86State *env = cpu->env_ptr;
 int b, prefixes;
@@ -4582,12 +4582,13 @@ static target_ulong disas_insn(DisasContext *s, 
CPUState *cpu)
 return s->pc;
 case 2:
 /* Restore state that may affect the next instruction. */
+s->pc = s->base.pc_next;
 s->cc_op_dirty = orig_cc_op_dirty;
 s->cc_op = orig_cc_op;
 s->base.num_insns--;
 tcg_remove_ops_after(s->prev_insn_end);
 s->base.is_jmp = DISAS_TOO_MANY;
-return s->base.pc_next;
+return false;
 default:
 g_assert_not_reached();
 }
@@ -8496,13 +8497,13 @@ static target_ulong disas_insn(DisasContext *s, 
CPUState *cpu)
 default:
 goto unknown_op;
 }
-return s->pc;
+return true;
  illegal_op:
 gen_illegal_opcode(s);
-return s->pc;
+return true;
  unknown_op:
 gen_unknown_opcode(env, s);
-return s->pc;
+return true;
 }
 
 void tcg_x86_init(void)
@@ -8667,7 +8668,6 @@ static void i386_tr_insn_start(DisasContextBase *dcbase, 
CPUState *cpu)
 static void i386_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
 {
 DisasContext *dc = container_of(dcbase, DisasContext, base);
-target_ulong pc_next;
 
 #ifdef TARGET_VSYSCALL_PAGE
 /*
@@ -8680,21 +8680,23 @@ static void i386_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cpu)
 }
 #endif
 
-pc_next = disas_insn(dc, cpu);
-dc->base.pc_next = pc_next;
+if (disas_insn(dc, cpu)) {
+target_ulong pc_next = dc->pc;
+dc->base.pc_next = pc_next;
 
-if (dc->base.is_jmp == DISAS_NEXT) {
-if (dc->flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK)) {
-/*
- * If single step mode, we generate only one instruction and
- * generate an exception.
- * If irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
- * the flag and abort the translation to give the irqs a
- * chance to happen.
- */
-dc->base.is_jmp = DISAS_TOO_MANY;
-} else if (!is_same_page(&dc->base, pc_next)) {
-dc->base.is_jmp = DISAS_TOO_MANY;
+if (dc->base.is_jmp == DISAS_NEXT) {
+if (dc->flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK)) {
+/*
+ * If single step mode, we generate only one instruction and
+ * generate an exception.
+ * If irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
+ * the flag and abort the translation to give the irqs a
+ * chance to happen.
+ */
+dc->base.is_jmp = DISAS_TOO_MANY;
+} else if (!is_same_page(&dc->base, pc_next)) {
+dc->base.is_jmp = DISAS_TOO_MANY;
+}
 }
 }
 }
-- 
2.34.1




[PATCH 21/22] target/i386: Create gen_eip_cur

2022-08-22 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 846040c1ab..6192a3e30e 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -516,6 +516,11 @@ static inline void gen_op_st_rm_T0_A0(DisasContext *s, int 
idx, int d)
 }
 }
 
+static TCGv gen_eip_cur(DisasContext *s)
+{
+return tcg_constant_tl(s->base.pc_next - s->cs_base);
+}
+
 static void gen_jmp_im(DisasContext *s, target_ulong pc)
 {
 gen_op_jmp_v(tcg_constant_tl(pc));
@@ -6461,7 +6466,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
offsetof(CPUX86State, segs[R_CS].selector));
 tcg_gen_st16_i32(s->tmp2_i32, cpu_env,
  offsetof(CPUX86State, fpcs));
-tcg_gen_st_tl(tcg_constant_tl(s->base.pc_next - s->cs_base),
+tcg_gen_st_tl(gen_eip_cur(s),
   cpu_env, offsetof(CPUX86State, fpip));
 }
 }
-- 
2.34.1




[PATCH 13/22] target/i386: Truncate values for lcall_real to i32

2022-08-22 Thread Richard Henderson
Use i32 not int or tl for eip and cs arguments.

Signed-off-by: Richard Henderson 
---
 target/i386/helper.h | 2 +-
 target/i386/tcg/seg_helper.c | 6 ++
 target/i386/tcg/translate.c  | 3 ++-
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/target/i386/helper.h b/target/i386/helper.h
index ac3b4d1ee3..39a3c24182 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -37,7 +37,7 @@ DEF_HELPER_2(lldt, void, env, int)
 DEF_HELPER_2(ltr, void, env, int)
 DEF_HELPER_3(load_seg, void, env, int, int)
 DEF_HELPER_4(ljmp_protected, void, env, int, tl, tl)
-DEF_HELPER_5(lcall_real, void, env, int, tl, int, int)
+DEF_HELPER_5(lcall_real, void, env, i32, i32, int, i32)
 DEF_HELPER_5(lcall_protected, void, env, int, tl, int, tl)
 DEF_HELPER_2(iret_real, void, env, int)
 DEF_HELPER_3(iret_protected, void, env, int, int)
diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c
index bffd82923f..539189b4d1 100644
--- a/target/i386/tcg/seg_helper.c
+++ b/target/i386/tcg/seg_helper.c
@@ -1504,14 +1504,12 @@ void helper_ljmp_protected(CPUX86State *env, int 
new_cs, target_ulong new_eip,
 }
 
 /* real mode call */
-void helper_lcall_real(CPUX86State *env, int new_cs, target_ulong new_eip1,
-   int shift, int next_eip)
+void helper_lcall_real(CPUX86State *env, uint32_t new_cs, uint32_t new_eip,
+   int shift, uint32_t next_eip)
 {
-int new_eip;
 uint32_t esp, esp_mask;
 target_ulong ssp;
 
-new_eip = new_eip1;
 esp = env->regs[R_ESP];
 esp_mask = get_sp_mask(env->segs[R_SS].flags);
 ssp = env->segs[R_SS].base;
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 367a7a335a..13577f5d7b 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -5189,7 +5189,8 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
tcg_const_tl(s->pc - s->cs_base));
 } else {
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
-gen_helper_lcall_real(cpu_env, s->tmp2_i32, s->T1,
+tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1);
+gen_helper_lcall_real(cpu_env, s->tmp2_i32, s->tmp3_i32,
   tcg_const_i32(dflag - 1),
   tcg_const_i32(s->pc - s->cs_base));
 }
-- 
2.34.1




[PATCH 05/22] target/i386: Create gen_update_eip_next

2022-08-22 Thread Richard Henderson
Sync EIP before exiting a translation block.
Replace all gen_jmp_im that use s->pc.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 45 -
 1 file changed, 25 insertions(+), 20 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 78b7641786..36883410e0 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -521,6 +521,11 @@ static void gen_update_eip_cur(DisasContext *s)
 gen_jmp_im(s, s->base.pc_next - s->cs_base);
 }
 
+static void gen_update_eip_next(DisasContext *s)
+{
+gen_jmp_im(s, s->pc - s->cs_base);
+}
+
 /* Compute SEG:REG into A0.  SEG is selected from the override segment
(OVR_SEG) and the default segment (DEF_SEG).  OVR_SEG may be -1 to
indicate no override.  */
@@ -5562,7 +5567,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_pop_update(s, ot);
 /* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp.  */
 if (s->base.is_jmp) {
-gen_jmp_im(s, s->pc - s->cs_base);
+gen_update_eip_next(s);
 if (reg == R_SS) {
 s->flags &= ~HF_TF_MASK;
 gen_eob_inhibit_irq(s, true);
@@ -5577,7 +5582,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_movl_seg_T0(s, (b >> 3) & 7);
 gen_pop_update(s, ot);
 if (s->base.is_jmp) {
-gen_jmp_im(s, s->pc - s->cs_base);
+gen_update_eip_next(s);
 gen_eob(s);
 }
 break;
@@ -5628,7 +5633,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_movl_seg_T0(s, reg);
 /* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp.  */
 if (s->base.is_jmp) {
-gen_jmp_im(s, s->pc - s->cs_base);
+gen_update_eip_next(s);
 if (reg == R_SS) {
 s->flags &= ~HF_TF_MASK;
 gen_eob_inhibit_irq(s, true);
@@ -5835,7 +5840,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 /* then put the data */
 gen_op_mov_reg_v(s, ot, reg, s->T1);
 if (s->base.is_jmp) {
-gen_jmp_im(s, s->pc - s->cs_base);
+gen_update_eip_next(s);
 gen_eob(s);
 }
 break;
@@ -6891,7 +6896,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_pop_update(s, ot);
 set_cc_op(s, CC_OP_EFLAGS);
 /* abort translation because TF/AC flag may change */
-gen_jmp_im(s, s->pc - s->cs_base);
+gen_update_eip_next(s);
 gen_eob(s);
 }
 break;
@@ -7227,7 +7232,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 if (check_iopl(s)) {
 gen_helper_sti(cpu_env);
 /* interruptions are enabled only the first insn after sti */
-gen_jmp_im(s, s->pc - s->cs_base);
+gen_update_eip_next(s);
 gen_eob_inhibit_irq(s, true);
 }
 break;
@@ -7303,7 +7308,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 
 gen_set_label(l3);
-gen_jmp_im(s, next_eip);
+gen_update_eip_next(s);
 tcg_gen_br(l2);
 
 gen_set_label(l1);
@@ -7321,7 +7326,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_helper_rdmsr(cpu_env);
 } else {
 gen_helper_wrmsr(cpu_env);
-gen_jmp_im(s, s->pc - s->cs_base);
+gen_update_eip_next(s);
 gen_eob(s);
 }
 }
@@ -7521,7 +7526,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 goto illegal_op;
 }
 gen_helper_clac(cpu_env);
-gen_jmp_im(s, s->pc - s->cs_base);
+gen_update_eip_next(s);
 gen_eob(s);
 break;
 
@@ -7531,7 +7536,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 goto illegal_op;
 }
 gen_helper_stac(cpu_env);
-gen_jmp_im(s, s->pc - s->cs_base);
+gen_update_eip_next(s);
 gen_eob(s);
 break;
 
@@ -7576,7 +7581,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]);
 gen_helper_xsetbv(cpu_env, s->tmp2_i32, s->tmp1_i64);
 /* End TB because translation flags may change.  */
-gen_jmp_im(s, s->pc - s->cs_base);
+gen_update_eip_next(s);
 gen_eob(s);
 break;
 
@@ -7638,7 +7643,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 gen_update_cc_op(s);
 gen_helper_stgi(cpu_env);
-gen_jmp_im(s, s->pc - s->cs_base);
+gen_update_eip_next(s);
 gen_eob(s);
 break;
 
@@ -7677,7 +7682,7 @@ static bool disas_insn(DisasContext *s,

[PATCH v3 17/17] target/arm: Enable TARGET_TB_PCREL

2022-08-22 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/arm/cpu-param.h |  2 ++
 target/arm/translate.h |  6 
 target/arm/cpu.c   | 23 +++---
 target/arm/translate-a64.c | 37 ++-
 target/arm/translate.c | 62 ++
 5 files changed, 100 insertions(+), 30 deletions(-)

diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h
index 68ffb12427..ef62371d8f 100644
--- a/target/arm/cpu-param.h
+++ b/target/arm/cpu-param.h
@@ -34,4 +34,6 @@
 
 #define NB_MMU_MODES 15
 
+#define TARGET_TB_PCREL 1
+
 #endif
diff --git a/target/arm/translate.h b/target/arm/translate.h
index d42059aa1d..7717ea3f45 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -12,6 +12,12 @@ typedef struct DisasContext {
 
 /* The address of the current instruction being translated. */
 target_ulong pc_curr;
+/*
+ * For TARGET_TB_PCREL, the value relative to pc_curr against which
+ * offsets must be computed for cpu_pc.  -1 if unknown due to jump.
+ */
+target_ulong pc_save;
+target_ulong pc_cond_save;
 target_ulong page_start;
 uint32_t insn;
 /* Nonzero if this instruction has been conditionally skipped.  */
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 047bf3f4ab..f5e74b6c3b 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -64,17 +64,18 @@ static void arm_cpu_set_pc(CPUState *cs, vaddr value)
 void arm_cpu_synchronize_from_tb(CPUState *cs,
  const TranslationBlock *tb)
 {
-ARMCPU *cpu = ARM_CPU(cs);
-CPUARMState *env = &cpu->env;
-
-/*
- * It's OK to look at env for the current mode here, because it's
- * never possible for an AArch64 TB to chain to an AArch32 TB.
- */
-if (is_a64(env)) {
-env->pc = tb_pc(tb);
-} else {
-env->regs[15] = tb_pc(tb);
+/* The program counter is always up to date with TARGET_TB_PCREL. */
+if (!TARGET_TB_PCREL) {
+CPUARMState *env = cs->env_ptr;
+/*
+ * It's OK to look at env for the current mode here, because it's
+ * never possible for an AArch64 TB to chain to an AArch32 TB.
+ */
+if (is_a64(env)) {
+env->pc = tb_pc(tb);
+} else {
+env->regs[15] = tb_pc(tb);
+}
 }
 }
 #endif /* CONFIG_TCG */
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 322a09c503..a433189722 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -150,12 +150,18 @@ static void reset_btype(DisasContext *s)
 
 static void gen_pc_plus_diff(DisasContext *s, TCGv_i64 dest, int diff)
 {
-tcg_gen_movi_i64(dest, s->pc_curr + diff);
+assert(s->pc_save != -1);
+if (TARGET_TB_PCREL) {
+tcg_gen_addi_i64(dest, cpu_pc, (s->pc_curr - s->pc_save) + diff);
+} else {
+tcg_gen_movi_i64(dest, s->pc_curr + diff);
+}
 }
 
 void gen_a64_update_pc(DisasContext *s, int diff)
 {
 gen_pc_plus_diff(s, cpu_pc, diff);
+s->pc_save = s->pc_curr + diff;
 }
 
 /*
@@ -209,6 +215,7 @@ static void gen_a64_set_pc(DisasContext *s, TCGv_i64 src)
  * then loading an address into the PC will clear out any tag.
  */
 gen_top_byte_ignore(s, cpu_pc, src, s->tbii);
+s->pc_save = -1;
 }
 
 /*
@@ -347,16 +354,22 @@ static void gen_exception_internal(int excp)
 
 static void gen_exception_internal_insn(DisasContext *s, int pc_diff, int excp)
 {
+target_ulong pc_save = s->pc_save;
+
 gen_a64_update_pc(s, pc_diff);
 gen_exception_internal(excp);
 s->base.is_jmp = DISAS_NORETURN;
+s->pc_save = pc_save;
 }
 
 static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syndrome)
 {
+target_ulong pc_save = s->pc_save;
+
 gen_a64_update_pc(s, 0);
 gen_helper_exception_bkpt_insn(cpu_env, tcg_constant_i32(syndrome));
 s->base.is_jmp = DISAS_NORETURN;
+s->pc_save = pc_save;
 }
 
 static void gen_step_complete_exception(DisasContext *s)
@@ -385,11 +398,16 @@ static inline bool use_goto_tb(DisasContext *s, uint64_t 
dest)
 
 static void gen_goto_tb(DisasContext *s, int n, int diff)
 {
-uint64_t dest = s->pc_curr + diff;
+target_ulong pc_save = s->pc_save;
 
-if (use_goto_tb(s, dest)) {
-tcg_gen_goto_tb(n);
-gen_a64_update_pc(s, diff);
+if (use_goto_tb(s, s->pc_curr + diff)) {
+if (TARGET_TB_PCREL) {
+gen_a64_update_pc(s, diff);
+tcg_gen_goto_tb(n);
+} else {
+tcg_gen_goto_tb(n);
+gen_a64_update_pc(s, diff);
+}
 tcg_gen_exit_tb(s->base.tb, n);
 s->base.is_jmp = DISAS_NORETURN;
 } else {
@@ -401,6 +419,7 @@ static void gen_goto_tb(DisasContext *s, int n, int diff)
 s->base.is_jmp = DISAS_NORETURN;
 }
 }
+s->pc_save = pc_save;
 }
 
 static void init_tmp_a64_array(DisasContext *s)
@@ -14717,7 +14736,7 @@ static void 
aarch64_tr_init_disas_context(DisasContextBase *dcbase,
 
 dc-

[PATCH 18/22] target/i386: Use gen_jmp_rel for gen_jcc

2022-08-22 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 57 -
 1 file changed, 18 insertions(+), 39 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 59e7596629..6d6c751c10 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -2373,32 +2373,14 @@ static void gen_goto_tb(DisasContext *s, int tb_num, 
target_ulong eip)
 }
 }
 
-static inline void gen_jcc(DisasContext *s, int b,
-   target_ulong val, target_ulong next_eip)
+static void gen_jcc(DisasContext *s, MemOp ot, int b, int diff)
 {
-TCGLabel *l1, *l2;
+TCGLabel *l1 = gen_new_label();
 
-if (s->jmp_opt) {
-l1 = gen_new_label();
-gen_jcc1(s, b, l1);
-
-gen_goto_tb(s, 0, next_eip);
-
-gen_set_label(l1);
-gen_goto_tb(s, 1, val);
-} else {
-l1 = gen_new_label();
-l2 = gen_new_label();
-gen_jcc1(s, b, l1);
-
-gen_jmp_im(s, next_eip);
-tcg_gen_br(l2);
-
-gen_set_label(l1);
-gen_jmp_im(s, val);
-gen_set_label(l2);
-gen_eob(s);
-}
+gen_jcc1(s, b, l1);
+gen_jmp_rel(s, ot, 0, 1);
+gen_set_label(l1);
+gen_jmp_rel(s, ot, diff, 0);
 }
 
 static void gen_cmovcc1(CPUX86State *env, DisasContext *s, MemOp ot, int b,
@@ -4608,7 +4590,6 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 int shift;
 MemOp ot, aflag, dflag;
 int modrm, reg, rm, mod, op, opreg, val;
-target_ulong next_eip, tval;
 bool orig_cc_op_dirty = s->cc_op_dirty;
 CCOp orig_cc_op = s->cc_op;
 
@@ -6768,22 +6749,20 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 break;
 case 0x70 ... 0x7f: /* jcc Jb */
-tval = (int8_t)insn_get(env, s, MO_8);
-goto do_jcc;
+{
+int diff = (int8_t)insn_get(env, s, MO_8);
+gen_bnd_jmp(s);
+gen_jcc(s, dflag, b, diff);
+}
+break;
 case 0x180 ... 0x18f: /* jcc Jv */
-if (dflag != MO_16) {
-tval = (int32_t)insn_get(env, s, MO_32);
-} else {
-tval = (int16_t)insn_get(env, s, MO_16);
+{
+int diff = (dflag != MO_16
+? (int32_t)insn_get(env, s, MO_32)
+: (int16_t)insn_get(env, s, MO_16));
+gen_bnd_jmp(s);
+gen_jcc(s, dflag, b, diff);
 }
-do_jcc:
-next_eip = s->pc - s->cs_base;
-tval += next_eip;
-if (dflag == MO_16) {
-tval &= 0x;
-}
-gen_bnd_jmp(s);
-gen_jcc(s, b, tval, next_eip);
 break;
 
 case 0x190 ... 0x19f: /* setcc Gv */
-- 
2.34.1




[PATCH 08/22] target/i386: Use DISAS_EOB_NEXT

2022-08-22 Thread Richard Henderson
Replace sequences of gen_update_cc_op, gen_update_eip_next,
and gen_eob with the new is_jmp enumerator.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 40 -
 1 file changed, 13 insertions(+), 27 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 4dc8f4c1f8..73e4330fc0 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -6874,8 +6874,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_pop_update(s, ot);
 set_cc_op(s, CC_OP_EFLAGS);
 /* abort translation because TF/AC flag may change */
-gen_update_eip_next(s);
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_NEXT;
 }
 break;
 case 0x9e: /* sahf */
@@ -7304,8 +7303,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_helper_rdmsr(cpu_env);
 } else {
 gen_helper_wrmsr(cpu_env);
-gen_update_eip_next(s);
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_NEXT;
 }
 }
 break;
@@ -7504,8 +7502,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 goto illegal_op;
 }
 gen_helper_clac(cpu_env);
-gen_update_eip_next(s);
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_NEXT;
 break;
 
 case 0xcb: /* stac */
@@ -7514,8 +7511,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 goto illegal_op;
 }
 gen_helper_stac(cpu_env);
-gen_update_eip_next(s);
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_NEXT;
 break;
 
 CASE_MODRM_MEM_OP(1): /* sidt */
@@ -7559,8 +7555,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]);
 gen_helper_xsetbv(cpu_env, s->tmp2_i32, s->tmp1_i64);
 /* End TB because translation flags may change.  */
-gen_update_eip_next(s);
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_NEXT;
 break;
 
 case 0xd8: /* VMRUN */
@@ -7621,8 +7616,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 gen_update_cc_op(s);
 gen_helper_stgi(cpu_env);
-gen_update_eip_next(s);
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_NEXT;
 break;
 
 case 0xdd: /* CLGI */
@@ -7660,8 +7654,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 tcg_gen_ext32u_tl(s->A0, cpu_regs[R_EAX]);
 }
 gen_helper_flush_page(cpu_env, s->A0);
-gen_update_eip_next(s);
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_NEXT;
 break;
 
 CASE_MODRM_MEM_OP(2): /* lgdt */
@@ -7744,8 +7737,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 tcg_gen_andi_tl(s->T1, s->T1, ~0xe);
 tcg_gen_or_tl(s->T0, s->T0, s->T1);
 gen_helper_write_crN(cpu_env, tcg_constant_i32(0), s->T0);
-gen_update_eip_next(s);
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_NEXT;
 break;
 
 CASE_MODRM_MEM_OP(7): /* invlpg */
@@ -7755,8 +7747,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_svm_check_intercept(s, SVM_EXIT_INVLPG);
 gen_lea_modrm(env, s, modrm);
 gen_helper_flush_page(cpu_env, s->A0);
-gen_update_eip_next(s);
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_NEXT;
 break;
 
 case 0xf8: /* swapgs */
@@ -8155,8 +8146,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0 + reg);
 gen_op_mov_v_reg(s, ot, s->T0, rm);
 gen_helper_write_crN(cpu_env, tcg_constant_i32(reg), s->T0);
-gen_update_eip_next(s);
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_NEXT;
 } else {
 gen_svm_check_intercept(s, SVM_EXIT_READ_CR0 + reg);
 gen_helper_read_crN(s->T0, cpu_env, tcg_constant_i32(reg));
@@ -8190,8 +8180,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_op_mov_v_reg(s, ot, s->T0, rm);
 tcg_gen_movi_i32(s->tmp2_i32, reg);
 gen_helper_set_dr(cpu_env, s->tmp2_i32, s->T0);
-gen_update_eip_next(s);
-gen_eob(s);
+s->base.is_jmp = DISAS_EOB_NEXT;
 } else {
 gen_svm_check_intercept(s, SVM_EXIT_READ_DR0 + reg);
 tcg_gen_movi_i32(s->tmp2_i32, reg);
@@ -8205,8 +8194,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0);
 gen_helper_cl

[PATCH 04/22] target/i386: Create gen_update_eip_cur

2022-08-22 Thread Richard Henderson
Like gen_update_cc_op, sync EIP before doing something
that could raise an exception.  Replace all gen_jmp_im
that use s->base.pc_next.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 52 -
 1 file changed, 28 insertions(+), 24 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index d3b16ea28c..78b7641786 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -511,10 +511,14 @@ static inline void gen_op_st_rm_T0_A0(DisasContext *s, 
int idx, int d)
 }
 }
 
-static inline void gen_jmp_im(DisasContext *s, target_ulong pc)
+static void gen_jmp_im(DisasContext *s, target_ulong pc)
 {
-tcg_gen_movi_tl(s->tmp0, pc);
-gen_op_jmp_v(s->tmp0);
+gen_op_jmp_v(tcg_constant_tl(pc));
+}
+
+static void gen_update_eip_cur(DisasContext *s)
+{
+gen_jmp_im(s, s->base.pc_next - s->cs_base);
 }
 
 /* Compute SEG:REG into A0.  SEG is selected from the override segment
@@ -703,7 +707,7 @@ static bool gen_check_io(DisasContext *s, MemOp ot, 
TCGv_i32 port,
 target_ulong next_eip = s->pc - s->cs_base;
 
 gen_update_cc_op(s);
-gen_jmp_im(s, cur_eip);
+gen_update_eip_cur(s);
 if (s->prefix & (PREFIX_REPZ | PREFIX_REPNZ)) {
 svm_flags |= SVM_IOIO_REP_MASK;
 }
@@ -1335,7 +1339,7 @@ static void gen_helper_fp_arith_STN_ST0(int op, int opreg)
 static void gen_exception(DisasContext *s, int trapno)
 {
 gen_update_cc_op(s);
-gen_jmp_im(s, s->base.pc_next - s->cs_base);
+gen_update_eip_cur(s);
 gen_helper_raise_exception(cpu_env, tcg_const_i32(trapno));
 s->base.is_jmp = DISAS_NORETURN;
 }
@@ -2605,7 +2609,7 @@ static void gen_unknown_opcode(CPUX86State *env, 
DisasContext *s)
 static void gen_interrupt(DisasContext *s, int intno)
 {
 gen_update_cc_op(s);
-gen_jmp_im(s, s->base.pc_next - s->cs_base);
+gen_update_eip_cur(s);
 gen_helper_raise_interrupt(cpu_env, tcg_constant_i32(intno),
tcg_constant_i32(s->pc - s->base.pc_next));
 s->base.is_jmp = DISAS_NORETURN;
@@ -6683,7 +6687,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 do_lret:
 if (PE(s) && !VM86(s)) {
 gen_update_cc_op(s);
-gen_jmp_im(s, s->base.pc_next - s->cs_base);
+gen_update_eip_cur(s);
 gen_helper_lret_protected(cpu_env, tcg_const_i32(dflag - 1),
   tcg_const_i32(val));
 } else {
@@ -7179,7 +7183,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 if (prefixes & PREFIX_REPZ) {
 gen_update_cc_op(s);
-gen_jmp_im(s, s->base.pc_next - s->cs_base);
+gen_update_eip_cur(s);
 gen_helper_pause(cpu_env, tcg_const_i32(s->pc - s->base.pc_next));
 s->base.is_jmp = DISAS_NORETURN;
 }
@@ -7205,7 +7209,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 if (CODE64(s))
 goto illegal_op;
 gen_update_cc_op(s);
-gen_jmp_im(s, s->base.pc_next - s->cs_base);
+gen_update_eip_cur(s);
 gen_helper_into(cpu_env, tcg_const_i32(s->pc - s->base.pc_next));
 break;
 #ifdef WANT_ICEBP
@@ -7312,7 +7316,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 case 0x132: /* rdmsr */
 if (check_cpl0(s)) {
 gen_update_cc_op(s);
-gen_jmp_im(s, s->base.pc_next - s->cs_base);
+gen_update_eip_cur(s);
 if (b & 2) {
 gen_helper_rdmsr(cpu_env);
 } else {
@@ -7324,7 +7328,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 break;
 case 0x131: /* rdtsc */
 gen_update_cc_op(s);
-gen_jmp_im(s, s->base.pc_next - s->cs_base);
+gen_update_eip_cur(s);
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
 }
@@ -7335,7 +7339,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 break;
 case 0x133: /* rdpmc */
 gen_update_cc_op(s);
-gen_jmp_im(s, s->base.pc_next - s->cs_base);
+gen_update_eip_cur(s);
 gen_helper_rdpmc(cpu_env);
 s->base.is_jmp = DISAS_NORETURN;
 break;
@@ -7365,7 +7369,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 case 0x105: /* syscall */
 /* XXX: is it usable in real mode ? */
 gen_update_cc_op(s);
-gen_jmp_im(s, s->base.pc_next - s->cs_base);
+gen_update_eip_cur(s);
 gen_helper_syscall(cpu_env, tcg_const_i32(s->pc - s->base.pc_next));
 /* TF handling for the syscall insn is different. The TF bit is  
checked
after the syscall insn completes. This allows #DB to not be
@@ -7391,13 +7395,13 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 #endif
 case 0x1a2: /* cpuid */
 gen_update_cc_op(s);
-gen_jmp_im(s, s->base.pc_next - s->cs_ba

[PATCH 03/22] target/i386: Remove cur_eip, next_eip arguments to gen_interrupt

2022-08-22 Thread Richard Henderson
All callers pass s->base.pc_next and s->pc, which we can just
as well compute within the function.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 13 ++---
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index f6a861e10c..d3b16ea28c 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -2602,13 +2602,12 @@ static void gen_unknown_opcode(CPUX86State *env, 
DisasContext *s)
 
 /* an interrupt is different from an exception because of the
privilege checks */
-static void gen_interrupt(DisasContext *s, int intno,
-  target_ulong cur_eip, target_ulong next_eip)
+static void gen_interrupt(DisasContext *s, int intno)
 {
 gen_update_cc_op(s);
-gen_jmp_im(s, cur_eip);
-gen_helper_raise_interrupt(cpu_env, tcg_const_i32(intno),
-   tcg_const_i32(next_eip - cur_eip));
+gen_jmp_im(s, s->base.pc_next - s->cs_base);
+gen_helper_raise_interrupt(cpu_env, tcg_constant_i32(intno),
+   tcg_constant_i32(s->pc - s->base.pc_next));
 s->base.is_jmp = DISAS_NORETURN;
 }
 
@@ -7194,12 +7193,12 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 }
 break;
 case 0xcc: /* int3 */
-gen_interrupt(s, EXCP03_INT3, s->base.pc_next - s->cs_base, s->pc - 
s->cs_base);
+gen_interrupt(s, EXCP03_INT3);
 break;
 case 0xcd: /* int N */
 val = x86_ldub_code(env, s);
 if (check_vm86_iopl(s)) {
-gen_interrupt(s, val, s->base.pc_next - s->cs_base, s->pc - 
s->cs_base);
+gen_interrupt(s, val);
 }
 break;
 case 0xce: /* into */
-- 
2.34.1




[PATCH 07/22] target/i386: Use DISAS_EOB* in gen_movl_seg_T0

2022-08-22 Thread Richard Henderson
Set is_jmp properly in gen_movl_seg_T0, so that the callers
need to nothing special.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 36 +---
 1 file changed, 5 insertions(+), 31 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 579ba37e76..4dc8f4c1f8 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -2432,13 +2432,15 @@ static void gen_movl_seg_T0(DisasContext *s, X86Seg 
seg_reg)
because ss32 may change. For R_SS, translation must always
stop as a special handling must be done to disable hardware
interrupts for the next instruction */
-if (seg_reg == R_SS || (CODE32(s) && seg_reg < R_FS)) {
-s->base.is_jmp = DISAS_TOO_MANY;
+if (seg_reg == R_SS) {
+s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ;
+} else if (CODE32(s) && seg_reg < R_FS) {
+s->base.is_jmp = DISAS_EOB_NEXT;
 }
 } else {
 gen_op_movl_seg_T0_vm(s, seg_reg);
 if (seg_reg == R_SS) {
-s->base.is_jmp = DISAS_TOO_MANY;
+s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ;
 }
 }
 }
@@ -5569,26 +5571,12 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 ot = gen_pop_T0(s);
 gen_movl_seg_T0(s, reg);
 gen_pop_update(s, ot);
-/* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp.  */
-if (s->base.is_jmp) {
-gen_update_eip_next(s);
-if (reg == R_SS) {
-s->flags &= ~HF_TF_MASK;
-gen_eob_inhibit_irq(s, true);
-} else {
-gen_eob(s);
-}
-}
 break;
 case 0x1a1: /* pop fs */
 case 0x1a9: /* pop gs */
 ot = gen_pop_T0(s);
 gen_movl_seg_T0(s, (b >> 3) & 7);
 gen_pop_update(s, ot);
-if (s->base.is_jmp) {
-gen_update_eip_next(s);
-gen_eob(s);
-}
 break;
 
 /**/
@@ -5635,16 +5623,6 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 goto illegal_op;
 gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
 gen_movl_seg_T0(s, reg);
-/* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp.  */
-if (s->base.is_jmp) {
-gen_update_eip_next(s);
-if (reg == R_SS) {
-s->flags &= ~HF_TF_MASK;
-gen_eob_inhibit_irq(s, true);
-} else {
-gen_eob(s);
-}
-}
 break;
 case 0x8c: /* mov Gv, seg */
 modrm = x86_ldub_code(env, s);
@@ -5843,10 +5821,6 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 gen_movl_seg_T0(s, op);
 /* then put the data */
 gen_op_mov_reg_v(s, ot, reg, s->T1);
-if (s->base.is_jmp) {
-gen_update_eip_next(s);
-gen_eob(s);
-}
 break;
 
 //
-- 
2.34.1




[PATCH v3 16/17] target/arm: Introduce gen_pc_plus_diff for aarch32

2022-08-22 Thread Richard Henderson
In preparation for TARGET_TB_PCREL, reduce reliance on absolute values.

Signed-off-by: Richard Henderson 
---
 target/arm/translate.c | 29 ++---
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/target/arm/translate.c b/target/arm/translate.c
index 4d13e365e2..f01c8df60a 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -276,11 +276,16 @@ static int jmp_diff(DisasContext *s, int diff)
 return diff + (s->thumb ? 4 : 8);
 }
 
+static void gen_pc_plus_diff(DisasContext *s, TCGv_i32 var, int diff)
+{
+tcg_gen_movi_i32(var, s->pc_curr + diff);
+}
+
 /* Set a variable to the value of a CPU register.  */
 void load_reg_var(DisasContext *s, TCGv_i32 var, int reg)
 {
 if (reg == 15) {
-tcg_gen_movi_i32(var, read_pc(s));
+gen_pc_plus_diff(s, var, jmp_diff(s, 0));
 } else {
 tcg_gen_mov_i32(var, cpu_R[reg]);
 }
@@ -296,7 +301,8 @@ TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs)
 TCGv_i32 tmp = tcg_temp_new_i32();
 
 if (reg == 15) {
-tcg_gen_movi_i32(tmp, (read_pc(s) & ~3) + ofs);
+/* This difference computes a page offset so ok for TARGET_TB_PCREL. */
+gen_pc_plus_diff(s, tmp, (read_pc(s) & ~3) - s->pc_curr + ofs);
 } else {
 tcg_gen_addi_i32(tmp, cpu_R[reg], ofs);
 }
@@ -1158,7 +1164,7 @@ void unallocated_encoding(DisasContext *s)
 /* Force a TB lookup after an instruction that changes the CPU state.  */
 void gen_lookup_tb(DisasContext *s)
 {
-tcg_gen_movi_i32(cpu_R[15], s->base.pc_next);
+gen_pc_plus_diff(s, cpu_R[15], curr_insn_len(s));
 s->base.is_jmp = DISAS_EXIT;
 }
 
@@ -6485,7 +6491,7 @@ static bool trans_BLX_r(DisasContext *s, arg_BLX_r *a)
 return false;
 }
 tmp = load_reg(s, a->rm);
-tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
+gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | s->thumb);
 gen_bx(s, tmp);
 return true;
 }
@@ -8356,7 +8362,7 @@ static bool trans_B_cond_thumb(DisasContext *s, arg_ci *a)
 
 static bool trans_BL(DisasContext *s, arg_i *a)
 {
-tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
+gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | s->thumb);
 gen_jmp(s, jmp_diff(s, a->imm));
 return true;
 }
@@ -8375,7 +8381,7 @@ static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a)
 if (s->thumb && (a->imm & 2)) {
 return false;
 }
-tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
+gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | s->thumb);
 store_cpu_field_constant(!s->thumb, thumb);
 /* This difference computes a page offset so ok for TARGET_TB_PCREL. */
 gen_jmp(s, (read_pc(s) & ~3) - s->pc_curr + a->imm);
@@ -8385,7 +8391,7 @@ static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a)
 static bool trans_BL_BLX_prefix(DisasContext *s, arg_BL_BLX_prefix *a)
 {
 assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
-tcg_gen_movi_i32(cpu_R[14], read_pc(s) + (a->imm << 12));
+gen_pc_plus_diff(s, cpu_R[14], jmp_diff(s, a->imm << 12));
 return true;
 }
 
@@ -8395,7 +8401,7 @@ static bool trans_BL_suffix(DisasContext *s, 
arg_BL_suffix *a)
 
 assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
 tcg_gen_addi_i32(tmp, cpu_R[14], (a->imm << 1) | 1);
-tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1);
+gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | 1);
 gen_bx(s, tmp);
 return true;
 }
@@ -8411,7 +8417,7 @@ static bool trans_BLX_suffix(DisasContext *s, 
arg_BLX_suffix *a)
 tmp = tcg_temp_new_i32();
 tcg_gen_addi_i32(tmp, cpu_R[14], a->imm << 1);
 tcg_gen_andi_i32(tmp, tmp, 0xfffc);
-tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1);
+gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | 1);
 gen_bx(s, tmp);
 return true;
 }
@@ -8734,10 +8740,11 @@ static bool op_tbranch(DisasContext *s, arg_tbranch *a, 
bool half)
 tcg_gen_add_i32(addr, addr, tmp);
 
 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);
-tcg_gen_addi_i32(tmp, tmp, read_pc(s));
+gen_pc_plus_diff(s, addr, jmp_diff(s, 0));
+tcg_gen_add_i32(tmp, tmp, addr);
+tcg_temp_free_i32(addr);
 store_reg(s, 15, tmp);
 return true;
 }
-- 
2.34.1




[PATCH 02/22] target/i386: Remove cur_eip argument to gen_exception

2022-08-22 Thread Richard Henderson
All callers pass s->base.pc_next - s->cs_base, which we can just
as well compute within the function.  Note the special case of
EXCP_VSYSCALL in which s->cs_base didn't have the subtraction,
but cs_base is always zero in 64-bit mode, when vsyscall is used.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 26 +-
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 2bdbfc6ddf..f6a861e10c 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -1332,10 +1332,10 @@ static void gen_helper_fp_arith_STN_ST0(int op, int 
opreg)
 }
 }
 
-static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
+static void gen_exception(DisasContext *s, int trapno)
 {
 gen_update_cc_op(s);
-gen_jmp_im(s, cur_eip);
+gen_jmp_im(s, s->base.pc_next - s->cs_base);
 gen_helper_raise_exception(cpu_env, tcg_const_i32(trapno));
 s->base.is_jmp = DISAS_NORETURN;
 }
@@ -1344,13 +1344,13 @@ static void gen_exception(DisasContext *s, int trapno, 
target_ulong cur_eip)
the instruction is known, but it isn't allowed in the current cpu mode.  */
 static void gen_illegal_opcode(DisasContext *s)
 {
-gen_exception(s, EXCP06_ILLOP, s->base.pc_next - s->cs_base);
+gen_exception(s, EXCP06_ILLOP);
 }
 
 /* Generate #GP for the current instruction. */
 static void gen_exception_gpf(DisasContext *s)
 {
-gen_exception(s, EXCP0D_GPF, s->base.pc_next - s->cs_base);
+gen_exception(s, EXCP0D_GPF);
 }
 
 /* Check for cpl == 0; if not, raise #GP and return false. */
@@ -3148,7 +3148,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b)
 }
 /* simple MMX/SSE operation */
 if (s->flags & HF_TS_MASK) {
-gen_exception(s, EXCP07_PREX, s->base.pc_next - s->cs_base);
+gen_exception(s, EXCP07_PREX);
 return;
 }
 if (s->flags & HF_EM_MASK) {
@@ -5929,7 +5929,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 if (s->flags & (HF_EM_MASK | HF_TS_MASK)) {
 /* if CR0.EM or CR0.TS are set, generate an FPU exception */
 /* XXX: what to do if illegal op ? */
-gen_exception(s, EXCP07_PREX, s->base.pc_next - s->cs_base);
+gen_exception(s, EXCP07_PREX);
 break;
 }
 modrm = x86_ldub_code(env, s);
@@ -7154,7 +7154,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 goto illegal_op;
 val = x86_ldub_code(env, s);
 if (val == 0) {
-gen_exception(s, EXCP00_DIVZ, s->base.pc_next - s->cs_base);
+gen_exception(s, EXCP00_DIVZ);
 } else {
 gen_helper_aam(cpu_env, tcg_const_i32(val));
 set_cc_op(s, CC_OP_LOGICB);
@@ -7188,7 +7188,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 case 0x9b: /* fwait */
 if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) ==
 (HF_MP_MASK | HF_TS_MASK)) {
-gen_exception(s, EXCP07_PREX, s->base.pc_next - s->cs_base);
+gen_exception(s, EXCP07_PREX);
 } else {
 gen_helper_fwait(cpu_env);
 }
@@ -8245,7 +8245,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 goto illegal_op;
 }
 if ((s->flags & HF_EM_MASK) || (s->flags & HF_TS_MASK)) {
-gen_exception(s, EXCP07_PREX, s->base.pc_next - s->cs_base);
+gen_exception(s, EXCP07_PREX);
 break;
 }
 gen_lea_modrm(env, s, modrm);
@@ -8258,7 +8258,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 goto illegal_op;
 }
 if ((s->flags & HF_EM_MASK) || (s->flags & HF_TS_MASK)) {
-gen_exception(s, EXCP07_PREX, s->base.pc_next - s->cs_base);
+gen_exception(s, EXCP07_PREX);
 break;
 }
 gen_lea_modrm(env, s, modrm);
@@ -8270,7 +8270,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 goto illegal_op;
 }
 if (s->flags & HF_TS_MASK) {
-gen_exception(s, EXCP07_PREX, s->base.pc_next - s->cs_base);
+gen_exception(s, EXCP07_PREX);
 break;
 }
 gen_lea_modrm(env, s, modrm);
@@ -8283,7 +8283,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
 goto illegal_op;
 }
 if (s->flags & HF_TS_MASK) {
-gen_exception(s, EXCP07_PREX, s->base.pc_next - s->cs_base);
+gen_exception(s, EXCP07_PREX);
 break;
 }
 gen_helper_update_mxcsr(cpu_env);
@@ -8674,7 +8674,7 @@ static void i386_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cpu)
  * Detect entry into the vsyscall page and invoke the syscall.
  */
 if ((dc->base

[PATCH 06/22] target/i386: Introduce DISAS_EOB*

2022-08-22 Thread Richard Henderson
Add a few DISAS_TARGET_* aliases to reduce the number of
calls to gen_eob() and gen_eob_inhibit_irq().  So far,
only update i386_tr_translate_insn for exiting the block
because of single-step or previous inhibit irq.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 23 +--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 36883410e0..579ba37e76 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -132,6 +132,10 @@ typedef struct DisasContext {
 TCGOp *prev_insn_end;
 } DisasContext;
 
+#define DISAS_EOB_ONLY DISAS_TARGET_0
+#define DISAS_EOB_NEXT DISAS_TARGET_1
+#define DISAS_EOB_INHIBIT_IRQ  DISAS_TARGET_2
+
 /* The environment in which user-only runs is constrained. */
 #ifdef CONFIG_USER_ONLY
 #define PE(S) true
@@ -8701,7 +8705,7 @@ static void i386_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cpu)
  * the flag and abort the translation to give the irqs a
  * chance to happen.
  */
-dc->base.is_jmp = DISAS_TOO_MANY;
+dc->base.is_jmp = DISAS_EOB_NEXT;
 } else if (!is_same_page(&dc->base, pc_next)) {
 dc->base.is_jmp = DISAS_TOO_MANY;
 }
@@ -8713,9 +8717,24 @@ static void i386_tr_tb_stop(DisasContextBase *dcbase, 
CPUState *cpu)
 {
 DisasContext *dc = container_of(dcbase, DisasContext, base);
 
-if (dc->base.is_jmp == DISAS_TOO_MANY) {
+switch (dc->base.is_jmp) {
+case DISAS_NORETURN:
+break;
+case DISAS_TOO_MANY:
+case DISAS_EOB_NEXT:
+gen_update_cc_op(dc);
 gen_update_eip_cur(dc);
+/* fall through */
+case DISAS_EOB_ONLY:
 gen_eob(dc);
+break;
+case DISAS_EOB_INHIBIT_IRQ:
+gen_update_cc_op(dc);
+gen_update_eip_cur(dc);
+gen_eob_inhibit_irq(dc, true);
+break;
+default:
+g_assert_not_reached();
 }
 }
 
-- 
2.34.1




[PATCH 00/22] target/i386: pc-relative translation

2022-08-22 Thread Richard Henderson
Based-on: <20220822232338.1727934-1-richard.hender...@linaro.org>
("[PATCH v3 00/17] accel/tcg + target/arm: pc-relative translation")

Improve translation with address space randomization.

Before:

gen code size   232687283/1073577984
TB count434021
TB flush count  1
TB invalidate count 478996

After:

gen code size   281614723/1073577984
TB count527520
TB flush count  0
TB invalidate count 125631

  beforeafter
BootLinuxX8664.test_pc_i440fx_tcg: 63.7956.01
BootLinuxX8664.test_pc_q35_tcg:69.1150.00
JOB TIME  595.51   533.57


r~


Richard Henderson (22):
  target/i386: Return bool from disas_insn
  target/i386: Remove cur_eip argument to gen_exception
  target/i386: Remove cur_eip, next_eip arguments to gen_interrupt
  target/i386: Create gen_update_eip_cur
  target/i386: Create gen_update_eip_next
  target/i386: Introduce DISAS_EOB*
  target/i386: Use DISAS_EOB* in gen_movl_seg_T0
  target/i386: Use DISAS_EOB_NEXT
  target/i386: USe DISAS_EOB_ONLY
  target/i386: Create cur_insn_len, cur_insn_len_i32
  target/i386: Remove cur_eip, next_eip arguments to gen_repz*
  target/i386: Introduce DISAS_JUMP
  target/i386: Truncate values for lcall_real to i32
  target/i386: Create eip_next_*
  target/i386: Use DISAS_TOO_MANY to exit after gen_io_start
  target/i386: Create gen_jmp_rel
  target/i386: Use gen_jmp_rel for loop and jecxz insns
  target/i386: Use gen_jmp_rel for gen_jcc
  target/i386: Use gen_jmp_rel for gen_repz*
  target/i386: Use gen_jmp_rel for DISAS_TOO_MANY
  target/i386: Create gen_eip_cur
  target/i386: Enable TARGET_TB_PCREL

 target/i386/cpu-param.h  |   1 +
 target/i386/helper.h |   2 +-
 target/i386/tcg/seg_helper.c |   6 +-
 target/i386/tcg/tcg-cpu.c|   8 +-
 target/i386/tcg/translate.c  | 710 ++-
 5 files changed, 365 insertions(+), 362 deletions(-)

-- 
2.34.1




[PATCH v3 12/17] target/arm: Change gen_exception_insn* to work on displacements

2022-08-22 Thread Richard Henderson
In preparation for TARGET_TB_PCREL, reduce reliance on absolute values.

Signed-off-by: Richard Henderson 
---
 target/arm/translate.h|  4 ++--
 target/arm/translate-a64.c| 28 +++--
 target/arm/translate-m-nocp.c |  6 +++---
 target/arm/translate-mve.c|  2 +-
 target/arm/translate-vfp.c|  6 +++---
 target/arm/translate.c| 39 +--
 6 files changed, 40 insertions(+), 45 deletions(-)

diff --git a/target/arm/translate.h b/target/arm/translate.h
index 33b94a18bb..d42059aa1d 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -281,9 +281,9 @@ 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_el(DisasContext *s, uint64_t pc, int excp,
+void gen_exception_insn_el(DisasContext *s, int pc_diff, int excp,
uint32_t syn, uint32_t target_el);
-void gen_exception_insn(DisasContext *s, uint64_t pc, int excp, uint32_t syn);
+void gen_exception_insn(DisasContext *s, int pc_diff, int excp, uint32_t syn);
 
 /* Return state of Alternate Half-precision flag, caller frees result */
 static inline TCGv_i32 get_ahp_flag(void)
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 90f31b1dff..422ce9288d 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -1163,7 +1163,7 @@ static bool fp_access_check_only(DisasContext *s)
 assert(!s->fp_access_checked);
 s->fp_access_checked = true;
 
-gen_exception_insn_el(s, s->pc_curr, EXCP_UDEF,
+gen_exception_insn_el(s, 0, EXCP_UDEF,
   syn_fp_access_trap(1, 0xe, false, 0),
   s->fp_excp_el);
 return false;
@@ -1178,7 +1178,7 @@ static bool fp_access_check(DisasContext *s)
 return false;
 }
 if (s->sme_trap_nonstreaming && s->is_nonstreaming) {
-gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
+gen_exception_insn(s, 0, EXCP_UDEF,
syn_smetrap(SME_ET_Streaming, false));
 return false;
 }
@@ -1198,7 +1198,7 @@ bool sve_access_check(DisasContext *s)
 goto fail_exit;
 }
 } else if (s->sve_excp_el) {
-gen_exception_insn_el(s, s->pc_curr, EXCP_UDEF,
+gen_exception_insn_el(s, 0, EXCP_UDEF,
   syn_sve_access_trap(), s->sve_excp_el);
 goto fail_exit;
 }
@@ -1220,7 +1220,7 @@ bool sve_access_check(DisasContext *s)
 static bool sme_access_check(DisasContext *s)
 {
 if (s->sme_excp_el) {
-gen_exception_insn_el(s, s->pc_curr, EXCP_UDEF,
+gen_exception_insn_el(s, 0, EXCP_UDEF,
   syn_smetrap(SME_ET_AccessTrap, false),
   s->sme_excp_el);
 return false;
@@ -1250,12 +1250,12 @@ bool sme_enabled_check_with_svcr(DisasContext *s, 
unsigned req)
 return false;
 }
 if (FIELD_EX64(req, SVCR, SM) && !s->pstate_sm) {
-gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
+gen_exception_insn(s, 0, EXCP_UDEF,
syn_smetrap(SME_ET_NotStreaming, false));
 return false;
 }
 if (FIELD_EX64(req, SVCR, ZA) && !s->pstate_za) {
-gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
+gen_exception_insn(s, 0, EXCP_UDEF,
syn_smetrap(SME_ET_InactiveZA, false));
 return false;
 }
@@ -1915,7 +1915,7 @@ static void gen_sysreg_undef(DisasContext *s, bool isread,
 } else {
 syndrome = syn_uncategorized();
 }
-gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syndrome);
+gen_exception_insn(s, 0, EXCP_UDEF, syndrome);
 }
 
 /* MRS - move from system register
@@ -2169,8 +2169,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
 switch (op2_ll) {
 case 1: /* SVC */
 gen_ss_advance(s);
-gen_exception_insn(s, s->base.pc_next, EXCP_SWI,
-   syn_aa64_svc(imm16));
+gen_exception_insn(s, 4, EXCP_SWI, syn_aa64_svc(imm16));
 break;
 case 2: /* HVC */
 if (s->current_el == 0) {
@@ -2183,8 +2182,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
 gen_a64_update_pc(s, 0);
 gen_helper_pre_hvc(cpu_env);
 gen_ss_advance(s);
-gen_exception_insn_el(s, s->base.pc_next, EXCP_HVC,
-  syn_aa64_hvc(imm16), 2);
+gen_exception_insn_el(s, 4, EXCP_HVC, syn_aa64_hvc(imm16), 2);
 break;
 case 3: /* SMC */
 if (s->current_el == 0) {
@@ -2194,8 +2192,7 @@ static void disas_exc(DisasContext *s, uint32_t i

[PATCH v3 14/17] target/arm: Change gen_jmp* to work on displacements

2022-08-22 Thread Richard Henderson
In preparation for TARGET_TB_PCREL, reduce reliance on absolute values.

Signed-off-by: Richard Henderson 
---
 target/arm/translate.c | 35 ---
 1 file changed, 20 insertions(+), 15 deletions(-)

diff --git a/target/arm/translate.c b/target/arm/translate.c
index 63a41ed438..4d13e365e2 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -270,6 +270,12 @@ static uint32_t read_pc(DisasContext *s)
 return s->pc_curr + (s->thumb ? 4 : 8);
 }
 
+/* The pc_curr difference for an architectural jump. */
+static int jmp_diff(DisasContext *s, int diff)
+{
+return diff + (s->thumb ? 4 : 8);
+}
+
 /* Set a variable to the value of a CPU register.  */
 void load_reg_var(DisasContext *s, TCGv_i32 var, int reg)
 {
@@ -2614,10 +2620,8 @@ static void gen_goto_tb(DisasContext *s, int n, int diff)
 }
 
 /* Jump, specifying which TB number to use if we gen_goto_tb() */
-static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
+static void gen_jmp_tb(DisasContext *s, int diff, int tbno)
 {
-int diff = dest - s->pc_curr;
-
 if (unlikely(s->ss_active)) {
 /* An indirect jump so that we still trigger the debug exception.  */
 gen_update_pc(s, diff);
@@ -2659,9 +2663,9 @@ static inline void gen_jmp_tb(DisasContext *s, uint32_t 
dest, int tbno)
 }
 }
 
-static inline void gen_jmp(DisasContext *s, uint32_t dest)
+static inline void gen_jmp(DisasContext *s, int diff)
 {
-gen_jmp_tb(s, dest, 0);
+gen_jmp_tb(s, diff, 0);
 }
 
 static inline void gen_mulxy(TCGv_i32 t0, TCGv_i32 t1, int x, int y)
@@ -8331,7 +8335,7 @@ static bool trans_CLRM(DisasContext *s, arg_CLRM *a)
 
 static bool trans_B(DisasContext *s, arg_i *a)
 {
-gen_jmp(s, read_pc(s) + a->imm);
+gen_jmp(s, jmp_diff(s, a->imm));
 return true;
 }
 
@@ -8346,14 +8350,14 @@ static bool trans_B_cond_thumb(DisasContext *s, arg_ci 
*a)
 return true;
 }
 arm_skip_unless(s, a->cond);
-gen_jmp(s, read_pc(s) + a->imm);
+gen_jmp(s, jmp_diff(s, a->imm));
 return true;
 }
 
 static bool trans_BL(DisasContext *s, arg_i *a)
 {
 tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
-gen_jmp(s, read_pc(s) + a->imm);
+gen_jmp(s, jmp_diff(s, a->imm));
 return true;
 }
 
@@ -8373,7 +8377,8 @@ static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a)
 }
 tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
 store_cpu_field_constant(!s->thumb, thumb);
-gen_jmp(s, (read_pc(s) & ~3) + a->imm);
+/* This difference computes a page offset so ok for TARGET_TB_PCREL. */
+gen_jmp(s, (read_pc(s) & ~3) - s->pc_curr + a->imm);
 return true;
 }
 
@@ -8534,10 +8539,10 @@ static bool trans_WLS(DisasContext *s, arg_WLS *a)
  * when we take this upcoming exit from this TB, so gen_jmp_tb() is OK.
  */
 }
-gen_jmp_tb(s, s->base.pc_next, 1);
+gen_jmp_tb(s, curr_insn_len(s), 1);
 
 gen_set_label(nextlabel);
-gen_jmp(s, read_pc(s) + a->imm);
+gen_jmp(s, jmp_diff(s, a->imm));
 return true;
 }
 
@@ -8617,7 +8622,7 @@ static bool trans_LE(DisasContext *s, arg_LE *a)
 
 if (a->f) {
 /* Loop-forever: just jump back to the loop start */
-gen_jmp(s, read_pc(s) - a->imm);
+gen_jmp(s, jmp_diff(s, -a->imm));
 return true;
 }
 
@@ -8648,7 +8653,7 @@ static bool trans_LE(DisasContext *s, arg_LE *a)
 tcg_temp_free_i32(decr);
 }
 /* Jump back to the loop start */
-gen_jmp(s, read_pc(s) - a->imm);
+gen_jmp(s, jmp_diff(s, -a->imm));
 
 gen_set_label(loopend);
 if (a->tp) {
@@ -8656,7 +8661,7 @@ static bool trans_LE(DisasContext *s, arg_LE *a)
 store_cpu_field(tcg_constant_i32(4), v7m.ltpsize);
 }
 /* End TB, continuing to following insn */
-gen_jmp_tb(s, s->base.pc_next, 1);
+gen_jmp_tb(s, curr_insn_len(s), 1);
 return true;
 }
 
@@ -8755,7 +8760,7 @@ static bool trans_CBZ(DisasContext *s, arg_CBZ *a)
 tcg_gen_brcondi_i32(a->nz ? TCG_COND_EQ : TCG_COND_NE,
 tmp, 0, s->condlabel);
 tcg_temp_free_i32(tmp);
-gen_jmp(s, read_pc(s) + a->imm);
+gen_jmp(s, jmp_diff(s, a->imm));
 return true;
 }
 
-- 
2.34.1




[PATCH v3 05/17] include/hw/core: Create struct CPUJumpCache

2022-08-22 Thread Richard Henderson
Wrap the bare TranslationBlock pointer into a structure.

Signed-off-by: Richard Henderson 
---
 include/hw/core/cpu.h | 8 ++--
 accel/tcg/cpu-exec.c  | 9 ++---
 accel/tcg/cputlb.c| 2 +-
 accel/tcg/translate-all.c | 4 ++--
 4 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 500503da13..8edef14199 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -233,6 +233,10 @@ struct hvf_vcpu_state;
 #define TB_JMP_CACHE_BITS 12
 #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
 
+typedef struct {
+TranslationBlock *tb;
+} CPUJumpCache;
+
 /* work queue */
 
 /* The union type allows passing of 64 bit target pointers on 32 bit
@@ -362,7 +366,7 @@ struct CPUState {
 IcountDecr *icount_decr_ptr;
 
 /* Accessed in parallel; all accesses must be atomic */
-TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE];
+CPUJumpCache tb_jmp_cache[TB_JMP_CACHE_SIZE];
 
 struct GDBRegisterState *gdb_regs;
 int gdb_num_regs;
@@ -453,7 +457,7 @@ static inline void cpu_tb_jmp_cache_clear(CPUState *cpu)
 unsigned int i;
 
 for (i = 0; i < TB_JMP_CACHE_SIZE; i++) {
-qatomic_set(&cpu->tb_jmp_cache[i], NULL);
+qatomic_set(&cpu->tb_jmp_cache[i].tb, NULL);
 }
 }
 
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index b1fd962718..3f8e4bbbc8 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -243,7 +243,7 @@ static inline TranslationBlock *tb_lookup(CPUState *cpu, 
target_ulong pc,
 tcg_debug_assert(!(cflags & CF_INVALID));
 
 hash = tb_jmp_cache_hash_func(pc);
-tb = qatomic_rcu_read(&cpu->tb_jmp_cache[hash]);
+tb = qatomic_rcu_read(&cpu->tb_jmp_cache[hash].tb);
 
 if (likely(tb &&
tb->pc == pc &&
@@ -257,7 +257,7 @@ static inline TranslationBlock *tb_lookup(CPUState *cpu, 
target_ulong pc,
 if (tb == NULL) {
 return NULL;
 }
-qatomic_set(&cpu->tb_jmp_cache[hash], tb);
+qatomic_set(&cpu->tb_jmp_cache[hash].tb, tb);
 return tb;
 }
 
@@ -978,6 +978,8 @@ int cpu_exec(CPUState *cpu)
 
 tb = tb_lookup(cpu, pc, cs_base, flags, cflags);
 if (tb == NULL) {
+uint32_t h;
+
 mmap_lock();
 tb = tb_gen_code(cpu, pc, cs_base, flags, cflags);
 mmap_unlock();
@@ -985,7 +987,8 @@ int cpu_exec(CPUState *cpu)
  * We add the TB in the virtual pc hash table
  * for the fast lookup
  */
-qatomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], 
tb);
+h = tb_jmp_cache_hash_func(pc);
+qatomic_set(&cpu->tb_jmp_cache[h].tb, tb);
 }
 
 #ifndef CONFIG_USER_ONLY
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 8b81b07b79..a8afe1ab9f 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -103,7 +103,7 @@ static void tb_jmp_cache_clear_page(CPUState *cpu, 
target_ulong page_addr)
 unsigned int i, i0 = tb_jmp_cache_hash_page(page_addr);
 
 for (i = 0; i < TB_JMP_PAGE_SIZE; i++) {
-qatomic_set(&cpu->tb_jmp_cache[i0 + i], NULL);
+qatomic_set(&cpu->tb_jmp_cache[i0 + i].tb, NULL);
 }
 }
 
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 20f00f4335..c2745f14a6 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -1187,8 +1187,8 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, 
bool rm_from_page_list)
 /* remove the TB from the hash list */
 h = tb_jmp_cache_hash_func(tb->pc);
 CPU_FOREACH(cpu) {
-if (qatomic_read(&cpu->tb_jmp_cache[h]) == tb) {
-qatomic_set(&cpu->tb_jmp_cache[h], NULL);
+if (qatomic_read(&cpu->tb_jmp_cache[h].tb) == tb) {
+qatomic_set(&cpu->tb_jmp_cache[h].tb, NULL);
 }
 }
 
-- 
2.34.1




[PATCH v3 15/17] target/arm: Introduce gen_pc_plus_diff for aarch64

2022-08-22 Thread Richard Henderson
In preparation for TARGET_TB_PCREL, reduce reliance on absolute values.

Signed-off-by: Richard Henderson 
---
 target/arm/translate-a64.c | 41 +++---
 1 file changed, 29 insertions(+), 12 deletions(-)

diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index b42643..322a09c503 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -148,9 +148,14 @@ static void reset_btype(DisasContext *s)
 }
 }
 
+static void gen_pc_plus_diff(DisasContext *s, TCGv_i64 dest, int diff)
+{
+tcg_gen_movi_i64(dest, s->pc_curr + diff);
+}
+
 void gen_a64_update_pc(DisasContext *s, int diff)
 {
-tcg_gen_movi_i64(cpu_pc, s->pc_curr + diff);
+gen_pc_plus_diff(s, cpu_pc, diff);
 }
 
 /*
@@ -1368,7 +1373,7 @@ static void disas_uncond_b_imm(DisasContext *s, uint32_t 
insn)
 
 if (insn & (1U << 31)) {
 /* BL Branch with link */
-tcg_gen_movi_i64(cpu_reg(s, 30), s->base.pc_next);
+gen_pc_plus_diff(s, cpu_reg(s, 30), curr_insn_len(s));
 }
 
 /* B Branch / BL Branch with link */
@@ -2319,11 +2324,17 @@ static void disas_uncond_b_reg(DisasContext *s, 
uint32_t insn)
 default:
 goto do_unallocated;
 }
-gen_a64_set_pc(s, dst);
 /* BLR also needs to load return address */
 if (opc == 1) {
-tcg_gen_movi_i64(cpu_reg(s, 30), s->base.pc_next);
+TCGv_i64 lr = cpu_reg(s, 30);
+if (dst == lr) {
+TCGv_i64 tmp = new_tmp_a64(s);
+tcg_gen_mov_i64(tmp, dst);
+dst = tmp;
+}
+gen_pc_plus_diff(s, lr, curr_insn_len(s));
 }
+gen_a64_set_pc(s, dst);
 break;
 
 case 8: /* BRAA */
@@ -2346,11 +2357,17 @@ static void disas_uncond_b_reg(DisasContext *s, 
uint32_t insn)
 } else {
 dst = cpu_reg(s, rn);
 }
-gen_a64_set_pc(s, dst);
 /* BLRAA also needs to load return address */
 if (opc == 9) {
-tcg_gen_movi_i64(cpu_reg(s, 30), s->base.pc_next);
+TCGv_i64 lr = cpu_reg(s, 30);
+if (dst == lr) {
+TCGv_i64 tmp = new_tmp_a64(s);
+tcg_gen_mov_i64(tmp, dst);
+dst = tmp;
+}
+gen_pc_plus_diff(s, lr, curr_insn_len(s));
 }
+gen_a64_set_pc(s, dst);
 break;
 
 case 4: /* ERET */
@@ -2918,7 +2935,8 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
 
 tcg_rt = cpu_reg(s, rt);
 
-clean_addr = tcg_constant_i64(s->pc_curr + imm);
+clean_addr = new_tmp_a64(s);
+gen_pc_plus_diff(s, clean_addr, imm);
 if (is_vector) {
 do_fp_ld(s, rt, clean_addr, size);
 } else {
@@ -4262,23 +4280,22 @@ static void disas_ldst(DisasContext *s, uint32_t insn)
 static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
 {
 unsigned int page, rd;
-uint64_t base;
-uint64_t offset;
+int64_t offset;
 
 page = extract32(insn, 31, 1);
 /* SignExtend(immhi:immlo) -> offset */
 offset = sextract64(insn, 5, 19);
 offset = offset << 2 | extract32(insn, 29, 2);
 rd = extract32(insn, 0, 5);
-base = s->pc_curr;
 
 if (page) {
 /* ADRP (page based) */
-base &= ~0xfff;
 offset <<= 12;
+/* The page offset is ok for TARGET_TB_PCREL. */
+offset -= s->pc_curr & 0xfff;
 }
 
-tcg_gen_movi_i64(cpu_reg(s, rd), base + offset);
+gen_pc_plus_diff(s, cpu_reg(s, rd), offset);
 }
 
 /*
-- 
2.34.1




[PATCH v3 13/17] target/arm: Change gen_exception_internal to work on displacements

2022-08-22 Thread Richard Henderson
In preparation for TARGET_TB_PCREL, reduce reliance on absolute values.

Signed-off-by: Richard Henderson 
---
 target/arm/translate-a64.c |  6 +++---
 target/arm/translate.c | 10 +-
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 422ce9288d..b42643 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -340,9 +340,9 @@ static void gen_exception_internal(int excp)
 gen_helper_exception_internal(cpu_env, tcg_constant_i32(excp));
 }
 
-static void gen_exception_internal_insn(DisasContext *s, uint64_t pc, int excp)
+static void gen_exception_internal_insn(DisasContext *s, int pc_diff, int excp)
 {
-gen_a64_update_pc(s, pc - s->pc_curr);
+gen_a64_update_pc(s, pc_diff);
 gen_exception_internal(excp);
 s->base.is_jmp = DISAS_NORETURN;
 }
@@ -2229,7 +2229,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
 break;
 }
 #endif
-gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
+gen_exception_internal_insn(s, 0, EXCP_SEMIHOST);
 } else {
 unallocated_encoding(s);
 }
diff --git a/target/arm/translate.c b/target/arm/translate.c
index d441e31d3a..63a41ed438 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -1078,10 +1078,10 @@ static inline void gen_smc(DisasContext *s)
 s->base.is_jmp = DISAS_SMC;
 }
 
-static void gen_exception_internal_insn(DisasContext *s, uint32_t pc, int excp)
+static void gen_exception_internal_insn(DisasContext *s, int pc_diff, int excp)
 {
 gen_set_condexec(s);
-gen_update_pc(s, pc - s->pc_curr);
+gen_update_pc(s, pc_diff);
 gen_exception_internal(excp);
 s->base.is_jmp = DISAS_NORETURN;
 }
@@ -1175,7 +1175,7 @@ static inline void gen_hlt(DisasContext *s, int imm)
 s->current_el != 0 &&
 #endif
 (imm == (s->thumb ? 0x3c : 0xf000))) {
-gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
+gen_exception_internal_insn(s, 0, EXCP_SEMIHOST);
 return;
 }
 
@@ -6565,7 +6565,7 @@ static bool trans_BKPT(DisasContext *s, arg_BKPT *a)
 !IS_USER(s) &&
 #endif
 (a->imm == 0xab)) {
-gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
+gen_exception_internal_insn(s, 0, EXCP_SEMIHOST);
 } else {
 gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false));
 }
@@ -8773,7 +8773,7 @@ static bool trans_SVC(DisasContext *s, arg_SVC *a)
 !IS_USER(s) &&
 #endif
 (a->imm == semihost_imm)) {
-gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
+gen_exception_internal_insn(s, 0, EXCP_SEMIHOST);
 } else {
 gen_update_pc(s, curr_insn_len(s));
 s->svc_imm = a->imm;
-- 
2.34.1




[PATCH v3 03/17] accel/tcg: Use DisasContextBase in plugin_gen_tb_start

2022-08-22 Thread Richard Henderson
Use the pc coming from db->pc_first rather than the TB.

Use the cached host_addr rather than re-computing for the
first page.  We still need a separate lookup for the second
page because it won't be computed for DisasContextBase until
the translator actually performs a read from the page.

Signed-off-by: Richard Henderson 
---
 include/exec/plugin-gen.h |  7 ---
 accel/tcg/plugin-gen.c| 23 ---
 accel/tcg/translator.c|  2 +-
 3 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/include/exec/plugin-gen.h b/include/exec/plugin-gen.h
index f92f169739..5004728c61 100644
--- a/include/exec/plugin-gen.h
+++ b/include/exec/plugin-gen.h
@@ -19,7 +19,8 @@ struct DisasContextBase;
 
 #ifdef CONFIG_PLUGIN
 
-bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb, bool 
supress);
+bool plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db,
+ bool supress);
 void plugin_gen_tb_end(CPUState *cpu);
 void plugin_gen_insn_start(CPUState *cpu, const struct DisasContextBase *db);
 void plugin_gen_insn_end(void);
@@ -48,8 +49,8 @@ static inline void plugin_insn_append(abi_ptr pc, const void 
*from, size_t size)
 
 #else /* !CONFIG_PLUGIN */
 
-static inline
-bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb, bool 
supress)
+static inline bool
+plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db, bool sup)
 {
 return false;
 }
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index 8377c15383..0f080386af 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -852,7 +852,8 @@ static void plugin_gen_inject(const struct qemu_plugin_tb 
*plugin_tb)
 pr_ops();
 }
 
-bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb, bool 
mem_only)
+bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db,
+ bool mem_only)
 {
 bool ret = false;
 
@@ -870,9 +871,9 @@ bool plugin_gen_tb_start(CPUState *cpu, const 
TranslationBlock *tb, bool mem_onl
 
 ret = true;
 
-ptb->vaddr = tb->pc;
+ptb->vaddr = db->pc_first;
 ptb->vaddr2 = -1;
-get_page_addr_code_hostp(cpu->env_ptr, tb->pc, true, &ptb->haddr1);
+ptb->haddr1 = db->host_addr[0];
 ptb->haddr2 = NULL;
 ptb->mem_only = mem_only;
 
@@ -898,16 +899,16 @@ void plugin_gen_insn_start(CPUState *cpu, const 
DisasContextBase *db)
  * Note that we skip this when haddr1 == NULL, e.g. when we're
  * fetching instructions from a region not backed by RAM.
  */
-if (likely(ptb->haddr1 != NULL && ptb->vaddr2 == -1) &&
-unlikely((db->pc_next & TARGET_PAGE_MASK) !=
- (db->pc_first & TARGET_PAGE_MASK))) {
-get_page_addr_code_hostp(cpu->env_ptr, db->pc_next,
- true, &ptb->haddr2);
-ptb->vaddr2 = db->pc_next;
-}
-if (likely(ptb->vaddr2 == -1)) {
+if (ptb->haddr1 == NULL) {
+pinsn->haddr = NULL;
+} else if (is_same_page(db, db->pc_next)) {
 pinsn->haddr = ptb->haddr1 + pinsn->vaddr - ptb->vaddr;
 } else {
+if (ptb->vaddr2 == -1) {
+ptb->vaddr2 = TARGET_PAGE_ALIGN(db->pc_first);
+get_page_addr_code_hostp(cpu->env_ptr, ptb->vaddr2,
+ true, &ptb->haddr2);
+}
 pinsn->haddr = ptb->haddr2 + pinsn->vaddr - ptb->vaddr2;
 }
 }
diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index c8e9523e52..db924601ea 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -75,7 +75,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int 
max_insns,
 ops->tb_start(db, cpu);
 tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
 
-plugin_enabled = plugin_gen_tb_start(cpu, tb, cflags & CF_MEMI_ONLY);
+plugin_enabled = plugin_gen_tb_start(cpu, db, cflags & CF_MEMI_ONLY);
 
 while (true) {
 db->num_insns++;
-- 
2.34.1




[PATCH v3 09/17] target/arm: Introduce curr_insn_len

2022-08-22 Thread Richard Henderson
A simple helper to retrieve the length of the current insn.

Signed-off-by: Richard Henderson 
---
 target/arm/translate.h | 5 +
 target/arm/translate-vfp.c | 2 +-
 target/arm/translate.c | 5 ++---
 3 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/target/arm/translate.h b/target/arm/translate.h
index af5d4a7086..90bf7c57fc 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -226,6 +226,11 @@ static inline void disas_set_insn_syndrome(DisasContext 
*s, uint32_t syn)
 s->insn_start = NULL;
 }
 
+static inline int curr_insn_len(DisasContext *s)
+{
+return s->base.pc_next - s->pc_curr;
+}
+
 /* is_jmp field values */
 #define DISAS_JUMP  DISAS_TARGET_0 /* only pc was modified dynamically */
 /* CPU state was modified dynamically; exit to main loop for interrupts. */
diff --git a/target/arm/translate-vfp.c b/target/arm/translate-vfp.c
index bd5ae27d09..94cc1e4b77 100644
--- a/target/arm/translate-vfp.c
+++ b/target/arm/translate-vfp.c
@@ -242,7 +242,7 @@ static bool vfp_access_check_a(DisasContext *s, bool 
ignore_vfp_enabled)
 if (s->sme_trap_nonstreaming) {
 gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
syn_smetrap(SME_ET_Streaming,
-   s->base.pc_next - s->pc_curr == 2));
+   curr_insn_len(s) == 2));
 return false;
 }
 
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 9474e4b44b..638a051281 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -6660,7 +6660,7 @@ static ISSInfo make_issinfo(DisasContext *s, int rd, bool 
p, bool w)
 /* ISS not valid if writeback */
 if (p && !w) {
 ret = rd;
-if (s->base.pc_next - s->pc_curr == 2) {
+if (curr_insn_len(s) == 2) {
 ret |= ISSIs16Bit;
 }
 } else {
@@ -9825,8 +9825,7 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, 
CPUState *cpu)
 /* nothing more to generate */
 break;
 case DISAS_WFI:
-gen_helper_wfi(cpu_env,
-   tcg_constant_i32(dc->base.pc_next - dc->pc_curr));
+gen_helper_wfi(cpu_env, tcg_constant_i32(curr_insn_len(dc)));
 /*
  * The helper doesn't necessarily throw an exception, but we
  * must go back to the main loop to check for interrupts anyway.
-- 
2.34.1




[PATCH v3 10/17] target/arm: Change gen_goto_tb to work on displacements

2022-08-22 Thread Richard Henderson
In preparation for TARGET_TB_PCREL, reduce reliance on absolute values.

Signed-off-by: Richard Henderson 
---
 target/arm/translate-a64.c | 40 --
 target/arm/translate.c | 10 ++
 2 files changed, 27 insertions(+), 23 deletions(-)

diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 163df8c615..695ccd0723 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -378,8 +378,10 @@ static inline bool use_goto_tb(DisasContext *s, uint64_t 
dest)
 return translator_use_goto_tb(&s->base, dest);
 }
 
-static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
+static void gen_goto_tb(DisasContext *s, int n, int diff)
 {
+uint64_t dest = s->pc_curr + diff;
+
 if (use_goto_tb(s, dest)) {
 tcg_gen_goto_tb(n);
 gen_a64_set_pc_im(dest);
@@ -1362,7 +1364,7 @@ static inline AArch64DecodeFn *lookup_disas_fn(const 
AArch64DecodeTable *table,
  */
 static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
 {
-uint64_t addr = s->pc_curr + sextract32(insn, 0, 26) * 4;
+int diff = sextract32(insn, 0, 26) * 4;
 
 if (insn & (1U << 31)) {
 /* BL Branch with link */
@@ -1371,7 +1373,7 @@ static void disas_uncond_b_imm(DisasContext *s, uint32_t 
insn)
 
 /* B Branch / BL Branch with link */
 reset_btype(s);
-gen_goto_tb(s, 0, addr);
+gen_goto_tb(s, 0, diff);
 }
 
 /* Compare and branch (immediate)
@@ -1383,14 +1385,14 @@ static void disas_uncond_b_imm(DisasContext *s, 
uint32_t insn)
 static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
 {
 unsigned int sf, op, rt;
-uint64_t addr;
+int diff;
 TCGLabel *label_match;
 TCGv_i64 tcg_cmp;
 
 sf = extract32(insn, 31, 1);
 op = extract32(insn, 24, 1); /* 0: CBZ; 1: CBNZ */
 rt = extract32(insn, 0, 5);
-addr = s->pc_curr + sextract32(insn, 5, 19) * 4;
+diff = sextract32(insn, 5, 19) * 4;
 
 tcg_cmp = read_cpu_reg(s, rt, sf);
 label_match = gen_new_label();
@@ -1399,9 +1401,9 @@ static void disas_comp_b_imm(DisasContext *s, uint32_t 
insn)
 tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
 tcg_cmp, 0, label_match);
 
-gen_goto_tb(s, 0, s->base.pc_next);
+gen_goto_tb(s, 0, 4);
 gen_set_label(label_match);
-gen_goto_tb(s, 1, addr);
+gen_goto_tb(s, 1, diff);
 }
 
 /* Test and branch (immediate)
@@ -1413,13 +1415,13 @@ static void disas_comp_b_imm(DisasContext *s, uint32_t 
insn)
 static void disas_test_b_imm(DisasContext *s, uint32_t insn)
 {
 unsigned int bit_pos, op, rt;
-uint64_t addr;
+int diff;
 TCGLabel *label_match;
 TCGv_i64 tcg_cmp;
 
 bit_pos = (extract32(insn, 31, 1) << 5) | extract32(insn, 19, 5);
 op = extract32(insn, 24, 1); /* 0: TBZ; 1: TBNZ */
-addr = s->pc_curr + sextract32(insn, 5, 14) * 4;
+diff = sextract32(insn, 5, 14) * 4;
 rt = extract32(insn, 0, 5);
 
 tcg_cmp = tcg_temp_new_i64();
@@ -1430,9 +1432,9 @@ static void disas_test_b_imm(DisasContext *s, uint32_t 
insn)
 tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
 tcg_cmp, 0, label_match);
 tcg_temp_free_i64(tcg_cmp);
-gen_goto_tb(s, 0, s->base.pc_next);
+gen_goto_tb(s, 0, 4);
 gen_set_label(label_match);
-gen_goto_tb(s, 1, addr);
+gen_goto_tb(s, 1, diff);
 }
 
 /* Conditional branch (immediate)
@@ -1444,13 +1446,13 @@ static void disas_test_b_imm(DisasContext *s, uint32_t 
insn)
 static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
 {
 unsigned int cond;
-uint64_t addr;
+int diff;
 
 if ((insn & (1 << 4)) || (insn & (1 << 24))) {
 unallocated_encoding(s);
 return;
 }
-addr = s->pc_curr + sextract32(insn, 5, 19) * 4;
+diff = sextract32(insn, 5, 19) * 4;
 cond = extract32(insn, 0, 4);
 
 reset_btype(s);
@@ -1458,12 +1460,12 @@ static void disas_cond_b_imm(DisasContext *s, uint32_t 
insn)
 /* genuinely conditional branches */
 TCGLabel *label_match = gen_new_label();
 arm_gen_test_cc(cond, label_match);
-gen_goto_tb(s, 0, s->base.pc_next);
+gen_goto_tb(s, 0, 4);
 gen_set_label(label_match);
-gen_goto_tb(s, 1, addr);
+gen_goto_tb(s, 1, diff);
 } else {
 /* 0xe and 0xf are both "always" conditions */
-gen_goto_tb(s, 0, addr);
+gen_goto_tb(s, 0, diff);
 }
 }
 
@@ -1637,7 +1639,7 @@ static void handle_sync(DisasContext *s, uint32_t insn,
  * any pending interrupts immediately.
  */
 reset_btype(s);
-gen_goto_tb(s, 0, s->base.pc_next);
+gen_goto_tb(s, 0, 4);
 return;
 
 case 7: /* SB */
@@ -1649,7 +1651,7 @@ static void handle_sync(DisasContext *s, uint32_t insn,
  * MB and end the TB instead.
  */
 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
-gen_goto_tb(s, 0, s->base.pc_next);
+gen_goto_tb(s, 0, 4);
 return;

[PATCH v3 01/17] accel/tcg: Remove PageDesc code_bitmap

2022-08-22 Thread Richard Henderson
This bitmap is created and discarded immediately.
We gain nothing by its existence.

Signed-off-by: Richard Henderson 
---
 accel/tcg/translate-all.c | 78 ++-
 1 file changed, 4 insertions(+), 74 deletions(-)

diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index e44f40b234..34bf296250 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -102,21 +102,14 @@
 #define assert_memory_lock() tcg_debug_assert(have_mmap_lock())
 #endif
 
-#define SMC_BITMAP_USE_THRESHOLD 10
-
 typedef struct PageDesc {
 /* list of TBs intersecting this ram page */
 uintptr_t first_tb;
-#ifdef CONFIG_SOFTMMU
-/* in order to optimize self modifying code, we count the number
-   of lookups we do to a given page to use a bitmap */
-unsigned long *code_bitmap;
-unsigned int code_write_count;
-#else
+#ifdef CONFIG_USER_ONLY
 unsigned long flags;
 void *target_data;
 #endif
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_SOFTMMU
 QemuSpin lock;
 #endif
 } PageDesc;
@@ -907,17 +900,6 @@ void tb_htable_init(void)
 qht_init(&tb_ctx.htable, tb_cmp, CODE_GEN_HTABLE_SIZE, mode);
 }
 
-/* call with @p->lock held */
-static inline void invalidate_page_bitmap(PageDesc *p)
-{
-assert_page_locked(p);
-#ifdef CONFIG_SOFTMMU
-g_free(p->code_bitmap);
-p->code_bitmap = NULL;
-p->code_write_count = 0;
-#endif
-}
-
 /* Set to NULL all the 'first_tb' fields in all PageDescs. */
 static void page_flush_tb_1(int level, void **lp)
 {
@@ -932,7 +914,6 @@ static void page_flush_tb_1(int level, void **lp)
 for (i = 0; i < V_L2_SIZE; ++i) {
 page_lock(&pd[i]);
 pd[i].first_tb = (uintptr_t)NULL;
-invalidate_page_bitmap(pd + i);
 page_unlock(&pd[i]);
 }
 } else {
@@ -1197,11 +1178,9 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, 
bool rm_from_page_list)
 if (rm_from_page_list) {
 p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
 tb_page_remove(p, tb);
-invalidate_page_bitmap(p);
 if (tb->page_addr[1] != -1) {
 p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
 tb_page_remove(p, tb);
-invalidate_page_bitmap(p);
 }
 }
 
@@ -1246,35 +1225,6 @@ void tb_phys_invalidate(TranslationBlock *tb, 
tb_page_addr_t page_addr)
 }
 }
 
-#ifdef CONFIG_SOFTMMU
-/* call with @p->lock held */
-static void build_page_bitmap(PageDesc *p)
-{
-int n, tb_start, tb_end;
-TranslationBlock *tb;
-
-assert_page_locked(p);
-p->code_bitmap = bitmap_new(TARGET_PAGE_SIZE);
-
-PAGE_FOR_EACH_TB(p, tb, n) {
-/* NOTE: this is subtle as a TB may span two physical pages */
-if (n == 0) {
-/* NOTE: tb_end may be after the end of the page, but
-   it is not a problem */
-tb_start = tb->pc & ~TARGET_PAGE_MASK;
-tb_end = tb_start + tb->size;
-if (tb_end > TARGET_PAGE_SIZE) {
-tb_end = TARGET_PAGE_SIZE;
- }
-} else {
-tb_start = 0;
-tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
-}
-bitmap_set(p->code_bitmap, tb_start, tb_end - tb_start);
-}
-}
-#endif
-
 /* add the tb in the target page and protect it if necessary
  *
  * Called with mmap_lock held for user-mode emulation.
@@ -1295,7 +1245,6 @@ static inline void tb_page_add(PageDesc *p, 
TranslationBlock *tb,
 page_already_protected = p->first_tb != (uintptr_t)NULL;
 #endif
 p->first_tb = (uintptr_t)tb | n;
-invalidate_page_bitmap(p);
 
 #if defined(CONFIG_USER_ONLY)
 /* translator_loop() must have made all TB pages non-writable */
@@ -1357,10 +1306,8 @@ tb_link_page(TranslationBlock *tb, tb_page_addr_t 
phys_pc,
 /* remove TB from the page(s) if we couldn't insert it */
 if (unlikely(existing_tb)) {
 tb_page_remove(p, tb);
-invalidate_page_bitmap(p);
 if (p2) {
 tb_page_remove(p2, tb);
-invalidate_page_bitmap(p2);
 }
 tb = existing_tb;
 }
@@ -1731,7 +1678,6 @@ tb_invalidate_phys_page_range__locked(struct 
page_collection *pages,
 #if !defined(CONFIG_USER_ONLY)
 /* if no code remaining, no need to continue to use slow writes */
 if (!p->first_tb) {
-invalidate_page_bitmap(p);
 tlb_unprotect_code(start);
 }
 #endif
@@ -1827,24 +1773,8 @@ void tb_invalidate_phys_page_fast(struct page_collection 
*pages,
 }
 
 assert_page_locked(p);
-if (!p->code_bitmap &&
-++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD) {
-build_page_bitmap(p);
-}
-if (p->code_bitmap) {
-unsigned int nr;
-unsigned long b;
-
-nr = start & ~TARGET_PAGE_MASK;
-b = p->code_bitmap[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG - 1));
-if (b & ((1 << len) - 1)) {
-goto do_invalidate;
-}
-} else {
-do_invalidate:

[PATCH v3 11/17] target/arm: Change gen_*set_pc_im to gen_*update_pc

2022-08-22 Thread Richard Henderson
In preparation for TARGET_TB_PCREL, reduce reliance on
absolute values by passing in pc difference.

Signed-off-by: Richard Henderson 
---
 target/arm/translate-a32.h |  2 +-
 target/arm/translate.h |  6 ++--
 target/arm/translate-a64.c | 32 +-
 target/arm/translate-vfp.c |  2 +-
 target/arm/translate.c | 68 --
 5 files changed, 56 insertions(+), 54 deletions(-)

diff --git a/target/arm/translate-a32.h b/target/arm/translate-a32.h
index 78a84c1414..09c8f467aa 100644
--- a/target/arm/translate-a32.h
+++ b/target/arm/translate-a32.h
@@ -40,7 +40,7 @@ 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_update_pc(DisasContext *s, int diff);
 void gen_lookup_tb(DisasContext *s);
 long vfp_reg_offset(bool dp, unsigned reg);
 long neon_full_reg_offset(unsigned reg);
diff --git a/target/arm/translate.h b/target/arm/translate.h
index 90bf7c57fc..33b94a18bb 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -254,7 +254,7 @@ static inline int curr_insn_len(DisasContext *s)
  * For instructions which want an immediate exit to the main loop, as opposed
  * to attempting to use lookup_and_goto_ptr.  Unlike DISAS_UPDATE_EXIT, this
  * doesn't write the PC on exiting the translation loop so you need to ensure
- * something (gen_a64_set_pc_im or runtime helper) has done so before we reach
+ * something (gen_a64_update_pc or runtime helper) has done so before we reach
  * return from cpu_tb_exec.
  */
 #define DISAS_EXIT  DISAS_TARGET_9
@@ -263,14 +263,14 @@ static inline int curr_insn_len(DisasContext *s)
 
 #ifdef TARGET_AARCH64
 void a64_translate_init(void);
-void gen_a64_set_pc_im(uint64_t val);
+void gen_a64_update_pc(DisasContext *s, int diff);
 extern const TranslatorOps aarch64_translator_ops;
 #else
 static inline void a64_translate_init(void)
 {
 }
 
-static inline void gen_a64_set_pc_im(uint64_t val)
+static inline void gen_a64_update_pc(DisasContext *s, int diff)
 {
 }
 #endif
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 695ccd0723..90f31b1dff 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -148,9 +148,9 @@ static void reset_btype(DisasContext *s)
 }
 }
 
-void gen_a64_set_pc_im(uint64_t val)
+void gen_a64_update_pc(DisasContext *s, int diff)
 {
-tcg_gen_movi_i64(cpu_pc, val);
+tcg_gen_movi_i64(cpu_pc, s->pc_curr + diff);
 }
 
 /*
@@ -342,14 +342,14 @@ static void gen_exception_internal(int excp)
 
 static void gen_exception_internal_insn(DisasContext *s, uint64_t pc, int excp)
 {
-gen_a64_set_pc_im(pc);
+gen_a64_update_pc(s, pc - s->pc_curr);
 gen_exception_internal(excp);
 s->base.is_jmp = DISAS_NORETURN;
 }
 
 static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syndrome)
 {
-gen_a64_set_pc_im(s->pc_curr);
+gen_a64_update_pc(s, 0);
 gen_helper_exception_bkpt_insn(cpu_env, tcg_constant_i32(syndrome));
 s->base.is_jmp = DISAS_NORETURN;
 }
@@ -384,11 +384,11 @@ static void gen_goto_tb(DisasContext *s, int n, int diff)
 
 if (use_goto_tb(s, dest)) {
 tcg_gen_goto_tb(n);
-gen_a64_set_pc_im(dest);
+gen_a64_update_pc(s, diff);
 tcg_gen_exit_tb(s->base.tb, n);
 s->base.is_jmp = DISAS_NORETURN;
 } else {
-gen_a64_set_pc_im(dest);
+gen_a64_update_pc(s, diff);
 if (s->ss_active) {
 gen_step_complete_exception(s);
 } else {
@@ -1960,7 +1960,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, 
bool isread,
 uint32_t syndrome;
 
 syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
-gen_a64_set_pc_im(s->pc_curr);
+gen_a64_update_pc(s, 0);
 gen_helper_access_check_cp_reg(cpu_env,
tcg_constant_ptr(ri),
tcg_constant_i32(syndrome),
@@ -1970,7 +1970,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, 
bool isread,
  * The readfn or writefn might raise an exception;
  * synchronize the CPU state in case it does.
  */
-gen_a64_set_pc_im(s->pc_curr);
+gen_a64_update_pc(s, 0);
 }
 
 /* Handle special cases first */
@@ -2180,7 +2180,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
 /* The pre HVC helper handles cases when HVC gets trapped
  * as an undefined insn by runtime configuration.
  */
-gen_a64_set_pc_im(s->pc_curr);
+gen_a64_update_pc(s, 0);
 gen_helper_pre_hvc(cpu_env);
 gen_ss_advance(s);
 gen_exception_insn_el(s, s->base.pc_next, EXCP_HVC,
@@ -2191,7 +2191,7 @@ static void disas_exc(DisasContext *s, uint32_

[PATCH v3 07/17] accel/tcg: Introduce TARGET_TB_PCREL

2022-08-22 Thread Richard Henderson
Prepare for targets to be able to produce TBs that can
run in more than one virtual context.

Signed-off-by: Richard Henderson 
---
 include/exec/cpu-defs.h   |  3 +++
 include/exec/exec-all.h   | 41 ++---
 include/hw/core/cpu.h |  1 +
 accel/tcg/cpu-exec.c  | 55 ++-
 accel/tcg/translate-all.c | 48 ++
 5 files changed, 115 insertions(+), 33 deletions(-)

diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
index ba3cd32a1e..87e2bc4e59 100644
--- a/include/exec/cpu-defs.h
+++ b/include/exec/cpu-defs.h
@@ -54,6 +54,9 @@
 #  error TARGET_PAGE_BITS must be defined in cpu-param.h
 # endif
 #endif
+#ifndef TARGET_TB_PCREL
+# define TARGET_TB_PCREL 0
+#endif
 
 #define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8)
 
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index cec3ef1666..b41835bb55 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -459,8 +459,32 @@ struct tb_tc {
 };
 
 struct TranslationBlock {
-target_ulong pc;   /* simulated PC corresponding to this block (EIP + CS 
base) */
-target_ulong cs_base; /* CS base for this block */
+#if !TARGET_TB_PCREL
+/*
+ * Guest PC corresponding to this block.  This must be the true
+ * virtual address.  Therefore e.g. x86 stores EIP + CS_BASE, and
+ * targets like Arm, MIPS, HP-PA, which reuse low bits for ISA or
+ * privilege, must store those bits elsewhere.
+ *
+ * If TARGET_TB_PCREL, the opcodes for the TranslationBlock are
+ * written such that the TB is associated only with the physical
+ * page and may be run in any virtual address context.  In this case,
+ * PC must always be taken from ENV in a target-specific manner.
+ * Unwind information is taken as byte offsets from the "current"
+ * value of the PC, as tracked by the translator.
+ */
+target_ulong pc;
+#endif
+
+/*
+ * Target-specific data associated with the TranslationBlock, e.g.:
+ * x86: the original user, the Code Segment virtual base,
+ * arm: an extension of tb->flags,
+ * s390x: instruction data for EXECUTE,
+ * sparc: the next pc of the instruction queue (for delay slots).
+ */
+target_ulong cs_base;
+
 uint32_t flags; /* flags defining in which context the code was generated 
*/
 uint32_t cflags;/* compile flags */
 
@@ -536,13 +560,24 @@ struct TranslationBlock {
 /* Hide the read to avoid ifdefs for TARGET_TB_PCREL. */
 static inline target_ulong tb_pc(const TranslationBlock *tb)
 {
+#if TARGET_TB_PCREL
+qemu_build_not_reached();
+#else
 return tb->pc;
+#endif
 }
 
-/* Similarly, but for logs. */
+/*
+ * Similarly, but for logs. In this case, when the virtual pc
+ * is not available, use the physical address.
+ */
 static inline target_ulong tb_pc_log(const TranslationBlock *tb)
 {
+#if TARGET_TB_PCREL
+return tb->page_addr[0];
+#else
 return tb->pc;
+#endif
 }
 
 /* Hide the qatomic_read to make code a little easier on the eyes */
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 8edef14199..7dcfccf6e2 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -235,6 +235,7 @@ struct hvf_vcpu_state;
 
 typedef struct {
 TranslationBlock *tb;
+vaddr pc;
 } CPUJumpCache;
 
 /* work queue */
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index f146960b7b..3fb7ce05f8 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -185,7 +185,7 @@ static bool tb_lookup_cmp(const void *p, const void *d)
 const TranslationBlock *tb = p;
 const struct tb_desc *desc = d;
 
-if (tb_pc(tb) == desc->pc &&
+if ((TARGET_TB_PCREL || tb_pc(tb) == desc->pc) &&
 tb->page_addr[0] == desc->page_addr0 &&
 tb->cs_base == desc->cs_base &&
 tb->flags == desc->flags &&
@@ -227,7 +227,8 @@ static TranslationBlock *tb_htable_lookup(CPUState *cpu, 
target_ulong pc,
 return NULL;
 }
 desc.page_addr0 = phys_pc;
-h = tb_hash_func(phys_pc, pc, flags, cflags, *cpu->trace_dstate);
+h = tb_hash_func(phys_pc, (TARGET_TB_PCREL ? 0 : pc),
+ flags, cflags, *cpu->trace_dstate);
 return qht_lookup_custom(&tb_ctx.htable, &desc, h, tb_lookup_cmp);
 }
 
@@ -243,21 +244,42 @@ static inline TranslationBlock *tb_lookup(CPUState *cpu, 
target_ulong pc,
 tcg_debug_assert(!(cflags & CF_INVALID));
 
 hash = tb_jmp_cache_hash_func(pc);
-tb = qatomic_rcu_read(&cpu->tb_jmp_cache[hash].tb);
-
-if (likely(tb &&
-   tb->pc == pc &&
-   tb->cs_base == cs_base &&
-   tb->flags == flags &&
-   tb->trace_vcpu_dstate == *cpu->trace_dstate &&
-   tb_cflags(tb) == cflags)) {
-return tb;
+if (TARGET_TB_PCREL) {
+/* Use acquire to ensure current load of pc from tb_jmp_cache[]. */
+tb = qatomic_load_acquire(&cpu->tb_jmp_cache[hash].tb);
+} else {
+/* Use rcu_

[PATCH v3 04/17] accel/tcg: Do not align tb->page_addr[0]

2022-08-22 Thread Richard Henderson
Let tb->page_addr[0] contain the offset within the page of the
start of the translation block.  We need to recover this value
anyway at various points, and it is easier to discard the page
offset when it's not needed, which happens naturally via the
existing find_page shift.

Signed-off-by: Richard Henderson 
---
 accel/tcg/cpu-exec.c  | 16 
 accel/tcg/cputlb.c|  3 ++-
 accel/tcg/translate-all.c |  9 +
 3 files changed, 15 insertions(+), 13 deletions(-)

diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 7b8977a0a4..b1fd962718 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -174,7 +174,7 @@ struct tb_desc {
 target_ulong pc;
 target_ulong cs_base;
 CPUArchState *env;
-tb_page_addr_t phys_page1;
+tb_page_addr_t page_addr0;
 uint32_t flags;
 uint32_t cflags;
 uint32_t trace_vcpu_dstate;
@@ -186,7 +186,7 @@ static bool tb_lookup_cmp(const void *p, const void *d)
 const struct tb_desc *desc = d;
 
 if (tb->pc == desc->pc &&
-tb->page_addr[0] == desc->phys_page1 &&
+tb->page_addr[0] == desc->page_addr0 &&
 tb->cs_base == desc->cs_base &&
 tb->flags == desc->flags &&
 tb->trace_vcpu_dstate == desc->trace_vcpu_dstate &&
@@ -195,12 +195,12 @@ static bool tb_lookup_cmp(const void *p, const void *d)
 if (tb->page_addr[1] == -1) {
 return true;
 } else {
-tb_page_addr_t phys_page2;
-target_ulong virt_page2;
+tb_page_addr_t phys_page1;
+target_ulong virt_page1;
 
-virt_page2 = (desc->pc & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
-phys_page2 = get_page_addr_code(desc->env, virt_page2);
-if (tb->page_addr[1] == phys_page2) {
+virt_page1 = TARGET_PAGE_ALIGN(desc->pc);
+phys_page1 = get_page_addr_code(desc->env, virt_page1);
+if (tb->page_addr[1] == phys_page1) {
 return true;
 }
 }
@@ -226,7 +226,7 @@ static TranslationBlock *tb_htable_lookup(CPUState *cpu, 
target_ulong pc,
 if (phys_pc == -1) {
 return NULL;
 }
-desc.phys_page1 = phys_pc & TARGET_PAGE_MASK;
+desc.page_addr0 = phys_pc;
 h = tb_hash_func(phys_pc, pc, flags, cflags, *cpu->trace_dstate);
 return qht_lookup_custom(&tb_ctx.htable, &desc, h, tb_lookup_cmp);
 }
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index ae7b40dd51..8b81b07b79 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -951,7 +951,8 @@ void tlb_flush_page_bits_by_mmuidx_all_cpus_synced(CPUState 
*src_cpu,
can be detected */
 void tlb_protect_code(ram_addr_t ram_addr)
 {
-cpu_physical_memory_test_and_clear_dirty(ram_addr, TARGET_PAGE_SIZE,
+cpu_physical_memory_test_and_clear_dirty(ram_addr & TARGET_PAGE_MASK,
+ TARGET_PAGE_SIZE,
  DIRTY_MEMORY_CODE);
 }
 
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index a8f1c34c4e..20f00f4335 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -1167,7 +1167,7 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, 
bool rm_from_page_list)
 qemu_spin_unlock(&tb->jmp_lock);
 
 /* remove the TB from the hash list */
-phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
+phys_pc = tb->page_addr[0];
 h = tb_hash_func(phys_pc, tb->pc, tb->flags, orig_cflags,
  tb->trace_vcpu_dstate);
 if (!qht_remove(&tb_ctx.htable, tb, h)) {
@@ -1291,7 +1291,7 @@ tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
  * we can only insert TBs that are fully initialized.
  */
 page_lock_pair(&p, phys_pc, &p2, phys_page2, true);
-tb_page_add(p, tb, 0, phys_pc & TARGET_PAGE_MASK);
+tb_page_add(p, tb, 0, phys_pc);
 if (p2) {
 tb_page_add(p2, tb, 1, phys_page2);
 } else {
@@ -1644,11 +1644,12 @@ tb_invalidate_phys_page_range__locked(struct 
page_collection *pages,
 if (n == 0) {
 /* NOTE: tb_end may be after the end of the page, but
it is not a problem */
-tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
+tb_start = tb->page_addr[0];
 tb_end = tb_start + tb->size;
 } else {
 tb_start = tb->page_addr[1];
-tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
+tb_end = tb_start + ((tb->page_addr[0] + tb->size)
+ & ~TARGET_PAGE_MASK);
 }
 if (!(tb_end <= start || tb_start >= end)) {
 #ifdef TARGET_HAS_PRECISE_SMC
-- 
2.34.1




[PATCH v3 00/17] accel/tcg + target/arm: pc-relative translation

2022-08-22 Thread Richard Henderson
Based-on: 20220819032615.884847-1-richard.hender...@linaro.org
("[PATCH v6 00/21] linux-user: Fix siginfo_t contents when jumping to 
non-readable pages")

v1: 
https://lore.kernel.org/qemu-devel/20220816203400.161187-1-richard.hender...@linaro.org/

Just a simple refresh from v2 for the dependencies.


r~


Richard Henderson (17):
  accel/tcg: Remove PageDesc code_bitmap
  accel/tcg: Use bool for page_find_alloc
  accel/tcg: Use DisasContextBase in plugin_gen_tb_start
  accel/tcg: Do not align tb->page_addr[0]
  include/hw/core: Create struct CPUJumpCache
  accel/tcg: Introduce tb_pc and tb_pc_log
  accel/tcg: Introduce TARGET_TB_PCREL
  accel/tcg: Split log_cpu_exec into inline and slow path
  target/arm: Introduce curr_insn_len
  target/arm: Change gen_goto_tb to work on displacements
  target/arm: Change gen_*set_pc_im to gen_*update_pc
  target/arm: Change gen_exception_insn* to work on displacements
  target/arm: Change gen_exception_internal to work on displacements
  target/arm: Change gen_jmp* to work on displacements
  target/arm: Introduce gen_pc_plus_diff for aarch64
  target/arm: Introduce gen_pc_plus_diff for aarch32
  target/arm: Enable TARGET_TB_PCREL

 include/exec/cpu-defs.h |   3 +
 include/exec/exec-all.h |  51 +-
 include/exec/plugin-gen.h   |   7 +-
 include/hw/core/cpu.h   |   9 +-
 target/arm/cpu-param.h  |   2 +
 target/arm/translate-a32.h  |   2 +-
 target/arm/translate.h  |  21 ++-
 accel/tcg/cpu-exec.c| 108 +++
 accel/tcg/cputlb.c  |   5 +-
 accel/tcg/plugin-gen.c  |  23 +--
 accel/tcg/translate-all.c   | 168 ++---
 accel/tcg/translator.c  |   2 +-
 target/arm/cpu.c|  23 +--
 target/arm/translate-a64.c  | 174 +++---
 target/arm/translate-m-nocp.c   |   6 +-
 target/arm/translate-mve.c  |   2 +-
 target/arm/translate-vfp.c  |  10 +-
 target/arm/translate.c  | 232 +++-
 target/avr/cpu.c|   2 +-
 target/hexagon/cpu.c|   2 +-
 target/hppa/cpu.c   |   4 +-
 target/i386/tcg/tcg-cpu.c   |   2 +-
 target/loongarch/cpu.c  |   2 +-
 target/microblaze/cpu.c |   2 +-
 target/mips/tcg/exception.c |   2 +-
 target/mips/tcg/sysemu/special_helper.c |   2 +-
 target/openrisc/cpu.c   |   2 +-
 target/riscv/cpu.c  |   4 +-
 target/rx/cpu.c |   2 +-
 target/sh4/cpu.c|   4 +-
 target/sparc/cpu.c  |   2 +-
 target/tricore/cpu.c|   2 +-
 tcg/tcg.c   |   6 +-
 33 files changed, 517 insertions(+), 371 deletions(-)

-- 
2.34.1




[PATCH v3 06/17] accel/tcg: Introduce tb_pc and tb_pc_log

2022-08-22 Thread Richard Henderson
The availability of tb->pc will shortly be conditional.
Introduce accessor functions to minimize ifdefs.

Signed-off-by: Richard Henderson 
---
 include/exec/exec-all.h | 12 ++
 accel/tcg/cpu-exec.c| 20 -
 accel/tcg/translate-all.c   | 29 +
 target/arm/cpu.c|  4 ++--
 target/avr/cpu.c|  2 +-
 target/hexagon/cpu.c|  2 +-
 target/hppa/cpu.c   |  4 ++--
 target/i386/tcg/tcg-cpu.c   |  2 +-
 target/loongarch/cpu.c  |  2 +-
 target/microblaze/cpu.c |  2 +-
 target/mips/tcg/exception.c |  2 +-
 target/mips/tcg/sysemu/special_helper.c |  2 +-
 target/openrisc/cpu.c   |  2 +-
 target/riscv/cpu.c  |  4 ++--
 target/rx/cpu.c |  2 +-
 target/sh4/cpu.c|  4 ++--
 target/sparc/cpu.c  |  2 +-
 target/tricore/cpu.c|  2 +-
 tcg/tcg.c   |  6 ++---
 19 files changed, 59 insertions(+), 46 deletions(-)

diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 4ad166966b..cec3ef1666 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -533,6 +533,18 @@ struct TranslationBlock {
 uintptr_t jmp_dest[2];
 };
 
+/* Hide the read to avoid ifdefs for TARGET_TB_PCREL. */
+static inline target_ulong tb_pc(const TranslationBlock *tb)
+{
+return tb->pc;
+}
+
+/* Similarly, but for logs. */
+static inline target_ulong tb_pc_log(const TranslationBlock *tb)
+{
+return tb->pc;
+}
+
 /* Hide the qatomic_read to make code a little easier on the eyes */
 static inline uint32_t tb_cflags(const TranslationBlock *tb)
 {
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 3f8e4bbbc8..f146960b7b 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -185,7 +185,7 @@ static bool tb_lookup_cmp(const void *p, const void *d)
 const TranslationBlock *tb = p;
 const struct tb_desc *desc = d;
 
-if (tb->pc == desc->pc &&
+if (tb_pc(tb) == desc->pc &&
 tb->page_addr[0] == desc->page_addr0 &&
 tb->cs_base == desc->cs_base &&
 tb->flags == desc->flags &&
@@ -413,7 +413,7 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int 
*tb_exit)
 TranslationBlock *last_tb;
 const void *tb_ptr = itb->tc.ptr;
 
-log_cpu_exec(itb->pc, cpu, itb);
+log_cpu_exec(tb_pc_log(itb), cpu, itb);
 
 qemu_thread_jit_execute();
 ret = tcg_qemu_tb_exec(env, tb_ptr);
@@ -437,16 +437,16 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int 
*tb_exit)
  * of the start of the TB.
  */
 CPUClass *cc = CPU_GET_CLASS(cpu);
-qemu_log_mask_and_addr(CPU_LOG_EXEC, last_tb->pc,
+qemu_log_mask_and_addr(CPU_LOG_EXEC, tb_pc_log(last_tb),
"Stopped execution of TB chain before %p ["
TARGET_FMT_lx "] %s\n",
-   last_tb->tc.ptr, last_tb->pc,
-   lookup_symbol(last_tb->pc));
+   last_tb->tc.ptr, tb_pc_log(last_tb),
+   lookup_symbol(tb_pc_log(last_tb)));
 if (cc->tcg_ops->synchronize_from_tb) {
 cc->tcg_ops->synchronize_from_tb(cpu, last_tb);
 } else {
 assert(cc->set_pc);
-cc->set_pc(cpu, last_tb->pc);
+cc->set_pc(cpu, tb_pc(last_tb));
 }
 }
 
@@ -588,11 +588,11 @@ static inline void tb_add_jump(TranslationBlock *tb, int 
n,
 
 qemu_spin_unlock(&tb_next->jmp_lock);
 
-qemu_log_mask_and_addr(CPU_LOG_EXEC, tb->pc,
+qemu_log_mask_and_addr(CPU_LOG_EXEC, tb_pc_log(tb),
"Linking TBs %p [" TARGET_FMT_lx
"] index %d -> %p [" TARGET_FMT_lx "]\n",
-   tb->tc.ptr, tb->pc, n,
-   tb_next->tc.ptr, tb_next->pc);
+   tb->tc.ptr, tb_pc_log(tb), n,
+   tb_next->tc.ptr, tb_pc_log(tb_next));
 return;
 
  out_unlock_next:
@@ -842,7 +842,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, 
TranslationBlock *tb,
 {
 int32_t insns_left;
 
-trace_exec_tb(tb, tb->pc);
+trace_exec_tb(tb, tb_pc_log(tb));
 tb = cpu_tb_exec(cpu, tb, tb_exit);
 if (*tb_exit != TB_EXIT_REQUESTED) {
 *last_tb = tb;
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index c2745f14a6..1248ee3433 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -298,7 +298,7 @@ static int encode_search(TranslationBlock *tb, uint8_t 
*block)
 
 for (j = 0; j < TARGET_INSN_START_WORDS; ++j) {
 if (i == 0) {
-prev = (j == 0 ? tb->pc : 0);
+prev = (j == 0 ? tb_pc(tb) : 0);
 } el

[PATCH v3 08/17] accel/tcg: Split log_cpu_exec into inline and slow path

2022-08-22 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 accel/tcg/cpu-exec.c | 18 --
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 3fb7ce05f8..4dc0a9ec41 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -283,12 +283,11 @@ static inline TranslationBlock *tb_lookup(CPUState *cpu, 
target_ulong pc,
 return tb;
 }
 
-static inline void log_cpu_exec(target_ulong pc, CPUState *cpu,
-const TranslationBlock *tb)
+static void log_cpu_exec1(CPUState *cpu, const TranslationBlock *tb)
 {
-if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_CPU | CPU_LOG_EXEC))
-&& qemu_log_in_addr_range(pc)) {
+target_ulong pc = tb_pc_log(tb);
 
+if (qemu_log_in_addr_range(pc)) {
 qemu_log_mask(CPU_LOG_EXEC,
   "Trace %d: %p [" TARGET_FMT_lx
   "/" TARGET_FMT_lx "/%08x/%08x] %s\n",
@@ -315,6 +314,13 @@ static inline void log_cpu_exec(target_ulong pc, CPUState 
*cpu,
 }
 }
 
+static inline void log_cpu_exec(CPUState *cpu, const TranslationBlock *tb)
+{
+if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_CPU | CPU_LOG_EXEC))) {
+log_cpu_exec1(cpu, tb);
+}
+}
+
 static bool check_for_breakpoints(CPUState *cpu, target_ulong pc,
   uint32_t *cflags)
 {
@@ -412,7 +418,7 @@ const void *HELPER(lookup_tb_ptr)(CPUArchState *env)
 return tcg_code_gen_epilogue;
 }
 
-log_cpu_exec(pc, cpu, tb);
+log_cpu_exec(cpu, tb);
 
 return tb->tc.ptr;
 }
@@ -435,7 +441,7 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int 
*tb_exit)
 TranslationBlock *last_tb;
 const void *tb_ptr = itb->tc.ptr;
 
-log_cpu_exec(tb_pc_log(itb), cpu, itb);
+log_cpu_exec(cpu, itb);
 
 qemu_thread_jit_execute();
 ret = tcg_qemu_tb_exec(env, tb_ptr);
-- 
2.34.1




[PATCH v3 02/17] accel/tcg: Use bool for page_find_alloc

2022-08-22 Thread Richard Henderson
Bool is more appropriate type for the alloc parameter.

Signed-off-by: Richard Henderson 
---
 accel/tcg/translate-all.c | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 34bf296250..a8f1c34c4e 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -465,7 +465,7 @@ void page_init(void)
 #endif
 }
 
-static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc)
+static PageDesc *page_find_alloc(tb_page_addr_t index, bool alloc)
 {
 PageDesc *pd;
 void **lp;
@@ -533,11 +533,11 @@ static PageDesc *page_find_alloc(tb_page_addr_t index, 
int alloc)
 
 static inline PageDesc *page_find(tb_page_addr_t index)
 {
-return page_find_alloc(index, 0);
+return page_find_alloc(index, false);
 }
 
 static void page_lock_pair(PageDesc **ret_p1, tb_page_addr_t phys1,
-   PageDesc **ret_p2, tb_page_addr_t phys2, int alloc);
+   PageDesc **ret_p2, tb_page_addr_t phys2, bool 
alloc);
 
 /* In user-mode page locks aren't used; mmap_lock is enough */
 #ifdef CONFIG_USER_ONLY
@@ -651,7 +651,7 @@ static inline void page_unlock(PageDesc *pd)
 /* lock the page(s) of a TB in the correct acquisition order */
 static inline void page_lock_tb(const TranslationBlock *tb)
 {
-page_lock_pair(NULL, tb->page_addr[0], NULL, tb->page_addr[1], 0);
+page_lock_pair(NULL, tb->page_addr[0], NULL, tb->page_addr[1], false);
 }
 
 static inline void page_unlock_tb(const TranslationBlock *tb)
@@ -840,7 +840,7 @@ void page_collection_unlock(struct page_collection *set)
 #endif /* !CONFIG_USER_ONLY */
 
 static void page_lock_pair(PageDesc **ret_p1, tb_page_addr_t phys1,
-   PageDesc **ret_p2, tb_page_addr_t phys2, int alloc)
+   PageDesc **ret_p2, tb_page_addr_t phys2, bool alloc)
 {
 PageDesc *p1, *p2;
 tb_page_addr_t page1;
@@ -1290,7 +1290,7 @@ tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
  * Note that inserting into the hash table first isn't an option, since
  * we can only insert TBs that are fully initialized.
  */
-page_lock_pair(&p, phys_pc, &p2, phys_page2, 1);
+page_lock_pair(&p, phys_pc, &p2, phys_page2, true);
 tb_page_add(p, tb, 0, phys_pc & TARGET_PAGE_MASK);
 if (p2) {
 tb_page_add(p2, tb, 1, phys_page2);
@@ -2219,7 +2219,7 @@ void page_set_flags(target_ulong start, target_ulong end, 
int flags)
 for (addr = start, len = end - start;
  len != 0;
  len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) {
-PageDesc *p = page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
+PageDesc *p = page_find_alloc(addr >> TARGET_PAGE_BITS, true);
 
 /* If the write protection bit is set, then we invalidate
the code inside.  */
-- 
2.34.1




Re: [PATCH v6 17/21] accel/tcg: Add fast path for translator_ld*

2022-08-22 Thread Ilya Leoshkevich
On Thu, 2022-08-18 at 20:26 -0700, Richard Henderson wrote:
> Cache the translation from guest to host address, so we may
> use direct loads when we hit on the primary translation page.
> 
> Look up the second translation page only once, during translation.
> This obviates another lookup of the second page within tb_gen_code
> after translation.
> 
> Fixes a bug in that plugin_insn_append should be passed the bytes
> in the original memory order, not bswapped by pieces.
> 
> Signed-off-by: Richard Henderson 
> ---
>  include/exec/translator.h |  63 +++
>  accel/tcg/translate-all.c |  26 +++-
>  accel/tcg/translator.c| 127 +---
> --
>  3 files changed, 144 insertions(+), 72 deletions(-)
> 
> diff --git a/include/exec/translator.h b/include/exec/translator.h
> index 69db0f5c21..329a42fe46 100644
> --- a/include/exec/translator.h
> +++ b/include/exec/translator.h
> @@ -81,24 +81,14 @@ typedef enum DisasJumpType {
>   * Architecture-agnostic disassembly context.
>   */
>  typedef struct DisasContextBase {
> -const TranslationBlock *tb;
> +TranslationBlock *tb;
>  target_ulong pc_first;
>  target_ulong pc_next;
>  DisasJumpType is_jmp;
>  int num_insns;
>  int max_insns;
>  bool singlestep_enabled;
> -#ifdef CONFIG_USER_ONLY
> -/*
> - * Guest address of the last byte of the last protected page.
> - *
> - * Pages containing the translated instructions are made non-
> writable in
> - * order to achieve consistency in case another thread is
> modifying the
> - * code while translate_insn() fetches the instruction bytes
> piecemeal.
> - * Such writer threads are blocked on mmap_lock() in
> page_unprotect().
> - */
> -target_ulong page_protect_end;
> -#endif
> +void *host_addr[2];
>  } DisasContextBase;
>  
>  /**
> @@ -183,24 +173,43 @@ bool translator_use_goto_tb(DisasContextBase
> *db, target_ulong dest);
>   * the relevant information at translation time.
>   */
>  
> -#define GEN_TRANSLATOR_LD(fullname, type, load_fn,
> swap_fn) \
> -type fullname ## _swap(CPUArchState *env, DisasContextBase
> *dcbase, \
> -   abi_ptr pc, bool
> do_swap);   \
> -static inline type fullname(CPUArchState
> *env,  \
> -DisasContextBase *dcbase, abi_ptr
> pc)   \
> -{   
> \
> -return fullname ## _swap(env, dcbase, pc,
> false);   \
> +uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db,
> abi_ptr pc);
> +uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db,
> abi_ptr pc);
> +uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db,
> abi_ptr pc);
> +uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db,
> abi_ptr pc);
> +
> +static inline uint16_t
> +translator_lduw_swap(CPUArchState *env, DisasContextBase *db,
> + abi_ptr pc, bool do_swap)
> +{
> +uint16_t ret = translator_lduw(env, db, pc);
> +if (do_swap) {
> +ret = bswap16(ret);
>  }
> +return ret;
> +}
>  
> -#define
> FOR_EACH_TRANSLATOR_LD(F)   \
> -F(translator_ldub, uint8_t, cpu_ldub_code, /* no swap
> */)   \
> -F(translator_lduw, uint16_t, cpu_lduw_code,
> bswap16)\
> -F(translator_ldl, uint32_t, cpu_ldl_code,
> bswap32)  \
> -F(translator_ldq, uint64_t, cpu_ldq_code, bswap64)
> +static inline uint32_t
> +translator_ldl_swap(CPUArchState *env, DisasContextBase *db,
> +abi_ptr pc, bool do_swap)
> +{
> +uint32_t ret = translator_ldl(env, db, pc);
> +if (do_swap) {
> +ret = bswap32(ret);
> +}
> +return ret;
> +}
>  
> -FOR_EACH_TRANSLATOR_LD(GEN_TRANSLATOR_LD)
> -
> -#undef GEN_TRANSLATOR_LD
> +static inline uint64_t
> +translator_ldq_swap(CPUArchState *env, DisasContextBase *db,
> +abi_ptr pc, bool do_swap)
> +{
> +uint64_t ret = translator_ldq_swap(env, db, pc, false);
> +if (do_swap) {
> +ret = bswap64(ret);
> +}
> +return ret;
> +}
>  
>  /*
>   * Return whether addr is on the same page as where disassembly
> started.
> diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
> index b224f856d0..e44f40b234 100644
> --- a/accel/tcg/translate-all.c
> +++ b/accel/tcg/translate-all.c
> @@ -1385,10 +1385,10 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
>  {
>  CPUArchState *env = cpu->env_ptr;
>  TranslationBlock *tb, *existing_tb;
> -tb_page_addr_t phys_pc, phys_page2;
> -target_ulong virt_page2;
> +tb_page_addr_t phys_pc;
>  tcg_insn_unit *gen_code_buf;
>  int gen_code_size, search_size, max_insns;
> +void *host_pc;
>  #ifdef CONFIG_PROFILER
>  TCGProfile *prof = &tcg_ctx->prof;
>  int64_t ti;
> @@ -1397,7 +1397,7 @@ TranslationBlock *tb_g

Re: [PATCH v7 2/8] file-posix: introduce get_sysfs_str_val for device zoned model

2022-08-22 Thread Stefan Hajnoczi
On Tue, Aug 16, 2022 at 02:25:16PM +0800, Sam Li wrote:
> +static int hdev_get_max_segments(int fd, struct stat *st) {
> +int ret;
> +if (S_ISCHR(st->st_mode)) {
> +if (ioctl(fd, SG_GET_SG_TABLESIZE, &ret) == 0) {

The ioctl must be within #ifdef CONFIG_LINUX since SG_GET_SG_TABLESIZE
will be undefined on other operating systems and a compiler error will
be encountered. Maybe keep the #ifdef around the entire body of this
hdev_get_max_segments().

> +return ret;
> +}
> +return -ENOTSUP;
>  }
> -g_free(sysfspath);
> -return ret;
> -#else
> -return -ENOTSUP;
> -#endif
> +return get_sysfs_long_val(st, "max_segments");

Where is get_sysfs_long_val() defined? Maybe in a later patch? The code
must compile after each patch. You can test this with "git rebase -i
origin/master" and then adding "x make" lines after each commit in the
interactive rebase file. When rebase runs it will execute make after
each commit and will stop if make fails.


signature.asc
Description: PGP signature


[PATCH 6/9] hw/isa/vt82c686: QOM'ify pm creation

2022-08-22 Thread Bernhard Beschow
Signed-off-by: Bernhard Beschow 
---
 hw/isa/vt82c686.c   | 9 +
 hw/mips/fuloong2e.c | 2 +-
 hw/ppc/pegasos2.c   | 2 +-
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index c2f2e0039a..b964d1a760 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -548,6 +548,7 @@ struct ViaISAState {
 ViaSuperIOState via_sio;
 PCIIDEState ide;
 UHCIState uhci[2];
+ViaPMState pm;
 };
 
 static const VMStateDescription vmstate_via = {
@@ -637,6 +638,12 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
 return;
 }
 }
+
+/* Function 4: Power Management */
+qdev_prop_set_int32(DEVICE(&s->pm), "addr", d->devfn + 4);
+if (!qdev_realize(DEVICE(&s->pm), BUS(pci_bus), errp)) {
+return;
+}
 }
 
 /* TYPE_VT82C686B_ISA */
@@ -679,6 +686,7 @@ static void vt82c686b_init(Object *obj)
 ViaISAState *s = VIA_ISA(obj);
 
 object_initialize_child(obj, "sio", &s->via_sio, TYPE_VT82C686B_SUPERIO);
+object_initialize_child(obj, "pm", &s->pm, TYPE_VT82C686B_PM);
 }
 
 static void vt82c686b_class_init(ObjectClass *klass, void *data)
@@ -742,6 +750,7 @@ static void vt8231_init(Object *obj)
 ViaISAState *s = VIA_ISA(obj);
 
 object_initialize_child(obj, "sio", &s->via_sio, TYPE_VT8231_SUPERIO);
+object_initialize_child(obj, "pm", &s->pm, TYPE_VT8231_PM);
 }
 
 static void vt8231_class_init(ObjectClass *klass, void *data)
diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c
index c375107c53..f05474348f 100644
--- a/hw/mips/fuloong2e.c
+++ b/hw/mips/fuloong2e.c
@@ -205,7 +205,7 @@ static void vt82c686b_southbridge_init(PCIBus *pci_bus, int 
slot, qemu_irq intc,
   TYPE_VT82C686B_ISA);
 qdev_connect_gpio_out(DEVICE(dev), 0, intc);
 
-dev = pci_create_simple(pci_bus, PCI_DEVFN(slot, 4), TYPE_VT82C686B_PM);
+dev = PCI_DEVICE(object_resolve_path_component(OBJECT(dev), "pm"));
 *i2c_bus = I2C_BUS(qdev_get_child_bus(DEVICE(dev), "i2c"));
 
 /* Audio support */
diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c
index a1b851638a..4e29e42fba 100644
--- a/hw/ppc/pegasos2.c
+++ b/hw/ppc/pegasos2.c
@@ -166,7 +166,7 @@ static void pegasos2_init(MachineState *machine)
   qdev_get_gpio_in_named(pm->mv, "gpp", 31));
 
 /* VT8231 function 4: Power Management Controller */
-dev = pci_create_simple(pci_bus, PCI_DEVFN(12, 4), TYPE_VT8231_PM);
+dev = PCI_DEVICE(object_resolve_path_component(OBJECT(dev), "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);
-- 
2.37.2




[PATCH 2/9] hw/isa/vt82c686: Resolve unneeded attribute

2022-08-22 Thread Bernhard Beschow
Now that also the super io device is realized in the common realize method,
the isa_bus attribute can be turned into a temporary.

Signed-off-by: Bernhard Beschow 
---
 hw/isa/vt82c686.c | 16 
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index 0217c98fe4..9d12e1cae4 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -543,7 +543,6 @@ struct ViaISAState {
 PCIDevice dev;
 qemu_irq cpu_intr;
 qemu_irq *isa_irqs;
-ISABus *isa_bus;
 ViaSuperIOState via_sio;
 };
 
@@ -585,17 +584,18 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
 ViaISAState *s = VIA_ISA(d);
 DeviceState *dev = DEVICE(d);
 qemu_irq *isa_irq;
+ISABus *isa_bus;
 int i;
 
 qdev_init_gpio_out(dev, &s->cpu_intr, 1);
 isa_irq = qemu_allocate_irqs(via_isa_request_i8259_irq, s, 1);
-s->isa_bus = isa_bus_new(dev, get_system_memory(), pci_address_space_io(d),
+isa_bus = isa_bus_new(dev, get_system_memory(), pci_address_space_io(d),
   &error_fatal);
-s->isa_irqs = i8259_init(s->isa_bus, *isa_irq);
-isa_bus_irqs(s->isa_bus, s->isa_irqs);
-i8254_pit_init(s->isa_bus, 0x40, 0, NULL);
-i8257_dma_init(s->isa_bus, 0);
-mc146818_rtc_init(s->isa_bus, 2000, NULL);
+s->isa_irqs = i8259_init(isa_bus, *isa_irq);
+isa_bus_irqs(isa_bus, s->isa_irqs);
+i8254_pit_init(isa_bus, 0x40, 0, NULL);
+i8257_dma_init(isa_bus, 0);
+mc146818_rtc_init(isa_bus, 2000, NULL);
 
 for (i = 0; i < PCI_CONFIG_HEADER_SIZE; i++) {
 if (i < PCI_COMMAND || i >= PCI_REVISION_ID) {
@@ -604,7 +604,7 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
 }
 
 /* Super I/O */
-if (!qdev_realize(DEVICE(&s->via_sio), BUS(s->isa_bus), errp)) {
+if (!qdev_realize(DEVICE(&s->via_sio), BUS(isa_bus), errp)) {
 return;
 }
 }
-- 
2.37.2




[PATCH 1/9] hw/isa/vt82c686: QOM'ify Super I/O creation

2022-08-22 Thread Bernhard Beschow
The object creation now happens in chip-specific init methods which
allows the realize methods to be consolidated into one method. Shifting
the logic into the init methods has the addidional advantage that the
parent object's init methods are called implicitly.

Signed-off-by: Bernhard Beschow 
---
 hw/isa/vt82c686.c | 33 ++---
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index 8f656251b8..0217c98fe4 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -544,7 +544,7 @@ struct ViaISAState {
 qemu_irq cpu_intr;
 qemu_irq *isa_irqs;
 ISABus *isa_bus;
-ViaSuperIOState *via_sio;
+ViaSuperIOState via_sio;
 };
 
 static const VMStateDescription vmstate_via = {
@@ -602,6 +602,11 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
 d->wmask[i] = 0;
 }
 }
+
+/* Super I/O */
+if (!qdev_realize(DEVICE(&s->via_sio), BUS(s->isa_bus), errp)) {
+return;
+}
 }
 
 /* TYPE_VT82C686B_ISA */
@@ -615,7 +620,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 */
-via_superio_io_enable(s->via_sio, val & BIT(1));
+via_superio_io_enable(&s->via_sio, val & BIT(1));
 }
 }
 
@@ -639,13 +644,11 @@ static void vt82c686b_isa_reset(DeviceState *dev)
 pci_conf[0x77] = 0x10; /* GPIO Control 1/2/3/4 */
 }
 
-static void vt82c686b_realize(PCIDevice *d, Error **errp)
+static void vt82c686b_init(Object *obj)
 {
-ViaISAState *s = VIA_ISA(d);
+ViaISAState *s = VIA_ISA(obj);
 
-via_isa_realize(d, errp);
-s->via_sio = VIA_SUPERIO(isa_create_simple(s->isa_bus,
-   TYPE_VT82C686B_SUPERIO));
+object_initialize_child(obj, "sio", &s->via_sio, TYPE_VT82C686B_SUPERIO);
 }
 
 static void vt82c686b_class_init(ObjectClass *klass, void *data)
@@ -653,7 +656,7 @@ static void vt82c686b_class_init(ObjectClass *klass, void 
*data)
 DeviceClass *dc = DEVICE_CLASS(klass);
 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
-k->realize = vt82c686b_realize;
+k->realize = via_isa_realize;
 k->config_write = vt82c686b_write_config;
 k->vendor_id = PCI_VENDOR_ID_VIA;
 k->device_id = PCI_DEVICE_ID_VIA_82C686B_ISA;
@@ -670,6 +673,7 @@ static const TypeInfo vt82c686b_isa_info = {
 .name  = TYPE_VT82C686B_ISA,
 .parent= TYPE_VIA_ISA,
 .instance_size = sizeof(ViaISAState),
+.instance_init = vt82c686b_init,
 .class_init= vt82c686b_class_init,
 };
 
@@ -684,7 +688,7 @@ static void vt8231_write_config(PCIDevice *d, uint32_t addr,
 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));
+via_superio_io_enable(&s->via_sio, val & BIT(2));
 }
 }
 
@@ -703,13 +707,11 @@ static void vt8231_isa_reset(DeviceState *dev)
 pci_conf[0x6b] = 0x01; /* Fast IR I/O Base */
 }
 
-static void vt8231_realize(PCIDevice *d, Error **errp)
+static void vt8231_init(Object *obj)
 {
-ViaISAState *s = VIA_ISA(d);
+ViaISAState *s = VIA_ISA(obj);
 
-via_isa_realize(d, errp);
-s->via_sio = VIA_SUPERIO(isa_create_simple(s->isa_bus,
-   TYPE_VT8231_SUPERIO));
+object_initialize_child(obj, "sio", &s->via_sio, TYPE_VT8231_SUPERIO);
 }
 
 static void vt8231_class_init(ObjectClass *klass, void *data)
@@ -717,7 +719,7 @@ 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->realize = via_isa_realize;
 k->config_write = vt8231_write_config;
 k->vendor_id = PCI_VENDOR_ID_VIA;
 k->device_id = PCI_DEVICE_ID_VIA_8231_ISA;
@@ -734,6 +736,7 @@ static const TypeInfo vt8231_isa_info = {
 .name  = TYPE_VT8231_ISA,
 .parent= TYPE_VIA_ISA,
 .instance_size = sizeof(ViaISAState),
+.instance_init = vt8231_init,
 .class_init= vt8231_class_init,
 };
 
-- 
2.37.2




[PATCH 9/9] hw/isa/vt82c686: Reuse errp

2022-08-22 Thread Bernhard Beschow
Rather than terminating abruptly, make use of the already present errp and
propagate the error to the caller.

Signed-off-by: Bernhard Beschow 
---
 hw/isa/vt82c686.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index ee745d5d49..15aa5b39f1 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -612,7 +612,12 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
 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, pci_address_space(d), pci_address_space_io(d),
-  &error_fatal);
+  errp);
+
+if (!isa_bus) {
+return;
+}
+
 s->isa_irqs = i8259_init(isa_bus, *isa_irq);
 isa_bus_irqs(isa_bus, s->isa_irqs);
 i8254_pit_init(isa_bus, 0x40, 0, NULL);
-- 
2.37.2




[PATCH 8/9] hw/isa/vt82c686: QOM'ify RTC creation

2022-08-22 Thread Bernhard Beschow
Signed-off-by: Bernhard Beschow 
---
 hw/isa/vt82c686.c | 12 +++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index 47f2fd2669..ee745d5d49 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -546,6 +546,7 @@ struct ViaISAState {
 qemu_irq cpu_intr;
 qemu_irq *isa_irqs;
 ViaSuperIOState via_sio;
+RTCState rtc;
 PCIIDEState ide;
 UHCIState uhci[2];
 ViaPMState pm;
@@ -567,6 +568,7 @@ static void via_isa_init(Object *obj)
 {
 ViaISAState *s = VIA_ISA(obj);
 
+object_initialize_child(obj, "rtc", &s->rtc, TYPE_MC146818_RTC);
 object_initialize_child(obj, "ide", &s->ide, "via-ide");
 object_initialize_child(obj, "uhci1", &s->uhci[0], "vt82c686b-usb-uhci");
 object_initialize_child(obj, "uhci2", &s->uhci[1], "vt82c686b-usb-uhci");
@@ -615,7 +617,15 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
 isa_bus_irqs(isa_bus, s->isa_irqs);
 i8254_pit_init(isa_bus, 0x40, 0, NULL);
 i8257_dma_init(isa_bus, 0);
-mc146818_rtc_init(isa_bus, 2000, NULL);
+
+/* RTC */
+qdev_prop_set_int32(DEVICE(&s->rtc), "base_year", 2000);
+if (!qdev_realize(DEVICE(&s->rtc), BUS(isa_bus), errp)) {
+return;
+}
+object_property_add_alias(qdev_get_machine(), "rtc-time", OBJECT(&s->rtc),
+  "date");
+isa_connect_gpio_out(ISA_DEVICE(&s->rtc), 0, s->rtc.isairq);
 
 for (i = 0; i < PCI_CONFIG_HEADER_SIZE; i++) {
 if (i < PCI_COMMAND || i >= PCI_REVISION_ID) {
-- 
2.37.2




[PATCH 5/6] target/i386: Use tcg gvec for pand, pandn, por, pxor

2022-08-22 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/i386/ops_sse.h|  5 
 target/i386/ops_sse_header.h |  5 
 target/i386/tcg/translate.c  | 45 +---
 3 files changed, 37 insertions(+), 18 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index 6f035b5c16..b21f315f37 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -405,11 +405,6 @@ SSE_HELPER_B(helper_pmaxub, FMAXUB)
 SSE_HELPER_W(helper_pminsw, FMINSW)
 SSE_HELPER_W(helper_pmaxsw, FMAXSW)
 
-SSE_HELPER_Q(helper_pand, FAND)
-SSE_HELPER_Q(helper_pandn, FANDN)
-SSE_HELPER_Q(helper_por, FOR)
-SSE_HELPER_Q(helper_pxor, FXOR)
-
 SSE_HELPER_W(helper_pmullw, FMULLW)
 #if SHIFT == 0
 SSE_HELPER_W(helper_pmulhrw, FMULHRW)
diff --git a/target/i386/ops_sse_header.h b/target/i386/ops_sse_header.h
index da630fbc40..542701720e 100644
--- a/target/i386/ops_sse_header.h
+++ b/target/i386/ops_sse_header.h
@@ -76,11 +76,6 @@ SSE_HELPER_B(pmaxub, FMAXUB)
 SSE_HELPER_W(pminsw, FMINSW)
 SSE_HELPER_W(pmaxsw, FMAXSW)
 
-SSE_HELPER_Q(pand, FAND)
-SSE_HELPER_Q(pandn, FANDN)
-SSE_HELPER_Q(por, FOR)
-SSE_HELPER_Q(pxor, FXOR)
-
 SSE_HELPER_W(pmullw, FMULLW)
 #if SHIFT == 0
 SSE_HELPER_W(pmulhrw, FMULHRW)
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 2a8ea3369a..d25d914d63 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -2820,10 +2820,10 @@ static const SSEFunc_0_epp sse_op_table1[256][4] = {
 [0x51] = SSE_FOP(sqrt),
 [0x52] = { gen_helper_rsqrtps, NULL, gen_helper_rsqrtss, NULL },
 [0x53] = { gen_helper_rcpps, NULL, gen_helper_rcpss, NULL },
-[0x54] = { gen_helper_pand_xmm, gen_helper_pand_xmm }, /* andps, andpd */
-[0x55] = { gen_helper_pandn_xmm, gen_helper_pandn_xmm }, /* andnps, andnpd 
*/
-[0x56] = { gen_helper_por_xmm, gen_helper_por_xmm }, /* orps, orpd */
-[0x57] = { gen_helper_pxor_xmm, gen_helper_pxor_xmm }, /* xorps, xorpd */
+[0x54] = { SSE_DUMMY, SSE_DUMMY }, /* andps, andpd */
+[0x55] = { SSE_DUMMY, SSE_DUMMY }, /* andnps, andnpd */
+[0x56] = { SSE_DUMMY, SSE_DUMMY }, /* orps, orpd */
+[0x57] = { SSE_DUMMY, SSE_DUMMY }, /* xorps, xorpd */
 [0x58] = SSE_FOP(add),
 [0x59] = SSE_FOP(mul),
 [0x5a] = { gen_helper_cvtps2pd, gen_helper_cvtpd2ps,
@@ -2889,11 +2889,11 @@ static const SSEFunc_0_epp sse_op_table1[256][4] = {
 [0xd8] = MMX_OP2(psubusb),
 [0xd9] = MMX_OP2(psubusw),
 [0xda] = MMX_OP2(pminub),
-[0xdb] = MMX_OP2(pand),
+[0xdb] = { SSE_DUMMY, SSE_DUMMY }, /* pand */
 [0xdc] = MMX_OP2(paddusb),
 [0xdd] = MMX_OP2(paddusw),
 [0xde] = MMX_OP2(pmaxub),
-[0xdf] = MMX_OP2(pandn),
+[0xdf] = { SSE_DUMMY, SSE_DUMMY }, /* pandn */
 [0xe0] = MMX_OP2(pavgb),
 [0xe1] = MMX_OP2(psraw),
 [0xe2] = MMX_OP2(psrad),
@@ -2905,11 +2905,11 @@ static const SSEFunc_0_epp sse_op_table1[256][4] = {
 [0xe8] = MMX_OP2(psubsb),
 [0xe9] = MMX_OP2(psubsw),
 [0xea] = MMX_OP2(pminsw),
-[0xeb] = MMX_OP2(por),
+[0xeb] = { SSE_DUMMY, SSE_DUMMY },  /* por */
 [0xec] = MMX_OP2(paddsb),
 [0xed] = MMX_OP2(paddsw),
 [0xee] = MMX_OP2(pmaxsw),
-[0xef] = MMX_OP2(pxor),
+[0xef] = { SSE_DUMMY, SSE_DUMMY },  /* pxor */
 [0xf0] = { NULL, NULL, NULL, SSE_SPECIAL }, /* lddqu */
 [0xf1] = MMX_OP2(psllw),
 [0xf2] = MMX_OP2(pslld),
@@ -4535,6 +4535,35 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 sse_fn_eppt = (SSEFunc_0_eppt)sse_fn_epp;
 sse_fn_eppt(cpu_env, s->ptr0, s->ptr1, s->A0);
 break;
+case 0x54: /* andps, andpd */
+case 0xdb: /* pand */
+op1_offset += xmm_ofs;
+op2_offset += xmm_ofs;
+tcg_gen_gvec_and(MO_64, op1_offset, op1_offset,
+ op2_offset, vec_len, vec_len);
+break;
+case 0x55: /* andnps, andnpd */
+case 0xdf: /* pandn */
+op1_offset += xmm_ofs;
+op2_offset += xmm_ofs;
+/* x86 inverts the first operand; tcg inverts the second. */
+tcg_gen_gvec_andc(MO_64, op1_offset, op2_offset,
+  op1_offset, vec_len, vec_len);
+break;
+case 0x56: /* orps, orpd */
+case 0xeb: /* por */
+op1_offset += xmm_ofs;
+op2_offset += xmm_ofs;
+tcg_gen_gvec_or(MO_64, op1_offset, op1_offset,
+op2_offset, vec_len, vec_len);
+break;
+case 0x57: /* xorps, xorpd */
+case 0xef: /* pxor */
+op1_offset += xmm_ofs;
+op2_offset += xmm_ofs;
+tcg_gen_gvec_xor(MO_64, op1_offset, op1_offset,
+ op2_offset, vec_len, vec_len);
+break;
 case 0x64: /* pcmpgtb */
 case 0x65: /* pcmpgtw */
 case 0x66: /* pcmpgtl */
-- 
2.34.1




[PATCH 5/9] hw/isa/vt82c686: QOM'ify vt82c686b-usb-uhci creation

2022-08-22 Thread Bernhard Beschow
Resolves duplicate code in the boards.

Signed-off-by: Bernhard Beschow 
---
 hw/isa/vt82c686.c   | 12 
 hw/mips/fuloong2e.c |  3 ---
 hw/ppc/pegasos2.c   |  4 
 3 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index 37d9ed635d..c2f2e0039a 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -23,6 +23,7 @@
 #include "hw/intc/i8259.h"
 #include "hw/irq.h"
 #include "hw/dma/i8257.h"
+#include "hw/usb/hcd-uhci.h"
 #include "hw/timer/i8254.h"
 #include "hw/rtc/mc146818rtc.h"
 #include "migration/vmstate.h"
@@ -546,6 +547,7 @@ struct ViaISAState {
 qemu_irq *isa_irqs;
 ViaSuperIOState via_sio;
 PCIIDEState ide;
+UHCIState uhci[2];
 };
 
 static const VMStateDescription vmstate_via = {
@@ -563,6 +565,8 @@ static void via_isa_init(Object *obj)
 ViaISAState *s = VIA_ISA(obj);
 
 object_initialize_child(obj, "ide", &s->ide, "via-ide");
+object_initialize_child(obj, "uhci1", &s->uhci[0], "vt82c686b-usb-uhci");
+object_initialize_child(obj, "uhci2", &s->uhci[1], "vt82c686b-usb-uhci");
 }
 
 static const TypeInfo via_isa_info = {
@@ -625,6 +629,14 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
 return;
 }
 pci_ide_create_devs(PCI_DEVICE(&s->ide));
+
+/* Functions 2-3: USB Ports */
+for (i = 0; i < ARRAY_SIZE(s->uhci); ++i) {
+qdev_prop_set_int32(DEVICE(&s->uhci[i]), "addr", d->devfn + 2 + i);
+if (!qdev_realize(DEVICE(&s->uhci[i]), BUS(pci_bus), errp)) {
+return;
+}
+}
 }
 
 /* TYPE_VT82C686B_ISA */
diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c
index dae263c1e3..c375107c53 100644
--- a/hw/mips/fuloong2e.c
+++ b/hw/mips/fuloong2e.c
@@ -205,9 +205,6 @@ static void vt82c686b_southbridge_init(PCIBus *pci_bus, int 
slot, qemu_irq intc,
   TYPE_VT82C686B_ISA);
 qdev_connect_gpio_out(DEVICE(dev), 0, intc);
 
-pci_create_simple(pci_bus, PCI_DEVFN(slot, 2), "vt82c686b-usb-uhci");
-pci_create_simple(pci_bus, PCI_DEVFN(slot, 3), "vt82c686b-usb-uhci");
-
 dev = pci_create_simple(pci_bus, PCI_DEVFN(slot, 4), TYPE_VT82C686B_PM);
 *i2c_bus = I2C_BUS(qdev_get_child_bus(DEVICE(dev), "i2c"));
 
diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c
index 2f59d08ad1..a1b851638a 100644
--- a/hw/ppc/pegasos2.c
+++ b/hw/ppc/pegasos2.c
@@ -165,10 +165,6 @@ static void pegasos2_init(MachineState *machine)
 qdev_connect_gpio_out(DEVICE(dev), 0,
   qdev_get_gpio_in_named(pm->mv, "gpp", 31));
 
-/* 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"));
-- 
2.37.2




[PATCH 7/9] hw/isa/vt82c686: QOM'ify ac97 and mc97 creation

2022-08-22 Thread Bernhard Beschow
Resolves duplicate code in the boards.

Signed-off-by: Bernhard Beschow 
---
 hw/isa/vt82c686.c   | 16 
 hw/mips/fuloong2e.c |  4 
 hw/ppc/pegasos2.c   |  4 
 3 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index b964d1a760..47f2fd2669 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -549,6 +549,8 @@ struct ViaISAState {
 PCIIDEState ide;
 UHCIState uhci[2];
 ViaPMState pm;
+PCIDevice ac97;
+PCIDevice mc97;
 };
 
 static const VMStateDescription vmstate_via = {
@@ -568,6 +570,8 @@ static void via_isa_init(Object *obj)
 object_initialize_child(obj, "ide", &s->ide, "via-ide");
 object_initialize_child(obj, "uhci1", &s->uhci[0], "vt82c686b-usb-uhci");
 object_initialize_child(obj, "uhci2", &s->uhci[1], "vt82c686b-usb-uhci");
+object_initialize_child(obj, "ac97", &s->ac97, TYPE_VIA_AC97);
+object_initialize_child(obj, "mc97", &s->mc97, TYPE_VIA_MC97);
 }
 
 static const TypeInfo via_isa_info = {
@@ -644,6 +648,18 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
 if (!qdev_realize(DEVICE(&s->pm), BUS(pci_bus), errp)) {
 return;
 }
+
+/* Function 5: AC97 Audio */
+qdev_prop_set_int32(DEVICE(&s->ac97), "addr", d->devfn + 5);
+if (!qdev_realize(DEVICE(&s->ac97), BUS(pci_bus), errp)) {
+return;
+}
+
+/* Function 6: AC97 Modem */
+qdev_prop_set_int32(DEVICE(&s->mc97), "addr", d->devfn + 6);
+if (!qdev_realize(DEVICE(&s->mc97), BUS(pci_bus), errp)) {
+return;
+}
 }
 
 /* TYPE_VT82C686B_ISA */
diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c
index f05474348f..ea1aef3049 100644
--- a/hw/mips/fuloong2e.c
+++ b/hw/mips/fuloong2e.c
@@ -207,10 +207,6 @@ static void vt82c686b_southbridge_init(PCIBus *pci_bus, 
int slot, qemu_irq intc,
 
 dev = PCI_DEVICE(object_resolve_path_component(OBJECT(dev), "pm"));
 *i2c_bus = I2C_BUS(qdev_get_child_bus(DEVICE(dev), "i2c"));
-
-/* Audio support */
-pci_create_simple(pci_bus, PCI_DEVFN(slot, 5), TYPE_VIA_AC97);
-pci_create_simple(pci_bus, PCI_DEVFN(slot, 6), TYPE_VIA_MC97);
 }
 
 /* Network support */
diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c
index 4e29e42fba..89ef4aed8b 100644
--- a/hw/ppc/pegasos2.c
+++ b/hw/ppc/pegasos2.c
@@ -171,10 +171,6 @@ static void pegasos2_init(MachineState *machine)
 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);
 
-- 
2.37.2




[PATCH 4/9] hw/isa/vt82c686: QOM'ify via-ide creation

2022-08-22 Thread Bernhard Beschow
The IDE function is closely tied to the ISA function (e.g. the IDE
interrupt routing happens there), so it makes sense that the IDE
function is instantiated within the southbridge itself. As a side effect,
duplicated code in the boards is resolved.

Signed-off-by: Bernhard Beschow 
---
 configs/devices/mips64el-softmmu/default.mak |  1 -
 hw/isa/Kconfig   |  1 +
 hw/isa/vt82c686.c| 18 ++
 hw/mips/fuloong2e.c  |  3 ---
 hw/ppc/Kconfig   |  1 -
 hw/ppc/pegasos2.c|  4 
 6 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/configs/devices/mips64el-softmmu/default.mak 
b/configs/devices/mips64el-softmmu/default.mak
index c610749ac1..d5188f7ea5 100644
--- a/configs/devices/mips64el-softmmu/default.mak
+++ b/configs/devices/mips64el-softmmu/default.mak
@@ -1,7 +1,6 @@
 # Default configuration for mips64el-softmmu
 
 include ../mips-softmmu/common.mak
-CONFIG_IDE_VIA=y
 CONFIG_FULOONG=y
 CONFIG_LOONGSON3V=y
 CONFIG_ATI_VGA=y
diff --git a/hw/isa/Kconfig b/hw/isa/Kconfig
index d42143a991..20de7e9294 100644
--- a/hw/isa/Kconfig
+++ b/hw/isa/Kconfig
@@ -53,6 +53,7 @@ config VT82C686
 select I8254
 select I8257
 select I8259
+select IDE_VIA
 select MC146818RTC
 select PARALLEL
 
diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index 5582c0b179..37d9ed635d 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -17,6 +17,7 @@
 #include "hw/isa/vt82c686.h"
 #include "hw/pci/pci.h"
 #include "hw/qdev-properties.h"
+#include "hw/ide/pci.h"
 #include "hw/isa/isa.h"
 #include "hw/isa/superio.h"
 #include "hw/intc/i8259.h"
@@ -544,6 +545,7 @@ struct ViaISAState {
 qemu_irq cpu_intr;
 qemu_irq *isa_irqs;
 ViaSuperIOState via_sio;
+PCIIDEState ide;
 };
 
 static const VMStateDescription vmstate_via = {
@@ -556,10 +558,18 @@ static const VMStateDescription vmstate_via = {
 }
 };
 
+static void via_isa_init(Object *obj)
+{
+ViaISAState *s = VIA_ISA(obj);
+
+object_initialize_child(obj, "ide", &s->ide, "via-ide");
+}
+
 static const TypeInfo via_isa_info = {
 .name  = TYPE_VIA_ISA,
 .parent= TYPE_PCI_DEVICE,
 .instance_size = sizeof(ViaISAState),
+.instance_init = via_isa_init,
 .abstract  = true,
 .interfaces= (InterfaceInfo[]) {
 { INTERFACE_CONVENTIONAL_PCI_DEVICE },
@@ -583,6 +593,7 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
 {
 ViaISAState *s = VIA_ISA(d);
 DeviceState *dev = DEVICE(d);
+PCIBus *pci_bus = pci_get_bus(d);
 qemu_irq *isa_irq;
 ISABus *isa_bus;
 int i;
@@ -607,6 +618,13 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
 if (!qdev_realize(DEVICE(&s->via_sio), BUS(isa_bus), errp)) {
 return;
 }
+
+/* Function 1: IDE */
+qdev_prop_set_int32(DEVICE(&s->ide), "addr", d->devfn + 1);
+if (!qdev_realize(DEVICE(&s->ide), BUS(pci_bus), errp)) {
+return;
+}
+pci_ide_create_devs(PCI_DEVICE(&s->ide));
 }
 
 /* TYPE_VT82C686B_ISA */
diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c
index 5ee546f5f6..dae263c1e3 100644
--- a/hw/mips/fuloong2e.c
+++ b/hw/mips/fuloong2e.c
@@ -205,9 +205,6 @@ static void vt82c686b_southbridge_init(PCIBus *pci_bus, int 
slot, qemu_irq intc,
   TYPE_VT82C686B_ISA);
 qdev_connect_gpio_out(DEVICE(dev), 0, intc);
 
-dev = pci_create_simple(pci_bus, PCI_DEVFN(slot, 1), "via-ide");
-pci_ide_create_devs(dev);
-
 pci_create_simple(pci_bus, PCI_DEVFN(slot, 2), "vt82c686b-usb-uhci");
 pci_create_simple(pci_bus, PCI_DEVFN(slot, 3), "vt82c686b-usb-uhci");
 
diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
index 400511c6b7..18565e966b 100644
--- a/hw/ppc/Kconfig
+++ b/hw/ppc/Kconfig
@@ -74,7 +74,6 @@ config PEGASOS2
 bool
 select MV64361
 select VT82C686
-select IDE_VIA
 select SMBUS_EEPROM
 select VOF
 # This should come with VT82C686
diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c
index 61f4263953..2f59d08ad1 100644
--- a/hw/ppc/pegasos2.c
+++ b/hw/ppc/pegasos2.c
@@ -165,10 +165,6 @@ static void pegasos2_init(MachineState *machine)
 qdev_connect_gpio_out(DEVICE(dev), 0,
   qdev_get_gpio_in_named(pm->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");
-- 
2.37.2




[PATCH 3/9] hw/isa/vt82c686: Prefer pci_address_space() over get_system_memory()

2022-08-22 Thread Bernhard Beschow
Unlike get_system_memory(), pci_address_space() respects the memory tree
available to the parent device.

Signed-off-by: Bernhard Beschow 
---
 hw/isa/vt82c686.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index 9d12e1cae4..5582c0b179 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -589,7 +589,7 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
 
 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),
+isa_bus = isa_bus_new(dev, pci_address_space(d), pci_address_space_io(d),
   &error_fatal);
 s->isa_irqs = i8259_init(isa_bus, *isa_irq);
 isa_bus_irqs(isa_bus, s->isa_irqs);
-- 
2.37.2




[PATCH 3/6] target/i386: Use tcg gvec for pcmp{eq,gt}*

2022-08-22 Thread Richard Henderson
As pcmpeqb is used by strlen et al, this is the highest overhead
sse operation, at 2.5%.  It's simple to include the other compares
at the same time.

Signed-off-by: Richard Henderson 
---
 target/i386/ops_sse.h|  8 
 target/i386/ops_sse_header.h |  8 
 target/i386/tcg/translate.c  | 31 +--
 3 files changed, 25 insertions(+), 22 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index 535440f882..94440a9dc5 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -420,14 +420,6 @@ SSE_HELPER_Q(helper_pandn, FANDN)
 SSE_HELPER_Q(helper_por, FOR)
 SSE_HELPER_Q(helper_pxor, FXOR)
 
-SSE_HELPER_B(helper_pcmpgtb, FCMPGTB)
-SSE_HELPER_W(helper_pcmpgtw, FCMPGTW)
-SSE_HELPER_L(helper_pcmpgtl, FCMPGTL)
-
-SSE_HELPER_B(helper_pcmpeqb, FCMPEQ)
-SSE_HELPER_W(helper_pcmpeqw, FCMPEQ)
-SSE_HELPER_L(helper_pcmpeql, FCMPEQ)
-
 SSE_HELPER_W(helper_pmullw, FMULLW)
 #if SHIFT == 0
 SSE_HELPER_W(helper_pmulhrw, FMULHRW)
diff --git a/target/i386/ops_sse_header.h b/target/i386/ops_sse_header.h
index cef28f2aae..b9f957daf8 100644
--- a/target/i386/ops_sse_header.h
+++ b/target/i386/ops_sse_header.h
@@ -91,14 +91,6 @@ SSE_HELPER_Q(pandn, FANDN)
 SSE_HELPER_Q(por, FOR)
 SSE_HELPER_Q(pxor, FXOR)
 
-SSE_HELPER_B(pcmpgtb, FCMPGTB)
-SSE_HELPER_W(pcmpgtw, FCMPGTW)
-SSE_HELPER_L(pcmpgtl, FCMPGTL)
-
-SSE_HELPER_B(pcmpeqb, FCMPEQ)
-SSE_HELPER_W(pcmpeqw, FCMPEQ)
-SSE_HELPER_L(pcmpeql, FCMPEQ)
-
 SSE_HELPER_W(pmullw, FMULLW)
 #if SHIFT == 0
 SSE_HELPER_W(pmulhrw, FMULHRW)
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index c1f1f6f66b..467d018b68 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -2847,9 +2847,9 @@ static const SSEFunc_0_epp sse_op_table1[256][4] = {
 [0x61] = MMX_OP2(punpcklwd),
 [0x62] = MMX_OP2(punpckldq),
 [0x63] = MMX_OP2(packsswb),
-[0x64] = MMX_OP2(pcmpgtb),
-[0x65] = MMX_OP2(pcmpgtw),
-[0x66] = MMX_OP2(pcmpgtl),
+[0x64] = { SSE_DUMMY, SSE_DUMMY },  /* pcmpgtb */
+[0x65] = { SSE_DUMMY, SSE_DUMMY },  /* pcmpgtw */
+[0x66] = { SSE_DUMMY, SSE_DUMMY },  /* pcmpgtl */
 [0x67] = MMX_OP2(packuswb),
 [0x68] = MMX_OP2(punpckhbw),
 [0x69] = MMX_OP2(punpckhwd),
@@ -2866,9 +2866,9 @@ static const SSEFunc_0_epp sse_op_table1[256][4] = {
 [0x71] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftw */
 [0x72] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftd */
 [0x73] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftq */
-[0x74] = MMX_OP2(pcmpeqb),
-[0x75] = MMX_OP2(pcmpeqw),
-[0x76] = MMX_OP2(pcmpeql),
+[0x74] = { SSE_DUMMY, SSE_DUMMY }, /* pcmpeqb */
+[0x75] = { SSE_DUMMY, SSE_DUMMY }, /* pcmpeqw */
+[0x76] = { SSE_DUMMY, SSE_DUMMY }, /* pcmpeql */
 [0x77] = { SSE_DUMMY }, /* emms */
 [0x78] = { NULL, SSE_SPECIAL, NULL, SSE_SPECIAL }, /* extrq_i, insertq_i */
 [0x79] = { NULL, gen_helper_extrq_r, NULL, gen_helper_insertq_r },
@@ -4415,6 +4415,9 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 return;
 }
 } else {
+int vec_len = is_xmm ? 16 : 8;
+int xmm_ofs = is_xmm ? offsetof(ZMMReg, ZMM_X(0)) : 0;
+
 /* generic MMX or SSE operation */
 switch(b) {
 case 0x70: /* pshufx insn */
@@ -4532,6 +4535,22 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 sse_fn_eppt = (SSEFunc_0_eppt)sse_fn_epp;
 sse_fn_eppt(cpu_env, s->ptr0, s->ptr1, s->A0);
 break;
+case 0x64: /* pcmpgtb */
+case 0x65: /* pcmpgtw */
+case 0x66: /* pcmpgtl */
+op1_offset += xmm_ofs;
+op2_offset += xmm_ofs;
+tcg_gen_gvec_cmp(TCG_COND_GT, b - 0x64, op1_offset, op1_offset,
+ op2_offset, vec_len, vec_len);
+break;
+case 0x74: /* pcmpeqb */
+case 0x75: /* pcmpeqw */
+case 0x76: /* pcmpeql */
+op1_offset += xmm_ofs;
+op2_offset += xmm_ofs;
+tcg_gen_gvec_cmp(TCG_COND_EQ, b - 0x74, op1_offset, op1_offset,
+ op2_offset, vec_len, vec_len);
+break;
 default:
 tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
 tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
-- 
2.34.1




[PATCH 0/9] QOM'ify VT82xx devices

2022-08-22 Thread Bernhard Beschow
This series instantiates all PCI functions of the VT82xx southbridges in the 
southbridges themselves.
For the IDE function this is especially important since its interrupt routing 
is configured in the
ISA function, hence doesn't make sense to instantiate it as a "Frankenstein" 
device. The interrupt
routing is currently hardcoded and changing that is currently not in the scope 
of this series.

Testing done:
* `qemu-system-ppc -machine pegasos2 -rtc base=localtime -device 
ati-vga,guest_hwcursor=true,romfile="" -cdrom morphos-3.17.iso -kernel 
morphos-3.17/boot.img`
  Boots successfully and it is possible to open games and tools.

* I was unable to test the fuloong2e board even before this series since it 
seems to be unfinished [1].
  A buildroot-baked kernel [2] booted but doesn't find its root partition, 
though the issues could be in the buildroot receipt I created.

[1] https://osdn.net/projects/qmiga/wiki/SubprojectPegasos2
[2] https://github.com/shentok/buildroot/commits/fuloong2e

Bernhard Beschow (9):
  hw/isa/vt82c686: QOM'ify Super I/O creation
  hw/isa/vt82c686: Resolve unneeded attribute
  hw/isa/vt82c686: Prefer pci_address_space() over get_system_memory()
  hw/isa/vt82c686: QOM'ify via-ide creation
  hw/isa/vt82c686: QOM'ify vt82c686b-usb-uhci creation
  hw/isa/vt82c686: QOM'ify pm creation
  hw/isa/vt82c686: QOM'ify ac97 and mc97 creation
  hw/isa/vt82c686: QOM'ify RTC creation
  hw/isa/vt82c686: Reuse errp

 configs/devices/mips64el-softmmu/default.mak |   1 -
 hw/isa/Kconfig   |   1 +
 hw/isa/vt82c686.c| 119 +++
 hw/mips/fuloong2e.c  |  12 +-
 hw/ppc/Kconfig   |   1 -
 hw/ppc/pegasos2.c|  14 +--
 6 files changed, 99 insertions(+), 49 deletions(-)

-- 
2.37.2




[PATCH 4/6] target/i386: Use tcg gvec for p{add,sub}*

2022-08-22 Thread Richard Henderson
Since psubb is the second highest overhead sse operation, at 0.9%.
It's simple to include add and the other sizes at the same time.

Signed-off-by: Richard Henderson 
---
 target/i386/ops_sse.h| 10 -
 target/i386/ops_sse_header.h | 10 -
 target/i386/tcg/translate.c  | 39 
 3 files changed, 31 insertions(+), 28 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index 94440a9dc5..6f035b5c16 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -389,16 +389,6 @@ static inline int satsw(int x)
 #define FAVG(a, b) (((a) + (b) + 1) >> 1)
 #endif
 
-SSE_HELPER_B(helper_paddb, FADD)
-SSE_HELPER_W(helper_paddw, FADD)
-SSE_HELPER_L(helper_paddl, FADD)
-SSE_HELPER_Q(helper_paddq, FADD)
-
-SSE_HELPER_B(helper_psubb, FSUB)
-SSE_HELPER_W(helper_psubw, FSUB)
-SSE_HELPER_L(helper_psubl, FSUB)
-SSE_HELPER_Q(helper_psubq, FSUB)
-
 SSE_HELPER_B(helper_paddusb, FADDUB)
 SSE_HELPER_B(helper_paddsb, FADDSB)
 SSE_HELPER_B(helper_psubusb, FSUBUB)
diff --git a/target/i386/ops_sse_header.h b/target/i386/ops_sse_header.h
index b9f957daf8..da630fbc40 100644
--- a/target/i386/ops_sse_header.h
+++ b/target/i386/ops_sse_header.h
@@ -60,16 +60,6 @@ DEF_HELPER_3(glue(pslldq, SUFFIX), void, env, Reg, Reg)
 #define SSE_HELPER_Q(name, F)\
 DEF_HELPER_3(glue(name, SUFFIX), void, env, Reg, Reg)
 
-SSE_HELPER_B(paddb, FADD)
-SSE_HELPER_W(paddw, FADD)
-SSE_HELPER_L(paddl, FADD)
-SSE_HELPER_Q(paddq, FADD)
-
-SSE_HELPER_B(psubb, FSUB)
-SSE_HELPER_W(psubw, FSUB)
-SSE_HELPER_L(psubl, FSUB)
-SSE_HELPER_Q(psubq, FSUB)
-
 SSE_HELPER_B(paddusb, FADDUB)
 SSE_HELPER_B(paddsb, FADDSB)
 SSE_HELPER_B(psubusb, FSUBUB)
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 467d018b68..2a8ea3369a 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -2882,7 +2882,7 @@ static const SSEFunc_0_epp sse_op_table1[256][4] = {
 [0xd1] = MMX_OP2(psrlw),
 [0xd2] = MMX_OP2(psrld),
 [0xd3] = MMX_OP2(psrlq),
-[0xd4] = MMX_OP2(paddq),
+[0xd4] = { SSE_DUMMY, SSE_DUMMY },  /* paddq */
 [0xd5] = MMX_OP2(pmullw),
 [0xd6] = { NULL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL },
 [0xd7] = { SSE_SPECIAL, SSE_SPECIAL }, /* pmovmskb */
@@ -2919,13 +2919,13 @@ static const SSEFunc_0_epp sse_op_table1[256][4] = {
 [0xf6] = MMX_OP2(psadbw),
 [0xf7] = { (SSEFunc_0_epp)gen_helper_maskmov_mmx,
(SSEFunc_0_epp)gen_helper_maskmov_xmm }, /* XXX: casts */
-[0xf8] = MMX_OP2(psubb),
-[0xf9] = MMX_OP2(psubw),
-[0xfa] = MMX_OP2(psubl),
-[0xfb] = MMX_OP2(psubq),
-[0xfc] = MMX_OP2(paddb),
-[0xfd] = MMX_OP2(paddw),
-[0xfe] = MMX_OP2(paddl),
+[0xf8] = { SSE_DUMMY, SSE_DUMMY },  /* psubb */
+[0xf9] = { SSE_DUMMY, SSE_DUMMY },  /* psubw */
+[0xfa] = { SSE_DUMMY, SSE_DUMMY },  /* psubl */
+[0xfb] = { SSE_DUMMY, SSE_DUMMY },  /* psubq */
+[0xfc] = { SSE_DUMMY, SSE_DUMMY },  /* paddb */
+[0xfd] = { SSE_DUMMY, SSE_DUMMY },  /* paddw */
+[0xfe] = { SSE_DUMMY, SSE_DUMMY },  /* paddl */
 };
 
 static const SSEFunc_0_epp sse_op_table2[3 * 8][2] = {
@@ -4551,6 +4551,29 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 tcg_gen_gvec_cmp(TCG_COND_EQ, b - 0x74, op1_offset, op1_offset,
  op2_offset, vec_len, vec_len);
 break;
+case 0xf8: /* psubb */
+case 0xf9: /* psubw */
+case 0xfa: /* psubl */
+case 0xfb: /* psubq */
+op1_offset += xmm_ofs;
+op2_offset += xmm_ofs;
+tcg_gen_gvec_sub(b - 0xf8, op1_offset, op1_offset,
+ op2_offset, vec_len, vec_len);
+break;
+case 0xfc: /* paddb */
+case 0xfd: /* paddw */
+case 0xfe: /* paddl */
+op1_offset += xmm_ofs;
+op2_offset += xmm_ofs;
+tcg_gen_gvec_add(b - 0xfc, op1_offset, op1_offset,
+ op2_offset, vec_len, vec_len);
+break;
+case 0xd4: /* paddq */
+op1_offset += xmm_ofs;
+op2_offset += xmm_ofs;
+tcg_gen_gvec_add(MO_64, op1_offset, op1_offset,
+ op2_offset, vec_len, vec_len);
+break;
 default:
 tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
 tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
-- 
2.34.1




[PATCH 2/6] target/i386: Use tcg gvec for gen_op_movo

2022-08-22 Thread Richard Henderson
Low hanging fruit, using gvec to move 16 bytes.

Signed-off-by: Richard Henderson 
---
 target/i386/cpu.h   | 4 ++--
 target/i386/tcg/translate.c | 7 +++
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 81e5abed86..dbc9a99a3b 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1587,8 +1587,8 @@ typedef struct CPUArchState {
 float_status mmx_status; /* for 3DNow! float ops */
 float_status sse_status;
 uint32_t mxcsr;
-ZMMReg xmm_regs[CPU_NB_REGS == 8 ? 8 : 32];
-ZMMReg xmm_t0;
+ZMMReg xmm_regs[CPU_NB_REGS == 8 ? 8 : 32] QEMU_ALIGNED(16);
+ZMMReg xmm_t0 QEMU_ALIGNED(16);
 MMXReg mmx_t0;
 
 uint64_t opmask_regs[NB_OPMASK_REGS];
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index b7972f0ff5..c1f1f6f66b 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -23,6 +23,7 @@
 #include "disas/disas.h"
 #include "exec/exec-all.h"
 #include "tcg/tcg-op.h"
+#include "tcg/tcg-op-gvec.h"
 #include "exec/cpu_ldst.h"
 #include "exec/translator.h"
 
@@ -2753,10 +2754,8 @@ static inline void gen_sto_env_A0(DisasContext *s, int 
offset)
 
 static inline void gen_op_movo(DisasContext *s, int d_offset, int s_offset)
 {
-tcg_gen_ld_i64(s->tmp1_i64, cpu_env, s_offset + offsetof(ZMMReg, 
ZMM_Q(0)));
-tcg_gen_st_i64(s->tmp1_i64, cpu_env, d_offset + offsetof(ZMMReg, 
ZMM_Q(0)));
-tcg_gen_ld_i64(s->tmp1_i64, cpu_env, s_offset + offsetof(ZMMReg, 
ZMM_Q(1)));
-tcg_gen_st_i64(s->tmp1_i64, cpu_env, d_offset + offsetof(ZMMReg, 
ZMM_Q(1)));
+int xmm_ofs = offsetof(ZMMReg, ZMM_X(0));
+tcg_gen_gvec_mov(MO_64, d_offset + xmm_ofs, s_offset + xmm_ofs, 16, 16);
 }
 
 static inline void gen_op_movq(DisasContext *s, int d_offset, int s_offset)
-- 
2.34.1




  1   2   3   >