Re: [PATCH v2 for-5.2] tests/9pfs: Mark "local" tests as "slow"

2020-11-23 Thread Thomas Huth
On 24/11/2020 08.43, Greg Kurz wrote:
> The "local" tests can fail on some automated build systems as
> reported here:
> 
> https://lists.nongnu.org/archive/html/qemu-devel/2020-11/msg05510.html
> 
> This will need to be investigated and addressed later. Let's go for a
> workaround in the meantime : mark the "local" tests as "slow" so that
> they aren't executed with a simple "make check" like in the case above.
> 
> Reported-by: Cole Robinson 
> Signed-off-by: Greg Kurz 
> ---
> v2: - less noisy patch
> ---
>  tests/qtest/virtio-9p-test.c |9 +
>  1 file changed, 9 insertions(+)
> 
> diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
> index 21e340fa5f43..92a498f24925 100644
> --- a/tests/qtest/virtio-9p-test.c
> +++ b/tests/qtest/virtio-9p-test.c
> @@ -1456,6 +1456,15 @@ static void register_virtio_9p_test(void)
>  
>  
>  /* 9pfs test cases using the 'local' filesystem driver */
> +
> +/*
> + * XXX: Until we are sure that these tests can run everywhere,
> + * keep them as "slow" so that they aren't run with "make check".
> + */
> +if (!g_test_slow()) {
> +return;
> +}
> +
>  opts.before = assign_9p_local_driver;
>  qos_add_test("local/config", "virtio-9p", pci_config,  );
>  qos_add_test("local/create_dir", "virtio-9p", fs_create_dir, );

Reviewed-by: Thomas Huth 

I assume you'll take this via the 9p tree? I don't have any other qtest
patches pending right now, so I did not plan to send another pull request
today...




[PATCH v2 for-5.2] tests/9pfs: Mark "local" tests as "slow"

2020-11-23 Thread Greg Kurz
The "local" tests can fail on some automated build systems as
reported here:

https://lists.nongnu.org/archive/html/qemu-devel/2020-11/msg05510.html

This will need to be investigated and addressed later. Let's go for a
workaround in the meantime : mark the "local" tests as "slow" so that
they aren't executed with a simple "make check" like in the case above.

Reported-by: Cole Robinson 
Signed-off-by: Greg Kurz 
---
v2: - less noisy patch
---
 tests/qtest/virtio-9p-test.c |9 +
 1 file changed, 9 insertions(+)

diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
index 21e340fa5f43..92a498f24925 100644
--- a/tests/qtest/virtio-9p-test.c
+++ b/tests/qtest/virtio-9p-test.c
@@ -1456,6 +1456,15 @@ static void register_virtio_9p_test(void)
 
 
 /* 9pfs test cases using the 'local' filesystem driver */
+
+/*
+ * XXX: Until we are sure that these tests can run everywhere,
+ * keep them as "slow" so that they aren't run with "make check".
+ */
+if (!g_test_slow()) {
+return;
+}
+
 opts.before = assign_9p_local_driver;
 qos_add_test("local/config", "virtio-9p", pci_config,  );
 qos_add_test("local/create_dir", "virtio-9p", fs_create_dir, );





[PATCH] hw/block/nvme: add compare command

2020-11-23 Thread Klaus Jensen
From: Gollu Appalanaidu 

Add the Compare command.

This implementation uses a bounce buffer to read in the data from
storage and then compare with the host supplied buffer.

Signed-off-by: Gollu Appalanaidu 
[k.jensen: rebased]
Signed-off-by: Klaus Jensen 
---
 hw/block/nvme.c   | 100 +-
 hw/block/trace-events |   2 +
 2 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index f7f888402b06..f88710ca3948 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -999,6 +999,50 @@ static void nvme_aio_discard_cb(void *opaque, int ret)
 nvme_enqueue_req_completion(nvme_cq(req), req);
 }
 
+struct nvme_compare_ctx {
+QEMUIOVector iov;
+uint8_t *bounce;
+size_t len;
+};
+
+static void nvme_compare_cb(void *opaque, int ret)
+{
+NvmeRequest *req = opaque;
+NvmeNamespace *ns = req->ns;
+struct nvme_compare_ctx *ctx = req->opaque;
+g_autofree uint8_t *buf = NULL;
+uint16_t status;
+
+trace_pci_nvme_compare_cb(nvme_cid(req));
+
+if (!ret) {
+block_acct_done(blk_get_stats(ns->blkconf.blk), >acct);
+} else {
+block_acct_failed(blk_get_stats(ns->blkconf.blk), >acct);
+nvme_aio_err(req, ret);
+goto out;
+}
+
+buf = g_malloc(ctx->len);
+
+status = nvme_dma(nvme_ctrl(req), buf, ctx->len, DMA_DIRECTION_TO_DEVICE,
+  req);
+if (status) {
+goto out;
+}
+
+if (memcmp(buf, ctx->bounce, ctx->len)) {
+req->status = NVME_CMP_FAILURE;
+}
+
+out:
+qemu_iovec_destroy(>iov);
+g_free(ctx->bounce);
+g_free(ctx);
+
+nvme_enqueue_req_completion(nvme_cq(req), req);
+}
+
 static uint16_t nvme_dsm(NvmeCtrl *n, NvmeRequest *req)
 {
 NvmeNamespace *ns = req->ns;
@@ -1072,6 +1116,57 @@ static uint16_t nvme_dsm(NvmeCtrl *n, NvmeRequest *req)
 return status;
 }
 
+static uint16_t nvme_compare(NvmeCtrl *n, NvmeRequest *req)
+{
+NvmeRwCmd *rw = (NvmeRwCmd *)>cmd;
+NvmeNamespace *ns = req->ns;
+BlockBackend *blk = ns->blkconf.blk;
+uint64_t slba = le64_to_cpu(rw->slba);
+uint32_t nlb = le16_to_cpu(rw->nlb) + 1;
+size_t len = nvme_l2b(ns, nlb);
+int64_t offset = nvme_l2b(ns, slba);
+uint8_t *bounce = NULL;
+struct nvme_compare_ctx *ctx = NULL;
+uint16_t status;
+
+trace_pci_nvme_compare(nvme_cid(req), nvme_nsid(ns), slba, nlb);
+
+status = nvme_check_mdts(n, len);
+if (status) {
+trace_pci_nvme_err_mdts(nvme_cid(req), len);
+return status;
+}
+
+status = nvme_check_bounds(ns, slba, nlb);
+if (status) {
+trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
+return status;
+}
+
+if (NVME_ERR_REC_DULBE(ns->features.err_rec)) {
+status = nvme_check_dulbe(ns, slba, nlb);
+if (status) {
+return status;
+}
+}
+
+bounce = g_malloc(len);
+
+ctx = g_new(struct nvme_compare_ctx, 1);
+ctx->bounce = bounce;
+ctx->len = len;
+
+req->opaque = ctx;
+
+qemu_iovec_init(>iov, 1);
+qemu_iovec_add(>iov, bounce, len);
+
+block_acct_start(blk_get_stats(blk), >acct, len, BLOCK_ACCT_READ);
+blk_aio_preadv(blk, offset, >iov, 0, nvme_compare_cb, req);
+
+return NVME_NO_COMPLETE;
+}
+
 static uint16_t nvme_flush(NvmeCtrl *n, NvmeRequest *req)
 {
 block_acct_start(blk_get_stats(req->ns->blkconf.blk), >acct, 0,
@@ -1201,6 +1296,8 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
 case NVME_CMD_WRITE:
 case NVME_CMD_READ:
 return nvme_rw(n, req);
+case NVME_CMD_COMPARE:
+return nvme_compare(n, req);
 case NVME_CMD_DSM:
 return nvme_dsm(n, req);
 default:
@@ -2927,7 +3024,8 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice 
*pci_dev)
 id->cqes = (0x4 << 4) | 0x4;
 id->nn = cpu_to_le32(n->num_namespaces);
 id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROES | NVME_ONCS_TIMESTAMP |
-   NVME_ONCS_FEATURES | NVME_ONCS_DSM);
+   NVME_ONCS_FEATURES | NVME_ONCS_DSM |
+   NVME_ONCS_COMPARE);
 
 id->vwc = 0x1;
 id->sgls = cpu_to_le32(NVME_CTRL_SGLS_SUPPORT_NO_ALIGN |
diff --git a/hw/block/trace-events b/hw/block/trace-events
index 1ffe0b3f76b5..68a4c8ed35e0 100644
--- a/hw/block/trace-events
+++ b/hw/block/trace-events
@@ -46,6 +46,8 @@ pci_nvme_write_zeroes(uint16_t cid, uint32_t nsid, uint64_t 
slba, uint32_t nlb)
 pci_nvme_block_status(int64_t offset, int64_t bytes, int64_t pnum, int ret, 
bool zeroed) "offset %"PRId64" bytes %"PRId64" pnum %"PRId64" ret 0x%x zeroed 
%d"
 pci_nvme_dsm(uint16_t cid, uint32_t nsid, uint32_t nr, uint32_t attr) "cid 
%"PRIu16" nsid %"PRIu32" nr %"PRIu32" attr 0x%"PRIx32""
 pci_nvme_dsm_deallocate(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t 
nlb) "cid %"PRIu16" nsid %"PRIu32" slba %"PRIu64" nlb %"PRIu32""
+pci_nvme_compare(uint16_t cid, uint32_t nsid, uint64_t 

Re: [PATCH for-5.2] tests/9pfs: Mark "local" tests as "slow"

2020-11-23 Thread Greg Kurz
On Mon, 23 Nov 2020 19:08:18 +0100
Christian Schoenebeck  wrote:

> On Montag, 23. November 2020 18:41:51 CET Greg Kurz wrote:
> > The "local" tests can fail on some automated build systems as
> > reported here:
> > 
> > https://lists.nongnu.org/archive/html/qemu-devel/2020-11/msg05510.html
> > 
> > This will need to be investigated and addressed later. Let's go for a
> > workaround in the meantime : mark the "local" tests as "slow" so that
> > they aren't executed with a simple "make check" like in the case above.
> > 
> > Reported-by: Cole Robinson 
> > Signed-off-by: Greg Kurz 
> > ---
> > 
> > Unless there's a strong argument against merging this, I'll post
> > a PR with this fix for RC3.
> > ---
> >  tests/qtest/virtio-9p-test.c |   35 +--
> >  1 file changed, 21 insertions(+), 14 deletions(-)
> > 
> > diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
> > index 21e340fa5f43..dad37ace9772 100644
> > --- a/tests/qtest/virtio-9p-test.c
> > +++ b/tests/qtest/virtio-9p-test.c
> > @@ -1454,20 +1454,27 @@ static void register_virtio_9p_test(void)
> >  qos_add_test("synth/readdir/split_128", "virtio-9p",
> >   fs_readdir_split_128,  );
> > 
> > -
> > -/* 9pfs test cases using the 'local' filesystem driver */
> > -opts.before = assign_9p_local_driver;
> > -qos_add_test("local/config", "virtio-9p", pci_config,  );
> > -qos_add_test("local/create_dir", "virtio-9p", fs_create_dir, );
> > -qos_add_test("local/unlinkat_dir", "virtio-9p", fs_unlinkat_dir,
> > ); -qos_add_test("local/create_file", "virtio-9p", fs_create_file,
> > ); -qos_add_test("local/unlinkat_file", "virtio-9p",
> > fs_unlinkat_file, ); -qos_add_test("local/symlink_file",
> > "virtio-9p", fs_symlink_file, ); -   
> > qos_add_test("local/unlinkat_symlink", "virtio-9p", fs_unlinkat_symlink, - 
> >);
> > -qos_add_test("local/hardlink_file", "virtio-9p", fs_hardlink_file,
> > ); -qos_add_test("local/unlinkat_hardlink", "virtio-9p",
> > fs_unlinkat_hardlink, - );
> > +if (g_test_slow()) {
> 
> If you don't mind, I would suggest simply using
> 
> if (!g_test_slow()) {
>   return;
> }
> 
> here to keep the diff noise low.
> 

Sure, I'll do that.

> > +/* 9pfs test cases using the 'local' filesystem driver */
> > +/*
> > + * XXX: Until we are sure that these tests can run everywhere,
> > + * keep them as "slow" so that they aren't run with "make check"
> > + */
> > +opts.before = assign_9p_local_driver;
> > +qos_add_test("local/config", "virtio-9p", pci_config,  );
> > +qos_add_test("local/create_dir", "virtio-9p", fs_create_dir,
> > ); +qos_add_test("local/unlinkat_dir", "virtio-9p",
> > fs_unlinkat_dir, ); +qos_add_test("local/create_file",
> > "virtio-9p", fs_create_file, ); +   
> > qos_add_test("local/unlinkat_file", "virtio-9p", fs_unlinkat_file, +   
> >  );
> > +qos_add_test("local/symlink_file", "virtio-9p", fs_symlink_file,
> > ); +qos_add_test("local/unlinkat_symlink", "virtio-9p",
> > fs_unlinkat_symlink, + );
> > +qos_add_test("local/hardlink_file", "virtio-9p", fs_hardlink_file,
> > + );
> > +qos_add_test("local/unlinkat_hardlink", "virtio-9p",
> > + fs_unlinkat_hardlink, );
> > +}
> >  }
> > 
> >  libqos_init(register_virtio_9p_test);
> 
> I agree that this is okay for now to avoid inconveniences with nearby 5.2 
> release, but do we agree that this is going to be reverted when 6.0 
> development phase starts?
> 
> In 6.0 I would rather handle this by introducing a previously mentioned 
> 'loglevel' option for 9p, and asking for the required log data if the local 
> tests fail for somebody. I can take care about the loglevel option when 6.0 
> phase starts.
> 
> Best regards,
> Christian Schoenebeck
> 
> 




Re: [PATCH for-5.2] tests/9pfs: Mark "local" tests as "slow"

2020-11-23 Thread Greg Kurz
On Mon, 23 Nov 2020 20:35:58 +0100
Christian Schoenebeck  wrote:

> On Montag, 23. November 2020 19:08:18 CET Christian Schoenebeck wrote:
> > On Montag, 23. November 2020 18:41:51 CET Greg Kurz wrote:
> > > The "local" tests can fail on some automated build systems as
> > > reported here:
> > > 
> > > https://lists.nongnu.org/archive/html/qemu-devel/2020-11/msg05510.html
> > > 
> > > This will need to be investigated and addressed later. Let's go for a
> > > workaround in the meantime : mark the "local" tests as "slow" so that
> > > they aren't executed with a simple "make check" like in the case above.
> > > 
> > > Reported-by: Cole Robinson 
> > > Signed-off-by: Greg Kurz 
> > > ---
> > > 
> > > Unless there's a strong argument against merging this, I'll post
> > > a PR with this fix for RC3.
> > > ---
> > > 
> > >  tests/qtest/virtio-9p-test.c |   35 +--
> > >  1 file changed, 21 insertions(+), 14 deletions(-)
> > > 
> > > diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c
> > > index 21e340fa5f43..dad37ace9772 100644
> > > --- a/tests/qtest/virtio-9p-test.c
> > > +++ b/tests/qtest/virtio-9p-test.c
> > > @@ -1454,20 +1454,27 @@ static void register_virtio_9p_test(void)
> > > 
> > >  qos_add_test("synth/readdir/split_128", "virtio-9p",
> > >  
> > >   fs_readdir_split_128,  );
> > > 
> > > -
> > > -/* 9pfs test cases using the 'local' filesystem driver */
> > > -opts.before = assign_9p_local_driver;
> > > -qos_add_test("local/config", "virtio-9p", pci_config,  );
> > > -qos_add_test("local/create_dir", "virtio-9p", fs_create_dir, );
> > > -qos_add_test("local/unlinkat_dir", "virtio-9p", fs_unlinkat_dir,
> > > ); -qos_add_test("local/create_file", "virtio-9p",
> > > fs_create_file,
> > > ); -qos_add_test("local/unlinkat_file", "virtio-9p",
> > > fs_unlinkat_file, ); -qos_add_test("local/symlink_file",
> > > "virtio-9p", fs_symlink_file, ); -
> > > qos_add_test("local/unlinkat_symlink", "virtio-9p", fs_unlinkat_symlink, -
> > > 
> > >);
> > > 
> > > -qos_add_test("local/hardlink_file", "virtio-9p", fs_hardlink_file,
> > > ); -qos_add_test("local/unlinkat_hardlink", "virtio-9p",
> > > fs_unlinkat_hardlink, - );
> > > +if (g_test_slow()) {
> > 
> > If you don't mind, I would suggest simply using
> > 
> > if (!g_test_slow()) {
> > return;
> > }
> > 
> > here to keep the diff noise low.
> > 
> > > +/* 9pfs test cases using the 'local' filesystem driver */
> > > +/*
> > > + * XXX: Until we are sure that these tests can run everywhere,
> > > + * keep them as "slow" so that they aren't run with "make check"
> > > + */
> > > +opts.before = assign_9p_local_driver;
> > > +qos_add_test("local/config", "virtio-9p", pci_config,  );
> > > +qos_add_test("local/create_dir", "virtio-9p", fs_create_dir,
> > > ); +qos_add_test("local/unlinkat_dir", "virtio-9p",
> > > fs_unlinkat_dir, ); +qos_add_test("local/create_file",
> > > "virtio-9p", fs_create_file, ); +
> > > qos_add_test("local/unlinkat_file", "virtio-9p", fs_unlinkat_file, +
> > > 
> > >  );
> > > 
> > > +qos_add_test("local/symlink_file", "virtio-9p", fs_symlink_file,
> > > ); +qos_add_test("local/unlinkat_symlink", "virtio-9p",
> > > fs_unlinkat_symlink, + );
> > > +qos_add_test("local/hardlink_file", "virtio-9p",
> > > fs_hardlink_file,
> > > + );
> > > +qos_add_test("local/unlinkat_hardlink", "virtio-9p",
> > > + fs_unlinkat_hardlink, );
> > > +}
> > > 
> > >  }
> > >  
> > >  libqos_init(register_virtio_9p_test);
> > 
> > I agree that this is okay for now to avoid inconveniences with nearby 5.2
> > release, but do we agree that this is going to be reverted when 6.0
> > development phase starts?
> > 
> > In 6.0 I would rather handle this by introducing a previously mentioned
> > 'loglevel' option for 9p, and asking for the required log data if the local
> > tests fail for somebody. I can take care about the loglevel option when 6.0
> > phase starts.
> > 
> > Best regards,
> > Christian Schoenebeck
> 
> BTW, if I had to shoot in the dark, then my guess would be that system where 
> mkdir() failed with ENOTSUPP, does not support xattrs.
> 
> If that's the root cause, then another option would be skipping the 'local' 
> 9p 
> tests if the host system lacks xattr support, instead of disabling these 
> tests 
> for all people by default.
> 

Maybe but it's a bit too late now. RC3 is later today. I really must
post something that fixes the "make check" breakage this morning.

> Best regards,
> Christian Schoenebeck
> 
> 




[PATCH 2/2] hw/block/nvme: add simple copy command

2020-11-23 Thread Klaus Jensen
From: Klaus Jensen 

Add support for TP 4065a ("Simple Copy Command"), v2020.05.04
("Ratified").

The implementation uses a bounce buffer to first read in the source
logical blocks, then issue a write of that bounce buffer. The default
maximum number of source logical blocks is 128, translating to 512 KiB
for 4k logical blocks which aligns with the default value of MDTS.

Signed-off-by: Klaus Jensen 
---
 hw/block/nvme-ns.h|   4 +
 hw/block/nvme.h   |   1 +
 hw/block/nvme-ns.c|   8 ++
 hw/block/nvme.c   | 225 +-
 hw/block/trace-events |   6 ++
 5 files changed, 243 insertions(+), 1 deletion(-)

diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h
index 44bf6271b744..745d288b09cf 100644
--- a/hw/block/nvme-ns.h
+++ b/hw/block/nvme-ns.h
@@ -21,6 +21,10 @@
 
 typedef struct NvmeNamespaceParams {
 uint32_t nsid;
+
+uint16_t mssrl;
+uint32_t mcl;
+uint8_t  msrc;
 } NvmeNamespaceParams;
 
 typedef struct NvmeNamespace {
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index 574333caa3f9..f549abeeb930 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -62,6 +62,7 @@ static inline const char *nvme_io_opc_str(uint8_t opc)
 case NVME_CMD_READ: return "NVME_NVM_CMD_READ";
 case NVME_CMD_WRITE_ZEROES: return "NVME_NVM_CMD_WRITE_ZEROES";
 case NVME_CMD_DSM:  return "NVME_NVM_CMD_DSM";
+case NVME_CMD_COPY: return "NVME_NVM_CMD_COPY";
 default:return "NVME_NVM_CMD_UNKNOWN";
 }
 }
diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c
index 2d69b5177b51..eb28757c2f17 100644
--- a/hw/block/nvme-ns.c
+++ b/hw/block/nvme-ns.c
@@ -59,6 +59,11 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp)
 
 id_ns->npda = id_ns->npdg = npdg - 1;
 
+/* simple copy */
+id_ns->mssrl = cpu_to_le16(ns->params.mssrl);
+id_ns->mcl = cpu_to_le32(ns->params.mcl);
+id_ns->msrc = ns->params.msrc;
+
 return 0;
 }
 
@@ -150,6 +155,9 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp)
 static Property nvme_ns_props[] = {
 DEFINE_BLOCK_PROPERTIES(NvmeNamespace, blkconf),
 DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0),
+DEFINE_PROP_UINT16("mssrl", NvmeNamespace, params.mssrl, 128),
+DEFINE_PROP_UINT32("mcl", NvmeNamespace, params.mcl, 128),
+DEFINE_PROP_UINT8("msrc", NvmeNamespace, params.msrc, 255),
 DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index f7f888402b06..82233f80541e 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -999,6 +999,109 @@ static void nvme_aio_discard_cb(void *opaque, int ret)
 nvme_enqueue_req_completion(nvme_cq(req), req);
 }
 
+struct nvme_copy_ctx {
+int copies;
+uint8_t *bounce;
+uint32_t nlb;
+};
+
+struct nvme_copy_in_ctx {
+NvmeRequest *req;
+QEMUIOVector iov;
+};
+
+static void nvme_copy_cb(void *opaque, int ret)
+{
+NvmeRequest *req = opaque;
+NvmeNamespace *ns = req->ns;
+struct nvme_copy_ctx *ctx = req->opaque;
+
+trace_pci_nvme_copy_cb(nvme_cid(req));
+
+if (!ret) {
+block_acct_done(blk_get_stats(ns->blkconf.blk), >acct);
+} else {
+block_acct_failed(blk_get_stats(ns->blkconf.blk), >acct);
+nvme_aio_err(req, ret);
+}
+
+g_free(ctx->bounce);
+g_free(ctx);
+
+nvme_enqueue_req_completion(nvme_cq(req), req);
+}
+
+static void nvme_copy_in_complete(NvmeRequest *req)
+{
+NvmeNamespace *ns = req->ns;
+NvmeCopyCmd *copy = (NvmeCopyCmd *)>cmd;
+struct nvme_copy_ctx *ctx = req->opaque;
+uint64_t sdlba = le64_to_cpu(copy->sdlba);
+uint16_t status;
+
+trace_pci_nvme_copy_in_complete(nvme_cid(req));
+
+block_acct_done(blk_get_stats(ns->blkconf.blk), >acct);
+
+status = nvme_check_bounds(ns, sdlba, ctx->nlb);
+if (status) {
+trace_pci_nvme_err_invalid_lba_range(sdlba, ctx->nlb, ns->id_ns.nsze);
+req->status = status;
+
+g_free(ctx->bounce);
+g_free(ctx);
+
+nvme_enqueue_req_completion(nvme_cq(req), req);
+
+return;
+}
+
+qemu_iovec_init(>iov, 1);
+qemu_iovec_add(>iov, ctx->bounce, nvme_l2b(ns, ctx->nlb));
+
+block_acct_start(blk_get_stats(ns->blkconf.blk), >acct,
+ nvme_l2b(ns, ctx->nlb), BLOCK_ACCT_WRITE);
+
+req->aiocb = blk_aio_pwritev(ns->blkconf.blk, nvme_l2b(ns, sdlba),
+ >iov, 0, nvme_copy_cb, req);
+}
+
+static void nvme_aio_copy_in_cb(void *opaque, int ret)
+{
+struct nvme_copy_in_ctx *in_ctx = opaque;
+NvmeRequest *req = in_ctx->req;
+NvmeNamespace *ns = req->ns;
+struct nvme_copy_ctx *ctx = req->opaque;
+
+qemu_iovec_destroy(_ctx->iov);
+g_free(in_ctx);
+
+trace_pci_nvme_aio_copy_in_cb(nvme_cid(req));
+
+if (ret) {
+nvme_aio_err(req, ret);
+}
+
+ctx->copies--;
+
+if (ctx->copies) {
+return;
+}
+
+if (req->status) {
+

[PATCH 0/2] hw/block/nvme: add simple copy command

2020-11-23 Thread Klaus Jensen
From: Klaus Jensen 

Add support for TP 4065 ("Simple Copy Command").

Klaus Jensen (2):
  nvme: updated shared header for copy command
  hw/block/nvme: add simple copy command

 hw/block/nvme-ns.h|   4 +
 hw/block/nvme.h   |   1 +
 include/block/nvme.h  |  45 -
 hw/block/nvme-ns.c|   8 ++
 hw/block/nvme.c   | 225 +-
 hw/block/trace-events |   6 ++
 6 files changed, 286 insertions(+), 3 deletions(-)

-- 
2.29.2




[PATCH 1/2] nvme: updated shared header for copy command

2020-11-23 Thread Klaus Jensen
From: Klaus Jensen 

Add new data structures and types for the Simple Copy command.

Signed-off-by: Klaus Jensen 
Cc: Stefan Hajnoczi 
Cc: Fam Zheng 
---
 include/block/nvme.h | 45 ++--
 1 file changed, 43 insertions(+), 2 deletions(-)

diff --git a/include/block/nvme.h b/include/block/nvme.h
index e95ff6ca9b37..b56efd6a89af 100644
--- a/include/block/nvme.h
+++ b/include/block/nvme.h
@@ -472,6 +472,7 @@ enum NvmeIoCommands {
 NVME_CMD_COMPARE= 0x05,
 NVME_CMD_WRITE_ZEROES   = 0x08,
 NVME_CMD_DSM= 0x09,
+NVME_CMD_COPY   = 0x19,
 };
 
 typedef struct QEMU_PACKED NvmeDeleteQ {
@@ -603,6 +604,35 @@ typedef struct QEMU_PACKED NvmeDsmRange {
 uint64_tslba;
 } NvmeDsmRange;
 
+enum {
+NVME_COPY_FORMAT_0 = 0x0,
+};
+
+typedef struct NvmeCopyCmd {
+uint8_t opcode;
+uint8_t flags;
+uint16_tcid;
+uint32_tnsid;
+uint32_trsvd2[4];
+NvmeCmdDptr dptr;
+uint64_tsdlba;
+uint32_tcdw12;
+uint32_tcdw13;
+uint32_tilbrt;
+uint16_tlbat;
+uint16_tlbatm;
+} NvmeCopyCmd;
+
+typedef struct NvmeCopySourceRange {
+uint8_t  rsvd0[8];
+uint64_t slba;
+uint16_t nlb;
+uint8_t  rsvd18[6];
+uint32_t eilbrt;
+uint16_t elbatm;
+uint16_t elbat;
+} NvmeCopySourceRange;
+
 enum NvmeAsyncEventRequest {
 NVME_AER_TYPE_ERROR = 0,
 NVME_AER_TYPE_SMART = 1,
@@ -680,6 +710,7 @@ enum NvmeStatusCodes {
 NVME_CONFLICTING_ATTRS  = 0x0180,
 NVME_INVALID_PROT_INFO  = 0x0181,
 NVME_WRITE_TO_RO= 0x0182,
+NVME_CMD_SIZE_LIMIT = 0x0183,
 NVME_WRITE_FAULT= 0x0280,
 NVME_UNRECOVERED_READ   = 0x0281,
 NVME_E2E_GUARD_ERROR= 0x0282,
@@ -831,7 +862,7 @@ typedef struct QEMU_PACKED NvmeIdCtrl {
 uint8_t nvscc;
 uint8_t rsvd531;
 uint16_tacwu;
-uint8_t rsvd534[2];
+uint16_tocfs;
 uint32_tsgls;
 uint8_t rsvd540[228];
 uint8_t subnqn[256];
@@ -854,6 +885,11 @@ enum NvmeIdCtrlOncs {
 NVME_ONCS_FEATURES  = 1 << 4,
 NVME_ONCS_RESRVATIONS   = 1 << 5,
 NVME_ONCS_TIMESTAMP = 1 << 6,
+NVME_ONCS_COPY  = 1 << 8,
+};
+
+enum NvmeIdCtrlOcfs {
+NVME_OCFS_COPY_FORMAT_0 = 1 << NVME_COPY_FORMAT_0,
 };
 
 enum NvmeIdCtrlFrmw {
@@ -995,7 +1031,10 @@ typedef struct QEMU_PACKED NvmeIdNs {
 uint16_tnpdg;
 uint16_tnpda;
 uint16_tnows;
-uint8_t rsvd74[30];
+uint16_tmssrl;
+uint32_tmcl;
+uint8_t msrc;
+uint8_t rsvd81[23];
 uint8_t nguid[16];
 uint64_teui64;
 NvmeLBAFlbaf[16];
@@ -1059,6 +1098,7 @@ static inline void _nvme_check_size(void)
 QEMU_BUILD_BUG_ON(sizeof(NvmeAerResult) != 4);
 QEMU_BUILD_BUG_ON(sizeof(NvmeCqe) != 16);
 QEMU_BUILD_BUG_ON(sizeof(NvmeDsmRange) != 16);
+QEMU_BUILD_BUG_ON(sizeof(NvmeCopySourceRange) != 32);
 QEMU_BUILD_BUG_ON(sizeof(NvmeCmd) != 64);
 QEMU_BUILD_BUG_ON(sizeof(NvmeDeleteQ) != 64);
 QEMU_BUILD_BUG_ON(sizeof(NvmeCreateCq) != 64);
@@ -1066,6 +1106,7 @@ static inline void _nvme_check_size(void)
 QEMU_BUILD_BUG_ON(sizeof(NvmeIdentify) != 64);
 QEMU_BUILD_BUG_ON(sizeof(NvmeRwCmd) != 64);
 QEMU_BUILD_BUG_ON(sizeof(NvmeDsmCmd) != 64);
+QEMU_BUILD_BUG_ON(sizeof(NvmeCopyCmd) != 64);
 QEMU_BUILD_BUG_ON(sizeof(NvmeRangeType) != 64);
 QEMU_BUILD_BUG_ON(sizeof(NvmeErrorLog) != 64);
 QEMU_BUILD_BUG_ON(sizeof(NvmeFwSlotInfoLog) != 512);
-- 
2.29.2




Re: [PATCH v2] target/i386: seg_helper: Correct segement selector nullification in the RET/IRET helper

2020-11-23 Thread Bin Meng
Hi Paolo,

On Tue, Nov 17, 2020 at 7:06 PM Paolo Bonzini  wrote:
>
> On 17/11/20 11:08, Bin Meng wrote:
> >> I see.  Is there any chance you could write a testcase for
> >> kvm-unit-tests?  Or just explain how to write such a test, and then I
> >> can write it myself; it's not clear to me how the guest can observe the
> >> base and limit of a non-present segment.
> >
> > I am not familiar with kvm-unit-test. The original issue cannot be
> > reproduced with a KVM enabled QEMU as the codes-in-flaw is in the
> > emulation path.
>
> kvm-unit-tests, despite the name, is a set generic tests for CPU
> behavior; it works with other accelerators that QEMU supports including
> the emulation path.  You can find it at
> https://gitlab.com/kvm-unit-tests/kvm-unit-tests.

I see. Thanks for the info.

> If you explain in enough detail how VxWorks triggers the bug, I can take
> care of writing the test.

I will try to create a test case using the kvm-unit-tests framework.

Regards,
Bin



[PULL 1/1] ppc/translate: Implement lxvwsx opcode

2020-11-23 Thread David Gibson
From: LemonBoy 

Implement the "Load VSX Vector Word & Splat Indexed" opcode, introduced
in Power ISA v3.0.

Buglink: https://bugs.launchpad.net/qemu/+bug/1793608
Signed-off-by: Giuseppe Musacchio 
Message-Id: 

Reviewed-by: Richard Henderson 
Signed-off-by: David Gibson 
---
 target/ppc/translate/vsx-impl.c.inc | 30 +
 target/ppc/translate/vsx-ops.c.inc  |  1 +
 2 files changed, 31 insertions(+)

diff --git a/target/ppc/translate/vsx-impl.c.inc 
b/target/ppc/translate/vsx-impl.c.inc
index b518de46db..075f063e98 100644
--- a/target/ppc/translate/vsx-impl.c.inc
+++ b/target/ppc/translate/vsx-impl.c.inc
@@ -139,6 +139,36 @@ static void gen_lxvw4x(DisasContext *ctx)
 tcg_temp_free_i64(xtl);
 }
 
+static void gen_lxvwsx(DisasContext *ctx)
+{
+TCGv EA;
+TCGv_i32 data;
+
+if (xT(ctx->opcode) < 32) {
+if (unlikely(!ctx->vsx_enabled)) {
+gen_exception(ctx, POWERPC_EXCP_VSXU);
+return;
+}
+} else {
+if (unlikely(!ctx->altivec_enabled)) {
+gen_exception(ctx, POWERPC_EXCP_VPU);
+return;
+}
+}
+
+gen_set_access_type(ctx, ACCESS_INT);
+EA = tcg_temp_new();
+
+gen_addr_reg_index(ctx, EA);
+
+data = tcg_temp_new_i32();
+tcg_gen_qemu_ld_i32(data, EA, ctx->mem_idx, MO_TEUL);
+tcg_gen_gvec_dup_i32(MO_UL, vsr_full_offset(xT(ctx->opcode)), 16, 16, 
data);
+
+tcg_temp_free(EA);
+tcg_temp_free_i32(data);
+}
+
 static void gen_bswap16x8(TCGv_i64 outh, TCGv_i64 outl,
   TCGv_i64 inh, TCGv_i64 inl)
 {
diff --git a/target/ppc/translate/vsx-ops.c.inc 
b/target/ppc/translate/vsx-ops.c.inc
index 7fd3942b84..1d41beef26 100644
--- a/target/ppc/translate/vsx-ops.c.inc
+++ b/target/ppc/translate/vsx-ops.c.inc
@@ -5,6 +5,7 @@ GEN_HANDLER_E(lxsibzx, 0x1F, 0x0D, 0x18, 0, PPC_NONE, 
PPC2_ISA300),
 GEN_HANDLER_E(lxsihzx, 0x1F, 0x0D, 0x19, 0, PPC_NONE, PPC2_ISA300),
 GEN_HANDLER_E(lxsspx, 0x1F, 0x0C, 0x10, 0, PPC_NONE, PPC2_VSX207),
 GEN_HANDLER_E(lxvd2x, 0x1F, 0x0C, 0x1A, 0, PPC_NONE, PPC2_VSX),
+GEN_HANDLER_E(lxvwsx, 0x1F, 0x0C, 0x0B, 0, PPC_NONE, PPC2_ISA300),
 GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX),
 GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX),
 GEN_HANDLER_E(lxvh8x, 0x1F, 0x0C, 0x19, 0, PPC_NONE,  PPC2_ISA300),
-- 
2.28.0




[PULL 0/1] ppc-for-5.2 queue 20201124

2020-11-23 Thread David Gibson
The following changes since commit 23895cbd82be95428e90168b12e925d0d3ca2f06:

  Merge remote-tracking branch 'remotes/awilliam/tags/vfio-update-20201123.0' 
into staging (2020-11-23 18:51:13 +)

are available in the Git repository at:

  https://gitlab.com/dgibson/qemu.git tags/ppc-for-5.2-20201124

for you to fetch changes up to afae37d98ae991c0792c867dbd9f32f988044318:

  ppc/translate: Implement lxvwsx opcode (2020-11-24 11:34:18 +1100)


ppc patch queue for 2020-11-24

One final update for qemu-5.2, implementing an instruction that we
already should have, given the ISA version we claim to support.  Sorry
for the lateness, I've been on holiday.

This isn't a regression, obviously, so if it misses qemu-5.2 it's not
a disaster, but it would be nice to have.  The risk is low that it
would break any existing instructions.


LemonBoy (1):
  ppc/translate: Implement lxvwsx opcode

 target/ppc/translate/vsx-impl.c.inc | 30 ++
 target/ppc/translate/vsx-ops.c.inc  |  1 +
 2 files changed, 31 insertions(+)



Re: [PATCH 05/11] exec: add debug version of physical memory read and write API

2020-11-23 Thread Dov Murik




On 16/11/2020 20:51, Ashish Kalra wrote:

From: Brijesh Singh 

Adds the following new APIs
- cpu_physical_memory_read_debug
- cpu_physical_memory_write_debug
- cpu_physical_memory_rw_debug
- ldl_phys_debug
- ldq_phys_debug

The subsequent patch will make use of the API introduced, to ensure
that the page table walks are handled correctly when debugging an
SEV guest.

Signed-off-by: Brijesh Singh 
Signed-off-by: Ashish Kalra 
---


[...]



diff --git a/softmmu/physmem.c b/softmmu/physmem.c
index 2c08624ca8..6945bd5efe 100644
--- a/softmmu/physmem.c
+++ b/softmmu/physmem.c
@@ -3354,6 +3354,53 @@ inline MemTxResult 
address_space_write_rom_debug(AddressSpace *as,
  return MEMTX_OK;
  }

+uint32_t ldl_phys_debug(CPUState *cpu, hwaddr addr)
+{
+MemTxAttrs attrs;
+int asidx = cpu_asidx_from_attrs(cpu, attrs);
+uint32_t val;
+
+/* set debug attrs to indicate memory access is from the debugger */
+attrs.debug = 1;
+
+debug_ops->read(cpu->cpu_ases[asidx].as, addr, attrs,
+(void *) , 4);
+
+return tswap32(val);
+}
+
+uint64_t ldq_phys_debug(CPUState *cpu, hwaddr addr)
+{
+MemTxAttrs attrs;
+int asidx = cpu_asidx_from_attrs(cpu, attrs);
+uint64_t val;
+
+/* set debug attrs to indicate memory access is from the debugger */
+attrs.debug = 1;
+
+debug_ops->read(cpu->cpu_ases[asidx].as, addr, attrs,
+(void *) , 8);
+return val;


You probably want tswap64(val) here like in ldl_phys_debug (even though 
I assume it's a noop in the SEV case).



+}
+
+void cpu_physical_memory_rw_debug(hwaddr addr, uint8_t *buf,
+  int len, int is_write)
+{
+MemTxAttrs attrs;
+
+/* set debug attrs to indicate memory access is from the debugger */
+attrs.debug = 1;


Maybe:

MemTxAttrs attrs = { .debug = 1 };

(Also in the functions above.)


+
+if (is_write) {
+debug_ops->write(_space_memory, addr,
+ attrs, buf, len);
+} else {
+debug_ops->read(_space_memory, addr,
+attrs, buf, len);
+}
+
+}
+
  int64_t address_space_cache_init(MemoryRegionCache *cache,
   AddressSpace *as,
   hwaddr addr,





[Bug 1905356] [NEW] No check for unaligned data access in ARM32 instructions

2020-11-23 Thread JIANG Muhui
Public bug reported:

hi

According to the ARM documentation, there are alignment requirements of
load/store instructions.  Alignment fault should be raised if the
alignment check is failed. However, it seems that QEMU doesn't implement
this, which is against the documentation of ARM. For example, the
instruction LDRD/STRD/LDREX/STREX must check the address is word
alignment no matter what value the SCTLR.A is.

I attached a testcase, which contains an instruction at VA 0x10240: ldrd
r0,[pc.#1] in the main function. QEMU can successfully load the data in
the unaligned address. The test is done in QEMU 5.1.0. I can provide
more testcases for the other instructions if you need. Many thanks.

To patch this, we need a check while we translate the instruction to
tcg. If the address is unaligned, a signal number (i.e., SIGBUS) should
be raised.

Regards
Muhui

** Affects: qemu
 Importance: Undecided
 Status: New

** Attachment added: "case_ldrd_arm"
   
https://bugs.launchpad.net/bugs/1905356/+attachment/5437364/+files/case_ldrd_arm

** Description changed:

  hi
  
  According to the ARM documentation, there are alignment requirements of
  load/store instructions.  Alignment fault should be raised if the
  alignment check is failed. However, it seems that QEMU doesn't implement
  this, which is against the documentation of ARM. For example, the
  instruction LDRD/STRD/LDREX/STREX must check the address is word
  alignment no matter what value the SCTLR.A is.
  
- I attached a testcase, which contains a instruction at VA 0x10240: ldrd
+ I attached a testcase, which contains an instruction at VA 0x10240: ldrd
  r0,[pc.#1] in the main function. QEMU can successfully load the data in
  the unaligned address. The test is done in QEMU 5.1.0. I can provide
  more testcases for the other instructions if you need. Many thanks.
  
  To patch this, we need a check while we translate the instruction to
  tcg. If the address is unaligned, a signal number (i.e., SIGBUS) should
  be raised.
  
  Regards
  Muhui

-- 
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1905356

Title:
  No check for unaligned data access in ARM32 instructions

Status in QEMU:
  New

Bug description:
  hi

  According to the ARM documentation, there are alignment requirements
  of load/store instructions.  Alignment fault should be raised if the
  alignment check is failed. However, it seems that QEMU doesn't
  implement this, which is against the documentation of ARM. For
  example, the instruction LDRD/STRD/LDREX/STREX must check the address
  is word alignment no matter what value the SCTLR.A is.

  I attached a testcase, which contains an instruction at VA 0x10240:
  ldrd r0,[pc.#1] in the main function. QEMU can successfully load the
  data in the unaligned address. The test is done in QEMU 5.1.0. I can
  provide more testcases for the other instructions if you need. Many
  thanks.

  To patch this, we need a check while we translate the instruction to
  tcg. If the address is unaligned, a signal number (i.e., SIGBUS)
  should be raised.

  Regards
  Muhui

To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1905356/+subscriptions



[PULL 4/5] tap: fix a memory leak

2020-11-23 Thread Jason Wang
From: yuanjungong 

Close fd before returning.

Buglink: https://bugs.launchpad.net/qemu/+bug/1904486

Signed-off-by: yuanjungong 
Reviewed-by: Peter Maydell 
Signed-off-by: Jason Wang 
---
 net/tap.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/tap.c b/net/tap.c
index c46ff66..fe95fa7 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -817,6 +817,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
 if (ret < 0) {
 error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
  name, fd);
+close(fd);
 return -1;
 }
 
@@ -831,6 +832,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
  vhostfdname, vnet_hdr, fd, );
 if (err) {
 error_propagate(errp, err);
+close(fd);
 return -1;
 }
 } else if (tap->has_fds) {
-- 
2.7.4




[PULL 3/5] net: purge queued rx packets on queue deletion

2020-11-23 Thread Jason Wang
From: Yuri Benditovich 

https://bugzilla.redhat.com/show_bug.cgi?id=1829272
When deleting queue pair, purge pending RX packets if any.
Example of problematic flow:
1. Bring up q35 VM with tap (vhost off) and virtio-net or e1000e
2. Run ping flood to the VM NIC ( 1 ms interval)
3. Hot unplug the NIC device (device_del)
   During unplug process one or more packets come, the NIC
   can't receive, tap disables read_poll
4. Hot plug the device (device_add) with the same netdev
The tap stays with read_poll disabled and does not receive
any packets anymore (tap_send never triggered)

Signed-off-by: Yuri Benditovich 
Signed-off-by: Jason Wang 
---
 net/net.c | 12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/net/net.c b/net/net.c
index 6362d30..6a2c3d9 100644
--- a/net/net.c
+++ b/net/net.c
@@ -412,10 +412,14 @@ void qemu_del_nic(NICState *nic)
 
 qemu_macaddr_set_free(>conf->macaddr);
 
-/* If this is a peer NIC and peer has already been deleted, free it now. */
-if (nic->peer_deleted) {
-for (i = 0; i < queues; i++) {
-qemu_free_net_client(qemu_get_subqueue(nic, i)->peer);
+for (i = 0; i < queues; i++) {
+NetClientState *nc = qemu_get_subqueue(nic, i);
+/* If this is a peer NIC and peer has already been deleted, free it 
now. */
+if (nic->peer_deleted) {
+qemu_free_net_client(nc->peer);
+} else if (nc->peer) {
+/* if there are RX packets pending, complete them */
+qemu_purge_queued_packets(nc->peer);
 }
 }
 
-- 
2.7.4




[PULL 5/5] net: Use correct default-path macro for downscript

2020-11-23 Thread Jason Wang
From: Keqian Zhu 

Fixes: 63c4db4c2e6d (net: relocate paths to helpers and scripts)
Signed-off-by: Keqian Zhu 
Signed-off-by: Jason Wang 
---
 net/tap.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/tap.c b/net/tap.c
index fe95fa7..b751285 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -953,7 +953,8 @@ free_fail:
 script = default_script = 
get_relocated_path(DEFAULT_NETWORK_SCRIPT);
 }
 if (!downscript) {
-downscript = default_downscript = 
get_relocated_path(DEFAULT_NETWORK_SCRIPT);
+downscript = default_downscript =
+ 
get_relocated_path(DEFAULT_NETWORK_DOWN_SCRIPT);
 }
 
 if (tap->has_ifname) {
-- 
2.7.4




[PULL 2/5] net: do not exit on "netdev_add help" monitor command

2020-11-23 Thread Jason Wang
From: Paolo Bonzini 

"netdev_add help" is causing QEMU to exit because the code that
invokes show_netdevs is shared between CLI and HMP processing.
Move the check to the callers so that exit(0) remains only
in the CLI flow.

"netdev_add help" is not fixed by this patch; that is left for
later work.

Signed-off-by: Paolo Bonzini 
Signed-off-by: Jason Wang 
---
 include/net/net.h  |  1 +
 monitor/hmp-cmds.c |  6 +
 net/net.c  | 68 +++---
 3 files changed, 41 insertions(+), 34 deletions(-)

diff --git a/include/net/net.h b/include/net/net.h
index 897b2d7..778fc78 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -199,6 +199,7 @@ extern const char *host_net_devices[];
 
 /* from net.c */
 int net_client_parse(QemuOptsList *opts_list, const char *str);
+void show_netdevs(void);
 int net_init_clients(Error **errp);
 void net_check_clients(void);
 void net_cleanup(void);
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index a6a6684..65d8ff4 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -24,6 +24,7 @@
 #include "qemu/option.h"
 #include "qemu/timer.h"
 #include "qemu/sockets.h"
+#include "qemu/help_option.h"
 #include "monitor/monitor-internal.h"
 #include "qapi/error.h"
 #include "qapi/clone-visitor.h"
@@ -1631,7 +1632,12 @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict)
 {
 Error *err = NULL;
 QemuOpts *opts;
+const char *type = qdict_get_try_str(qdict, "type");
 
+if (type && is_help_option(type)) {
+show_netdevs();
+return;
+}
 opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict, );
 if (err) {
 goto out;
diff --git a/net/net.c b/net/net.c
index 794c652..6362d30 100644
--- a/net/net.c
+++ b/net/net.c
@@ -44,6 +44,7 @@
 #include "qemu/config-file.h"
 #include "qemu/ctype.h"
 #include "qemu/iov.h"
+#include "qemu/qemu-print.h"
 #include "qemu/main-loop.h"
 #include "qemu/option.h"
 #include "qapi/error.h"
@@ -1025,7 +1026,7 @@ static int net_client_init1(const Netdev *netdev, bool 
is_netdev, Error **errp)
 return 0;
 }
 
-static void show_netdevs(void)
+void show_netdevs(void)
 {
 int idx;
 const char *available_netdevs[] = {
@@ -1055,9 +1056,9 @@ static void show_netdevs(void)
 #endif
 };
 
-printf("Available netdev backend types:\n");
+qemu_printf("Available netdev backend types:\n");
 for (idx = 0; idx < ARRAY_SIZE(available_netdevs); idx++) {
-puts(available_netdevs[idx]);
+qemu_printf("%s\n", available_netdevs[idx]);
 }
 }
 
@@ -1068,42 +1069,35 @@ static int net_client_init(QemuOpts *opts, bool 
is_netdev, Error **errp)
 int ret = -1;
 Visitor *v = opts_visitor_new(opts);
 
-const char *type = qemu_opt_get(opts, "type");
-
-if (is_netdev && type && is_help_option(type)) {
-show_netdevs();
-exit(0);
-} else {
-/* Parse convenience option format ip6-net=fec0::0[/64] */
-const char *ip6_net = qemu_opt_get(opts, "ipv6-net");
+/* Parse convenience option format ip6-net=fec0::0[/64] */
+const char *ip6_net = qemu_opt_get(opts, "ipv6-net");
 
-if (ip6_net) {
-char *prefix_addr;
-unsigned long prefix_len = 64; /* Default 64bit prefix length. */
+if (ip6_net) {
+char *prefix_addr;
+unsigned long prefix_len = 64; /* Default 64bit prefix length. */
 
-substrings = g_strsplit(ip6_net, "/", 2);
-if (!substrings || !substrings[0]) {
-error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "ipv6-net",
-   "a valid IPv6 prefix");
-goto out;
-}
+substrings = g_strsplit(ip6_net, "/", 2);
+if (!substrings || !substrings[0]) {
+error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "ipv6-net",
+   "a valid IPv6 prefix");
+goto out;
+}
 
-prefix_addr = substrings[0];
+prefix_addr = substrings[0];
 
-/* Handle user-specified prefix length. */
-if (substrings[1] &&
-qemu_strtoul(substrings[1], NULL, 10, _len))
-{
-error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
-   "ipv6-prefixlen", "a number");
-goto out;
-}
-
-qemu_opt_set(opts, "ipv6-prefix", prefix_addr, _abort);
-qemu_opt_set_number(opts, "ipv6-prefixlen", prefix_len,
-_abort);
-qemu_opt_unset(opts, "ipv6-net");
+/* Handle user-specified prefix length. */
+if (substrings[1] &&
+qemu_strtoul(substrings[1], NULL, 10, _len))
+{
+error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+   "ipv6-prefixlen", "a number");
+goto out;
 }
+
+qemu_opt_set(opts, "ipv6-prefix", prefix_addr, _abort);
+qemu_opt_set_number(opts, 

[PULL 1/5] hw/net/e1000e: advance desc_offset in case of null descriptor

2020-11-23 Thread Jason Wang
From: Prasad J Pandit 

While receiving packets via e1000e_write_packet_to_guest() routine,
'desc_offset' is advanced only when RX descriptor is processed. And
RX descriptor is not processed if it has NULL buffer address.
This may lead to an infinite loop condition. Increament 'desc_offset'
to process next descriptor in the ring to avoid infinite loop.

Reported-by: Cheol-woo Myung <330cj...@gmail.com>
Signed-off-by: Prasad J Pandit 
Signed-off-by: Jason Wang 
---
 hw/net/e1000e_core.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
index d8b9e4b..095c01e 100644
--- a/hw/net/e1000e_core.c
+++ b/hw/net/e1000e_core.c
@@ -1596,13 +1596,13 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct 
NetRxPkt *pkt,
   (const char *) _pad, e1000x_fcs_len(core->mac));
 }
 }
-desc_offset += desc_size;
-if (desc_offset >= total_size) {
-is_last = true;
-}
 } else { /* as per intel docs; skip descriptors with null buf addr */
 trace_e1000e_rx_null_descriptor();
 }
+desc_offset += desc_size;
+if (desc_offset >= total_size) {
+is_last = true;
+}
 
 e1000e_write_rx_descr(core, desc, is_last ? core->rx_pkt : NULL,
rss_info, do_ps ? ps_hdr_len : 0, );
-- 
2.7.4




[PULL 0/5] Net patches

2020-11-23 Thread Jason Wang
The following changes since commit 23895cbd82be95428e90168b12e925d0d3ca2f06:

  Merge remote-tracking branch 'remotes/awilliam/tags/vfio-update-20201123.0' 
into staging (2020-11-23 18:51:13 +)

are available in the git repository at:

  https://github.com/jasowang/qemu.git tags/net-pull-request

for you to fetch changes up to 9925990d01a92564af55f6f69d0f5f59b47609b1:

  net: Use correct default-path macro for downscript (2020-11-24 10:40:17 +0800)




Keqian Zhu (1):
  net: Use correct default-path macro for downscript

Paolo Bonzini (1):
  net: do not exit on "netdev_add help" monitor command

Prasad J Pandit (1):
  hw/net/e1000e: advance desc_offset in case of null descriptor

Yuri Benditovich (1):
  net: purge queued rx packets on queue deletion

yuanjungong (1):
  tap: fix a memory leak

 hw/net/e1000e_core.c |  8 +++---
 include/net/net.h|  1 +
 monitor/hmp-cmds.c   |  6 
 net/net.c| 80 +++-
 net/tap.c|  5 +++-
 5 files changed, 57 insertions(+), 43 deletions(-)




[PATCH] hw/arm/smmuv3: Fix up L1STD_SPAN decoding

2020-11-23 Thread Kunkun Jiang
Accroding to the SMMUv3 spec, the SPAN field of Level1 Stream Table
Descriptor is 5 bits([4:0]).

Fixes: 9bde7f0674f(hw/arm/smmuv3: Implement translate callback)
Signed-off-by: Kunkun Jiang 
---
 hw/arm/smmuv3-internal.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index fa3c088972..b6f7e53b7c 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -633,6 +633,6 @@ static inline uint64_t l1std_l2ptr(STEDesc *desc)
 return hi << 32 | lo;
 }
 
-#define L1STD_SPAN(stm) (extract32((stm)->word[0], 0, 4))
+#define L1STD_SPAN(stm) (extract32((stm)->word[0], 0, 5))
 
 #endif
-- 
2.23.0




Re: [PATCH] xive: Add trace events

2020-11-23 Thread David Gibson
On Mon, Nov 23, 2020 at 05:37:17PM +0100, Cédric Le Goater wrote:
> I have been keeping those logging messages in an ugly form for
> while. Make them clean !
> 
> Beware not to activate all of them, this is really verbose.
> 
> Signed-off-by: Cédric Le Goater 

Applied to ppc-for-6.0, thanks.

> ---
>  hw/intc/spapr_xive.c | 27 +++
>  hw/intc/xive.c   | 40 +---
>  hw/intc/trace-events | 26 ++
>  3 files changed, 90 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
> index 1fa09f287ac0..644cc85cbdc9 100644
> --- a/hw/intc/spapr_xive.c
> +++ b/hw/intc/spapr_xive.c
> @@ -24,6 +24,7 @@
>  #include "hw/ppc/xive.h"
>  #include "hw/ppc/xive_regs.h"
>  #include "hw/qdev-properties.h"
> +#include "trace.h"
>  
>  /*
>   * XIVE Virtualization Controller BAR and Thread Managment BAR that we
> @@ -900,6 +901,8 @@ static target_ulong h_int_get_source_info(PowerPCCPU *cpu,
>  target_ulong flags  = args[0];
>  target_ulong lisn   = args[1];
>  
> +trace_spapr_xive_get_source_info(flags, lisn);
> +
>  if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
>  return H_FUNCTION;
>  }
> @@ -1015,6 +1018,8 @@ static target_ulong h_int_set_source_config(PowerPCCPU 
> *cpu,
>  uint8_t end_blk;
>  uint32_t end_idx;
>  
> +trace_spapr_xive_set_source_config(flags, lisn, target, priority, eisn);
> +
>  if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
>  return H_FUNCTION;
>  }
> @@ -1120,6 +1125,8 @@ static target_ulong h_int_get_source_config(PowerPCCPU 
> *cpu,
>  uint8_t nvt_blk;
>  uint32_t end_idx, nvt_idx;
>  
> +trace_spapr_xive_get_source_config(flags, lisn);
> +
>  if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
>  return H_FUNCTION;
>  }
> @@ -1194,6 +1201,8 @@ static target_ulong h_int_get_queue_info(PowerPCCPU 
> *cpu,
>  uint8_t end_blk;
>  uint32_t end_idx;
>  
> +trace_spapr_xive_get_queue_info(flags, target, priority);
> +
>  if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
>  return H_FUNCTION;
>  }
> @@ -1281,6 +1290,8 @@ static target_ulong h_int_set_queue_config(PowerPCCPU 
> *cpu,
>  uint8_t end_blk, nvt_blk;
>  uint32_t end_idx, nvt_idx;
>  
> +trace_spapr_xive_set_queue_config(flags, target, priority, qpage, qsize);
> +
>  if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
>  return H_FUNCTION;
>  }
> @@ -1448,6 +1459,8 @@ static target_ulong h_int_get_queue_config(PowerPCCPU 
> *cpu,
>  uint8_t end_blk;
>  uint32_t end_idx;
>  
> +trace_spapr_xive_get_queue_config(flags, target, priority);
> +
>  if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
>  return H_FUNCTION;
>  }
> @@ -1541,6 +1554,10 @@ static target_ulong 
> h_int_set_os_reporting_line(PowerPCCPU *cpu,
>  target_ulong opcode,
>  target_ulong *args)
>  {
> +target_ulong flags   = args[0];
> +
> +trace_spapr_xive_set_os_reporting_line(flags);
> +
>  if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
>  return H_FUNCTION;
>  }
> @@ -1577,6 +1594,10 @@ static target_ulong 
> h_int_get_os_reporting_line(PowerPCCPU *cpu,
>  target_ulong opcode,
>  target_ulong *args)
>  {
> +target_ulong flags   = args[0];
> +
> +trace_spapr_xive_get_os_reporting_line(flags);
> +
>  if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
>  return H_FUNCTION;
>  }
> @@ -1629,6 +1650,8 @@ static target_ulong h_int_esb(PowerPCCPU *cpu,
>  hwaddr mmio_addr;
>  XiveSource *xsrc = >source;
>  
> +trace_spapr_xive_esb(flags, lisn, offset, data);
> +
>  if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
>  return H_FUNCTION;
>  }
> @@ -1698,6 +1721,8 @@ static target_ulong h_int_sync(PowerPCCPU *cpu,
>  target_ulong flags = args[0];
>  target_ulong lisn = args[1];
>  
> +trace_spapr_xive_sync(flags, lisn);
> +
>  if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
>  return H_FUNCTION;
>  }
> @@ -1763,6 +1788,8 @@ static target_ulong h_int_reset(PowerPCCPU *cpu,
>  SpaprXive *xive = spapr->xive;
>  target_ulong flags   = args[0];
>  
> +trace_spapr_xive_reset(flags);
> +
>  if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
>  return H_FUNCTION;
>  }
> diff --git a/hw/intc/xive.c b/hw/intc/xive.c
> index 489e6256ef70..fa8c3d82877f 100644
> --- a/hw/intc/xive.c
> +++ b/hw/intc/xive.c
> @@ -21,6 +21,7 @@
>  #include "hw/irq.h"
>  #include "hw/ppc/xive.h"
>  #include "hw/ppc/xive_regs.h"
> +#include "trace.h"
>  
>  /*
>   * XIVE Thread Interrupt Management context
> @@ -93,6 +94,10 @@ static 

Re: [PULL 0/2] VFIO updates for QEMU 5.2-rc3

2020-11-23 Thread Peter Maydell
On Mon, 23 Nov 2020 at 17:59, Alex Williamson
 wrote:
>
> The following changes since commit 683685e72dccaf8cb9fe8ffa20f5c5aacea72118:
>
>   Merge remote-tracking branch 
> 'remotes/stefanha-gitlab/tags/block-pull-request' into staging (2020-11-23 
> 13:03:13 +)
>
> are available in the Git repository at:
>
>   git://github.com/awilliam/qemu-vfio.git tags/vfio-update-20201123.0
>
> for you to fetch changes up to bb0990d1740f6dced5b50a923677034c9399c213:
>
>   vfio: Change default dirty pages tracking behavior during migration 
> (2020-11-23 10:05:58 -0700)
>
> 
> VFIO update 2020-11-23
>
>  * Enable pre-copy dirty page tracking by default (Kirti Wankhede)
>
>  * Mark migration as experimental (Alex Williamson)
>
> 


Applied, thanks.

Please update the changelog at https://wiki.qemu.org/ChangeLog/5.2
for any user-visible changes.

-- PMM



Re: [PATCH V17 4/6] hw/mips: Add Loongson-3 boot parameter helpers

2020-11-23 Thread Philippe Mathieu-Daudé
On 11/6/20 5:21 AM, Huacai Chen wrote:
> Preparing to add Loongson-3 machine support, add Loongson-3's LEFI (a
> UEFI-like interface for BIOS-Kernel boot parameters) helpers first.
> 
> Reviewed-by: Philippe Mathieu-Daudé 
> Signed-off-by: Huacai Chen 
> Co-developed-by: Jiaxun Yang 
> Signed-off-by: Jiaxun Yang 
> ---
>  hw/mips/loongson3_bootp.c | 165 +++
>  hw/mips/loongson3_bootp.h | 241 
> ++
>  hw/mips/meson.build   |   1 +
>  3 files changed, 407 insertions(+)
>  create mode 100644 hw/mips/loongson3_bootp.c
>  create mode 100644 hw/mips/loongson3_bootp.h
> 
> diff --git a/hw/mips/loongson3_bootp.c b/hw/mips/loongson3_bootp.c
> new file mode 100644
> index 000..3a16081
> --- /dev/null
> +++ b/hw/mips/loongson3_bootp.c
> @@ -0,0 +1,165 @@
> +/*
> + * LEFI (a UEFI-like interface for BIOS-Kernel boot parameters) helpers
> + *
> + * Copyright (c) 2018-2020 Huacai Chen (che...@lemote.com)
> + * Copyright (c) 2018-2020 Jiaxun Yang 
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see .
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/units.h"
> +#include "qemu/cutils.h"
> +#include "cpu.h"
> +#include "hw/boards.h"
> +#include "hw/mips/loongson3_bootp.h"
> +
> +#define LOONGSON3_CORE_PER_NODE 4
> +
> +static struct efi_cpuinfo_loongson *init_cpu_info(void *g_cpuinfo, uint64_t 
> cpu_freq)
> +{
> +struct efi_cpuinfo_loongson *c = g_cpuinfo;
> +
> +stl_le_p(>cputype, Loongson_3A);
> +stl_le_p(>processor_id, MIPS_CPU(first_cpu)->env.CP0_PRid);

Build failing with Clang:

FAILED: libqemu-mips64el-softmmu.fa.p/hw_mips_loongson3_bootp.c.o
hw/mips/loongson3_bootp.c:35:15: error: taking address of packed member
'processor_id' of class or structure 'efi_cpuinfo_loongson' may result
in an unaligned pointer value [-Werror,-Waddress-of-packed-member]
stl_le_p(>processor_id, MIPS_CPU(first_cpu)->env.CP0_PRid);
  ^~~
1 error generated.

> +if (cpu_freq > UINT_MAX) {
> +stl_le_p(>cpu_clock_freq, UINT_MAX);
> +} else {
> +stl_le_p(>cpu_clock_freq, cpu_freq);
> +}
> +
> +stw_le_p(>cpu_startup_core_id, 0);
> +stl_le_p(>nr_cpus, current_machine->smp.cpus);
> +stl_le_p(>total_node, DIV_ROUND_UP(current_machine->smp.cpus,
> +  LOONGSON3_CORE_PER_NODE));
> +
> +return c;
> +}
> +
> +static struct efi_memory_map_loongson *init_memory_map(void *g_map, uint64_t 
> ram_size)
> +{
> +struct efi_memory_map_loongson *emap = g_map;
> +
> +stl_le_p(>nr_map, 2);
> +stl_le_p(>mem_freq, 3);
> +
> +stl_le_p(>map[0].node_id, 0);
> +stl_le_p(>map[0].mem_type, 1);
> +stq_le_p(>map[0].mem_start, 0x0);
> +stl_le_p(>map[0].mem_size, 240);
> +
> +stl_le_p(>map[1].node_id, 0);
> +stl_le_p(>map[1].mem_type, 2);
> +stq_le_p(>map[1].mem_start, 0x9000);
> +stl_le_p(>map[1].mem_size, (ram_size / MiB) - 256);
> +
> +return emap;
> +}
> +
> +static struct system_loongson *init_system_loongson(void *g_system)
> +{
> +struct system_loongson *s = g_system;
> +
> +stl_le_p(>ccnuma_smp, 0);
> +stl_le_p(>sing_double_channel, 1);
> +stl_le_p(>nr_uarts, 1);
> +stl_le_p(>uarts[0].iotype, 2);
> +stl_le_p(>uarts[0].int_offset, 2);
> +stl_le_p(>uarts[0].uartclk, 2500); /* Random value */
> +stq_le_p(>uarts[0].uart_base, virt_memmap[VIRT_UART].base);
> +
> +return s;
> +}
> +
> +static struct irq_source_routing_table *init_irq_source(void *g_irq_source)
> +{
> +struct irq_source_routing_table *irq_info = g_irq_source;
> +
> +stl_le_p(_info->node_id, 0);
> +stl_le_p(_info->PIC_type, 0);
> +stw_le_p(_info->dma_mask_bits, 64);
> +stq_le_p(_info->pci_mem_start_addr, 
> virt_memmap[VIRT_PCIE_MMIO].base);
> +stq_le_p(_info->pci_mem_end_addr, virt_memmap[VIRT_PCIE_MMIO].base +
> +  virt_memmap[VIRT_PCIE_MMIO].size - 
> 1);
> +stq_le_p(_info->pci_io_start_addr, virt_memmap[VIRT_PCIE_PIO].base);
> +
> +return irq_info;
> +}
> +
> +static struct interface_info *init_interface_info(void *g_interface)
> +{
> +struct interface_info *interface = g_interface;
> +
> +stw_le_p(>vers, 0x01);
> +strpadcpy(interface->description, 64, "UEFI_Version_v1.0", '\0');
> +
> +return 

Re: [PATCH V17 2/6] hw/intc: Rework Loongson LIOINTC

2020-11-23 Thread Philippe Mathieu-Daudé
On 11/23/20 9:52 PM, Philippe Mathieu-Daudé wrote:
> On 11/6/20 5:21 AM, Huacai Chen wrote:
>> As suggested by Philippe Mathieu-Daudé, rework Loongson's liointc:
>> 1, Move macro definitions to loongson_liointc.h;
>> 2, Remove magic values and use macros instead;
>> 3, Replace dead D() code by trace events.
>>
>> Suggested-by: Philippe Mathieu-Daudé 
>> Signed-off-by: Huacai Chen 
>> ---
>>  hw/intc/loongson_liointc.c | 49 
>> +++---
>>  include/hw/intc/loongson_liointc.h | 39 ++
>>  2 files changed, 53 insertions(+), 35 deletions(-)
>>  create mode 100644 include/hw/intc/loongson_liointc.h
>>
>> diff --git a/hw/intc/loongson_liointc.c b/hw/intc/loongson_liointc.c
>> index fbbfb57..be29e2f 100644
>> --- a/hw/intc/loongson_liointc.c
>> +++ b/hw/intc/loongson_liointc.c
>> @@ -1,6 +1,7 @@
>>  /*
>>   * QEMU Loongson Local I/O interrupt controler.
>>   *
>> + * Copyright (c) 2020 Huacai Chen 
>>   * Copyright (c) 2020 Jiaxun Yang 
>>   *
>>   * This program is free software: you can redistribute it and/or modify
>> @@ -19,33 +20,11 @@
>>   */
>>  
>>  #include "qemu/osdep.h"
>> -#include "hw/sysbus.h"
>>  #include "qemu/module.h"
>> +#include "qemu/log.h"
>>  #include "hw/irq.h"
>>  #include "hw/qdev-properties.h"
>> -#include "qom/object.h"
>> -
>> -#define D(x)
>> -
>> -#define NUM_IRQS32
>> -
>> -#define NUM_CORES   4
>> -#define NUM_IPS 4
>> -#define NUM_PARENTS (NUM_CORES * NUM_IPS)
>> -#define PARENT_COREx_IPy(x, y)  (NUM_IPS * x + y)
>> -
>> -#define R_MAPPER_START  0x0
>> -#define R_MAPPER_END0x20
>> -#define R_ISR   R_MAPPER_END
>> -#define R_IEN   0x24
>> -#define R_IEN_SET   0x28
>> -#define R_IEN_CLR   0x2c
>> -#define R_PERCORE_ISR(x)(0x40 + 0x8 * x)
>> -#define R_END   0x64
>> -
>> -#define TYPE_LOONGSON_LIOINTC "loongson.liointc"
>> -DECLARE_INSTANCE_CHECKER(struct loongson_liointc, LOONGSON_LIOINTC,
>> - TYPE_LOONGSON_LIOINTC)
>> +#include "hw/intc/loongson_liointc.h"
>>  
>>  struct loongson_liointc {
>>  SysBusDevice parent_obj;
>> @@ -123,14 +102,13 @@ liointc_read(void *opaque, hwaddr addr, unsigned int 
>> size)
>>  goto out;
>>  }
>>  
>> -/* Rest is 4 byte */
>> +/* Rest are 4 bytes */
>>  if (size != 4 || (addr % 4)) {
>>  goto out;
>>  }
>>  
>> -if (addr >= R_PERCORE_ISR(0) &&
>> -addr < R_PERCORE_ISR(NUM_CORES)) {
>> -int core = (addr - R_PERCORE_ISR(0)) / 8;
>> +if (addr >= R_START && addr < R_END) {
>> +int core = (addr - R_START) / R_ISR_SIZE;
>>  r = p->per_core_isr[core];
>>  goto out;
>>  }
>> @@ -147,7 +125,8 @@ liointc_read(void *opaque, hwaddr addr, unsigned int 
>> size)
>>  }
>>  
>>  out:
>> -D(qemu_log("%s: size=%d addr=%lx val=%x\n", __func__, size, addr, r));
>> +qemu_log_mask(CPU_LOG_INT, "%s: size=%d addr=%lx val=%x\n",
>> +  __func__, size, addr, r);
>>  return r;
>>  }
>>  
>> @@ -158,7 +137,8 @@ liointc_write(void *opaque, hwaddr addr,
>>  struct loongson_liointc *p = opaque;
>>  uint32_t value = val64;
>>  
>> -D(qemu_log("%s: size=%d, addr=%lx val=%x\n", __func__, size, addr, 
>> value));
>> +qemu_log_mask(CPU_LOG_INT, "%s: size=%d, addr=%lx val=%x\n",
>> +  __func__, size, addr, value);
>>  
>>  /* Mapper is 1 byte */
>>  if (size == 1 && addr < R_MAPPER_END) {
>> @@ -166,14 +146,13 @@ liointc_write(void *opaque, hwaddr addr,
>>  goto out;
>>  }
>>  
>> -/* Rest is 4 byte */
>> +/* Rest are 4 bytes */
>>  if (size != 4 || (addr % 4)) {
>>  goto out;
>>  }
>>  
>> -if (addr >= R_PERCORE_ISR(0) &&
>> -addr < R_PERCORE_ISR(NUM_CORES)) {
>> -int core = (addr - R_PERCORE_ISR(0)) / 8;
>> +if (addr >= R_START && addr < R_END) {
>> +int core = (addr - R_START) / R_ISR_SIZE;
>>  p->per_core_isr[core] = value;
>>  goto out;
>>  }
>> @@ -224,7 +203,7 @@ static void loongson_liointc_init(Object *obj)
>>  }
>>  
>>  memory_region_init_io(>mmio, obj, _ops, p,
>> - "loongson.liointc", R_END);
>> + TYPE_LOONGSON_LIOINTC, R_END);
>>  sysbus_init_mmio(SYS_BUS_DEVICE(obj), >mmio);
>>  }
>>  
>> diff --git a/include/hw/intc/loongson_liointc.h 
>> b/include/hw/intc/loongson_liointc.h
>> new file mode 100644
>> index 000..e11f482
>> --- /dev/null
>> +++ b/include/hw/intc/loongson_liointc.h
>> @@ -0,0 +1,39 @@
>> +/*
>> + * This file is subject to the terms and conditions of the GNU General 
>> Public
>> + * License.  See the file "COPYING" in the main directory of this archive
>> + * for more details.
>> + *
>> + * Copyright (c) 2020 Huacai Chen 
>> + * Copyright (c) 2020 Jiaxun Yang 
>> + *
>> + */
>> +
>> +#ifndef 

Re: [PATCH] hmp: Changed hmp_netdev_add() using qmp_marshal_netdev_add()

2020-11-23 Thread Yuri Benditovich
The patch below solves both issues: with netdev created by hmp and with
netdev created from command-line:

diff --git a/net/net.c b/net/net.c
index bcd5da4aa0..98294f24ed 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1155,6 +1155,11 @@ void qmp_netdev_del(const char *id, Error **errp)
 }

 qemu_del_net_client(nc);
+
+QemuOpts *opts = qemu_opts_find(qemu_find_opts("netdev"), id);
+if (opts) {
+qemu_opts_del(opts);
+}
 }

static void netfilter_print_info(Monitor *mon, NetFilterState *nf)

Please let me know if you have any objections.
If not, I'll send it as a patch.


On Mon, Nov 23, 2020 at 5:35 PM Yuri Benditovich <
yuri.benditov...@daynix.com> wrote:

>
>
> On Mon, Nov 23, 2020 at 11:25 AM Markus Armbruster 
> wrote:
>
>> Andrew Melnichenko  writes:
>>
>> > --f73b2205b4aef0c5
>> > Content-Type: text/plain; charset="UTF-8"
>> >
>> > Hi, the bug can be reproduced like that:
>> >
>> >> QEMU 5.1.50 monitor - type 'help' for more information
>> >> (qemu) netdev_add
>> >> type=tap,id=net0,script=/home/and/SRCS/qemu/ifup.sh,downscript=no
>> >> (qemu) info network
>> >> hub 0
>> >>  \ hub0port1: __org.qemu.net1:
>> index=0,type=user,net=10.0.2.0,restrict=off
>> >>  \ hub0port0: e1000e.0:
>> >> index=0,type=nic,model=e1000e,macaddr=52:54:00:12:34:56
>> >> dnet0: index=0,type=nic,model=virtio-net-pci,macaddr=52:54:00:12:34:57
>> >> net0:
>> >>
>> index=0,type=tap,ifname=tap0,script=/home/and/SRCS/qemu/ifup.sh,downscript=no
>> >> (qemu) netdev_del net0
>> >> (qemu) info network
>> >> hub 0
>> >>  \ hub0port1: __org.qemu.net1:
>> index=0,type=user,net=10.0.2.0,restrict=off
>> >>  \ hub0port0: e1000e.0:
>> >> index=0,type=nic,model=e1000e,macaddr=52:54:00:12:34:56
>> >> dnet0: index=0,type=nic,model=virtio-net-pci,macaddr=52:54:00:12:34:57
>> >> (qemu) netdev_add
>> >> type=tap,id=net0,script=/home/and/SRCS/qemu/ifup.sh,downscript=no
>> >> Try "help netdev_add" for more information
>> >> (qemu) info network
>> >> hub 0
>> >>  \ hub0port1: __org.qemu.net1:
>> index=0,type=user,net=10.0.2.0,restrict=off
>> >>  \ hub0port0: e1000e.0:
>> >> index=0,type=nic,model=e1000e,macaddr=52:54:00:12:34:56
>> >> dnet0: index=0,type=nic,model=virtio-net-pci,macaddr=52:54:00:12:34:57
>> >> (qemu)
>> >>
>> >>
>> > Its still actual bug - I've checked it with the
>> > master(2c6605389c1f76973d92b69b85d40d94b8f1092c).
>>
>> I can see this with an even simpler reproducer:
>>
>> $ qemu-system-x86_64 -S -display none -nodefaults -monitor stdio
>> QEMU 5.1.92 monitor - type 'help' for more information
>> (qemu) netdev_add user,id=net0
>> (qemu) info network
>> net0: index=0,type=user,net=10.0.2.0,restrict=off
>> (qemu) netdev_del net0
>> (qemu) info network
>> (qemu) netdev_add user,id=net0
>> upstream-qemu: Duplicate ID 'net0' for netdev
>> Try "help netdev_add" for more information
>>
>> The appended patch fixes it for me.  It relies on nothing using the
>> "netdev" QemuOpts anymore.  Eric, what do you think?
>>
>>
>> diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
>> index a6a6684df1..8bc6b7bcc6 100644
>> --- a/monitor/hmp-cmds.c
>> +++ b/monitor/hmp-cmds.c
>> @@ -1638,9 +1638,7 @@ void hmp_netdev_add(Monitor *mon, const QDict
>> *qdict)
>>  }
>>
>>  netdev_add(opts, );
>> -if (err) {
>> -qemu_opts_del(opts);
>> -}
>> +qemu_opts_del(opts);
>>
>>
> Unfortunately, if I'm not mistaken, with this fix qemu will be able to
> create from hmp several devices with the same id
> (which is not expected).
> For example:
> netdev_add user,id=net0
> netdev_add user,id=net0
> info network lists 2 devices net0
>
>
>
>>  out:
>>  hmp_handle_error(mon, err);
>>
>>


Re: [PATCH V17 5/6] hw/mips: Add Loongson-3 machine support

2020-11-23 Thread Philippe Mathieu-Daudé
Hi Huacai,

On 11/6/20 5:21 AM, Huacai Chen wrote:
> Add Loongson-3 based machine support, it use liointc as the interrupt
> controler and use GPEX as the pci controller. Currently it can work with
> both TCG and KVM.
> 
> As the machine model is not based on any exiting physical hardware, the
> name of the machine is "loongson3-virt". It may be superseded in future
> by a real machine model. If this happens, then a regular deprecation
> procedure shall occur for "loongson3-virt" machine.
> 
> We now already have a full functional Linux kernel (based on Linux-5.4.x
> LTS) here:
> 
> https://github.com/chenhuacai/linux
> 
> Of course the upstream kernel is also usable (the kvm host side and
> guest side have both been upstream in Linux-5.9):
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
> 
> How to use QEMU/Loongson-3?
> 1, Download kernel source from the above URL;
> 2, Build a kernel with arch/mips/configs/loongson3_defconfig;
> 3, Boot a Loongson-3A4000 host with this kernel (for KVM mode);
> 4, Build QEMU-master with this patchset;
> 5, modprobe kvm (only necessary for KVM mode);
> 6, Use QEMU with TCG:
>qemu-system-mips64el -M loongson3-virt,accel=tcg -cpu Loongson-3A1000 
> -kernel  -append ...
>Use QEMU with KVM:
>qemu-system-mips64el -M loongson3-virt,accel=kvm -cpu Loongson-3A4000 
> -kernel  -append ...
> 
>The "-cpu" parameter is optional here and QEMU will use the correct type 
> for TCG/KVM automatically.
> 
> Signed-off-by: Huacai Chen 
> Co-developed-by: Jiaxun Yang 
> Signed-off-by: Jiaxun Yang 
> ---
>  default-configs/devices/mips64el-softmmu.mak |   1 +
>  hw/mips/Kconfig  |  12 +
>  hw/mips/loongson3_virt.c | 614 
> +++
>  hw/mips/meson.build  |   2 +-
>  4 files changed, 628 insertions(+), 1 deletion(-)
>  create mode 100644 hw/mips/loongson3_virt.c
> 
> diff --git a/default-configs/devices/mips64el-softmmu.mak 
> b/default-configs/devices/mips64el-softmmu.mak
> index 9f8a3ef..26c660a 100644
> --- a/default-configs/devices/mips64el-softmmu.mak
> +++ b/default-configs/devices/mips64el-softmmu.mak
> @@ -3,6 +3,7 @@
>  include mips-softmmu-common.mak
>  CONFIG_IDE_VIA=y
>  CONFIG_FULOONG=y
> +CONFIG_LOONGSON3V=y
>  CONFIG_ATI_VGA=y
>  CONFIG_RTL8139_PCI=y
>  CONFIG_JAZZ=y
> diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> index 8be7012..ef5cee1 100644
> --- a/hw/mips/Kconfig
> +++ b/hw/mips/Kconfig
> @@ -32,6 +32,18 @@ config FULOONG
>  bool
>  select PCI_BONITO
>  
> +config LOONGSON3V
> +bool
> +select PCKBD

Is it used? I only see USB.

> +select SERIAL
> +select GOLDFISH_RTC
> +select LOONGSON_LIOINTC
> +select PCI_DEVICES
> +select PCI_EXPRESS_GENERIC_BRIDGE
> +select VIRTIO_VGA
> +select QXL if SPICE

I don't understand the UI dependencies, as we should
be able to start this machine without UI (just console
for example).

Maybe you want the 'imply' keyword instead?

> +select MSI_NONBROKEN
> +
>  config MIPS_CPS
>  bool
>  select PTIMER
> diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
> new file mode 100644
> index 000..c5db2db
> --- /dev/null
> +++ b/hw/mips/loongson3_virt.c
> @@ -0,0 +1,614 @@
> +/*
> + * Generic Loongson-3 Platform support
> + *
> + * Copyright (c) 2018-2020 Huacai Chen (che...@lemote.com)
> + * Copyright (c) 2018-2020 Jiaxun Yang 
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see .
> + */
> +
> +/*
> + * Generic virtualized PC Platform based on Loongson-3 CPU (MIPS64R2 with
> + * extensions, 800~2000MHz)
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu-common.h"
> +#include "qemu/units.h"
> +#include "qemu/cutils.h"
> +#include "qapi/error.h"
> +#include "cpu.h"
> +#include "elf.h"
> +#include "kvm_mips.h"
> +#include "hw/boards.h"
> +#include "hw/char/serial.h"
> +#include "hw/intc/loongson_liointc.h"
> +#include "hw/mips/mips.h"
> +#include "hw/mips/cpudevs.h"
> +#include "hw/mips/fw_cfg.h"
> +#include "hw/mips/loongson3_bootp.h"
> +#include "hw/misc/unimp.h"
> +#include "hw/intc/i8259.h"
> +#include "hw/loader.h"
> +#include "hw/isa/superio.h"
> +#include "hw/pci/msi.h"
> +#include "hw/pci/pci.h"
> +#include "hw/pci/pci_host.h"
> +#include "hw/pci-host/gpex.h"
> +#include "hw/usb.h"
> +#include "net/net.h"
> 

Re: [PATCH RFC] vfio: Move the saving of the config space to the right place in VFIO migration

2020-11-23 Thread Alex Williamson
On Mon, 23 Nov 2020 11:33:37 -0800
Neo Jia  wrote:

> On Mon, Nov 23, 2020 at 11:14:38AM +0800, Shenming Lu wrote:
> > External email: Use caution opening links or attachments
> > 
> > 
> > On 2020/11/21 6:01, Alex Williamson wrote:  
> > > On Fri, 20 Nov 2020 22:05:49 +0800
> > > Shenming Lu  wrote:
> > >  
> > >> On 2020/11/20 1:41, Alex Williamson wrote:  
> > >>> On Thu, 19 Nov 2020 14:13:24 +0530
> > >>> Kirti Wankhede  wrote:
> > >>>  
> >  On 11/14/2020 2:47 PM, Shenming Lu wrote:  
> > > When running VFIO migration, I found that the restoring of VFIO PCI 
> > > device’s
> > > config space is before VGIC on ARM64 target. But generally, interrupt 
> > > controllers
> > > need to be restored before PCI devices.  
> > 
> >  Is there any other way by which VGIC can be restored before PCI 
> >  device?  
> > >>
> > >> As far as I know, it seems to have to depend on priorities in the 
> > >> non-iterable process.
> > >>  
> >   
> > > Besides, if a VFIO PCI device is
> > > configured to have directly-injected MSIs (VLPIs), the restoring of 
> > > its config
> > > space will trigger the configuring of these VLPIs (in kernel), where 
> > > it would
> > > return an error as I saw due to the dependency on kvm’s vgic.
> > >  
> > 
> >  Can this be fixed in kernel to re-initialize the kernel state?  
> > >>
> > >> Did you mean to reconfigure these VLPIs when restoring kvm's vgic?
> > >> But the fact is that this error is not caused by kernel, it is due to 
> > >> the incorrect
> > >> calling order of qemu...
> > >>  
> >   
> > > To avoid this, we can move the saving of the config space from the 
> > > iterable
> > > process to the non-iterable process, so that it will be called after 
> > > VGIC
> > > according to their priorities.
> > >  
> > 
> >  With this change, at resume side, pre-copy phase data would reach
> >  destination without restored config space. VFIO device on destination
> >  might need it's config space setup and validated before it can accept
> >  further VFIO device specific migration state.
> > 
> >  This also changes bit-stream, so it would break migration with original
> >  migration patch-set.  
> > >>>
> > >>> Config space can continue to change while in pre-copy, if we're only
> > >>> sending config space at the initiation of pre-copy, how are any changes
> > >>> that might occur before the VM is stopped conveyed to the target?  For
> > >>> example the guest might reboot and a device returned to INTx mode from
> > >>> MSI during pre-copy.  Thanks,  
> > >>
> > >> What I see is that the config space is only saved once in 
> > >> save_live_complete_precopy
> > >> currently...
> > >> As you said, a VFIO device might need it's config space setup first, and
> > >> the config space can continue to change while in pre-copy, Did you mean 
> > >> we
> > >> have to migrate the config space in save_live_iterate?
> > >> However, I still have a little doubt about the restoring dependence 
> > >> between
> > >> the qemu emulated config space and the device data...
> > >>
> > >> Besides, if we surely can't move the saving of the config space back, 
> > >> can we
> > >> just move some actions which are triggered by the restoring of the 
> > >> config space
> > >> back (such as vfio_msix_enable())?  
> > >
> > > It seems that the significant benefit to enabling interrupts during
> > > pre-copy would be to reduce the latency and failure potential during
> > > the final phase of migration.  Do we have any data for how much it adds
> > > to the device contributed downtime to configure interrupts only at the
> > > final stage?  My guess is that it's a measurable delay on its own.  At
> > > the same time, we can't ignore the differences in machine specific
> > > dependencies and if we don't even sync the config space once the VM is
> > > stopped... this all seems not ready to call supported, especially if we
> > > have concerns already about migration bit-stream compatibility.
> > >  
> > 
> > I have another question for this, if we restore the config space while in 
> > pre-copy
> > (include enabling interrupts), does it affect the _RESUMING state (paused) 
> > of the
> > device on the dst host (cause it to send interrupts? which should not be 
> > allowed
> > in this stage). Does the restore sequence need to be further discussed and 
> > reach
> > a consensus(spec) (taking into account other devices and the corresponding 
> > actions
> > of the vendor driver)?

If a target device generates an interrupt when stopped, I think that
would violate the basic notion of running vs stopped in the device
state, right?

> > > Given our timing relative to QEMU 5.2, the only path I feel comfortable
> > > with is to move forward with downgrading vfio migration support to be
> > > enabled via an experimental option.  Objections?  Thanks,  
> > 
> > Alright, but this issue is related 

Re: [PATCH v2] net/e1000e_core: adjust count if RDH exceeds RDT in e1000e_ring_advance()

2020-11-23 Thread Mauro Matteo Cascella
On Thu, Nov 19, 2020 at 6:57 AM Jason Wang  wrote:
>
>
> On 2020/11/18 下午4:53, Mauro Matteo Cascella wrote:
> > On Wed, Nov 18, 2020 at 4:56 AM Jason Wang  wrote:
> >>
> >> On 2020/11/13 下午6:31, Mauro Matteo Cascella wrote:
> >>> The e1000e_write_packet_to_guest() function iterates over a set of
> >>> receive descriptors by advancing rx descriptor head register (RDH) from
> >>> its initial value to rx descriptor tail register (RDT). The check in
> >>> e1000e_ring_empty() is responsible for detecting whether RDH has reached
> >>> RDT, terminating the loop if that's the case. Additional checks have
> >>> been added in the past to deal with bogus values submitted by the guest
> >>> to prevent possible infinite loop. This is done by "wrapping around" RDH
> >>> at some point and detecting whether it assumes the original value during
> >>> the loop.
> >>>
> >>> However, when e1000e is configured to use the packet split feature, RDH is
> >>> incremented by two instead of one, as the packet split descriptors are
> >>> 32 bytes while regular descriptors are 16 bytes. A malicious or buggy
> >>> guest may set RDT to an odd value and transmit only null RX descriptors.
> >>> This corner case would prevent RDH from ever matching RDT, leading to an
> >>> infinite loop. This patch adds a check in e1000e_ring_advance() to make 
> >>> sure
> >>> RDH does not exceed RDT in a single incremental step, adjusting the count
> >>> value accordingly.
> >>
> >> Can this patch solve this issue in another way?
> >>
> >> https://patchew.org/QEMU/2020130636.2208620-1-ppan...@redhat.com/
> >>
> >> Thanks
> >>
> > Yes, it does work nicely. Still, I think this patch is useful to avoid
> > possible inconsistent state in e1000e_ring_advance() when count > 1.
>
>
> So if RDT is odd, it looks to me the following codes in
> e1000e_write_packet_to_guest() needs to be fixed as well.
>
>
>  base = e1000e_ring_head_descr(core, rxi);
>
>  pci_dma_read(d, base, , core->rx_desc_len);
>
> Otherwise e1000e may try to read out of descriptor ring.

Sorry, I'm not sure I understand what you mean. Isn't the base address
computed from RDH? How can e1000e read out of the descriptor ring if
RDT is odd?

>
> Thanks


On Thu, Nov 19, 2020 at 6:57 AM Jason Wang  wrote:
>
>
> On 2020/11/18 下午4:53, Mauro Matteo Cascella wrote:
> > On Wed, Nov 18, 2020 at 4:56 AM Jason Wang  wrote:
> >>
> >> On 2020/11/13 下午6:31, Mauro Matteo Cascella wrote:
> >>> The e1000e_write_packet_to_guest() function iterates over a set of
> >>> receive descriptors by advancing rx descriptor head register (RDH) from
> >>> its initial value to rx descriptor tail register (RDT). The check in
> >>> e1000e_ring_empty() is responsible for detecting whether RDH has reached
> >>> RDT, terminating the loop if that's the case. Additional checks have
> >>> been added in the past to deal with bogus values submitted by the guest
> >>> to prevent possible infinite loop. This is done by "wrapping around" RDH
> >>> at some point and detecting whether it assumes the original value during
> >>> the loop.
> >>>
> >>> However, when e1000e is configured to use the packet split feature, RDH is
> >>> incremented by two instead of one, as the packet split descriptors are
> >>> 32 bytes while regular descriptors are 16 bytes. A malicious or buggy
> >>> guest may set RDT to an odd value and transmit only null RX descriptors.
> >>> This corner case would prevent RDH from ever matching RDT, leading to an
> >>> infinite loop. This patch adds a check in e1000e_ring_advance() to make 
> >>> sure
> >>> RDH does not exceed RDT in a single incremental step, adjusting the count
> >>> value accordingly.
> >>
> >> Can this patch solve this issue in another way?
> >>
> >> https://patchew.org/QEMU/2020130636.2208620-1-ppan...@redhat.com/
> >>
> >> Thanks
> >>
> > Yes, it does work nicely. Still, I think this patch is useful to avoid
> > possible inconsistent state in e1000e_ring_advance() when count > 1.
>
>
> So if RDT is odd, it looks to me the following codes in
> e1000e_write_packet_to_guest() needs to be fixed as well.
>
>
>  base = e1000e_ring_head_descr(core, rxi);
>
>  pci_dma_read(d, base, , core->rx_desc_len);
>
> Otherwise e1000e may try to read out of descriptor ring.
>
> Thanks
>
>
> >
> > Thank you,
>


-- 
Mauro Matteo Cascella
Red Hat Product Security
PGP-Key ID: BB3410B0




Re: [PATCH V17 2/6] hw/intc: Rework Loongson LIOINTC

2020-11-23 Thread Philippe Mathieu-Daudé
On 11/6/20 5:21 AM, Huacai Chen wrote:
> As suggested by Philippe Mathieu-Daudé, rework Loongson's liointc:
> 1, Move macro definitions to loongson_liointc.h;
> 2, Remove magic values and use macros instead;
> 3, Replace dead D() code by trace events.
> 
> Suggested-by: Philippe Mathieu-Daudé 
> Signed-off-by: Huacai Chen 
> ---
>  hw/intc/loongson_liointc.c | 49 
> +++---
>  include/hw/intc/loongson_liointc.h | 39 ++
>  2 files changed, 53 insertions(+), 35 deletions(-)
>  create mode 100644 include/hw/intc/loongson_liointc.h
> 
> diff --git a/hw/intc/loongson_liointc.c b/hw/intc/loongson_liointc.c
> index fbbfb57..be29e2f 100644
> --- a/hw/intc/loongson_liointc.c
> +++ b/hw/intc/loongson_liointc.c
> @@ -1,6 +1,7 @@
>  /*
>   * QEMU Loongson Local I/O interrupt controler.
>   *
> + * Copyright (c) 2020 Huacai Chen 
>   * Copyright (c) 2020 Jiaxun Yang 
>   *
>   * This program is free software: you can redistribute it and/or modify
> @@ -19,33 +20,11 @@
>   */
>  
>  #include "qemu/osdep.h"
> -#include "hw/sysbus.h"
>  #include "qemu/module.h"
> +#include "qemu/log.h"
>  #include "hw/irq.h"
>  #include "hw/qdev-properties.h"
> -#include "qom/object.h"
> -
> -#define D(x)
> -
> -#define NUM_IRQS32
> -
> -#define NUM_CORES   4
> -#define NUM_IPS 4
> -#define NUM_PARENTS (NUM_CORES * NUM_IPS)
> -#define PARENT_COREx_IPy(x, y)  (NUM_IPS * x + y)
> -
> -#define R_MAPPER_START  0x0
> -#define R_MAPPER_END0x20
> -#define R_ISR   R_MAPPER_END
> -#define R_IEN   0x24
> -#define R_IEN_SET   0x28
> -#define R_IEN_CLR   0x2c
> -#define R_PERCORE_ISR(x)(0x40 + 0x8 * x)
> -#define R_END   0x64
> -
> -#define TYPE_LOONGSON_LIOINTC "loongson.liointc"
> -DECLARE_INSTANCE_CHECKER(struct loongson_liointc, LOONGSON_LIOINTC,
> - TYPE_LOONGSON_LIOINTC)
> +#include "hw/intc/loongson_liointc.h"
>  
>  struct loongson_liointc {
>  SysBusDevice parent_obj;
> @@ -123,14 +102,13 @@ liointc_read(void *opaque, hwaddr addr, unsigned int 
> size)
>  goto out;
>  }
>  
> -/* Rest is 4 byte */
> +/* Rest are 4 bytes */
>  if (size != 4 || (addr % 4)) {
>  goto out;
>  }
>  
> -if (addr >= R_PERCORE_ISR(0) &&
> -addr < R_PERCORE_ISR(NUM_CORES)) {
> -int core = (addr - R_PERCORE_ISR(0)) / 8;
> +if (addr >= R_START && addr < R_END) {
> +int core = (addr - R_START) / R_ISR_SIZE;
>  r = p->per_core_isr[core];
>  goto out;
>  }
> @@ -147,7 +125,8 @@ liointc_read(void *opaque, hwaddr addr, unsigned int size)
>  }
>  
>  out:
> -D(qemu_log("%s: size=%d addr=%lx val=%x\n", __func__, size, addr, r));
> +qemu_log_mask(CPU_LOG_INT, "%s: size=%d addr=%lx val=%x\n",
> +  __func__, size, addr, r);
>  return r;
>  }
>  
> @@ -158,7 +137,8 @@ liointc_write(void *opaque, hwaddr addr,
>  struct loongson_liointc *p = opaque;
>  uint32_t value = val64;
>  
> -D(qemu_log("%s: size=%d, addr=%lx val=%x\n", __func__, size, addr, 
> value));
> +qemu_log_mask(CPU_LOG_INT, "%s: size=%d, addr=%lx val=%x\n",
> +  __func__, size, addr, value);
>  
>  /* Mapper is 1 byte */
>  if (size == 1 && addr < R_MAPPER_END) {
> @@ -166,14 +146,13 @@ liointc_write(void *opaque, hwaddr addr,
>  goto out;
>  }
>  
> -/* Rest is 4 byte */
> +/* Rest are 4 bytes */
>  if (size != 4 || (addr % 4)) {
>  goto out;
>  }
>  
> -if (addr >= R_PERCORE_ISR(0) &&
> -addr < R_PERCORE_ISR(NUM_CORES)) {
> -int core = (addr - R_PERCORE_ISR(0)) / 8;
> +if (addr >= R_START && addr < R_END) {
> +int core = (addr - R_START) / R_ISR_SIZE;
>  p->per_core_isr[core] = value;
>  goto out;
>  }
> @@ -224,7 +203,7 @@ static void loongson_liointc_init(Object *obj)
>  }
>  
>  memory_region_init_io(>mmio, obj, _ops, p,
> - "loongson.liointc", R_END);
> + TYPE_LOONGSON_LIOINTC, R_END);
>  sysbus_init_mmio(SYS_BUS_DEVICE(obj), >mmio);
>  }
>  
> diff --git a/include/hw/intc/loongson_liointc.h 
> b/include/hw/intc/loongson_liointc.h
> new file mode 100644
> index 000..e11f482
> --- /dev/null
> +++ b/include/hw/intc/loongson_liointc.h
> @@ -0,0 +1,39 @@
> +/*
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License.  See the file "COPYING" in the main directory of this archive
> + * for more details.
> + *
> + * Copyright (c) 2020 Huacai Chen 
> + * Copyright (c) 2020 Jiaxun Yang 
> + *
> + */
> +
> +#ifndef LOONSGON_LIOINTC_H
> +#define LOONGSON_LIOINTC_H
> +
> +#include "qemu/units.h"
> +#include "hw/sysbus.h"
> +#include "qom/object.h"
> +
> +#define NUM_IRQS32
> +
> +#define NUM_CORES   4
> 

Re: [PATCH v3 3/7] support UFFD write fault processing in ram_save_iterate()

2020-11-23 Thread Peter Xu
On Fri, Nov 20, 2020 at 07:53:34PM +0300, Andrey Gruzdev wrote:
> On 20.11.2020 19:43, Peter Xu wrote:
> > On Fri, Nov 20, 2020 at 07:15:07PM +0300, Andrey Gruzdev wrote:
> > > Yeah, I think we can re-use the postcopy queue code for faulting pages. 
> > > I'm
> > > worring a little about some additional overhead dealing with urgent 
> > > request
> > > semaphore. Also, the code won't change a lot, something like:
> > > 
> > > [...]
> > >  /* In case of 'write-tracking' migration we first try
> > >   * to poll UFFD and sse if we have write page fault event */
> > >  poll_fault_page(rs);
> > > 
> > >  again = true;
> > >  found = get_queued_page(rs, );
> > > 
> > >  if (!found) {
> > >  /* priority queue empty, so just search for something dirty 
> > > */
> > >  found = find_dirty_block(rs, , );
> > >  }
> > > [...]
> > 
> > Could I ask what's the "urgent request semaphore"?  Thanks,
> > 
> 
> These function use it (the correct name is 'rate_limit_sem'):
> 
> void migration_make_urgent_request(void)
> {
> qemu_sem_post(_get_current()->rate_limit_sem);
> }
> 
> void migration_consume_urgent_request(void)
> {
> qemu_sem_wait(_get_current()->rate_limit_sem);
> }
> 
> They are called from ram_save_queue_pages and unqueue_page, accordingly, to
> control migration rate limiter.
> 
> bool migration_rate_limit(void)
> {
> [...]
> /*
>  * Wait for a delay to do rate limiting OR
>  * something urgent to post the semaphore.
>  */
> int ms = s->iteration_start_time + BUFFER_DELAY - now;
> trace_migration_rate_limit_pre(ms);
> if (qemu_sem_timedwait(>rate_limit_sem, ms) == 0) {
> /*
>  * We were woken by one or more urgent things but
>  * the timedwait will have consumed one of them.
>  * The service routine for the urgent wake will dec
>  * the semaphore itself for each item it consumes,
>  * so add this one we just eat back.
>  */
> qemu_sem_post(>rate_limit_sem);
> urgent = true;
> }
> [...]
> }
> 

Hmm... Why its overhead could be a problem?  If it's an overhead that can be
avoided, then postcopy might want that too.

The thing is I really feel like the snapshot logic can leverage the whole idea
of existing postcopy (like get_queued_page/unqueue_page; it's probably due to
the fact that both of them want to "migrate some more urgent pages than the
background migration, due to either missing/wrprotected pages"), but I might
have something missing.

Thanks,

-- 
Peter Xu




Re: [PATCH v2 27/28] MAINTAINERS: Add entry for MIPS Ingenic Xburst TCG

2020-11-23 Thread Philippe Mathieu-Daudé
On Mon, Nov 23, 2020 at 9:47 PM Philippe Mathieu-Daudé  wrote:
>
> Add an entry for the TCG core related to Ingenic Xburst.
>
> Signed-off-by: Philippe Mathieu-Daudé 
> ---
> Adding Craig Janeczek in case he wants to be notified of changes,
> patch conditional to his approval.
> ---
>  MAINTAINERS | 6 ++
>  1 file changed, 6 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 0f49b997f2e..976d23508c8 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -248,6 +248,12 @@ R: Jiaxun Yang 
>  S: Odd Fixes
>  F: target/mips/vendor-loong*
>
> +MIPS TCG CPUs (Ingenic Xburst)
> +M: Philippe Mathieu-Daudé 
> +R: Craig Janeczek 
> +S: Odd Fixes
> +F: target/mips/vendor-xburst*

Oops this is now vendor-mxu*

> +
>  MIPS TCG CPUs (nanoMIPS ISA)
>  S: Orphan
>  F: disas/nanomips.*
> --
> 2.26.2
>



[PATCH v2 24/28] target/mips: Extract Toshiba TXx9 translation routines

2020-11-23 Thread Philippe Mathieu-Daudé
Extract 300 lines of the Toshiba TX19/TX39/TX49/TX79
translation routines to 'vendor-tx_translate.c.inc'.

Signed-off-by: Philippe Mathieu-Daudé 
Reviewed-by: Richard Henderson 
Message-Id: <20201120210844.2625602-23-f4...@amsat.org>
---
 target/mips/translate.c   | 302 +---
 target/mips/vendor-tx_translate.c.inc | 315 ++
 2 files changed, 316 insertions(+), 301 deletions(-)
 create mode 100644 target/mips/vendor-tx_translate.c.inc

diff --git a/target/mips/translate.c b/target/mips/translate.c
index 8854d284d33..a4558c21d3f 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -633,31 +633,6 @@ enum {
  * configure the 128-bit data path as two 64-bit, four 32-bit, eight 16-bit
  * or sixteen 8-bit paths.
  *
- * Reference:
- *
- * The Toshiba TX System RISC TX79 Core Architecture manual,
- * https://wiki.qemu.org/File:C790.pdf
- *
- * Three-Operand Multiply and Multiply-Add (4 instructions)
- * 
- * MADD[rd,] rs, rt  Multiply/Add
- * MADDU   [rd,] rs, rt  Multiply/Add Unsigned
- * MULT[rd,] rs, rt  Multiply (3-operand)
- * MULTU   [rd,] rs, rt  Multiply Unsigned (3-operand)
- *
- * Multiply Instructions for Pipeline 1 (10 instructions)
- * --
- * MULT1   [rd,] rs, rt  Multiply Pipeline 1
- * MULTU1  [rd,] rs, rt  Multiply Unsigned Pipeline 1
- * DIV1rs, rtDivide Pipeline 1
- * DIVU1   rs, rtDivide Unsigned Pipeline 1
- * MADD1   [rd,] rs, rt  Multiply-Add Pipeline 1
- * MADDU1  [rd,] rs, rt  Multiply-Add Unsigned Pipeline 1
- * MFHI1   rdMove From HI1 Register
- * MFLO1   rdMove From LO1 Register
- * MTHI1   rsMove To HI1 Register
- * MTLO1   rsMove To LO1 Register
- *
  * Arithmetic (19 instructions)
  * 
  * PADDB   rd, rs, rtParallel Add Byte
@@ -2949,44 +2924,6 @@ static void gen_shift(DisasContext *ctx, uint32_t opc,
 tcg_temp_free(t1);
 }
 
-#if defined(TARGET_MIPS64)
-/* Copy GPR to and from TX79 HI1/LO1 register. */
-static void gen_HILO1_tx79(DisasContext *ctx, uint32_t opc, int reg)
-{
-if (reg == 0 && (opc == OPC_MFHI1 || opc == OPC_MFLO1)) {
-/* Treat as NOP. */
-return;
-}
-
-switch (opc) {
-case OPC_MFHI1:
-tcg_gen_mov_tl(cpu_gpr[reg], cpu_HI[1]);
-break;
-case OPC_MFLO1:
-tcg_gen_mov_tl(cpu_gpr[reg], cpu_LO[1]);
-break;
-case OPC_MTHI1:
-if (reg != 0) {
-tcg_gen_mov_tl(cpu_HI[1], cpu_gpr[reg]);
-} else {
-tcg_gen_movi_tl(cpu_HI[1], 0);
-}
-break;
-case OPC_MTLO1:
-if (reg != 0) {
-tcg_gen_mov_tl(cpu_LO[1], cpu_gpr[reg]);
-} else {
-tcg_gen_movi_tl(cpu_LO[1], 0);
-}
-break;
-default:
-MIPS_INVAL("mfthilo1 TX79");
-generate_exception_end(ctx, EXCP_RI);
-break;
-}
-}
-#endif
-
 /* Arithmetic on HI/LO registers */
 static void gen_HILO(DisasContext *ctx, uint32_t opc, int acc, int reg)
 {
@@ -3335,65 +3272,6 @@ static void gen_r6_muldiv(DisasContext *ctx, int opc, 
int rd, int rs, int rt)
 tcg_temp_free(t1);
 }
 
-#if defined(TARGET_MIPS64)
-static void gen_div1_tx79(DisasContext *ctx, uint32_t opc, int rs, int rt)
-{
-TCGv t0, t1;
-
-t0 = tcg_temp_new();
-t1 = tcg_temp_new();
-
-gen_load_gpr(t0, rs);
-gen_load_gpr(t1, rt);
-
-switch (opc) {
-case OPC_DIV1:
-{
-TCGv t2 = tcg_temp_new();
-TCGv t3 = tcg_temp_new();
-tcg_gen_ext32s_tl(t0, t0);
-tcg_gen_ext32s_tl(t1, t1);
-tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN);
-tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1);
-tcg_gen_and_tl(t2, t2, t3);
-tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
-tcg_gen_or_tl(t2, t2, t3);
-tcg_gen_movi_tl(t3, 0);
-tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
-tcg_gen_div_tl(cpu_LO[1], t0, t1);
-tcg_gen_rem_tl(cpu_HI[1], t0, t1);
-tcg_gen_ext32s_tl(cpu_LO[1], cpu_LO[1]);
-tcg_gen_ext32s_tl(cpu_HI[1], cpu_HI[1]);
-tcg_temp_free(t3);
-tcg_temp_free(t2);
-}
-break;
-case OPC_DIVU1:
-{
-TCGv t2 = tcg_const_tl(0);
-TCGv t3 = tcg_const_tl(1);
-tcg_gen_ext32u_tl(t0, t0);
-tcg_gen_ext32u_tl(t1, t1);
-tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
-tcg_gen_divu_tl(cpu_LO[1], t0, t1);
-tcg_gen_remu_tl(cpu_HI[1], t0, t1);
-tcg_gen_ext32s_tl(cpu_LO[1], cpu_LO[1]);
-tcg_gen_ext32s_tl(cpu_HI[1], cpu_HI[1]);
-tcg_temp_free(t3);
-

[PATCH v2 23/28] target/mips: Make pipeline 1 multiply opcodes generic

2020-11-23 Thread Philippe Mathieu-Daudé
Special2 multiply opcodes are not specific to Toshiba TX79,
and are not part of its multimedia extension.

Signed-off-by: Philippe Mathieu-Daudé 
Reviewed-by: Richard Henderson 
Message-Id: <20201120210844.2625602-22-f4...@amsat.org>
---
 target/mips/translate.c | 75 +
 1 file changed, 38 insertions(+), 37 deletions(-)

diff --git a/target/mips/translate.c b/target/mips/translate.c
index 7ef3bc52358..8854d284d33 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -330,6 +330,19 @@ enum {
 OPC_MUL  = 0x02 | OPC_SPECIAL2,
 OPC_MSUB = 0x04 | OPC_SPECIAL2,
 OPC_MSUBU= 0x05 | OPC_SPECIAL2,
+
+/* Multiply Instructions for Pipeline 1 */
+OPC_MFHI1= 0x10 | OPC_SPECIAL2,
+OPC_MTHI1= 0x11 | OPC_SPECIAL2,
+OPC_MFLO1= 0x12 | OPC_SPECIAL2,
+OPC_MTLO1= 0x13 | OPC_SPECIAL2,
+OPC_MULT1= 0x18 | OPC_SPECIAL2,
+OPC_MULTU1   = 0x19 | OPC_SPECIAL2,
+OPC_DIV1 = 0x1A | OPC_SPECIAL2,
+OPC_DIVU1= 0x1B | OPC_SPECIAL2,
+OPC_MADD1= 0x20 | OPC_SPECIAL2,
+OPC_MADDU1   = 0x21 | OPC_SPECIAL2,
+
 /* Misc */
 OPC_CLZ  = 0x20 | OPC_SPECIAL2,
 OPC_CLO  = 0x21 | OPC_SPECIAL2,
@@ -836,21 +849,9 @@ enum {
 
 #define MASK_MMI(op) (MASK_OP_MAJOR(op) | ((op) & 0x3F))
 enum {
-MMI_OPC_MADD   = 0x00 | MMI_OPC_CLASS_MMI, /* Same as OPC_MADD */
-MMI_OPC_MADDU  = 0x01 | MMI_OPC_CLASS_MMI, /* Same as OPC_MADDU */
 MMI_OPC_PLZCW  = 0x04 | MMI_OPC_CLASS_MMI,
 MMI_OPC_CLASS_MMI0 = 0x08 | MMI_OPC_CLASS_MMI,
 MMI_OPC_CLASS_MMI2 = 0x09 | MMI_OPC_CLASS_MMI,
-MMI_OPC_MFHI1  = 0x10 | MMI_OPC_CLASS_MMI, /* Same minor as OPC_MFHI */
-MMI_OPC_MTHI1  = 0x11 | MMI_OPC_CLASS_MMI, /* Same minor as OPC_MTHI */
-MMI_OPC_MFLO1  = 0x12 | MMI_OPC_CLASS_MMI, /* Same minor as OPC_MFLO */
-MMI_OPC_MTLO1  = 0x13 | MMI_OPC_CLASS_MMI, /* Same minor as OPC_MTLO */
-MMI_OPC_MULT1  = 0x18 | MMI_OPC_CLASS_MMI, /* Same minor as OPC_MULT */
-MMI_OPC_MULTU1 = 0x19 | MMI_OPC_CLASS_MMI, /* Same min. as OPC_MULTU */
-MMI_OPC_DIV1   = 0x1A | MMI_OPC_CLASS_MMI, /* Same minor as OPC_DIV  */
-MMI_OPC_DIVU1  = 0x1B | MMI_OPC_CLASS_MMI, /* Same minor as OPC_DIVU */
-MMI_OPC_MADD1  = 0x20 | MMI_OPC_CLASS_MMI,
-MMI_OPC_MADDU1 = 0x21 | MMI_OPC_CLASS_MMI,
 MMI_OPC_CLASS_MMI1 = 0x28 | MMI_OPC_CLASS_MMI,
 MMI_OPC_CLASS_MMI3 = 0x29 | MMI_OPC_CLASS_MMI,
 MMI_OPC_PMFHL  = 0x30 | MMI_OPC_CLASS_MMI,
@@ -2952,26 +2953,26 @@ static void gen_shift(DisasContext *ctx, uint32_t opc,
 /* Copy GPR to and from TX79 HI1/LO1 register. */
 static void gen_HILO1_tx79(DisasContext *ctx, uint32_t opc, int reg)
 {
-if (reg == 0 && (opc == MMI_OPC_MFHI1 || opc == MMI_OPC_MFLO1)) {
+if (reg == 0 && (opc == OPC_MFHI1 || opc == OPC_MFLO1)) {
 /* Treat as NOP. */
 return;
 }
 
 switch (opc) {
-case MMI_OPC_MFHI1:
+case OPC_MFHI1:
 tcg_gen_mov_tl(cpu_gpr[reg], cpu_HI[1]);
 break;
-case MMI_OPC_MFLO1:
+case OPC_MFLO1:
 tcg_gen_mov_tl(cpu_gpr[reg], cpu_LO[1]);
 break;
-case MMI_OPC_MTHI1:
+case OPC_MTHI1:
 if (reg != 0) {
 tcg_gen_mov_tl(cpu_HI[1], cpu_gpr[reg]);
 } else {
 tcg_gen_movi_tl(cpu_HI[1], 0);
 }
 break;
-case MMI_OPC_MTLO1:
+case OPC_MTLO1:
 if (reg != 0) {
 tcg_gen_mov_tl(cpu_LO[1], cpu_gpr[reg]);
 } else {
@@ -3346,7 +3347,7 @@ static void gen_div1_tx79(DisasContext *ctx, uint32_t 
opc, int rs, int rt)
 gen_load_gpr(t1, rt);
 
 switch (opc) {
-case MMI_OPC_DIV1:
+case OPC_DIV1:
 {
 TCGv t2 = tcg_temp_new();
 TCGv t3 = tcg_temp_new();
@@ -3367,7 +3368,7 @@ static void gen_div1_tx79(DisasContext *ctx, uint32_t 
opc, int rs, int rt)
 tcg_temp_free(t2);
 }
 break;
-case MMI_OPC_DIVU1:
+case OPC_DIVU1:
 {
 TCGv t2 = tcg_const_tl(0);
 TCGv t3 = tcg_const_tl(1);
@@ -3622,7 +3623,7 @@ static void gen_mul_txx9(DisasContext *ctx, uint32_t opc,
 gen_load_gpr(t1, rt);
 
 switch (opc) {
-case MMI_OPC_MULT1:
+case OPC_MULT1:
 acc = 1;
 /* Fall through */
 case OPC_MULT:
@@ -3641,7 +3642,7 @@ static void gen_mul_txx9(DisasContext *ctx, uint32_t opc,
 tcg_temp_free_i32(t3);
 }
 break;
-case MMI_OPC_MULTU1:
+case OPC_MULTU1:
 acc = 1;
 /* Fall through */
 case OPC_MULTU:
@@ -3660,10 +3661,10 @@ static void gen_mul_txx9(DisasContext *ctx, uint32_t 
opc,
 tcg_temp_free_i32(t3);
 }
 break;
-case MMI_OPC_MADD1:
+case OPC_MADD1:
 acc = 1;
 /* Fall through */
-case MMI_OPC_MADD:
+case OPC_MADD:
 {
 TCGv_i64 t2 = tcg_temp_new_i64();
 TCGv_i64 t3 = tcg_temp_new_i64();

[PATCH v2 21/28] target/mips: Extract Loongson EXTensions translation routines

2020-11-23 Thread Philippe Mathieu-Daudé
LoongEXTs are general-purpose extensions from the LoongISA.

Extract 650 lines of translation routines to
'vendor-loong-ext_translate.c.inc'.

Signed-off-by: Philippe Mathieu-Daudé 
---
 target/mips/translate.c  | 652 +-
 target/mips/vendor-loong-ext_translate.c.inc | 665 +++
 2 files changed, 666 insertions(+), 651 deletions(-)
 create mode 100644 target/mips/vendor-loong-ext_translate.c.inc

diff --git a/target/mips/translate.c b/target/mips/translate.c
index 745bf9a9dd9..90ab84c69a3 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -330,19 +330,6 @@ enum {
 OPC_MUL  = 0x02 | OPC_SPECIAL2,
 OPC_MSUB = 0x04 | OPC_SPECIAL2,
 OPC_MSUBU= 0x05 | OPC_SPECIAL2,
-/* Loongson 2F */
-OPC_MULT_G_2F   = 0x10 | OPC_SPECIAL2,
-OPC_DMULT_G_2F  = 0x11 | OPC_SPECIAL2,
-OPC_MULTU_G_2F  = 0x12 | OPC_SPECIAL2,
-OPC_DMULTU_G_2F = 0x13 | OPC_SPECIAL2,
-OPC_DIV_G_2F= 0x14 | OPC_SPECIAL2,
-OPC_DDIV_G_2F   = 0x15 | OPC_SPECIAL2,
-OPC_DIVU_G_2F   = 0x16 | OPC_SPECIAL2,
-OPC_DDIVU_G_2F  = 0x17 | OPC_SPECIAL2,
-OPC_MOD_G_2F= 0x1c | OPC_SPECIAL2,
-OPC_DMOD_G_2F   = 0x1d | OPC_SPECIAL2,
-OPC_MODU_G_2F   = 0x1e | OPC_SPECIAL2,
-OPC_DMODU_G_2F  = 0x1f | OPC_SPECIAL2,
 /* Misc */
 OPC_CLZ  = 0x20 | OPC_SPECIAL2,
 OPC_CLO  = 0x21 | OPC_SPECIAL2,
@@ -412,48 +399,6 @@ enum {
 R6_OPC_SCD = 0x27 | OPC_SPECIAL3,
 };
 
-/* Loongson EXT load/store quad word opcodes */
-#define MASK_LOONGSON_GSLSQ(op)   (MASK_OP_MAJOR(op) | (op & 0x8020))
-enum {
-OPC_GSLQ= 0x0020 | OPC_LWC2,
-OPC_GSLQC1  = 0x8020 | OPC_LWC2,
-OPC_GSSHFL  = OPC_LWC2,
-OPC_GSSQ= 0x0020 | OPC_SWC2,
-OPC_GSSQC1  = 0x8020 | OPC_SWC2,
-OPC_GSSHFS  = OPC_SWC2,
-};
-
-/* Loongson EXT shifted load/store opcodes */
-#define MASK_LOONGSON_GSSHFLS(op) (MASK_OP_MAJOR(op) | (op & 0xc03f))
-enum {
-OPC_GSLWLC1 = 0x4 | OPC_GSSHFL,
-OPC_GSLWRC1 = 0x5 | OPC_GSSHFL,
-OPC_GSLDLC1 = 0x6 | OPC_GSSHFL,
-OPC_GSLDRC1 = 0x7 | OPC_GSSHFL,
-OPC_GSSWLC1 = 0x4 | OPC_GSSHFS,
-OPC_GSSWRC1 = 0x5 | OPC_GSSHFS,
-OPC_GSSDLC1 = 0x6 | OPC_GSSHFS,
-OPC_GSSDRC1 = 0x7 | OPC_GSSHFS,
-};
-
-/* Loongson EXT LDC2/SDC2 opcodes */
-#define MASK_LOONGSON_LSDC2(op)   (MASK_OP_MAJOR(op) | (op & 0x7))
-
-enum {
-OPC_GSLBX  = 0x0 | OPC_LDC2,
-OPC_GSLHX  = 0x1 | OPC_LDC2,
-OPC_GSLWX  = 0x2 | OPC_LDC2,
-OPC_GSLDX  = 0x3 | OPC_LDC2,
-OPC_GSLWXC1= 0x6 | OPC_LDC2,
-OPC_GSLDXC1= 0x7 | OPC_LDC2,
-OPC_GSSBX  = 0x0 | OPC_SDC2,
-OPC_GSSHX  = 0x1 | OPC_SDC2,
-OPC_GSSWX  = 0x2 | OPC_SDC2,
-OPC_GSSDX  = 0x3 | OPC_SDC2,
-OPC_GSSWXC1= 0x6 | OPC_SDC2,
-OPC_GSSDXC1= 0x7 | OPC_SDC2,
-};
-
 /* BSHFL opcodes */
 #define MASK_BSHFL(op)  (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
 
@@ -4472,602 +4417,6 @@ static void gen_cl(DisasContext *ctx, uint32_t opc,
 }
 }
 
-/* Godson integer instructions */
-static void gen_loongson_integer(DisasContext *ctx, uint32_t opc,
- int rd, int rs, int rt)
-{
-TCGv t0, t1;
-
-if (rd == 0) {
-/* Treat as NOP. */
-return;
-}
-
-switch (opc) {
-case OPC_MULT_G_2E:
-case OPC_MULT_G_2F:
-case OPC_MULTU_G_2E:
-case OPC_MULTU_G_2F:
-#if defined(TARGET_MIPS64)
-case OPC_DMULT_G_2E:
-case OPC_DMULT_G_2F:
-case OPC_DMULTU_G_2E:
-case OPC_DMULTU_G_2F:
-#endif
-t0 = tcg_temp_new();
-t1 = tcg_temp_new();
-break;
-default:
-t0 = tcg_temp_local_new();
-t1 = tcg_temp_local_new();
-break;
-}
-
-gen_load_gpr(t0, rs);
-gen_load_gpr(t1, rt);
-
-switch (opc) {
-case OPC_MULT_G_2E:
-case OPC_MULT_G_2F:
-tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
-tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
-break;
-case OPC_MULTU_G_2E:
-case OPC_MULTU_G_2F:
-tcg_gen_ext32u_tl(t0, t0);
-tcg_gen_ext32u_tl(t1, t1);
-tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
-tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
-break;
-case OPC_DIV_G_2E:
-case OPC_DIV_G_2F:
-{
-TCGLabel *l1 = gen_new_label();
-TCGLabel *l2 = gen_new_label();
-TCGLabel *l3 = gen_new_label();
-tcg_gen_ext32s_tl(t0, t0);
-tcg_gen_ext32s_tl(t1, t1);
-tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
-tcg_gen_movi_tl(cpu_gpr[rd], 0);
-tcg_gen_br(l3);
-gen_set_label(l1);
-tcg_gen_brcondi_tl(TCG_COND_NE, t0, INT_MIN, l2);
-tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1, l2);
-tcg_gen_mov_tl(cpu_gpr[rd], t0);
-tcg_gen_br(l3);
-gen_set_label(l2);
-

[PATCH v2 27/28] MAINTAINERS: Add entry for MIPS Ingenic Xburst TCG

2020-11-23 Thread Philippe Mathieu-Daudé
Add an entry for the TCG core related to Ingenic Xburst.

Signed-off-by: Philippe Mathieu-Daudé 
---
Adding Craig Janeczek in case he wants to be notified of changes,
patch conditional to his approval.
---
 MAINTAINERS | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 0f49b997f2e..976d23508c8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -248,6 +248,12 @@ R: Jiaxun Yang 
 S: Odd Fixes
 F: target/mips/vendor-loong*
 
+MIPS TCG CPUs (Ingenic Xburst)
+M: Philippe Mathieu-Daudé 
+R: Craig Janeczek 
+S: Odd Fixes
+F: target/mips/vendor-xburst*
+
 MIPS TCG CPUs (nanoMIPS ISA)
 S: Orphan
 F: disas/nanomips.*
-- 
2.26.2




Re: [PATCH V17 6/6] docs/system: Update MIPS machine documentation

2020-11-23 Thread Philippe Mathieu-Daudé
On 11/6/20 5:21 AM, Huacai Chen wrote:
> Update MIPS machine documentation to add Loongson-3 based machine description.
> 
> Signed-off-by: Huacai Chen 
> ---
>  docs/system/target-mips.rst | 10 ++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/docs/system/target-mips.rst b/docs/system/target-mips.rst
> index cd2a931..138441b 100644
> --- a/docs/system/target-mips.rst
> +++ b/docs/system/target-mips.rst
> @@ -84,6 +84,16 @@ The Fuloong 2E emulation supports:
>  
>  -  RTL8139D as a network card chipset
>  
> +The Loongson-3 virtual platform emulation supports:
> +
> +-  Loongson 3A CPU
> +
> +-  LIOINTC as interrupt controller
> +
> +-  GPEX and virtio as peripheral devices
> +
> +-  Both KVM and TCG supported

Reviewed-by: Philippe Mathieu-Daudé 



[PATCH v2 19/28] target/mips: Extract Loongson SIMD helper definitions

2020-11-23 Thread Philippe Mathieu-Daudé
Extract the Loongson SIMD helper definitions to
'vendor-loong-simd_helper.h'.

Signed-off-by: Philippe Mathieu-Daudé 
Reviewed-by: Richard Henderson 
Message-Id: <20201120210844.2625602-18-f4...@amsat.org>
---
 target/mips/helper.h   | 60 +--
 target/mips/vendor-loong-simd_helper.h.inc | 69 ++
 2 files changed, 70 insertions(+), 59 deletions(-)
 create mode 100644 target/mips/vendor-loong-simd_helper.h.inc

diff --git a/target/mips/helper.h b/target/mips/helper.h
index 58c716a1480..4de11e8209b 100644
--- a/target/mips/helper.h
+++ b/target/mips/helper.h
@@ -343,65 +343,6 @@ DEF_HELPER_1(rdhwr_xnp, tl, env)
 DEF_HELPER_2(pmon, void, env, int)
 DEF_HELPER_1(wait, void, env)
 
-/* Loongson multimedia functions.  */
-DEF_HELPER_FLAGS_2(paddsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(paddush, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(paddh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(paddw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(paddsb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(paddusb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(paddb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-
-DEF_HELPER_FLAGS_2(psubsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(psubush, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(psubh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(psubw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(psubsb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(psubusb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(psubb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-
-DEF_HELPER_FLAGS_2(pshufh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(packsswh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(packsshb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(packushb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-
-DEF_HELPER_FLAGS_2(punpcklhw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(punpckhhw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(punpcklbh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(punpckhbh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(punpcklwd, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(punpckhwd, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-
-DEF_HELPER_FLAGS_2(pavgh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(pavgb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(pmaxsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(pminsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(pmaxub, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(pminub, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-
-DEF_HELPER_FLAGS_2(pcmpeqw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(pcmpgtw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(pcmpeqh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(pcmpgth, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(pcmpeqb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(pcmpgtb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-
-DEF_HELPER_FLAGS_2(psllw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(psllh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(psrlw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(psrlh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(psraw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(psrah, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-
-DEF_HELPER_FLAGS_2(pmullh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(pmulhh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(pmulhuh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(pmaddhw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-
-DEF_HELPER_FLAGS_2(pasubub, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_1(biadd, TCG_CALL_NO_RWG_SE, i64, i64)
-DEF_HELPER_FLAGS_1(pmovmskb, TCG_CALL_NO_RWG_SE, i64, i64)
-
 DEF_HELPER_3(cache, void, env, tl, i32)
 
 #include "isa-micromips_helper.h.inc"
@@ -411,3 +352,4 @@ DEF_HELPER_3(cache, void, env, tl, i32)
 #include "mod-mt_helper.h.inc"
 
 #include "vendor-vr54xx_helper.h.inc"
+#include "vendor-loong-simd_helper.h.inc"
diff --git a/target/mips/vendor-loong-simd_helper.h.inc 
b/target/mips/vendor-loong-simd_helper.h.inc
new file mode 100644
index 000..30e5fda66e9
--- /dev/null
+++ b/target/mips/vendor-loong-simd_helper.h.inc
@@ -0,0 +1,69 @@
+/*
+ * Loongson SIMD instruction emulation helpers for QEMU.
+ *
+ *  Copyright (c) 2004-2005 Jocelyn Mayer
+ *  Copyright (c) 2006 Marius Groeger (FPU operations)
+ *  Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support)
+ *  Copyright (c) 2009 CodeSourcery (MIPS16 and microMIPS support)
+ *  Copyright (c) 2011 Richard Henderson 
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+DEF_HELPER_FLAGS_2(paddsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(paddush, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(paddh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(paddw, 

[PATCH v2 18/28] target/mips: Rename lmmi_helper.c as loong-simd_helper.c

2020-11-23 Thread Philippe Mathieu-Daudé
The LoongMMI extension has been renamed LoongSIMD
(part of the LoongISA). Rename the helper file accordingly.

Signed-off-by: Philippe Mathieu-Daudé 
Reviewed-by: Richard Henderson 
Message-Id: <20201120210844.2625602-17-f4...@amsat.org>
---
 target/mips/{lmmi_helper.c => vendor-loong-simd_helper.c} | 0
 target/mips/meson.build   | 2 +-
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename target/mips/{lmmi_helper.c => vendor-loong-simd_helper.c} (100%)

diff --git a/target/mips/lmmi_helper.c b/target/mips/vendor-loong-simd_helper.c
similarity index 100%
rename from target/mips/lmmi_helper.c
rename to target/mips/vendor-loong-simd_helper.c
diff --git a/target/mips/meson.build b/target/mips/meson.build
index 8cc1d0ca0f7..d9285ae047a 100644
--- a/target/mips/meson.build
+++ b/target/mips/meson.build
@@ -4,10 +4,10 @@
   'fpu_helper.c',
   'gdbstub.c',
   'helper.c',
-  'lmmi_helper.c',
   'op_helper.c',
   'mod-dsp_helper.c',
   'mod-msa_helper.c',
+  'vendor-loong-simd_helper.c',
   'vendor-vr54xx_helper.c',
 
   'translate.c',
-- 
2.26.2




[PATCH v2 28/28] MAINTAINERS: Add entry for MIPS Toshiba TCG

2020-11-23 Thread Philippe Mathieu-Daudé
Add an entry for the TCG core related to Toshiba TXx9.

Signed-off-by: Philippe Mathieu-Daudé 
---
Adding Fredrik Noring in case he wants to be notified of changes,
patch conditional to his approval.
---
 MAINTAINERS | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 976d23508c8..7b70cd9a799 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -254,6 +254,12 @@ R: Craig Janeczek 
 S: Odd Fixes
 F: target/mips/vendor-xburst*
 
+MIPS TCG CPUs (Toshiba TX)
+M: Philippe Mathieu-Daudé 
+R: Fredrik Noring 
+S: Odd Fixes
+F: target/mips/vendor-tx*
+
 MIPS TCG CPUs (nanoMIPS ISA)
 S: Orphan
 F: disas/nanomips.*
-- 
2.26.2




[PATCH v2 26/28] MAINTAINERS: Add entry for MIPS Loongson TCG

2020-11-23 Thread Philippe Mathieu-Daudé
Add an entry for the TCG core related to Loongson.

Signed-off-by: Philippe Mathieu-Daudé 
---
Adding Huacai and Jiaxun in case they want to be notified of
changes, patch conditional to their individual approval.
---
 MAINTAINERS | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 10e87d27eab..0f49b997f2e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -241,6 +241,13 @@ F: include/hw/timer/mips_gictimer.h
 F: tests/tcg/mips/
 K: ^Subject:.*(?i)mips
 
+MIPS TCG CPUs (Loongson)
+M: Philippe Mathieu-Daudé 
+R: Huacai Chen 
+R: Jiaxun Yang 
+S: Odd Fixes
+F: target/mips/vendor-loong*
+
 MIPS TCG CPUs (nanoMIPS ISA)
 S: Orphan
 F: disas/nanomips.*
-- 
2.26.2




[PATCH v2 25/28] target/mips: Extract Toshiba TX79 multimedia translation routines

2020-11-23 Thread Philippe Mathieu-Daudé
Extract 600 lines of the the Toshiba TX79 multimedia
translation routines to 'vendor-tx-mmi_translate.c.inc'.

Signed-off-by: Philippe Mathieu-Daudé 
---
 target/mips/translate.c   | 568 +
 target/mips/vendor-tx-mmi_translate.c.inc | 573 ++
 2 files changed, 574 insertions(+), 567 deletions(-)
 create mode 100644 target/mips/vendor-tx-mmi_translate.c.inc

diff --git a/target/mips/translate.c b/target/mips/translate.c
index a4558c21d3f..e95c1e666aa 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -622,405 +622,6 @@ enum {
 OPC_NMSUB_PS= 0x3E | OPC_CP3,
 };
 
-
-/*
- * Overview of the TX79-specific instruction set
- * =
- *
- * The R5900 and the C790 have 128-bit wide GPRs, where the upper 64 bits
- * are only used by the specific quadword (128-bit) LQ/SQ load/store
- * instructions and certain multimedia instructions (MMIs). These MMIs
- * configure the 128-bit data path as two 64-bit, four 32-bit, eight 16-bit
- * or sixteen 8-bit paths.
- *
- * Arithmetic (19 instructions)
- * 
- * PADDB   rd, rs, rtParallel Add Byte
- * PSUBB   rd, rs, rtParallel Subtract Byte
- * PADDH   rd, rs, rtParallel Add Halfword
- * PSUBH   rd, rs, rtParallel Subtract Halfword
- * PADDW   rd, rs, rtParallel Add Word
- * PSUBW   rd, rs, rtParallel Subtract Word
- * PADSBH  rd, rs, rtParallel Add/Subtract Halfword
- * PADDSB  rd, rs, rtParallel Add with Signed Saturation Byte
- * PSUBSB  rd, rs, rtParallel Subtract with Signed Saturation Byte
- * PADDSH  rd, rs, rtParallel Add with Signed Saturation Halfword
- * PSUBSH  rd, rs, rtParallel Subtract with Signed Saturation Halfword
- * PADDSW  rd, rs, rtParallel Add with Signed Saturation Word
- * PSUBSW  rd, rs, rtParallel Subtract with Signed Saturation Word
- * PADDUB  rd, rs, rtParallel Add with Unsigned saturation Byte
- * PSUBUB  rd, rs, rtParallel Subtract with Unsigned saturation Byte
- * PADDUH  rd, rs, rtParallel Add with Unsigned saturation Halfword
- * PSUBUH  rd, rs, rtParallel Subtract with Unsigned saturation 
Halfword
- * PADDUW  rd, rs, rtParallel Add with Unsigned saturation Word
- * PSUBUW  rd, rs, rtParallel Subtract with Unsigned saturation Word
- *
- * Min/Max (4 instructions)
- * 
- * PMAXH   rd, rs, rtParallel Maximum Halfword
- * PMINH   rd, rs, rtParallel Minimum Halfword
- * PMAXW   rd, rs, rtParallel Maximum Word
- * PMINW   rd, rs, rtParallel Minimum Word
- *
- * Absolute (2 instructions)
- * -
- * PABSH   rd, rtParallel Absolute Halfword
- * PABSW   rd, rtParallel Absolute Word
- *
- * Logical (4 instructions)
- * 
- * PANDrd, rs, rtParallel AND
- * POR rd, rs, rtParallel OR
- * PXORrd, rs, rtParallel XOR
- * PNORrd, rs, rtParallel NOR
- *
- * Shift (9 instructions)
- * --
- * PSLLH   rd, rt, saParallel Shift Left Logical Halfword
- * PSRLH   rd, rt, saParallel Shift Right Logical Halfword
- * PSRAH   rd, rt, saParallel Shift Right Arithmetic Halfword
- * PSLLW   rd, rt, saParallel Shift Left Logical Word
- * PSRLW   rd, rt, saParallel Shift Right Logical Word
- * PSRAW   rd, rt, saParallel Shift Right Arithmetic Word
- * PSLLVW  rd, rt, rsParallel Shift Left Logical Variable Word
- * PSRLVW  rd, rt, rsParallel Shift Right Logical Variable Word
- * PSRAVW  rd, rt, rsParallel Shift Right Arithmetic Variable Word
- *
- * Compare (6 instructions)
- * 
- * PCGTB   rd, rs, rtParallel Compare for Greater Than Byte
- * PCEQB   rd, rs, rtParallel Compare for Equal Byte
- * PCGTH   rd, rs, rtParallel Compare for Greater Than Halfword
- * PCEQH   rd, rs, rtParallel Compare for Equal Halfword
- * PCGTW   rd, rs, rtParallel Compare for Greater Than Word
- * PCEQW   rd, rs, rtParallel Compare for Equal Word
- *
- * LZC (1 instruction)
- * ---
- * PLZCW   rd, rsParallel Leading Zero or One Count Word
- *
- * Quadword Load and Store (2 instructions)
- * 
- * LQ  rt, offset(base)  Load Quadword
- * SQ  rt, offset(base)  Store Quadword
- *
- * Multiply and Divide (19 instructions)
- * -
- * PMULTW  rd, rs, rtParallel Multiply Word
- * PMULTUW rd, rs, rtParallel Multiply Unsigned Word
- * PDIVW   rs, rtParallel Divide Word
- * PDIVUW  rs, rtParallel Divide Unsigned Word
- * PMADDW  rd, rs, rtParallel 

Re: [PATCH v8 0/5] hw/block/nvme: dulbe and dsm support

2020-11-23 Thread Klaus Jensen
On Nov 12 20:59, Klaus Jensen wrote:
> From: Klaus Jensen 
> 
> This adds support for the Deallocated or Unwritten Logical Block error
> recovery feature as well as the Dataset Management command.
> 
> v8:
>   - Move req->opaque clearing to nvme_req_clear.
>   - Add two preparation/cleanup patches.
> 
> v7:
>   - Handle negative return value from bdrv_block_status.
>   - bdrv_get_info may not be supported on all block drivers, so do not
> consider it a fatal error.
> 
> v6:
>   - Skip the allocation of the discards integer and just use the opaque
> value directly (Philippe)
>   - Split changes to include/block/nvme.h into a separate patch
> (Philippe)
>   - Clean up some convoluted checks on the discards value (Philippe)
>   - Use unambiguous units in the commit messages (Philippe)
>   - Stack allocate the range array (Keith)
> 
> v5:
>   - Restore status code from callback (Keith)
> 
> v4:
>   - Removed mixed declaration and code (Keith)
>   - Set NPDG and NPDA and account for the blockdev cluster size.
> 
> Klaus Jensen (5):
>   hw/block/nvme: remove superfluous NvmeCtrl parameter
>   hw/block/nvme: pull aio error handling
>   hw/block/nvme: add dulbe support
>   nvme: add namespace I/O optimization fields to shared header
>   hw/block/nvme: add the dataset management command
> 
>  hw/block/nvme-ns.h|   4 +
>  hw/block/nvme.h   |   2 +
>  include/block/nvme.h  |  12 +-
>  hw/block/nvme-ns.c|  34 +-
>  hw/block/nvme.c   | 258 --
>  hw/block/trace-events |   4 +
>  6 files changed, 276 insertions(+), 38 deletions(-)
> 
> -- 
> 2.29.2
> 

Thanks for the reviews everyone; applied to nvme-next.


signature.asc
Description: PGP signature


[PATCH v2 15/28] target/mips: Extract NEC Vr54xx helpers to vendor-vr54xx_helper.c

2020-11-23 Thread Philippe Mathieu-Daudé
Extract NEC Vr54xx helpers from op_helper.c to a new file:
'vendor-vr54xx_helper.c'.

Signed-off-by: Philippe Mathieu-Daudé 
Reviewed-by: Richard Henderson 
Message-Id: <20201120210844.2625602-14-f4...@amsat.org>
---
 target/mips/op_helper.c| 118 --
 target/mips/vendor-vr54xx_helper.c | 131 +
 target/mips/meson.build|   1 +
 3 files changed, 132 insertions(+), 118 deletions(-)
 create mode 100644 target/mips/vendor-vr54xx_helper.c

diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c
index dd09a4c714a..a900c008b5a 100644
--- a/target/mips/op_helper.c
+++ b/target/mips/op_helper.c
@@ -54,124 +54,6 @@ static void raise_exception(CPUMIPSState *env, uint32_t 
exception)
 do_raise_exception(env, exception, 0);
 }
 
-/* 64 bits arithmetic for 32 bits hosts */
-static inline uint64_t get_HILO(CPUMIPSState *env)
-{
-return ((uint64_t)(env->active_tc.HI[0]) << 32) |
-   (uint32_t)env->active_tc.LO[0];
-}
-
-static inline target_ulong set_HIT0_LO(CPUMIPSState *env, uint64_t HILO)
-{
-env->active_tc.LO[0] = (int32_t)(HILO & 0x);
-return env->active_tc.HI[0] = (int32_t)(HILO >> 32);
-}
-
-static inline target_ulong set_HI_LOT0(CPUMIPSState *env, uint64_t HILO)
-{
-target_ulong tmp = env->active_tc.LO[0] = (int32_t)(HILO & 0x);
-env->active_tc.HI[0] = (int32_t)(HILO >> 32);
-return tmp;
-}
-
-/* Multiplication variants of the vr54xx. */
-target_ulong helper_muls(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
-return set_HI_LOT0(env, 0 - ((int64_t)(int32_t)arg1 *
- (int64_t)(int32_t)arg2));
-}
-
-target_ulong helper_mulsu(CPUMIPSState *env, target_ulong arg1,
-  target_ulong arg2)
-{
-return set_HI_LOT0(env, 0 - (uint64_t)(uint32_t)arg1 *
-   (uint64_t)(uint32_t)arg2);
-}
-
-target_ulong helper_macc(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
-return set_HI_LOT0(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
-   (int64_t)(int32_t)arg2);
-}
-
-target_ulong helper_macchi(CPUMIPSState *env, target_ulong arg1,
-   target_ulong arg2)
-{
-return set_HIT0_LO(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
-   (int64_t)(int32_t)arg2);
-}
-
-target_ulong helper_maccu(CPUMIPSState *env, target_ulong arg1,
-  target_ulong arg2)
-{
-return set_HI_LOT0(env, (uint64_t)get_HILO(env) +
-   (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
-}
-
-target_ulong helper_macchiu(CPUMIPSState *env, target_ulong arg1,
-target_ulong arg2)
-{
-return set_HIT0_LO(env, (uint64_t)get_HILO(env) +
-   (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
-}
-
-target_ulong helper_msac(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2)
-{
-return set_HI_LOT0(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
-   (int64_t)(int32_t)arg2);
-}
-
-target_ulong helper_msachi(CPUMIPSState *env, target_ulong arg1,
-   target_ulong arg2)
-{
-return set_HIT0_LO(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
-   (int64_t)(int32_t)arg2);
-}
-
-target_ulong helper_msacu(CPUMIPSState *env, target_ulong arg1,
-  target_ulong arg2)
-{
-return set_HI_LOT0(env, (uint64_t)get_HILO(env) -
-   (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
-}
-
-target_ulong helper_msachiu(CPUMIPSState *env, target_ulong arg1,
-target_ulong arg2)
-{
-return set_HIT0_LO(env, (uint64_t)get_HILO(env) -
-   (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
-}
-
-target_ulong helper_mulhi(CPUMIPSState *env, target_ulong arg1,
-  target_ulong arg2)
-{
-return set_HIT0_LO(env, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
-}
-
-target_ulong helper_mulhiu(CPUMIPSState *env, target_ulong arg1,
-   target_ulong arg2)
-{
-return set_HIT0_LO(env, (uint64_t)(uint32_t)arg1 *
-   (uint64_t)(uint32_t)arg2);
-}
-
-target_ulong helper_mulshi(CPUMIPSState *env, target_ulong arg1,
-   target_ulong arg2)
-{
-return set_HIT0_LO(env, 0 - (int64_t)(int32_t)arg1 *
-   (int64_t)(int32_t)arg2);
-}
-
-target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1,
-target_ulong arg2)
-{
-return set_HIT0_LO(env, 0 - (uint64_t)(uint32_t)arg1 *
-   (uint64_t)(uint32_t)arg2);
-}
-
 static inline target_ulong bitswap(target_ulong v)
 {
 v = ((v >> 1) & (target_ulong)0xULL) |
diff --git 

[PATCH v2 20/28] target/mips: Extract Loongson SIMD translation routines

2020-11-23 Thread Philippe Mathieu-Daudé
LoongSIMD (formerly LoongMMI in Loongson 2E/F) is the
128-bit SIMD extension from the LoongISA.

Extract ~500 lines of translation routines to
'vendor-loong-simd_translate.c.inc'.

Signed-off-by: Philippe Mathieu-Daudé 
Reviewed-by: Richard Henderson 
Message-Id: <20201120210844.2625602-19-f4...@amsat.org>
---
 target/mips/translate.c   | 483 +
 target/mips/vendor-loong-simd_translate.c.inc | 492 ++
 2 files changed, 493 insertions(+), 482 deletions(-)
 create mode 100644 target/mips/vendor-loong-simd_translate.c.inc

diff --git a/target/mips/translate.c b/target/mips/translate.c
index ca2e79d955a..745bf9a9dd9 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -639,103 +639,6 @@ enum {
 OPC_BC2NEZ  = (0x0D << 21) | OPC_CP2,
 };
 
-#define MASK_LMMI(op)(MASK_OP_MAJOR(op) | (op & (0x1F << 21)) | (op & 
0x1F))
-
-enum {
-OPC_PADDSH  = (24 << 21) | (0x00) | OPC_CP2,
-OPC_PADDUSH = (25 << 21) | (0x00) | OPC_CP2,
-OPC_PADDH   = (26 << 21) | (0x00) | OPC_CP2,
-OPC_PADDW   = (27 << 21) | (0x00) | OPC_CP2,
-OPC_PADDSB  = (28 << 21) | (0x00) | OPC_CP2,
-OPC_PADDUSB = (29 << 21) | (0x00) | OPC_CP2,
-OPC_PADDB   = (30 << 21) | (0x00) | OPC_CP2,
-OPC_PADDD   = (31 << 21) | (0x00) | OPC_CP2,
-
-OPC_PSUBSH  = (24 << 21) | (0x01) | OPC_CP2,
-OPC_PSUBUSH = (25 << 21) | (0x01) | OPC_CP2,
-OPC_PSUBH   = (26 << 21) | (0x01) | OPC_CP2,
-OPC_PSUBW   = (27 << 21) | (0x01) | OPC_CP2,
-OPC_PSUBSB  = (28 << 21) | (0x01) | OPC_CP2,
-OPC_PSUBUSB = (29 << 21) | (0x01) | OPC_CP2,
-OPC_PSUBB   = (30 << 21) | (0x01) | OPC_CP2,
-OPC_PSUBD   = (31 << 21) | (0x01) | OPC_CP2,
-
-OPC_PSHUFH  = (24 << 21) | (0x02) | OPC_CP2,
-OPC_PACKSSWH= (25 << 21) | (0x02) | OPC_CP2,
-OPC_PACKSSHB= (26 << 21) | (0x02) | OPC_CP2,
-OPC_PACKUSHB= (27 << 21) | (0x02) | OPC_CP2,
-OPC_XOR_CP2 = (28 << 21) | (0x02) | OPC_CP2,
-OPC_NOR_CP2 = (29 << 21) | (0x02) | OPC_CP2,
-OPC_AND_CP2 = (30 << 21) | (0x02) | OPC_CP2,
-OPC_PANDN   = (31 << 21) | (0x02) | OPC_CP2,
-
-OPC_PUNPCKLHW   = (24 << 21) | (0x03) | OPC_CP2,
-OPC_PUNPCKHHW   = (25 << 21) | (0x03) | OPC_CP2,
-OPC_PUNPCKLBH   = (26 << 21) | (0x03) | OPC_CP2,
-OPC_PUNPCKHBH   = (27 << 21) | (0x03) | OPC_CP2,
-OPC_PINSRH_0= (28 << 21) | (0x03) | OPC_CP2,
-OPC_PINSRH_1= (29 << 21) | (0x03) | OPC_CP2,
-OPC_PINSRH_2= (30 << 21) | (0x03) | OPC_CP2,
-OPC_PINSRH_3= (31 << 21) | (0x03) | OPC_CP2,
-
-OPC_PAVGH   = (24 << 21) | (0x08) | OPC_CP2,
-OPC_PAVGB   = (25 << 21) | (0x08) | OPC_CP2,
-OPC_PMAXSH  = (26 << 21) | (0x08) | OPC_CP2,
-OPC_PMINSH  = (27 << 21) | (0x08) | OPC_CP2,
-OPC_PMAXUB  = (28 << 21) | (0x08) | OPC_CP2,
-OPC_PMINUB  = (29 << 21) | (0x08) | OPC_CP2,
-
-OPC_PCMPEQW = (24 << 21) | (0x09) | OPC_CP2,
-OPC_PCMPGTW = (25 << 21) | (0x09) | OPC_CP2,
-OPC_PCMPEQH = (26 << 21) | (0x09) | OPC_CP2,
-OPC_PCMPGTH = (27 << 21) | (0x09) | OPC_CP2,
-OPC_PCMPEQB = (28 << 21) | (0x09) | OPC_CP2,
-OPC_PCMPGTB = (29 << 21) | (0x09) | OPC_CP2,
-
-OPC_PSLLW   = (24 << 21) | (0x0A) | OPC_CP2,
-OPC_PSLLH   = (25 << 21) | (0x0A) | OPC_CP2,
-OPC_PMULLH  = (26 << 21) | (0x0A) | OPC_CP2,
-OPC_PMULHH  = (27 << 21) | (0x0A) | OPC_CP2,
-OPC_PMULUW  = (28 << 21) | (0x0A) | OPC_CP2,
-OPC_PMULHUH = (29 << 21) | (0x0A) | OPC_CP2,
-
-OPC_PSRLW   = (24 << 21) | (0x0B) | OPC_CP2,
-OPC_PSRLH   = (25 << 21) | (0x0B) | OPC_CP2,
-OPC_PSRAW   = (26 << 21) | (0x0B) | OPC_CP2,
-OPC_PSRAH   = (27 << 21) | (0x0B) | OPC_CP2,
-OPC_PUNPCKLWD   = (28 << 21) | (0x0B) | OPC_CP2,
-OPC_PUNPCKHWD   = (29 << 21) | (0x0B) | OPC_CP2,
-
-OPC_ADDU_CP2= (24 << 21) | (0x0C) | OPC_CP2,
-OPC_OR_CP2  = (25 << 21) | (0x0C) | OPC_CP2,
-OPC_ADD_CP2 = (26 << 21) | (0x0C) | OPC_CP2,
-OPC_DADD_CP2= (27 << 21) | (0x0C) | OPC_CP2,
-OPC_SEQU_CP2= (28 << 21) | (0x0C) | OPC_CP2,
-OPC_SEQ_CP2 = (29 << 21) | (0x0C) | OPC_CP2,
-
-OPC_SUBU_CP2= (24 << 21) | (0x0D) | OPC_CP2,
-OPC_PASUBUB = (25 << 21) | (0x0D) | OPC_CP2,
-OPC_SUB_CP2 = (26 << 21) | (0x0D) | OPC_CP2,
-OPC_DSUB_CP2= (27 << 21) | (0x0D) | OPC_CP2,
-OPC_SLTU_CP2= (28 << 21) | (0x0D) | OPC_CP2,
-OPC_SLT_CP2 = (29 << 21) | (0x0D) | OPC_CP2,
-
-OPC_SLL_CP2 = (24 << 21) | (0x0E) | OPC_CP2,
-OPC_DSLL_CP2= (25 << 21) | (0x0E) | OPC_CP2,
-OPC_PEXTRH  = (26 << 21) | (0x0E) | OPC_CP2,
-OPC_PMADDHW = (27 << 21) | (0x0E) | OPC_CP2,
-OPC_SLEU_CP2= (28 << 21) | (0x0E) | OPC_CP2,
-OPC_SLE_CP2 = (29 << 21) | (0x0E) | OPC_CP2,
-
-OPC_SRL_CP2 = (24 << 21) | (0x0F) | OPC_CP2,
-OPC_DSRL_CP2  

[PATCH v2 08/28] target/mips: Extract DSP helper definitions

2020-11-23 Thread Philippe Mathieu-Daudé
'MIPS DSP' is defined as a Module by MIPS. Extract the helper
definitions to 'mod-dsp_helper.h.inc'.

Signed-off-by: Philippe Mathieu-Daudé 
Reviewed-by: Richard Henderson 
Message-Id: <20201120210844.2625602-7-f4...@amsat.org>
---
 target/mips/helper.h | 335 +-
 target/mips/mod-dsp_helper.h.inc | 344 +++
 2 files changed, 345 insertions(+), 334 deletions(-)
 create mode 100644 target/mips/mod-dsp_helper.h.inc

diff --git a/target/mips/helper.h b/target/mips/helper.h
index 80eb675fa64..82f40c3b9bc 100644
--- a/target/mips/helper.h
+++ b/target/mips/helper.h
@@ -447,340 +447,7 @@ DEF_HELPER_FLAGS_2(pasubub, TCG_CALL_NO_RWG_SE, i64, i64, 
i64)
 DEF_HELPER_FLAGS_1(biadd, TCG_CALL_NO_RWG_SE, i64, i64)
 DEF_HELPER_FLAGS_1(pmovmskb, TCG_CALL_NO_RWG_SE, i64, i64)
 
-/*** MIPS DSP ***/
-/* DSP Arithmetic Sub-class insns */
-DEF_HELPER_FLAGS_3(addq_ph, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_3(addq_s_ph, 0, tl, tl, tl, env)
-#if defined(TARGET_MIPS64)
-DEF_HELPER_FLAGS_3(addq_qh, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_3(addq_s_qh, 0, tl, tl, tl, env)
-#endif
-DEF_HELPER_FLAGS_3(addq_s_w, 0, tl, tl, tl, env)
-#if defined(TARGET_MIPS64)
-DEF_HELPER_FLAGS_3(addq_pw, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_3(addq_s_pw, 0, tl, tl, tl, env)
-#endif
-DEF_HELPER_FLAGS_3(addu_qb, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_3(addu_s_qb, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_2(adduh_qb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_2(adduh_r_qb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_3(addu_ph, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_3(addu_s_ph, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_2(addqh_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_2(addqh_r_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_2(addqh_w, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_2(addqh_r_w, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-#if defined(TARGET_MIPS64)
-DEF_HELPER_FLAGS_3(addu_ob, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_3(addu_s_ob, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_2(adduh_ob, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_2(adduh_r_ob, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_3(addu_qh, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_3(addu_s_qh, 0, tl, tl, tl, env)
-#endif
-DEF_HELPER_FLAGS_3(subq_ph, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_3(subq_s_ph, 0, tl, tl, tl, env)
-#if defined(TARGET_MIPS64)
-DEF_HELPER_FLAGS_3(subq_qh, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_3(subq_s_qh, 0, tl, tl, tl, env)
-#endif
-DEF_HELPER_FLAGS_3(subq_s_w, 0, tl, tl, tl, env)
-#if defined(TARGET_MIPS64)
-DEF_HELPER_FLAGS_3(subq_pw, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_3(subq_s_pw, 0, tl, tl, tl, env)
-#endif
-DEF_HELPER_FLAGS_3(subu_qb, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_3(subu_s_qb, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_2(subuh_qb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_2(subuh_r_qb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_3(subu_ph, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_3(subu_s_ph, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_2(subqh_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_2(subqh_r_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_2(subqh_w, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_2(subqh_r_w, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-#if defined(TARGET_MIPS64)
-DEF_HELPER_FLAGS_3(subu_ob, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_3(subu_s_ob, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_2(subuh_ob, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_2(subuh_r_ob, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_3(subu_qh, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_3(subu_s_qh, 0, tl, tl, tl, env)
-#endif
-DEF_HELPER_FLAGS_3(addsc, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_3(addwc, 0, tl, tl, tl, env)
-DEF_HELPER_FLAGS_2(modsub, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_1(raddu_w_qb, TCG_CALL_NO_RWG_SE, tl, tl)
-#if defined(TARGET_MIPS64)
-DEF_HELPER_FLAGS_1(raddu_l_ob, TCG_CALL_NO_RWG_SE, tl, tl)
-#endif
-DEF_HELPER_FLAGS_2(absq_s_qb, 0, tl, tl, env)
-DEF_HELPER_FLAGS_2(absq_s_ph, 0, tl, tl, env)
-DEF_HELPER_FLAGS_2(absq_s_w, 0, tl, tl, env)
-#if defined(TARGET_MIPS64)
-DEF_HELPER_FLAGS_2(absq_s_ob, 0, tl, tl, env)
-DEF_HELPER_FLAGS_2(absq_s_qh, 0, tl, tl, env)
-DEF_HELPER_FLAGS_2(absq_s_pw, 0, tl, tl, env)
-#endif
-DEF_HELPER_FLAGS_2(precr_qb_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_2(precrq_qb_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_3(precr_sra_ph_w, TCG_CALL_NO_RWG_SE,
-   tl, i32, tl, tl)
-DEF_HELPER_FLAGS_3(precr_sra_r_ph_w, TCG_CALL_NO_RWG_SE,
-   tl, i32, tl, tl)
-DEF_HELPER_FLAGS_2(precrq_ph_w, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_3(precrq_rs_ph_w, 0, tl, tl, tl, env)
-#if defined(TARGET_MIPS64)
-DEF_HELPER_FLAGS_2(precr_ob_qh, TCG_CALL_NO_RWG_SE, tl, tl, tl)
-DEF_HELPER_FLAGS_3(precr_sra_qh_pw,
-   TCG_CALL_NO_RWG_SE, tl, tl, tl, i32)
-DEF_HELPER_FLAGS_3(precr_sra_r_qh_pw,
-   TCG_CALL_NO_RWG_SE, tl, tl, tl, i32)
-DEF_HELPER_FLAGS_2(precrq_ob_qh, 

[PATCH v2 16/28] target/mips: Extract NEC Vr54xx helper definitions

2020-11-23 Thread Philippe Mathieu-Daudé
Extract the NEC Vr54xx helper definitions to
'vendor-vr54xx_helper.h'.

Signed-off-by: Philippe Mathieu-Daudé 
Reviewed-by: Richard Henderson 
Message-Id: <20201120210844.2625602-15-f4...@amsat.org>
---
 target/mips/helper.h   | 17 ++---
 target/mips/vendor-vr54xx_helper.h.inc | 24 
 2 files changed, 26 insertions(+), 15 deletions(-)
 create mode 100644 target/mips/vendor-vr54xx_helper.h.inc

diff --git a/target/mips/helper.h b/target/mips/helper.h
index 06da4c6cf68..58c716a1480 100644
--- a/target/mips/helper.h
+++ b/target/mips/helper.h
@@ -20,21 +20,6 @@ DEF_HELPER_3(lld, tl, env, tl, int)
 #endif
 #endif
 
-DEF_HELPER_3(muls, tl, env, tl, tl)
-DEF_HELPER_3(mulsu, tl, env, tl, tl)
-DEF_HELPER_3(macc, tl, env, tl, tl)
-DEF_HELPER_3(maccu, tl, env, tl, tl)
-DEF_HELPER_3(msac, tl, env, tl, tl)
-DEF_HELPER_3(msacu, tl, env, tl, tl)
-DEF_HELPER_3(mulhi, tl, env, tl, tl)
-DEF_HELPER_3(mulhiu, tl, env, tl, tl)
-DEF_HELPER_3(mulshi, tl, env, tl, tl)
-DEF_HELPER_3(mulshiu, tl, env, tl, tl)
-DEF_HELPER_3(macchi, tl, env, tl, tl)
-DEF_HELPER_3(macchiu, tl, env, tl, tl)
-DEF_HELPER_3(msachi, tl, env, tl, tl)
-DEF_HELPER_3(msachiu, tl, env, tl, tl)
-
 DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl)
 #ifdef TARGET_MIPS64
 DEF_HELPER_FLAGS_1(dbitswap, TCG_CALL_NO_RWG_SE, tl, tl)
@@ -424,3 +409,5 @@ DEF_HELPER_3(cache, void, env, tl, i32)
 #include "mod-dsp_helper.h.inc"
 #include "mod-msa_helper.h.inc"
 #include "mod-mt_helper.h.inc"
+
+#include "vendor-vr54xx_helper.h.inc"
diff --git a/target/mips/vendor-vr54xx_helper.h.inc 
b/target/mips/vendor-vr54xx_helper.h.inc
new file mode 100644
index 000..50b1f5b818d
--- /dev/null
+++ b/target/mips/vendor-vr54xx_helper.h.inc
@@ -0,0 +1,24 @@
+/*
+ * MIPS NEC Vr54xx instruction emulation helpers for QEMU.
+ *
+ *  Copyright (c) 2004-2005 Jocelyn Mayer
+ *  Copyright (c) 2006 Marius Groeger (FPU operations)
+ *  Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support)
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+DEF_HELPER_3(muls, tl, env, tl, tl)
+DEF_HELPER_3(mulsu, tl, env, tl, tl)
+DEF_HELPER_3(macc, tl, env, tl, tl)
+DEF_HELPER_3(maccu, tl, env, tl, tl)
+DEF_HELPER_3(msac, tl, env, tl, tl)
+DEF_HELPER_3(msacu, tl, env, tl, tl)
+DEF_HELPER_3(mulhi, tl, env, tl, tl)
+DEF_HELPER_3(mulhiu, tl, env, tl, tl)
+DEF_HELPER_3(mulshi, tl, env, tl, tl)
+DEF_HELPER_3(mulshiu, tl, env, tl, tl)
+DEF_HELPER_3(macchi, tl, env, tl, tl)
+DEF_HELPER_3(macchiu, tl, env, tl, tl)
+DEF_HELPER_3(msachi, tl, env, tl, tl)
+DEF_HELPER_3(msachiu, tl, env, tl, tl)
-- 
2.26.2




[PATCH v2 01/28] target/mips: Use FloatRoundMode enum for FCR31 modes conversion

2020-11-23 Thread Philippe Mathieu-Daudé
Use the FloatRoundMode enum type introduced in commit 3dede407cc6
("softfloat: Name rounding mode enum") instead of 'unsigned int'.

Suggested-by: Richard Henderson 
Signed-off-by: Philippe Mathieu-Daudé 
---
 target/mips/internal.h   | 3 ++-
 target/mips/fpu_helper.c | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/target/mips/internal.h b/target/mips/internal.h
index dd8a7809b64..bbd10e9d45f 100644
--- a/target/mips/internal.h
+++ b/target/mips/internal.h
@@ -225,7 +225,8 @@ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int 
size,
 uint32_t float_class_s(uint32_t arg, float_status *fst);
 uint64_t float_class_d(uint64_t arg, float_status *fst);
 
-extern unsigned int ieee_rm[];
+extern const FloatRoundMode ieee_rm[4];
+
 void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask);
 
 static inline void restore_rounding_mode(CPUMIPSState *env)
diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c
index 020b768e87b..501bd401a16 100644
--- a/target/mips/fpu_helper.c
+++ b/target/mips/fpu_helper.c
@@ -42,7 +42,7 @@
 #define FP_TO_INT64_OVERFLOW 0x7fffULL
 
 /* convert MIPS rounding mode in FCR31 to IEEE library */
-unsigned int ieee_rm[] = {
+const FloatRoundMode ieee_rm[4] = {
 float_round_nearest_even,
 float_round_to_zero,
 float_round_up,
-- 
2.26.2




[PATCH v2 10/28] target/mips: Extract Multi-Threading helper definitions

2020-11-23 Thread Philippe Mathieu-Daudé
'MIPS MT' is defined as a Module by MIPS. Extract the helper
definitions to 'mod-mt_helper.h.inc'.

Signed-off-by: Philippe Mathieu-Daudé 
Reviewed-by: Richard Henderson 
Message-Id: <20201120210844.2625602-9-f4...@amsat.org>
---
 target/mips/helper.h| 23 +
 target/mips/mod-mt_helper.h.inc | 36 +
 2 files changed, 37 insertions(+), 22 deletions(-)
 create mode 100644 target/mips/mod-mt_helper.h.inc

diff --git a/target/mips/helper.h b/target/mips/helper.h
index 82f40c3b9bc..18366bc0345 100644
--- a/target/mips/helper.h
+++ b/target/mips/helper.h
@@ -179,25 +179,6 @@ DEF_HELPER_2(dmtc0_entrylo0, void, env, i64)
 DEF_HELPER_2(dmtc0_entrylo1, void, env, i64)
 #endif
 
-/* MIPS MT functions */
-DEF_HELPER_2(mftgpr, tl, env, i32)
-DEF_HELPER_2(mftlo, tl, env, i32)
-DEF_HELPER_2(mfthi, tl, env, i32)
-DEF_HELPER_2(mftacx, tl, env, i32)
-DEF_HELPER_1(mftdsp, tl, env)
-DEF_HELPER_3(mttgpr, void, env, tl, i32)
-DEF_HELPER_3(mttlo, void, env, tl, i32)
-DEF_HELPER_3(mtthi, void, env, tl, i32)
-DEF_HELPER_3(mttacx, void, env, tl, i32)
-DEF_HELPER_2(mttdsp, void, env, tl)
-DEF_HELPER_0(dmt, tl)
-DEF_HELPER_0(emt, tl)
-DEF_HELPER_1(dvpe, tl, env)
-DEF_HELPER_1(evpe, tl, env)
-
-/* R6 Multi-threading */
-DEF_HELPER_1(dvp, tl, env)
-DEF_HELPER_1(evp, tl, env)
 #endif /* !CONFIG_USER_ONLY */
 
 /* microMIPS functions */
@@ -208,9 +189,6 @@ DEF_HELPER_4(ldm, void, env, tl, tl, i32)
 DEF_HELPER_4(sdm, void, env, tl, tl, i32)
 #endif
 
-DEF_HELPER_2(fork, void, tl, tl)
-DEF_HELPER_2(yield, tl, env, tl)
-
 /* CP1 functions */
 DEF_HELPER_2(cfc1, tl, env, i32)
 DEF_HELPER_4(ctc1, void, env, tl, i32, i32)
@@ -451,3 +429,4 @@ DEF_HELPER_3(cache, void, env, tl, i32)
 
 #include "mod-dsp_helper.h.inc"
 #include "mod-msa_helper.h.inc"
+#include "mod-mt_helper.h.inc"
diff --git a/target/mips/mod-mt_helper.h.inc b/target/mips/mod-mt_helper.h.inc
new file mode 100644
index 000..0db58e2a780
--- /dev/null
+++ b/target/mips/mod-mt_helper.h.inc
@@ -0,0 +1,36 @@
+/*
+ * MIPS Multi-Threading helpers for QEMU.
+ *
+ *  Copyright (c) 2004-2005 Jocelyn Mayer
+ *  Copyright (c) 2006 Marius Groeger (FPU operations)
+ *  Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support)
+ *  Copyright (c) 2009 CodeSourcery (MIPS16 and microMIPS support)
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_2(mftgpr, tl, env, i32)
+DEF_HELPER_2(mftlo, tl, env, i32)
+DEF_HELPER_2(mfthi, tl, env, i32)
+DEF_HELPER_2(mftacx, tl, env, i32)
+DEF_HELPER_1(mftdsp, tl, env)
+DEF_HELPER_3(mttgpr, void, env, tl, i32)
+DEF_HELPER_3(mttlo, void, env, tl, i32)
+DEF_HELPER_3(mtthi, void, env, tl, i32)
+DEF_HELPER_3(mttacx, void, env, tl, i32)
+DEF_HELPER_2(mttdsp, void, env, tl)
+
+DEF_HELPER_0(dmt, tl)
+DEF_HELPER_0(emt, tl)
+
+DEF_HELPER_1(dvpe, tl, env)
+DEF_HELPER_1(evpe, tl, env)
+
+/* R6 Multi-threading */
+DEF_HELPER_1(dvp, tl, env)
+DEF_HELPER_1(evp, tl, env)
+#endif /* !CONFIG_USER_ONLY */
+
+DEF_HELPER_2(fork, void, tl, tl)
+DEF_HELPER_2(yield, tl, env, tl)
-- 
2.26.2




[PATCH v2 07/28] target/mips: Rename dsp_helper.c as mod-dsp_helper.c

2020-11-23 Thread Philippe Mathieu-Daudé
'MIPS DSP' is defined as a Module by MIPS, rename it as
mod-dsp_helper.c.

Reviewed-by: Richard Henderson 
Signed-off-by: Philippe Mathieu-Daudé 
Message-Id: <20201120210844.2625602-6-f4...@amsat.org>
---
 target/mips/{dsp_helper.c => mod-dsp_helper.c} | 2 ++
 target/mips/meson.build| 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)
 rename target/mips/{dsp_helper.c => mod-dsp_helper.c} (99%)

diff --git a/target/mips/dsp_helper.c b/target/mips/mod-dsp_helper.c
similarity index 99%
rename from target/mips/dsp_helper.c
rename to target/mips/mod-dsp_helper.c
index 09b6e5fb15a..10a965bd20d 100644
--- a/target/mips/dsp_helper.c
+++ b/target/mips/mod-dsp_helper.c
@@ -15,6 +15,8 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, see .
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
  */
 
 #include "qemu/osdep.h"
diff --git a/target/mips/meson.build b/target/mips/meson.build
index 35dbbbf6519..aa6ac67df76 100644
--- a/target/mips/meson.build
+++ b/target/mips/meson.build
@@ -1,12 +1,12 @@
 mips_ss = ss.source_set()
 mips_ss.add(files(
   'cpu.c',
-  'dsp_helper.c',
   'fpu_helper.c',
   'gdbstub.c',
   'helper.c',
   'lmmi_helper.c',
   'op_helper.c',
+  'mod-dsp_helper.c',
   'mod-msa_helper.c',
 
   'translate.c',
-- 
2.26.2




[PATCH v2 17/28] target/mips: Extract NEC Vr54xx translation routines

2020-11-23 Thread Philippe Mathieu-Daudé
Extract the NEC Vr54xx translation routines to
'vendor-vr54xx_translate.c.inc'.

Signed-off-by: Philippe Mathieu-Daudé 
Reviewed-by: Richard Henderson 
Message-Id: <20201120210844.2625602-16-f4...@amsat.org>
---
 target/mips/translate.c   | 86 +
 target/mips/vendor-vr54xx_translate.c.inc | 93 +++
 2 files changed, 95 insertions(+), 84 deletions(-)
 create mode 100644 target/mips/vendor-vr54xx_translate.c.inc

diff --git a/target/mips/translate.c b/target/mips/translate.c
index d6133bd7de7..ca2e79d955a 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -295,26 +295,6 @@ enum {
 OPC_DLSA = 0x15 | OPC_SPECIAL,
 };
 
-/* Multiplication variants of the vr54xx. */
-#define MASK_MUL_VR54XX(op) (MASK_SPECIAL(op) | (op & (0x1F << 6)))
-
-enum {
-OPC_VR54XX_MULS= (0x03 << 6) | OPC_MULT,
-OPC_VR54XX_MULSU   = (0x03 << 6) | OPC_MULTU,
-OPC_VR54XX_MACC= (0x05 << 6) | OPC_MULT,
-OPC_VR54XX_MACCU   = (0x05 << 6) | OPC_MULTU,
-OPC_VR54XX_MSAC= (0x07 << 6) | OPC_MULT,
-OPC_VR54XX_MSACU   = (0x07 << 6) | OPC_MULTU,
-OPC_VR54XX_MULHI   = (0x09 << 6) | OPC_MULT,
-OPC_VR54XX_MULHIU  = (0x09 << 6) | OPC_MULTU,
-OPC_VR54XX_MULSHI  = (0x0B << 6) | OPC_MULT,
-OPC_VR54XX_MULSHIU = (0x0B << 6) | OPC_MULTU,
-OPC_VR54XX_MACCHI  = (0x0D << 6) | OPC_MULT,
-OPC_VR54XX_MACCHIU = (0x0D << 6) | OPC_MULTU,
-OPC_VR54XX_MSACHI  = (0x0F << 6) | OPC_MULT,
-OPC_VR54XX_MSACHIU = (0x0F << 6) | OPC_MULTU,
-};
-
 /* REGIMM (rt field) opcodes */
 #define MASK_REGIMM(op) (MASK_OP_MAJOR(op) | (op & (0x1F << 16)))
 
@@ -4546,70 +4526,6 @@ static void gen_mul_txx9(DisasContext *ctx, uint32_t opc,
 tcg_temp_free(t1);
 }
 
-static void gen_mul_vr54xx(DisasContext *ctx, uint32_t opc,
-   int rd, int rs, int rt)
-{
-TCGv t0 = tcg_temp_new();
-TCGv t1 = tcg_temp_new();
-
-gen_load_gpr(t0, rs);
-gen_load_gpr(t1, rt);
-
-switch (opc) {
-case OPC_VR54XX_MULS:
-gen_helper_muls(t0, cpu_env, t0, t1);
-break;
-case OPC_VR54XX_MULSU:
-gen_helper_mulsu(t0, cpu_env, t0, t1);
-break;
-case OPC_VR54XX_MACC:
-gen_helper_macc(t0, cpu_env, t0, t1);
-break;
-case OPC_VR54XX_MACCU:
-gen_helper_maccu(t0, cpu_env, t0, t1);
-break;
-case OPC_VR54XX_MSAC:
-gen_helper_msac(t0, cpu_env, t0, t1);
-break;
-case OPC_VR54XX_MSACU:
-gen_helper_msacu(t0, cpu_env, t0, t1);
-break;
-case OPC_VR54XX_MULHI:
-gen_helper_mulhi(t0, cpu_env, t0, t1);
-break;
-case OPC_VR54XX_MULHIU:
-gen_helper_mulhiu(t0, cpu_env, t0, t1);
-break;
-case OPC_VR54XX_MULSHI:
-gen_helper_mulshi(t0, cpu_env, t0, t1);
-break;
-case OPC_VR54XX_MULSHIU:
-gen_helper_mulshiu(t0, cpu_env, t0, t1);
-break;
-case OPC_VR54XX_MACCHI:
-gen_helper_macchi(t0, cpu_env, t0, t1);
-break;
-case OPC_VR54XX_MACCHIU:
-gen_helper_macchiu(t0, cpu_env, t0, t1);
-break;
-case OPC_VR54XX_MSACHI:
-gen_helper_msachi(t0, cpu_env, t0, t1);
-break;
-case OPC_VR54XX_MSACHIU:
-gen_helper_msachiu(t0, cpu_env, t0, t1);
-break;
-default:
-MIPS_INVAL("mul vr54xx");
-generate_exception_end(ctx, EXCP_RI);
-goto out;
-}
-gen_store_gpr(t0, rd);
-
- out:
-tcg_temp_free(t0);
-tcg_temp_free(t1);
-}
-
 static void gen_cl(DisasContext *ctx, uint32_t opc,
int rd, int rs)
 {
@@ -13022,6 +12938,8 @@ out:
 
 #include "mod-dsp_translate.c.inc"
 
+#include "vendor-vr54xx_translate.c.inc"
+
 static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
 {
 int rs, rt, rd, sa;
diff --git a/target/mips/vendor-vr54xx_translate.c.inc 
b/target/mips/vendor-vr54xx_translate.c.inc
new file mode 100644
index 000..8c952a98ebc
--- /dev/null
+++ b/target/mips/vendor-vr54xx_translate.c.inc
@@ -0,0 +1,93 @@
+/*
+ *  MIPS NEC Vr54xx translation routines.
+ *
+ *  Copyright (c) 2004-2005 Jocelyn Mayer
+ *  Copyright (c) 2006 Marius Groeger (FPU operations)
+ *  Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support)
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+/* Multiplication variants of the vr54xx. */
+#define MASK_MUL_VR54XX(op) (MASK_SPECIAL(op) | (op & (0x1F << 6)))
+
+enum {
+OPC_VR54XX_MULS= (0x03 << 6) | OPC_MULT,
+OPC_VR54XX_MULSU   = (0x03 << 6) | OPC_MULTU,
+OPC_VR54XX_MACC= (0x05 << 6) | OPC_MULT,
+OPC_VR54XX_MACCU   = (0x05 << 6) | OPC_MULTU,
+OPC_VR54XX_MSAC= (0x07 << 6) | OPC_MULT,
+OPC_VR54XX_MSACU   = (0x07 << 6) | OPC_MULTU,
+OPC_VR54XX_MULHI   = (0x09 << 6) | OPC_MULT,
+OPC_VR54XX_MULHIU  = (0x09 << 6) | OPC_MULTU,
+OPC_VR54XX_MULSHI  = (0x0B << 6) | OPC_MULT,
+OPC_VR54XX_MULSHIU = (0x0B << 6) | OPC_MULTU,
+

[PATCH v2 04/28] target/mips: Extract MSA helpers from op_helper.c

2020-11-23 Thread Philippe Mathieu-Daudé
We have ~400 lines of MSA helpers in the generic op_helper.c,
move them with the other helpers in 'mod-msa_helper.c'.

Signed-off-by: Philippe Mathieu-Daudé 
---
 target/mips/mod-msa_helper.c | 392 ++
 target/mips/op_helper.c  | 393 ---
 2 files changed, 392 insertions(+), 393 deletions(-)

diff --git a/target/mips/mod-msa_helper.c b/target/mips/mod-msa_helper.c
index b89b4c44902..56fca86a242 100644
--- a/target/mips/mod-msa_helper.c
+++ b/target/mips/mod-msa_helper.c
@@ -8201,3 +8201,395 @@ void helper_msa_ffint_u_df(CPUMIPSState *env, uint32_t 
df, uint32_t wd,
 
 msa_move_v(pwd, pwx);
 }
+
+/* Data format min and max values */
+#define DF_BITS(df) (1 << ((df) + 3))
+
+/* Element-by-element access macros */
+#define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df))
+
+#if !defined(CONFIG_USER_ONLY)
+#define MEMOP_IDX(DF)   \
+TCGMemOpIdx oi = make_memop_idx(MO_TE | DF | MO_UNALN,  \
+cpu_mmu_index(env, false));
+#else
+#define MEMOP_IDX(DF)
+#endif
+
+void helper_msa_ld_b(CPUMIPSState *env, uint32_t wd,
+ target_ulong addr)
+{
+wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+MEMOP_IDX(DF_BYTE)
+#if !defined(CONFIG_USER_ONLY)
+#if !defined(HOST_WORDS_BIGENDIAN)
+pwd->b[0]  = helper_ret_ldub_mmu(env, addr + (0  << DF_BYTE), oi, GETPC());
+pwd->b[1]  = helper_ret_ldub_mmu(env, addr + (1  << DF_BYTE), oi, GETPC());
+pwd->b[2]  = helper_ret_ldub_mmu(env, addr + (2  << DF_BYTE), oi, GETPC());
+pwd->b[3]  = helper_ret_ldub_mmu(env, addr + (3  << DF_BYTE), oi, GETPC());
+pwd->b[4]  = helper_ret_ldub_mmu(env, addr + (4  << DF_BYTE), oi, GETPC());
+pwd->b[5]  = helper_ret_ldub_mmu(env, addr + (5  << DF_BYTE), oi, GETPC());
+pwd->b[6]  = helper_ret_ldub_mmu(env, addr + (6  << DF_BYTE), oi, GETPC());
+pwd->b[7]  = helper_ret_ldub_mmu(env, addr + (7  << DF_BYTE), oi, GETPC());
+pwd->b[8]  = helper_ret_ldub_mmu(env, addr + (8  << DF_BYTE), oi, GETPC());
+pwd->b[9]  = helper_ret_ldub_mmu(env, addr + (9  << DF_BYTE), oi, GETPC());
+pwd->b[10] = helper_ret_ldub_mmu(env, addr + (10 << DF_BYTE), oi, GETPC());
+pwd->b[11] = helper_ret_ldub_mmu(env, addr + (11 << DF_BYTE), oi, GETPC());
+pwd->b[12] = helper_ret_ldub_mmu(env, addr + (12 << DF_BYTE), oi, GETPC());
+pwd->b[13] = helper_ret_ldub_mmu(env, addr + (13 << DF_BYTE), oi, GETPC());
+pwd->b[14] = helper_ret_ldub_mmu(env, addr + (14 << DF_BYTE), oi, GETPC());
+pwd->b[15] = helper_ret_ldub_mmu(env, addr + (15 << DF_BYTE), oi, GETPC());
+#else
+pwd->b[0]  = helper_ret_ldub_mmu(env, addr + (7  << DF_BYTE), oi, GETPC());
+pwd->b[1]  = helper_ret_ldub_mmu(env, addr + (6  << DF_BYTE), oi, GETPC());
+pwd->b[2]  = helper_ret_ldub_mmu(env, addr + (5  << DF_BYTE), oi, GETPC());
+pwd->b[3]  = helper_ret_ldub_mmu(env, addr + (4  << DF_BYTE), oi, GETPC());
+pwd->b[4]  = helper_ret_ldub_mmu(env, addr + (3  << DF_BYTE), oi, GETPC());
+pwd->b[5]  = helper_ret_ldub_mmu(env, addr + (2  << DF_BYTE), oi, GETPC());
+pwd->b[6]  = helper_ret_ldub_mmu(env, addr + (1  << DF_BYTE), oi, GETPC());
+pwd->b[7]  = helper_ret_ldub_mmu(env, addr + (0  << DF_BYTE), oi, GETPC());
+pwd->b[8]  = helper_ret_ldub_mmu(env, addr + (15 << DF_BYTE), oi, GETPC());
+pwd->b[9]  = helper_ret_ldub_mmu(env, addr + (14 << DF_BYTE), oi, GETPC());
+pwd->b[10] = helper_ret_ldub_mmu(env, addr + (13 << DF_BYTE), oi, GETPC());
+pwd->b[11] = helper_ret_ldub_mmu(env, addr + (12 << DF_BYTE), oi, GETPC());
+pwd->b[12] = helper_ret_ldub_mmu(env, addr + (11 << DF_BYTE), oi, GETPC());
+pwd->b[13] = helper_ret_ldub_mmu(env, addr + (10 << DF_BYTE), oi, GETPC());
+pwd->b[14] = helper_ret_ldub_mmu(env, addr + (9  << DF_BYTE), oi, GETPC());
+pwd->b[15] = helper_ret_ldub_mmu(env, addr + (8  << DF_BYTE), oi, GETPC());
+#endif
+#else
+#if !defined(HOST_WORDS_BIGENDIAN)
+pwd->b[0]  = cpu_ldub_data(env, addr + (0  << DF_BYTE));
+pwd->b[1]  = cpu_ldub_data(env, addr + (1  << DF_BYTE));
+pwd->b[2]  = cpu_ldub_data(env, addr + (2  << DF_BYTE));
+pwd->b[3]  = cpu_ldub_data(env, addr + (3  << DF_BYTE));
+pwd->b[4]  = cpu_ldub_data(env, addr + (4  << DF_BYTE));
+pwd->b[5]  = cpu_ldub_data(env, addr + (5  << DF_BYTE));
+pwd->b[6]  = cpu_ldub_data(env, addr + (6  << DF_BYTE));
+pwd->b[7]  = cpu_ldub_data(env, addr + (7  << DF_BYTE));
+pwd->b[8]  = cpu_ldub_data(env, addr + (8  << DF_BYTE));
+pwd->b[9]  = cpu_ldub_data(env, addr + (9  << DF_BYTE));
+pwd->b[10] = cpu_ldub_data(env, addr + (10 << DF_BYTE));
+pwd->b[11] = cpu_ldub_data(env, addr + (11 << DF_BYTE));
+pwd->b[12] = cpu_ldub_data(env, addr + (12 << DF_BYTE));
+pwd->b[13] = cpu_ldub_data(env, addr + (13 << DF_BYTE));
+pwd->b[14] = cpu_ldub_data(env, addr + (14 << DF_BYTE));
+pwd->b[15] = cpu_ldub_data(env, addr + (15 << DF_BYTE));

[PATCH v2 03/28] target/mips: Rename msa_helper.c as mod-msa_helper.c

2020-11-23 Thread Philippe Mathieu-Daudé
MSA means 'MIPS SIMD Architecture' and is defined as a Module by
MIPS.
To keep the directory sorted, we use the 'mod' prefix for MIPS
modules. Rename msa_helper.c as mod-msa_helper.c.

Signed-off-by: Philippe Mathieu-Daudé 
---
 target/mips/{msa_helper.c => mod-msa_helper.c} | 0
 target/mips/meson.build| 3 ++-
 2 files changed, 2 insertions(+), 1 deletion(-)
 rename target/mips/{msa_helper.c => mod-msa_helper.c} (100%)

diff --git a/target/mips/msa_helper.c b/target/mips/mod-msa_helper.c
similarity index 100%
rename from target/mips/msa_helper.c
rename to target/mips/mod-msa_helper.c
diff --git a/target/mips/meson.build b/target/mips/meson.build
index 681a5524c0e..35dbbbf6519 100644
--- a/target/mips/meson.build
+++ b/target/mips/meson.build
@@ -6,8 +6,9 @@
   'gdbstub.c',
   'helper.c',
   'lmmi_helper.c',
-  'msa_helper.c',
   'op_helper.c',
+  'mod-msa_helper.c',
+
   'translate.c',
 ))
 mips_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'))
-- 
2.26.2




[PATCH v2 06/28] target/mips: Extract MSA translation routines

2020-11-23 Thread Philippe Mathieu-Daudé
Extract 2200 lines from the huge translate.c to a new file,
'mod-msa_translate.c.inc'. As there are too many inter-dependencies
we don't compile it as another object, but keep including it in the
big translate.o. We gain in code maintainability.

Signed-off-by: Philippe Mathieu-Daudé 
Reviewed-by: Richard Henderson 
Message-Id: <20201120210844.2625602-5-f4...@amsat.org>
---
 target/mips/translate.c | 2209 +-
 target/mips/mod-msa_translate.c.inc | 2218 +++
 2 files changed, 2219 insertions(+), 2208 deletions(-)
 create mode 100644 target/mips/mod-msa_translate.c.inc

diff --git a/target/mips/translate.c b/target/mips/translate.c
index 5ec9fd7e92a..e174bf778e6 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -1211,239 +1211,6 @@ enum {
 OPC_NMSUB_PS= 0x3E | OPC_CP3,
 };
 
-/* MSA Opcodes */
-#define MASK_MSA_MINOR(op)  (MASK_OP_MAJOR(op) | (op & 0x3F))
-enum {
-OPC_MSA_I8_00   = 0x00 | OPC_MSA,
-OPC_MSA_I8_01   = 0x01 | OPC_MSA,
-OPC_MSA_I8_02   = 0x02 | OPC_MSA,
-OPC_MSA_I5_06   = 0x06 | OPC_MSA,
-OPC_MSA_I5_07   = 0x07 | OPC_MSA,
-OPC_MSA_BIT_09  = 0x09 | OPC_MSA,
-OPC_MSA_BIT_0A  = 0x0A | OPC_MSA,
-OPC_MSA_3R_0D   = 0x0D | OPC_MSA,
-OPC_MSA_3R_0E   = 0x0E | OPC_MSA,
-OPC_MSA_3R_0F   = 0x0F | OPC_MSA,
-OPC_MSA_3R_10   = 0x10 | OPC_MSA,
-OPC_MSA_3R_11   = 0x11 | OPC_MSA,
-OPC_MSA_3R_12   = 0x12 | OPC_MSA,
-OPC_MSA_3R_13   = 0x13 | OPC_MSA,
-OPC_MSA_3R_14   = 0x14 | OPC_MSA,
-OPC_MSA_3R_15   = 0x15 | OPC_MSA,
-OPC_MSA_ELM = 0x19 | OPC_MSA,
-OPC_MSA_3RF_1A  = 0x1A | OPC_MSA,
-OPC_MSA_3RF_1B  = 0x1B | OPC_MSA,
-OPC_MSA_3RF_1C  = 0x1C | OPC_MSA,
-OPC_MSA_VEC = 0x1E | OPC_MSA,
-
-/* MI10 instruction */
-OPC_LD_B= (0x20) | OPC_MSA,
-OPC_LD_H= (0x21) | OPC_MSA,
-OPC_LD_W= (0x22) | OPC_MSA,
-OPC_LD_D= (0x23) | OPC_MSA,
-OPC_ST_B= (0x24) | OPC_MSA,
-OPC_ST_H= (0x25) | OPC_MSA,
-OPC_ST_W= (0x26) | OPC_MSA,
-OPC_ST_D= (0x27) | OPC_MSA,
-};
-
-enum {
-/* I5 instruction df(bits 22..21) = _b, _h, _w, _d */
-OPC_ADDVI_df= (0x0 << 23) | OPC_MSA_I5_06,
-OPC_CEQI_df = (0x0 << 23) | OPC_MSA_I5_07,
-OPC_SUBVI_df= (0x1 << 23) | OPC_MSA_I5_06,
-OPC_MAXI_S_df   = (0x2 << 23) | OPC_MSA_I5_06,
-OPC_CLTI_S_df   = (0x2 << 23) | OPC_MSA_I5_07,
-OPC_MAXI_U_df   = (0x3 << 23) | OPC_MSA_I5_06,
-OPC_CLTI_U_df   = (0x3 << 23) | OPC_MSA_I5_07,
-OPC_MINI_S_df   = (0x4 << 23) | OPC_MSA_I5_06,
-OPC_CLEI_S_df   = (0x4 << 23) | OPC_MSA_I5_07,
-OPC_MINI_U_df   = (0x5 << 23) | OPC_MSA_I5_06,
-OPC_CLEI_U_df   = (0x5 << 23) | OPC_MSA_I5_07,
-OPC_LDI_df  = (0x6 << 23) | OPC_MSA_I5_07,
-
-/* I8 instruction */
-OPC_ANDI_B  = (0x0 << 24) | OPC_MSA_I8_00,
-OPC_BMNZI_B = (0x0 << 24) | OPC_MSA_I8_01,
-OPC_SHF_B   = (0x0 << 24) | OPC_MSA_I8_02,
-OPC_ORI_B   = (0x1 << 24) | OPC_MSA_I8_00,
-OPC_BMZI_B  = (0x1 << 24) | OPC_MSA_I8_01,
-OPC_SHF_H   = (0x1 << 24) | OPC_MSA_I8_02,
-OPC_NORI_B  = (0x2 << 24) | OPC_MSA_I8_00,
-OPC_BSELI_B = (0x2 << 24) | OPC_MSA_I8_01,
-OPC_SHF_W   = (0x2 << 24) | OPC_MSA_I8_02,
-OPC_XORI_B  = (0x3 << 24) | OPC_MSA_I8_00,
-
-/* VEC/2R/2RF instruction */
-OPC_AND_V   = (0x00 << 21) | OPC_MSA_VEC,
-OPC_OR_V= (0x01 << 21) | OPC_MSA_VEC,
-OPC_NOR_V   = (0x02 << 21) | OPC_MSA_VEC,
-OPC_XOR_V   = (0x03 << 21) | OPC_MSA_VEC,
-OPC_BMNZ_V  = (0x04 << 21) | OPC_MSA_VEC,
-OPC_BMZ_V   = (0x05 << 21) | OPC_MSA_VEC,
-OPC_BSEL_V  = (0x06 << 21) | OPC_MSA_VEC,
-
-OPC_MSA_2R  = (0x18 << 21) | OPC_MSA_VEC,
-OPC_MSA_2RF = (0x19 << 21) | OPC_MSA_VEC,
-
-/* 2R instruction df(bits 17..16) = _b, _h, _w, _d */
-OPC_FILL_df = (0x00 << 18) | OPC_MSA_2R,
-OPC_PCNT_df = (0x01 << 18) | OPC_MSA_2R,
-OPC_NLOC_df = (0x02 << 18) | OPC_MSA_2R,
-OPC_NLZC_df = (0x03 << 18) | OPC_MSA_2R,
-
-/* 2RF instruction df(bit 16) = _w, _d */
-OPC_FCLASS_df   = (0x00 << 17) | OPC_MSA_2RF,
-OPC_FTRUNC_S_df = (0x01 << 17) | OPC_MSA_2RF,
-OPC_FTRUNC_U_df = (0x02 << 17) | OPC_MSA_2RF,
-OPC_FSQRT_df= (0x03 << 17) | OPC_MSA_2RF,
-OPC_FRSQRT_df   = (0x04 << 17) | OPC_MSA_2RF,
-OPC_FRCP_df = (0x05 << 17) | OPC_MSA_2RF,
-OPC_FRINT_df= (0x06 << 17) | OPC_MSA_2RF,
-OPC_FLOG2_df= (0x07 << 17) | OPC_MSA_2RF,
-OPC_FEXUPL_df   = (0x08 << 17) | OPC_MSA_2RF,
-OPC_FEXUPR_df   = (0x09 << 17) | OPC_MSA_2RF,
-OPC_FFQL_df = (0x0A << 17) | OPC_MSA_2RF,
-OPC_FFQR_df = (0x0B << 17) | OPC_MSA_2RF,
-OPC_FTINT_S_df  = (0x0C << 17) | OPC_MSA_2RF,
-OPC_FTINT_U_df  = (0x0D << 17) | OPC_MSA_2RF,
-OPC_FFINT_S_df  = (0x0E << 17) | OPC_MSA_2RF,
-OPC_FFINT_U_df  = (0x0F << 17) 

[PATCH v2 02/28] target/mips: Extract FPU helpers to 'fpu_helper.h'

2020-11-23 Thread Philippe Mathieu-Daudé
Extract FPU specific helpers from "internal.h" to "fpu_helper.h".

Reviewed-by: Richard Henderson 
Signed-off-by: Philippe Mathieu-Daudé 
Message-Id: <20201120210844.2625602-2-f4...@amsat.org>
---
 target/mips/fpu_helper.h   | 50 ++
 target/mips/internal.h | 43 
 linux-user/mips/cpu_loop.c |  1 +
 target/mips/fpu_helper.c   |  1 +
 target/mips/gdbstub.c  |  1 +
 target/mips/kvm.c  |  1 +
 target/mips/machine.c  |  1 +
 target/mips/msa_helper.c   |  1 +
 target/mips/translate.c|  1 +
 9 files changed, 57 insertions(+), 43 deletions(-)
 create mode 100644 target/mips/fpu_helper.h

diff --git a/target/mips/fpu_helper.h b/target/mips/fpu_helper.h
new file mode 100644
index 000..3aaee3f3430
--- /dev/null
+++ b/target/mips/fpu_helper.h
@@ -0,0 +1,50 @@
+/*
+ *  Helpers for emulation of FPU-related MIPS instructions.
+ *
+ *  Copyright (C) 2004-2005  Jocelyn Mayer
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+#include "fpu/softfloat-helpers.h"
+#include "cpu.h"
+
+extern const FloatRoundMode ieee_rm[4];
+
+uint32_t float_class_s(uint32_t arg, float_status *fst);
+uint64_t float_class_d(uint64_t arg, float_status *fst);
+
+static inline void restore_rounding_mode(CPUMIPSState *env)
+{
+set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3],
+>active_fpu.fp_status);
+}
+
+static inline void restore_flush_mode(CPUMIPSState *env)
+{
+set_flush_to_zero((env->active_fpu.fcr31 & (1 << FCR31_FS)) != 0,
+  >active_fpu.fp_status);
+}
+
+static inline void restore_snan_bit_mode(CPUMIPSState *env)
+{
+set_snan_bit_is_one((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) == 0,
+>active_fpu.fp_status);
+}
+
+static inline void restore_fp_status(CPUMIPSState *env)
+{
+restore_rounding_mode(env);
+restore_flush_mode(env);
+restore_snan_bit_mode(env);
+}
+
+static inline void restore_msa_fp_status(CPUMIPSState *env)
+{
+float_status *status = >active_tc.msa_fp_status;
+int rounding_mode = (env->active_tc.msacsr & MSACSR_RM_MASK) >> MSACSR_RM;
+bool flush_to_zero = (env->active_tc.msacsr & MSACSR_FS_MASK) != 0;
+
+set_float_rounding_mode(ieee_rm[rounding_mode], status);
+set_flush_to_zero(flush_to_zero, status);
+set_flush_inputs_to_zero(flush_to_zero, status);
+}
diff --git a/target/mips/internal.h b/target/mips/internal.h
index bbd10e9d45f..7bea3af0b29 100644
--- a/target/mips/internal.h
+++ b/target/mips/internal.h
@@ -8,8 +8,6 @@
 #ifndef MIPS_INTERNAL_H
 #define MIPS_INTERNAL_H
 
-#include "fpu/softfloat-helpers.h"
-
 /*
  * MMU types, the first four entries have the same layout as the
  * CP0C0_MT field.
@@ -222,49 +220,8 @@ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int 
size,
bool probe, uintptr_t retaddr);
 
 /* op_helper.c */
-uint32_t float_class_s(uint32_t arg, float_status *fst);
-uint64_t float_class_d(uint64_t arg, float_status *fst);
-
-extern const FloatRoundMode ieee_rm[4];
-
 void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask);
 
-static inline void restore_rounding_mode(CPUMIPSState *env)
-{
-set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3],
->active_fpu.fp_status);
-}
-
-static inline void restore_flush_mode(CPUMIPSState *env)
-{
-set_flush_to_zero((env->active_fpu.fcr31 & (1 << FCR31_FS)) != 0,
-  >active_fpu.fp_status);
-}
-
-static inline void restore_snan_bit_mode(CPUMIPSState *env)
-{
-set_snan_bit_is_one((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) == 0,
->active_fpu.fp_status);
-}
-
-static inline void restore_fp_status(CPUMIPSState *env)
-{
-restore_rounding_mode(env);
-restore_flush_mode(env);
-restore_snan_bit_mode(env);
-}
-
-static inline void restore_msa_fp_status(CPUMIPSState *env)
-{
-float_status *status = >active_tc.msa_fp_status;
-int rounding_mode = (env->active_tc.msacsr & MSACSR_RM_MASK) >> MSACSR_RM;
-bool flush_to_zero = (env->active_tc.msacsr & MSACSR_FS_MASK) != 0;
-
-set_float_rounding_mode(ieee_rm[rounding_mode], status);
-set_flush_to_zero(flush_to_zero, status);
-set_flush_inputs_to_zero(flush_to_zero, status);
-}
-
 static inline void restore_pamask(CPUMIPSState *env)
 {
 if (env->hflags & MIPS_HFLAG_ELPA) {
diff --git a/linux-user/mips/cpu_loop.c b/linux-user/mips/cpu_loop.c
index cfe7ba5c47d..b58dbeb83d1 100644
--- a/linux-user/mips/cpu_loop.c
+++ b/linux-user/mips/cpu_loop.c
@@ -23,6 +23,7 @@
 #include "cpu_loop-common.h"
 #include "elf.h"
 #include "internal.h"
+#include "fpu_helper.h"
 
 # ifdef TARGET_ABI_MIPSO32
 #  define MIPS_SYSCALL_NUMBER_UNUSED -1
diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c
index 501bd401a16..7d949cd8e3a 100644
--- a/target/mips/fpu_helper.c
+++ b/target/mips/fpu_helper.c
@@ -31,6 +31,7 @@
 #include 

[PATCH v2 12/28] target/mips: Extract the microMIPS ISA helper definitions

2020-11-23 Thread Philippe Mathieu-Daudé
Extract the microMIPS ISA helper definitions to
'isa-micromips_helper.h.inc'.

Signed-off-by: Philippe Mathieu-Daudé 
Reviewed-by: Richard Henderson 
Message-Id: <20201120210844.2625602-11-f4...@amsat.org>
---
 target/mips/helper.h   | 10 ++
 target/mips/isa-micromips_helper.h.inc | 17 +
 2 files changed, 19 insertions(+), 8 deletions(-)
 create mode 100644 target/mips/isa-micromips_helper.h.inc

diff --git a/target/mips/helper.h b/target/mips/helper.h
index 18366bc0345..06da4c6cf68 100644
--- a/target/mips/helper.h
+++ b/target/mips/helper.h
@@ -181,14 +181,6 @@ DEF_HELPER_2(dmtc0_entrylo1, void, env, i64)
 
 #endif /* !CONFIG_USER_ONLY */
 
-/* microMIPS functions */
-DEF_HELPER_4(lwm, void, env, tl, tl, i32)
-DEF_HELPER_4(swm, void, env, tl, tl, i32)
-#ifdef TARGET_MIPS64
-DEF_HELPER_4(ldm, void, env, tl, tl, i32)
-DEF_HELPER_4(sdm, void, env, tl, tl, i32)
-#endif
-
 /* CP1 functions */
 DEF_HELPER_2(cfc1, tl, env, i32)
 DEF_HELPER_4(ctc1, void, env, tl, i32, i32)
@@ -427,6 +419,8 @@ DEF_HELPER_FLAGS_1(pmovmskb, TCG_CALL_NO_RWG_SE, i64, i64)
 
 DEF_HELPER_3(cache, void, env, tl, i32)
 
+#include "isa-micromips_helper.h.inc"
+
 #include "mod-dsp_helper.h.inc"
 #include "mod-msa_helper.h.inc"
 #include "mod-mt_helper.h.inc"
diff --git a/target/mips/isa-micromips_helper.h.inc 
b/target/mips/isa-micromips_helper.h.inc
new file mode 100644
index 000..66a764c4aac
--- /dev/null
+++ b/target/mips/isa-micromips_helper.h.inc
@@ -0,0 +1,17 @@
+/*
+ * microMIPS instruction emulation helpers for QEMU.
+ *
+ *  Copyright (c) 2004-2005 Jocelyn Mayer
+ *  Copyright (c) 2006 Marius Groeger (FPU operations)
+ *  Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support)
+ *  Copyright (c) 2009 CodeSourcery (MIPS16 and microMIPS support)
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+DEF_HELPER_4(lwm, void, env, tl, tl, i32)
+DEF_HELPER_4(swm, void, env, tl, tl, i32)
+#ifdef TARGET_MIPS64
+DEF_HELPER_4(ldm, void, env, tl, tl, i32)
+DEF_HELPER_4(sdm, void, env, tl, tl, i32)
+#endif
-- 
2.26.2




[PATCH v2 05/28] target/mips: Extract MSA helper definitions

2020-11-23 Thread Philippe Mathieu-Daudé
Keep all MSA-related code altogether.

Reviewed-by: Richard Henderson 
Signed-off-by: Philippe Mathieu-Daudé 
Message-Id: <20201120210844.2625602-4-f4...@amsat.org>
---
 target/mips/helper.h | 436 +-
 target/mips/mod-msa_helper.h.inc | 443 +++
 2 files changed, 445 insertions(+), 434 deletions(-)
 create mode 100644 target/mips/mod-msa_helper.h.inc

diff --git a/target/mips/helper.h b/target/mips/helper.h
index e97655dc0eb..80eb675fa64 100644
--- a/target/mips/helper.h
+++ b/target/mips/helper.h
@@ -781,438 +781,6 @@ DEF_HELPER_FLAGS_3(dmthlip, 0, void, tl, tl, env)
 DEF_HELPER_FLAGS_3(wrdsp, 0, void, tl, tl, env)
 DEF_HELPER_FLAGS_2(rddsp, 0, tl, tl, env)
 
-/* MIPS SIMD Architecture */
-
-DEF_HELPER_3(msa_nloc_b, void, env, i32, i32)
-DEF_HELPER_3(msa_nloc_h, void, env, i32, i32)
-DEF_HELPER_3(msa_nloc_w, void, env, i32, i32)
-DEF_HELPER_3(msa_nloc_d, void, env, i32, i32)
-
-DEF_HELPER_3(msa_nlzc_b, void, env, i32, i32)
-DEF_HELPER_3(msa_nlzc_h, void, env, i32, i32)
-DEF_HELPER_3(msa_nlzc_w, void, env, i32, i32)
-DEF_HELPER_3(msa_nlzc_d, void, env, i32, i32)
-
-DEF_HELPER_3(msa_pcnt_b, void, env, i32, i32)
-DEF_HELPER_3(msa_pcnt_h, void, env, i32, i32)
-DEF_HELPER_3(msa_pcnt_w, void, env, i32, i32)
-DEF_HELPER_3(msa_pcnt_d, void, env, i32, i32)
-
-DEF_HELPER_4(msa_binsl_b, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_binsl_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_binsl_w, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_binsl_d, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_binsr_b, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_binsr_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_binsr_w, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_binsr_d, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_bmnz_v, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_bmz_v, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_bsel_v, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_bclr_b, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_bclr_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_bclr_w, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_bclr_d, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_bneg_b, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_bneg_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_bneg_w, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_bneg_d, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_bset_b, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_bset_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_bset_w, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_bset_d, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_add_a_b, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_add_a_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_add_a_w, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_add_a_d, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_adds_a_b, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_adds_a_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_adds_a_w, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_adds_a_d, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_adds_s_b, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_adds_s_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_adds_s_w, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_adds_s_d, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_adds_u_b, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_adds_u_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_adds_u_w, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_adds_u_d, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_addv_b, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_addv_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_addv_w, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_addv_d, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_hadd_s_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_hadd_s_w, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_hadd_s_d, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_hadd_u_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_hadd_u_w, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_hadd_u_d, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_ave_s_b, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_ave_s_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_ave_s_w, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_ave_s_d, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_ave_u_b, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_ave_u_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_ave_u_w, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_ave_u_d, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_aver_s_b, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_aver_s_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_aver_s_w, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_aver_s_d, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_aver_u_b, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_aver_u_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_aver_u_w, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_aver_u_d, void, env, i32, i32, i32)
-
-DEF_HELPER_4(msa_ceq_b, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_ceq_h, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_ceq_w, void, env, i32, i32, i32)

[PATCH 20/21] block: introduce bdrv_drop_filter()

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
Using bdrv_replace_node() for removing filter is not good enough: it
keeps child reference of the filter, which may conflict with original
top node during permission update.

Instead let's create new interface, which will do all graph
modifications first and then update permissions.

Let's modify bdrv_replace_node_common(), allowing it additionally drop
backing chain child link pointing to new node. This is quite
appropriate for bdrv_drop_intermediate() and makes possible to add
new bdrv_drop_filter() as a simple wrapper.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 include/block/block.h |  1 +
 block.c   | 35 ---
 2 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/include/block/block.h b/include/block/block.h
index 6c1efce0c3..981a07e29d 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -348,6 +348,7 @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState 
*bs_top,
 Error **errp);
 int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
   Error **errp);
+int bdrv_drop_filter(BlockDriverState *bs, Error **errp);
 
 int bdrv_parse_aio(const char *mode, int *flags);
 int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough);
diff --git a/block.c b/block.c
index 6ea926e2c1..ee0143aff2 100644
--- a/block.c
+++ b/block.c
@@ -4923,15 +4923,30 @@ static int bdrv_replace_node_noperm(BlockDriverState 
*from,
  *
  * With auto_skip=false the error is returned if from has a parent which should
  * not be updated.
+ *
+ * With detach_subchain to must be in a backing chain of from. In this case
+ * backing link of the cow-parent of @to is removed.
  */
 static int bdrv_replace_node_common(BlockDriverState *from,
 BlockDriverState *to,
-bool auto_skip, Error **errp)
+bool auto_skip, bool detach_subchain,
+Error **errp)
 {
 int ret = -EPERM;
 GSList *tran = NULL;
 g_autoptr(GHashTable) found = NULL;
 g_autoptr(GSList) refresh_list = NULL;
+BlockDriverState *to_cow_parent;
+
+if (detach_subchain) {
+assert(bdrv_chain_contains(from, to));
+for (to_cow_parent = from;
+ bdrv_filter_or_cow_bs(to_cow_parent) != to;
+ to_cow_parent = bdrv_filter_or_cow_bs(to_cow_parent))
+{
+;
+}
+}
 
 /* Make sure that @from doesn't go away until we have successfully attached
  * all of its parents to @to. */
@@ -4952,6 +4967,10 @@ static int bdrv_replace_node_common(BlockDriverState 
*from,
 goto out;
 }
 
+if (detach_subchain) {
+bdrv_remove_backing(to_cow_parent, );
+}
+
 found = g_hash_table_new(NULL, NULL);
 
 refresh_list = bdrv_topological_dfs(refresh_list, found, to);
@@ -4971,7 +4990,13 @@ out:
 int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
   Error **errp)
 {
-return bdrv_replace_node_common(from, to, true, errp);
+return bdrv_replace_node_common(from, to, true, false, errp);
+}
+
+int bdrv_drop_filter(BlockDriverState *bs, Error **errp)
+{
+return bdrv_replace_node_common(bs, bdrv_filter_or_cow_bs(bs), true, true,
+errp);
 }
 
 /*
@@ -5303,7 +5328,11 @@ int bdrv_drop_intermediate(BlockDriverState *top, 
BlockDriverState *base,
 updated_children = g_slist_prepend(updated_children, c);
 }
 
-bdrv_replace_node_common(top, base, false, _err);
+/*
+ * It seems correct to pass detach_subchain=true here, but it triggers one
+ * more yet not fixed bug
+ */
+bdrv_replace_node_common(top, base, false, false, _err);
 if (local_err) {
 error_report_err(local_err);
 goto exit;
-- 
2.21.3




[PATCH v2 11/28] target/mips: Extract Code Compaction ASE translation routines

2020-11-23 Thread Philippe Mathieu-Daudé
Extract 1200 lines from the huge translate.c to a new file,
'ase-mips16e_translate.c.inc'. As there are too many inter-
dependencies we don't compile it as another object, but
keep including it in the big translate.o. We gain in code
maintainability.

Signed-off-by: Philippe Mathieu-Daudé 
Reviewed-by: Richard Henderson 
Message-Id: <20201120210844.2625602-10-f4...@amsat.org>
---
 target/mips/translate.c | 1161 +-
 target/mips/ase-mips16e_translate.c.inc | 1170 +++
 2 files changed, 1171 insertions(+), 1160 deletions(-)
 create mode 100644 target/mips/ase-mips16e_translate.c.inc

diff --git a/target/mips/translate.c b/target/mips/translate.c
index d1e154b1f79..1a329bcdede 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -13131,1167 +13131,8 @@ out:
 }
 
 /* ISA extensions (ASEs) */
-/* MIPS16 extension to MIPS32 */
 
-/* MIPS16 major opcodes */
-enum {
-  M16_OPC_ADDIUSP = 0x00,
-  M16_OPC_ADDIUPC = 0x01,
-  M16_OPC_B = 0x02,
-  M16_OPC_JAL = 0x03,
-  M16_OPC_BEQZ = 0x04,
-  M16_OPC_BNEQZ = 0x05,
-  M16_OPC_SHIFT = 0x06,
-  M16_OPC_LD = 0x07,
-  M16_OPC_RRIA = 0x08,
-  M16_OPC_ADDIU8 = 0x09,
-  M16_OPC_SLTI = 0x0a,
-  M16_OPC_SLTIU = 0x0b,
-  M16_OPC_I8 = 0x0c,
-  M16_OPC_LI = 0x0d,
-  M16_OPC_CMPI = 0x0e,
-  M16_OPC_SD = 0x0f,
-  M16_OPC_LB = 0x10,
-  M16_OPC_LH = 0x11,
-  M16_OPC_LWSP = 0x12,
-  M16_OPC_LW = 0x13,
-  M16_OPC_LBU = 0x14,
-  M16_OPC_LHU = 0x15,
-  M16_OPC_LWPC = 0x16,
-  M16_OPC_LWU = 0x17,
-  M16_OPC_SB = 0x18,
-  M16_OPC_SH = 0x19,
-  M16_OPC_SWSP = 0x1a,
-  M16_OPC_SW = 0x1b,
-  M16_OPC_RRR = 0x1c,
-  M16_OPC_RR = 0x1d,
-  M16_OPC_EXTEND = 0x1e,
-  M16_OPC_I64 = 0x1f
-};
-
-/* I8 funct field */
-enum {
-  I8_BTEQZ = 0x0,
-  I8_BTNEZ = 0x1,
-  I8_SWRASP = 0x2,
-  I8_ADJSP = 0x3,
-  I8_SVRS = 0x4,
-  I8_MOV32R = 0x5,
-  I8_MOVR32 = 0x7
-};
-
-/* RRR f field */
-enum {
-  RRR_DADDU = 0x0,
-  RRR_ADDU = 0x1,
-  RRR_DSUBU = 0x2,
-  RRR_SUBU = 0x3
-};
-
-/* RR funct field */
-enum {
-  RR_JR = 0x00,
-  RR_SDBBP = 0x01,
-  RR_SLT = 0x02,
-  RR_SLTU = 0x03,
-  RR_SLLV = 0x04,
-  RR_BREAK = 0x05,
-  RR_SRLV = 0x06,
-  RR_SRAV = 0x07,
-  RR_DSRL = 0x08,
-  RR_CMP = 0x0a,
-  RR_NEG = 0x0b,
-  RR_AND = 0x0c,
-  RR_OR = 0x0d,
-  RR_XOR = 0x0e,
-  RR_NOT = 0x0f,
-  RR_MFHI = 0x10,
-  RR_CNVT = 0x11,
-  RR_MFLO = 0x12,
-  RR_DSRA = 0x13,
-  RR_DSLLV = 0x14,
-  RR_DSRLV = 0x16,
-  RR_DSRAV = 0x17,
-  RR_MULT = 0x18,
-  RR_MULTU = 0x19,
-  RR_DIV = 0x1a,
-  RR_DIVU = 0x1b,
-  RR_DMULT = 0x1c,
-  RR_DMULTU = 0x1d,
-  RR_DDIV = 0x1e,
-  RR_DDIVU = 0x1f
-};
-
-/* I64 funct field */
-enum {
-  I64_LDSP = 0x0,
-  I64_SDSP = 0x1,
-  I64_SDRASP = 0x2,
-  I64_DADJSP = 0x3,
-  I64_LDPC = 0x4,
-  I64_DADDIU5 = 0x5,
-  I64_DADDIUPC = 0x6,
-  I64_DADDIUSP = 0x7
-};
-
-/* RR ry field for CNVT */
-enum {
-  RR_RY_CNVT_ZEB = 0x0,
-  RR_RY_CNVT_ZEH = 0x1,
-  RR_RY_CNVT_ZEW = 0x2,
-  RR_RY_CNVT_SEB = 0x4,
-  RR_RY_CNVT_SEH = 0x5,
-  RR_RY_CNVT_SEW = 0x6,
-};
-
-static int xlat(int r)
-{
-  static int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
-
-  return map[r];
-}
-
-static void gen_mips16_save(DisasContext *ctx,
-int xsregs, int aregs,
-int do_ra, int do_s0, int do_s1,
-int framesize)
-{
-TCGv t0 = tcg_temp_new();
-TCGv t1 = tcg_temp_new();
-TCGv t2 = tcg_temp_new();
-int args, astatic;
-
-switch (aregs) {
-case 0:
-case 1:
-case 2:
-case 3:
-case 11:
-args = 0;
-break;
-case 4:
-case 5:
-case 6:
-case 7:
-args = 1;
-break;
-case 8:
-case 9:
-case 10:
-args = 2;
-break;
-case 12:
-case 13:
-args = 3;
-break;
-case 14:
-args = 4;
-break;
-default:
-generate_exception_end(ctx, EXCP_RI);
-return;
-}
-
-switch (args) {
-case 4:
-gen_base_offset_addr(ctx, t0, 29, 12);
-gen_load_gpr(t1, 7);
-tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL);
-/* Fall through */
-case 3:
-gen_base_offset_addr(ctx, t0, 29, 8);
-gen_load_gpr(t1, 6);
-tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL);
-/* Fall through */
-case 2:
-gen_base_offset_addr(ctx, t0, 29, 4);
-gen_load_gpr(t1, 5);
-tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL);
-/* Fall through */
-case 1:
-gen_base_offset_addr(ctx, t0, 29, 0);
-gen_load_gpr(t1, 4);
-tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL);
-}
-
-gen_load_gpr(t0, 29);
-
-#define DECR_AND_STORE(reg) do { \
-tcg_gen_movi_tl(t2, -4); \
-gen_op_addr_add(ctx, t0, t0, t2);\
-gen_load_gpr(t1, reg);   \
-tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); \
-} while (0)
-
-if 

[PATCH v2 00/28] target/mips: Explode 60% of the 32K-lines translate.c

2020-11-23 Thread Philippe Mathieu-Daudé
Since v1:
- Addressed Richard review comments

Patches missing review: 1,3,4,21,22,25

Hi,

This series, while boring, helps maintainability.

I simply exploded 60% of the huge target/mips/translate.c,
reducing it from 32K lines of code to 13500.

The small overhead in the diffstat is due to entries added in
MAINTAINERS and license boilerplate addition:
20225 insertions(+), 19987 deletions(-)

While being a massive diff, it is a no-brain review using
'git-diff --color-moved=dimmed-zebra' which highlights very few
changes: #include and license lines.

The exploded new layout, which allows more useful filtering
with the get_maintainer.pl script, is:

- MIPS ISA, ASE and modules:

 . isa-micromips_helper.h.inc
 . isa-nanomips_translate.c.inc

 . ase-mips16e_translate.c.inc

 . mod-dsp_helper.c
 . mod-dsp_helper.h.inc
 . mod-dsp_translate.c.inc
 . mod-msa_helper.h.inc
 . mod-msa_translate.c.inc
 . mod-msa_helper.c
 . mod-mt_helper.h.inc

- MIPS Vendor Specific:

 . vendor-loong-simd_helper.c
 . vendor-loong-ext_translate.c.inc
 . vendor-loong-simd_helper.h.inc
 . vendor-loong-simd_translate.c.inc

 . vendor-tx-mmi_translate.c.inc
 . vendor-tx_translate.c.inc

 . vendor-vr54xx_helper.c
 . vendor-vr54xx_helper.h.inc
 . vendor-vr54xx_translate.c.inc

 . vendor-mxu_translate.c.inc

There should be no logical code change (only code movement).

The series is available at:

  https://gitlab.com/philmd/qemu.git tags/mips_translate_explode-v2

Regards,

Phil.

Philippe Mathieu-Daudé (28):
  target/mips: Use FloatRoundMode enum for FCR31 modes conversion
  target/mips: Extract FPU helpers to 'fpu_helper.h'
  target/mips: Rename msa_helper.c as mod-msa_helper.c
  target/mips: Extract MSA helpers from op_helper.c
  target/mips: Extract MSA helper definitions
  target/mips: Extract MSA translation routines
  target/mips: Rename dsp_helper.c as mod-dsp_helper.c
  target/mips: Extract DSP helper definitions
  target/mips: Extract DSP translation routines
  target/mips: Extract Multi-Threading helper definitions
  target/mips: Extract Code Compaction ASE translation routines
  target/mips: Extract the microMIPS ISA helper definitions
  target/mips: Extract the microMIPS ISA translation routines
  target/mips: Extract nanoMIPS ISA translation routines
  target/mips: Extract NEC Vr54xx helpers to vendor-vr54xx_helper.c
  target/mips: Extract NEC Vr54xx helper definitions
  target/mips: Extract NEC Vr54xx translation routines
  target/mips: Rename lmmi_helper.c as loong-simd_helper.c
  target/mips: Extract Loongson SIMD helper definitions
  target/mips: Extract Loongson SIMD translation routines
  target/mips: Extract Loongson EXTensions translation routines
  target/mips: Extract XBurst Media eXtension Unit translation routines
  target/mips: Make pipeline 1 multiply opcodes generic
  target/mips: Extract Toshiba TXx9 translation routines
  target/mips: Extract Toshiba TX79 multimedia translation routines
  MAINTAINERS: Add entry for MIPS Loongson TCG
  MAINTAINERS: Add entry for MIPS Ingenic Xburst TCG
  MAINTAINERS: Add entry for MIPS Toshiba TCG

 target/mips/fpu_helper.h  |50 +
 target/mips/helper.h  |   881 +-
 target/mips/internal.h|42 -
 linux-user/mips/cpu_loop.c| 1 +
 target/mips/fpu_helper.c  | 3 +-
 target/mips/gdbstub.c | 1 +
 target/mips/kvm.c | 1 +
 target/mips/machine.c | 1 +
 .../mips/{dsp_helper.c => mod-dsp_helper.c}   | 2 +
 .../mips/{msa_helper.c => mod-msa_helper.c}   |   393 +
 target/mips/op_helper.c   |   511 -
 target/mips/translate.c   | 18696 +---
 ...mi_helper.c => vendor-loong-simd_helper.c} | 0
 target/mips/vendor-vr54xx_helper.c|   131 +
 MAINTAINERS   |20 +
 target/mips/ase-mips16e_translate.c.inc   |  1170 +
 target/mips/isa-micromips_helper.h.inc|17 +
 target/mips/isa-micromips_translate.c.inc |  3316 +++
 target/mips/isa-nanomips_translate.c.inc  |  4839 
 target/mips/meson.build   | 8 +-
 target/mips/mod-dsp_helper.h.inc  |   344 +
 target/mips/mod-dsp_translate.c.inc   |  2158 ++
 target/mips/mod-msa_helper.h.inc  |   443 +
 target/mips/mod-msa_translate.c.inc   |  2218 ++
 target/mips/mod-mt_helper.h.inc   |36 +
 target/mips/vendor-loong-ext_translate.c.inc  |   665 +
 target/mips/vendor-loong-simd_helper.h.inc|69 +
 target/mips/vendor-loong-simd_translate.c.inc |   492 +
 target/mips/vendor-mxu_translate.c.inc|  2892 +++
 target/mips/vendor-tx-mmi_translate.c.inc |   573 +
 target/mips/vendor-tx_translate.c.inc |   315 +
 target/mips/vendor-vr54xx_helper.h.inc|24 +
 target/mips/vendor-vr54xx_translate.c.inc |93 +
 33 

[PATCH 15/21] block: split out bdrv_replace_node_noperm()

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
Split part of bdrv_replace_node_common() to be used separately.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block.c | 47 ++-
 1 file changed, 30 insertions(+), 17 deletions(-)

diff --git a/block.c b/block.c
index 5f6ad1d016..1327254b8e 100644
--- a/block.c
+++ b/block.c
@@ -4859,6 +4859,33 @@ static bool should_update_child(BdrvChild *c, 
BlockDriverState *to)
 return ret;
 }
 
+static int bdrv_replace_node_noperm(BlockDriverState *from,
+BlockDriverState *to,
+bool auto_skip, GSList **tran, Error 
**errp)
+{
+BdrvChild *c, *next;
+
+QLIST_FOREACH_SAFE(c, >parents, next_parent, next) {
+assert(c->bs == from);
+if (!should_update_child(c, to)) {
+if (auto_skip) {
+continue;
+}
+error_setg(errp, "Should not change '%s' link to '%s'",
+   c->name, from->node_name);
+return -EPERM;
+}
+if (c->frozen) {
+error_setg(errp, "Cannot change '%s' link to '%s'",
+   c->name, from->node_name);
+return -EPERM;
+}
+bdrv_replace_child_safe(c, to, tran);
+}
+
+return 0;
+}
+
 /*
  * With auto_skip=true bdrv_replace_node_common skips updating from parents
  * if it creates a parent-child relation loop or if parent is block-job.
@@ -4871,7 +4898,6 @@ static int bdrv_replace_node_common(BlockDriverState 
*from,
 bool auto_skip, Error **errp)
 {
 int ret = -EPERM;
-BdrvChild *c, *next;
 GSList *tran = NULL;
 g_autoptr(GHashTable) found = NULL;
 g_autoptr(GSList) refresh_list = NULL;
@@ -4890,22 +4916,9 @@ static int bdrv_replace_node_common(BlockDriverState 
*from,
  * permissions based on new graph. If we fail, we'll roll-back the
  * replacement.
  */
-QLIST_FOREACH_SAFE(c, >parents, next_parent, next) {
-assert(c->bs == from);
-if (!should_update_child(c, to)) {
-if (auto_skip) {
-continue;
-}
-error_setg(errp, "Should not change '%s' link to '%s'",
-   c->name, from->node_name);
-goto out;
-}
-if (c->frozen) {
-error_setg(errp, "Cannot change '%s' link to '%s'",
-   c->name, from->node_name);
-goto out;
-}
-bdrv_replace_child_safe(c, to, );
+ret = bdrv_replace_node_noperm(from, to, auto_skip, , errp);
+if (ret < 0) {
+goto out;
 }
 
 found = g_hash_table_new(NULL, NULL);
-- 
2.21.3




[PATCH 13/21] block: fix bdrv_replace_node_common

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
inore_children thing doesn't help to track all propagated permissions
of children we want to ignore. The simplest way to correctly update
permissions is update graph first and then do permission update. In
this case we just referesh permissions for the whole subgraph (in
topological-sort defined order) and everything is correctly calculated
automatically without any ignore_children.

So, refactor bdrv_replace_node_common to first do graph update and then
refresh the permissions.

Test test_parallel_exclusive_write() now pass, so move it out of
debugging "if".

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block.c | 42 ++---
 tests/test-bdrv-graph-mod.c | 18 +++-
 2 files changed, 19 insertions(+), 41 deletions(-)

diff --git a/block.c b/block.c
index 5c94f5a428..08501350b7 100644
--- a/block.c
+++ b/block.c
@@ -2178,7 +2178,6 @@ static BdrvActionDrv bdrv_replace_child_drv = {
  *
  * Note: real unref of old_bs is done only on commit.
  */
-__attribute__((unused))
 static void bdrv_replace_child_safe(BdrvChild *child, BlockDriverState *new_bs,
 GSList **tran)
 {
@@ -4787,8 +4786,9 @@ static int bdrv_replace_node_common(BlockDriverState 
*from,
 {
 int ret = -EPERM;
 BdrvChild *c, *next;
-GSList *list = NULL, *p;
-uint64_t perm = 0, shared = BLK_PERM_ALL;
+GSList *tran = NULL;
+g_autoptr(GHashTable) found = NULL;
+g_autoptr(GSList) refresh_list = NULL;
 
 /* Make sure that @from doesn't go away until we have successfully attached
  * all of its parents to @to. */
@@ -4798,7 +4798,12 @@ static int bdrv_replace_node_common(BlockDriverState 
*from,
 assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to));
 bdrv_drained_begin(from);
 
-/* Put all parents into @list and calculate their cumulative permissions */
+/*
+ * Do the replacement without permission update.
+ * Replacement may influence the permissions, we should calculate new
+ * permissions based on new graph. If we fail, we'll roll-back the
+ * replacement.
+ */
 QLIST_FOREACH_SAFE(c, >parents, next_parent, next) {
 assert(c->bs == from);
 if (!should_update_child(c, to)) {
@@ -4814,34 +4819,19 @@ static int bdrv_replace_node_common(BlockDriverState 
*from,
c->name, from->node_name);
 goto out;
 }
-list = g_slist_prepend(list, c);
-perm |= c->perm;
-shared &= c->shared_perm;
-}
-
-/* Check whether the required permissions can be granted on @to, ignoring
- * all BdrvChild in @list so that they can't block themselves. */
-ret = bdrv_check_update_perm(to, NULL, perm, shared, list, errp);
-if (ret < 0) {
-bdrv_abort_perm_update(to);
-goto out;
+bdrv_replace_child_safe(c, to, );
 }
 
-/* Now actually perform the change. We performed the permission check for
- * all elements of @list at once, so set the permissions all at once at the
- * very end. */
-for (p = list; p != NULL; p = p->next) {
-c = p->data;
+found = g_hash_table_new(NULL, NULL);
 
-bdrv_ref(to);
-bdrv_replace_child_noperm(c, to);
-bdrv_unref(from);
-}
+refresh_list = bdrv_topological_dfs(refresh_list, found, to);
+refresh_list = bdrv_topological_dfs(refresh_list, found, from);
 
-bdrv_set_perm(to);
+ret = bdrv_list_refresh_perms(refresh_list, errp);
 
 out:
-g_slist_free(list);
+tran_finalize(tran, ret);
+
 bdrv_drained_end(from);
 bdrv_unref(from);
 
diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c
index 594a1df58b..d0e0f56ec3 100644
--- a/tests/test-bdrv-graph-mod.c
+++ b/tests/test-bdrv-graph-mod.c
@@ -292,20 +292,11 @@ static void test_parallel_perm_update(void)
 bdrv_child_refresh_perms(top, top->children.lh_first, _abort);
 
 assert(c_fl1->perm & BLK_PERM_WRITE);
+bdrv_unref(top);
 }
 
 int main(int argc, char *argv[])
 {
-int i;
-bool debug = false;
-
-for (i = 1; i < argc; i++) {
-if (!strcmp(argv[i], "-d")) {
-debug = true;
-break;
-}
-}
-
 bdrv_init();
 qemu_init_main_loop(_abort);
 
@@ -316,11 +307,8 @@ int main(int argc, char *argv[])
 test_should_update_child);
 g_test_add_func("/bdrv-graph-mod/parallel-perm-update",
 test_parallel_perm_update);
-
-if (debug) {
-g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write",
-test_parallel_exclusive_write);
-}
+g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write",
+test_parallel_exclusive_write);
 
 return g_test_run();
 }
-- 
2.21.3




[PATCH 21/21] block/backup-top: drop .active

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
We don't need this workaround anymore: bdrv_append is already smart
enough and we can use new bdrv_drop_filter().

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block/backup-top.c | 38 +-
 tests/qemu-iotests/283.out |  2 +-
 2 files changed, 2 insertions(+), 38 deletions(-)

diff --git a/block/backup-top.c b/block/backup-top.c
index 650ed6195c..84eb73aeb7 100644
--- a/block/backup-top.c
+++ b/block/backup-top.c
@@ -37,7 +37,6 @@
 typedef struct BDRVBackupTopState {
 BlockCopyState *bcs;
 BdrvChild *target;
-bool active;
 int64_t cluster_size;
 } BDRVBackupTopState;
 
@@ -127,21 +126,6 @@ static void backup_top_child_perm(BlockDriverState *bs, 
BdrvChild *c,
   uint64_t perm, uint64_t shared,
   uint64_t *nperm, uint64_t *nshared)
 {
-BDRVBackupTopState *s = bs->opaque;
-
-if (!s->active) {
-/*
- * The filter node may be in process of bdrv_append(), which firstly do
- * bdrv_set_backing_hd() and then bdrv_replace_node(). This means that
- * we can't unshare BLK_PERM_WRITE during bdrv_append() operation. So,
- * let's require nothing during bdrv_append() and refresh permissions
- * after it (see bdrv_backup_top_append()).
- */
-*nperm = 0;
-*nshared = BLK_PERM_ALL;
-return;
-}
-
 if (!(role & BDRV_CHILD_FILTERED)) {
 /*
  * Target child
@@ -229,18 +213,6 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState 
*source,
 }
 appended = true;
 
-/*
- * bdrv_append() finished successfully, now we can require permissions
- * we want.
- */
-state->active = true;
-bdrv_child_refresh_perms(top, top->backing, _err);
-if (local_err) {
-error_prepend(_err,
-  "Cannot set permissions for backup-top filter: ");
-goto fail;
-}
-
 state->cluster_size = cluster_size;
 state->bcs = block_copy_state_new(top->backing, state->target,
   cluster_size, write_flags, _err);
@@ -256,7 +228,6 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState 
*source,
 
 fail:
 if (appended) {
-state->active = false;
 bdrv_backup_top_drop(top);
 } else {
 bdrv_unref(top);
@@ -272,16 +243,9 @@ void bdrv_backup_top_drop(BlockDriverState *bs)
 {
 BDRVBackupTopState *s = bs->opaque;
 
-bdrv_drained_begin(bs);
+bdrv_drop_filter(bs, _abort);
 
 block_copy_state_free(s->bcs);
 
-s->active = false;
-bdrv_child_refresh_perms(bs, bs->backing, _abort);
-bdrv_replace_node(bs, bs->backing->bs, _abort);
-bdrv_set_backing_hd(bs, NULL, _abort);
-
-bdrv_drained_end(bs);
-
 bdrv_unref(bs);
 }
diff --git a/tests/qemu-iotests/283.out b/tests/qemu-iotests/283.out
index fbb7d0f619..a34e4e3f92 100644
--- a/tests/qemu-iotests/283.out
+++ b/tests/qemu-iotests/283.out
@@ -5,4 +5,4 @@
 {"execute": "blockdev-add", "arguments": {"driver": "blkdebug", "image": 
"base", "node-name": "other", "take-child-perms": ["write"]}}
 {"return": {}}
 {"execute": "blockdev-backup", "arguments": {"device": "source", "sync": 
"full", "target": "target"}}
-{"error": {"class": "GenericError", "desc": "Cannot set permissions for 
backup-top filter: Conflicts with use by source as 'image', which does not 
allow 'write' on base"}}
+{"error": {"class": "GenericError", "desc": "Cannot append backup-top filter: 
Conflicts with use by source as 'image', which does not allow 'write' on base"}}
-- 
2.21.3




[PATCH 19/21] block: add bdrv_remove_backing transaction action

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block.c | 42 --
 1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/block.c b/block.c
index cf7b859a81..6ea926e2c1 100644
--- a/block.c
+++ b/block.c
@@ -2974,12 +2974,19 @@ BdrvChild *bdrv_attach_child(BlockDriverState 
*parent_bs,
 return child;
 }
 
+static void bdrv_child_free(void *opaque)
+{
+BdrvChild *c = opaque;
+
+g_free(c->name);
+g_free(c);
+}
+
 static void bdrv_remove_empty_child(BdrvChild *child)
 {
 assert(!child->bs);
 QLIST_SAFE_REMOVE(child, next);
-g_free(child->name);
-g_free(child);
+bdrv_child_free(child);
 }
 
 typedef struct BdrvAttachChildNopermState {
@@ -4852,6 +4859,37 @@ static bool should_update_child(BdrvChild *c, 
BlockDriverState *to)
 return ret;
 }
 
+/* this doesn't restore original child bs, only the child itself */
+static void bdrv_remove_backing_abort(void *opaque)
+{
+BdrvChild *c = opaque;
+BlockDriverState *parent_bs = c->opaque;
+
+QLIST_INSERT_HEAD(_bs->children, c, next);
+parent_bs->backing = c;
+}
+
+static BdrvActionDrv bdrv_remove_backing_drv = {
+.abort = bdrv_remove_backing_abort,
+.commit = bdrv_child_free,
+};
+
+__attribute__((unused))
+static void bdrv_remove_backing(BlockDriverState *bs, GSList **tran)
+{
+if (!bs->backing) {
+return;
+}
+
+if (bs->backing->bs) {
+bdrv_replace_child_safe(bs->backing, NULL, tran);
+}
+
+tran_prepend(tran, _remove_backing_drv, bs->backing);
+QLIST_SAFE_REMOVE(bs->backing, next);
+bs->backing = NULL;
+}
+
 static int bdrv_replace_node_noperm(BlockDriverState *from,
 BlockDriverState *to,
 bool auto_skip, GSList **tran, Error 
**errp)
-- 
2.21.3




[PATCH 05/21] block: refactor bdrv_child* permission functions

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
Split out non-recursive parts, and refactor as block graph transaction
action.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block.c | 79 ++---
 1 file changed, 59 insertions(+), 20 deletions(-)

diff --git a/block.c b/block.c
index 0d0f065db4..e12acd5029 100644
--- a/block.c
+++ b/block.c
@@ -48,6 +48,7 @@
 #include "qemu/timer.h"
 #include "qemu/cutils.h"
 #include "qemu/id.h"
+#include "qemu/transactions.h"
 #include "block/coroutines.h"
 
 #ifdef CONFIG_BSD
@@ -2011,6 +2012,61 @@ static void bdrv_child_perm(BlockDriverState *bs, 
BlockDriverState *child_bs,
 }
 }
 
+static void bdrv_child_set_perm_commit(void *opaque)
+{
+BdrvChild *c = opaque;
+
+c->has_backup_perm = false;
+}
+
+static void bdrv_child_set_perm_abort(void *opaque)
+{
+BdrvChild *c = opaque;
+/*
+ * We may have child->has_backup_perm unset at this point, as in case of
+ * _check_ stage of permission update failure we may _check_ not the whole
+ * subtree.  Still, _abort_ is called on the whole subtree anyway.
+ */
+if (c->has_backup_perm) {
+c->perm = c->backup_perm;
+c->shared_perm = c->backup_shared_perm;
+c->has_backup_perm = false;
+}
+}
+
+static BdrvActionDrv bdrv_child_set_pem_drv = {
+.abort = bdrv_child_set_perm_abort,
+.commit = bdrv_child_set_perm_commit,
+};
+
+/*
+ * With tran=NULL needs to be followed by direct call to either
+ * bdrv_child_set_perm_commit() or bdrv_child_set_perm_abort().
+ *
+ * With non-NUll tran needs to be followed by tran_abort() or tran_commit()
+ * instead.
+ */
+static void bdrv_child_set_perm_safe(BdrvChild *c, uint64_t perm,
+ uint64_t shared, GSList **tran)
+{
+if (!c->has_backup_perm) {
+c->has_backup_perm = true;
+c->backup_perm = c->perm;
+c->backup_shared_perm = c->shared_perm;
+}
+/*
+ * Note: it's OK if c->has_backup_perm was already set, as we can find the
+ * same c twice during check_perm procedure
+ */
+
+c->perm = perm;
+c->shared_perm = shared;
+
+if (tran) {
+tran_prepend(tran, _child_set_pem_drv, c);
+}
+}
+
 /*
  * Check whether permissions on this node can be changed in a way that
  * @cumulative_perms and @cumulative_shared_perms are the new cumulative
@@ -2276,37 +2332,20 @@ static int bdrv_child_check_perm(BdrvChild *c, 
BlockReopenQueue *q,
 return ret;
 }
 
-if (!c->has_backup_perm) {
-c->has_backup_perm = true;
-c->backup_perm = c->perm;
-c->backup_shared_perm = c->shared_perm;
-}
-/*
- * Note: it's OK if c->has_backup_perm was already set, as we can find the
- * same child twice during check_perm procedure
- */
-
-c->perm = perm;
-c->shared_perm = shared;
+bdrv_child_set_perm_safe(c, perm, shared, NULL);
 
 return 0;
 }
 
 static void bdrv_child_set_perm(BdrvChild *c)
 {
-c->has_backup_perm = false;
-
+bdrv_child_set_perm_commit(c);
 bdrv_set_perm(c->bs);
 }
 
 static void bdrv_child_abort_perm_update(BdrvChild *c)
 {
-if (c->has_backup_perm) {
-c->perm = c->backup_perm;
-c->shared_perm = c->backup_shared_perm;
-c->has_backup_perm = false;
-}
-
+bdrv_child_set_perm_abort(c);
 bdrv_abort_perm_update(c->bs);
 }
 
-- 
2.21.3




[PATCH 18/21] block: adapt bdrv_append() for inserting filters

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
bdrv_append is not very good for inserting filters: it does extra
permission update as part of bdrv_set_backing_hd(). During this update
filter may conflict with other parents of top_bs.

Instead, let's first do all graph modifications and after it update
permissions.

Note: bdrv_append() is still only works for backing-child based
filters. It's something to improve later.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block.c | 50 +++---
 1 file changed, 39 insertions(+), 11 deletions(-)

diff --git a/block.c b/block.c
index f2e714a81d..cf7b859a81 100644
--- a/block.c
+++ b/block.c
@@ -4953,22 +4953,50 @@ int bdrv_replace_node(BlockDriverState *from, 
BlockDriverState *to,
 int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
 Error **errp)
 {
-Error *local_err = NULL;
+int ret;
+GSList *tran = NULL;
+AioContext *bs_new_ctx = bdrv_get_aio_context(bs_new);
+AioContext *bs_top_ctx = bdrv_get_aio_context(bs_top);
 
-bdrv_set_backing_hd(bs_new, bs_top, _err);
-if (local_err) {
-error_propagate(errp, local_err);
-return -EPERM;
+assert(!bs_new->backing);
+
+if (bs_new_ctx != bs_top_ctx) {
+ret = bdrv_try_set_aio_context(bs_new, bs_top_ctx, NULL);
+if (ret < 0) {
+ret = bdrv_try_set_aio_context(bs_top, bs_new_ctx, errp);
+}
+if (ret < 0) {
+return ret;
+}
 }
 
-bdrv_replace_node(bs_top, bs_new, _err);
-if (local_err) {
-error_propagate(errp, local_err);
-bdrv_set_backing_hd(bs_new, NULL, _abort);
-return -EPERM;
+bs_new->backing = bdrv_attach_child_noperm(bs_new, bs_top, "backing",
+   bdrv_backing_role(bs_new),
+   , errp);
+if (!bs_new->backing) {
+ret = -EINVAL;
+goto out;
 }
 
-return 0;
+ret = bdrv_replace_node_noperm(bs_top, bs_new, true, , errp);
+if (ret < 0) {
+goto out;
+}
+
+ret = bdrv_refresh_perms(bs_new, errp);
+out:
+tran_finalize(tran, ret);
+if (ret < 0) {
+bs_new->backing = NULL;
+if (bs_new_ctx != bdrv_get_aio_context(bs_new)) {
+bdrv_try_set_aio_context(bs_new, bs_new_ctx, _abort);
+}
+if (bs_top_ctx != bdrv_get_aio_context(bs_top)) {
+bdrv_try_set_aio_context(bs_top, bs_top_ctx, _abort);
+}
+}
+
+return ret;
 }
 
 static void bdrv_delete(BlockDriverState *bs)
-- 
2.21.3




[PATCH 16/21] block: bdrv_append(): don't consume reference

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
We have too much comments for this feature. It seems better just don't
do it. Most of real users (tests don't count) have to create additional
reference.

Drop also comment in external_snapshot_prepare:
 - bdrv_append doesn't "remove" old bs in common sense, it sounds
   strange
 - the fact that bdrv_append can fail is obvious from the context
 - the fact that we must rollback all changes in transaction abort is
   known (it's the direct role of abort)

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block.c | 19 +++
 block/backup-top.c  |  1 -
 block/commit.c  |  1 +
 block/mirror.c  |  3 ---
 blockdev.c  |  4 
 tests/test-bdrv-drain.c |  2 +-
 tests/test-bdrv-graph-mod.c |  2 ++
 7 files changed, 7 insertions(+), 25 deletions(-)

diff --git a/block.c b/block.c
index 1327254b8e..a75c5b4aea 100644
--- a/block.c
+++ b/block.c
@@ -3485,11 +3485,6 @@ static BlockDriverState 
*bdrv_append_temp_snapshot(BlockDriverState *bs,
 goto out;
 }
 
-/* bdrv_append() consumes a strong reference to bs_snapshot
- * (i.e. it will call bdrv_unref() on it) even on error, so in
- * order to be able to return one, we have to increase
- * bs_snapshot's refcount here */
-bdrv_ref(bs_snapshot);
 bdrv_append(bs_snapshot, bs, _err);
 if (local_err) {
 error_propagate(errp, local_err);
@@ -4954,10 +4949,8 @@ int bdrv_replace_node(BlockDriverState *from, 
BlockDriverState *to,
  *
  * This function does not create any image files.
  *
- * bdrv_append() takes ownership of a bs_new reference and unrefs it because
- * that's what the callers commonly need. bs_new will be referenced by the old
- * parents of bs_top after bdrv_append() returns. If the caller needs to keep a
- * reference of its own, it must call bdrv_ref().
+ * Recent update: bdrv_append does NOT eat bs_new reference for now. Drop this
+ * comment several moths later.
  */
 void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
  Error **errp)
@@ -4967,20 +4960,14 @@ void bdrv_append(BlockDriverState *bs_new, 
BlockDriverState *bs_top,
 bdrv_set_backing_hd(bs_new, bs_top, _err);
 if (local_err) {
 error_propagate(errp, local_err);
-goto out;
+return;
 }
 
 bdrv_replace_node(bs_top, bs_new, _err);
 if (local_err) {
 error_propagate(errp, local_err);
 bdrv_set_backing_hd(bs_new, NULL, _abort);
-goto out;
 }
-
-/* bs_new is now referenced by its new parents, we don't need the
- * additional reference any more. */
-out:
-bdrv_unref(bs_new);
 }
 
 static void bdrv_delete(BlockDriverState *bs)
diff --git a/block/backup-top.c b/block/backup-top.c
index fe6883cc97..650ed6195c 100644
--- a/block/backup-top.c
+++ b/block/backup-top.c
@@ -222,7 +222,6 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState 
*source,
 
 bdrv_drained_begin(source);
 
-bdrv_ref(top);
 bdrv_append(top, source, _err);
 if (local_err) {
 error_prepend(_err, "Cannot append backup-top filter: ");
diff --git a/block/commit.c b/block/commit.c
index 71db7ba747..61924bcf66 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -313,6 +313,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
 commit_top_bs->total_sectors = top->total_sectors;
 
 bdrv_append(commit_top_bs, top, _err);
+bdrv_unref(commit_top_bs); /* referenced by new parents or failed */
 if (local_err) {
 commit_top_bs = NULL;
 error_propagate(errp, local_err);
diff --git a/block/mirror.c b/block/mirror.c
index 8e1ad6eceb..13f7ecc998 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -1605,9 +1605,6 @@ static BlockJob *mirror_start_job(
 bs_opaque = g_new0(MirrorBDSOpaque, 1);
 mirror_top_bs->opaque = bs_opaque;
 
-/* bdrv_append takes ownership of the mirror_top_bs reference, need to keep
- * it alive until block_job_create() succeeds even if bs has no parent. */
-bdrv_ref(mirror_top_bs);
 bdrv_drained_begin(bs);
 bdrv_append(mirror_top_bs, bs, _err);
 bdrv_drained_end(bs);
diff --git a/blockdev.c b/blockdev.c
index b5f11c524b..96c96f8ba6 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1587,10 +1587,6 @@ static void external_snapshot_prepare(BlkActionState 
*common,
 goto out;
 }
 
-/* This removes our old bs and adds the new bs. This is an operation that
- * can fail, so we need to do it in .prepare; undoing it for abort is
- * always possible. */
-bdrv_ref(state->new_bs);
 bdrv_append(state->new_bs, state->old_bs, _err);
 if (local_err) {
 error_propagate(errp, local_err);
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
index 8a29e33e00..892f7f47d8 100644
--- a/tests/test-bdrv-drain.c
+++ b/tests/test-bdrv-drain.c
@@ -1478,7 +1478,6 @@ static void test_append_to_drained(void)
 g_assert_cmpint(base_s->drain_count, ==, 1);
 

[PATCH 17/21] block: bdrv_append(): return status

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
Return int status to avoid extra error propagation schemes.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 include/block/block.h   |  4 ++--
 block.c | 15 ---
 block/commit.c  |  6 ++
 block/mirror.c  |  6 ++
 blockdev.c  |  6 +++---
 tests/test-bdrv-graph-mod.c |  6 +++---
 6 files changed, 20 insertions(+), 23 deletions(-)

diff --git a/include/block/block.h b/include/block/block.h
index ab812e14d8..6c1efce0c3 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -344,8 +344,8 @@ int bdrv_create(BlockDriver *drv, const char* filename,
 int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp);
 
 BlockDriverState *bdrv_new(void);
-void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
- Error **errp);
+int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
+Error **errp);
 int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
   Error **errp);
 
diff --git a/block.c b/block.c
index a75c5b4aea..f2e714a81d 100644
--- a/block.c
+++ b/block.c
@@ -3443,7 +3443,6 @@ static BlockDriverState 
*bdrv_append_temp_snapshot(BlockDriverState *bs,
 int64_t total_size;
 QemuOpts *opts = NULL;
 BlockDriverState *bs_snapshot = NULL;
-Error *local_err = NULL;
 int ret;
 
 /* if snapshot, we create a temporary backing file and open it
@@ -3485,9 +3484,8 @@ static BlockDriverState 
*bdrv_append_temp_snapshot(BlockDriverState *bs,
 goto out;
 }
 
-bdrv_append(bs_snapshot, bs, _err);
-if (local_err) {
-error_propagate(errp, local_err);
+ret = bdrv_append(bs_snapshot, bs, errp);
+if (ret < 0) {
 bs_snapshot = NULL;
 goto out;
 }
@@ -4952,22 +4950,25 @@ int bdrv_replace_node(BlockDriverState *from, 
BlockDriverState *to,
  * Recent update: bdrv_append does NOT eat bs_new reference for now. Drop this
  * comment several moths later.
  */
-void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
- Error **errp)
+int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
+Error **errp)
 {
 Error *local_err = NULL;
 
 bdrv_set_backing_hd(bs_new, bs_top, _err);
 if (local_err) {
 error_propagate(errp, local_err);
-return;
+return -EPERM;
 }
 
 bdrv_replace_node(bs_top, bs_new, _err);
 if (local_err) {
 error_propagate(errp, local_err);
 bdrv_set_backing_hd(bs_new, NULL, _abort);
+return -EPERM;
 }
+
+return 0;
 }
 
 static void bdrv_delete(BlockDriverState *bs)
diff --git a/block/commit.c b/block/commit.c
index 61924bcf66..b89bb20b75 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -254,7 +254,6 @@ void commit_start(const char *job_id, BlockDriverState *bs,
 BlockDriverState *iter;
 BlockDriverState *commit_top_bs = NULL;
 BlockDriverState *filtered_base;
-Error *local_err = NULL;
 int64_t base_size, top_size;
 uint64_t base_perms, iter_shared_perms;
 int ret;
@@ -312,11 +311,10 @@ void commit_start(const char *job_id, BlockDriverState 
*bs,
 
 commit_top_bs->total_sectors = top->total_sectors;
 
-bdrv_append(commit_top_bs, top, _err);
+ret = bdrv_append(commit_top_bs, top, errp);
 bdrv_unref(commit_top_bs); /* referenced by new parents or failed */
-if (local_err) {
+if (ret < 0) {
 commit_top_bs = NULL;
-error_propagate(errp, local_err);
 goto fail;
 }
 
diff --git a/block/mirror.c b/block/mirror.c
index 13f7ecc998..c3fbe3e8bd 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -1560,7 +1560,6 @@ static BlockJob *mirror_start_job(
 BlockDriverState *mirror_top_bs;
 bool target_is_backing;
 uint64_t target_perms, target_shared_perms;
-Error *local_err = NULL;
 int ret;
 
 if (granularity == 0) {
@@ -1606,12 +1605,11 @@ static BlockJob *mirror_start_job(
 mirror_top_bs->opaque = bs_opaque;
 
 bdrv_drained_begin(bs);
-bdrv_append(mirror_top_bs, bs, _err);
+ret = bdrv_append(mirror_top_bs, bs, errp);
 bdrv_drained_end(bs);
 
-if (local_err) {
+if (ret < 0) {
 bdrv_unref(mirror_top_bs);
-error_propagate(errp, local_err);
 return NULL;
 }
 
diff --git a/blockdev.c b/blockdev.c
index 96c96f8ba6..2af35d0958 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1432,6 +1432,7 @@ typedef struct ExternalSnapshotState {
 static void external_snapshot_prepare(BlkActionState *common,
   Error **errp)
 {
+int ret;
 int flags = 0;
 QDict *options = NULL;
 Error *local_err = NULL;
@@ -1587,9 +1588,8 @@ static void external_snapshot_prepare(BlkActionState 
*common,
 goto out;
 }
 
-bdrv_append(state->new_bs, state->old_bs, _err);
-if (local_err) {
-error_propagate(errp, local_err);
+ret = 

[PATCH 1/2] block: make bdrv_drop_intermediate() less wrong

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
First, permission update loop tries to do iterations transactionally,
but the whole update is not transactional: nobody roll-back successful
loop iterations when some iteration fails.

Second, in the iteration we have nested permission update:
c->klass->update_filename may point to bdrv_child_cb_update_filename()
which calls bdrv_backing_update_filename(), which may do node reopen to
RW.

Permission update system is not prepared to nested updates, at least it
has intermediate permission-update state stored in BdrvChild
structures: has_backup_perm, backup_perm and backup_shared_perm.

So, let's first do bdrv_replace_node() (which is more transactional
than open-coded update in bdrv_drop_intermediate()) and then call
update_filename() in separate. We still do not rollback changes in case
of update_filename() failure but it's not much worse than pre-patch
behavior.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block.c | 36 +++-
 1 file changed, 15 insertions(+), 21 deletions(-)

diff --git a/block.c b/block.c
index 9538af4884..bd9f4e534b 100644
--- a/block.c
+++ b/block.c
@@ -4958,36 +4958,30 @@ int bdrv_drop_intermediate(BlockDriverState *top, 
BlockDriverState *base,
 backing_file_str = base->filename;
 }
 
-QLIST_FOREACH_SAFE(c, >parents, next_parent, next) {
-/* Check whether we are allowed to switch c from top to base */
-GSList *ignore_children = g_slist_prepend(NULL, c);
-ret = bdrv_check_update_perm(base, NULL, c->perm, c->shared_perm,
- ignore_children, NULL, _err);
-g_slist_free(ignore_children);
-if (ret < 0) {
-error_report_err(local_err);
-goto exit;
-}
+bdrv_replace_node(top, base, _err);
+if (local_err) {
+error_report_err(local_err);
+goto exit;
+}
 
-/* If so, update the backing file path in the image file */
+QLIST_FOREACH_SAFE(c, >parents, next_parent, next) {
 if (c->klass->update_filename) {
 ret = c->klass->update_filename(c, base, backing_file_str,
 _err);
 if (ret < 0) {
-bdrv_abort_perm_update(base);
+/*
+ * TODO: Actually, we want to rollback all previous iterations
+ * of this loop, and (which is almost impossible) previous
+ * bdrv_replace_node()...
+ *
+ * Note, that c->klass->update_filename may lead to permission
+ * update, so it's a bad idea to call it inside permission
+ * update transaction of bdrv_replace_node.
+ */
 error_report_err(local_err);
 goto exit;
 }
 }
-
-/*
- * Do the actual switch in the in-memory graph.
- * Completes bdrv_check_update_perm() transaction internally.
- * c->frozen is false, we have checked that above.
- */
-bdrv_ref(base);
-bdrv_replace_child(c, base);
-bdrv_unref(top);
 }
 
 if (update_inherits_from) {
-- 
2.21.3




[PATCH 12/21] block: return value from bdrv_replace_node()

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
Functions with errp argument are not recommened to be void-functions.
Improve bdrv_replace_node().

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 include/block/block.h |  4 ++--
 block.c   | 14 --
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/include/block/block.h b/include/block/block.h
index db37a35cee..ab812e14d8 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -346,8 +346,8 @@ int bdrv_create_file(const char *filename, QemuOpts *opts, 
Error **errp);
 BlockDriverState *bdrv_new(void);
 void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
  Error **errp);
-void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
-   Error **errp);
+int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
+  Error **errp);
 
 int bdrv_parse_aio(const char *mode, int *flags);
 int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough);
diff --git a/block.c b/block.c
index 1b10b6fb5e..5c94f5a428 100644
--- a/block.c
+++ b/block.c
@@ -4781,14 +4781,14 @@ static bool should_update_child(BdrvChild *c, 
BlockDriverState *to)
  * With auto_skip=false the error is returned if from has a parent which should
  * not be updated.
  */
-static void bdrv_replace_node_common(BlockDriverState *from,
- BlockDriverState *to,
- bool auto_skip, Error **errp)
+static int bdrv_replace_node_common(BlockDriverState *from,
+BlockDriverState *to,
+bool auto_skip, Error **errp)
 {
+int ret = -EPERM;
 BdrvChild *c, *next;
 GSList *list = NULL, *p;
 uint64_t perm = 0, shared = BLK_PERM_ALL;
-int ret;
 
 /* Make sure that @from doesn't go away until we have successfully attached
  * all of its parents to @to. */
@@ -4844,10 +4844,12 @@ out:
 g_slist_free(list);
 bdrv_drained_end(from);
 bdrv_unref(from);
+
+return ret;
 }
 
-void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
-   Error **errp)
+int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
+  Error **errp)
 {
 return bdrv_replace_node_common(from, to, true, errp);
 }
-- 
2.21.3




[PATCH 08/21] block: use topological sort for permission update

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
Rewrite bdrv_check_perm(), bdrv_abort_perm_update() and bdrv_set_perm()
to update nodes in topological sort order instead of simple DFS. With
topologically sorted nodes, we update a node only when all its parents
already updated. With DFS it's not so.

Consider the following example:

A -+
|  |
|  v
|  B
|  |
v  |
C<-+

A is parent for B and C, B is parent for C.

Obviously, to update permissions, we should go in order A B C, so, when
we update C, all parent permissions already updated. But with current
approach (simple recursion) we can update in sequence A C B C (C is
updated twice). On first update of C, we consider old B permissions, so
doing wrong thing. If it succeed, all is OK, on second C update we will
finish with correct graph. But if the wrong thing failed, we break the
whole process for no reason (it's possible that updated B permission
will be less strict, but we will never check it).

Also new approach gives a way to simultaneously and correctly update
several nodes, we just need to run bdrv_topological_dfs() several times
to add all nodes and their subtrees into one topologically sorted list
(next patch will update bdrv_replace_node() in this manner).

Test test_parallel_perm_update() is now passing, so move it out of
debugging "if".

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block.c | 108 
 tests/test-bdrv-graph-mod.c |   4 +-
 tests/qemu-iotests/283.out  |   2 +-
 3 files changed, 88 insertions(+), 26 deletions(-)

diff --git a/block.c b/block.c
index 22498b5288..56263407e8 100644
--- a/block.c
+++ b/block.c
@@ -1973,13 +1973,17 @@ static bool bdrv_a_allow_b(BdrvChild *a, BdrvChild *b, 
Error **errp)
 return false;
 }
 
-static bool bdrv_check_parents_compliance(BlockDriverState *bs, Error **errp)
+static bool bdrv_check_parents_compliance(BlockDriverState *bs,
+  GSList *ignore_children,
+  Error **errp)
 {
 BdrvChild *a, *b;
 
 QLIST_FOREACH(a, >parents, next_parent) {
 QLIST_FOREACH(b, >parents, next_parent) {
-if (a == b) {
+if (a == b || g_slist_find(ignore_children, a) ||
+g_slist_find(ignore_children, b))
+{
 continue;
 }
 
@@ -2012,6 +2016,29 @@ static void bdrv_child_perm(BlockDriverState *bs, 
BlockDriverState *child_bs,
 }
 }
 
+static GSList *bdrv_topological_dfs(GSList *list, GHashTable *found,
+BlockDriverState *bs)
+{
+BdrvChild *child;
+g_autoptr(GHashTable) local_found = NULL;
+
+if (!found) {
+assert(!list);
+found = local_found = g_hash_table_new(NULL, NULL);
+}
+
+if (g_hash_table_contains(found, bs)) {
+return list;
+}
+g_hash_table_add(found, bs);
+
+QLIST_FOREACH(child, >children, next) {
+list = bdrv_topological_dfs(list, found, child->bs);
+}
+
+return g_slist_prepend(list, bs);
+}
+
 static void bdrv_child_set_perm_commit(void *opaque)
 {
 BdrvChild *c = opaque;
@@ -2076,14 +2103,13 @@ static void bdrv_child_set_perm_safe(BdrvChild *c, 
uint64_t perm,
  * A call to this function must always be followed by a call to bdrv_set_perm()
  * or bdrv_abort_perm_update().
  */
-static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
-   uint64_t cumulative_perms,
-   uint64_t cumulative_shared_perms,
-   GSList *ignore_children, Error **errp)
+static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
+uint64_t cumulative_perms,
+uint64_t cumulative_shared_perms,
+GSList *ignore_children, Error **errp)
 {
 BlockDriver *drv = bs->drv;
 BdrvChild *c;
-int ret;
 
 /* Write permissions never work with read-only images */
 if ((cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) &&
@@ -2128,8 +2154,8 @@ static int bdrv_check_perm(BlockDriverState *bs, 
BlockReopenQueue *q,
 }
 
 if (drv->bdrv_check_perm) {
-ret = drv->bdrv_check_perm(bs, cumulative_perms,
-   cumulative_shared_perms, errp);
+int ret = drv->bdrv_check_perm(bs, cumulative_perms,
+   cumulative_shared_perms, errp);
 if (ret < 0) {
 return ret;
 }
@@ -2144,21 +2170,43 @@ static int bdrv_check_perm(BlockDriverState *bs, 
BlockReopenQueue *q,
 /* Check all children */
 QLIST_FOREACH(c, >children, next) {
 uint64_t cur_perm, cur_shared;
-GSList *cur_ignore_children;
 
 bdrv_child_perm(bs, c->bs, c, c->role, q,
 cumulative_perms, cumulative_shared_perms,
 _perm, _shared);
+bdrv_child_set_perm_safe(c, 

[PATCH 14/21] block: add bdrv_attach_child_noperm() transaction action

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
The code partly duplicates bdrv_root_attach_child() and
bdrv_attach_child(). Still refactoring these two functions by renaming
them to *_common with new noperm argument is more complicating. When
all operations moved to new graph update paradigm (update permissions
only on updated graph) all duplications should leave.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block.c | 94 ++---
 1 file changed, 90 insertions(+), 4 deletions(-)

diff --git a/block.c b/block.c
index 08501350b7..5f6ad1d016 100644
--- a/block.c
+++ b/block.c
@@ -2974,16 +2974,102 @@ BdrvChild *bdrv_attach_child(BlockDriverState 
*parent_bs,
 return child;
 }
 
-static void bdrv_detach_child(BdrvChild *child)
+static void bdrv_remove_empty_child(BdrvChild *child)
 {
+assert(!child->bs);
 QLIST_SAFE_REMOVE(child, next);
-
-bdrv_replace_child(child, NULL);
-
 g_free(child->name);
 g_free(child);
 }
 
+typedef struct BdrvAttachChildNopermState {
+BdrvChild *child;
+AioContext *old_aio_context; /* NULL if not changed */
+} BdrvAttachChildNopermState;
+
+static void bdrv_attach_child_noperm_abort(void *opaque)
+{
+BdrvAttachChildNopermState *s = opaque;
+BlockDriverState *bs = s->child->bs;
+
+bdrv_replace_child_noperm(s->child, NULL);
+bdrv_remove_empty_child(s->child);
+
+/*
+ * refcnt was positive prior to bdrv_ref() in bdrv_attach_child_noperm(),
+ * so bs should not be deleted now.
+ */
+assert(bs->refcnt > 1);
+bdrv_unref(bs);
+if (s->old_aio_context) {
+bdrv_try_set_aio_context(bs, s->old_aio_context, NULL);
+}
+}
+
+static BdrvActionDrv bdrv_attach_child_noperm_drv = {
+.abort = bdrv_attach_child_noperm_abort,
+.clean = g_free,
+};
+
+__attribute__((unused))
+static BdrvChild *bdrv_attach_child_noperm(BlockDriverState *parent_bs,
+   BlockDriverState *child_bs,
+   const char *child_name,
+   BdrvChildRole child_role,
+   GSList **tran,
+   Error **errp)
+{
+int ret;
+BdrvChild *child;
+uint64_t perm, shared_perm;
+AioContext *parent_ctx = bdrv_get_aio_context(parent_bs);
+AioContext *child_ctx = bdrv_get_aio_context(child_bs);
+BdrvAttachChildNopermState *s;
+
+if (child_ctx != parent_ctx) {
+ret = bdrv_try_set_aio_context(child_bs, parent_ctx, errp);
+if (ret < 0) {
+return NULL;
+}
+}
+
+bdrv_get_cumulative_perm(parent_bs, , _perm);
+
+assert(parent_bs->drv);
+bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL,
+perm, shared_perm, , _perm);
+
+child = g_new(BdrvChild, 1);
+*child = (BdrvChild) {
+.bs = NULL,
+.name   = g_strdup(child_name),
+.klass  = _of_bds,
+.role   = child_role,
+.perm   = perm,
+.shared_perm= shared_perm,
+.opaque = parent_bs,
+};
+bdrv_ref(child_bs);
+bdrv_replace_child_noperm(child, child_bs);
+
+QLIST_INSERT_HEAD(_bs->children, child, next);
+
+s = g_new(BdrvAttachChildNopermState, 1);
+*s = (BdrvAttachChildNopermState) {
+.child = child,
+.old_aio_context = child_ctx == parent_ctx ? NULL : child_ctx,
+};
+tran_prepend(tran, _attach_child_noperm_drv, s);
+
+return child;
+}
+
+static void bdrv_detach_child(BdrvChild *child)
+{
+bdrv_replace_child(child, NULL);
+bdrv_remove_empty_child(child);
+}
+
 /* Callers must ensure that child->frozen is false. */
 void bdrv_root_unref_child(BdrvChild *child)
 {
-- 
2.21.3




[PATCH 07/21] block: inline bdrv_child_*() permission functions calls

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
Each of them has only one caller. Open-coding simplifies further
pemission-update system changes.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block.c | 59 +
 1 file changed, 17 insertions(+), 42 deletions(-)

diff --git a/block.c b/block.c
index a9e4d2b57c..22498b5288 100644
--- a/block.c
+++ b/block.c
@@ -1893,11 +1893,11 @@ static int bdrv_fill_options(QDict **options, const 
char *filename,
 return 0;
 }
 
-static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
- uint64_t perm, uint64_t shared,
- GSList *ignore_children, Error **errp);
-static void bdrv_child_abort_perm_update(BdrvChild *c);
-static void bdrv_child_set_perm(BdrvChild *c);
+static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q,
+  uint64_t new_used_perm,
+  uint64_t new_shared_perm,
+  GSList *ignore_children,
+  Error **errp);
 
 typedef struct BlockReopenQueueEntry {
  bool prepared;
@@ -2144,15 +2144,21 @@ static int bdrv_check_perm(BlockDriverState *bs, 
BlockReopenQueue *q,
 /* Check all children */
 QLIST_FOREACH(c, >children, next) {
 uint64_t cur_perm, cur_shared;
+GSList *cur_ignore_children;
 
 bdrv_child_perm(bs, c->bs, c, c->role, q,
 cumulative_perms, cumulative_shared_perms,
 _perm, _shared);
-ret = bdrv_child_check_perm(c, q, cur_perm, cur_shared, 
ignore_children,
-errp);
+
+cur_ignore_children = g_slist_prepend(g_slist_copy(ignore_children), 
c);
+ret = bdrv_check_update_perm(c->bs, q, cur_perm, cur_shared,
+ cur_ignore_children, errp);
+g_slist_free(cur_ignore_children);
 if (ret < 0) {
 return ret;
 }
+
+bdrv_child_set_perm_safe(c, cur_perm, cur_shared, NULL);
 }
 
 return 0;
@@ -2179,7 +2185,8 @@ static void bdrv_abort_perm_update(BlockDriverState *bs)
 }
 
 QLIST_FOREACH(c, >children, next) {
-bdrv_child_abort_perm_update(c);
+bdrv_child_set_perm_abort(c);
+bdrv_abort_perm_update(c->bs);
 }
 }
 
@@ -2208,7 +2215,8 @@ static void bdrv_set_perm(BlockDriverState *bs)
 
 /* Update all children */
 QLIST_FOREACH(c, >children, next) {
-bdrv_child_set_perm(c);
+bdrv_child_set_perm_commit(c);
+bdrv_set_perm(c->bs);
 }
 }
 
@@ -2316,39 +2324,6 @@ static int bdrv_check_update_perm(BlockDriverState *bs, 
BlockReopenQueue *q,
ignore_children, errp);
 }
 
-/* Needs to be followed by a call to either bdrv_child_set_perm() or
- * bdrv_child_abort_perm_update(). */
-static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
- uint64_t perm, uint64_t shared,
- GSList *ignore_children, Error **errp)
-{
-int ret;
-
-ignore_children = g_slist_prepend(g_slist_copy(ignore_children), c);
-ret = bdrv_check_update_perm(c->bs, q, perm, shared, ignore_children, 
errp);
-g_slist_free(ignore_children);
-
-if (ret < 0) {
-return ret;
-}
-
-bdrv_child_set_perm_safe(c, perm, shared, NULL);
-
-return 0;
-}
-
-static void bdrv_child_set_perm(BdrvChild *c)
-{
-bdrv_child_set_perm_commit(c);
-bdrv_set_perm(c->bs);
-}
-
-static void bdrv_child_abort_perm_update(BdrvChild *c)
-{
-bdrv_child_set_perm_abort(c);
-bdrv_abort_perm_update(c->bs);
-}
-
 static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp)
 {
 int ret;
-- 
2.21.3




[PATCH RFC 00/21] block: update graph permissions update

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
Hi all!

Here is a proposal of updating graph changing procedures.

The thing brought me here is a question about "activating" filters after
insertion, which is done in mirror_top and backup_top. The problem is
that we can't simply avoid permission conflict when inserting the
filter: during insertion old permissions of relations to be removed
conflicting with new permissions of new created relations. And current
solution is supporting additional "inactive" mode for the filter when it
doesn't require any permissions.

I suggest to change the order of operations: let's first do all graph
relations modifications and then refresh permissions. Of course we'll
need a way to restore old graph if refresh fails.

Another problem with permission update is that we update permissions in
order of DFS which is not always correct. Better is update node when all
its parents already updated and require correct permissions. This needs
a topological sort of nodes prior to permission update, see more in
patches later.

Key patches here:

01,02 - add failing tests to illustrate conceptual problems of current
permission update system.
[Here is side suggestion: we usually add tests after fix, so careful
 reviewer has to change order of patches to check that test fails before
 fix. I add tests in the way the may be simply executed but not yet take
 part in make check. It seems more native: first show the problem, then
 fix it. And when fixed, make tests available for make check]

08 - toplogical sort implemented for permission update, one of new tests
now pass

13 - improve bdrv_replace_node. second new test now pass

21 - drop .active field and activation procedure for backup-top!

Series marked as RFC as they are non-complete. Some things like
bdrv_replace_node() and bdrv_append() are moved into new paradigm
(update graph first) some not (like bdrv_reopen_multiple()). Because of
it we have to still support old interfaces (like ignore_children).

Still, I'd be very grateful for some feedback before investigating more
time to this thing.

Note, that this series does nothing with another graph-update problem
discussed under "[PATCH RFC 0/5] Fix accidental crash in iotest 30".


The series based on block-next Max's branch and can be found here:

git: https://src.openvz.org/scm/~vsementsov/qemu.git
tag: up-block-topologic-perm-v1

Vladimir Sementsov-Ogievskiy (21):
  tests/test-bdrv-graph-mod: add test_parallel_exclusive_write
  tests/test-bdrv-graph-mod: add test_parallel_perm_update
  util: add transactions.c
  block: bdrv_refresh_perms: check parents compliance
  block: refactor bdrv_child* permission functions
  block: rewrite bdrv_child_try_set_perm() using bdrv_refresh_perms()
  block: inline bdrv_child_*() permission functions calls
  block: use topological sort for permission update
  block: add bdrv_drv_set_perm transaction action
  block: add bdrv_list_* permission update functions
  block: add bdrv_replace_child_safe() transaction action
  block: return value from bdrv_replace_node()
  block: fix bdrv_replace_node_common
  block: add bdrv_attach_child_noperm() transaction action
  block: split out bdrv_replace_node_noperm()
  block: bdrv_append(): don't consume reference
  block: bdrv_append(): return status
  block: adapt bdrv_append() for inserting filters
  block: add bdrv_remove_backing transaction action
  block: introduce bdrv_drop_filter()
  block/backup-top: drop .active

 include/block/block.h   |   9 +-
 include/qemu/transactions.h |  46 +++
 block.c | 789 
 block/backup-top.c  |  39 +-
 block/commit.c  |   7 +-
 block/mirror.c  |   9 +-
 blockdev.c  |  10 +-
 tests/test-bdrv-drain.c |   2 +-
 tests/test-bdrv-graph-mod.c | 122 +-
 util/transactions.c |  81 
 tests/qemu-iotests/283.out  |   2 +-
 util/meson.build|   1 +
 12 files changed, 872 insertions(+), 245 deletions(-)
 create mode 100644 include/qemu/transactions.h
 create mode 100644 util/transactions.c

-- 
2.21.3




[PATCH 10/21] block: add bdrv_list_* permission update functions

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
Add new interface, allowing use of existing node list. It will be used
to fix bdrv_replace_node() in the following commit.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block.c | 112 ++--
 1 file changed, 76 insertions(+), 36 deletions(-)

diff --git a/block.c b/block.c
index 799c475dda..d799afeedd 100644
--- a/block.c
+++ b/block.c
@@ -2154,7 +2154,8 @@ static int bdrv_drv_set_perm(BlockDriverState *bs, 
uint64_t perm,
 static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
 uint64_t cumulative_perms,
 uint64_t cumulative_shared_perms,
-GSList *ignore_children, Error **errp)
+GSList *ignore_children,
+GSList **tran, Error **errp)
 {
 int ret;
 BlockDriver *drv = bs->drv;
@@ -2202,7 +2203,7 @@ static int bdrv_node_check_perm(BlockDriverState *bs, 
BlockReopenQueue *q,
 return 0;
 }
 
-ret = bdrv_drv_set_perm(bs, cumulative_perms, cumulative_shared_perms, 
NULL,
+ret = bdrv_drv_set_perm(bs, cumulative_perms, cumulative_shared_perms, 
tran,
 errp);
 if (ret < 0) {
 return ret;
@@ -2221,36 +,53 @@ static int bdrv_node_check_perm(BlockDriverState *bs, 
BlockReopenQueue *q,
 bdrv_child_perm(bs, c->bs, c, c->role, q,
 cumulative_perms, cumulative_shared_perms,
 _perm, _shared);
-bdrv_child_set_perm_safe(c, cur_perm, cur_shared, NULL);
+bdrv_child_set_perm_safe(c, cur_perm, cur_shared, tran);
 }
 
 return 0;
 }
 
-static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
-   uint64_t cumulative_perms,
-   uint64_t cumulative_shared_perms,
-   GSList *ignore_children, Error **errp)
+/*
+ * If use_cumulative_perms is true, use cumulative_perms and
+ * cumulative_shared_perms for first element of the list. Otherwise just 
refresh
+ * all permissions.
+ */
+static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q,
+  bool use_cumulative_perms,
+  uint64_t cumulative_perms,
+  uint64_t cumulative_shared_perms,
+  GSList *ignore_children,
+  GSList **tran, Error **errp)
 {
 int ret;
-BlockDriverState *root = bs;
-g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, root);
+BlockDriverState *bs;
 
-for ( ; list; list = list->next) {
+if (use_cumulative_perms) {
 bs = list->data;
 
-if (bs != root) {
-if (!bdrv_check_parents_compliance(bs, ignore_children, errp)) {
-return -EINVAL;
-}
+ret = bdrv_node_check_perm(bs, q, cumulative_perms,
+   cumulative_shared_perms,
+   ignore_children, tran, errp);
+if (ret < 0) {
+return ret;
+}
+
+list = list->next;
+}
 
-bdrv_get_cumulative_perm(bs, _perms,
- _shared_perms);
+for ( ; list; list = list->next) {
+bs = list->data;
+
+if (!bdrv_check_parents_compliance(bs, ignore_children, errp)) {
+return -EINVAL;
 }
 
+bdrv_get_cumulative_perm(bs, _perms,
+ _shared_perms);
+
 ret = bdrv_node_check_perm(bs, q, cumulative_perms,
cumulative_shared_perms,
-   ignore_children, errp);
+   ignore_children, tran, errp);
 if (ret < 0) {
 return ret;
 }
@@ -2259,6 +2277,22 @@ static int bdrv_check_perm(BlockDriverState *bs, 
BlockReopenQueue *q,
 return 0;
 }
 
+static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
+   uint64_t cumulative_perms,
+   uint64_t cumulative_shared_perms,
+   GSList *ignore_children, Error **errp)
+{
+g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs);
+return bdrv_check_perm_common(list, q, true, cumulative_perms,
+  cumulative_shared_perms, ignore_children,
+  NULL, errp);
+}
+
+static int bdrv_list_check_perm(GSList *list, GSList **tran, Error **errp)
+{
+return bdrv_check_perm_common(list, NULL, false, 0, 0, NULL, tran, errp);
+}
+
 /*
  * Notifies drivers that after a previous bdrv_check_perm() call, the
  * permission update is not performed and any preparations made for it (e.g.
@@ -2280,15 +2314,19 @@ static void 
bdrv_node_abort_perm_update(BlockDriverState *bs)
 }
 }
 
-static void 

[PATCH 03/21] util: add transactions.c

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
Add simple transaction API to use in further update of block graph
operations.

Supposed usage is:

- "prepare" is main function of the action and it should make the main
  effect of the action to be visible for the following actions, keeping
  possibility of roll-back, saving necessary things in action state,
  which is prepended to the list. So, driver struct doesn't include
  "prepare" field, as it is supposed to be called directly.

- commit/rollback is supposed to be called for the list of action
  states, to commit/rollback all the actions in reverse order

- When possible "commit" should not make visible effect for other
  actions, which make possible transparent logical interaction between
  actions.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 include/qemu/transactions.h | 46 +
 util/transactions.c | 81 +
 util/meson.build|  1 +
 3 files changed, 128 insertions(+)
 create mode 100644 include/qemu/transactions.h
 create mode 100644 util/transactions.c

diff --git a/include/qemu/transactions.h b/include/qemu/transactions.h
new file mode 100644
index 00..db8fced65f
--- /dev/null
+++ b/include/qemu/transactions.h
@@ -0,0 +1,46 @@
+/*
+ * Simple transactions API
+ *
+ * Copyright (c) 2020 Virtuozzo International GmbH.
+ *
+ * Author:
+ *  Sementsov-Ogievskiy Vladimir 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef QEMU_TRANSACTIONS_H
+#define QEMU_TRANSACTIONS_H
+
+#include 
+
+typedef struct BdrvActionDrv {
+void (*abort)(void *opeque);
+void (*commit)(void *opeque);
+void (*clean)(void *opeque);
+} BdrvActionDrv;
+
+void tran_prepend(GSList **list, BdrvActionDrv *drv, void *opaque);
+void tran_abort(GSList *backup);
+void tran_commit(GSList *backup);
+static inline void tran_finalize(GSList *backup, int ret)
+{
+if (ret < 0) {
+tran_abort(backup);
+} else {
+tran_commit(backup);
+}
+}
+
+#endif /* QEMU_TRANSACTIONS_H */
diff --git a/util/transactions.c b/util/transactions.c
new file mode 100644
index 00..845d77fc16
--- /dev/null
+++ b/util/transactions.c
@@ -0,0 +1,81 @@
+/*
+ * Simple transactions API
+ *
+ * Copyright (c) 2020 Virtuozzo International GmbH.
+ *
+ * Author:
+ *  Sementsov-Ogievskiy Vladimir 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "qemu/osdep.h"
+
+#include "qemu/transactions.h"
+
+typedef struct BdrvAction {
+BdrvActionDrv *drv;
+void *opaque;
+} BdrvAction;
+
+void tran_prepend(GSList **list, BdrvActionDrv *drv, void *opaque)
+{
+BdrvAction *act;
+
+act = g_new(BdrvAction, 1);
+*act = (BdrvAction) {
+.drv = drv,
+.opaque = opaque
+};
+
+*list = g_slist_prepend(*list, act);
+}
+
+void tran_abort(GSList *list)
+{
+GSList *p;
+
+for (p = list; p != NULL; p = p->next) {
+BdrvAction *act = p->data;
+
+if (act->drv->abort) {
+act->drv->abort(act->opaque);
+}
+
+if (act->drv->clean) {
+act->drv->clean(act->opaque);
+}
+}
+
+g_slist_free_full(list, g_free);
+}
+
+void tran_commit(GSList *list)
+{
+GSList *p;
+
+for (p = list; p != NULL; p = p->next) {
+BdrvAction *act = p->data;
+
+if (act->drv->commit) {
+act->drv->commit(act->opaque);
+}
+
+if (act->drv->clean) {
+act->drv->clean(act->opaque);
+}
+}
+
+g_slist_free_full(list, g_free);
+}
diff --git a/util/meson.build b/util/meson.build
index f359af0d46..8c7c28bd40 100644
--- a/util/meson.build
+++ b/util/meson.build
@@ -41,6 +41,7 @@ util_ss.add(files('qsp.c'))
 util_ss.add(files('range.c'))
 util_ss.add(files('stats64.c'))
 util_ss.add(files('systemd.c'))

[PATCH 09/21] block: add bdrv_drv_set_perm transaction action

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
Refactor calling driver callbacks to a separate transaction action to
be used later.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block.c | 71 -
 1 file changed, 55 insertions(+), 16 deletions(-)

diff --git a/block.c b/block.c
index 56263407e8..799c475dda 100644
--- a/block.c
+++ b/block.c
@@ -2094,6 +2094,54 @@ static void bdrv_child_set_perm_safe(BdrvChild *c, 
uint64_t perm,
 }
 }
 
+static void bdrv_drv_set_perm_commit(void *opaque)
+{
+BlockDriverState *bs = opaque;
+uint64_t cumulative_perms, cumulative_shared_perms;
+
+if (bs->drv->bdrv_set_perm) {
+bdrv_get_cumulative_perm(bs, _perms,
+ _shared_perms);
+bs->drv->bdrv_set_perm(bs, cumulative_perms, cumulative_shared_perms);
+}
+}
+
+static void bdrv_drv_set_perm_abort(void *opaque)
+{
+BlockDriverState *bs = opaque;
+
+if (bs->drv->bdrv_abort_perm_update) {
+bs->drv->bdrv_abort_perm_update(bs);
+}
+}
+
+BdrvActionDrv bdrv_drv_set_perm_drv = {
+.abort = bdrv_drv_set_perm_abort,
+.commit = bdrv_drv_set_perm_commit,
+};
+
+static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm,
+ uint64_t shared_perm, GSList **tran,
+ Error **errp)
+{
+if (!bs->drv) {
+return 0;
+}
+
+if (bs->drv->bdrv_check_perm) {
+int ret = bs->drv->bdrv_check_perm(bs, perm, shared_perm, errp);
+if (ret < 0) {
+return ret;
+}
+}
+
+if (tran) {
+tran_prepend(tran, _drv_set_perm_drv, bs);
+}
+
+return 0;
+}
+
 /*
  * Check whether permissions on this node can be changed in a way that
  * @cumulative_perms and @cumulative_shared_perms are the new cumulative
@@ -2108,6 +2156,7 @@ static int bdrv_node_check_perm(BlockDriverState *bs, 
BlockReopenQueue *q,
 uint64_t cumulative_shared_perms,
 GSList *ignore_children, Error **errp)
 {
+int ret;
 BlockDriver *drv = bs->drv;
 BdrvChild *c;
 
@@ -2153,12 +2202,10 @@ static int bdrv_node_check_perm(BlockDriverState *bs, 
BlockReopenQueue *q,
 return 0;
 }
 
-if (drv->bdrv_check_perm) {
-int ret = drv->bdrv_check_perm(bs, cumulative_perms,
-   cumulative_shared_perms, errp);
-if (ret < 0) {
-return ret;
-}
+ret = bdrv_drv_set_perm(bs, cumulative_perms, cumulative_shared_perms, 
NULL,
+errp);
+if (ret < 0) {
+return ret;
 }
 
 /* Drivers that never have children can omit .bdrv_child_perm() */
@@ -2226,9 +2273,7 @@ static void bdrv_node_abort_perm_update(BlockDriverState 
*bs)
 return;
 }
 
-if (drv->bdrv_abort_perm_update) {
-drv->bdrv_abort_perm_update(bs);
-}
+bdrv_drv_set_perm_abort(bs);
 
 QLIST_FOREACH(c, >children, next) {
 bdrv_child_set_perm_abort(c);
@@ -2246,7 +2291,6 @@ static void bdrv_abort_perm_update(BlockDriverState *bs)
 
 static void bdrv_node_set_perm(BlockDriverState *bs)
 {
-uint64_t cumulative_perms, cumulative_shared_perms;
 BlockDriver *drv = bs->drv;
 BdrvChild *c;
 
@@ -2254,12 +2298,7 @@ static void bdrv_node_set_perm(BlockDriverState *bs)
 return;
 }
 
-bdrv_get_cumulative_perm(bs, _perms, _shared_perms);
-
-/* Update this node */
-if (drv->bdrv_set_perm) {
-drv->bdrv_set_perm(bs, cumulative_perms, cumulative_shared_perms);
-}
+bdrv_drv_set_perm_commit(bs);
 
 /* Drivers that never have children can omit .bdrv_child_perm() */
 if (!drv->bdrv_child_perm) {
-- 
2.21.3




[PATCH 11/21] block: add bdrv_replace_child_safe() transaction action

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
To be used in the following commit.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block.c | 54 ++
 1 file changed, 54 insertions(+)

diff --git a/block.c b/block.c
index d799afeedd..1b10b6fb5e 100644
--- a/block.c
+++ b/block.c
@@ -82,6 +82,9 @@ static BlockDriverState *bdrv_open_inherit(const char 
*filename,
BdrvChildRole child_role,
Error **errp);
 
+static void bdrv_replace_child_noperm(BdrvChild *child,
+  BlockDriverState *new_bs);
+
 /* If non-zero, use only whitelisted block drivers */
 static int use_bdrv_whitelist;
 
@@ -2142,6 +2145,57 @@ static int bdrv_drv_set_perm(BlockDriverState *bs, 
uint64_t perm,
 return 0;
 }
 
+typedef struct BdrvReplaceChildState {
+BdrvChild *child;
+BlockDriverState *old_bs;
+} BdrvReplaceChildState;
+
+static void bdrv_replace_child_commit(void *opaque)
+{
+BdrvReplaceChildState *s = opaque;
+
+bdrv_unref(s->old_bs);
+}
+
+static void bdrv_replace_child_abort(void *opaque)
+{
+BdrvReplaceChildState *s = opaque;
+BlockDriverState *new_bs = s->child->bs;
+
+/* old_bs reference is transparently moved from @s to @s->child */
+bdrv_replace_child_noperm(s->child, s->old_bs);
+bdrv_unref(new_bs);
+}
+
+static BdrvActionDrv bdrv_replace_child_drv = {
+.commit = bdrv_replace_child_commit,
+.abort = bdrv_replace_child_abort,
+.clean = g_free,
+};
+
+/*
+ * bdrv_replace_child_safe
+ *
+ * Note: real unref of old_bs is done only on commit.
+ */
+__attribute__((unused))
+static void bdrv_replace_child_safe(BdrvChild *child, BlockDriverState *new_bs,
+GSList **tran)
+{
+BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1);
+*s = (BdrvReplaceChildState) {
+.child = child,
+.old_bs = child->bs,
+};
+tran_prepend(tran, _replace_child_drv, s);
+
+if (new_bs) {
+bdrv_ref(new_bs);
+}
+bdrv_replace_child_noperm(child, new_bs);
+/* old_bs reference is transparently moved from @child to @s */
+}
+
 /*
  * Check whether permissions on this node can be changed in a way that
  * @cumulative_perms and @cumulative_shared_perms are the new cumulative
-- 
2.21.3




[PATCH 02/21] tests/test-bdrv-graph-mod: add test_parallel_perm_update

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
Add test to show that simple DFS recursion order is not correct for
permission update. Correct order is topological-sort order, which will
be introduced later.

Consider the block driver which has two filter children: one active
with exclusive write access and one inactive with no specific
permissions.

And, these two children has a common base child, like this:

┌─┐ ┌──┐
│ fl2 │ ◀── │ top  │
└─┘ └──┘
  │   │
  │   │ w
  │   ▼
  │ ┌──┐
  │ │ fl1  │
  │ └──┘
  │   │
  │   │ w
  │   ▼
  │ ┌──┐
  └───▶ │ base │
└──┘

So, exclusive write is propagated.

Assume, we want to make fl2 active instead of fl1.
So, we set some option for top driver and do permission update.

If permission update (remember, it's DFS) goes first through
top->fl1->base branch it will succeed: it firstly drop exclusive write
permissions and than apply them for another BdrvChildren.
But if permission update goes first through top->fl2->base branch it
will fail, as when we try to update fl2->base child, old not yet
updated fl1->base child will be in conflict.

Now test fails, so it runs only with -d flag. To run do

  ./test-bdrv-graph-mod -d -p /bdrv-graph-mod/parallel-perm-update

from /tests.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 tests/test-bdrv-graph-mod.c | 64 +
 1 file changed, 64 insertions(+)

diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c
index 3b9e6f242f..27e3361a60 100644
--- a/tests/test-bdrv-graph-mod.c
+++ b/tests/test-bdrv-graph-mod.c
@@ -232,6 +232,68 @@ static void test_parallel_exclusive_write(void)
 bdrv_unref(top);
 }
 
+static void write_to_file_perms(BlockDriverState *bs, BdrvChild *c,
+ BdrvChildRole role,
+ BlockReopenQueue *reopen_queue,
+ uint64_t perm, uint64_t shared,
+ uint64_t *nperm, uint64_t *nshared)
+{
+if (bs->file && c == bs->file) {
+*nperm = BLK_PERM_WRITE;
+*nshared = BLK_PERM_ALL & ~BLK_PERM_WRITE;
+} else {
+*nperm = 0;
+*nshared = BLK_PERM_ALL;
+}
+}
+
+static BlockDriver bdrv_write_to_file = {
+.format_name = "tricky-perm",
+.bdrv_child_perm = write_to_file_perms,
+};
+
+static void test_parallel_perm_update(void)
+{
+BlockDriverState *top = no_perm_node("top");
+BlockDriverState *tricky =
+bdrv_new_open_driver(_write_to_file, "tricky", BDRV_O_RDWR,
+ _abort);
+BlockDriverState *base = no_perm_node("base");
+BlockDriverState *fl1 = pass_through_node("fl1");
+BlockDriverState *fl2 = pass_through_node("fl2");
+BdrvChild *c_fl1, *c_fl2;
+
+bdrv_attach_child(top, tricky, "file", _of_bds, BDRV_CHILD_DATA,
+  _abort);
+c_fl1 = bdrv_attach_child(tricky, fl1, "first", _of_bds,
+  BDRV_CHILD_FILTERED, _abort);
+c_fl2 = bdrv_attach_child(tricky, fl2, "second", _of_bds,
+  BDRV_CHILD_FILTERED, _abort);
+bdrv_attach_child(fl1, base, "backing", _of_bds, BDRV_CHILD_FILTERED,
+  _abort);
+bdrv_attach_child(fl2, base, "backing", _of_bds, BDRV_CHILD_FILTERED,
+  _abort);
+bdrv_ref(base);
+
+/* Select fl1 as first child to be active */
+tricky->file = c_fl1;
+bdrv_child_refresh_perms(top, top->children.lh_first, _abort);
+
+assert(c_fl1->perm & BLK_PERM_WRITE);
+
+/* Now, try to switch active child and update permissions */
+tricky->file = c_fl2;
+bdrv_child_refresh_perms(top, top->children.lh_first, _abort);
+
+assert(c_fl2->perm & BLK_PERM_WRITE);
+
+/* Switch once more, to not care about real child order in the list */
+tricky->file = c_fl1;
+bdrv_child_refresh_perms(top, top->children.lh_first, _abort);
+
+assert(c_fl1->perm & BLK_PERM_WRITE);
+}
+
 int main(int argc, char *argv[])
 {
 int i;
@@ -256,6 +318,8 @@ int main(int argc, char *argv[])
 if (debug) {
 g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write",
 test_parallel_exclusive_write);
+g_test_add_func("/bdrv-graph-mod/parallel-perm-update",
+test_parallel_perm_update);
 }
 
 return g_test_run();
-- 
2.21.3




[PATCH 04/21] block: bdrv_refresh_perms: check parents compliance

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
Add additional check that node parents do not interfere with each
other. This should not hurt existing callers and allows in further
patch use bdrv_refresh_perms() to update a subtree of changed
BdrvChild (check that change is correct).

New check will substitute bdrv_check_update_perm() in following
permissions refactoring, so keep error messages the same to avoid
unit test result changes.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block.c | 62 -
 1 file changed, 53 insertions(+), 9 deletions(-)

diff --git a/block.c b/block.c
index 0dd28f0902..0d0f065db4 100644
--- a/block.c
+++ b/block.c
@@ -1945,6 +1945,56 @@ bool bdrv_is_writable(BlockDriverState *bs)
 return bdrv_is_writable_after_reopen(bs, NULL);
 }
 
+static char *bdrv_child_user_desc(BdrvChild *c)
+{
+if (c->klass->get_parent_desc) {
+return c->klass->get_parent_desc(c);
+}
+
+return g_strdup("another user");
+}
+
+static bool bdrv_a_allow_b(BdrvChild *a, BdrvChild *b, Error **errp)
+{
+g_autofree char *user = NULL;
+g_autofree char *perm_names = NULL;
+
+if ((b->perm & a->shared_perm) == b->perm) {
+return true;
+}
+
+perm_names = bdrv_perm_names(b->perm & ~a->shared_perm);
+user = bdrv_child_user_desc(a);
+error_setg(errp, "Conflicts with use by %s as '%s', which does not "
+   "allow '%s' on %s",
+   user, a->name, perm_names, bdrv_get_node_name(b->bs));
+
+return false;
+}
+
+static bool bdrv_check_parents_compliance(BlockDriverState *bs, Error **errp)
+{
+BdrvChild *a, *b;
+
+QLIST_FOREACH(a, >parents, next_parent) {
+QLIST_FOREACH(b, >parents, next_parent) {
+if (a == b) {
+continue;
+}
+
+if (!bdrv_a_allow_b(a, b, errp)) {
+return false;
+}
+
+if (!bdrv_a_allow_b(b, a, errp)) {
+return false;
+}
+}
+}
+
+return true;
+}
+
 static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs,
 BdrvChild *c, BdrvChildRole role,
 BlockReopenQueue *reopen_queue,
@@ -2122,15 +2172,6 @@ void bdrv_get_cumulative_perm(BlockDriverState *bs, 
uint64_t *perm,
 *shared_perm = cumulative_shared_perms;
 }
 
-static char *bdrv_child_user_desc(BdrvChild *c)
-{
-if (c->klass->get_parent_desc) {
-return c->klass->get_parent_desc(c);
-}
-
-return g_strdup("another user");
-}
-
 char *bdrv_perm_names(uint64_t perm)
 {
 struct perm_name {
@@ -2274,6 +2315,9 @@ static int bdrv_refresh_perms(BlockDriverState *bs, Error 
**errp)
 int ret;
 uint64_t perm, shared_perm;
 
+if (!bdrv_check_parents_compliance(bs, errp)) {
+return -EPERM;
+}
 bdrv_get_cumulative_perm(bs, , _perm);
 ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, errp);
 if (ret < 0) {
-- 
2.21.3




[PATCH 06/21] block: rewrite bdrv_child_try_set_perm() using bdrv_refresh_perms()

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
We are going to drop recursive bdrv_child_* functions, so stop use them
in bdrv_child_try_set_perm() as a first step.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block.c | 14 --
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/block.c b/block.c
index e12acd5029..a9e4d2b57c 100644
--- a/block.c
+++ b/block.c
@@ -2372,11 +2372,16 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t 
perm, uint64_t shared,
 Error **errp)
 {
 Error *local_err = NULL;
+GSList *tran = NULL;
 int ret;
 
-ret = bdrv_child_check_perm(c, NULL, perm, shared, NULL, _err);
+bdrv_child_set_perm_safe(c, perm, shared, );
+
+ret = bdrv_refresh_perms(c->bs, _err);
+
+tran_finalize(tran, ret);
+
 if (ret < 0) {
-bdrv_child_abort_perm_update(c);
 if ((perm & ~c->perm) || (c->shared_perm & ~shared)) {
 /* tighten permissions */
 error_propagate(errp, local_err);
@@ -2390,12 +2395,9 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, 
uint64_t shared,
 error_free(local_err);
 ret = 0;
 }
-return ret;
 }
 
-bdrv_child_set_perm(c);
-
-return 0;
+return ret;
 }
 
 int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp)
-- 
2.21.3




[PATCH v3 16/19] qom: Make PropertyInfo.set_default_value optional

2020-11-23 Thread Eduardo Habkost
If .set_default_value is not set, call
object_property_set_default().  This will let us delete most of
the .set_default_value functions later.

Signed-off-by: Eduardo Habkost 
---
This is a new patch in v3 of this series.

In v2 of the series, equivalent functionality was implemented by
"qom: Use qlit to represent property defaults".
---
 include/qom/field-property.h |  3 +++
 qom/field-property.c | 12 ++--
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/include/qom/field-property.h b/include/qom/field-property.h
index 951cec2fb0..00b83ee9ba 100644
--- a/include/qom/field-property.h
+++ b/include/qom/field-property.h
@@ -53,6 +53,9 @@ struct PropertyInfo {
  * @set_default_value: Callback for initializing the default value
  *
  * @defval is a weak reference.
+ *
+ * Optional.  If not set and Property.defval is not QTYPE_NONE,
+ * object_property_set_default() will be called.
  */
 void (*set_default_value)(ObjectProperty *op, const Property *prop,
   const QObject *defval);
diff --git a/qom/field-property.c b/qom/field-property.c
index 593ffb53e9..d21ff98862 100644
--- a/qom/field-property.c
+++ b/qom/field-property.c
@@ -72,8 +72,16 @@ static void field_prop_set_default_value(ObjectProperty *op,
 }
 
 defval = qobject_from_qlit(>defval);
-assert(prop->info->set_default_value);
-prop->info->set_default_value(op, prop, defval);
+if (prop->info->set_default_value) {
+/* .set_default_value() gets a weak reference */
+prop->info->set_default_value(op, prop, defval);
+} else {
+/*
+ * object_property_set_default() takes ownership,
+ * so qobject_ref() is needed.
+ */
+object_property_set_default(op, qobject_ref(defval));
+}
 qobject_unref(defval);
 }
 
-- 
2.28.0




[PATCH v3 15/19] qom: Make object_property_set_default() public

2020-11-23 Thread Eduardo Habkost
The function will be used outside qom/object.c, to simplify the
field property code that sets the property default value.

Reviewed-by: Marc-André Lureau 
Signed-off-by: Eduardo Habkost 
---
 include/qom/object.h | 11 +++
 qom/object.c |  2 +-
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/include/qom/object.h b/include/qom/object.h
index 2ab124b8f0..4234cc9b66 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -1090,6 +1090,17 @@ ObjectProperty *object_class_property_add(ObjectClass 
*klass, const char *name,
   ObjectPropertyRelease *release,
   void *opaque);
 
+/**
+ * object_property_set_default:
+ * @prop: the property to set
+ * @value: the value to be written to the property
+ *
+ * Set the property default value.
+ *
+ * Ownership of @value is transferred to the property.
+ */
+void object_property_set_default(ObjectProperty *prop, QObject *value);
+
 /**
  * object_property_set_default_bool:
  * @prop: the property to set
diff --git a/qom/object.c b/qom/object.c
index 7c11bcd3b1..6b0d9d8c79 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -1547,7 +1547,7 @@ static void object_property_init_defval(Object *obj, 
ObjectProperty *prop)
 visit_free(v);
 }
 
-static void object_property_set_default(ObjectProperty *prop, QObject *defval)
+void object_property_set_default(ObjectProperty *prop, QObject *defval)
 {
 assert(!prop->defval);
 assert(!prop->init);
-- 
2.28.0




[PATCH 01/21] tests/test-bdrv-graph-mod: add test_parallel_exclusive_write

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
Add the test that shows that concept of ignore_children is incomplete.
Actually, when we want to update something, ignoring permission of some
existing BdrvChild, we should ignore also the propagated effect of this
child to the other children. But that's not done. Better approach
(update permissions on already updated graph) will be implemented
later.

No the test fails, so it's added with -d argument to not break make
check.

Test fails with

 "Conflicts with use by fl1 as 'backing', which does not allow 'write' on base"

because when updating permissions we can ignore original top->fl1
BdrvChild. But we don't ignore exclusive write permission in fl1->base
BdrvChild, which is propagated. Correct thing to do is make graph
change first and then do permission update from the top node.

To run test do

  ./test-bdrv-graph-mod -d -p /bdrv-graph-mod/parallel-exclusive-write

from /tests.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 tests/test-bdrv-graph-mod.c | 62 +
 1 file changed, 62 insertions(+)

diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c
index 8cff13830e..3b9e6f242f 100644
--- a/tests/test-bdrv-graph-mod.c
+++ b/tests/test-bdrv-graph-mod.c
@@ -44,6 +44,21 @@ static BlockDriver bdrv_no_perm = {
 .bdrv_child_perm = no_perm_default_perms,
 };
 
+static void exclusive_write_perms(BlockDriverState *bs, BdrvChild *c,
+  BdrvChildRole role,
+  BlockReopenQueue *reopen_queue,
+  uint64_t perm, uint64_t shared,
+  uint64_t *nperm, uint64_t *nshared)
+{
+*nperm = BLK_PERM_WRITE;
+*nshared = BLK_PERM_ALL & ~BLK_PERM_WRITE;
+}
+
+static BlockDriver bdrv_exclusive_writer = {
+.format_name = "exclusive-writer",
+.bdrv_child_perm = exclusive_write_perms,
+};
+
 static BlockDriverState *no_perm_node(const char *name)
 {
 return bdrv_new_open_driver(_no_perm, name, BDRV_O_RDWR, 
_abort);
@@ -55,6 +70,12 @@ static BlockDriverState *pass_through_node(const char *name)
 BDRV_O_RDWR, _abort);
 }
 
+static BlockDriverState *exclusive_writer_node(const char *name)
+{
+return bdrv_new_open_driver(_exclusive_writer, name,
+BDRV_O_RDWR, _abort);
+}
+
 /*
  * test_update_perm_tree
  *
@@ -185,8 +206,44 @@ static void test_should_update_child(void)
 blk_unref(root);
 }
 
+/*
+ * test_parallel_exclusive_write
+ *
+ * Check that when we replace node, old permissions of the node being removed
+ * doesn't break the replacement.
+ */
+static void test_parallel_exclusive_write(void)
+{
+BlockDriverState *top = exclusive_writer_node("top");
+BlockDriverState *base = no_perm_node("base");
+BlockDriverState *fl1 = pass_through_node("fl1");
+BlockDriverState *fl2 = pass_through_node("fl2");
+
+bdrv_attach_child(top, fl1, "backing", _of_bds, BDRV_CHILD_DATA,
+  _abort);
+bdrv_attach_child(fl1, base, "backing", _of_bds, BDRV_CHILD_FILTERED,
+  _abort);
+bdrv_attach_child(fl2, base, "backing", _of_bds, BDRV_CHILD_FILTERED,
+  _abort);
+bdrv_ref(base);
+
+bdrv_replace_node(fl1, fl2, _abort);
+
+bdrv_unref(top);
+}
+
 int main(int argc, char *argv[])
 {
+int i;
+bool debug = false;
+
+for (i = 1; i < argc; i++) {
+if (!strcmp(argv[i], "-d")) {
+debug = true;
+break;
+}
+}
+
 bdrv_init();
 qemu_init_main_loop(_abort);
 
@@ -196,5 +253,10 @@ int main(int argc, char *argv[])
 g_test_add_func("/bdrv-graph-mod/should-update-child",
 test_should_update_child);
 
+if (debug) {
+g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write",
+test_parallel_exclusive_write);
+}
+
 return g_test_run();
 }
-- 
2.21.3




[PATCH 2/2] block: assert that permission commit sets same permissions

2020-11-23 Thread Vladimir Sementsov-Ogievskiy
On permission update commit we must set same permissions as on _check_.
Let's add assertions. Next step may be to drop permission parameters
from _set_.

Note that prior to previous commit, fixing bdrv_drop_intermediate(),
new assertion in bdrv_child_set_perm() crashes on iotests 30 and 40.

Signed-off-by: Vladimir Sementsov-Ogievskiy 
---
 block.c | 11 +--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/block.c b/block.c
index bd9f4e534b..0f4da59a6c 100644
--- a/block.c
+++ b/block.c
@@ -2105,9 +2105,10 @@ static void bdrv_abort_perm_update(BlockDriverState *bs)
 }
 }
 
-static void bdrv_set_perm(BlockDriverState *bs, uint64_t cumulative_perms,
-  uint64_t cumulative_shared_perms)
+static void bdrv_set_perm(BlockDriverState *bs, uint64_t _cumulative_perms,
+  uint64_t _cumulative_shared_perms)
 {
+uint64_t cumulative_perms, cumulative_shared_perms;
 BlockDriver *drv = bs->drv;
 BdrvChild *c;
 
@@ -2115,6 +2116,10 @@ static void bdrv_set_perm(BlockDriverState *bs, uint64_t 
cumulative_perms,
 return;
 }
 
+bdrv_get_cumulative_perm(bs, _perms, _shared_perms);
+assert(_cumulative_perms == cumulative_perms);
+assert(_cumulative_shared_perms == cumulative_shared_perms);
+
 /* Update this node */
 if (drv->bdrv_set_perm) {
 drv->bdrv_set_perm(bs, cumulative_perms, cumulative_shared_perms);
@@ -2301,6 +2306,8 @@ static void bdrv_child_set_perm(BdrvChild *c, uint64_t 
perm, uint64_t shared)
 
 c->has_backup_perm = false;
 
+assert(c->perm == perm);
+assert(c->shared_perm == shared);
 c->perm = perm;
 c->shared_perm = shared;
 
-- 
2.21.3




[PATCH v3 13/19] qom: Fix documentation of UUID property type

2020-11-23 Thread Eduardo Habkost
On some cases, the documentation for UUID properties is lying:
properties defined using DEFINE_PROP_UUID_NODEFAULT are not set
to "auto" by default.  It's better to omit this instead of
providing incorrect information.

Signed-off-by: Eduardo Habkost 
---
This is a new patch addeed in v3 of this series.
---
 hw/core/qdev-properties-system.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 217e041152..6071f672a4 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -1089,7 +1089,7 @@ static void set_default_uuid_auto(ObjectProperty *op, 
const Property *prop,
 const PropertyInfo qdev_prop_uuid = {
 .name  = "str",
 .description = "UUID (aka GUID) or \"" UUID_VALUE_AUTO
-"\" for random value (default)",
+"\" for random value",
 .get   = get_uuid,
 .set   = set_uuid,
 .set_default_value = set_default_uuid_auto,
-- 
2.28.0




[PATCH v3 11/19] qom: field_prop_set_default_value() helper

2020-11-23 Thread Eduardo Habkost
Move code that sets the property default value to a separate
function, to reduce duplication and make refactoring easier.

Signed-off-by: Eduardo Habkost 
---
This is a new patch added in v3 of this series.
Hopefully, this will make the series easier to review.

The field_prop_set_default_value() was added in v2 at
"qom: Use qlit to represent property defaults".
---
 qom/field-property.c | 24 
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/qom/field-property.c b/qom/field-property.c
index cb729626ce..6a0df7c6ea 100644
--- a/qom/field-property.c
+++ b/qom/field-property.c
@@ -62,6 +62,17 @@ static void static_prop_release_dynamic_prop(Object *obj, 
const char *name,
 g_free(prop);
 }
 
+static void field_prop_set_default_value(ObjectProperty *op,
+ Property *prop)
+{
+if (!prop->set_default) {
+return;
+}
+
+assert(prop->info->set_default_value);
+prop->info->set_default_value(op, prop);
+}
+
 ObjectProperty *
 object_property_add_field(Object *obj, const char *name,
   Property *prop,
@@ -83,11 +94,9 @@ object_property_add_field(Object *obj, const char *name,
 object_property_set_description(obj, name,
 newprop->info->description);
 
-if (newprop->set_default) {
-newprop->info->set_default_value(op, newprop);
-if (op->init) {
-op->init(obj, op);
-}
+field_prop_set_default_value(op, newprop);
+if (op->init) {
+op->init(obj, op);
 }
 
 op->allow_set = allow_set;
@@ -113,9 +122,8 @@ object_class_property_add_field_static(ObjectClass *oc, 
const char *name,
prop->info->release,
prop);
 }
-if (prop->set_default) {
-prop->info->set_default_value(op, prop);
-}
+
+field_prop_set_default_value(op, prop);
 if (prop->info->description) {
 object_class_property_set_description(oc, name,
   prop->info->description);
-- 
2.28.0




[PATCH v3 17/19] qom: Delete field_prop_set_default_value_*int()

2020-11-23 Thread Eduardo Habkost
The field_prop_set_default_value_*int() functions can be
completely replaced by object_propert_set_default(),
we don't need them anymore.

Signed-off-by: Eduardo Habkost 
---
This is a new patch in v3 of this series.

In v2 of the series, equivalent changes were part of "qom: Use
qlit to represent property defaults".
---
 include/qom/field-property-internal.h |  6 --
 hw/core/qdev-properties-system.c  |  2 --
 qom/property-types.c  | 25 -
 3 files changed, 33 deletions(-)

diff --git a/include/qom/field-property-internal.h 
b/include/qom/field-property-internal.h
index 7ed0d8d160..4bcf5b45f3 100644
--- a/include/qom/field-property-internal.h
+++ b/include/qom/field-property-internal.h
@@ -16,12 +16,6 @@ void field_prop_set_enum(Object *obj, Visitor *v, const char 
*name,
 void field_prop_set_default_value_enum(ObjectProperty *op,
const Property *prop,
const QObject *defval);
-void field_prop_set_default_value_int(ObjectProperty *op,
-  const Property *prop,
-   const QObject *defval);
-void field_prop_set_default_value_uint(ObjectProperty *op,
-   const Property *prop,
-   const QObject *defval);
 
 void field_prop_get_int32(Object *obj, Visitor *v, const char *name,
   void *opaque, Error **errp);
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 117c540254..b2df955f2a 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -571,7 +571,6 @@ const PropertyInfo qdev_prop_blocksize = {
" and " MAX_BLOCK_SIZE_STR,
 .get   = field_prop_get_size32,
 .set   = set_blocksize,
-.set_default_value = field_prop_set_default_value_uint,
 };
 
 /* --- Block device error handling policy --- */
@@ -769,7 +768,6 @@ const PropertyInfo qdev_prop_pci_devfn = {
 .print = print_pci_devfn,
 .get   = field_prop_get_int32,
 .set   = set_pci_devfn,
-.set_default_value = field_prop_set_default_value_int,
 };
 
 /* --- pci host address --- */
diff --git a/qom/property-types.c b/qom/property-types.c
index 0fc24b3687..399e36c29e 100644
--- a/qom/property-types.c
+++ b/qom/property-types.c
@@ -195,27 +195,10 @@ static void set_uint8(Object *obj, Visitor *v, const char 
*name, void *opaque,
 visit_type_uint8(v, name, ptr, errp);
 }
 
-void field_prop_set_default_value_int(ObjectProperty *op,
-  const Property *prop,
-  const QObject *defval)
-{
-QNum *qn = qobject_to(QNum, defval);
-object_property_set_default_int(op, qnum_get_int(qn));
-}
-
-void field_prop_set_default_value_uint(ObjectProperty *op,
-   const Property *prop,
-   const QObject *defval)
-{
-QNum *qn = qobject_to(QNum, defval);
-object_property_set_default_uint(op, qnum_get_uint(qn));
-}
-
 const PropertyInfo prop_info_uint8 = {
 .name  = "uint8",
 .get   = get_uint8,
 .set   = set_uint8,
-.set_default_value = field_prop_set_default_value_uint,
 };
 
 /* --- 16bit integer --- */
@@ -242,7 +225,6 @@ const PropertyInfo prop_info_uint16 = {
 .name  = "uint16",
 .get   = get_uint16,
 .set   = set_uint16,
-.set_default_value = field_prop_set_default_value_uint,
 };
 
 /* --- 32bit integer --- */
@@ -287,14 +269,12 @@ const PropertyInfo prop_info_uint32 = {
 .name  = "uint32",
 .get   = get_uint32,
 .set   = set_uint32,
-.set_default_value = field_prop_set_default_value_uint,
 };
 
 const PropertyInfo prop_info_int32 = {
 .name  = "int32",
 .get   = field_prop_get_int32,
 .set   = set_int32,
-.set_default_value = field_prop_set_default_value_int,
 };
 
 /* --- 64bit integer --- */
@@ -339,14 +319,12 @@ const PropertyInfo prop_info_uint64 = {
 .name  = "uint64",
 .get   = get_uint64,
 .set   = set_uint64,
-.set_default_value = field_prop_set_default_value_uint,
 };
 
 const PropertyInfo prop_info_int64 = {
 .name  = "int64",
 .get   = get_int64,
 .set   = set_int64,
-.set_default_value = field_prop_set_default_value_int,
 };
 
 /* --- string --- */
@@ -441,7 +419,6 @@ const PropertyInfo prop_info_size32 = {
 .name  = "size",
 .get = field_prop_get_size32,
 .set = set_size32,
-.set_default_value = field_prop_set_default_value_uint,
 };
 
 /* --- support for array properties --- */
@@ -505,7 +482,6 @@ const PropertyInfo prop_info_arraylen = {
 .name = "uint32",
 .get = get_uint32,
 .set = set_prop_arraylen,
-.set_default_value = field_prop_set_default_value_uint,
 };
 
 /* --- 64bit unsigned int 'size' type --- */
@@ -532,7 +508,6 @@ const PropertyInfo prop_info_size = {
 .name  = 

[PATCH v3 14/19] qom: Don't ignore defval on UUID property

2020-11-23 Thread Eduardo Habkost
UUID properties were weird because the value of .defval was
completely ignored.  Fix this by setting the default value to
QLIT_QSTR("auto") on the default case, and actually using .defval
inside .set_default_value.

Signed-off-by: Eduardo Habkost 
---
This is a new patch added in v3 of this series.

This is similar (but not completely the same) to changes that
were submitted as part of
"[PATCH v2 8/8] qom: Use qlit to represent property defaults".
---
 include/hw/qdev-properties-system.h |  9 +++--
 hw/core/qdev-properties-system.c| 10 +-
 2 files changed, 8 insertions(+), 11 deletions(-)

diff --git a/include/hw/qdev-properties-system.h 
b/include/hw/qdev-properties-system.h
index 6221da704e..834ca84904 100644
--- a/include/hw/qdev-properties-system.h
+++ b/include/hw/qdev-properties-system.h
@@ -63,14 +63,11 @@ extern const PropertyInfo qdev_prop_pcie_link_width;
 DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pcie_link_width, \
 PCIExpLinkWidth)
 
+#define UUID_VALUE_AUTO"auto"
+
 #define DEFINE_PROP_UUID(_name, _state, _field) \
 DEFINE_PROP(_name, _state, _field, qdev_prop_uuid, QemuUUID, \
-/*   \
- * Note that set_default_uuid_auto() currently   \
- * ignores the actual value value of .defval,\
- * we just need it to not be not QTYPE_NONE  \
- */  \
-.defval = QLIT_QNULL)
+.defval = QLIT_QSTR(UUID_VALUE_AUTO))
 
 #define DEFINE_PROP_AUDIODEV(_n, _s, _f) \
 DEFINE_PROP(_n, _s, _f, qdev_prop_audiodev, QEMUSoundCard)
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 6071f672a4..117c540254 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -15,6 +15,7 @@
 #include "hw/qdev-properties-system.h"
 #include "qapi/error.h"
 #include "qapi/visitor.h"
+#include "qapi/qmp/qstring.h"
 #include "qapi/qapi-types-block.h"
 #include "qapi/qapi-types-machine.h"
 #include "qapi/qapi-types-migration.h"
@@ -1059,8 +1060,6 @@ static void get_uuid(Object *obj, Visitor *v, const char 
*name, void *opaque,
 visit_type_str(v, name, , errp);
 }
 
-#define UUID_VALUE_AUTO"auto"
-
 static void set_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
 Error **errp)
 {
@@ -1080,10 +1079,11 @@ static void set_uuid(Object *obj, Visitor *v, const 
char *name, void *opaque,
 g_free(str);
 }
 
-static void set_default_uuid_auto(ObjectProperty *op, const Property *prop,
+static void set_default_uuid(ObjectProperty *op, const Property *prop,
   const QObject *defval)
 {
-object_property_set_default_str(op, UUID_VALUE_AUTO);
+QString *qs = qobject_to(QString, defval);
+object_property_set_default_str(op, qstring_get_str(qs));
 }
 
 const PropertyInfo qdev_prop_uuid = {
@@ -1092,5 +1092,5 @@ const PropertyInfo qdev_prop_uuid = {
 "\" for random value",
 .get   = get_uuid,
 .set   = set_uuid,
-.set_default_value = set_default_uuid_auto,
+.set_default_value = set_default_uuid,
 };
-- 
2.28.0




[PATCH v3 03/19] qnum: QNumValue type for QNum value literals

2020-11-23 Thread Eduardo Habkost
Provide a separate QNumValue type that can be used for QNum value
literals without the referencing counting and memory allocation
features provided by QObject.

Signed-off-by: Eduardo Habkost 
---
Changes v2 -> v3:
* Fixed copy-pasta at qnum_from_value() documentation
* Removed qnum_get_value() function
* Moved doc comment of qnum_from_value() to .c file, for
  consistency with other functions.
* Removed "private:" doc comment at QNumValue.
* Removed unnecessary kernel-doc noise (obvious
  parameter descriptions).
* Removed space after type cast in qnum_from_*().
* qnum_is_equal() variable const-ness & renames:
  * Renamed new QNumValue variables to val_x/val_y.
  * Keep existing QNum num_x/num_y variable names.
  * const-ness change of num_x/num_y was moved to a separate
patch.

Changes v1 -> v2:
* Fix "make check" failure, by updating check-qnum unit test to
  use the new struct fields
---
 include/qapi/qmp/qnum.h | 23 ++-
 qobject/qnum.c  | 91 ++---
 tests/check-qnum.c  | 14 +++
 3 files changed, 76 insertions(+), 52 deletions(-)

diff --git a/include/qapi/qmp/qnum.h b/include/qapi/qmp/qnum.h
index 3e9ecd324e..03193dca20 100644
--- a/include/qapi/qmp/qnum.h
+++ b/include/qapi/qmp/qnum.h
@@ -44,16 +44,35 @@ typedef enum {
  * in range: qnum_get_try_int() / qnum_get_try_uint() check range and
  * convert under the hood.
  */
-struct QNum {
-struct QObjectBase_ base;
+
+/**
+ * struct QNumValue: the value of a QNum
+ *
+ * QNumValue literals can be constructed using the `QNUM_VAL_INT`,
+ * `QNUM_VAL_UINT`, and `QNUM_VAL_DOUBLE` macros.
+ */
+typedef struct QNumValue {
 QNumKind kind;
 union {
 int64_t i64;
 uint64_t u64;
 double dbl;
 } u;
+} QNumValue;
+
+#define QNUM_VAL_INT(value) \
+{ .kind = QNUM_I64, .u.i64 = value }
+#define QNUM_VAL_UINT(value) \
+{ .kind = QNUM_U64, .u.u64 = value }
+#define QNUM_VAL_DOUBLE(value) \
+{ .kind = QNUM_DOUBLE, .u.dbl = value }
+
+struct QNum {
+struct QObjectBase_ base;
+QNumValue value;
 };
 
+QNum *qnum_from_value(QNumValue value);
 QNum *qnum_from_int(int64_t value);
 QNum *qnum_from_uint(uint64_t value);
 QNum *qnum_from_double(double value);
diff --git a/qobject/qnum.c b/qobject/qnum.c
index e5ea728638..94e668db60 100644
--- a/qobject/qnum.c
+++ b/qobject/qnum.c
@@ -16,21 +16,29 @@
 #include "qapi/qmp/qnum.h"
 
 /**
- * qnum_from_int(): Create a new QNum from an int64_t
+ * qnum_from_value(): Create a new QNum from a QNumValue
  *
  * Return strong reference.
  */
-QNum *qnum_from_int(int64_t value)
+QNum *qnum_from_value(QNumValue value)
 {
 QNum *qn = g_new(QNum, 1);
 
 qobject_init(QOBJECT(qn), QTYPE_QNUM);
-qn->kind = QNUM_I64;
-qn->u.i64 = value;
-
+qn->value = value;
 return qn;
 }
 
+/**
+ * qnum_from_int(): Create a new QNum from an int64_t
+ *
+ * Return strong reference.
+ */
+QNum *qnum_from_int(int64_t value)
+{
+return qnum_from_value((QNumValue)QNUM_VAL_INT(value));
+}
+
 /**
  * qnum_from_uint(): Create a new QNum from an uint64_t
  *
@@ -38,13 +46,7 @@ QNum *qnum_from_int(int64_t value)
  */
 QNum *qnum_from_uint(uint64_t value)
 {
-QNum *qn = g_new(QNum, 1);
-
-qobject_init(QOBJECT(qn), QTYPE_QNUM);
-qn->kind = QNUM_U64;
-qn->u.u64 = value;
-
-return qn;
+return qnum_from_value((QNumValue)QNUM_VAL_UINT(value));
 }
 
 /**
@@ -54,13 +56,7 @@ QNum *qnum_from_uint(uint64_t value)
  */
 QNum *qnum_from_double(double value)
 {
-QNum *qn = g_new(QNum, 1);
-
-qobject_init(QOBJECT(qn), QTYPE_QNUM);
-qn->kind = QNUM_DOUBLE;
-qn->u.dbl = value;
-
-return qn;
+return qnum_from_value((QNumValue)QNUM_VAL_DOUBLE(value));
 }
 
 /**
@@ -70,15 +66,17 @@ QNum *qnum_from_double(double value)
  */
 bool qnum_get_try_int(const QNum *qn, int64_t *val)
 {
-switch (qn->kind) {
+const QNumValue *qv = >value;
+
+switch (qv->kind) {
 case QNUM_I64:
-*val = qn->u.i64;
+*val = qv->u.i64;
 return true;
 case QNUM_U64:
-if (qn->u.u64 > INT64_MAX) {
+if (qv->u.u64 > INT64_MAX) {
 return false;
 }
-*val = qn->u.u64;
+*val = qv->u.u64;
 return true;
 case QNUM_DOUBLE:
 return false;
@@ -108,15 +106,17 @@ int64_t qnum_get_int(const QNum *qn)
  */
 bool qnum_get_try_uint(const QNum *qn, uint64_t *val)
 {
-switch (qn->kind) {
+const QNumValue *qv = >value;
+
+switch (qv->kind) {
 case QNUM_I64:
-if (qn->u.i64 < 0) {
+if (qv->u.i64 < 0) {
 return false;
 }
-*val = qn->u.i64;
+*val = qv->u.i64;
 return true;
 case QNUM_U64:
-*val = qn->u.u64;
+*val = qv->u.u64;
 return true;
 case QNUM_DOUBLE:
 return false;
@@ -146,13 +146,15 @@ uint64_t qnum_get_uint(const QNum *qn)
  */
 double qnum_get_double(const QNum *qn)
 {
-switch (qn->kind) {
+const QNumValue 

simple aarch64 binary can cause linux-user QEMU to segv in zero_bss()

2020-11-23 Thread Peter Maydell
Somebody reported this on stackoverflow. Before I spend too
much time thinking about how this ought to work, does anybody
have the elfload.c intended operation in their head still?
Bug description and analysis of what goes wrong below:

https://stackoverflow.com/questions/64956322/alignment-requirements-for-arm64-elf-executables-run-in-qemu-assembled-by-gas

Given this trivial asm:

===begin program.s===
// GNU Assembler, ARM64 Linux

.bss

.lcomm ARRAY, 16

.text

.global _start

_start:
mov x8, 93 // exit sys num
mov x0, 0 // success
svc 0
===endit===

clang -nostdlib -fno-integrated-as -target aarch64-linux-gnu -s
program.s -o program.out

the resulting program.out works fine on a real kernel but makes
qemu-aarch64 SEGV:
$ ./build/x86/qemu-aarch64 /tmp/program.out
Segmentation fault (core dumped)

Looking at it with gdb, the segv is from QEMU itself, in zero_bss():

if (host_start < host_map_start) {
memset((void *)host_start, 0, host_map_start - host_start);
}

We try to clear the memory from 'host_start' to 'host_map_start'
(the latter being the round-up-to-host-page version of the former),
but for this binary we never mmap()ed host_start as writeable,
so we segv inside the memset.

The guest-binary relevant bits of /proc/maps are:
0040-00401000 r--p  08:15 5767333
  /tmp/program.out
00401000-01411000 ---p  00:00 0

The program header is:
Program Header:
LOAD off0x vaddr 0x0040 paddr
0x0040 align 2**16
 filesz 0x00bc memsz 0x00bc flags r-x
LOAD off0x00c0 vaddr 0x004100c0 paddr
0x004100c0 align 2**16
 filesz 0x memsz 0x0010 flags rw-

and in zero_bss() host_start == 0x4100c0, host_map_start == 0x411000,
last_bss == 0x411000. The code calls
 page_set_flags(start = 0x41, end = 0x411000,
flags=PAGE_VALID|PAGE_READ|PAGE_WRITE)
with, I assume, the intention that that will make the memset() OK,
but page_set_flags() just sets up some data structure bits which will
mean that a subsequent SEGV will cause us to do a page_unprotect() that
sets the page as actually writeable. Unfortunately the SIGSEGV handler
is not installed until quite late in linux-user/main.c, so when the
memset() in zero_bss() SEGVs QEMU just dies.

Should we try to get the SEGV handler working earlier in initialization
(it's pretty hairy machinery so that could be tricky) or should
elfload.c be mprotect()ing things appropriately itself?

thanks
-- PMM



[PATCH v3 04/19] qnum: qnum_value_is_equal() function

2020-11-23 Thread Eduardo Habkost
Extract the QNum value comparison logic to a function that takes
QNumValue* as argument.

Signed-off-by: Eduardo Habkost 
---
Changes v2 -> v3:
* Rename function parameters to val_x/val_y
* Insert blank line after variable declarations at
  qnum_is_equal()
---
 include/qapi/qmp/qnum.h |  1 +
 qobject/qnum.c  | 24 
 2 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/include/qapi/qmp/qnum.h b/include/qapi/qmp/qnum.h
index 03193dca20..3dcb020689 100644
--- a/include/qapi/qmp/qnum.h
+++ b/include/qapi/qmp/qnum.h
@@ -87,6 +87,7 @@ double qnum_get_double(const QNum *qn);
 
 char *qnum_to_string(QNum *qn);
 
+bool qnum_value_is_equal(const QNumValue *val_x, const QNumValue *val_y);
 bool qnum_is_equal(const QObject *x, const QObject *y);
 void qnum_destroy_obj(QObject *obj);
 
diff --git a/qobject/qnum.c b/qobject/qnum.c
index 94e668db60..53c637f46d 100644
--- a/qobject/qnum.c
+++ b/qobject/qnum.c
@@ -202,7 +202,7 @@ char *qnum_to_string(QNum *qn)
 }
 
 /**
- * qnum_is_equal(): Test whether the two QNums are equal
+ * qnum_value_is_equal(): Test whether two QNumValues are equal
  *
  * Negative integers are never considered equal to unsigned integers,
  * but positive integers in the range [0, INT64_MAX] are considered
@@ -210,13 +210,8 @@ char *qnum_to_string(QNum *qn)
  *
  * Doubles are never considered equal to integers.
  */
-bool qnum_is_equal(const QObject *x, const QObject *y)
+bool qnum_value_is_equal(const QNumValue *val_x, const QNumValue *val_y)
 {
-const QNum *num_x = qobject_to(QNum, x);
-const QNum *num_y = qobject_to(QNum, y);
-const QNumValue *val_x = _x->value;
-const QNumValue *val_y = _y->value;
-
 switch (val_x->kind) {
 case QNUM_I64:
 switch (val_y->kind) {
@@ -234,7 +229,7 @@ bool qnum_is_equal(const QObject *x, const QObject *y)
 case QNUM_U64:
 switch (val_y->kind) {
 case QNUM_I64:
-return qnum_is_equal(y, x);
+return qnum_value_is_equal(val_y, val_x);
 case QNUM_U64:
 /* Comparison in native uint64_t type */
 return val_x->u.u64 == val_y->u.u64;
@@ -257,6 +252,19 @@ bool qnum_is_equal(const QObject *x, const QObject *y)
 abort();
 }
 
+/**
+ * qnum_is_equal(): Test whether the two QNums are equal
+ *
+ * See qnum_value_is_equal() for details on the comparison rules.
+ */
+bool qnum_is_equal(const QObject *x, const QObject *y)
+{
+const QNum *qnum_x = qobject_to(QNum, x);
+const QNum *qnum_y = qobject_to(QNum, y);
+
+return qnum_value_is_equal(_x->value, _y->value);
+}
+
 /**
  * qnum_destroy_obj(): Free all memory allocated by a
  * QNum object
-- 
2.28.0




[PATCH v3 19/19] qom: Delete set_default_value_bool()

2020-11-23 Thread Eduardo Habkost
set_default_value_bool() can be completely replaced by
object_property_set_default(), we don't need that function
anymore.

Signed-off-by: Eduardo Habkost 
---
This is a new patch in v3 of this series.

In v2 of the series, equivalent changes were part of "qom: Use
qlit to represent property defaults".
---
 qom/property-types.c | 10 --
 1 file changed, 10 deletions(-)

diff --git a/qom/property-types.c b/qom/property-types.c
index 399e36c29e..cb7ba2a229 100644
--- a/qom/property-types.c
+++ b/qom/property-types.c
@@ -84,19 +84,11 @@ static void prop_set_bit(Object *obj, Visitor *v, const 
char *name,
 bit_prop_set(obj, prop, value);
 }
 
-static void set_default_value_bool(ObjectProperty *op, const Property *prop,
-   const QObject *defval)
-{
-QBool *qb = qobject_to(QBool, defval);
-object_property_set_default_bool(op, qbool_get_bool(qb));
-}
-
 const PropertyInfo prop_info_bit = {
 .name  = "bool",
 .description = "on/off",
 .get   = prop_get_bit,
 .set   = prop_set_bit,
-.set_default_value = set_default_value_bool,
 };
 
 /* Bit64 */
@@ -145,7 +137,6 @@ const PropertyInfo prop_info_bit64 = {
 .description = "on/off",
 .get   = prop_get_bit64,
 .set   = prop_set_bit64,
-.set_default_value = set_default_value_bool,
 };
 
 /* --- bool --- */
@@ -172,7 +163,6 @@ const PropertyInfo prop_info_bool = {
 .name  = "bool",
 .get   = get_bool,
 .set   = set_bool,
-.set_default_value = set_default_value_bool,
 };
 
 /* --- 8bit integer --- */
-- 
2.28.0




[PATCH v3 12/19] qom: Replace defval value in Property with QLitObject

2020-11-23 Thread Eduardo Habkost
QLitObject is capable of representing a wider range of values,
and it will allow us to simplify a lot of the existing code
setting property defaults, later.  Replace the bool and union
fields with QLitObject.

In short, this is just a direct translation from:
  prop->set_default
to
  prop->defval.type != QTYPE_NONE

from
  prop->defval.i
to
  qnum_get_int(qobject_to(QNum, prop->defval)

and from
  prop->defval.u
to
  qnum_get_uint(qobject_to(QNum, prop->defval)

Note that this doesn't replace any of the default property
setters (yet), but just make them safer.  Now the actual type of
.defval is validated before it is used.

Also note that set_default_uuid_auto() is a bit weird: it ignores
.defval completely.  This patch keeps the existing behavior, and
set_default_uuid_auto() weirdness will be addressed later.

Signed-off-by: Eduardo Habkost 
---
This is a new patch added in v3 of this series.

I am splitting the changes and making them in smaller steps to
make them easier to understand and review.  With this, I intend
to demonstrate that the conversion from bool+union to QLitObject
is an improvement even if the removal of custom .set_defaul_value
functions isn't 100% finished yet.
---
 include/hw/qdev-properties-system.h   |  7 ++-
 include/qom/field-property-internal.h |  9 ++---
 include/qom/field-property.h  | 27 ++-
 include/qom/property-types.h  | 18 ++
 hw/core/qdev-properties-system.c  |  3 ++-
 qom/field-property.c  |  8 ++--
 qom/property-types.c  | 26 ++
 7 files changed, 54 insertions(+), 44 deletions(-)

diff --git a/include/hw/qdev-properties-system.h 
b/include/hw/qdev-properties-system.h
index 0ac327ae60..6221da704e 100644
--- a/include/hw/qdev-properties-system.h
+++ b/include/hw/qdev-properties-system.h
@@ -65,7 +65,12 @@ extern const PropertyInfo qdev_prop_pcie_link_width;
 
 #define DEFINE_PROP_UUID(_name, _state, _field) \
 DEFINE_PROP(_name, _state, _field, qdev_prop_uuid, QemuUUID, \
-.set_default = true)
+/*   \
+ * Note that set_default_uuid_auto() currently   \
+ * ignores the actual value value of .defval,\
+ * we just need it to not be not QTYPE_NONE  \
+ */  \
+.defval = QLIT_QNULL)
 
 #define DEFINE_PROP_AUDIODEV(_n, _s, _f) \
 DEFINE_PROP(_n, _s, _f, qdev_prop_audiodev, QEMUSoundCard)
diff --git a/include/qom/field-property-internal.h 
b/include/qom/field-property-internal.h
index a7b7e2b69d..7ed0d8d160 100644
--- a/include/qom/field-property-internal.h
+++ b/include/qom/field-property-internal.h
@@ -14,11 +14,14 @@ void field_prop_set_enum(Object *obj, Visitor *v, const 
char *name,
  void *opaque, Error **errp);
 
 void field_prop_set_default_value_enum(ObjectProperty *op,
-   const Property *prop);
+   const Property *prop,
+   const QObject *defval);
 void field_prop_set_default_value_int(ObjectProperty *op,
-  const Property *prop);
+  const Property *prop,
+   const QObject *defval);
 void field_prop_set_default_value_uint(ObjectProperty *op,
-   const Property *prop);
+   const Property *prop,
+   const QObject *defval);
 
 void field_prop_get_int32(Object *obj, Visitor *v, const char *name,
   void *opaque, Error **errp);
diff --git a/include/qom/field-property.h b/include/qom/field-property.h
index 0cb1fe2217..951cec2fb0 100644
--- a/include/qom/field-property.h
+++ b/include/qom/field-property.h
@@ -6,6 +6,7 @@
 
 #include "qom/object.h"
 #include "qapi/util.h"
+#include "qapi/qmp/qlit.h"
 
 /**
  * struct Property: definition of a field property
@@ -27,21 +28,8 @@ struct Property {
 const PropertyInfo *info;
 ptrdiff_toffset;
 uint8_t  bitnr;
-/**
- * @set_default: true if the default value should be set from @defval,
- *in which case @info->set_default_value must not be NULL
- *(if false then no default value is set by the property system
- * and the field retains whatever value it was given by instance_init).
- */
-bool set_default;
-/**
- * @defval: default value for the property. This is used only if 
@set_default
- * is true.
- */
-union {
-int64_t i;
-uint64_t u;
-} defval;
+/** @defval: If not QTYPE_NONE, the default value for the property */
+QLitObject defval;
 /* private: */
 int  arrayoffset;
 const PropertyInfo 

[PATCH v3 09/19] qlit: Add more test literals to qlit_equal_qobject() test case

2020-11-23 Thread Eduardo Habkost
Add a few examples of each qlit type, to make sure each one
compare as equal to itself, but not equal to the other values.

Signed-off-by: Eduardo Habkost 
---
This is a new patch added in v3 of this series.
---
 tests/check-qlit.c | 16 
 1 file changed, 16 insertions(+)

diff --git a/tests/check-qlit.c b/tests/check-qlit.c
index b1cfbddb17..5a9260b93f 100644
--- a/tests/check-qlit.c
+++ b/tests/check-qlit.c
@@ -50,11 +50,27 @@ static void qlit_equal_qobject_test(void)
 {
 /* Each entry in the values[] array should be different from the others */
 QLitObject values[] = {
+QLIT_QNULL,
+QLIT_QBOOL(false),
+QLIT_QBOOL(true),
+QLIT_QNUM_INT(-1),
+QLIT_QNUM_INT(0),
+QLIT_QNUM_INT(1),
+QLIT_QNUM_INT(INT64_MIN),
+QLIT_QNUM_INT(INT64_MAX),
+QLIT_QSTR(""),
+QLIT_QSTR("foo"),
 qlit,
 QLIT_QDICT(((QLitDictEntry[]) {
 { "foo", QLIT_QNUM_INT(42) },
 { },
 })),
+QLIT_QLIST(((QLitObject[]){
+QLIT_QNUM_INT(-1),
+QLIT_QNUM_INT(0),
+QLIT_QNUM_INT(1),
+{ },
+})),
 };
 int i;
 QObject *qobj = make_qobject();
-- 
2.28.0




[PATCH v3 02/19] qnum: Make num_x/num_y variables at qnum_is_equal() const

2020-11-23 Thread Eduardo Habkost
qobject_to() drops const-ness by accident, but our function
arguments (x, y) are const.  Make num_x/num_y const too.

Signed-off-by: Eduardo Habkost 
---
This is a new patch added in v3 of the series.
---
 qobject/qnum.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/qobject/qnum.c b/qobject/qnum.c
index d328d91fcb..e5ea728638 100644
--- a/qobject/qnum.c
+++ b/qobject/qnum.c
@@ -209,8 +209,8 @@ char *qnum_to_string(QNum *qn)
  */
 bool qnum_is_equal(const QObject *x, const QObject *y)
 {
-QNum *num_x = qobject_to(QNum, x);
-QNum *num_y = qobject_to(QNum, y);
+const QNum *num_x = qobject_to(QNum, x);
+const QNum *num_y = qobject_to(QNum, y);
 
 switch (num_x->kind) {
 case QNUM_I64:
-- 
2.28.0




[PATCH v3 18/19] qom: Delete set_default_uuid()

2020-11-23 Thread Eduardo Habkost
The function can be completely replaced by
object_property_set_default(), we don't need it anymore.

Signed-off-by: Eduardo Habkost 
---
This is a new patch in v3 of this series.

In v2 of the series, equivalent changes were part of "qom: Use
qlit to represent property defaults".
---
 hw/core/qdev-properties-system.c | 8 
 1 file changed, 8 deletions(-)

diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index b2df955f2a..07945ea1c0 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -1077,18 +1077,10 @@ static void set_uuid(Object *obj, Visitor *v, const 
char *name, void *opaque,
 g_free(str);
 }
 
-static void set_default_uuid(ObjectProperty *op, const Property *prop,
-  const QObject *defval)
-{
-QString *qs = qobject_to(QString, defval);
-object_property_set_default_str(op, qstring_get_str(qs));
-}
-
 const PropertyInfo qdev_prop_uuid = {
 .name  = "str",
 .description = "UUID (aka GUID) or \"" UUID_VALUE_AUTO
 "\" for random value",
 .get   = get_uuid,
 .set   = set_uuid,
-.set_default_value = set_default_uuid,
 };
-- 
2.28.0




[PATCH v3 06/19] qlit: Rename QLIT_QNUM to QLIT_QNUM_INT

2020-11-23 Thread Eduardo Habkost
Rename the existing QLIT_QNUM macro to indicate it only supports
signed int values.  We're going to add support to other types of
QNums later.

Signed-off-by: Eduardo Habkost 
---
This is a new patch added in v3 of this series.

In v2, the existing QLIT_QNUM() macro was being kept, now it is
replaced by QLIT_QNUM_INT().
---
 include/qapi/qmp/qlit.h |  2 +-
 tests/check-qjson.c | 30 +++---
 tests/check-qlit.c  | 10 +-
 3 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/include/qapi/qmp/qlit.h b/include/qapi/qmp/qlit.h
index c0676d5daf..2fc2db282e 100644
--- a/include/qapi/qmp/qlit.h
+++ b/include/qapi/qmp/qlit.h
@@ -39,7 +39,7 @@ struct QLitDictEntry {
 { .type = QTYPE_QNULL }
 #define QLIT_QBOOL(val) \
 { .type = QTYPE_QBOOL, .value.qbool = (val) }
-#define QLIT_QNUM(val) \
+#define QLIT_QNUM_INT(val) \
 { .type = QTYPE_QNUM, .value.qnum = (val) }
 #define QLIT_QSTR(val) \
 { .type = QTYPE_QSTRING, .value.qstr = (val) }
diff --git a/tests/check-qjson.c b/tests/check-qjson.c
index 07a773e653..bc5b7ebdf3 100644
--- a/tests/check-qjson.c
+++ b/tests/check-qjson.c
@@ -1062,7 +1062,7 @@ static void simple_dict(void)
 {
 .encoded = "{\"foo\": 42, \"bar\": \"hello world\"}",
 .decoded = QLIT_QDICT(((QLitDictEntry[]){
-{ "foo", QLIT_QNUM(42) },
+{ "foo", QLIT_QNUM_INT(42) },
 { "bar", QLIT_QSTR("hello world") },
 { }
 })),
@@ -1074,7 +1074,7 @@ static void simple_dict(void)
 }, {
 .encoded = "{\"foo\": 43}",
 .decoded = QLIT_QDICT(((QLitDictEntry[]){
-{ "foo", QLIT_QNUM(43) },
+{ "foo", QLIT_QNUM_INT(43) },
 { }
 })),
 },
@@ -1160,15 +1160,15 @@ static void simple_list(void)
 {
 .encoded = "[43,42]",
 .decoded = QLIT_QLIST(((QLitObject[]){
-QLIT_QNUM(43),
-QLIT_QNUM(42),
+QLIT_QNUM_INT(43),
+QLIT_QNUM_INT(42),
 { }
 })),
 },
 {
 .encoded = "[43]",
 .decoded = QLIT_QLIST(((QLitObject[]){
-QLIT_QNUM(43),
+QLIT_QNUM_INT(43),
 { }
 })),
 },
@@ -1217,35 +1217,35 @@ static void simple_whitespace(void)
 {
 .encoded = " [ 43 , 42 ]",
 .decoded = QLIT_QLIST(((QLitObject[]){
-QLIT_QNUM(43),
-QLIT_QNUM(42),
+QLIT_QNUM_INT(43),
+QLIT_QNUM_INT(42),
 { }
 })),
 },
 {
 .encoded = "\t[ 43 , { 'h' : 'b' },\r\n\t[ ], 42 ]\n",
 .decoded = QLIT_QLIST(((QLitObject[]){
-QLIT_QNUM(43),
+QLIT_QNUM_INT(43),
 QLIT_QDICT(((QLitDictEntry[]){
 { "h", QLIT_QSTR("b") },
 { }})),
 QLIT_QLIST(((QLitObject[]){
 { }})),
-QLIT_QNUM(42),
+QLIT_QNUM_INT(42),
 { }
 })),
 },
 {
 .encoded = " [ 43 , { 'h' : 'b' , 'a' : 32 }, [ ], 42 ]",
 .decoded = QLIT_QLIST(((QLitObject[]){
-QLIT_QNUM(43),
+QLIT_QNUM_INT(43),
 QLIT_QDICT(((QLitDictEntry[]){
 { "h", QLIT_QSTR("b") },
-{ "a", QLIT_QNUM(32) },
+{ "a", QLIT_QNUM_INT(32) },
 { }})),
 QLIT_QLIST(((QLitObject[]){
 { }})),
-QLIT_QNUM(42),
+QLIT_QNUM_INT(42),
 { }
 })),
 },
@@ -1275,11 +1275,11 @@ static void simple_interpolation(void)
 QObject *embedded_obj;
 QObject *obj;
 QLitObject decoded = QLIT_QLIST(((QLitObject[]){
-QLIT_QNUM(1),
+QLIT_QNUM_INT(1),
 QLIT_QSTR("100%"),
 QLIT_QLIST(((QLitObject[]){
-QLIT_QNUM(32),
-QLIT_QNUM(42),
+QLIT_QNUM_INT(32),
+QLIT_QNUM_INT(42),
 {}})),
 {}}));
 
diff --git a/tests/check-qlit.c b/tests/check-qlit.c
index 58ceaae5a3..24ac21395c 100644
--- a/tests/check-qlit.c
+++ b/tests/check-qlit.c
@@ -17,12 +17,12 @@
 #include 

[PATCH v3 08/19] qlit: Move qlit_equal_qobject() reference values to array

2020-11-23 Thread Eduardo Habkost
Add an array of values to qlit_equal_qobject_test(), so we can
extend the test case to compare multiple literals, not just the
ones at the existing `qlit` and `qlit_foo` variables.

Signed-off-by: Eduardo Habkost 
---
This is a new patch added in v3 of this series.
---
 tests/check-qlit.c | 26 +++---
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/tests/check-qlit.c b/tests/check-qlit.c
index 24ac21395c..b1cfbddb17 100644
--- a/tests/check-qlit.c
+++ b/tests/check-qlit.c
@@ -29,11 +29,6 @@ static QLitObject qlit = QLIT_QDICT(((QLitDictEntry[]) {
 { },
 }));
 
-static QLitObject qlit_foo = QLIT_QDICT(((QLitDictEntry[]) {
-{ "foo", QLIT_QNUM_INT(42) },
-{ },
-}));
-
 static QObject *make_qobject(void)
 {
 QDict *qdict = qdict_new();
@@ -53,16 +48,33 @@ static QObject *make_qobject(void)
 
 static void qlit_equal_qobject_test(void)
 {
+/* Each entry in the values[] array should be different from the others */
+QLitObject values[] = {
+qlit,
+QLIT_QDICT(((QLitDictEntry[]) {
+{ "foo", QLIT_QNUM_INT(42) },
+{ },
+})),
+};
+int i;
 QObject *qobj = make_qobject();
 
 g_assert(qlit_equal_qobject(, qobj));
 
-g_assert(!qlit_equal_qobject(_foo, qobj));
-
 qdict_put(qobject_to(QDict, qobj), "bee", qlist_new());
 g_assert(!qlit_equal_qobject(, qobj));
 
 qobject_unref(qobj);
+
+for (i = 0; i < ARRAY_SIZE(values); i++) {
+int j;
+QObject *o = qobject_from_qlit([i]);
+for (j = 0; j < ARRAY_SIZE(values); j++) {
+g_assert(qlit_equal_qobject([j], o) == (i == j));
+}
+qobject_unref(o);
+}
+
 }
 
 static void qlit_equal_large_qnum_test(void)
-- 
2.28.0




[PATCH v3 10/19] qlit: Support all types of QNums

2020-11-23 Thread Eduardo Habkost
Add two new macros to support other types of QNums:
QLIT_QNUM_UINT, and QLIT_QNUM_DOUBLE, and include them
in the qlit_equal_qobject_test() test case.

Signed-off-by: Eduardo Habkost 
---
Changes v2 -> v3:
* QLIT_QNUM macro doesn't exist anymore
* Addition of the QNumValue field to QLitObject is
  now in a separate patch ("qlit: Use QNumValue to represent QNums")
* check-qjson test case changes dropped.
  Instead, I'm only extending the qlit_equal_qobject_test() test
  case.

Changes v1 -> v2:
* Coding style fix at qlit_equal_qobject()
---
 include/qapi/qmp/qlit.h | 4 
 tests/check-qlit.c  | 5 +
 2 files changed, 9 insertions(+)

diff --git a/include/qapi/qmp/qlit.h b/include/qapi/qmp/qlit.h
index a240cdd299..a2881b7f42 100644
--- a/include/qapi/qmp/qlit.h
+++ b/include/qapi/qmp/qlit.h
@@ -42,6 +42,10 @@ struct QLitDictEntry {
 { .type = QTYPE_QBOOL, .value.qbool = (val) }
 #define QLIT_QNUM_INT(val) \
 { .type = QTYPE_QNUM, .value.qnum = QNUM_VAL_INT(val) }
+#define QLIT_QNUM_UINT(val) \
+{ .type = QTYPE_QNUM, .value.qnum = QNUM_VAL_UINT(val) }
+#define QLIT_QNUM_DOUBLE(val) \
+{ .type = QTYPE_QNUM, .value.qnum = QNUM_VAL_DOUBLE(val) }
 #define QLIT_QSTR(val) \
 { .type = QTYPE_QSTRING, .value.qstr = (val) }
 #define QLIT_QDICT(val) \
diff --git a/tests/check-qlit.c b/tests/check-qlit.c
index 5a9260b93f..31e90f8965 100644
--- a/tests/check-qlit.c
+++ b/tests/check-qlit.c
@@ -58,6 +58,11 @@ static void qlit_equal_qobject_test(void)
 QLIT_QNUM_INT(1),
 QLIT_QNUM_INT(INT64_MIN),
 QLIT_QNUM_INT(INT64_MAX),
+QLIT_QNUM_UINT(UINT64_MAX),
+/* Larger than UINT64_MAX: */
+QLIT_QNUM_DOUBLE(18446744073709552e3),
+/* Smaller than INT64_MIN: */
+QLIT_QNUM_DOUBLE(-92233720368547758e2),
 QLIT_QSTR(""),
 QLIT_QSTR("foo"),
 qlit,
-- 
2.28.0




[PATCH v3 01/19] qnum: Make qnum_get_double() get const pointer

2020-11-23 Thread Eduardo Habkost
qnum_get_double() won't change the object, the argument can be
const.

Reviewed-by: Marc-André Lureau 
Signed-off-by: Eduardo Habkost 
---
 include/qapi/qmp/qnum.h | 2 +-
 qobject/qnum.c  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/qapi/qmp/qnum.h b/include/qapi/qmp/qnum.h
index bbae0a5ec8..3e9ecd324e 100644
--- a/include/qapi/qmp/qnum.h
+++ b/include/qapi/qmp/qnum.h
@@ -64,7 +64,7 @@ int64_t qnum_get_int(const QNum *qn);
 bool qnum_get_try_uint(const QNum *qn, uint64_t *val);
 uint64_t qnum_get_uint(const QNum *qn);
 
-double qnum_get_double(QNum *qn);
+double qnum_get_double(const QNum *qn);
 
 char *qnum_to_string(QNum *qn);
 
diff --git a/qobject/qnum.c b/qobject/qnum.c
index 7012fc57f2..d328d91fcb 100644
--- a/qobject/qnum.c
+++ b/qobject/qnum.c
@@ -144,7 +144,7 @@ uint64_t qnum_get_uint(const QNum *qn)
  *
  * qnum_get_double() loses precision for integers beyond 53 bits.
  */
-double qnum_get_double(QNum *qn)
+double qnum_get_double(const QNum *qn)
 {
 switch (qn->kind) {
 case QNUM_I64:
-- 
2.28.0




  1   2   3   4   >