Re: [PATCH v1 15/40] i386/tdx: Add property sept-ve-disable for tdx-guest object

2022-09-01 Thread Gerd Hoffmann
On Fri, Sep 02, 2022 at 02:52:25AM +, Sean Christopherson wrote:
> On Fri, Sep 02, 2022, Xiaoyao Li wrote:
> > On 8/26/2022 1:57 PM, Gerd Hoffmann wrote:
> > >Hi,
> > > > For TD guest kernel, it has its own reason to turn SEPT_VE on or off. 
> > > > E.g.,
> > > > linux TD guest requires SEPT_VE to be disabled to avoid #VE on syscall 
> > > > gap
> > > > [1].
> > > 
> > > Why is that a problem for a TD guest kernel?  Installing exception
> > > handlers is done quite early in the boot process, certainly before any
> > > userspace code runs.  So I think we should never see a syscall without
> > > a #VE handler being installed.  /me is confused.
> > > 
> > > Or do you want tell me linux has no #VE handler?
> > 
> > The problem is not "no #VE handler" and Linux does have #VE handler. The
> > problem is Linux doesn't want any (or certain) exception occurrence in
> > syscall gap, it's not specific to #VE. Frankly, I don't understand the
> > reason clearly, it's something related to IST used in x86 Linux kernel.
> 
> The SYSCALL gap issue is that because SYSCALL doesn't load RSP, the first 
> instruction
> at the SYSCALL entry point runs with a userspaced-controlled RSP.  With TDX, a
> malicious hypervisor can induce a #VE on the SYSCALL page and thus get the 
> kernel
> to run the #VE handler with a userspace stack.
> 
> The "fix" is to use an IST for #VE so that a kernel-controlled RSP is loaded 
> on #VE,
> but ISTs are terrible because they don't play nice with re-entrancy (among 
> other
> reasons).  The RSP used for IST-based handlers is hardcoded, and so if a #VE
> handler triggers another #VE at any point before IRET, the second #VE will 
> clobber
> the stack and hose the kernel.
> v
> It's possible to workaround this, e.g. change the IST entry at the very 
> beginning
> of the handler, but it's a maintenance burden.  Since the only reason to use 
> an IST
> is to guard against a malicious hypervisor, Linux decided it would be just as 
> easy
> and more beneficial to avoid unexpected #VEs due to unaccepted private pages 
> entirely.

Hmm, ok, but shouldn't the SEPT_VE bit *really* controlled by the guest then?

Having a hypervisor-controlled config bit to protect against a malicious
hypervisor looks pointless to me ...

take care,
  Gerd




Re: [PATCH v3 1/3] util/main-loop: Fix maximum number of wait objects for win32

2022-09-01 Thread Bin Meng
On Wed, Aug 24, 2022 at 4:52 PM Bin Meng  wrote:
>
> From: Bin Meng 
>
> The maximum number of wait objects for win32 should be
> MAXIMUM_WAIT_OBJECTS, not MAXIMUM_WAIT_OBJECTS + 1.
>
> Signed-off-by: Bin Meng 
> ---
>
> Changes in v3:
> - move the check of adding the same HANDLE twice to a separete patch
>
> Changes in v2:
> - fix the logic in qemu_add_wait_object() to avoid adding
>   the same HANDLE twice
>
>  util/main-loop.c | 11 +++
>  1 file changed, 7 insertions(+), 4 deletions(-)
>
> diff --git a/util/main-loop.c b/util/main-loop.c
> index f00a25451b..cb018dc33c 100644
> --- a/util/main-loop.c
> +++ b/util/main-loop.c
> @@ -363,10 +363,10 @@ void qemu_del_polling_cb(PollingFunc *func, void 
> *opaque)
>  /* Wait objects support */
>  typedef struct WaitObjects {
>  int num;
> -int revents[MAXIMUM_WAIT_OBJECTS + 1];
> -HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
> -WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
> -void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
> +int revents[MAXIMUM_WAIT_OBJECTS];
> +HANDLE events[MAXIMUM_WAIT_OBJECTS];
> +WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS];
> +void *opaque[MAXIMUM_WAIT_OBJECTS];
>  } WaitObjects;
>
>  static WaitObjects wait_objects = {0};
> @@ -395,6 +395,9 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc 
> *func, void *opaque)
>  if (w->events[i] == handle) {
>  found = 1;
>  }
> +if (i == MAXIMUM_WAIT_OBJECTS - 1) {
> +break;
> +}
>  if (found) {
>  w->events[i] = w->events[i + 1];
>  w->func[i] = w->func[i + 1];
> --

Ping for this series?



[PATCH] RISC-V: Add support for Ztso

2022-09-01 Thread Palmer Dabbelt
Ztso, the RISC-V extension that provides the TSO memory model, was
recently frozen.  This provides support for Ztso on targets that are
themselves TSO.

Signed-off-by: Palmer Dabbelt 

---

My first thought was to just add the TCG barries to load/store and AMOs
that as defined by Ztso, but after poking around a bit it seems that's
frowned upon by check_tcg_memory_orders_compatible().  I feel like the
indicated performance issues could probably be worked out, but this is
about the same amount of code and doesn't suffer from those performance
issues.  That said, it just seems wrong to couple targets to a RISC-V
feature.

This is also essentially un-tested, aside from poking around in the
generated device tree to make sure "_ztso" shows up when enabled.  I
don't think there's really any way to test it further, as we don't have
any TSO-enabled workloads and we were defacto providing TSO already on
x86 targets (which I'm assuming are what the vast majority of users are
running).
---
 target/riscv/cpu.c   | 12 
 target/riscv/cpu.h   | 16 +++-
 target/riscv/translate.c |  6 ++
 tcg/i386/tcg-target.h|  1 +
 tcg/s390x/tcg-target.h   |  1 +
 5 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index ac6f82ebd0..d05b8c7c4a 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -919,6 +919,15 @@ static Property riscv_cpu_extensions[] = {
 DEFINE_PROP_BOOL("zhinx", RISCVCPU, cfg.ext_zhinx, false),
 DEFINE_PROP_BOOL("zhinxmin", RISCVCPU, cfg.ext_zhinxmin, false),
 
+#ifdef TCG_TARGET_SUPPORTS_MCTCG_RVTSO
+/*
+ * We only support Ztso on targets that themselves are already TSO, which
+ * means there's no way to provide just RVWMO on those targets.  Instead
+ * just default to telling the guest that Ztso is enabled.:
+ */
+DEFINE_PROP_BOOL("ztso", RISCVCPU, cfg.ext_ztso, true),
+#endif
+
 /* Vendor-specific custom extensions */
 DEFINE_PROP_BOOL("xventanacondops", RISCVCPU, cfg.ext_XVentanaCondOps, 
false),
 
@@ -1094,6 +1103,9 @@ static void riscv_isa_string_ext(RISCVCPU *cpu, char 
**isa_str, int max_str_len)
 ISA_EDATA_ENTRY(zksed, ext_zksed),
 ISA_EDATA_ENTRY(zksh, ext_zksh),
 ISA_EDATA_ENTRY(zkt, ext_zkt),
+#ifdef TCG_TARGET_SUPPORTS_MCTCG_RVTSO
+ISA_EDATA_ENTRY(ztso, ext_ztso),
+#endif
 ISA_EDATA_ENTRY(zve32f, ext_zve32f),
 ISA_EDATA_ENTRY(zve64f, ext_zve64f),
 ISA_EDATA_ENTRY(zhinx, ext_zhinx),
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 5c7acc055a..879e11a950 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -27,8 +27,19 @@
 #include "qom/object.h"
 #include "qemu/int128.h"
 #include "cpu_bits.h"
+#include "tcg-target.h"
 
-#define TCG_GUEST_DEFAULT_MO 0
+/*
+ * RISC-V has two memory models: TSO is a bit weaker than Intel (MMIO and
+ * fetch), and WMO is approximately equivilant to Arm MCA.  Rather than
+ * enforcing orderings on most accesses, just default to the target memory
+ * order.
+ */
+#ifdef TCG_TARGET_SUPPORTS_MCTCG_RVTSO
+# define TCG_GUEST_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD)
+#else
+# define TCG_GUEST_DEFAULT_MO (0)
+#endif
 
 /*
  * RISC-V-specific extra insn start words:
@@ -433,6 +444,9 @@ struct RISCVCPUConfig {
 bool ext_zve32f;
 bool ext_zve64f;
 bool ext_zmmul;
+#ifdef TCG_TARGET_SUPPORTS_MCTCG_RVTSO
+bool ext_ztso;
+#endif
 bool rvv_ta_all_1s;
 
 uint32_t mvendorid;
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 63b04e8a94..00fd75b971 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -109,6 +109,9 @@ typedef struct DisasContext {
 /* PointerMasking extension */
 bool pm_mask_enabled;
 bool pm_base_enabled;
+#ifdef TCG_TARGET_SUPPORTS_MCTCG_RVTSO
+bool ztso;
+#endif
 /* TCG of the current insn_start */
 TCGOp *insn_start;
 } DisasContext;
@@ -1109,6 +1112,9 @@ static void riscv_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cs)
 memset(ctx->ftemp, 0, sizeof(ctx->ftemp));
 ctx->pm_mask_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_MASK_ENABLED);
 ctx->pm_base_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_BASE_ENABLED);
+#ifdef TCG_TARGET_SUPPORTS_MCTCG_RVTSO
+ctx->ztso = cpu->cfg.ext_ztso;
+#endif
 ctx->zero = tcg_constant_tl(0);
 }
 
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index 00fcbe297d..2a43d54fcd 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -236,6 +236,7 @@ static inline void tb_target_set_jmp_target(uintptr_t 
tc_ptr, uintptr_t jmp_rx,
 #include "tcg/tcg-mo.h"
 
 #define TCG_TARGET_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD)
+#define TCG_TARGET_SUPPORTS_MCTCG_RVTSO 1
 
 #define TCG_TARGET_HAS_MEMORY_BSWAP  have_movbe
 
diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h
index 23e2063667..f423c124a0 100644
--- a/tcg/s390x/tcg-target.h
+++ b/tcg/s390x/tcg-target.h
@@ -171,6 +171,7 @@ extern uint64_t 

Re: [PATCH v2 0/8] vhost-user-blk: dynamically resize config space based on features

2022-09-01 Thread Raphael Norwitz
> ping

Apologies for the late review - busy week. First pass looks good but will review
comprehensively tomorrow or over the weekend.



Re: [PATCH v1 15/40] i386/tdx: Add property sept-ve-disable for tdx-guest object

2022-09-01 Thread Sean Christopherson
On Fri, Sep 02, 2022, Xiaoyao Li wrote:
> On 8/26/2022 1:57 PM, Gerd Hoffmann wrote:
> >Hi,
> > > For TD guest kernel, it has its own reason to turn SEPT_VE on or off. 
> > > E.g.,
> > > linux TD guest requires SEPT_VE to be disabled to avoid #VE on syscall gap
> > > [1].
> > 
> > Why is that a problem for a TD guest kernel?  Installing exception
> > handlers is done quite early in the boot process, certainly before any
> > userspace code runs.  So I think we should never see a syscall without
> > a #VE handler being installed.  /me is confused.
> > 
> > Or do you want tell me linux has no #VE handler?
> 
> The problem is not "no #VE handler" and Linux does have #VE handler. The
> problem is Linux doesn't want any (or certain) exception occurrence in
> syscall gap, it's not specific to #VE. Frankly, I don't understand the
> reason clearly, it's something related to IST used in x86 Linux kernel.

The SYSCALL gap issue is that because SYSCALL doesn't load RSP, the first 
instruction
at the SYSCALL entry point runs with a userspaced-controlled RSP.  With TDX, a
malicious hypervisor can induce a #VE on the SYSCALL page and thus get the 
kernel
to run the #VE handler with a userspace stack.

The "fix" is to use an IST for #VE so that a kernel-controlled RSP is loaded on 
#VE,
but ISTs are terrible because they don't play nice with re-entrancy (among other
reasons).  The RSP used for IST-based handlers is hardcoded, and so if a #VE
handler triggers another #VE at any point before IRET, the second #VE will 
clobber
the stack and hose the kernel.

It's possible to workaround this, e.g. change the IST entry at the very 
beginning
of the handler, but it's a maintenance burden.  Since the only reason to use an 
IST
is to guard against a malicious hypervisor, Linux decided it would be just as 
easy
and more beneficial to avoid unexpected #VEs due to unaccepted private pages 
entirely.



Re: [PATCH v1 15/40] i386/tdx: Add property sept-ve-disable for tdx-guest object

2022-09-01 Thread Xiaoyao Li

On 8/26/2022 1:57 PM, Gerd Hoffmann wrote:

   Hi,
  

For TD guest kernel, it has its own reason to turn SEPT_VE on or off. E.g.,
linux TD guest requires SEPT_VE to be disabled to avoid #VE on syscall gap
[1].


Why is that a problem for a TD guest kernel?  Installing exception
handlers is done quite early in the boot process, certainly before any
userspace code runs.  So I think we should never see a syscall without
a #VE handler being installed.  /me is confused.

Or do you want tell me linux has no #VE handler?


The problem is not "no #VE handler" and Linux does have #VE handler. The 
problem is Linux doesn't want any (or certain) exception occurrence in 
syscall gap, it's not specific to #VE. Frankly, I don't understand the 
reason clearly, it's something related to IST used in x86 Linux kernel.



Frankly speaking, this bit is better to be configured by TD guest
kernel, however current TDX architecture makes the design to let VMM
configure.


Indeed.  Requiring users to know guest kernel capabilities and manually
configuring the vmm accordingly looks fragile to me.

Even better would be to not have that bit in the first place and require
TD guests properly handle #VE exceptions.


This can cause problems with the "system call gap": a malicious
hypervisor might trigger a #VE for example on the system call entry
code, and when a user process does a system call it would trigger a
and SYSCALL relies on the kernel code to switch to the kernel stack,
this would lead to kernel code running on the ring 3 stack.


Hmm?  Exceptions switch to kernel context too ...

take care,
   Gerd






Re: [PATCH v8 3/7] block: add block layer APIs resembling Linux ZonedBlockDevice ioctls

2022-09-01 Thread Damien Le Moal
On 9/1/22 23:57, Markus Armbruster wrote:
> Sam Li  writes:
> 
>> Markus Armbruster  于2022年8月31日周三 16:35写道:
>>>
>>> Sam Li  writes:
>>>
 Markus Armbruster  于2022年8月30日周二 19:57写道:
>
> Sam Li  writes:
>
>> By adding zone management operations in BlockDriver, storage controller
>> emulation can use the new block layer APIs including Report Zone and
>> four zone management operations (open, close, finish, reset).
>>
>> Add zoned storage commands of the device: zone_report(zrp), 
>> zone_open(zo),
>> zone_close(zc), zone_reset(zrs), zone_finish(zf).
>>
>> For example, to test zone_report, use following command:
>> $ ./build/qemu-io --image-opts driver=zoned_host_device, 
>> filename=/dev/nullb0
>> -c "zrp offset nr_zones"
>>
>> Signed-off-by: Sam Li 
>> Reviewed-by: Hannes Reinecke 
>
> [...]
>
>> diff --git a/block/file-posix.c b/block/file-posix.c
>> index 0a8b4b426e..e3efba6db7 100644
>> --- a/block/file-posix.c
>> +++ b/block/file-posix.c
>
> [...]
>
>> @@ -3752,6 +4025,54 @@ static BlockDriver bdrv_host_device = {
>>  #endif
>>  };
>>
>> +#if defined(CONFIG_BLKZONED)
>> +static BlockDriver bdrv_zoned_host_device = {
>> +.format_name = "zoned_host_device",
>
> Indentation should be 4, not 8.
>
>> +.protocol_name = "zoned_host_device",
>> +.instance_size = sizeof(BDRVRawState),
>> +.bdrv_needs_filename = true,
>> +.bdrv_probe_device  = hdev_probe_device,
>> +.bdrv_file_open = hdev_open,
>> +.bdrv_close = raw_close,
>> +.bdrv_reopen_prepare = raw_reopen_prepare,
>> +.bdrv_reopen_commit  = raw_reopen_commit,
>> +.bdrv_reopen_abort   = raw_reopen_abort,
>> +.bdrv_co_create_opts = bdrv_co_create_opts_simple,
>> +.create_opts = _create_opts_simple,
>> +.mutable_opts= mutable_opts,
>> +.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
>> +.bdrv_co_pwrite_zeroes = hdev_co_pwrite_zeroes,
>> +
>> +.bdrv_co_preadv = raw_co_preadv,
>> +.bdrv_co_pwritev= raw_co_pwritev,
>> +.bdrv_co_flush_to_disk  = raw_co_flush_to_disk,
>> +.bdrv_co_pdiscard   = hdev_co_pdiscard,
>> +.bdrv_co_copy_range_from = raw_co_copy_range_from,
>> +.bdrv_co_copy_range_to  = raw_co_copy_range_to,
>> +.bdrv_refresh_limits = raw_refresh_limits,
>> +.bdrv_io_plug = raw_aio_plug,
>> +.bdrv_io_unplug = raw_aio_unplug,
>> +.bdrv_attach_aio_context = raw_aio_attach_aio_context,
>> +
>> +.bdrv_co_truncate   = raw_co_truncate,
>> +.bdrv_getlength = raw_getlength,
>> +.bdrv_get_info = raw_get_info,
>> +.bdrv_get_allocated_file_size
>> += raw_get_allocated_file_size,
>> +.bdrv_get_specific_stats = hdev_get_specific_stats,
>> +.bdrv_check_perm = raw_check_perm,
>> +.bdrv_set_perm   = raw_set_perm,
>> +.bdrv_abort_perm_update = raw_abort_perm_update,
>> +.bdrv_probe_blocksizes = hdev_probe_blocksizes,
>> +.bdrv_probe_geometry = hdev_probe_geometry,
>> +.bdrv_co_ioctl = hdev_co_ioctl,
>> +
>> +/* zone management operations */
>> +.bdrv_co_zone_report = raw_co_zone_report,
>> +.bdrv_co_zone_mgmt = raw_co_zone_mgmt,
>> +};
>
> Differences to bdrv_host_device:
>
> * .bdrv_parse_filename is not set
>
> * .bdrv_co_ioctl is not set
>
> * .bdrv_co_zone_report and .bdrv_co_zone_mgmt are set

 As Stefan mentioned, zoned_host_device is a new driver that doesn't
 work with string filenames. .bdrv_parse_filename() helps legacy
 drivers strip the optional protocol prefix off the filename and no use
 here. Therefore it can be dropped.
>>>
>>> Makes sense.
>>>
 .bdrv_co_ioctl is set actually.
>>>
>>> You're right; I diffed the two and misread the result.
>>>
 Zoned_host_device is basically host_device + zone operations. It
 serves for a simple purpose: if the host device is zoned, register
 zoned_host_device driver; else, register host_device.
>>>
>>> Why would I ever want to use host_device instead of zoned_host_device?
>>>
>>> To answer this question, we need to understand how their behavior
>>> differs.
>>>
>>> We can ignore the legacy protocol prefix / string filename part.
>>>
>>> All that's left seems to be "if the host device is zoned, then using the
>>> zoned_host_device driver gets you the zoned features, whereas using the
>>> host_device driver doesn't".  What am I missing?
>>
>> I think that's basically what users need to know about.
> 
> Now answer my previous question, please: why would 

Re: [Qemu-devel] [RFC PATCH] Add qemu .clang-format

2022-09-01 Thread Wang, Lei
On 9/1/2022 7:55 PM, Alex Bennée wrote:
> 
> "Wang, Lei"  writes:
> 
>> On 9/1/2022 4:12 PM, Daniel P. Berrangé wrote:
>>> On Thu, Sep 01, 2022 at 09:08:33AM +0800, Wang, Lei wrote:
 On 8/31/2022 6:39 PM, Daniel P. Berrangé wrote:
> On Wed, Aug 31, 2022 at 05:18:34PM +0800, Wang, Lei wrote:
>>
>>
>> On 8/31/2022 4:49 PM, Daniel P. Berrangé wrote:
>>> On Wed, Aug 31, 2022 at 02:23:51PM +0800, Wang, Lei wrote:

 On 10/2/2015 1:30 AM, marcandre.lur...@redhat.com wrote:
> From: Marc-André Lureau 
>
> clang-format is awesome to reflow your code according to qemu coding
> style in an editor (in the region you modify).
>
> (note: clang-tidy should be able to add missing braces around
> statements, but I haven't tried it, it's quite recent)
>
> Signed-off-by: Marc-André Lureau 
> ---
> .clang-format | 6 ++
> 1 file changed, 6 insertions(+)
> create mode 100644 .clang-format
>
> diff --git a/.clang-format b/.clang-format
> new file mode 100644
> index 000..6422547
> --- /dev/null
> +++ b/.clang-format
> @@ -0,0 +1,6 @@
> +BasedOnStyle: LLVM
> +IndentWidth: 4
> +UseTab: Never
> +BreakBeforeBraces: Linux
> +AllowShortIfStatementsOnASingleLine: false
> +IndentCaseLabels: false

 Hi, any progress on this? I also found a gist on GitHub which can be a
 reference: 
 https://gist.github.com/elmarco/aa5e0b23567f46fb7f0e73cde586a0c1
>>>
>>> clang-format is a great tool and I'd highly recommend its use on
>>> any newly started projects, and even retrospectively on existing
>>> projects which are small scale. Adding it to large existing projects
>>> is problematic though.
>>>
>>> None of the QEMU code complies with it today and indeed there is
>>> quite a bit of style variance across different parts of QEMU. If
>>> we add this config file, and someone makes a 1 line change in a
>>> file, clang-format will reformat the entire file contents.
>>>
>>> The only practical way to introduce use of clang-format would be
>>> to do a bulk reformat of the entire codebase. That is something
>>> that is quite disruptive to both people with patches they're
>>> working on but not submitted yet, as well as people wanting to
>>> cherry-pick new commits back to old code branches.
>>>
>>> With regards,
>>> Daniel
>>
>> I think the benefits of introducing clang-format mainly for its ability 
>> to
>> format a code range, which means for any future contributions, we could
>> encourage a range format before the patch is generated. This can 
>> extensively
>> simplify my workflow, especially because I use the Neovim + LSP 
>> combination,
>> which supports a built-in function "lua vim.lsp.buf.range_formatting()".
>
> IMHO partial format conversions are even worse than full conversions,
> because they would make code inconsistent within the scope of a file.

 So you mean when we're adding new code in an old file, the coding style
 should also be the old one? That sounds a bit unreasonable. I thought we 
 are
 shifting the coding style in an on-demand way, so we can finally achieve to
 the new style mildly, if each time we're using the old coding style, that
 could be impossible.
>>>
>>> From my POV as a maintainer, the best situation would be consistency across
>>> the entire codebase. Since we likely won't get that though, then next best
>>> is consistency across the subsystem directory, and next best is consistency
>>> across the whole file.  Mixing code styles within a file is the worst IMHO.
>>>

>> I have no interest in reformatting the existing code and also think 
>> using it
>> to reformat an entire file shouldn't be encouraged, but, we can leverage
>> this tool to give future contributions a better experience. It's also
>> important to note that the kernel already has a ".clang-format" file, so 
>> I
>> think we can give it a try:)
>
> The mere action of introducing a .clang-format file in the root of the
> repository will cause some contributors' editors to automatically
> reformat files every time they are saved. IOW even if you don't want
> intend to do reformatting, that will be a net result.

 I think that depends on developer's configuration, as far as I know, format
 on save is a feature which can be easily disabled on most of the IDE's, 
 such
 as VSCode.
>>>
>>> You could disable it, but it requires each developer to know that we're
>>> shipping a clang-format that should not in fact be used to reformat
>>> code, which is rather counterintuitive. 
>>>
>>> With regards,
>>> Daniel
>>
>> OK, your POV makes sense too. I 

Re: [PATCH] scsi/lsi53c895a: really fix use-after-free in lsi_do_msgout (CVE-2022-0216)

2022-09-01 Thread Bin Meng
Hi,

On Wed, Jul 13, 2022 at 8:45 PM Paolo Bonzini  wrote:
>
> From: Mauro Matteo Cascella 
>
> Set current_req to NULL, not current_req->req, to prevent reusing a free'd
> buffer in case of repeated SCSI cancel requests.  Also apply the fix to
> CLEAR QUEUE and BUS DEVICE RESET messages as well, since they also cancel
> the request.
>
> Thanks to Alexander Bulekov for providing a reproducer.
>
> Fixes: CVE-2022-0216
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/972
> Signed-off-by: Mauro Matteo Cascella 
> Tested-by: Alexander Bulekov 
> Message-Id: <20220711123316.421279-1-mcasc...@redhat.com>
> Signed-off-by: Paolo Bonzini 
> ---
> Adjust the patch from v1 to v2 since the changes crossed
> with the pull request.
>
>  hw/scsi/lsi53c895a.c   |  3 +-
>  tests/qtest/fuzz-lsi53c895a-test.c | 71 ++
>  2 files changed, 73 insertions(+), 1 deletion(-)
>
> diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
> index 99ea42d49b..ad5f5e5f39 100644
> --- a/hw/scsi/lsi53c895a.c
> +++ b/hw/scsi/lsi53c895a.c
> @@ -1030,7 +1030,7 @@ static void lsi_do_msgout(LSIState *s)
>  trace_lsi_do_msgout_abort(current_tag);
>  if (current_req && current_req->req) {
>  scsi_req_cancel(current_req->req);
> -current_req->req = NULL;
> +current_req = NULL;
>  }
>  lsi_disconnect(s);
>  break;
> @@ -1056,6 +1056,7 @@ static void lsi_do_msgout(LSIState *s)
>  /* clear the current I/O process */
>  if (s->current) {
>  scsi_req_cancel(s->current->req);
> +current_req = NULL;
>  }
>
>  /* As the current implemented devices scsi_disk and scsi_generic
> diff --git a/tests/qtest/fuzz-lsi53c895a-test.c 
> b/tests/qtest/fuzz-lsi53c895a-test.c
> index 2e8e67859e..6872c70d3a 100644
> --- a/tests/qtest/fuzz-lsi53c895a-test.c
> +++ b/tests/qtest/fuzz-lsi53c895a-test.c
> @@ -8,6 +8,74 @@
>  #include "qemu/osdep.h"
>  #include "libqtest.h"
>
> +/*
> + * This used to trigger a UAF in lsi_do_msgout()
> + * https://gitlab.com/qemu-project/qemu/-/issues/972
> + */
> +static void test_lsi_do_msgout_cancel_req(void)
> +{
> +QTestState *s;
> +
> +s = qtest_init("-M q35 -m 4G -display none -nodefaults "

This test does not run on machines with small size memory. Is 4G a
must have for this test?

> +   "-device lsi53c895a,id=scsi "
> +   "-device scsi-hd,drive=disk0 "
> +   "-drive file=null-co://,id=disk0,if=none,format=raw");
> +
> +qtest_outl(s, 0xcf8, 0x8810);
> +qtest_outl(s, 0xcf8, 0xc000);
> +qtest_outl(s, 0xcf8, 0x8810);
> +qtest_outw(s, 0xcfc, 0x7);
> +qtest_outl(s, 0xcf8, 0x8810);
> +qtest_outl(s, 0xcfc, 0xc000);
> +qtest_outl(s, 0xcf8, 0x8804);
> +qtest_outw(s, 0xcfc, 0x05);
> +qtest_writeb(s, 0x69736c10, 0x08);
> +qtest_writeb(s, 0x69736c13, 0x58);
> +qtest_writeb(s, 0x69736c1a, 0x01);
> +qtest_writeb(s, 0x69736c1b, 0x06);
> +qtest_writeb(s, 0x69736c22, 0x01);
> +qtest_writeb(s, 0x69736c23, 0x07);
> +qtest_writeb(s, 0x69736c2b, 0x02);
> +qtest_writeb(s, 0x69736c48, 0x08);
> +qtest_writeb(s, 0x69736c4b, 0x58);
> +qtest_writeb(s, 0x69736c52, 0x04);
> +qtest_writeb(s, 0x69736c53, 0x06);
> +qtest_writeb(s, 0x69736c5b, 0x02);
> +qtest_outl(s, 0xc02d, 0x697300);
> +qtest_writeb(s, 0x5a554662, 0x01);
> +qtest_writeb(s, 0x5a554663, 0x07);
> +qtest_writeb(s, 0x5a55466a, 0x10);
> +qtest_writeb(s, 0x5a55466b, 0x22);
> +qtest_writeb(s, 0x5a55466c, 0x5a);
> +qtest_writeb(s, 0x5a55466d, 0x5a);
> +qtest_writeb(s, 0x5a55466e, 0x34);
> +qtest_writeb(s, 0x5a55466f, 0x5a);
> +qtest_writeb(s, 0x5a345a5a, 0x77);
> +qtest_writeb(s, 0x5a345a5b, 0x55);
> +qtest_writeb(s, 0x5a345a5c, 0x51);
> +qtest_writeb(s, 0x5a345a5d, 0x27);
> +qtest_writeb(s, 0x27515577, 0x41);
> +qtest_outl(s, 0xc02d, 0x5a5500);
> +qtest_writeb(s, 0x364001d0, 0x08);
> +qtest_writeb(s, 0x364001d3, 0x58);
> +qtest_writeb(s, 0x364001da, 0x01);
> +qtest_writeb(s, 0x364001db, 0x26);
> +qtest_writeb(s, 0x364001dc, 0x0d);
> +qtest_writeb(s, 0x364001dd, 0xae);
> +qtest_writeb(s, 0x364001de, 0x41);
> +qtest_writeb(s, 0x364001df, 0x5a);
> +qtest_writeb(s, 0x5a41ae0d, 0xf8);
> +qtest_writeb(s, 0x5a41ae0e, 0x36);
> +qtest_writeb(s, 0x5a41ae0f, 0xd7);
> +qtest_writeb(s, 0x5a41ae10, 0x36);
> +qtest_writeb(s, 0x36d736f8, 0x0c);
> +qtest_writeb(s, 0x36d736f9, 0x80);
> +qtest_writeb(s, 0x36d736fa, 0x0d);
> +qtest_outl(s, 0xc02d, 0x364000);
> +
> +qtest_quit(s);
> +}
> +
>  /*
>   * This used to trigger the assert in lsi_do_dma()
>   * https://bugs.launchpad.net/qemu/+bug/697510
> @@ -44,5 +112,8 @@ int main(int argc, char **argv)
>  

[PATCH 4/4] hw/timer: ibex_timer.c: Add support for writes to mtime

2022-09-01 Thread Tyler Ng
1. Adds fields to hold the value of mtime in timer_upper0 and timer_lower0.

2. Changes the read and write functions to use the mtime fields.

3. Updates the value of mtime in update_mtime() by extrapolating the
time elapsed. This will need to change if/when the prescalar is
implemented.

Signed-off-by: Tyler Ng 
---
 hw/timer/ibex_timer.c | 94 +--
 include/hw/timer/ibex_timer.h |  5 ++
 2 files changed, 73 insertions(+), 26 deletions(-)

diff --git a/hw/timer/ibex_timer.c b/hw/timer/ibex_timer.c
index 9ffd4821e8..7d0ea2db1e 100644
--- a/hw/timer/ibex_timer.c
+++ b/hw/timer/ibex_timer.c
@@ -52,30 +52,59 @@ REG32(UPPER0, 0x114)
 REG32(COMPARE_LOWER0, 0x118)
 REG32(COMPARE_UPPER0, 0x11C)

-static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
+
+/*
+ * The goal of this function is to:
+ * 1. Check if the timer is enabled. If not, return false,
+ * 2. Calculate the amount of time that has passed since.
+ * 3. Extrapolate the number of ticks that have passed, and add it to `mtime`.
+ * 4. Return true.
+ */
+static bool update_mtime(IbexTimerState *s)
+{
+if (!(R_CTRL & R_CTRL_ACTIVE_MASK)) {
+return false;
+}
+/* Get the time then extrapolate the number of ticks that have elapsed */
+uint64_t mtime = (s->timer_lower0) | ((uint64_t) s->timer_upper0 << 32);
+int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+int64_t elapsed = now - s->timer_last_update;
+if (elapsed < 0) {
+/* We jumped back in time. */
+mtime -= muldiv64((uint64_t)(-elapsed), s->timebase_freq,
+   NANOSECONDS_PER_SECOND);
+} else {
+mtime += muldiv64(elapsed, s->timebase_freq, NANOSECONDS_PER_SECOND);
+}
+s->timer_lower0 = mtime & 0x;
+s->timer_upper0 = (mtime >> 32) & 0x;
+/* update last-checkpoint timestamp */
+s->timer_last_update = now;
+return true;
+}
+
+static inline uint64_t cpu_riscv_read_rtc(void *opaque)
 {
-return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
-timebase_freq, NANOSECONDS_PER_SECOND);
+IbexTimerState *s = opaque;
+return (s->timer_lower0) | ((uint64_t) s->timer_upper0 << 32);
 }

 static void ibex_timer_update_irqs(IbexTimerState *s)
 {
 CPUState *cs = qemu_get_cpu(0);
 RISCVCPU *cpu = RISCV_CPU(cs);
-uint64_t value = s->timer_compare_lower0 |
+uint64_t mtimecmp = s->timer_compare_lower0 |
  ((uint64_t)s->timer_compare_upper0 << 32);
-uint64_t next, diff;
-uint64_t now = cpu_riscv_read_rtc(s->timebase_freq);
-
-if (!(s->timer_ctrl & R_CTRL_ACTIVE_MASK)) {
-/* Timer isn't active */
+if (!update_mtime(s)) {
+/* Timer is not enabled? */
 return;
 }
+uint64_t mtime = cpu_riscv_read_rtc(s);

 /* Update the CPUs mtimecmp */
-cpu->env.timecmp = value;
+cpu->env.timecmp = mtimecmp;

-if (cpu->env.timecmp <= now) {
+if (cpu->env.timecmp <= mtime) {
 /*
  * If the mtimecmp was in the past raise the interrupt now.
  */
@@ -86,18 +115,18 @@ static void ibex_timer_update_irqs(IbexTimerState *s)
 }
 return;
 }
-
+/* Update timers */
+int64_t next;
+uint64_t diff;
 /* Setup a timer to trigger the interrupt in the future */
 qemu_irq_lower(s->m_timer_irq);
 qemu_set_irq(s->irq, false);
-
-diff = cpu->env.timecmp - now;
-next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- muldiv64(diff,
-  NANOSECONDS_PER_SECOND,
-  s->timebase_freq);
-
-if (next < qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) {
+/* Compute the difference, and set a timer for the next update. */
+diff = mtimecmp - mtime;
+const uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+const uint64_t towait = muldiv64(diff, NANOSECONDS_PER_SECOND,
s->timebase_freq);
+next = now + towait;
+if (next < now) {
 /* We overflowed the timer, just set it as large as we can */
 timer_mod(cpu->env.timer, 0x7FFF);
 } else {
@@ -128,11 +157,13 @@ static void ibex_timer_reset(DeviceState *dev)

 s->timer_ctrl = 0x;
 s->timer_cfg0 = 0x0001;
+s->timer_lower0 = 0x;
+s->timer_upper0 = 0x;
 s->timer_compare_lower0 = 0x;
 s->timer_compare_upper0 = 0x;
 s->timer_intr_enable = 0x;
 s->timer_intr_state = 0x;
-
+s->timer_last_update = 0x;
 ibex_timer_update_irqs(s);
 }

@@ -140,7 +171,6 @@ static uint64_t ibex_timer_read(void *opaque, hwaddr addr,
unsigned int size)
 {
 IbexTimerState *s = opaque;
-uint64_t now = cpu_riscv_read_rtc(s->timebase_freq);
 uint64_t retvalue = 0;

 switch (addr >> 2) {
@@ -155,10 +185,12 @@ static uint64_t ibex_timer_read(void *opaque, hwaddr addr,
 

[PATCH 1/4] hw/watchdog: wdt_ibex_aon.c: Implement the watchdog for the OpenTitan

2022-09-01 Thread Tyler Ng
This commit adds most of an implementation of the OpenTitan Always-On
Timer. The documentation for this timer is found here:

https://docs.opentitan.org/hw/ip/aon_timer/doc/

The implementation includes most of the watchdog features; it does not
implement the wakeup timer.

An important note: the OpenTitan board uses the sifive_plic. The plic
will not be able to claim the bark interrupt (158) because the sifive
plic sets priority[158], but checks priority[157] for the priority, so
it thinks that the interrupt's priority is 0 (effectively disabled).

Changed Files:
hw/riscv/Kconfig: Add configuration for the watchdog.
hw/riscv/opentitan.c: Connect AON Timer to the OpenTitan board.

hw/watchdog/Kconfig: Configuration for the watchdog.
hw/watchdog/meson.build: Compile the watchdog.
hw/watchdog/wdt_ibex_aon.c: The watchdog itself.

include/hw/riscv/opentitan.h: Add watchdog bark/wakeup IRQs and timer.
include/hw/watchdog/wdt_ibex_aon.h: Add watchdog.

tests/qtest/ibex-aon-timer-test.c: Ibex Timer test.
tests/qtest/meson.build: Build the timer test.

Signed-off-by: Tyler Ng 
---
 hw/riscv/Kconfig   |   4 +
 hw/riscv/opentitan.c   |  22 +-
 hw/watchdog/Kconfig|   3 +
 hw/watchdog/meson.build|   1 +
 hw/watchdog/wdt_ibex_aon.c | 432 +
 include/hw/riscv/opentitan.h   |   9 +-
 include/hw/watchdog/wdt_ibex_aon.h |  67 +
 tests/qtest/ibex-aon-timer-test.c  | 189 +
 tests/qtest/meson.build|   3 +
 9 files changed, 725 insertions(+), 5 deletions(-)
 create mode 100644 hw/watchdog/wdt_ibex_aon.c
 create mode 100644 include/hw/watchdog/wdt_ibex_aon.h
 create mode 100644 tests/qtest/ibex-aon-timer-test.c

diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 79ff61c464..72094010be 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -4,6 +4,9 @@ config RISCV_NUMA
 config IBEX
 bool

+config IBEX_AON
+bool
+
 config MICROCHIP_PFSOC
 bool
 select CADENCE_SDHCI
@@ -20,6 +23,7 @@ config MICROCHIP_PFSOC
 config OPENTITAN
 bool
 select IBEX
+select IBEX_AON
 select UNIMP

 config SHAKTI_C
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
index 4495a2c039..10834b831f 100644
--- a/hw/riscv/opentitan.c
+++ b/hw/riscv/opentitan.c
@@ -1,4 +1,5 @@
 /*
+ptimer_
  * QEMU RISC-V Board Compatible with OpenTitan FPGA platform
  *
  * Copyright (c) 2020 Western Digital
@@ -47,7 +48,7 @@ static const MemMapEntry ibex_memmap[] = {
 [IBEX_DEV_RSTMGR] = {  0x4041,  0x1000  },
 [IBEX_DEV_CLKMGR] = {  0x4042,  0x1000  },
 [IBEX_DEV_PINMUX] = {  0x4046,  0x1000  },
-[IBEX_DEV_PADCTRL] ={  0x4047,  0x1000  },
+[IBEX_DEV_AON_TIMER] =  {  0x4047,  0x1000  },
 [IBEX_DEV_FLASH_CTRL] = {  0x4100,  0x1000  },
 [IBEX_DEV_AES] ={  0x4110,  0x1000  },
 [IBEX_DEV_HMAC] =   {  0x4111,  0x1000  },
@@ -121,6 +122,8 @@ static void lowrisc_ibex_soc_init(Object *obj)

 object_initialize_child(obj, "timer", >timer, TYPE_IBEX_TIMER);

+object_initialize_child(obj, "aon_timer", >aon_timer,
TYPE_IBEX_AON_TIMER);
+
 for (int i = 0; i < OPENTITAN_NUM_SPI_HOSTS; i++) {
 object_initialize_child(obj, "spi_host[*]", >spi_host[i],
 TYPE_IBEX_SPI_HOST);
@@ -205,6 +208,7 @@ static void lowrisc_ibex_soc_realize(DeviceState
*dev_soc, Error **errp)
3, qdev_get_gpio_in(DEVICE(>plic),
IBEX_UART0_RX_OVERFLOW_IRQ));

+/* RV Timer */
 if (!sysbus_realize(SYS_BUS_DEVICE(>timer), errp)) {
 return;
 }
@@ -215,6 +219,20 @@ static void lowrisc_ibex_soc_realize(DeviceState
*dev_soc, Error **errp)
 qdev_connect_gpio_out(DEVICE(>timer), 0,
   qdev_get_gpio_in(DEVICE(qemu_get_cpu(0)),
IRQ_M_TIMER));
+
+/* AON Timer */
+if (!sysbus_realize(SYS_BUS_DEVICE(>aon_timer), errp)) {
+return;
+}
+sysbus_mmio_map(SYS_BUS_DEVICE(>aon_timer), 0,
memmap[IBEX_DEV_AON_TIMER].base);
+sysbus_connect_irq(SYS_BUS_DEVICE(>aon_timer),
+   0, qdev_get_gpio_in(DEVICE(>plic),
+   IBEX_AONTIMER_WDOG_BARK));
+/*
+ * Note: There should be a line to pwrmgr but it's not implemented.
+ * TODO: Needs a line connected in, "counter-run" (stop the watchdog if
+ * debugging)
+ */

 /* SPI-Hosts */
 for (int i = 0; i < OPENTITAN_NUM_SPI_HOSTS; ++i) {
@@ -261,8 +279,6 @@ static void lowrisc_ibex_soc_realize(DeviceState
*dev_soc, Error **errp)
 memmap[IBEX_DEV_CLKMGR].base, memmap[IBEX_DEV_CLKMGR].size);
 create_unimplemented_device("riscv.lowrisc.ibex.pinmux",
 memmap[IBEX_DEV_PINMUX].base, memmap[IBEX_DEV_PINMUX].size);
-create_unimplemented_device("riscv.lowrisc.ibex.padctrl",
-memmap[IBEX_DEV_PADCTRL].base, 

[PATCH 0/4] Implement the OpenTitan watchdog

2022-09-01 Thread Tyler Ng
This patch series does three things:
1) Adds an implementation of the OpenTitan Always-On Timer's watchdog
functionality
2) Fixes a bug encountered with the SiFive PLIC device during development
3) Updates the register addresses and adds support for writes to mtime
for the Ibex timer

(2) is necessary for the bark interrupt to work. (3) will bring the
Ibex timer up to spec.

Tyler Ng (4):
  hw/watchdog: wdt_ibex_aon.c: Implement the watchdog for the OpenTitan
  hw/intc: sifive_plic.c: Fix interrupt priority index.
  hw/timer: ibex_timer.c: Update register addresses
  hw/timer: ibex_timer.c: Add support for writes to mtime

 hw/intc/sifive_plic.c  |   2 +-
 hw/riscv/Kconfig   |   4 +
 hw/riscv/opentitan.c   |  22 +-
 hw/timer/ibex_timer.c  | 114 +---
 hw/watchdog/Kconfig|   3 +
 hw/watchdog/meson.build|   1 +
 hw/watchdog/wdt_ibex_aon.c | 432 +
 include/hw/riscv/opentitan.h   |   9 +-
 include/hw/timer/ibex_timer.h  |   5 +
 include/hw/watchdog/wdt_ibex_aon.h |  67 +
 tests/qtest/ibex-aon-timer-test.c  | 189 +
 tests/qtest/meson.build|   3 +
 12 files changed, 809 insertions(+), 42 deletions(-)
 create mode 100644 hw/watchdog/wdt_ibex_aon.c
 create mode 100644 include/hw/watchdog/wdt_ibex_aon.h
 create mode 100644 tests/qtest/ibex-aon-timer-test.c

--
2.30.2



[PATCH 3/4] hw/timer: ibex_timer.c: Update register addresses

2022-09-01 Thread Tyler Ng
Updates the register addresses to match the OpenTitan spec.

These changes were made in this commit:
https://github.com/lowRISC/opentitan/commit/a25e162b8f91bd0ca32258c83d1d480f93327204

Signed-off-by: Tyler Ng 
---
 hw/timer/ibex_timer.c | 20 ++--
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/hw/timer/ibex_timer.c b/hw/timer/ibex_timer.c
index 8c2ca364da..9ffd4821e8 100644
--- a/hw/timer/ibex_timer.c
+++ b/hw/timer/ibex_timer.c
@@ -38,19 +38,19 @@ REG32(ALERT_TEST, 0x00)
 FIELD(ALERT_TEST, FATAL_FAULT, 0, 1)
 REG32(CTRL, 0x04)
 FIELD(CTRL, ACTIVE, 0, 1)
-REG32(CFG0, 0x100)
-FIELD(CFG0, PRESCALE, 0, 12)
-FIELD(CFG0, STEP, 16, 8)
-REG32(LOWER0, 0x104)
-REG32(UPPER0, 0x108)
-REG32(COMPARE_LOWER0, 0x10C)
-REG32(COMPARE_UPPER0, 0x110)
-REG32(INTR_ENABLE, 0x114)
+REG32(INTR_ENABLE, 0x100)
 FIELD(INTR_ENABLE, IE_0, 0, 1)
-REG32(INTR_STATE, 0x118)
+REG32(INTR_STATE, 0x104)
 FIELD(INTR_STATE, IS_0, 0, 1)
-REG32(INTR_TEST, 0x11C)
+REG32(INTR_TEST, 0x108)
 FIELD(INTR_TEST, T_0, 0, 1)
+REG32(CFG0, 0x10C)
+FIELD(CFG0, PRESCALE, 0, 12)
+FIELD(CFG0, STEP, 16, 8)
+REG32(LOWER0, 0x110)
+REG32(UPPER0, 0x114)
+REG32(COMPARE_LOWER0, 0x118)
+REG32(COMPARE_UPPER0, 0x11C)

 static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
 {
--
2.30.2



[PATCH 2/4] hw/intc: sifive_plic.c: Fix interrupt priority index.

2022-09-01 Thread Tyler Ng
Fixes a bug in which the index of the interrupt priority is off by 1.
For example, using an IRQ number of 3 with a priority of 1 is supposed to set
plic->source_priority[2] = 1, but instead it sets
plic->source_priority[3] = 1. When an interrupt is claimed to be
serviced, it checks the index 2 instead of 3.

Signed-off-by: Tyler Ng 
---
 hw/intc/sifive_plic.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/intc/sifive_plic.c b/hw/intc/sifive_plic.c
index af4ae3630e..e75c47300a 100644
--- a/hw/intc/sifive_plic.c
+++ b/hw/intc/sifive_plic.c
@@ -178,7 +178,7 @@ static void sifive_plic_write(void *opaque, hwaddr
addr, uint64_t value,
 SiFivePLICState *plic = opaque;

 if (addr_between(addr, plic->priority_base, plic->num_sources << 2)) {
-uint32_t irq = ((addr - plic->priority_base) >> 2) + 1;
+uint32_t irq = ((addr - plic->priority_base) >> 2) + 0;

 plic->source_priority[irq] = value & 7;
 sifive_plic_update(plic);
--
2.30.2



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

2022-09-01 Thread Kangjie Xu

Do you have any comments about this patch set?

Thanks

在 2022/8/25 16:08, Kangjie Xu 写道:

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

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

This patch set is to support this function in QEMU. It consists of several 
parts:
1. Patches 1-7 are the basic interfaces for vq reset in virtio and virtio-pci.
2. Patches 8-11 support vq reset and vq restart for vhost-kernel.
3. Patches 12-14 support vq reset and vq restart for virtio-net.
5. Patch 15 enables the vq reset feature for vhost-kernel.

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

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

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


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

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

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

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

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

Looking forward to your review and comments. Thanks.

changelog:
v3:
   1. Remove support for vhost-user in this series and refactor the code.
   2. Rename 'vhost_net_virtqueue_stop' to 'vhost_net_virtqueue_reset'.
   3. Make PCI transport ready before device ready when queue_enabled is set to 
true.
   3. Add some comments.

v2:
   1. Add support for vhost-net kernel scenario.
   2. Add a new vhost-user message VHOST_USER_RESET_VRING.
   3. Add migration compatibility for virtqueue reset.

Kangjie Xu (10):
   virtio: introduce virtio_queue_enable()
   virtio: core: vq reset feature negotation support
   virtio-pci: support queue enable
   vhost: extract the logic of unmapping the vrings and desc
   vhost: expose vhost_virtqueue_start()
   vhost-net: vhost-kernel: introduce vhost_net_virtqueue_reset()
   vhost-net: vhost-kernel: introduce vhost_net_virtqueue_restart()
   virtio-net: introduce flush_or_purge_queued_packets()
   virtio-net: support queue_enable
   vhost: vhost-kernel: enable vq reset feature

Xuan Zhuo (5):
   virtio: sync relevant definitions with linux
   virtio: introduce __virtio_queue_reset()
   virtio: introduce virtio_queue_reset()
   virtio-pci: support queue reset
   virtio-net: support queue reset

  hw/core/machine.c |  1 +
  hw/net/vhost_net.c| 75 +++
  hw/net/virtio-net.c   | 56 --
  hw/virtio/vhost.c | 28 ---
  hw/virtio/virtio-pci.c| 16 
  hw/virtio/virtio.c| 62 +++
  include/hw/virtio/vhost.h |  5 ++
  include/hw/virtio/virtio-pci.h|  5 ++
  include/hw/virtio/virtio.h|  8 +-
  include/net/vhost_net.h   |  4 +
  .../standard-headers/linux/virtio_config.h|  5 ++
  include/standard-headers/linux/virtio_pci.h   |  2 +
  12 files changed, 234 insertions(+), 33 deletions(-)





[PATCH] KVM: use store-release to mark dirty pages as harvested

2022-09-01 Thread Paolo Bonzini
The following scenario can happen if QEMU sets more RESET flags while
the KVM_RESET_DIRTY_RINGS ioctl is ongoing on another host CPU:

CPU0 CPU1   CPU2
 -- 
fill gfn0
store-rel flags for gfn0
fill gfn1
store-rel flags for gfn1
load-acq flags for gfn0
set RESET for gfn0
load-acq flags for gfn1
set RESET for gfn1
do ioctl! --->
 ioctl(RESET_RINGS)
fill gfn2
store-rel flags for gfn2
load-acq flags for gfn2
set RESET for gfn2
 process gfn0
 process gfn1
 process gfn2
do ioctl!
etc.

The three load-acquire in CPU0 synchronize with the three store-release
in CPU2, but CPU0 and CPU1 are only synchronized up to gfn1 and CPU1
may miss gfn2's fields other than flags.

The kernel must be able to cope with invalid values of the fields, and
userspace *will* invoke the ioctl once more.  However, once the RESET flag
is cleared on gfn2, it is lost forever, therefore in the above scenario
CPU1 must read the correct value of gfn2's fields.

Therefore RESET must be set with a store-release, that will synchronize
with KVM's load-acquire in CPU1.

Cc: Gavin Shan 
Cc: Peter Xu 
Signed-off-by: Paolo Bonzini 
---
 accel/kvm/kvm-all.c | 18 +-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 136c8eaed3..7c8ce18bdd 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -728,7 +728,23 @@ static bool dirty_gfn_is_dirtied(struct kvm_dirty_gfn *gfn)
 
 static void dirty_gfn_set_collected(struct kvm_dirty_gfn *gfn)
 {
-gfn->flags = KVM_DIRTY_GFN_F_RESET;
+/*
+ * Use a store-release so that the CPU that executes KVM_RESET_DIRTY_RINGS
+ * sees the full content of the ring:
+ *
+ * CPU0 CPU1 CPU2
+ * 
--
+ *   fill gfn0
+ *   store-rel flags 
for gfn0
+ * load-acq flags for gfn0
+ * store-rel RESET for gfn0
+ *  ioctl(RESET_RINGS)
+ *load-acq flags for gfn0
+ *check if flags have RESET
+ *
+ * The synchronization goes from CPU2 to CPU0 to CPU1.
+ */
+qatomic_store_release(>flags, KVM_DIRTY_GFN_F_RESET);
 }
 
 /*
-- 
2.37.2




Re: [PATCH 0/2] expose host-phys-bits to guest

2022-09-01 Thread Xiaoyao Li

On 9/2/2022 12:17 AM, Gerd Hoffmann wrote:

On Thu, Sep 01, 2022 at 10:36:19PM +0800, Xiaoyao Li wrote:

On 9/1/2022 9:58 PM, Gerd Hoffmann wrote:


Anyway, IMO, guest including guest firmware, should always consult from
CPUID leaf 0x8008 for physical address length.


It simply can't for the reason outlined above.  Even if we fix qemu
today that doesn't solve the problem for the firmware because we want
backward compatibility with older qemu versions.  Thats why I want the
extra bit which essentially says "CPUID leaf 0x8008 actually works".


I don't understand how it backward compatible with older qemu version. Old
QEMU won't set the extra bit you introduced in this series, and all the
guest created with old QEMU will become untrusted on CPUID leaf 0x8008 ?


Correct, on old qemu firmware will not trust CPUID leaf 0x8008.
That is not worse than the situation we have today, currently the
firmware never trusts CPUID leaf 0x8008.

So the patches will improves the situation for new qemu only, but I
don't see a way around that.



I see.

But IMHO, I don't think it's good that guest firmware workaround the 
issue on its own. Instead, it's better to just trust CPUID leaf 
0x8008 and fail if the given physical address length cannot be 
virtualized/supported.


It's just the bug of VMM to virtualize the physical address length. The 
correction direction is to fix the bug not the workaround to hide the bug.





Re: [RFC] hw/registerfields: add `FIELDx_1CLEAR()` macro

2022-09-01 Thread Philippe Mathieu-Daudé via

On 1/9/22 07:32, Richard Henderson wrote:

On 9/1/22 02:02, Wilfred Mallawa wrote:

From: Wilfred Mallawa 

Adds a helper macro that implements the `rw1c`
behaviour.

Ex:
   uint32_t data = FIELD32_1CLEAR(val, REG, FIELD);

if the specified `FIELD` is set (single/multi bit all fields)
then the respective field is cleared and returned to `data`.

If ALL bits of the bitfield are not set, then no change and
val is returned.

Signed-off-by: Wilfred Mallawa 


Why do these operations need to go into hw/registerfields.h?
It's not a common operation, since we've never needed it so far.


I suggested it to improve readability of this patch:
https://lore.kernel.org/qemu-devel/c33257a3-645f-9386-52e5-21a15ef0e...@amsat.org/


---
  include/hw/registerfields.h | 28 
  1 file changed, 28 insertions(+)

diff --git a/include/hw/registerfields.h b/include/hw/registerfields.h
index 1330ca77de..5a804f72e3 100644
--- a/include/hw/registerfields.h
+++ b/include/hw/registerfields.h
@@ -115,6 +115,34 @@
    R_ ## reg ## _ ## field ## _LENGTH, 
_v.v);  \

  _d; })
+/* Get the max value (uint) discribed by `num_bits` bits */
+#define MAX_N_BITS(num_bits) ((1 << (num_bits)) - 1)
+
+/*
+ * Clear the specified field in reg_val if
+ * all field bits are set, else no changes made. Implements
+ * single/multi-bit `rw1c`
+ */
+#define FIELD8_1CLEAR(reg_val, reg, 
field)    \
+    ((FIELD_EX8(reg_val, reg, field) 
==   \
+  MAX_N_BITS(R_ ## reg ## _ ## field ## _LENGTH)) 
?   \

+  FIELD_DP8(reg_val, reg, field, 0x00) : reg_val)
+
+#define FIELD16_1CLEAR(reg_val, reg, 
field)   \
+    ((FIELD_EX16(reg_val, reg, field) 
==  \
+  MAX_N_BITS(R_ ## reg ## _ ## field ## _LENGTH)) 
?   \

+  FIELD_DP16(reg_val, reg, field, 0x00) : reg_val)
+
+#define FIELD32_1CLEAR(reg_val, reg, 
field)   \
+    ((FIELD_EX32(reg_val, reg, field) 
==  \
+  MAX_N_BITS(R_ ## reg ## _ ## field ## _LENGTH)) 
?   \

+  FIELD_DP32(reg_val, reg, field, 0x00) : reg_val)
+
+#define FIELD64_1CLEAR(reg_val, reg, 
field)   \
+    ((FIELD_EX64(reg_val, reg, field) 
==  \
+  MAX_N_BITS(R_ ## reg ## _ ## field ## _LENGTH)) 
?   \

+  FIELD_DP64(reg_val, reg, field, 0x00) : reg_val)
+
  #define FIELD_SDP8(storage, reg, field, val) 
({   \
  struct 
{  \
  signed int v:R_ ## reg ## _ ## field ## 
_LENGTH;  \








Re: [PATCH 13/42] hw/isa/piix3: Add size constraints to rcr_ops

2022-09-01 Thread Philippe Mathieu-Daudé via

On 1/9/22 18:25, Bernhard Beschow wrote:

According to the PIIX3 datasheet, the reset control register is one byte in 
size.
Moreover, PIIX4 has it, so add it to PIIX3 as well.

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


Reviewed-by: Philippe Mathieu-Daudé 




[PATCH] Hexagon (target/hexagon) implement mutability mask for GPRs

2022-09-01 Thread Brian Cain
Some registers are defined to have immutable bits, this commit
will implement that behavior.

Signed-off-by: Brian Cain 
---
 target/hexagon/gen_masked.c   |  44 
 target/hexagon/gen_masked.h   |  26 
 target/hexagon/genptr.c   |  33 -
 target/hexagon/hex_regs.h |   6 ++
 target/hexagon/meson.build|   1 +
 tests/tcg/hexagon/Makefile.target |   1 +
 tests/tcg/hexagon/reg_mut.c   | 107 ++
 7 files changed, 217 insertions(+), 1 deletion(-)
 create mode 100644 target/hexagon/gen_masked.c
 create mode 100644 target/hexagon/gen_masked.h
 create mode 100644 tests/tcg/hexagon/reg_mut.c

diff --git a/target/hexagon/gen_masked.c b/target/hexagon/gen_masked.c
new file mode 100644
index 00..faffee2e13
--- /dev/null
+++ b/target/hexagon/gen_masked.c
@@ -0,0 +1,44 @@
+/*
+ *  Copyright(c) 2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see .
+ */
+
+#include "qemu/osdep.h"
+#include "tcg/tcg-op.h"
+#include "gen_masked.h"
+
+void gen_masked_reg_write(TCGv cur_val, TCGv in_val, TCGv out_val,
+target_ulong reg_mask) {
+TCGv set_bits = tcg_temp_new();
+TCGv cleared_bits = tcg_temp_new();
+
+/*
+ * set_bits = in_val & reg_mask
+ * cleared_bits = (~in_val) & reg_mask
+ */
+tcg_gen_andi_tl(set_bits, in_val, reg_mask);
+tcg_gen_not_tl(cleared_bits, in_val);
+tcg_gen_andi_tl(cleared_bits, cleared_bits, reg_mask);
+
+/*
+ * result = (reg_cur | set_bits) & (~cleared_bits)
+ */
+tcg_gen_not_tl(cleared_bits, cleared_bits);
+tcg_gen_or_tl(set_bits, set_bits, cur_val);
+tcg_gen_and_tl(out_val, set_bits, cleared_bits);
+
+tcg_temp_free(set_bits);
+tcg_temp_free(cleared_bits);
+}
diff --git a/target/hexagon/gen_masked.h b/target/hexagon/gen_masked.h
new file mode 100644
index 00..71f4b2818b
--- /dev/null
+++ b/target/hexagon/gen_masked.h
@@ -0,0 +1,26 @@
+/*
+ *  Copyright(c) 2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see .
+ */
+
+#ifndef GEN_MASKED_H
+#define GEN_MASKED_H
+
+#include "tcg/tcg-op.h"
+
+void gen_masked_reg_write(TCGv cur_val, TCGv in_val, TCGv out_val,
+target_ulong reg_mask);
+
+#endif /* GEN_MASKED_H */
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 8a334ba07b..21385f556e 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -29,6 +29,7 @@
 #undef QEMU_GENERATE
 #include "gen_tcg.h"
 #include "gen_tcg_hvx.h"
+#include "gen_masked.h"
 
 static inline void gen_log_predicated_reg_write(int rnum, TCGv val, int slot)
 {
@@ -53,9 +54,24 @@ static inline void gen_log_predicated_reg_write(int rnum, 
TCGv val, int slot)
 tcg_temp_free(slot_mask);
 }
 
+static const hexagon_mut_entry gpr_mut_masks[HEX_REG_LAST_VALUE] = {
+[HEX_REG_PC] = {true, 0x},
+[HEX_REG_GP] = {true, 0xffc0},
+[HEX_REG_USR] = {true, 0x3ecfff3f},
+[HEX_REG_UTIMERLO] = {true, 0x},
+[HEX_REG_UTIMERHI] = {true, 0x},
+};
+
+
 static inline void gen_log_reg_write(int rnum, TCGv val)
 {
-tcg_gen_mov_tl(hex_new_value[rnum], val);
+const hexagon_mut_entry entry = gpr_mut_masks[rnum];
+if (entry.present) {
+gen_masked_reg_write(hex_gpr[rnum], val, hex_new_value[rnum],
+entry.mask);
+} else {
+tcg_gen_mov_tl(hex_new_value[rnum], val);
+}
 if (HEX_DEBUG) {
 /* Do this so HELPER(debug_commit_end) will know */
 tcg_gen_movi_tl(hex_reg_written[rnum], 1);
@@ -64,18 +80,32 @@ static inline void gen_log_reg_write(int rnum, TCGv val)
 
 static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val, 

Re: [PULL 00/20] tcg patch queue

2022-09-01 Thread Stefan Hajnoczi
clang builds are failing:

clang -m64 -mcx16 -Ilibqemu-alpha-softmmu.fa.p -I. -I.. -Itarget/alpha
-I../target/alpha -Iqapi -Itrace -Iui -Iui/shader
-I/usr/include/pixman-1 -I/usr/include/capstone
-I/usr/include/spice-server -I/usr/include/spice-1
-I/usr/include/cacard -I/usr/include/glib-2.0
-I/usr/lib64/glib-2.0/include -I/usr/include/sysprof-4
-I/usr/include/nss3 -I/usr/include/nspr4 -I/usr/include/PCSC
-fcolor-diagnostics -Wall -Winvalid-pch -Werror -std=gnu11 -O2 -g
-isystem /builds/qemu-project/qemu/linux-headers -isystem
linux-headers -iquote . -iquote /builds/qemu-project/qemu -iquote
/builds/qemu-project/qemu/include -iquote
/builds/qemu-project/qemu/tcg/i386 -pthread -D_GNU_SOURCE
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Wstrict-prototypes
-Wredundant-decls -Wundef -Wwrite-strings -Wmissing-prototypes
-fno-strict-aliasing -fno-common -fwrapv -Wold-style-definition
-Wtype-limits -Wformat-security -Wformat-y2k -Winit-self
-Wignored-qualifiers -Wempty-body -Wnested-externs -Wendif-labels
-Wexpansion-to-defined -Wno-initializer-overrides
-Wno-missing-include-dirs -Wno-shift-negative-value
-Wno-string-plus-int -Wno-typedef-redefinition
-Wno-tautological-type-limit-compare -Wno-psabi
-fstack-protector-strong -fsanitize=undefined
-fno-sanitize-recover=undefined -fPIE -isystem../linux-headers
-isystemlinux-headers -DNEED_CPU_H
'-DCONFIG_TARGET="alpha-softmmu-config-target.h"'
'-DCONFIG_DEVICES="alpha-softmmu-config-devices.h"' -MD -MQ
libqemu-alpha-softmmu.fa.p/target_alpha_translate.c.o -MF
libqemu-alpha-softmmu.fa.p/target_alpha_translate.c.o.d -o
libqemu-alpha-softmmu.fa.p/target_alpha_translate.c.o -c
../target/alpha/translate.c
In file included from ../target/alpha/translate.c:30:
/builds/qemu-project/qemu/include/exec/translator.h:206:1: error: all
paths through this function will call itself
[-Werror,-Winfinite-recursion]

https://gitlab.com/qemu-project/qemu/-/jobs/2968573429#L2247

Stefan



[RFC 1/4] docs/tcg-plugins: describe QPP API

2022-09-01 Thread Andrew Fasano
Describe how multiple TCG plugins can interact using the QEMU
Plugin-to-Plugin API (QPP) with both callbacks and direct
function calls.

Signed-off-by: Andrew Fasano 
---
 docs/devel/tcg-plugins.rst | 76 ++
 1 file changed, 76 insertions(+)

diff --git a/docs/devel/tcg-plugins.rst b/docs/devel/tcg-plugins.rst
index a7cc44aa20..7985572027 100644
--- a/docs/devel/tcg-plugins.rst
+++ b/docs/devel/tcg-plugins.rst
@@ -441,3 +441,79 @@ The plugin has a number of arguments, all of them are 
optional:
   associativity of the L2 cache, respectively. Setting any of the L2
   configuration arguments implies ``l2=on``.
   (default: N = 2097152 (2MB), B = 64, A = 16)
+
+Plugin-to-Plugin Interactions
+-
+
+Plugins may interact with other plugins through the QEMU Plugin-to-Plugin
+("QPP") API by including ``qemu/plugin-qpp.h``. This API supports direct
+function calls between plugins as well as an inter-plugin callback system.
+This API allows for composition of plugins: plugins can make use of logic in
+other plugins without the need for code duplication.
+
+Plugin names
+
+Plugins are automatically given a name by removing the suffix from their
+filename.  These plugin names will be used during QPP interactions as
+described below.  A plugin can access its own name through the preprocessor
+variable ``CURRENT_PLUGIN``.
+
+QPP function calls
+~~
+When a plugin (e.g. ``plugin_a``) wishes to make some of its functions (e.g.
+``func_1``) available to other plugins, it must:
+
+1. Mark the function definition with the ``QEMU_PLUGIN_EXPORT`` macro. For
+example : ``QEMU_PLUGIN_EXPORT int func_1(int x) {...}``.
+2. Provide prototypes for exported functions in a header file (e.g.
+``plugin_a.h``) using the macro ``QPP_FUN_PROTOTYPE`` with arguments of the
+plugin's name, the function's return type, the function's name, and any
+arguments the function takes. For example:
+``QPP_FUN_PROTOTYPE(plugin_a, int, func_1, int);``.
+3. Import this header from the plugin.
+
+When other plugins wish to use the functions exported by ``plugin_a``, they
+must:
+
+1. Import the header file (e.g. ``plugin_a.h``) with the function prototype(s).
+2. Call the function when desired by combining the target plugin name, an
+   underscore, and the target function name, e.g. ``plugin_a_func_1()``.
+
+QPP callbacks
+~
+
+The QPP API also allows a plugin to define callback events and for other 
plugins
+to request to be notified whenever these events happens. The plugin that 
defines
+the callback is responsible for triggering the callback when it so wishes. 
Other
+plugins that wish to be notified on these events must define a function of an
+appropriate type and register it to run on this event.
+
+When a plugin (e.g. ``plugin_a``) wishes to define a callback (an event that
+other plugins can request to be notified about), it must:
+
+1. Define the callback using the ``QPP_CREATE_CB`` macro with a single argument
+   of the callback's name. For example: ``QPP_CREATE_CB(on_some_event);``.
+2. In a header file (e.g. ``plugin_a.h``) create a prototype for the callback
+   type with ``QPP_CB_PROTOTYPE`` with arguments of the callback's return type
+   (only ``void`` is currently supported), the name of the callback, and any
+   arguments the callback function will be called with. For example with a
+   callback named ``on_some_event`` that returns a void and takes an int and
+   a bool as an argument, you would use: ``QPP_CB_PROTOTYPE(void,
+   on_some_event, int, bool)``.
+3. Import this header from the plugin.
+4. When the plugin wishes to run any registered callback functions, it should
+   use the macro ``QPP_RUN_CB`` with the first argument set to the callback
+   name followed by the arguments as specified in the header. For example:
+   ``QPP_RUN_CB(on_some_event, 2, true);``.
+
+When other plugins wish to register a function to run on such an event, they
+must:
+
+1. Import the header file with the callback prototype(s) (e.g. ``plugin_a.h``)
+2. Define a function that matches the callback signature. For example:
+   ``void plugin_b_callback(int, bool) {...}``.
+3. Register this function to be run on the callback using the ``QPP_REG_CB``
+   macro with the first argument being the name of the plugin that provides the
+   callback (as a string), the second being the callback name, and the third as
+   the function that should be run. For example: ``QPP_REG_CB("plugin_a",
+   on_some_event, plugin_b_callback);``
-- 
2.34.1




[RFC 3/4] tcg/plugins: Support for inter-plugin interactions

2022-09-01 Thread Andrew Fasano
Expand tcg-plugin system to allow for plugins to export functions
and callbacks that can be used by other plugins. Exported functions
can be called at runtime by other loaded plugins. Loaded plugins
can register functions with exported callbacks and have these
functions run whenever the callback is triggered.

Signed-off-by: Andrew Fasano 
---
 include/qemu/plugin-qpp.h| 252 +++
 plugins/core.c   |  11 ++
 plugins/loader.c |  24 
 plugins/plugin.h |   5 +
 plugins/qemu-plugins.symbols |   1 +
 5 files changed, 293 insertions(+)
 create mode 100644 include/qemu/plugin-qpp.h

diff --git a/include/qemu/plugin-qpp.h b/include/qemu/plugin-qpp.h
new file mode 100644
index 00..befa4f9b8b
--- /dev/null
+++ b/include/qemu/plugin-qpp.h
@@ -0,0 +1,252 @@
+#ifndef PLUGIN_QPP_H
+#define PLUGIN_QPP_H
+
+/*
+ * Facilities for "QEMU plugin to plugin" (QPP) interactions between tcg
+ * plugins.  These allow for an inter-plugin callback system as well
+ * as direct function calls between loaded plugins. For more details see
+ * docs/devel/plugin.rst.
+ */
+
+#include 
+#include 
+#include 
+extern GModule * qemu_plugin_name_to_handle(const char *);
+
+#define PLUGIN_CONCAT(x, y) _PLUGIN_CONCAT(x, y)
+#define _PLUGIN_CONCAT(x, y) x##y
+#define QPP_NAME(plugin, fn) PLUGIN_CONCAT(plugin, PLUGIN_CONCAT(_, fn))
+#define QPP_MAX_CB 256
+#define _QPP_SETUP_NAME(plugin, fn) PLUGIN_CONCAT(_qpp_setup_, \
+QPP_NAME(plugin, fn))
+
+/*
+ **
+ * The QPP_CREATE_CB and QPP_RUN_CB macros are to be used by a plugin that
+ * wishs to create and later trigger QPP-based callback events. These are
+ * events that the plugin can detect (i.e., through analysis of guest state)
+ * that may be of interest to other plugins.
+ **
+ */
+
+/*
+ * QPP_CREATE_CB(name) will create a callback by defining necessary internal
+ * functions and variables based off the provided name. It must be run before
+ * triggering the callback event (with QPP_RUN_CB). This macro will create the
+ * following variables and functions, based off the provided name:
+ *
+ * 1) qpp_[name]_cb is an array of function pointers storing the
+ *registered callbacks.
+ * 2) qpp_[name]_num_cb stores the number of functions stored with this
+ *callback.
+ * 3) qpp_add_cb_[name] is a function to add a pointer into the qpp_[name]_cb
+ *array and increment qpp_[name]_num_cb.
+ * 4) qpp_remove_cb_[name] finds a registered callback, deletes it, decrements
+ *_num_cb and shifts the _cb array appropriately to fill the gap.
+ *
+ * Important notes:
+ *
+ * 1) Multiple callbacks can be registered for the same event, however 
consumers
+ *can not control the order in which they are called and this order may
+ *change in the future.
+ *
+ * 2) If this macro is incorrectly used multiple times in the same plugin with
+ *the same callback name set, it will raise a compilation error since
+ *these variables would then be defined multiple times. The same callback
+ *name can, however, be created in distrinct plugins without issue.
+ */
+#define QPP_CREATE_CB(cb_name)  \
+void qpp_add_cb_##cb_name(cb_name##_t fptr);\
+bool qpp_remove_cb_##cb_name(cb_name##_t fptr); \
+cb_name##_t * qpp_##cb_name##_cb[QPP_MAX_CB];   \
+int qpp_##cb_name##_num_cb; \
+\
+void qpp_add_cb_##cb_name(cb_name##_t fptr) \
+{   \
+  assert(qpp_##cb_name##_num_cb < QPP_MAX_CB);  \
+  qpp_##cb_name##_cb[qpp_##cb_name##_num_cb] = fptr;\
+  qpp_##cb_name##_num_cb += 1;  \
+}   \
+\
+bool qpp_remove_cb_##cb_name(cb_name##_t fptr)  \
+{   \
+  int i = 0;\
+  bool found = false;   \
+  for (; i < MIN(QPP_MAX_CB, qpp_##cb_name##_num_cb); i++) {\
+if (!found && fptr == qpp_##cb_name##_cb[i]) {  \
+found = true;   \
+qpp_##cb_name##_num_cb--;   \
+}   \
+if (found && i < QPP_MAX_CB - 2) {  \
+qpp_##cb_name##_cb[i] = qpp_##cb_name##_cb[i + 1];  \
+}   \
+  } \
+  return found; \
+}
+

[RFC 4/4] tcg/plugins: Add example pair of QPP plugins

2022-09-01 Thread Andrew Fasano
The first plugin, qpp_srv exposes two functions and one callback that other
plugins can leverage. These functions are described in the corresponding
header file.

The second plugin, qpp_client, imports this header file, registers its
own function to run on a qpp_srv-provided callback, and directly calls
into the two exposed functions in qpp_srv.

Signed-off-by: Andrew Fasano 
---
 contrib/plugins/Makefile |  2 ++
 contrib/plugins/qpp_client.c | 42 
 contrib/plugins/qpp_client.h |  1 +
 contrib/plugins/qpp_srv.c| 33 
 contrib/plugins/qpp_srv.h| 17 +++
 5 files changed, 95 insertions(+)
 create mode 100644 contrib/plugins/qpp_client.c
 create mode 100644 contrib/plugins/qpp_client.h
 create mode 100644 contrib/plugins/qpp_srv.c
 create mode 100644 contrib/plugins/qpp_srv.h

diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile
index b7720fea0f..b7510de89c 100644
--- a/contrib/plugins/Makefile
+++ b/contrib/plugins/Makefile
@@ -21,6 +21,8 @@ NAMES += lockstep
 NAMES += hwprofile
 NAMES += cache
 NAMES += drcov
+NAMES += qpp_srv
+NAMES += qpp_client
 
 SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES)))
 
diff --git a/contrib/plugins/qpp_client.c b/contrib/plugins/qpp_client.c
new file mode 100644
index 00..de3335e167
--- /dev/null
+++ b/contrib/plugins/qpp_client.c
@@ -0,0 +1,42 @@
+#include 
+#include 
+#include 
+#include 
+#include "qpp_srv.h"
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+void my_on_exit(int x, bool b)
+{
+  g_autoptr(GString) report = g_string_new("Client: on_exit runs with args: ");
+  g_string_append_printf(report, "%d, %d\n", x, b);
+  qemu_plugin_outs(report->str);
+
+  g_string_printf(report, "Client: calls qpp_srv's do_add(1): %d\n",
+  qpp_srv_do_add(1));
+  qemu_plugin_outs(report->str);
+
+  g_string_printf(report, "Client: calls qpp_srv's do_sub(1): %d\n",
+   qpp_srv_do_sub(1));
+  qemu_plugin_outs(report->str);
+}
+
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
+   const qemu_info_t *info, int argc, char **argv) {
+
+/*
+ * Register our "my_on_exit" function to run on the on_exit QPP-callback
+ * exported by qpp_srv
+ */
+QPP_REG_CB("qpp_srv", on_exit, my_on_exit);
+
+g_autoptr(GString) report = g_string_new(CURRENT_PLUGIN ": Call "
+ "qpp_srv's do_add(0) => ");
+g_string_append_printf(report, "%d\n", qpp_srv_do_add(0));
+qemu_plugin_outs(report->str);
+
+g_string_printf(report, "Client: registered on_exit callback\n");
+return 0;
+}
+
diff --git a/contrib/plugins/qpp_client.h b/contrib/plugins/qpp_client.h
new file mode 100644
index 00..573923f580
--- /dev/null
+++ b/contrib/plugins/qpp_client.h
@@ -0,0 +1 @@
+void my_on_exit(int, bool);
diff --git a/contrib/plugins/qpp_srv.c b/contrib/plugins/qpp_srv.c
new file mode 100644
index 00..61a6ab38ed
--- /dev/null
+++ b/contrib/plugins/qpp_srv.c
@@ -0,0 +1,33 @@
+#include 
+#include 
+#include 
+#include 
+#include "qpp_srv.h"
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+QPP_CREATE_CB(on_exit);
+
+static void plugin_exit(qemu_plugin_id_t id, void *p)
+{
+  qemu_plugin_outs(CURRENT_PLUGIN "exit triggered, running all registered"
+  " QPP callbacks\n");
+  QPP_RUN_CB(on_exit, 0, true);
+}
+
+QEMU_PLUGIN_EXPORT int do_add(int x)
+{
+  return x + 1;
+}
+
+QEMU_PLUGIN_EXPORT int do_sub(int x)
+{
+  return x - 1;
+}
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
+   const qemu_info_t *info, int argc, char **argv) {
+qemu_plugin_outs("qpp_srv loaded\n");
+qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
+return 0;
+}
diff --git a/contrib/plugins/qpp_srv.h b/contrib/plugins/qpp_srv.h
new file mode 100644
index 00..ceb26e3d2c
--- /dev/null
+++ b/contrib/plugins/qpp_srv.h
@@ -0,0 +1,17 @@
+#ifndef QPP_SRV_H
+#define QPP_SRV_H
+
+/*
+ * Prototype for the on_exit callback: callback functions should be
+ * of type `void f(int, bool)`
+ */
+QPP_CB_PROTOTYPE(void, on_exit, int, bool);
+
+/*
+ * Prototypes for the do_add and do_sub functions. Both return an int and
+ * take an int as an argument.
+ */
+QPP_FUN_PROTOTYPE(qpp_srv, int, do_add, int);
+QPP_FUN_PROTOTYPE(qpp_srv, int, do_sub, int);
+
+#endif /* QPP_SRV_H */
-- 
2.34.1




[RFC 2/4] tcg/plugins: Automatically define CURRENT_PLUGIN

2022-09-01 Thread Andrew Fasano
Use plugin filenames to set the preprocessor variable CURRENT_PLUGIN
as a string during plugin compilation.

Signed-off-by: Andrew Fasano 
---
 contrib/plugins/Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile
index df3499f4f2..b7720fea0f 100644
--- a/contrib/plugins/Makefile
+++ b/contrib/plugins/Makefile
@@ -34,7 +34,7 @@ CFLAGS += -I$(SRC_PATH)/include/qemu
 all: $(SONAMES)
 
 %.o: %.c
-   $(CC) $(CFLAGS) -c -o $@ $<
+   $(CC) $(CFLAGS) -DCURRENT_PLUGIN=\"$(basename $@)\" -c -o $@ $<
 
 lib%.so: %.o
$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDLIBS)
-- 
2.34.1




[RFC 0/4] Support interactions between TCG plugins

2022-09-01 Thread Andrew Fasano
Hello,

I'm requesting comments on the following series of patches expanding the
TCG plugin system to add the "QEMU Plugin-to-Plugin (QPP)" interface
that allows for interactions between TCG plugins. The goal of this
interface is to enable plugins to expand on other plugins and reduce
code duplication. This patch series includes documentation and
significant comments, but a high-level summary is below along with a
discussion of the current implementation as well as the benefits and
drawbacks of these changes.

**Summary**

The QPP interface allows two types of interactions between plugins:

1) Exported functions: A plugin may wish to allow other plugins to call
one of the functions it has defined. To do this, the plugin must mark
the function definition as publicly visible with the QEMU_PLUGIN_EXPORT
macro and place a definition in an included header file using the
QPP_FUN_PROTOTYPE macro. Other plugins can then include this header and
call the exported function by combining the name of the target plugin
with the name of the exported function.

For example, consider a hypothetical plugin that collects a list of
cache misses. This plugin could export two functions using the QPP
interface: one to allow another plugin to query this list and another
to empty the list. This would enable the development of another plugin
that examines guest CPU state to identify process changes and reports
the cache misses per process. With the QPP interface, this second plugin
would not need to duplicate any logic from the first.

2) Callbacks: Multiple plugins may wish to take some action when some
event of interest occurs inside a running guest. To support modularity
and reduce code duplication, the QPP callback system allows this logic
to be contained in single plugin that detects whenever a given event
occurs and exposes a callback with a given name. Another plugin can then
request to have one of its own functions run whenever this event occurs.
Additional plugins could also use this same callback to run additional
logic whenever this event occurs.

For example, consider (again) a hypothetical plugin that detects when
the current guest process changes by analyzing the guest CPU state. This
plugin could define a callback named "on_process_change" and trigger
this callback event whenever it detects a process change. Other plugins
could then be developed that take various actions on process changes by
registering internal functions to run on this event.

These patches and examples are inspired by the PANDA project
(https://panda.re and https://github.com/panda-re/panda), a fork of QEMU
modified to support dynamic program analysis and reverse engineering.
PANDA also includes a large plugin system with a similar interface for
interactions between plugins. I'm one of the maintainers of PANDA
and have seen how the ability for plugins to interact with
other plugins reduces code duplication and enables the creation of many
useful plugins.


**Implementation Overview**

These patches modify the TCG plugin build system to define the 
preprocessor variable CURRENT_PLUGIN to the name of the current plugin
based off its filename. This can be useful for plugin developers in
general and is used internally in the QPP implementation to determine
if an exported plugin function is defined in the current plugin or
in another.

These patches also add the function qemu_plugin_name_to_handle to the 
core plugin API which uses the new internal function is_plugin_named.
The ability for plugins to get a handle to another plugin is necessary
for the inter-plugin interactions described below.

The QPP implementation is contained inside a header file plugin-qpp.h
that adds the macros QPP_CREATE_CB, QPP_RUN_CB, QPP_REG_CB,
QPP_REMOVE_CB, and QPP_FUN_PROTOTYPE. The first 4 of these are related
to the callback system and the last one is for exported functions.

The QPP_CREATE_CB macro is used by a plugin that wishes to create a
callback with a given name. The macro will create an array of function
pointers for every function that has been registered to run on this
callback event. Other plugins can register a local function
with this callback (i.e., add it to this list of function pointers)
or remove a previously-registered function using QPP_REG_CB or
QPP_REMOVE_CB, respectively. When a plugin wishes to run all the
registered callback functions for a given callback, it uses the
QPP_RUN_CB macro.

The QPP_FUN_PROTOYPE macro enables a plugin to expose a function
it defines to other plugins. This macro is used in a header file that
is included by both the plugin that defines a function as well as
plugins that wish to use the function. This prototype creates a 
constructor function that runs on plugin load. If the target plugin
name differs from the value of CURRENT_PLUGIN, this function
will use qemu_plugin_name_to_handle to get a handle to the target
plugin and use g_module_symbol to resolve the target function in
that plugin. If this fails, it will print a 

Re: [PATCH 42/42] hw/i386/acpi-build: Resolve PIIX ISA bridge rather than ACPI controller

2022-09-01 Thread Philippe Mathieu-Daudé via

On 1/9/22 18:26, Bernhard Beschow wrote:

Resolving the PIIX ISA bridge rather than the PIIX ACPI controller mirrors
the ICH9 code one line below.

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

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 8af75b1e22..d7bb1ccb26 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -288,7 +288,7 @@ static void acpi_get_pm_info(MachineState *machine, 
AcpiPmInfo *pm)
  
  static void acpi_get_misc_info(AcpiMiscInfo *info)

  {
-Object *piix = object_resolve_type_unambiguous(TYPE_PIIX4_PM);
+Object *piix = object_resolve_type_unambiguous(TYPE_PIIX_PCI_DEVICE);
  Object *lpc = object_resolve_type_unambiguous(TYPE_ICH9_LPC_DEVICE);
  assert(!!piix != !!lpc);
  


This looks correct to  me w.r.t the hardware, but my understanding is
some x86 machines allow abusing the PIIX ACPI PCI function, by plugging
it alone, without the rest of the south bridge... Then this patch would
regress such Frankenstein use :/

Reviewed-by: Philippe Mathieu-Daudé 



Re: [PATCH 00/20] ppc4xx_sdram QOMify and clean ups

2022-09-01 Thread BALATON Zoltan

On Fri, 19 Aug 2022, BALATON Zoltan wrote:

Hello,

This is based on gitlab.com/danielhb/qemu/tree/ppc-7.2


Now that the queue is flushed it should apply on master so

Ping

Regards,
BALATON Zoltan


This is the end of the QOMify series started by Cédric. This series
handles the SDRAM controller models to clean them up, QOMify and unify
them and at least partially clean up the mess that has accumulated
around these in the past. This includes the not yet merged patches
from the last series and new ones that change the DDR2 version used by
sam460ex. This is all I have for now I don't intend to make any more
bigger changes for this now.

Regards,
BALATON Zoltan

BALATON Zoltan (20):
 ppc440_bamboo: Remove unnecessary memsets
 ppc4xx: Introduce Ppc4xxSdramBank struct
 ppc4xx_sdram: Get rid of the init RAM hack
 ppc4xx: Use Ppc4xxSdramBank in ppc4xx_sdram_banks()
 ppc440_bamboo: Add missing 4 MiB valid memory size
 ppc4xx_sdram: Move size check to ppc4xx_sdram_init()
 ppc4xx_sdram: QOM'ify
 ppc4xx_sdram: Drop extra zeros for readability
 ppc440_sdram: Split off map/unmap of sdram banks for later reuse
 ppc440_sdram: Implement enable bit in the DDR2 SDRAM controller
 ppc440_sdram: Get rid of the init RAM hack
 ppc440_sdram: Rename local variable for readibility
 ppc4xx_sdram: Rename functions to prevent name clashes
 ppc440_sdram: Move RAM size check to ppc440_sdram_init
 ppc440_sdram: QOM'ify
 ppc4xx_sdram: Move ppc4xx DDR and DDR2 SDRAM controller models
   together
 ppc4xx_sdram: Use hwaddr for memory bank size
 ppc4xx_sdram: Rename local state variable for brevity
 ppc4xx_sdram: Generalise bank setup
 ppc4xx_sdram: Convert DDR SDRAM controller to new bank handling

hw/ppc/meson.build  |   3 +-
hw/ppc/ppc405.h |   8 +-
hw/ppc/ppc405_boards.c  |  19 +-
hw/ppc/ppc405_uc.c  |  33 +-
hw/ppc/ppc440.h |   4 -
hw/ppc/ppc440_bamboo.c  |  29 +-
hw/ppc/ppc440_uc.c  | 267 +--
hw/ppc/ppc4xx_devs.c| 413 ---
hw/ppc/ppc4xx_sdram.c   | 723 
hw/ppc/sam460ex.c   |  48 +--
hw/ppc/trace-events |   1 +
include/hw/ppc/ppc4xx.h |  66 +++-
12 files changed, 844 insertions(+), 770 deletions(-)
create mode 100644 hw/ppc/ppc4xx_sdram.c



Re: [PATCH 32/42] hw/isa/piix4: Rename wrongly named method

2022-09-01 Thread Philippe Mathieu-Daudé via

On 1/9/22 18:26, Bernhard Beschow wrote:

This method post-loads the southbridge, not the IDE device.

Signed-off-by: Bernhard Beschow 
---
  hw/isa/piix4.c | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)


Reviewed-by: Philippe Mathieu-Daudé 



Re: [PATCH 27/42] hw/isa/piix4: Allow board to provide PCI interrupt routes

2022-09-01 Thread Philippe Mathieu-Daudé via

On 1/9/22 18:25, Bernhard Beschow wrote:

PIIX3 initializes the PIRQx route control registers to the default
values as described in the 82371AB PCI-TO-ISA/IDE XCELERATOR (PIIX4)
April 1997 manual. PIIX4, however, initializes the routes according to
the Malta™ User’s Manual, ch 6.6, which are IRQs 10 and 11. In order to
allow the reset methods to be consolidated, allow board code to specify
the routes.

Signed-off-by: Bernhard Beschow 
---
  hw/isa/piix4.c  | 14 ++
  hw/mips/malta.c |  4 
  2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c
index ed9eca715f..763c98b565 100644
--- a/hw/isa/piix4.c
+++ b/hw/isa/piix4.c
@@ -57,6 +57,8 @@ struct PIIX4State {
  MemoryRegion rcr_mem;
  uint8_t rcr;
  
+uint8_t pci_irq_reset_mappings[PIIX_NUM_PIRQS];

+
  bool has_acpi;
  bool has_usb;
  bool smm_enabled;
@@ -122,10 +124,10 @@ static void piix4_isa_reset(DeviceState *dev)
  pci_conf[0x4c] = 0x4d;
  pci_conf[0x4e] = 0x03;
  pci_conf[0x4f] = 0x00;
-pci_conf[0x60] = 0x0a; // PCI A -> IRQ 10
-pci_conf[0x61] = 0x0a; // PCI B -> IRQ 10
-pci_conf[0x62] = 0x0b; // PCI C -> IRQ 11
-pci_conf[0x63] = 0x0b; // PCI D -> IRQ 11
+pci_conf[PIIX_PIRQCA] = d->pci_irq_reset_mappings[0];
+pci_conf[PIIX_PIRQCB] = d->pci_irq_reset_mappings[1];
+pci_conf[PIIX_PIRQCC] = d->pci_irq_reset_mappings[2];
+pci_conf[PIIX_PIRQCD] = d->pci_irq_reset_mappings[3];
  pci_conf[0x69] = 0x02;
  pci_conf[0x70] = 0x80;
  pci_conf[0x76] = 0x0c;
@@ -299,6 +301,10 @@ static void piix4_init(Object *obj)
  
  static Property piix4_props[] = {

  DEFINE_PROP_UINT32("smb_io_base", PIIX4State, smb_io_base, 0),
+DEFINE_PROP_UINT8("pirqa", PIIX4State, pci_irq_reset_mappings[0], 0x80),
+DEFINE_PROP_UINT8("pirqb", PIIX4State, pci_irq_reset_mappings[1], 0x80),
+DEFINE_PROP_UINT8("pirqc", PIIX4State, pci_irq_reset_mappings[2], 0x80),
+DEFINE_PROP_UINT8("pirqd", PIIX4State, pci_irq_reset_mappings[3], 0x80),
  DEFINE_PROP_BOOL("has-acpi", PIIX4State, has_acpi, true),
  DEFINE_PROP_BOOL("has-usb", PIIX4State, has_usb, true),
  DEFINE_PROP_BOOL("smm-enabled", PIIX4State, smm_enabled, false),
diff --git a/hw/mips/malta.c b/hw/mips/malta.c
index 6339b0d66c..44b6b14f3d 100644
--- a/hw/mips/malta.c
+++ b/hw/mips/malta.c
@@ -1403,6 +1403,10 @@ void mips_malta_init(MachineState *machine)
  piix4 = pci_new_multifunction(PCI_DEVFN(10, 0), true,
TYPE_PIIX4_PCI_DEVICE);
  qdev_prop_set_uint32(DEVICE(piix4), "smb_io_base", 0x1100);
+qdev_prop_set_uint8(DEVICE(piix4), "pirqa", 10);
+qdev_prop_set_uint8(DEVICE(piix4), "pirqb", 10);
+qdev_prop_set_uint8(DEVICE(piix4), "pirqc", 11);
+qdev_prop_set_uint8(DEVICE(piix4), "pirqd", 11);
  pci_realize_and_unref(piix4, pci_bus, _fatal);
  isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix4), "isa.0"));
  


Nice!

Reviewed-by: Philippe Mathieu-Daudé 




Re: [PATCH 25/42] hw/isa/piix4: Move pci_ide_create_devs() call to board code

2022-09-01 Thread Philippe Mathieu-Daudé via

On 1/9/22 18:25, Bernhard Beschow wrote:

For the VIA south bridges there was a comment to have the call in board code.
Move it there for PIIX4 as well for consistency.

Signed-off-by: Bernhard Beschow 
---
  hw/isa/piix4.c  |  1 -
  hw/mips/malta.c | 10 ++
  2 files changed, 6 insertions(+), 5 deletions(-)


Reviewed-by: Philippe Mathieu-Daudé 



Re: [PATCH 22/42] hw/mips/malta: Reuse dev variable

2022-09-01 Thread Philippe Mathieu-Daudé via

On 1/9/22 18:25, Bernhard Beschow wrote:

While at it, move the assignments closer to where they are used.

Signed-off-by: Bernhard Beschow 
---
  hw/mips/malta.c | 5 ++---
  1 file changed, 2 insertions(+), 3 deletions(-)


Reviewed-by: Philippe Mathieu-Daudé 



Re: [PATCH 15/42] hw/isa/piix3: Prefer pci_address_space() over get_system_memory()

2022-09-01 Thread Philippe Mathieu-Daudé via

On 1/9/22 18:25, Bernhard Beschow wrote:

get_system_memory() accesses global state while pci_address_space() uses
whatever has been passed to the device instance, so avoid the global.
Moreover, PIIX4 uses pci_address_space() here as well.

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


Reviewed-by: Philippe Mathieu-Daudé 




Re: [PATCH 14/42] hw/isa/piix3: Modernize reset handling

2022-09-01 Thread Philippe Mathieu-Daudé via

On 1/9/22 18:25, Bernhard Beschow wrote:

Rather than registering the reset handler via a function which
appends the handler to a global list, prefer to implement it as
a virtual method - PIIX4 does the same already.

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

diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c
index c8c2dd6048..0350f70706 100644
--- a/hw/isa/piix3.c
+++ b/hw/isa/piix3.c
@@ -31,7 +31,6 @@
  #include "hw/qdev-properties.h"
  #include "hw/isa/isa.h"
  #include "hw/xen/xen.h"
-#include "sysemu/reset.h"
  #include "sysemu/runstate.h"
  #include "migration/vmstate.h"
  #include "hw/acpi/acpi_aml_interface.h"
@@ -156,9 +155,9 @@ static void piix3_write_config_xen(PCIDevice *dev,
  piix3_write_config(dev, address, val, len);
  }
  
-static void piix3_reset(void *opaque)

+static void piix3_reset(DeviceState *dev)
  {
-PIIX3State *d = opaque;
+PIIX3State *d = PIIX3_PCI_DEVICE(dev);
  uint8_t *pci_conf = d->dev.config;
  
  pci_conf[0x04] = 0x07; /* master, memory and I/O */

@@ -321,8 +320,6 @@ static void pci_piix3_realize(PCIDevice *dev, Error **errp)
  memory_region_add_subregion_overlap(pci_address_space_io(dev),
  PIIX_RCR_IOPORT, >rcr_mem, 1);
  
-qemu_register_reset(piix3_reset, d);

-
  i8257_dma_init(isa_bus, 0);
  
  /* RTC */

@@ -397,6 +394,7 @@ static void pci_piix3_class_init(ObjectClass *klass, void 
*data)
  PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
  AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
  
+dc->reset   = piix3_reset;

  dc->desc= "ISA bridge";
  dc->vmsd= _piix3;
  dc->hotpluggable   = false;


Yay 4 years later...
https://lore.kernel.org/qemu-devel/20180108024558.17983-28-f4...@amsat.org/

Reviewed-by: Philippe Mathieu-Daudé 



Re: [PATCH 11/42] hw/isa/piix3: Remove extra '; ' outside of functions

2022-09-01 Thread Philippe Mathieu-Daudé via

On 1/9/22 18:25, Bernhard Beschow wrote:

Fixes the "extra-semi" clang-tidy check.

Signed-off-by: Bernhard Beschow 
Reviewed-by: Peter Maydell 
---
  hw/isa/piix3.c | 6 +++---
  1 file changed, 3 insertions(+), 3 deletions(-)


Reviewed-by: Philippe Mathieu-Daudé 



Re: [PULL v2 00/60] ppc queue

2022-09-01 Thread Stefan Hajnoczi
Applied, thanks.

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


signature.asc
Description: PGP signature


Re: QEMU 7.2 release schedule

2022-09-01 Thread Stefan Hajnoczi
On Thu, Sep 1, 2022, 14:09 Daniel Henrique Barboza 
wrote:

>
>
> On 8/30/22 18:12, Stefan Hajnoczi wrote:
> > Hi,
> > Richard Henderson has tagged QEMU 7.1 and handed over to me for the 7.2
> > release cycle. Thanks to Richard and Michael Roth their work on 7.1!
>
> Are you going to handle the pull requests for this release cycle? I saw
> that you've handled Thomas' PRs.
>
> If that's the case I'll CC you in the PRs instead of Peter/Richard.
>

Hi Daniel,
I will, but don't worry, I'm tracking all pull requests on qemu-devel so
it's not necessary to Cc me to get my attention.

Your latest pull requests is in the staging branch and will be merged once
CI has completed.

Stefan

>


Re: [PATCH 05/42] hw/isa/piix3: Create USB controller in host device

2022-09-01 Thread Philippe Mathieu-Daudé via

On 1/9/22 18:25, Bernhard Beschow wrote:

The USB controller is an integral part of PIIX3 (function 2). So create
it as part of the south bridge.

Note that the USB function is optional in QEMU. This is why it gets
object_initialize_child()'ed in realize rather than in instance_init.

Signed-off-by: Bernhard Beschow 
---
  hw/i386/pc_piix.c |  6 ++
  hw/isa/Kconfig|  1 +
  hw/isa/piix3.c| 17 +
  include/hw/southbridge/piix.h |  4 
  4 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index b08d946992..76ac8b2035 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -219,6 +219,8 @@ static void pc_init1(MachineState *machine,
  pcms->bus = pci_bus;
  
  pci_dev = pci_new_multifunction(-1, true, type);

+object_property_set_bool(OBJECT(pci_dev), "has-usb",
+ machine_usb(machine), _abort);
  pci_realize_and_unref(pci_dev, pci_bus, _fatal);
  piix3 = PIIX3_PCI_DEVICE(pci_dev);
  piix3->pic = x86ms->gsi;
@@ -297,10 +299,6 @@ static void pc_init1(MachineState *machine,
  }
  #endif
  
-if (pcmc->pci_enabled && machine_usb(machine)) {

-pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci");
-}
-
  if (pcmc->pci_enabled && x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) {
  PCIDevice *piix4_pm;
  
diff --git a/hw/isa/Kconfig b/hw/isa/Kconfig

index 6e8f9cac54..f02eca3c3e 100644
--- a/hw/isa/Kconfig
+++ b/hw/isa/Kconfig
@@ -36,6 +36,7 @@ config PIIX3
  select I8257
  select ISA_BUS
  select MC146818RTC
+select USB_UHCI
  
  config PIIX4

  bool
diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c
index 96ab7107e2..27052a5546 100644
--- a/hw/isa/piix3.c
+++ b/hw/isa/piix3.c
@@ -297,6 +297,7 @@ static const MemoryRegionOps rcr_ops = {
  static void pci_piix3_realize(PCIDevice *dev, Error **errp)
  {
  PIIX3State *d = PIIX3_PCI_DEVICE(dev);
+PCIBus *pci_bus = pci_get_bus(dev);
  ISABus *isa_bus;
  
  isa_bus = isa_bus_new(DEVICE(d), get_system_memory(),

@@ -319,6 +320,16 @@ static void pci_piix3_realize(PCIDevice *dev, Error **errp)
  if (!qdev_realize(DEVICE(>rtc), BUS(isa_bus), errp)) {
  return;
  }
+
+/* USB */
+if (d->has_usb) {
+object_initialize_child(OBJECT(dev), "uhci", >uhci,
+"piix3-usb-uhci");
+qdev_prop_set_int32(DEVICE(>uhci), "addr", dev->devfn + 2);
+if (!qdev_realize(DEVICE(>uhci), BUS(pci_bus), errp)) {
+return;
+}
+}
  }
  
  static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope)

@@ -341,6 +352,11 @@ static void pci_piix3_init(Object *obj)
  object_initialize_child(obj, "rtc", >rtc, TYPE_MC146818_RTC);
  }
  
+static Property pci_piix3_props[] = {

+DEFINE_PROP_BOOL("has-usb", PIIX3State, has_usb, true),


Maybe s/has-usb/usb-enabled/?


+DEFINE_PROP_END_OF_LIST(),
+};
+
  static void pci_piix3_class_init(ObjectClass *klass, void *data)
  {
  DeviceClass *dc = DEVICE_CLASS(klass);
@@ -359,6 +375,7 @@ static void pci_piix3_class_init(ObjectClass *klass, void 
*data)
   * pc_piix.c's pc_init1()
   */
  dc->user_creatable = false;
+device_class_set_props(dc, pci_piix3_props);
  adevc->build_dev_aml = build_pci_isa_aml;
  }
  
diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h

index b1fa08dd2b..5367917182 100644
--- a/include/hw/southbridge/piix.h
+++ b/include/hw/southbridge/piix.h
@@ -15,6 +15,7 @@
  #include "hw/pci/pci.h"
  #include "qom/object.h"
  #include "hw/rtc/mc146818rtc.h"
+#include "hw/usb/hcd-uhci.h"
  
  /* PIRQRC[A:D]: PIRQx Route Control Registers */

  #define PIIX_PIRQCA 0x60
@@ -54,12 +55,15 @@ struct PIIXState {
  int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
  
  RTCState rtc;

+UHCIState uhci;
  
  /* Reset Control Register contents */

  uint8_t rcr;
  
  /* IO memory region for Reset Control Register (PIIX_RCR_IOPORT) */

  MemoryRegion rcr_mem;
+
+bool has_usb;
  };
  typedef struct PIIXState PIIX3State;
  





Re: [PATCH 01/42] hw/i386/pc: Create DMA controllers in south bridges

2022-09-01 Thread Philippe Mathieu-Daudé via

On 1/9/22 18:25, Bernhard Beschow wrote:

Just like in the real hardware (and in PIIX4), create the DMA
controllers in the south bridges.

Signed-off-by: Bernhard Beschow 
---
  hw/i386/pc.c  | 3 ---
  hw/i386/pc_piix.c | 2 ++
  hw/isa/Kconfig| 2 ++
  hw/isa/lpc_ich9.c | 3 +++
  hw/isa/piix3.c| 9 +++--
  5 files changed, 14 insertions(+), 5 deletions(-)


Reviewed-by: Philippe Mathieu-Daudé 



[PULL 36/39] target/i386: Misc AVX helper prep

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

Fixup various vector helpers that either trivially exten to 256 bit,
or don't have 256 bit variants.

No functional changes to existing helpers

Signed-off-by: Paul Brook 
Message-Id: <20220424220204.2493824-19-p...@nowt.org>
Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 target/i386/ops_sse.h | 143 +++---
 1 file changed, 94 insertions(+), 49 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index c6dba9572d..0c4257dee7 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -422,6 +422,7 @@ void glue(helper_psadbw, SUFFIX)(CPUX86State *env, Reg *d, 
Reg *s)
 }
 }
 
+#if SHIFT < 2
 void glue(helper_maskmov, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
   target_ulong a0)
 {
@@ -433,6 +434,7 @@ void glue(helper_maskmov, SUFFIX)(CPUX86State *env, Reg *d, 
Reg *s,
 }
 }
 }
+#endif
 
 void glue(helper_movl_mm_T0, SUFFIX)(Reg *d, uint32_t val)
 {
@@ -635,21 +637,24 @@ void helper_sqrtsd(CPUX86State *env, Reg *d, Reg *s)
 /* float to float conversions */
 void glue(helper_cvtps2pd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
 {
-float32 s0, s1;
-
-s0 = s->ZMM_S(0);
-s1 = s->ZMM_S(1);
-d->ZMM_D(0) = float32_to_float64(s0, >sse_status);
-d->ZMM_D(1) = float32_to_float64(s1, >sse_status);
+int i;
+for (i = 1 << SHIFT; --i >= 0; ) {
+d->ZMM_D(i) = float32_to_float64(s->ZMM_S(i), >sse_status);
+}
 }
 
 void glue(helper_cvtpd2ps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
 {
-d->ZMM_S(0) = float64_to_float32(s->ZMM_D(0), >sse_status);
-d->ZMM_S(1) = float64_to_float32(s->ZMM_D(1), >sse_status);
-d->Q(1) = 0;
+int i;
+for (i = 0; i < 1 << SHIFT; i++) {
+ d->ZMM_S(i) = float64_to_float32(s->ZMM_D(i), >sse_status);
+}
+for (i >>= 1; i < 1 << SHIFT; i++) {
+ d->Q(i) = 0;
+}
 }
 
+#if SHIFT == 1
 void helper_cvtss2sd(CPUX86State *env, Reg *d, Reg *s)
 {
 d->ZMM_D(0) = float32_to_float64(s->ZMM_S(0), >sse_status);
@@ -659,26 +664,27 @@ void helper_cvtsd2ss(CPUX86State *env, Reg *d, Reg *s)
 {
 d->ZMM_S(0) = float64_to_float32(s->ZMM_D(0), >sse_status);
 }
+#endif
 
 /* integer to float */
 void glue(helper_cvtdq2ps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
 {
-d->ZMM_S(0) = int32_to_float32(s->ZMM_L(0), >sse_status);
-d->ZMM_S(1) = int32_to_float32(s->ZMM_L(1), >sse_status);
-d->ZMM_S(2) = int32_to_float32(s->ZMM_L(2), >sse_status);
-d->ZMM_S(3) = int32_to_float32(s->ZMM_L(3), >sse_status);
+int i;
+for (i = 0; i < 2 << SHIFT; i++) {
+d->ZMM_S(i) = int32_to_float32(s->ZMM_L(i), >sse_status);
+}
 }
 
 void glue(helper_cvtdq2pd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
 {
-int32_t l0, l1;
-
-l0 = (int32_t)s->ZMM_L(0);
-l1 = (int32_t)s->ZMM_L(1);
-d->ZMM_D(0) = int32_to_float64(l0, >sse_status);
-d->ZMM_D(1) = int32_to_float64(l1, >sse_status);
+int i;
+for (i = 1 << SHIFT; --i >= 0; ) {
+int32_t l = s->ZMM_L(i);
+d->ZMM_D(i) = int32_to_float64(l, >sse_status);
+}
 }
 
+#if SHIFT == 1
 void helper_cvtpi2ps(CPUX86State *env, ZMMReg *d, MMXReg *s)
 {
 d->ZMM_S(0) = int32_to_float32(s->MMX_L(0), >sse_status);
@@ -713,8 +719,11 @@ void helper_cvtsq2sd(CPUX86State *env, ZMMReg *d, uint64_t 
val)
 }
 #endif
 
+#endif
+
 /* float to integer */
 
+#if SHIFT == 1
 /*
  * x86 mandates that we return the indefinite integer value for the result
  * of any float-to-integer conversion that raises the 'invalid' exception.
@@ -745,22 +754,28 @@ WRAP_FLOATCONV(int64_t, float32_to_int64, float32, 
INT64_MIN)
 WRAP_FLOATCONV(int64_t, float32_to_int64_round_to_zero, float32, INT64_MIN)
 WRAP_FLOATCONV(int64_t, float64_to_int64, float64, INT64_MIN)
 WRAP_FLOATCONV(int64_t, float64_to_int64_round_to_zero, float64, INT64_MIN)
+#endif
 
 void glue(helper_cvtps2dq, SUFFIX)(CPUX86State *env, ZMMReg *d, ZMMReg *s)
 {
-d->ZMM_L(0) = x86_float32_to_int32(s->ZMM_S(0), >sse_status);
-d->ZMM_L(1) = x86_float32_to_int32(s->ZMM_S(1), >sse_status);
-d->ZMM_L(2) = x86_float32_to_int32(s->ZMM_S(2), >sse_status);
-d->ZMM_L(3) = x86_float32_to_int32(s->ZMM_S(3), >sse_status);
+int i;
+for (i = 0; i < 2 << SHIFT; i++) {
+d->ZMM_L(i) = x86_float32_to_int32(s->ZMM_S(i), >sse_status);
+}
 }
 
 void glue(helper_cvtpd2dq, SUFFIX)(CPUX86State *env, ZMMReg *d, ZMMReg *s)
 {
-d->ZMM_L(0) = x86_float64_to_int32(s->ZMM_D(0), >sse_status);
-d->ZMM_L(1) = x86_float64_to_int32(s->ZMM_D(1), >sse_status);
-d->ZMM_Q(1) = 0;
+int i;
+for (i = 0; i < 1 << SHIFT; i++) {
+d->ZMM_L(i) = x86_float64_to_int32(s->ZMM_D(i), >sse_status);
+}
+for (i >>= 1; i < 1 << SHIFT; i++) {
+ d->Q(i) = 0;
+}
 }
 
+#if SHIFT == 1
 void helper_cvtps2pi(CPUX86State *env, MMXReg *d, ZMMReg *s)
 {
 d->MMX_L(0) = x86_float32_to_int32(s->ZMM_S(0), >sse_status);
@@ -794,23 +809,31 @@ int64_t 

[PULL 33/39] target/i386: reimplement AVX comparison helpers

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

AVX includes an additional set of comparison predicates, some of which
our softfloat implementation does not expose as separate functions.
Rewrite the helpers in terms of floatN_compare for future extensibility.

Signed-off-by: Paul Brook 
Reviewed-by: Richard Henderson 
Message-Id: <20220424220204.2493824-24-p...@nowt.org>
Signed-off-by: Paolo Bonzini 
---
 target/i386/ops_sse.h| 97 
 target/i386/ops_sse_header.h | 24 -
 target/i386/tcg/translate.c  | 20 
 3 files changed, 75 insertions(+), 66 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index 86ca74492e..7463ff1599 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -1005,57 +1005,66 @@ void glue(helper_addsubpd, SUFFIX)(CPUX86State *env, 
Reg *d, Reg *s)
 }
 }
 
-/* XXX: unordered */
-#define SSE_HELPER_CMP(name, F) \
-void glue(helper_ ## name ## ps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)\
+#define SSE_HELPER_CMP_P(name, F, C)\
+void glue(helper_ ## name ## ps, SUFFIX)(CPUX86State *env,  \
+ Reg *d, Reg *s)\
 {   \
-d->ZMM_L(0) = F(32, d->ZMM_S(0), s->ZMM_S(0));  \
-d->ZMM_L(1) = F(32, d->ZMM_S(1), s->ZMM_S(1));  \
-d->ZMM_L(2) = F(32, d->ZMM_S(2), s->ZMM_S(2));  \
-d->ZMM_L(3) = F(32, d->ZMM_S(3), s->ZMM_S(3));  \
+Reg *v = d; \
+int i;  \
+for (i = 0; i < 2 << SHIFT; i++) {  \
+d->ZMM_L(i) = C(F(32, v->ZMM_S(i), s->ZMM_S(i))) ? -1 : 0;  \
+}   \
 }   \
 \
-void helper_ ## name ## ss(CPUX86State *env, Reg *d, Reg *s)\
+void glue(helper_ ## name ## pd, SUFFIX)(CPUX86State *env,  \
+ Reg *d, Reg *s)\
 {   \
-d->ZMM_L(0) = F(32, d->ZMM_S(0), s->ZMM_S(0));  \
-}   \
-\
-void glue(helper_ ## name ## pd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)\
-{   \
-d->ZMM_Q(0) = F(64, d->ZMM_D(0), s->ZMM_D(0));  \
-d->ZMM_Q(1) = F(64, d->ZMM_D(1), s->ZMM_D(1));  \
-}   \
-\
-void helper_ ## name ## sd(CPUX86State *env, Reg *d, Reg *s)\
-{   \
-d->ZMM_Q(0) = F(64, d->ZMM_D(0), s->ZMM_D(0));  \
+Reg *v = d; \
+int i;  \
+for (i = 0; i < 1 << SHIFT; i++) {  \
+d->ZMM_Q(i) = C(F(64, v->ZMM_D(i), s->ZMM_D(i))) ? -1 : 0;  \
+}   \
 }
 
-#define FPU_CMPEQ(size, a, b)   \
-(float ## size ## _eq_quiet(a, b, >sse_status) ? -1 : 0)
-#define FPU_CMPLT(size, a, b)   \
-(float ## size ## _lt(a, b, >sse_status) ? -1 : 0)
-#define FPU_CMPLE(size, a, b)   \
-(float ## size ## _le(a, b, >sse_status) ? -1 : 0)
-#define FPU_CMPUNORD(size, a, b)\
-(float ## size ## _unordered_quiet(a, b, >sse_status) ? -1 : 0)
-#define FPU_CMPNEQ(size, a, b)  \
-(float ## size ## _eq_quiet(a, b, >sse_status) ? 0 : -1)
-#define FPU_CMPNLT(size, a, b)  \
-(float ## size ## _lt(a, b, >sse_status) ? 0 : -1)
-#define FPU_CMPNLE(size, a, b)  \
-(float ## size ## _le(a, b, >sse_status) ? 0 : -1)
-#define FPU_CMPORD(size, a, b)  \
-(float ## size ## _unordered_quiet(a, b, >sse_status) ? 0 : -1)
+#if SHIFT == 1
+#define SSE_HELPER_CMP(name, F, C)  \
+SSE_HELPER_CMP_P(name, F, C)\
+void 

[PULL 35/39] target/i386: Destructive FP helpers for AVX

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

Perpare the horizontal atithmetic vector helpers for AVX
These currently use a dummy Reg typed variable to store the result then
assign the whole register.  This will cause 128 bit operations to corrupt
the upper half of the register, so replace it with explicit temporaries
and element assignments.

Signed-off-by: Paul Brook 
Message-Id: <20220424220204.2493824-18-p...@nowt.org>
Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 target/i386/ops_sse.h | 91 ++-
 1 file changed, 38 insertions(+), 53 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index c9737e16b9..c6dba9572d 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -22,7 +22,6 @@
 
 #if SHIFT == 0
 #define Reg MMXReg
-#define SIZE 8
 #define XMM_ONLY(...)
 #define B(n) MMX_B(n)
 #define W(n) MMX_W(n)
@@ -31,7 +30,6 @@
 #define SUFFIX _mmx
 #else
 #define Reg ZMMReg
-#define SIZE 16
 #define XMM_ONLY(...) __VA_ARGS__
 #define B(n) ZMM_B(n)
 #define W(n) ZMM_W(n)
@@ -43,22 +41,6 @@
 #define LANE_WIDTH (SHIFT ? 16 : 8)
 #define PACK_WIDTH (LANE_WIDTH / 2)
 
-/*
- * Copy the relevant parts of a Reg value around. In the case where
- * sizeof(Reg) > SIZE, these helpers operate only on the lower bytes of
- * a 64 byte ZMMReg, so we must copy only those and keep the top bytes
- * untouched in the guest-visible destination destination register.
- * Note that the "lower bytes" are placed last in memory on big-endian
- * hosts, which store the vector backwards in memory.  In that case the
- * copy *starts* at B(SIZE - 1) and ends at B(0), the opposite of
- * the little-endian case.
- */
-#if HOST_BIG_ENDIAN
-#define MOVE(d, r) memcpy(&((d).B(SIZE - 1)), &(r).B(SIZE - 1), SIZE)
-#else
-#define MOVE(d, r) memcpy(&(d).B(0), &(r).B(0), SIZE)
-#endif
-
 #if SHIFT == 0
 #define FPSRL(x, c) ((x) >> shift)
 #define FPSRAW(x, c) ((int16_t)(x) >> shift)
@@ -945,45 +927,49 @@ void helper_insertq_i(CPUX86State *env, ZMMReg *d, int 
index, int length)
 d->ZMM_Q(0) = helper_insertq(d->ZMM_Q(0), index, length);
 }
 
-void glue(helper_haddps, SUFFIX)(CPUX86State *env, ZMMReg *d, ZMMReg *s)
-{
-ZMMReg r;
-
-r.ZMM_S(0) = float32_add(d->ZMM_S(0), d->ZMM_S(1), >sse_status);
-r.ZMM_S(1) = float32_add(d->ZMM_S(2), d->ZMM_S(3), >sse_status);
-r.ZMM_S(2) = float32_add(s->ZMM_S(0), s->ZMM_S(1), >sse_status);
-r.ZMM_S(3) = float32_add(s->ZMM_S(2), s->ZMM_S(3), >sse_status);
-MOVE(*d, r);
+#define SSE_HELPER_HPS(name, F)  \
+void glue(helper_ ## name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \
+{ \
+Reg *v = d;   \
+float32 r[2 << SHIFT];\
+int i, j, k;  \
+for (k = 0; k < 2 << SHIFT; k += LANE_WIDTH / 4) {\
+for (i = j = 0; j < 4; i++, j += 2) { \
+r[i + k] = F(v->ZMM_S(j + k), v->ZMM_S(j + k + 1), 
>sse_status); \
+} \
+for (j = 0; j < 4; i++, j += 2) { \
+r[i + k] = F(s->ZMM_S(j + k), s->ZMM_S(j + k + 1), 
>sse_status); \
+} \
+} \
+for (i = 0; i < 2 << SHIFT; i++) {\
+d->ZMM_S(i) = r[i];   \
+} \
 }
 
-void glue(helper_haddpd, SUFFIX)(CPUX86State *env, ZMMReg *d, ZMMReg *s)
-{
-ZMMReg r;
+SSE_HELPER_HPS(haddps, float32_add)
+SSE_HELPER_HPS(hsubps, float32_sub)
 
-r.ZMM_D(0) = float64_add(d->ZMM_D(0), d->ZMM_D(1), >sse_status);
-r.ZMM_D(1) = float64_add(s->ZMM_D(0), s->ZMM_D(1), >sse_status);
-MOVE(*d, r);
+#define SSE_HELPER_HPD(name, F)  \
+void glue(helper_ ## name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \
+{ \
+Reg *v = d;   \
+float64 r[1 << SHIFT];\
+int i, j, k;  \
+for (k = 0; k < 1 << SHIFT; k += LANE_WIDTH / 8) {\
+for (i = j = 0; j < 2; i++, j += 2) { \
+r[i + k] = F(v->ZMM_D(j + k), v->ZMM_D(j + k + 1), 
>sse_status); \
+} \
+for (j = 0; j < 2; i++, j += 2) { \
+r[i + k] = F(s->ZMM_D(j + k), s->ZMM_D(j + k + 1), 
>sse_status); \
+} \
+} \
+for (i = 0; i < 1 << SHIFT; i++) { 

[PULL 29/39] target/i386: Rewrite simple integer vector helpers

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

Rewrite the "simple" vector integer helpers in preperation for AVX support.

While the current code is able to use the same prototype for unary
(a = F(b)) and binary (a = F(b, c)) operations, future changes will cause
them to diverge.

No functional changes to existing helpers

Signed-off-by: Paul Brook 
Message-Id: <20220424220204.2493824-12-p...@nowt.org>
Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 target/i386/ops_sse.h | 83 +++
 1 file changed, 28 insertions(+), 55 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index a4a09226e3..ce03362810 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -229,63 +229,36 @@ void glue(helper_pslldq, SUFFIX)(CPUX86State *env, Reg 
*d, Reg *c)
 }
 #endif
 
-#define SSE_HELPER_B(name, F)   \
+#define SSE_HELPER_1(name, elem, num, F)\
 void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)   \
 {   \
-d->B(0) = F(d->B(0), s->B(0));  \
-d->B(1) = F(d->B(1), s->B(1));  \
-d->B(2) = F(d->B(2), s->B(2));  \
-d->B(3) = F(d->B(3), s->B(3));  \
-d->B(4) = F(d->B(4), s->B(4));  \
-d->B(5) = F(d->B(5), s->B(5));  \
-d->B(6) = F(d->B(6), s->B(6));  \
-d->B(7) = F(d->B(7), s->B(7));  \
-XMM_ONLY(   \
- d->B(8) = F(d->B(8), s->B(8)); \
- d->B(9) = F(d->B(9), s->B(9)); \
- d->B(10) = F(d->B(10), s->B(10));  \
- d->B(11) = F(d->B(11), s->B(11));  \
- d->B(12) = F(d->B(12), s->B(12));  \
- d->B(13) = F(d->B(13), s->B(13));  \
- d->B(14) = F(d->B(14), s->B(14));  \
- d->B(15) = F(d->B(15), s->B(15));  \
-)   \
-}
+int n = num;\
+for (int i = 0; i < n; i++) {   \
+d->elem(i) = F(s->elem(i)); \
+}   \
+}
+
+#define SSE_HELPER_2(name, elem, num, F)\
+void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)   \
+{   \
+Reg *v = d; \
+int n = num;\
+for (int i = 0; i < n; i++) {   \
+d->elem(i) = F(v->elem(i), s->elem(i)); \
+}   \
+}
+
+#define SSE_HELPER_B(name, F)   \
+SSE_HELPER_2(name, B, 8 << SHIFT, F)
 
 #define SSE_HELPER_W(name, F)   \
-void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)   \
-{   \
-d->W(0) = F(d->W(0), s->W(0));  \
-d->W(1) = F(d->W(1), s->W(1));  \
-d->W(2) = F(d->W(2), s->W(2));  \
-d->W(3) = F(d->W(3), s->W(3));  \
-XMM_ONLY(   \
- d->W(4) = F(d->W(4), s->W(4)); \
- d->W(5) = F(d->W(5), s->W(5)); \
- d->W(6) = F(d->W(6), s->W(6)); \
- d->W(7) = F(d->W(7), s->W(7)); \
-)   \
-}
+SSE_HELPER_2(name, W, 4 << SHIFT, F)
 
 #define SSE_HELPER_L(name, F)   \
-void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)   \
-{   \
-d->L(0) = F(d->L(0), s->L(0));  \
-d->L(1) = F(d->L(1), s->L(1));  \
-XMM_ONLY(   \
- d->L(2) = F(d->L(2), s->L(2)); \
- d->L(3) = F(d->L(3), s->L(3)); \
-)   \
-}
+SSE_HELPER_2(name, L, 2 << SHIFT, F)
 
 #define SSE_HELPER_Q(name, F)   \
-void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)   \
-{  

[PULL 38/39] target/i386: AVX pclmulqdq prep

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

Make the pclmulqdq helper AVX ready

Signed-off-by: Paul Brook 
Message-Id: <20220424220204.2493824-21-p...@nowt.org>
Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 target/i386/ops_sse.h | 29 ++---
 1 file changed, 22 insertions(+), 7 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index 5241663227..c791e86af7 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -2211,14 +2211,14 @@ target_ulong helper_crc32(uint32_t crc1, target_ulong 
msg, uint32_t len)
 
 #endif
 
-void glue(helper_pclmulqdq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
-uint32_t ctrl)
+#if SHIFT == 1
+static void clmulq(uint64_t *dest_l, uint64_t *dest_h,
+  uint64_t a, uint64_t b)
 {
-uint64_t ah, al, b, resh, resl;
+uint64_t al, ah, resh, resl;
 
 ah = 0;
-al = d->Q((ctrl & 1) != 0);
-b = s->Q((ctrl & 16) != 0);
+al = a;
 resh = resl = 0;
 
 while (b) {
@@ -2231,8 +2231,23 @@ void glue(helper_pclmulqdq, SUFFIX)(CPUX86State *env, 
Reg *d, Reg *s,
 b >>= 1;
 }
 
-d->Q(0) = resl;
-d->Q(1) = resh;
+*dest_l = resl;
+*dest_h = resh;
+}
+#endif
+
+void glue(helper_pclmulqdq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
+uint32_t ctrl)
+{
+Reg *v = d;
+uint64_t a, b;
+int i;
+
+for (i = 0; i < 1 << SHIFT; i += 2) {
+a = v->Q(((ctrl & 1) != 0) + i);
+b = s->Q(((ctrl & 16) != 0) + i);
+clmulq(>Q(i), >Q(i + 1), a, b);
+}
 }
 
 void glue(helper_aesdec, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
-- 
2.37.2





[PULL 30/39] target/i386: Misc integer AVX helper prep

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

More preparatory work for AVX support in various integer vector helpers

No functional changes to existing helpers.

Signed-off-by: Paul Brook 
Message-Id: <20220424220204.2493824-13-p...@nowt.org>
Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 target/i386/ops_sse.h | 164 +-
 1 file changed, 80 insertions(+), 84 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index ce03362810..557cc7ce7d 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -390,19 +390,22 @@ SSE_HELPER_W(helper_pavgw, FAVG)
 
 void glue(helper_pmuludq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
 {
-d->Q(0) = (uint64_t)s->L(0) * (uint64_t)d->L(0);
-#if SHIFT == 1
-d->Q(1) = (uint64_t)s->L(2) * (uint64_t)d->L(2);
-#endif
+Reg *v = d;
+int i;
+
+for (i = 0; i < (1 << SHIFT); i++) {
+d->Q(i) = (uint64_t)s->L(i * 2) * (uint64_t)v->L(i * 2);
+}
 }
 
 void glue(helper_pmaddwd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
 {
+Reg *v = d;
 int i;
 
 for (i = 0; i < (2 << SHIFT); i++) {
-d->L(i) = (int16_t)s->W(2 * i) * (int16_t)d->W(2 * i) +
-(int16_t)s->W(2 * i + 1) * (int16_t)d->W(2 * i + 1);
+d->L(i) = (int16_t)s->W(2 * i) * (int16_t)v->W(2 * i) +
+(int16_t)s->W(2 * i + 1) * (int16_t)v->W(2 * i + 1);
 }
 }
 
@@ -416,32 +419,24 @@ static inline int abs1(int a)
 }
 }
 #endif
+
 void glue(helper_psadbw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
 {
-unsigned int val;
+Reg *v = d;
+int i;
 
-val = 0;
-val += abs1(d->B(0) - s->B(0));
-val += abs1(d->B(1) - s->B(1));
-val += abs1(d->B(2) - s->B(2));
-val += abs1(d->B(3) - s->B(3));
-val += abs1(d->B(4) - s->B(4));
-val += abs1(d->B(5) - s->B(5));
-val += abs1(d->B(6) - s->B(6));
-val += abs1(d->B(7) - s->B(7));
-d->Q(0) = val;
-#if SHIFT == 1
-val = 0;
-val += abs1(d->B(8) - s->B(8));
-val += abs1(d->B(9) - s->B(9));
-val += abs1(d->B(10) - s->B(10));
-val += abs1(d->B(11) - s->B(11));
-val += abs1(d->B(12) - s->B(12));
-val += abs1(d->B(13) - s->B(13));
-val += abs1(d->B(14) - s->B(14));
-val += abs1(d->B(15) - s->B(15));
-d->Q(1) = val;
-#endif
+for (i = 0; i < (1 << SHIFT); i++) {
+unsigned int val = 0;
+val += abs1(v->B(8 * i + 0) - s->B(8 * i + 0));
+val += abs1(v->B(8 * i + 1) - s->B(8 * i + 1));
+val += abs1(v->B(8 * i + 2) - s->B(8 * i + 2));
+val += abs1(v->B(8 * i + 3) - s->B(8 * i + 3));
+val += abs1(v->B(8 * i + 4) - s->B(8 * i + 4));
+val += abs1(v->B(8 * i + 5) - s->B(8 * i + 5));
+val += abs1(v->B(8 * i + 6) - s->B(8 * i + 6));
+val += abs1(v->B(8 * i + 7) - s->B(8 * i + 7));
+d->Q(i) = val;
+}
 }
 
 void glue(helper_maskmov, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
@@ -458,20 +453,24 @@ void glue(helper_maskmov, SUFFIX)(CPUX86State *env, Reg 
*d, Reg *s,
 
 void glue(helper_movl_mm_T0, SUFFIX)(Reg *d, uint32_t val)
 {
+int i;
+
 d->L(0) = val;
 d->L(1) = 0;
-#if SHIFT == 1
-d->Q(1) = 0;
-#endif
+for (i = 1; i < (1 << SHIFT); i++) {
+d->Q(i) = 0;
+}
 }
 
 #ifdef TARGET_X86_64
 void glue(helper_movq_mm_T0, SUFFIX)(Reg *d, uint64_t val)
 {
+int i;
+
 d->Q(0) = val;
-#if SHIFT == 1
-d->Q(1) = 0;
-#endif
+for (i = 1; i < (1 << SHIFT); i++) {
+d->Q(i) = 0;
+}
 }
 #endif
 
@@ -1074,26 +1073,21 @@ uint32_t glue(helper_movmskpd, SUFFIX)(CPUX86State 
*env, Reg *s)
 uint32_t glue(helper_pmovmskb, SUFFIX)(CPUX86State *env, Reg *s)
 {
 uint32_t val;
+int i;
 
 val = 0;
-val |= (s->B(0) >> 7);
-val |= (s->B(1) >> 6) & 0x02;
-val |= (s->B(2) >> 5) & 0x04;
-val |= (s->B(3) >> 4) & 0x08;
-val |= (s->B(4) >> 3) & 0x10;
-val |= (s->B(5) >> 2) & 0x20;
-val |= (s->B(6) >> 1) & 0x40;
-val |= (s->B(7)) & 0x80;
-#if SHIFT == 1
-val |= (s->B(8) << 1) & 0x0100;
-val |= (s->B(9) << 2) & 0x0200;
-val |= (s->B(10) << 3) & 0x0400;
-val |= (s->B(11) << 4) & 0x0800;
-val |= (s->B(12) << 5) & 0x1000;
-val |= (s->B(13) << 6) & 0x2000;
-val |= (s->B(14) << 7) & 0x4000;
-val |= (s->B(15) << 8) & 0x8000;
-#endif
+for (i = 0; i < (1 << SHIFT); i++) {
+uint8_t byte = 0;
+byte |= (s->B(8 * i + 0) >> 7);
+byte |= (s->B(8 * i + 1) >> 6) & 0x02;
+byte |= (s->B(8 * i + 2) >> 5) & 0x04;
+byte |= (s->B(8 * i + 3) >> 4) & 0x08;
+byte |= (s->B(8 * i + 4) >> 3) & 0x10;
+byte |= (s->B(8 * i + 5) >> 2) & 0x20;
+byte |= (s->B(8 * i + 6) >> 1) & 0x40;
+byte |= (s->B(8 * i + 7)) & 0x80;
+val |= byte << (8 * i);
+}
 return val;
 }
 
@@ -1638,46 +1632,48 @@ SSE_HELPER_V(helper_blendvpd, Q, 2, FBLENDVPD)
 
 void glue(helper_ptest, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
 {
-uint64_t zf = (s->Q(0) &  d->Q(0)) | (s->Q(1) &  d->Q(1));
- 

[PULL 28/39] target/i386: Rewrite vector shift helper

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

Rewrite the vector shift helpers in preperation for AVX support (3 operand
form and 256 bit vectors).

For now keep the existing two operand interface.

No functional changes to existing helpers.

Signed-off-by: Paul Brook 
Message-Id: <20220424220204.2493824-11-p...@nowt.org>
Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 target/i386/ops_sse.h | 247 +++---
 1 file changed, 112 insertions(+), 135 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index 2c0090a647..a4a09226e3 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -40,6 +40,8 @@
 #define SUFFIX _xmm
 #endif
 
+#define LANE_WIDTH (SHIFT ? 16 : 8)
+
 /*
  * Copy the relevant parts of a Reg value around. In the case where
  * sizeof(Reg) > SIZE, these helpers operate only on the lower bytes of
@@ -56,198 +58,173 @@
 #define MOVE(d, r) memcpy(&(d).B(0), &(r).B(0), SIZE)
 #endif
 
-void glue(helper_psrlw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
-{
-int shift;
+#if SHIFT == 0
+#define FPSRL(x, c) ((x) >> shift)
+#define FPSRAW(x, c) ((int16_t)(x) >> shift)
+#define FPSRAL(x, c) ((int32_t)(x) >> shift)
+#define FPSLL(x, c) ((x) << shift)
+#endif
 
-if (s->Q(0) > 15) {
-d->Q(0) = 0;
-#if SHIFT == 1
-d->Q(1) = 0;
-#endif
+void glue(helper_psrlw, SUFFIX)(CPUX86State *env, Reg *d, Reg *c)
+{
+Reg *s = d;
+int shift;
+if (c->Q(0) > 15) {
+for (int i = 0; i < 1 << SHIFT; i++) {
+d->Q(i) = 0;
+}
 } else {
-shift = s->B(0);
-d->W(0) >>= shift;
-d->W(1) >>= shift;
-d->W(2) >>= shift;
-d->W(3) >>= shift;
-#if SHIFT == 1
-d->W(4) >>= shift;
-d->W(5) >>= shift;
-d->W(6) >>= shift;
-d->W(7) >>= shift;
-#endif
+shift = c->B(0);
+for (int i = 0; i < 4 << SHIFT; i++) {
+d->W(i) = FPSRL(s->W(i), shift);
+}
 }
 }
 
-void glue(helper_psraw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
+void glue(helper_psllw, SUFFIX)(CPUX86State *env, Reg *d, Reg *c)
 {
+Reg *s = d;
 int shift;
+if (c->Q(0) > 15) {
+for (int i = 0; i < 1 << SHIFT; i++) {
+d->Q(i) = 0;
+}
+} else {
+shift = c->B(0);
+for (int i = 0; i < 4 << SHIFT; i++) {
+d->W(i) = FPSLL(s->W(i), shift);
+}
+}
+}
 
-if (s->Q(0) > 15) {
+void glue(helper_psraw, SUFFIX)(CPUX86State *env, Reg *d, Reg *c)
+{
+Reg *s = d;
+int shift;
+if (c->Q(0) > 15) {
 shift = 15;
 } else {
-shift = s->B(0);
+shift = c->B(0);
+}
+for (int i = 0; i < 4 << SHIFT; i++) {
+d->W(i) = FPSRAW(s->W(i), shift);
 }
-d->W(0) = (int16_t)d->W(0) >> shift;
-d->W(1) = (int16_t)d->W(1) >> shift;
-d->W(2) = (int16_t)d->W(2) >> shift;
-d->W(3) = (int16_t)d->W(3) >> shift;
-#if SHIFT == 1
-d->W(4) = (int16_t)d->W(4) >> shift;
-d->W(5) = (int16_t)d->W(5) >> shift;
-d->W(6) = (int16_t)d->W(6) >> shift;
-d->W(7) = (int16_t)d->W(7) >> shift;
-#endif
 }
 
-void glue(helper_psllw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
+void glue(helper_psrld, SUFFIX)(CPUX86State *env, Reg *d, Reg *c)
 {
+Reg *s = d;
 int shift;
-
-if (s->Q(0) > 15) {
-d->Q(0) = 0;
-#if SHIFT == 1
-d->Q(1) = 0;
-#endif
+if (c->Q(0) > 31) {
+for (int i = 0; i < 1 << SHIFT; i++) {
+d->Q(i) = 0;
+}
 } else {
-shift = s->B(0);
-d->W(0) <<= shift;
-d->W(1) <<= shift;
-d->W(2) <<= shift;
-d->W(3) <<= shift;
-#if SHIFT == 1
-d->W(4) <<= shift;
-d->W(5) <<= shift;
-d->W(6) <<= shift;
-d->W(7) <<= shift;
-#endif
+shift = c->B(0);
+for (int i = 0; i < 2 << SHIFT; i++) {
+d->L(i) = FPSRL(s->L(i), shift);
+}
 }
 }
 
-void glue(helper_psrld, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
+void glue(helper_pslld, SUFFIX)(CPUX86State *env, Reg *d, Reg *c)
 {
+Reg *s = d;
 int shift;
-
-if (s->Q(0) > 31) {
-d->Q(0) = 0;
-#if SHIFT == 1
-d->Q(1) = 0;
-#endif
+if (c->Q(0) > 31) {
+for (int i = 0; i < 1 << SHIFT; i++) {
+d->Q(i) = 0;
+}
 } else {
-shift = s->B(0);
-d->L(0) >>= shift;
-d->L(1) >>= shift;
-#if SHIFT == 1
-d->L(2) >>= shift;
-d->L(3) >>= shift;
-#endif
+shift = c->B(0);
+for (int i = 0; i < 2 << SHIFT; i++) {
+d->L(i) = FPSLL(s->L(i), shift);
+}
 }
 }
 
-void glue(helper_psrad, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
+void glue(helper_psrad, SUFFIX)(CPUX86State *env, Reg *d, Reg *c)
 {
+Reg *s = d;
 int shift;
-
-if (s->Q(0) > 31) {
+if (c->Q(0) > 31) {
 shift = 31;
 } else {
-shift = s->B(0);
+shift = c->B(0);
+}
+for (int i = 0; i < 2 << SHIFT; i++) {
+d->L(i) = 

[PULL 37/39] target/i386: Rewrite blendv helpers

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

Rewrite the blendv helpers so that they can easily be extended to support
the AVX encodings, which make all 4 arguments explicit.

No functional changes to the existing helpers

Signed-off-by: Paul Brook 
Message-Id: <20220424220204.2493824-20-p...@nowt.org>
Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 target/i386/ops_sse.h | 86 ---
 1 file changed, 24 insertions(+), 62 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index 0c4257dee7..5241663227 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -1591,76 +1591,38 @@ void glue(helper_palignr, SUFFIX)(CPUX86State *env, Reg 
*d, Reg *s,
 }
 }
 
-#define XMM0 (env->xmm_regs[0])
+#if SHIFT >= 1
 
-#if SHIFT == 1
 #define SSE_HELPER_V(name, elem, num, F)\
-void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)   \
+void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)   \
 {   \
-d->elem(0) = F(d->elem(0), s->elem(0), XMM0.elem(0));   \
-d->elem(1) = F(d->elem(1), s->elem(1), XMM0.elem(1));   \
-if (num > 2) {  \
-d->elem(2) = F(d->elem(2), s->elem(2), XMM0.elem(2));   \
-d->elem(3) = F(d->elem(3), s->elem(3), XMM0.elem(3));   \
-if (num > 4) {  \
-d->elem(4) = F(d->elem(4), s->elem(4), XMM0.elem(4));   \
-d->elem(5) = F(d->elem(5), s->elem(5), XMM0.elem(5));   \
-d->elem(6) = F(d->elem(6), s->elem(6), XMM0.elem(6));   \
-d->elem(7) = F(d->elem(7), s->elem(7), XMM0.elem(7));   \
-if (num > 8) {  \
-d->elem(8) = F(d->elem(8), s->elem(8), XMM0.elem(8)); \
-d->elem(9) = F(d->elem(9), s->elem(9), XMM0.elem(9)); \
-d->elem(10) = F(d->elem(10), s->elem(10), XMM0.elem(10)); \
-d->elem(11) = F(d->elem(11), s->elem(11), XMM0.elem(11)); \
-d->elem(12) = F(d->elem(12), s->elem(12), XMM0.elem(12)); \
-d->elem(13) = F(d->elem(13), s->elem(13), XMM0.elem(13)); \
-d->elem(14) = F(d->elem(14), s->elem(14), XMM0.elem(14)); \
-d->elem(15) = F(d->elem(15), s->elem(15), XMM0.elem(15)); \
-}   \
-}   \
+Reg *v = d; \
+Reg *m = >xmm_regs[0]; \
+int i;  \
+for (i = 0; i < num; i++) { \
+d->elem(i) = F(v->elem(i), s->elem(i), m->elem(i)); \
 }   \
 }
 
 #define SSE_HELPER_I(name, elem, num, F)\
-void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t imm) \
+void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,   \
+uint32_t imm)   \
 {   \
-d->elem(0) = F(d->elem(0), s->elem(0), ((imm >> 0) & 1));   \
-d->elem(1) = F(d->elem(1), s->elem(1), ((imm >> 1) & 1));   \
-if (num > 2) {  \
-d->elem(2) = F(d->elem(2), s->elem(2), ((imm >> 2) & 1));   \
-d->elem(3) = F(d->elem(3), s->elem(3), ((imm >> 3) & 1));   \
-if (num > 4) {  \
-d->elem(4) = F(d->elem(4), s->elem(4), ((imm >> 4) & 1)); \
-d->elem(5) = F(d->elem(5), s->elem(5), ((imm >> 5) & 1)); \
-d->elem(6) = F(d->elem(6), s->elem(6), ((imm >> 6) & 1)); \
-d->elem(7) = F(d->elem(7), s->elem(7), ((imm >> 7) & 1)); \
-if (num > 8) {  \
-d->elem(8) = F(d->elem(8), s->elem(8), ((imm >> 8) & 1)); \
-d->elem(9) = F(d->elem(9), s->elem(9), ((imm >> 9) & 1)); \
-d->elem(10) = F(d->elem(10), s->elem(10),   \
-((imm >> 10) & 1)); \
-d->elem(11) = F(d->elem(11), s->elem(11),   \
-((imm >> 11) & 1)); \
-d->elem(12) = F(d->elem(12), s->elem(12),   \
-((imm >> 12) & 1)); \
-

[PULL 25/39] target/i386: do not cast gen_helper_* function pointers

2022-09-01 Thread Paolo Bonzini
Use a union to store the various possible kinds of function pointers, and
access the correct one based on the flags.

SSEOpHelper_table6 and SSEOpHelper_table7 right now only have one case,
but this would change with AVX's 3- and 4-argument operations.  Use
unions there too, to keep the code more similar for the three tables.

Extracted from a patch by Paul Brook .

Signed-off-by: Paolo Bonzini 
---
 target/i386/tcg/translate.c | 75 ++---
 1 file changed, 37 insertions(+), 38 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 16db155c94..c6a9a5b1d4 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -2784,6 +2784,8 @@ typedef void (*SSEFunc_l_ep)(TCGv_i64 val, TCGv_ptr env, 
TCGv_ptr reg);
 typedef void (*SSEFunc_0_epi)(TCGv_ptr env, TCGv_ptr reg, TCGv_i32 val);
 typedef void (*SSEFunc_0_epl)(TCGv_ptr env, TCGv_ptr reg, TCGv_i64 val);
 typedef void (*SSEFunc_0_epp)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b);
+typedef void (*SSEFunc_0_eppp)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b,
+   TCGv_ptr reg_c);
 typedef void (*SSEFunc_0_eppi)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b,
TCGv_i32 val);
 typedef void (*SSEFunc_0_ppi)(TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv_i32 val);
@@ -2798,7 +2800,7 @@ typedef void (*SSEFunc_0_eppt)(TCGv_ptr env, TCGv_ptr 
reg_a, TCGv_ptr reg_b,
 #define SSE_OPF_SHUF  (1 << 9) /* pshufx/shufpx */
 
 #define OP(op, flags, a, b, c, d)   \
-{flags, {a, b, c, d} }
+{flags, {{.op = a}, {.op = b}, {.op = c}, {.op = d} } }
 
 #define MMX_OP(x) OP(op1, SSE_OPF_MMX, \
 gen_helper_ ## x ## _mmx, gen_helper_ ## x ## _xmm, NULL, NULL)
@@ -2809,9 +2811,15 @@ typedef void (*SSEFunc_0_eppt)(TCGv_ptr env, TCGv_ptr 
reg_a, TCGv_ptr reg_b,
 #define SSE_OP(sname, dname, op, flags) OP(op, flags, \
 gen_helper_##sname##_xmm, gen_helper_##dname##_xmm, NULL, NULL)
 
+typedef union SSEFuncs {
+SSEFunc_0_epp op1;
+SSEFunc_0_ppi op1i;
+SSEFunc_0_eppt op1t;
+} SSEFuncs;
+
 struct SSEOpHelper_table1 {
 int flags;
-SSEFunc_0_epp op[4];
+SSEFuncs fn[4];
 };
 
 #define SSE_3DNOW { SSE_OPF_3DNOW }
@@ -2867,8 +2875,7 @@ static const struct SSEOpHelper_table1 sse_op_table1[256] 
= {
 [0x5f] = SSE_FOP(max),
 
 [0xc2] = SSE_FOP(cmpeq), /* sse_op_table4 */
-[0xc6] = OP(dummy, SSE_OPF_SHUF, (SSEFunc_0_epp)gen_helper_shufps_xmm,
-(SSEFunc_0_epp)gen_helper_shufpd_xmm, NULL, NULL),
+[0xc6] = SSE_OP(shufps, shufpd, op1i, SSE_OPF_SHUF),
 
 /* SSSE3, SSE4, MOVBE, CRC32, BMI1, BMI2, ADX.  */
 [0x38] = SSE_SPECIAL,
@@ -2894,10 +2901,8 @@ static const struct SSEOpHelper_table1 
sse_op_table1[256] = {
 [0x6e] = SSE_SPECIAL, /* movd mm, ea */
 [0x6f] = SSE_SPECIAL, /* movq, movdqa, , movqdu */
 [0x70] = OP(op1i, SSE_OPF_SHUF | SSE_OPF_MMX,
-(SSEFunc_0_epp)gen_helper_pshufw_mmx,
-(SSEFunc_0_epp)gen_helper_pshufd_xmm,
-(SSEFunc_0_epp)gen_helper_pshufhw_xmm,
-(SSEFunc_0_epp)gen_helper_pshuflw_xmm),
+gen_helper_pshufw_mmx, gen_helper_pshufd_xmm,
+gen_helper_pshufhw_xmm, gen_helper_pshuflw_xmm),
 [0x71] = SSE_SPECIAL, /* shiftw */
 [0x72] = SSE_SPECIAL, /* shiftd */
 [0x73] = SSE_SPECIAL, /* shiftq */
@@ -2959,8 +2964,7 @@ static const struct SSEOpHelper_table1 sse_op_table1[256] 
= {
 [0xf5] = MMX_OP(pmaddwd),
 [0xf6] = MMX_OP(psadbw),
 [0xf7] = OP(op1t, SSE_OPF_MMX,
-(SSEFunc_0_epp)gen_helper_maskmov_mmx,
-(SSEFunc_0_epp)gen_helper_maskmov_xmm, NULL, NULL),
+gen_helper_maskmov_mmx, gen_helper_maskmov_xmm, NULL, NULL),
 [0xf8] = MMX_OP(psubb),
 [0xf9] = MMX_OP(psubw),
 [0xfa] = MMX_OP(psubl),
@@ -3057,17 +3061,19 @@ static const SSEFunc_0_epp sse_op_table5[256] = {
 [0xb6] = gen_helper_movq, /* pfrcpit2 */
 [0xb7] = gen_helper_pmulhrw_mmx,
 [0xbb] = gen_helper_pswapd,
-[0xbf] = gen_helper_pavgb_mmx /* pavgusb */
+[0xbf] = gen_helper_pavgb_mmx,
 };
 
 struct SSEOpHelper_table6 {
-SSEFunc_0_epp op[2];
+SSEFuncs fn[2];
 uint32_t ext_mask;
 int flags;
 };
 
 struct SSEOpHelper_table7 {
-SSEFunc_0_eppi op[2];
+union {
+SSEFunc_0_eppi op1;
+} fn[2];
 uint32_t ext_mask;
 int flags;
 };
@@ -3075,7 +3081,8 @@ struct SSEOpHelper_table7 {
 #define gen_helper_special_xmm NULL
 
 #define OP(name, op, flags, ext, mmx_name) \
-{{mmx_name, gen_helper_ ## name ## _xmm}, CPUID_EXT_ ## ext, flags}
+{{{.op = mmx_name}, {.op = gen_helper_ ## name ## _xmm} }, \
+CPUID_EXT_ ## ext, flags}
 #define BINARY_OP_MMX(name, ext) \
 OP(name, op1, SSE_OPF_MMX, ext, gen_helper_ ## name ## _mmx)
 #define BINARY_OP(name, ext, flags) \
@@ -3185,11 +3192,9 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 int b1, op1_offset, op2_offset, is_xmm, 

[PULL 39/39] target/i386: AVX+AES helpers prep

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

Make the AES vector helpers AVX ready

No functional changes to existing helpers

Signed-off-by: Paul Brook 
Message-Id: <20220424220204.2493824-22-p...@nowt.org>
Signed-off-by: Paolo Bonzini 
---
 target/i386/ops_sse.h | 41 ++---
 1 file changed, 22 insertions(+), 19 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index c791e86af7..c0766de18d 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -2256,11 +2256,12 @@ void glue(helper_aesdec, SUFFIX)(CPUX86State *env, Reg 
*d, Reg *s)
 Reg st = *d;
 Reg rk = *s;
 
-for (i = 0 ; i < 4 ; i++) {
-d->L(i) = rk.L(i) ^ bswap32(AES_Td0[st.B(AES_ishifts[4*i+0])] ^
-AES_Td1[st.B(AES_ishifts[4*i+1])] ^
-AES_Td2[st.B(AES_ishifts[4*i+2])] ^
-AES_Td3[st.B(AES_ishifts[4*i+3])]);
+for (i = 0 ; i < 2 << SHIFT ; i++) {
+int j = i & 3;
+d->L(i) = rk.L(i) ^ bswap32(AES_Td0[st.B(AES_ishifts[4 * j + 0])] ^
+AES_Td1[st.B(AES_ishifts[4 * j + 1])] ^
+AES_Td2[st.B(AES_ishifts[4 * j + 2])] ^
+AES_Td3[st.B(AES_ishifts[4 * j + 3])]);
 }
 }
 
@@ -2270,8 +2271,8 @@ void glue(helper_aesdeclast, SUFFIX)(CPUX86State *env, 
Reg *d, Reg *s)
 Reg st = *d;
 Reg rk = *s;
 
-for (i = 0; i < 16; i++) {
-d->B(i) = rk.B(i) ^ (AES_isbox[st.B(AES_ishifts[i])]);
+for (i = 0; i < 8 << SHIFT; i++) {
+d->B(i) = rk.B(i) ^ (AES_isbox[st.B(AES_ishifts[i & 15] + (i & ~15))]);
 }
 }
 
@@ -2281,11 +2282,12 @@ void glue(helper_aesenc, SUFFIX)(CPUX86State *env, Reg 
*d, Reg *s)
 Reg st = *d;
 Reg rk = *s;
 
-for (i = 0 ; i < 4 ; i++) {
-d->L(i) = rk.L(i) ^ bswap32(AES_Te0[st.B(AES_shifts[4*i+0])] ^
-AES_Te1[st.B(AES_shifts[4*i+1])] ^
-AES_Te2[st.B(AES_shifts[4*i+2])] ^
-AES_Te3[st.B(AES_shifts[4*i+3])]);
+for (i = 0 ; i < 2 << SHIFT ; i++) {
+int j = i & 3;
+d->L(i) = rk.L(i) ^ bswap32(AES_Te0[st.B(AES_shifts[4 * j + 0])] ^
+AES_Te1[st.B(AES_shifts[4 * j + 1])] ^
+AES_Te2[st.B(AES_shifts[4 * j + 2])] ^
+AES_Te3[st.B(AES_shifts[4 * j + 3])]);
 }
 }
 
@@ -2295,22 +2297,22 @@ void glue(helper_aesenclast, SUFFIX)(CPUX86State *env, 
Reg *d, Reg *s)
 Reg st = *d;
 Reg rk = *s;
 
-for (i = 0; i < 16; i++) {
-d->B(i) = rk.B(i) ^ (AES_sbox[st.B(AES_shifts[i])]);
+for (i = 0; i < 8 << SHIFT; i++) {
+d->B(i) = rk.B(i) ^ (AES_sbox[st.B(AES_shifts[i & 15] + (i & ~15))]);
 }
-
 }
 
+#if SHIFT == 1
 void glue(helper_aesimc, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
 {
 int i;
 Reg tmp = *s;
 
 for (i = 0 ; i < 4 ; i++) {
-d->L(i) = bswap32(AES_imc[tmp.B(4*i+0)][0] ^
-  AES_imc[tmp.B(4*i+1)][1] ^
-  AES_imc[tmp.B(4*i+2)][2] ^
-  AES_imc[tmp.B(4*i+3)][3]);
+d->L(i) = bswap32(AES_imc[tmp.B(4 * i + 0)][0] ^
+  AES_imc[tmp.B(4 * i + 1)][1] ^
+  AES_imc[tmp.B(4 * i + 2)][2] ^
+  AES_imc[tmp.B(4 * i + 3)][3]);
 }
 }
 
@@ -2328,6 +2330,7 @@ void glue(helper_aeskeygenassist, SUFFIX)(CPUX86State 
*env, Reg *d, Reg *s,
 d->L(3) = (d->L(2) << 24 | d->L(2) >> 8) ^ ctrl;
 }
 #endif
+#endif
 
 #undef SSE_HELPER_S
 
-- 
2.37.2




[PULL 27/39] target/i386: rewrite destructive 3DNow operations

2022-09-01 Thread Paolo Bonzini
Remove use of the MOVE macro, since it will be purged from
MMX/SSE as well.

Signed-off-by: Paolo Bonzini 
---
 target/i386/ops_sse.h | 32 
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index f603981ab8..2c0090a647 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -1327,11 +1327,11 @@ void helper_pf2iw(CPUX86State *env, MMXReg *d, MMXReg 
*s)
 
 void helper_pfacc(CPUX86State *env, MMXReg *d, MMXReg *s)
 {
-MMXReg r;
+float32 r;
 
-r.MMX_S(0) = float32_add(d->MMX_S(0), d->MMX_S(1), >mmx_status);
-r.MMX_S(1) = float32_add(s->MMX_S(0), s->MMX_S(1), >mmx_status);
-MOVE(*d, r);
+r = float32_add(d->MMX_S(0), d->MMX_S(1), >mmx_status);
+d->MMX_S(1) = float32_add(s->MMX_S(0), s->MMX_S(1), >mmx_status);
+d->MMX_S(0) = r;
 }
 
 void helper_pfadd(CPUX86State *env, MMXReg *d, MMXReg *s)
@@ -1392,20 +1392,20 @@ void helper_pfmul(CPUX86State *env, MMXReg *d, MMXReg 
*s)
 
 void helper_pfnacc(CPUX86State *env, MMXReg *d, MMXReg *s)
 {
-MMXReg r;
+float32 r;
 
-r.MMX_S(0) = float32_sub(d->MMX_S(0), d->MMX_S(1), >mmx_status);
-r.MMX_S(1) = float32_sub(s->MMX_S(0), s->MMX_S(1), >mmx_status);
-MOVE(*d, r);
+r = float32_sub(d->MMX_S(0), d->MMX_S(1), >mmx_status);
+d->MMX_S(1) = float32_sub(s->MMX_S(0), s->MMX_S(1), >mmx_status);
+d->MMX_S(0) = r;
 }
 
 void helper_pfpnacc(CPUX86State *env, MMXReg *d, MMXReg *s)
 {
-MMXReg r;
+float32 r;
 
-r.MMX_S(0) = float32_sub(d->MMX_S(0), d->MMX_S(1), >mmx_status);
-r.MMX_S(1) = float32_add(s->MMX_S(0), s->MMX_S(1), >mmx_status);
-MOVE(*d, r);
+r = float32_sub(d->MMX_S(0), d->MMX_S(1), >mmx_status);
+d->MMX_S(1) = float32_add(s->MMX_S(0), s->MMX_S(1), >mmx_status);
+d->MMX_S(0) = r;
 }
 
 void helper_pfrcp(CPUX86State *env, MMXReg *d, MMXReg *s)
@@ -1438,11 +1438,11 @@ void helper_pfsubr(CPUX86State *env, MMXReg *d, MMXReg 
*s)
 
 void helper_pswapd(CPUX86State *env, MMXReg *d, MMXReg *s)
 {
-MMXReg r;
+uint32_t r;
 
-r.MMX_L(0) = s->MMX_L(1);
-r.MMX_L(1) = s->MMX_L(0);
-MOVE(*d, r);
+r = s->MMX_L(0);
+d->MMX_L(0) = s->MMX_L(1);
+d->MMX_L(1) = r;
 }
 #endif
 
-- 
2.37.2





[PULL 31/39] target/i386: Destructive vector helpers for AVX

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

These helpers need to take special care to avoid overwriting source values
before the wole result has been calculated.  Currently they use a dummy
Reg typed variable to store the result then assign the whole register.
This will cause 128 bit operations to corrupt the upper half of the register,
so replace it with explicit temporaries and element assignments.

Signed-off-by: Paul Brook 
Message-Id: <20220424220204.2493824-14-p...@nowt.org>
Signed-off-by: Paolo Bonzini 
---
 target/i386/ops_sse.h | 556 --
 1 file changed, 262 insertions(+), 294 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index 557cc7ce7d..bb50ca6f8d 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -41,6 +41,7 @@
 #endif
 
 #define LANE_WIDTH (SHIFT ? 16 : 8)
+#define PACK_WIDTH (LANE_WIDTH / 2)
 
 /*
  * Copy the relevant parts of a Reg value around. In the case where
@@ -474,71 +475,81 @@ void glue(helper_movq_mm_T0, SUFFIX)(Reg *d, uint64_t val)
 }
 #endif
 
+#define SHUFFLE4(F, a, b, offset) do {  \
+r0 = a->F((order & 3) + offset);\
+r1 = a->F(((order >> 2) & 3) + offset); \
+r2 = b->F(((order >> 4) & 3) + offset); \
+r3 = b->F(((order >> 6) & 3) + offset); \
+d->F(offset) = r0;  \
+d->F(offset + 1) = r1;  \
+d->F(offset + 2) = r2;  \
+d->F(offset + 3) = r3;  \
+} while (0)
+
 #if SHIFT == 0
 void glue(helper_pshufw, SUFFIX)(Reg *d, Reg *s, int order)
 {
-Reg r;
+uint16_t r0, r1, r2, r3;
 
-r.W(0) = s->W(order & 3);
-r.W(1) = s->W((order >> 2) & 3);
-r.W(2) = s->W((order >> 4) & 3);
-r.W(3) = s->W((order >> 6) & 3);
-MOVE(*d, r);
+SHUFFLE4(W, s, s, 0);
 }
 #else
 void glue(helper_shufps, SUFFIX)(Reg *d, Reg *s, int order)
 {
-Reg r;
+Reg *v = d;
+uint32_t r0, r1, r2, r3;
+int i;
 
-r.L(0) = d->L(order & 3);
-r.L(1) = d->L((order >> 2) & 3);
-r.L(2) = s->L((order >> 4) & 3);
-r.L(3) = s->L((order >> 6) & 3);
-MOVE(*d, r);
+for (i = 0; i < 2 << SHIFT; i += 4) {
+SHUFFLE4(L, v, s, i);
+}
 }
 
 void glue(helper_shufpd, SUFFIX)(Reg *d, Reg *s, int order)
 {
-Reg r;
+Reg *v = d;
+uint64_t r0, r1;
+int i;
 
-r.Q(0) = d->Q(order & 1);
-r.Q(1) = s->Q((order >> 1) & 1);
-MOVE(*d, r);
+for (i = 0; i < 1 << SHIFT; i += 2) {
+r0 = v->Q(((order & 1) & 1) + i);
+r1 = s->Q(((order >> 1) & 1) + i);
+d->Q(i) = r0;
+d->Q(i + 1) = r1;
+order >>= 2;
+}
 }
 
 void glue(helper_pshufd, SUFFIX)(Reg *d, Reg *s, int order)
 {
-Reg r;
+uint32_t r0, r1, r2, r3;
+int i;
 
-r.L(0) = s->L(order & 3);
-r.L(1) = s->L((order >> 2) & 3);
-r.L(2) = s->L((order >> 4) & 3);
-r.L(3) = s->L((order >> 6) & 3);
-MOVE(*d, r);
+for (i = 0; i < 2 << SHIFT; i += 4) {
+SHUFFLE4(L, s, s, i);
+}
 }
 
 void glue(helper_pshuflw, SUFFIX)(Reg *d, Reg *s, int order)
 {
-Reg r;
+uint16_t r0, r1, r2, r3;
+int i, j;
 
-r.W(0) = s->W(order & 3);
-r.W(1) = s->W((order >> 2) & 3);
-r.W(2) = s->W((order >> 4) & 3);
-r.W(3) = s->W((order >> 6) & 3);
-r.Q(1) = s->Q(1);
-MOVE(*d, r);
+for (i = 0, j = 1; j < 1 << SHIFT; i += 8, j += 2) {
+SHUFFLE4(W, s, s, i);
+d->Q(j) = s->Q(j);
+}
 }
 
 void glue(helper_pshufhw, SUFFIX)(Reg *d, Reg *s, int order)
 {
-Reg r;
+uint16_t r0, r1, r2, r3;
+int i, j;
 
-r.Q(0) = s->Q(0);
-r.W(4) = s->W(4 + (order & 3));
-r.W(5) = s->W(4 + ((order >> 2) & 3));
-r.W(6) = s->W(4 + ((order >> 4) & 3));
-r.W(7) = s->W(4 + ((order >> 6) & 3));
-MOVE(*d, r);
+for (i = 4, j = 0; j < 1 << SHIFT; i += 8, j += 2) {
+d->Q(j) = s->Q(j);
+SHUFFLE4(W, s, s, i);
+}
 }
 #endif
 
@@ -1091,156 +1102,132 @@ uint32_t glue(helper_pmovmskb, SUFFIX)(CPUX86State 
*env, Reg *s)
 return val;
 }
 
-void glue(helper_packsswb, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
-{
-Reg r;
-
-r.B(0) = satsb((int16_t)d->W(0));
-r.B(1) = satsb((int16_t)d->W(1));
-r.B(2) = satsb((int16_t)d->W(2));
-r.B(3) = satsb((int16_t)d->W(3));
-#if SHIFT == 1
-r.B(4) = satsb((int16_t)d->W(4));
-r.B(5) = satsb((int16_t)d->W(5));
-r.B(6) = satsb((int16_t)d->W(6));
-r.B(7) = satsb((int16_t)d->W(7));
-#endif
-r.B((4 << SHIFT) + 0) = satsb((int16_t)s->W(0));
-r.B((4 << SHIFT) + 1) = satsb((int16_t)s->W(1));
-r.B((4 << SHIFT) + 2) = satsb((int16_t)s->W(2));
-r.B((4 << SHIFT) + 3) = satsb((int16_t)s->W(3));
-#if SHIFT == 1
-r.B(12) = satsb((int16_t)s->W(4));
-r.B(13) = satsb((int16_t)s->W(5));
-r.B(14) = satsb((int16_t)s->W(6));
-r.B(15) = satsb((int16_t)s->W(7));
-#endif
-MOVE(*d, r);
+#define PACK_HELPER_B(name, F) \
+void glue(helper_pack ## name, SUFFIX)(CPUX86State *env,  \
+Reg *d, Reg *s)

[PULL 18/39] target/i386: Add ZMM_OFFSET macro

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

Add a convenience macro to get the address of an xmm_regs element within
CPUX86State.

This was originally going to be the basis of an implementation that broke
operations into 128 bit chunks. I scrapped that idea, so this is now a purely
cosmetic change. But I think a worthwhile one - it reduces the number of
function calls that need to be split over multiple lines.

No functional changes.

Signed-off-by: Paul Brook 
Reviewed-by: Richard Henderson 
Message-Id: <20220424220204.2493824-9-p...@nowt.org>
Signed-off-by: Paolo Bonzini 
---
 target/i386/tcg/translate.c | 60 +
 1 file changed, 27 insertions(+), 33 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 25a2539d59..cba862746b 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -2777,6 +2777,8 @@ static inline void gen_op_movq_env_0(DisasContext *s, int 
d_offset)
 tcg_gen_st_i64(s->tmp1_i64, cpu_env, d_offset);
 }
 
+#define ZMM_OFFSET(reg) offsetof(CPUX86State, xmm_regs[reg])
+
 typedef void (*SSEFunc_i_ep)(TCGv_i32 val, TCGv_ptr env, TCGv_ptr reg);
 typedef void (*SSEFunc_l_ep)(TCGv_i64 val, TCGv_ptr env, TCGv_ptr reg);
 typedef void (*SSEFunc_0_epi)(TCGv_ptr env, TCGv_ptr reg, TCGv_i32 val);
@@ -3198,13 +3200,13 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 if (mod == 3)
 goto illegal_op;
 gen_lea_modrm(env, s, modrm);
-gen_sto_env_A0(s, offsetof(CPUX86State, xmm_regs[reg]));
+gen_sto_env_A0(s, ZMM_OFFSET(reg));
 break;
 case 0x3f0: /* lddqu */
 if (mod == 3)
 goto illegal_op;
 gen_lea_modrm(env, s, modrm);
-gen_ldo_env_A0(s, offsetof(CPUX86State, xmm_regs[reg]));
+gen_ldo_env_A0(s, ZMM_OFFSET(reg));
 break;
 case 0x22b: /* movntss */
 case 0x32b: /* movntsd */
@@ -3240,15 +3242,13 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 #ifdef TARGET_X86_64
 if (s->dflag == MO_64) {
 gen_ldst_modrm(env, s, modrm, MO_64, OR_TMP0, 0);
-tcg_gen_addi_ptr(s->ptr0, cpu_env,
- offsetof(CPUX86State,xmm_regs[reg]));
+tcg_gen_addi_ptr(s->ptr0, cpu_env, ZMM_OFFSET(reg));
 gen_helper_movq_mm_T0_xmm(s->ptr0, s->T0);
 } else
 #endif
 {
 gen_ldst_modrm(env, s, modrm, MO_32, OR_TMP0, 0);
-tcg_gen_addi_ptr(s->ptr0, cpu_env,
- offsetof(CPUX86State,xmm_regs[reg]));
+tcg_gen_addi_ptr(s->ptr0, cpu_env, ZMM_OFFSET(reg));
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 gen_helper_movl_mm_T0_xmm(s->ptr0, s->tmp2_i32);
 }
@@ -3273,11 +3273,10 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 case 0x26f: /* movdqu xmm, ea */
 if (mod != 3) {
 gen_lea_modrm(env, s, modrm);
-gen_ldo_env_A0(s, offsetof(CPUX86State, xmm_regs[reg]));
+gen_ldo_env_A0(s, ZMM_OFFSET(reg));
 } else {
 rm = (modrm & 7) | REX_B(s);
-gen_op_movo(s, offsetof(CPUX86State, xmm_regs[reg]),
-offsetof(CPUX86State,xmm_regs[rm]));
+gen_op_movo(s, ZMM_OFFSET(reg), ZMM_OFFSET(rm));
 }
 break;
 case 0x210: /* movss xmm, ea */
@@ -,7 +3332,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 case 0x212: /* movsldup */
 if (mod != 3) {
 gen_lea_modrm(env, s, modrm);
-gen_ldo_env_A0(s, offsetof(CPUX86State, xmm_regs[reg]));
+gen_ldo_env_A0(s, ZMM_OFFSET(reg));
 } else {
 rm = (modrm & 7) | REX_B(s);
 gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(0)),
@@ -3375,7 +3374,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 case 0x216: /* movshdup */
 if (mod != 3) {
 gen_lea_modrm(env, s, modrm);
-gen_ldo_env_A0(s, offsetof(CPUX86State, xmm_regs[reg]));
+gen_ldo_env_A0(s, ZMM_OFFSET(reg));
 } else {
 rm = (modrm & 7) | REX_B(s);
 gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(1)),
@@ -3397,8 +3396,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 goto illegal_op;
 field_length = x86_ldub_code(env, s) & 0x3F;
 bit_index = x86_ldub_code(env, s) & 0x3F;
-tcg_gen_addi_ptr(s->ptr0, cpu_env,
-offsetof(CPUX86State,xmm_regs[reg]));
+tcg_gen_addi_ptr(s->ptr0, cpu_env, ZMM_OFFSET(reg));
 if (b1 == 1)
 

[PULL 26/39] target/i386: Add CHECK_NO_VEX

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

Reject invalid VEX encodings on MMX instructions.

Signed-off-by: Paul Brook 
Reviewed-by: Richard Henderson 
Message-Id: <20220424220204.2493824-7-p...@nowt.org>
Signed-off-by: Paolo Bonzini 
---
 target/i386/tcg/translate.c | 26 ++
 1 file changed, 26 insertions(+)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index c6a9a5b1d4..99c84473f4 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -3186,6 +3186,12 @@ static const struct SSEOpHelper_table7 
sse_op_table7[256] = {
 #undef BLENDV_OP
 #undef SPECIAL_OP
 
+/* VEX prefix not allowed */
+#define CHECK_NO_VEX(s) do { \
+if (s->prefix & PREFIX_VEX) \
+goto illegal_op; \
+} while (0)
+
 static void gen_sse(CPUX86State *env, DisasContext *s, int b,
 target_ulong pc_start)
 {
@@ -3272,6 +3278,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 b |= (b1 << 8);
 switch(b) {
 case 0x0e7: /* movntq */
+CHECK_NO_VEX(s);
 if (mod == 3) {
 goto illegal_op;
 }
@@ -3307,6 +3314,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 }
 break;
 case 0x6e: /* movd mm, ea */
+CHECK_NO_VEX(s);
 #ifdef TARGET_X86_64
 if (s->dflag == MO_64) {
 gen_ldst_modrm(env, s, modrm, MO_64, OR_TMP0, 0);
@@ -3338,6 +3346,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 }
 break;
 case 0x6f: /* movq mm, ea */
+CHECK_NO_VEX(s);
 if (mod != 3) {
 gen_lea_modrm(env, s, modrm);
 gen_ldq_env_A0(s, offsetof(CPUX86State, fpregs[reg].mmx));
@@ -3473,6 +3482,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 break;
 case 0x178:
 case 0x378:
+CHECK_NO_VEX(s);
 {
 int bit_index, field_length;
 
@@ -3492,6 +3502,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 }
 break;
 case 0x7e: /* movd ea, mm */
+CHECK_NO_VEX(s);
 #ifdef TARGET_X86_64
 if (s->dflag == MO_64) {
 tcg_gen_ld_i64(s->T0, cpu_env,
@@ -3532,6 +3543,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 gen_op_movq_env_0(s, offsetof(CPUX86State, 
xmm_regs[reg].ZMM_Q(1)));
 break;
 case 0x7f: /* movq ea, mm */
+CHECK_NO_VEX(s);
 if (mod != 3) {
 gen_lea_modrm(env, s, modrm);
 gen_stq_env_A0(s, offsetof(CPUX86State, fpregs[reg].mmx));
@@ -3614,6 +3626,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 offsetof(CPUX86State, xmm_t0.ZMM_L(1)));
 op1_offset = offsetof(CPUX86State,xmm_t0);
 } else {
+CHECK_NO_VEX(s);
 tcg_gen_movi_tl(s->T0, val);
 tcg_gen_st32_tl(s->T0, cpu_env,
 offsetof(CPUX86State, mmx_t0.MMX_L(0)));
@@ -3653,6 +3666,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 break;
 case 0x02a: /* cvtpi2ps */
 case 0x12a: /* cvtpi2pd */
+CHECK_NO_VEX(s);
 gen_helper_enter_mmx(cpu_env);
 if (mod != 3) {
 gen_lea_modrm(env, s, modrm);
@@ -3698,6 +3712,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 case 0x12c: /* cvttpd2pi */
 case 0x02d: /* cvtps2pi */
 case 0x12d: /* cvtpd2pi */
+CHECK_NO_VEX(s);
 gen_helper_enter_mmx(cpu_env);
 if (mod != 3) {
 gen_lea_modrm(env, s, modrm);
@@ -3771,6 +3786,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 tcg_gen_st16_tl(s->T0, cpu_env,
 
offsetof(CPUX86State,xmm_regs[reg].ZMM_W(val)));
 } else {
+CHECK_NO_VEX(s);
 val &= 3;
 tcg_gen_st16_tl(s->T0, cpu_env,
 
offsetof(CPUX86State,fpregs[reg].mmx.MMX_W(val)));
@@ -3810,6 +3826,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 }
 break;
 case 0x2d6: /* movq2dq */
+CHECK_NO_VEX(s);
 gen_helper_enter_mmx(cpu_env);
 rm = (modrm & 7);
 gen_op_movq(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(0)),
@@ -3817,6 +3834,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 gen_op_movq_env_0(s, offsetof(CPUX86State, 
xmm_regs[reg].ZMM_Q(1)));
 break;
 case 0x3d6: /* movdq2q */
+CHECK_NO_VEX(s);
 gen_helper_enter_mmx(cpu_env);
 rm = (modrm & 7) | REX_B(s);
 gen_op_movq(s, 

[PULL 34/39] target/i386: Dot product AVX helper prep

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

Make the dpps and dppd helpers AVX-ready

I can't see any obvious reason why dppd shouldn't work on 256 bit ymm
registers, but both AMD and Intel agree that it's xmm only.

Signed-off-by: Paul Brook 
Message-Id: <20220424220204.2493824-17-p...@nowt.org>
Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 target/i386/ops_sse.h | 80 ---
 1 file changed, 45 insertions(+), 35 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index 7463ff1599..c9737e16b9 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -1903,55 +1903,64 @@ SSE_HELPER_I(helper_blendps, L, 4, FBLENDP)
 SSE_HELPER_I(helper_blendpd, Q, 2, FBLENDP)
 SSE_HELPER_I(helper_pblendw, W, 8, FBLENDP)
 
-void glue(helper_dpps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mask)
+void glue(helper_dpps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
+   uint32_t mask)
 {
+Reg *v = d;
 float32 prod1, prod2, temp2, temp3, temp4;
+int i;
 
-/*
- * We must evaluate (A+B)+(C+D), not ((A+B)+C)+D
- * to correctly round the intermediate results
- */
-if (mask & (1 << 4)) {
-prod1 = float32_mul(d->ZMM_S(0), s->ZMM_S(0), >sse_status);
-} else {
-prod1 = float32_zero;
-}
-if (mask & (1 << 5)) {
-prod2 = float32_mul(d->ZMM_S(1), s->ZMM_S(1), >sse_status);
-} else {
-prod2 = float32_zero;
-}
-temp2 = float32_add(prod1, prod2, >sse_status);
-if (mask & (1 << 6)) {
-prod1 = float32_mul(d->ZMM_S(2), s->ZMM_S(2), >sse_status);
-} else {
-prod1 = float32_zero;
-}
-if (mask & (1 << 7)) {
-prod2 = float32_mul(d->ZMM_S(3), s->ZMM_S(3), >sse_status);
-} else {
-prod2 = float32_zero;
-}
-temp3 = float32_add(prod1, prod2, >sse_status);
-temp4 = float32_add(temp2, temp3, >sse_status);
+for (i = 0; i < 2 << SHIFT; i += 4) {
+/*
+ * We must evaluate (A+B)+(C+D), not ((A+B)+C)+D
+ * to correctly round the intermediate results
+ */
+if (mask & (1 << 4)) {
+prod1 = float32_mul(v->ZMM_S(i), s->ZMM_S(i), >sse_status);
+} else {
+prod1 = float32_zero;
+}
+if (mask & (1 << 5)) {
+prod2 = float32_mul(v->ZMM_S(i+1), s->ZMM_S(i+1), 
>sse_status);
+} else {
+prod2 = float32_zero;
+}
+temp2 = float32_add(prod1, prod2, >sse_status);
+if (mask & (1 << 6)) {
+prod1 = float32_mul(v->ZMM_S(i+2), s->ZMM_S(i+2), 
>sse_status);
+} else {
+prod1 = float32_zero;
+}
+if (mask & (1 << 7)) {
+prod2 = float32_mul(v->ZMM_S(i+3), s->ZMM_S(i+3), 
>sse_status);
+} else {
+prod2 = float32_zero;
+}
+temp3 = float32_add(prod1, prod2, >sse_status);
+temp4 = float32_add(temp2, temp3, >sse_status);
 
-d->ZMM_S(0) = (mask & (1 << 0)) ? temp4 : float32_zero;
-d->ZMM_S(1) = (mask & (1 << 1)) ? temp4 : float32_zero;
-d->ZMM_S(2) = (mask & (1 << 2)) ? temp4 : float32_zero;
-d->ZMM_S(3) = (mask & (1 << 3)) ? temp4 : float32_zero;
+d->ZMM_S(i) = (mask & (1 << 0)) ? temp4 : float32_zero;
+d->ZMM_S(i+1) = (mask & (1 << 1)) ? temp4 : float32_zero;
+d->ZMM_S(i+2) = (mask & (1 << 2)) ? temp4 : float32_zero;
+d->ZMM_S(i+3) = (mask & (1 << 3)) ? temp4 : float32_zero;
+}
 }
 
-void glue(helper_dppd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mask)
+#if SHIFT == 1
+/* Oddly, there is no ymm version of dppd */
+void glue(helper_dppd, SUFFIX)(CPUX86State *env,
+   Reg *d, Reg *s, uint32_t mask)
 {
+Reg *v = d;
 float64 prod1, prod2, temp2;
 
 if (mask & (1 << 4)) {
-prod1 = float64_mul(d->ZMM_D(0), s->ZMM_D(0), >sse_status);
+prod1 = float64_mul(v->ZMM_D(0), s->ZMM_D(0), >sse_status);
 } else {
 prod1 = float64_zero;
 }
 if (mask & (1 << 5)) {
-prod2 = float64_mul(d->ZMM_D(1), s->ZMM_D(1), >sse_status);
+prod2 = float64_mul(v->ZMM_D(1), s->ZMM_D(1), >sse_status);
 } else {
 prod2 = float64_zero;
 }
@@ -1959,6 +1968,7 @@ void glue(helper_dppd, SUFFIX)(CPUX86State *env, Reg *d, 
Reg *s, uint32_t mask)
 d->ZMM_D(0) = (mask & (1 << 0)) ? temp2 : float64_zero;
 d->ZMM_D(1) = (mask & (1 << 1)) ? temp2 : float64_zero;
 }
+#endif
 
 void glue(helper_mpsadbw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
   uint32_t offset)
-- 
2.37.2





[PULL 24/39] target/i386: Add size suffix to vector FP helpers

2022-09-01 Thread Paolo Bonzini
For AVX we're going to need both 128 bit (xmm) and 256 bit (ymm) variants of
floating point helpers. Add the register type suffix to the existing
*PS and *PD helpers (SS and SD variants are only valid on 128 bit vectors)

No functional changes.

Signed-off-by: Paul Brook 
Message-Id: <20220424220204.2493824-15-p...@nowt.org>
Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 target/i386/ops_sse.h| 48 ++--
 target/i386/ops_sse_header.h | 48 ++--
 target/i386/tcg/translate.c  | 37 +--
 3 files changed, 67 insertions(+), 66 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index b12b271fcd..f603981ab8 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -537,7 +537,7 @@ void glue(helper_pshufw, SUFFIX)(Reg *d, Reg *s, int order)
 MOVE(*d, r);
 }
 #else
-void helper_shufps(Reg *d, Reg *s, int order)
+void glue(helper_shufps, SUFFIX)(Reg *d, Reg *s, int order)
 {
 Reg r;
 
@@ -548,7 +548,7 @@ void helper_shufps(Reg *d, Reg *s, int order)
 MOVE(*d, r);
 }
 
-void helper_shufpd(Reg *d, Reg *s, int order)
+void glue(helper_shufpd, SUFFIX)(Reg *d, Reg *s, int order)
 {
 Reg r;
 
@@ -598,7 +598,7 @@ void glue(helper_pshufhw, SUFFIX)(Reg *d, Reg *s, int order)
 /* XXX: not accurate */
 
 #define SSE_HELPER_S(name, F)   \
-void helper_ ## name ## ps(CPUX86State *env, Reg *d, Reg *s)\
+void glue(helper_ ## name ## ps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)\
 {   \
 d->ZMM_S(0) = F(32, d->ZMM_S(0), s->ZMM_S(0));  \
 d->ZMM_S(1) = F(32, d->ZMM_S(1), s->ZMM_S(1));  \
@@ -611,7 +611,7 @@ void glue(helper_pshufhw, SUFFIX)(Reg *d, Reg *s, int order)
 d->ZMM_S(0) = F(32, d->ZMM_S(0), s->ZMM_S(0));  \
 }   \
 \
-void helper_ ## name ## pd(CPUX86State *env, Reg *d, Reg *s)\
+void glue(helper_ ## name ## pd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)\
 {   \
 d->ZMM_D(0) = F(64, d->ZMM_D(0), s->ZMM_D(0));  \
 d->ZMM_D(1) = F(64, d->ZMM_D(1), s->ZMM_D(1));  \
@@ -647,7 +647,7 @@ SSE_HELPER_S(sqrt, FPU_SQRT)
 
 
 /* float to float conversions */
-void helper_cvtps2pd(CPUX86State *env, Reg *d, Reg *s)
+void glue(helper_cvtps2pd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
 {
 float32 s0, s1;
 
@@ -657,7 +657,7 @@ void helper_cvtps2pd(CPUX86State *env, Reg *d, Reg *s)
 d->ZMM_D(1) = float32_to_float64(s1, >sse_status);
 }
 
-void helper_cvtpd2ps(CPUX86State *env, Reg *d, Reg *s)
+void glue(helper_cvtpd2ps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
 {
 d->ZMM_S(0) = float64_to_float32(s->ZMM_D(0), >sse_status);
 d->ZMM_S(1) = float64_to_float32(s->ZMM_D(1), >sse_status);
@@ -675,7 +675,7 @@ void helper_cvtsd2ss(CPUX86State *env, Reg *d, Reg *s)
 }
 
 /* integer to float */
-void helper_cvtdq2ps(CPUX86State *env, Reg *d, Reg *s)
+void glue(helper_cvtdq2ps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
 {
 d->ZMM_S(0) = int32_to_float32(s->ZMM_L(0), >sse_status);
 d->ZMM_S(1) = int32_to_float32(s->ZMM_L(1), >sse_status);
@@ -683,7 +683,7 @@ void helper_cvtdq2ps(CPUX86State *env, Reg *d, Reg *s)
 d->ZMM_S(3) = int32_to_float32(s->ZMM_L(3), >sse_status);
 }
 
-void helper_cvtdq2pd(CPUX86State *env, Reg *d, Reg *s)
+void glue(helper_cvtdq2pd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
 {
 int32_t l0, l1;
 
@@ -760,7 +760,7 @@ WRAP_FLOATCONV(int64_t, float32_to_int64_round_to_zero, 
float32, INT64_MIN)
 WRAP_FLOATCONV(int64_t, float64_to_int64, float64, INT64_MIN)
 WRAP_FLOATCONV(int64_t, float64_to_int64_round_to_zero, float64, INT64_MIN)
 
-void helper_cvtps2dq(CPUX86State *env, ZMMReg *d, ZMMReg *s)
+void glue(helper_cvtps2dq, SUFFIX)(CPUX86State *env, ZMMReg *d, ZMMReg *s)
 {
 d->ZMM_L(0) = x86_float32_to_int32(s->ZMM_S(0), >sse_status);
 d->ZMM_L(1) = x86_float32_to_int32(s->ZMM_S(1), >sse_status);
@@ -768,7 +768,7 @@ void helper_cvtps2dq(CPUX86State *env, ZMMReg *d, ZMMReg *s)
 d->ZMM_L(3) = x86_float32_to_int32(s->ZMM_S(3), >sse_status);
 }
 
-void helper_cvtpd2dq(CPUX86State *env, ZMMReg *d, ZMMReg *s)
+void glue(helper_cvtpd2dq, SUFFIX)(CPUX86State *env, ZMMReg *d, ZMMReg *s)
 {
 d->ZMM_L(0) = x86_float64_to_int32(s->ZMM_D(0), >sse_status);
 d->ZMM_L(1) = x86_float64_to_int32(s->ZMM_D(1), >sse_status);
@@ -810,7 +810,7 @@ int64_t helper_cvtsd2sq(CPUX86State *env, ZMMReg *s)
 #endif
 
 /* float to integer truncated */
-void helper_cvttps2dq(CPUX86State *env, ZMMReg *d, ZMMReg *s)
+void glue(helper_cvttps2dq, SUFFIX)(CPUX86State *env, ZMMReg *d, ZMMReg *s)
 {
 

[PULL 32/39] target/i386: Floating point arithmetic helper AVX prep

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

Prepare the "easy" floating point vector helpers for AVX

No functional changes to existing helpers.

Signed-off-by: Paul Brook 
Message-Id: <20220424220204.2493824-16-p...@nowt.org>
Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 target/i386/ops_sse.h | 138 --
 1 file changed, 92 insertions(+), 46 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index bb50ca6f8d..86ca74492e 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -553,40 +553,58 @@ void glue(helper_pshufhw, SUFFIX)(Reg *d, Reg *s, int 
order)
 }
 #endif
 
-#if SHIFT == 1
+#if SHIFT >= 1
 /* FPU ops */
 /* XXX: not accurate */
 
-#define SSE_HELPER_S(name, F)   \
-void glue(helper_ ## name ## ps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)\
+#define SSE_HELPER_P(name, F)   \
+void glue(helper_ ## name ## ps, SUFFIX)(CPUX86State *env,  \
+Reg *d, Reg *s) \
 {   \
-d->ZMM_S(0) = F(32, d->ZMM_S(0), s->ZMM_S(0));  \
-d->ZMM_S(1) = F(32, d->ZMM_S(1), s->ZMM_S(1));  \
-d->ZMM_S(2) = F(32, d->ZMM_S(2), s->ZMM_S(2));  \
-d->ZMM_S(3) = F(32, d->ZMM_S(3), s->ZMM_S(3));  \
+Reg *v = d; \
+int i;  \
+for (i = 0; i < 2 << SHIFT; i++) {  \
+d->ZMM_S(i) = F(32, v->ZMM_S(i), s->ZMM_S(i));  \
+}   \
 }   \
 \
-void helper_ ## name ## ss(CPUX86State *env, Reg *d, Reg *s)\
+void glue(helper_ ## name ## pd, SUFFIX)(CPUX86State *env,  \
+Reg *d, Reg *s) \
 {   \
-d->ZMM_S(0) = F(32, d->ZMM_S(0), s->ZMM_S(0));  \
-}   \
-\
-void glue(helper_ ## name ## pd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)\
-{   \
-d->ZMM_D(0) = F(64, d->ZMM_D(0), s->ZMM_D(0));  \
-d->ZMM_D(1) = F(64, d->ZMM_D(1), s->ZMM_D(1));  \
-}   \
-\
-void helper_ ## name ## sd(CPUX86State *env, Reg *d, Reg *s)\
-{   \
-d->ZMM_D(0) = F(64, d->ZMM_D(0), s->ZMM_D(0));  \
+Reg *v = d; \
+int i;  \
+for (i = 0; i < 1 << SHIFT; i++) {  \
+d->ZMM_D(i) = F(64, v->ZMM_D(i), s->ZMM_D(i));  \
+}   \
 }
 
+#if SHIFT == 1
+
+#define SSE_HELPER_S(name, F)   \
+SSE_HELPER_P(name, F)   \
+\
+void helper_ ## name ## ss(CPUX86State *env, Reg *d, Reg *s)\
+{   \
+Reg *v = d; \
+d->ZMM_S(0) = F(32, v->ZMM_S(0), s->ZMM_S(0));  \
+}   \
+\
+void helper_ ## name ## sd(CPUX86State *env, Reg *d, Reg *s)\
+{   \
+Reg *v = d; \
+d->ZMM_D(0) = F(64, v->ZMM_D(0), s->ZMM_D(0));  \
+}
+
+#else
+
+#define SSE_HELPER_S(name, F) SSE_HELPER_P(name, F)
+
+#endif
+
 #define FPU_ADD(size, a, b) float ## size ## _add(a, b, >sse_status)
 #define FPU_SUB(size, a, b) float ## size ## _sub(a, b, >sse_status)
 #define FPU_MUL(size, a, b) float ## size ## _mul(a, b, >sse_status)
 #define FPU_DIV(size, a, b) float ## size ## _div(a, b, >sse_status)
-#define FPU_SQRT(size, a, b) float ## size ## _sqrt(b, >sse_status)
 
 /* Note 

[PULL 19/39] target/i386: Rework sse_op_table1

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

Add a flags field to each row in sse_op_table1.

Initially this is only used as a replacement for the magic
SSE_SPECIAL and SSE_DUMMY pointers, the other flags are mostly
relevant for the AVX implementation but can be applied to SSE as well.

Signed-off-by: Paul Brook 
Message-Id: <20220424220204.2493824-5-p...@nowt.org>
Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 target/i386/tcg/translate.c | 311 +---
 1 file changed, 182 insertions(+), 129 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index cba862746b..7332bbcf44 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -2790,146 +2790,193 @@ typedef void (*SSEFunc_0_ppi)(TCGv_ptr reg_a, 
TCGv_ptr reg_b, TCGv_i32 val);
 typedef void (*SSEFunc_0_eppt)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b,
TCGv val);
 
-#define SSE_SPECIAL ((void *)1)
-#define SSE_DUMMY ((void *)2)
+#define SSE_OPF_CMP   (1 << 1) /* does not write for first operand */
+#define SSE_OPF_SPECIAL   (1 << 3) /* magic */
+#define SSE_OPF_3DNOW (1 << 4) /* 3DNow! instruction */
+#define SSE_OPF_MMX   (1 << 5) /* MMX/integer/AVX2 instruction */
+#define SSE_OPF_SCALAR(1 << 6) /* Has SSE scalar variants */
+#define SSE_OPF_SHUF  (1 << 9) /* pshufx/shufpx */
 
-#define MMX_OP2(x) { gen_helper_ ## x ## _mmx, gen_helper_ ## x ## _xmm }
-#define SSE_FOP(x) { gen_helper_ ## x ## ps, gen_helper_ ## x ## pd, \
- gen_helper_ ## x ## ss, gen_helper_ ## x ## sd, }
+#define OP(op, flags, a, b, c, d)   \
+{flags, {a, b, c, d} }
 
-static const SSEFunc_0_epp sse_op_table1[256][4] = {
+#define MMX_OP(x) OP(op1, SSE_OPF_MMX, \
+gen_helper_ ## x ## _mmx, gen_helper_ ## x ## _xmm, NULL, NULL)
+
+#define SSE_FOP(name) OP(op1, SSE_OPF_SCALAR, \
+gen_helper_##name##ps, gen_helper_##name##pd, \
+gen_helper_##name##ss, gen_helper_##name##sd)
+#define SSE_OP(sname, dname, op, flags) OP(op, flags, \
+gen_helper_##sname##_xmm, gen_helper_##dname##_xmm, NULL, NULL)
+
+struct SSEOpHelper_table1 {
+int flags;
+SSEFunc_0_epp op[4];
+};
+
+#define SSE_3DNOW { SSE_OPF_3DNOW }
+#define SSE_SPECIAL { SSE_OPF_SPECIAL }
+
+static const struct SSEOpHelper_table1 sse_op_table1[256] = {
 /* 3DNow! extensions */
-[0x0e] = { SSE_DUMMY }, /* femms */
-[0x0f] = { SSE_DUMMY }, /* pf... */
+[0x0e] = SSE_SPECIAL, /* femms */
+[0x0f] = SSE_3DNOW, /* pf... (sse_op_table5) */
 /* pure SSE operations */
-[0x10] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* 
movups, movupd, movss, movsd */
-[0x11] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* 
movups, movupd, movss, movsd */
-[0x12] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* 
movlps, movlpd, movsldup, movddup */
-[0x13] = { SSE_SPECIAL, SSE_SPECIAL },  /* movlps, movlpd */
-[0x14] = { gen_helper_punpckldq_xmm, gen_helper_punpcklqdq_xmm },
-[0x15] = { gen_helper_punpckhdq_xmm, gen_helper_punpckhqdq_xmm },
-[0x16] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL },  /* movhps, movhpd, 
movshdup */
-[0x17] = { SSE_SPECIAL, SSE_SPECIAL },  /* movhps, movhpd */
+[0x10] = SSE_SPECIAL, /* movups, movupd, movss, movsd */
+[0x11] = SSE_SPECIAL, /* movups, movupd, movss, movsd */
+[0x12] = SSE_SPECIAL, /* movlps, movlpd, movsldup, movddup */
+[0x13] = SSE_SPECIAL, /* movlps, movlpd */
+[0x14] = SSE_OP(punpckldq, punpcklqdq, op1, 0), /* unpcklps, unpcklpd */
+[0x15] = SSE_OP(punpckhdq, punpckhqdq, op1, 0), /* unpckhps, unpckhpd */
+[0x16] = SSE_SPECIAL, /* movhps, movhpd, movshdup */
+[0x17] = SSE_SPECIAL, /* movhps, movhpd */
 
-[0x28] = { SSE_SPECIAL, SSE_SPECIAL },  /* movaps, movapd */
-[0x29] = { SSE_SPECIAL, SSE_SPECIAL },  /* movaps, movapd */
-[0x2a] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* 
cvtpi2ps, cvtpi2pd, cvtsi2ss, cvtsi2sd */
-[0x2b] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* 
movntps, movntpd, movntss, movntsd */
-[0x2c] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* 
cvttps2pi, cvttpd2pi, cvttsd2si, cvttss2si */
-[0x2d] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* 
cvtps2pi, cvtpd2pi, cvtsd2si, cvtss2si */
-[0x2e] = { gen_helper_ucomiss, gen_helper_ucomisd },
-[0x2f] = { gen_helper_comiss, gen_helper_comisd },
-[0x50] = { SSE_SPECIAL, SSE_SPECIAL }, /* movmskps, movmskpd */
-[0x51] = SSE_FOP(sqrt),
-[0x52] = { gen_helper_rsqrtps, NULL, gen_helper_rsqrtss, NULL },
-[0x53] = { gen_helper_rcpps, NULL, gen_helper_rcpss, NULL },
-[0x54] = { gen_helper_pand_xmm, gen_helper_pand_xmm }, /* andps, andpd */
-[0x55] = { gen_helper_pandn_xmm, gen_helper_pandn_xmm }, /* andnps, andnpd 
*/
-[0x56] = { gen_helper_por_xmm, gen_helper_por_xmm }, /* orps, orpd */
-[0x57] = { gen_helper_pxor_xmm, 

[PULL 23/39] target/i386: isolate MMX code more

2022-09-01 Thread Paolo Bonzini
Extracted from a patch by Paul Brook .

Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 target/i386/tcg/translate.c | 52 +++--
 1 file changed, 33 insertions(+), 19 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 849c40b685..097c895ef1 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -3888,6 +3888,12 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 gen_ldo_env_A0(s, op2_offset);
 }
 }
+if (!op6->op[b1]) {
+goto illegal_op;
+}
+tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
+tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
+op6->op[b1](cpu_env, s->ptr0, s->ptr1);
 } else {
 if ((op6->flags & SSE_OPF_MMX) == 0) {
 goto unknown_op;
@@ -3900,14 +3906,10 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 gen_lea_modrm(env, s, modrm);
 gen_ldq_env_A0(s, op2_offset);
 }
+tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
+tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
+op6->op[0](cpu_env, s->ptr0, s->ptr1);
 }
-if (!op6->op[b1]) {
-goto illegal_op;
-}
-
-tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
-tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
-op6->op[b1](cpu_env, s->ptr0, s->ptr1);
 
 if (op6->flags & SSE_OPF_CMP) {
 set_cc_op(s, CC_OP_EFLAGS);
@@ -4427,16 +4429,8 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 return;
 }
 
-if (b1) {
-op1_offset = ZMM_OFFSET(reg);
-if (mod == 3) {
-op2_offset = ZMM_OFFSET(rm | REX_B(s));
-} else {
-op2_offset = offsetof(CPUX86State,xmm_t0);
-gen_lea_modrm(env, s, modrm);
-gen_ldo_env_A0(s, op2_offset);
-}
-} else {
+if (b1 == 0) {
+/* MMX */
 if ((op7->flags & SSE_OPF_MMX) == 0) {
 goto illegal_op;
 }
@@ -4448,9 +4442,29 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 gen_lea_modrm(env, s, modrm);
 gen_ldq_env_A0(s, op2_offset);
 }
-}
-val = x86_ldub_code(env, s);
+val = x86_ldub_code(env, s);
+tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
+tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
 
+/* We only actually have one MMX instuction (palignr) */
+assert(b == 0x0f);
+
+op7->op[0](cpu_env, s->ptr0, s->ptr1,
+   tcg_const_i32(val));
+break;
+}
+
+/* SSE */
+op1_offset = ZMM_OFFSET(reg);
+if (mod == 3) {
+op2_offset = ZMM_OFFSET(rm | REX_B(s));
+} else {
+op2_offset = offsetof(CPUX86State, xmm_t0);
+gen_lea_modrm(env, s, modrm);
+gen_ldo_env_A0(s, op2_offset);
+}
+
+val = x86_ldub_code(env, s);
 if ((b & 0xfc) == 0x60) { /* pcmpXstrX */
 set_cc_op(s, CC_OP_EFLAGS);
 
-- 
2.37.2





[PULL 21/39] target/i386: Move 3DNOW decoder

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

Handle 3DNOW instructions early to avoid complicating the MMX/SSE logic.

Signed-off-by: Paul Brook 
Message-Id: <20220424220204.2493824-25-p...@nowt.org>
Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 target/i386/tcg/translate.c | 30 +-
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index b7321b7588..c76f6dba11 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -3216,6 +3216,11 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 is_xmm = 1;
 }
 }
+if (sse_op_flags & SSE_OPF_3DNOW) {
+if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW)) {
+goto illegal_op;
+}
+}
 /* simple MMX/SSE operation */
 if (s->flags & HF_TS_MASK) {
 gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
@@ -4567,21 +4572,20 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 rm = (modrm & 7);
 op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
 }
+if (sse_op_flags & SSE_OPF_3DNOW) {
+/* 3DNow! data insns */
+val = x86_ldub_code(env, s);
+SSEFunc_0_epp op_3dnow = sse_op_table5[val];
+if (!op_3dnow) {
+goto unknown_op;
+}
+tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
+tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
+op_3dnow(cpu_env, s->ptr0, s->ptr1);
+return;
+}
 }
 switch(b) {
-case 0x0f: /* 3DNow! data insns */
-val = x86_ldub_code(env, s);
-sse_fn_epp = sse_op_table5[val];
-if (!sse_fn_epp) {
-goto unknown_op;
-}
-if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW)) {
-goto illegal_op;
-}
-tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
-tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
-sse_fn_epp(cpu_env, s->ptr0, s->ptr1);
-break;
 case 0x70: /* pshufx insn */
 case 0xc6: /* pshufx insn */
 val = x86_ldub_code(env, s);
-- 
2.37.2





[PULL 16/39] target/i386: do not use MOVL to move data between SSE registers

2022-09-01 Thread Paolo Bonzini
Write down explicitly the load/store sequence.

Extracted from a patch by Paul Brook .

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index b7972f0ff5..3237c1d8f9 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -3295,8 +3295,10 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 offsetof(CPUX86State, xmm_regs[reg].ZMM_L(3)));
 } else {
 rm = (modrm & 7) | REX_B(s);
-gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(0)),
-offsetof(CPUX86State,xmm_regs[rm].ZMM_L(0)));
+tcg_gen_ld_i32(s->tmp2_i32, cpu_env,
+   offsetof(CPUX86State, xmm_regs[rm].ZMM_L(0)));
+tcg_gen_st_i32(s->tmp2_i32, cpu_env,
+   offsetof(CPUX86State, xmm_regs[reg].ZMM_L(0)));
 }
 break;
 case 0x310: /* movsd xmm, ea */
-- 
2.37.2





[PULL 22/39] target/i386: check SSE table flags instead of hardcoding opcodes

2022-09-01 Thread Paolo Bonzini
Put more flags to work to avoid hardcoding lists of opcodes.  The op7 case
for SSE_OPF_CMP is included for homogeneity and because AVX needs it, but
it is never used by SSE or MMX.

Extracted from a patch by Paul Brook .

Signed-off-by: Paolo Bonzini 
---
 target/i386/tcg/translate.c | 75 +++--
 1 file changed, 31 insertions(+), 44 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index c76f6dba11..849c40b685 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -3909,7 +3909,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
 op6->op[b1](cpu_env, s->ptr0, s->ptr1);
 
-if (b == 0x17) {
+if (op6->flags & SSE_OPF_CMP) {
 set_cc_op(s, CC_OP_EFLAGS);
 }
 break;
@@ -4463,6 +4463,9 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
 tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
 op7->op[b1](cpu_env, s->ptr0, s->ptr1, tcg_const_i32(val));
+if (op7->flags & SSE_OPF_CMP) {
+set_cc_op(s, CC_OP_EFLAGS);
+}
 break;
 
 case 0x33a:
@@ -4518,28 +4521,24 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 int sz = 4;
 
 gen_lea_modrm(env, s, modrm);
-op2_offset = offsetof(CPUX86State,xmm_t0);
+op2_offset = offsetof(CPUX86State, xmm_t0);
 
-switch (b) {
-case 0x50 ... 0x5a:
-case 0x5c ... 0x5f:
-case 0xc2:
-/* Most sse scalar operations.  */
-if (b1 == 2) {
-sz = 2;
-} else if (b1 == 3) {
-sz = 3;
-}
-break;
-
-case 0x2e:  /* ucomis[sd] */
-case 0x2f:  /* comis[sd] */
-if (b1 == 0) {
-sz = 2;
+if (sse_op_flags & SSE_OPF_SCALAR) {
+if (sse_op_flags & SSE_OPF_CMP) {
+/* ucomis[sd], comis[sd] */
+if (b1 == 0) {
+sz = 2;
+} else {
+sz = 3;
+}
 } else {
-sz = 3;
+/* Most sse scalar operations.  */
+if (b1 == 2) {
+sz = 2;
+} else if (b1 == 3) {
+sz = 3;
+}
 }
-break;
 }
 
 switch (sz) {
@@ -4585,26 +4584,14 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 return;
 }
 }
-switch(b) {
-case 0x70: /* pshufx insn */
-case 0xc6: /* pshufx insn */
+tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
+tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
+if (sse_op_flags & SSE_OPF_SHUF) {
 val = x86_ldub_code(env, s);
-tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
-tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
 /* XXX: introduce a new table? */
 sse_fn_ppi = (SSEFunc_0_ppi)sse_fn_epp;
 sse_fn_ppi(s->ptr0, s->ptr1, tcg_const_i32(val));
-break;
-case 0xc2:
-/* compare insns, bits 7:3 (7:5 for AVX) are ignored */
-val = x86_ldub_code(env, s) & 7;
-sse_fn_epp = sse_op_table4[val][b1];
-
-tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
-tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
-sse_fn_epp(cpu_env, s->ptr0, s->ptr1);
-break;
-case 0xf7:
+} else if (b == 0xf7) {
 /* maskmov : we must prepare A0 */
 if (mod != 3) {
 goto illegal_op;
@@ -4613,19 +4600,19 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 gen_extu(s->aflag, s->A0);
 gen_add_A0_ds_seg(s);
 
-tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
-tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
 /* XXX: introduce a new table? */
 sse_fn_eppt = (SSEFunc_0_eppt)sse_fn_epp;
 sse_fn_eppt(cpu_env, s->ptr0, s->ptr1, s->A0);
-break;
-default:
-tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
-tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
+} else if (b == 0xc2) {
+/* compare insns, bits 7:3 (7:5 for AVX) are ignored */
+val = x86_ldub_code(env, s) & 7;
+sse_fn_epp = 

[PULL 13/39] target/i386: fix PHSUB* instructions with dest=src

2022-09-01 Thread Paolo Bonzini
The computation must not overwrite neither the destination
nor the source before the last element has been computed.

Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 target/i386/ops_sse.h | 49 +--
 1 file changed, 29 insertions(+), 20 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index 535440f882..2524db4c25 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -1528,34 +1528,43 @@ void glue(helper_pmaddubsw, SUFFIX)(CPUX86State *env, 
Reg *d, Reg *s)
 
 void glue(helper_phsubw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
 {
-d->W(0) = (int16_t)d->W(0) - (int16_t)d->W(1);
-d->W(1) = (int16_t)d->W(2) - (int16_t)d->W(3);
-XMM_ONLY(d->W(2) = (int16_t)d->W(4) - (int16_t)d->W(5));
-XMM_ONLY(d->W(3) = (int16_t)d->W(6) - (int16_t)d->W(7));
-d->W((2 << SHIFT) + 0) = (int16_t)s->W(0) - (int16_t)s->W(1);
-d->W((2 << SHIFT) + 1) = (int16_t)s->W(2) - (int16_t)s->W(3);
-XMM_ONLY(d->W(6) = (int16_t)s->W(4) - (int16_t)s->W(5));
-XMM_ONLY(d->W(7) = (int16_t)s->W(6) - (int16_t)s->W(7));
+Reg r;
+
+r.W(0) = (int16_t)d->W(0) - (int16_t)d->W(1);
+r.W(1) = (int16_t)d->W(2) - (int16_t)d->W(3);
+XMM_ONLY(r.W(2) = (int16_t)d->W(4) - (int16_t)d->W(5));
+XMM_ONLY(r.W(3) = (int16_t)d->W(6) - (int16_t)d->W(7));
+r.W((2 << SHIFT) + 0) = (int16_t)s->W(0) - (int16_t)s->W(1);
+r.W((2 << SHIFT) + 1) = (int16_t)s->W(2) - (int16_t)s->W(3);
+XMM_ONLY(r.W(6) = (int16_t)s->W(4) - (int16_t)s->W(5));
+XMM_ONLY(r.W(7) = (int16_t)s->W(6) - (int16_t)s->W(7));
+MOVE(*d, r);
 }
 
 void glue(helper_phsubd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
 {
-d->L(0) = (int32_t)d->L(0) - (int32_t)d->L(1);
-XMM_ONLY(d->L(1) = (int32_t)d->L(2) - (int32_t)d->L(3));
-d->L((1 << SHIFT) + 0) = (int32_t)s->L(0) - (int32_t)s->L(1);
-XMM_ONLY(d->L(3) = (int32_t)s->L(2) - (int32_t)s->L(3));
+Reg r;
+
+r.L(0) = (int32_t)d->L(0) - (int32_t)d->L(1);
+XMM_ONLY(r.L(1) = (int32_t)d->L(2) - (int32_t)d->L(3));
+r.L((1 << SHIFT) + 0) = (int32_t)s->L(0) - (int32_t)s->L(1);
+XMM_ONLY(r.L(3) = (int32_t)s->L(2) - (int32_t)s->L(3));
+MOVE(*d, r);
 }
 
 void glue(helper_phsubsw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
 {
-d->W(0) = satsw((int16_t)d->W(0) - (int16_t)d->W(1));
-d->W(1) = satsw((int16_t)d->W(2) - (int16_t)d->W(3));
-XMM_ONLY(d->W(2) = satsw((int16_t)d->W(4) - (int16_t)d->W(5)));
-XMM_ONLY(d->W(3) = satsw((int16_t)d->W(6) - (int16_t)d->W(7)));
-d->W((2 << SHIFT) + 0) = satsw((int16_t)s->W(0) - (int16_t)s->W(1));
-d->W((2 << SHIFT) + 1) = satsw((int16_t)s->W(2) - (int16_t)s->W(3));
-XMM_ONLY(d->W(6) = satsw((int16_t)s->W(4) - (int16_t)s->W(5)));
-XMM_ONLY(d->W(7) = satsw((int16_t)s->W(6) - (int16_t)s->W(7)));
+Reg r;
+
+r.W(0) = satsw((int16_t)d->W(0) - (int16_t)d->W(1));
+r.W(1) = satsw((int16_t)d->W(2) - (int16_t)d->W(3));
+XMM_ONLY(r.W(2) = satsw((int16_t)d->W(4) - (int16_t)d->W(5)));
+XMM_ONLY(r.W(3) = satsw((int16_t)d->W(6) - (int16_t)d->W(7)));
+r.W((2 << SHIFT) + 0) = satsw((int16_t)s->W(0) - (int16_t)s->W(1));
+r.W((2 << SHIFT) + 1) = satsw((int16_t)s->W(2) - (int16_t)s->W(3));
+XMM_ONLY(r.W(6) = satsw((int16_t)s->W(4) - (int16_t)s->W(5)));
+XMM_ONLY(r.W(7) = satsw((int16_t)s->W(6) - (int16_t)s->W(7)));
+MOVE(*d, r);
 }
 
 #define FABSB(_, x) (x > INT8_MAX  ? -(int8_t)x : x)
-- 
2.37.2





[PULL 12/39] tests/tcg: i386: extend BMI test

2022-09-01 Thread Paolo Bonzini
Cover all BMI1 and BMI2 instructions, both 32- and 64-bit.

Due to the use of inlines, the test now has to be compiled with -O2.

Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 tests/tcg/i386/Makefile.target  |   1 +
 tests/tcg/i386/test-i386-bmi2.c | 169 ++--
 2 files changed, 162 insertions(+), 8 deletions(-)

diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target
index 5614838ffc..646b4ac13e 100644
--- a/tests/tcg/i386/Makefile.target
+++ b/tests/tcg/i386/Makefile.target
@@ -18,6 +18,7 @@ test-i386-pcmpistri: CFLAGS += -msse4.2
 run-test-i386-pcmpistri: QEMU_OPTS += -cpu max
 run-plugin-test-i386-pcmpistri-%: QEMU_OPTS += -cpu max
 
+test-i386-bmi2: CFLAGS=-O2
 run-test-i386-bmi2: QEMU_OPTS += -cpu max
 run-plugin-test-i386-bmi2-%: QEMU_OPTS += -cpu max
 
diff --git a/tests/tcg/i386/test-i386-bmi2.c b/tests/tcg/i386/test-i386-bmi2.c
index 935a4d2a73..5fadf47510 100644
--- a/tests/tcg/i386/test-i386-bmi2.c
+++ b/tests/tcg/i386/test-i386-bmi2.c
@@ -1,6 +1,66 @@
 /* See if various BMI2 instructions give expected results */
 #include 
 #include 
+#include 
+
+#define insn1q(name, arg0) 
  \
+static inline uint64_t name##q(uint64_t arg0)  
  \
+{  
  \
+uint64_t result64; 
  \
+asm volatile (#name "q   %1, %0" : "=r"(result64) : "rm"(arg0));   
  \
+return result64;   
  \
+}
+
+#define insn1l(name, arg0) 
  \
+static inline uint32_t name##l(uint32_t arg0)  
  \
+{  
  \
+uint32_t result32; 
  \
+asm volatile (#name "l   %k1, %k0" : "=r"(result32) : "rm"(arg0)); 
  \
+return result32;   
  \
+}
+
+#define insn2q(name, arg0, c0, arg1, c1)   
  \
+static inline uint64_t name##q(uint64_t arg0, uint64_t arg1)   
  \
+{  
  \
+uint64_t result64; 
  \
+asm volatile (#name "q   %2, %1, %0" : "=r"(result64) : c0(arg0), 
c1(arg1)); \
+return result64;   
  \
+}
+
+#define insn2l(name, arg0, c0, arg1, c1)   
  \
+static inline uint32_t name##l(uint32_t arg0, uint32_t arg1)   
  \
+{  
  \
+uint32_t result32; 
  \
+asm volatile (#name "l   %k2, %k1, %k0" : "=r"(result32) : c0(arg0), 
c1(arg1));  \
+return result32;   
  \
+}
+
+#ifdef __x86_64
+insn2q(pext, src, "r", mask, "rm")
+insn2q(pdep, src, "r", mask, "rm")
+insn2q(andn, clear, "rm", val, "r")
+insn2q(bextr, range, "rm", val, "r")
+insn2q(bzhi, pos, "rm", val, "r")
+insn2q(rorx, val, "r", n, "i")
+insn2q(sarx, val, "rm", n, "r")
+insn2q(shlx, val, "rm", n, "r")
+insn2q(shrx, val, "rm", n, "r")
+insn1q(blsi, src)
+insn1q(blsmsk, src)
+insn1q(blsr, src)
+#endif
+insn2l(pext, src, "r", mask, "rm")
+insn2l(pdep, src, "r", mask, "rm")
+insn2l(andn, clear, "rm", val, "r")
+insn2l(bextr, range, "rm", val, "r")
+insn2l(bzhi, pos, "rm", val, "r")
+insn2l(rorx, val, "r", n, "i")
+insn2l(sarx, val, "rm", n, "r")
+insn2l(shlx, val, "rm", n, "r")
+insn2l(shrx, val, "rm", n, "r")
+insn1l(blsi, src)
+insn1l(blsmsk, src)
+insn1l(blsr, src)
 
 int main(int argc, char *argv[]) {
 uint64_t ehlo = 0x202020204f4c4845ull;
@@ -11,32 +71,125 @@ int main(int argc, char *argv[]) {
 uint64_t result64;
 
 /* 64 bits */
-asm volatile ("pextq   %2, %1, %0" : "=r"(result64) : "r"(ehlo), 
"m"(mask));
+result64 = andnq(mask, ehlo);
+assert(result64 == 0x002020204d4c4844);
+
+result64 = pextq(ehlo, mask);
 assert(result64 == 133);
 
-asm volatile ("pdepq   %2, %1, %0" : "=r"(result64) : "r"(result64), 
"m"(mask));
+result64 = pdepq(result64, mask);
 assert(result64 == (ehlo & mask));
 
-asm volatile ("pextq   %2, %1, %0" : "=r"(result64) : "r"(-1ull), 
"m"(mask));
+result64 = pextq(-1ull, mask);
 assert(result64 == 511); /* mask has 9 bits set */
 
-asm volatile ("pdepq   %2, %1, %0" : "=r"(result64) : "r"(-1ull), 
"m"(mask));
+result64 = pdepq(-1ull, mask);
 assert(result64 == mask);
+
+result64 = 

[PULL 17/39] target/i386: formatting fixes

2022-09-01 Thread Paolo Bonzini
Extracted from a patch by Paul Brook .

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 3237c1d8f9..25a2539d59 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -3314,7 +3314,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 } else {
 rm = (modrm & 7) | REX_B(s);
 gen_op_movq(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(0)),
-offsetof(CPUX86State,xmm_regs[rm].ZMM_Q(0)));
+offsetof(CPUX86State, xmm_regs[rm].ZMM_Q(0)));
 }
 break;
 case 0x012: /* movlps */
@@ -4463,7 +4463,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 /* 32 bit access */
 gen_op_ld_v(s, MO_32, s->T0, s->A0);
 tcg_gen_st32_tl(s->T0, cpu_env,
-offsetof(CPUX86State,xmm_t0.ZMM_L(0)));
+offsetof(CPUX86State, xmm_t0.ZMM_L(0)));
 break;
 case 3:
 /* 64 bit access */
@@ -4523,8 +4523,9 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 break;
 case 0xf7:
 /* maskmov : we must prepare A0 */
-if (mod != 3)
+if (mod != 3) {
 goto illegal_op;
+}
 tcg_gen_mov_tl(s->A0, cpu_regs[R_EDI]);
 gen_extu(s->aflag, s->A0);
 gen_add_A0_ds_seg(s);
-- 
2.37.2





[PULL 20/39] target/i386: Rework sse_op_table6/7

2022-09-01 Thread Paolo Bonzini
From: Paul Brook 

Add a flags field each row in sse_op_table6 and sse_op_table7.

Initially this is only used as a replacement for the magic SSE41_SPECIAL
pointer.  The other flags are mostly relevant for the AVX implementation
but can be applied to SSE as well.

Signed-off-by: Paul Brook 
Message-Id: <20220424220204.2493824-6-p...@nowt.org>
Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 target/i386/tcg/translate.c | 230 
 1 file changed, 131 insertions(+), 99 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 7332bbcf44..b7321b7588 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -2976,7 +2976,6 @@ static const struct SSEOpHelper_table1 sse_op_table1[256] 
= {
 #undef SSE_SPECIAL
 
 #define MMX_OP2(x) { gen_helper_ ## x ## _mmx, gen_helper_ ## x ## _xmm }
-#define SSE_SPECIAL_FN ((void *)1)
 
 static const SSEFunc_0_epp sse_op_table2[3 * 8][2] = {
 [0 + 2] = MMX_OP2(psrlw),
@@ -3060,113 +3059,134 @@ static const SSEFunc_0_epp sse_op_table5[256] = {
 [0xbf] = gen_helper_pavgb_mmx /* pavgusb */
 };
 
-struct SSEOpHelper_epp {
+struct SSEOpHelper_table6 {
 SSEFunc_0_epp op[2];
 uint32_t ext_mask;
+int flags;
 };
 
-struct SSEOpHelper_eppi {
+struct SSEOpHelper_table7 {
 SSEFunc_0_eppi op[2];
 uint32_t ext_mask;
+int flags;
 };
 
-#define SSSE3_OP(x) { MMX_OP2(x), CPUID_EXT_SSSE3 }
-#define SSE41_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, CPUID_EXT_SSE41 }
-#define SSE42_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, CPUID_EXT_SSE42 }
-#define SSE41_SPECIAL { { NULL, SSE_SPECIAL_FN }, CPUID_EXT_SSE41 }
-#define PCLMULQDQ_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, \
-CPUID_EXT_PCLMULQDQ }
-#define AESNI_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, CPUID_EXT_AES }
+#define gen_helper_special_xmm NULL
 
-static const struct SSEOpHelper_epp sse_op_table6[256] = {
-[0x00] = SSSE3_OP(pshufb),
-[0x01] = SSSE3_OP(phaddw),
-[0x02] = SSSE3_OP(phaddd),
-[0x03] = SSSE3_OP(phaddsw),
-[0x04] = SSSE3_OP(pmaddubsw),
-[0x05] = SSSE3_OP(phsubw),
-[0x06] = SSSE3_OP(phsubd),
-[0x07] = SSSE3_OP(phsubsw),
-[0x08] = SSSE3_OP(psignb),
-[0x09] = SSSE3_OP(psignw),
-[0x0a] = SSSE3_OP(psignd),
-[0x0b] = SSSE3_OP(pmulhrsw),
-[0x10] = SSE41_OP(pblendvb),
-[0x14] = SSE41_OP(blendvps),
-[0x15] = SSE41_OP(blendvpd),
-[0x17] = SSE41_OP(ptest),
-[0x1c] = SSSE3_OP(pabsb),
-[0x1d] = SSSE3_OP(pabsw),
-[0x1e] = SSSE3_OP(pabsd),
-[0x20] = SSE41_OP(pmovsxbw),
-[0x21] = SSE41_OP(pmovsxbd),
-[0x22] = SSE41_OP(pmovsxbq),
-[0x23] = SSE41_OP(pmovsxwd),
-[0x24] = SSE41_OP(pmovsxwq),
-[0x25] = SSE41_OP(pmovsxdq),
-[0x28] = SSE41_OP(pmuldq),
-[0x29] = SSE41_OP(pcmpeqq),
-[0x2a] = SSE41_SPECIAL, /* movntqda */
-[0x2b] = SSE41_OP(packusdw),
-[0x30] = SSE41_OP(pmovzxbw),
-[0x31] = SSE41_OP(pmovzxbd),
-[0x32] = SSE41_OP(pmovzxbq),
-[0x33] = SSE41_OP(pmovzxwd),
-[0x34] = SSE41_OP(pmovzxwq),
-[0x35] = SSE41_OP(pmovzxdq),
-[0x37] = SSE42_OP(pcmpgtq),
-[0x38] = SSE41_OP(pminsb),
-[0x39] = SSE41_OP(pminsd),
-[0x3a] = SSE41_OP(pminuw),
-[0x3b] = SSE41_OP(pminud),
-[0x3c] = SSE41_OP(pmaxsb),
-[0x3d] = SSE41_OP(pmaxsd),
-[0x3e] = SSE41_OP(pmaxuw),
-[0x3f] = SSE41_OP(pmaxud),
-[0x40] = SSE41_OP(pmulld),
-[0x41] = SSE41_OP(phminposuw),
-[0xdb] = AESNI_OP(aesimc),
-[0xdc] = AESNI_OP(aesenc),
-[0xdd] = AESNI_OP(aesenclast),
-[0xde] = AESNI_OP(aesdec),
-[0xdf] = AESNI_OP(aesdeclast),
+#define OP(name, op, flags, ext, mmx_name) \
+{{mmx_name, gen_helper_ ## name ## _xmm}, CPUID_EXT_ ## ext, flags}
+#define BINARY_OP_MMX(name, ext) \
+OP(name, op1, SSE_OPF_MMX, ext, gen_helper_ ## name ## _mmx)
+#define BINARY_OP(name, ext, flags) \
+OP(name, op1, flags, ext, NULL)
+#define UNARY_OP_MMX(name, ext) \
+OP(name, op1, SSE_OPF_MMX, ext, gen_helper_ ## name ## _mmx)
+#define UNARY_OP(name, ext, flags) \
+OP(name, op1, flags, ext, NULL)
+#define BLENDV_OP(name, ext, flags) OP(name, op1, 0, ext, NULL)
+#define CMP_OP(name, ext) OP(name, op1, SSE_OPF_CMP, ext, NULL)
+#define SPECIAL_OP(ext) OP(special, op1, SSE_OPF_SPECIAL, ext, NULL)
+
+/* prefix [66] 0f 38 */
+static const struct SSEOpHelper_table6 sse_op_table6[256] = {
+[0x00] = BINARY_OP_MMX(pshufb, SSSE3),
+[0x01] = BINARY_OP_MMX(phaddw, SSSE3),
+[0x02] = BINARY_OP_MMX(phaddd, SSSE3),
+[0x03] = BINARY_OP_MMX(phaddsw, SSSE3),
+[0x04] = BINARY_OP_MMX(pmaddubsw, SSSE3),
+[0x05] = BINARY_OP_MMX(phsubw, SSSE3),
+[0x06] = BINARY_OP_MMX(phsubd, SSSE3),
+[0x07] = BINARY_OP_MMX(phsubsw, SSSE3),
+[0x08] = BINARY_OP_MMX(psignb, SSSE3),
+[0x09] = BINARY_OP_MMX(psignw, SSSE3),
+[0x0a] = BINARY_OP_MMX(psignd, SSSE3),
+[0x0b] = BINARY_OP_MMX(pmulhrsw, SSSE3),
+[0x10] = BLENDV_OP(pblendvb, SSE41, SSE_OPF_MMX),
+ 

[PULL 09/39] meson: remove dead assignments

2022-09-01 Thread Paolo Bonzini
Found with "muon analyze".

Reviewed-by: Marc-André Lureau 
Signed-off-by: Paolo Bonzini 
---
 plugins/meson.build   |  2 +-
 tests/fp/meson.build  |  2 +-
 tests/qapi-schema/meson.build | 24 
 3 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/plugins/meson.build b/plugins/meson.build
index fa12047327..752377c66d 100644
--- a/plugins/meson.build
+++ b/plugins/meson.build
@@ -2,7 +2,7 @@ plugin_ldflags = []
 # Modules need more symbols than just those in plugins/qemu-plugins.symbols
 if not enable_modules
   if targetos == 'darwin'
-qemu_plugins_symbols_list = configure_file(
+configure_file(
   input: files('qemu-plugins.symbols'),
   output: 'qemu-plugins-ld64.symbols',
   capture: true,
diff --git a/tests/fp/meson.build b/tests/fp/meson.build
index 2b4f00b916..6258e2bd7d 100644
--- a/tests/fp/meson.build
+++ b/tests/fp/meson.build
@@ -632,7 +632,7 @@ test('fp-test-mulAdd', fptest,
['f16_mulAdd', 'f32_mulAdd', 'f64_mulAdd', 'f128_mulAdd'],
  suite: ['softfloat-slow', 'softfloat-ops-slow', 'slow'], timeout: 90)
 
-fpbench = executable(
+executable(
   'fp-bench',
   ['fp-bench.c', '../../fpu/softfloat.c'],
   link_with: [libtestfloat, libsoftfloat],
diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build
index c18dd7d02f..406bc7255d 100644
--- a/tests/qapi-schema/meson.build
+++ b/tests/qapi-schema/meson.build
@@ -215,18 +215,18 @@ test('QAPI schema regression tests', python,
 
 diff = find_program('diff')
 
-qapi_doc = custom_target('QAPI doc',
- output: ['doc-good-qapi-commands.c', 
'doc-good-qapi-commands.h',
-  'doc-good-qapi-emit-events.c', 
'doc-good-qapi-emit-events.h',
-  'doc-good-qapi-events.c', 
'doc-good-qapi-events.h',
-  'doc-good-qapi-init-commands.c', 
'doc-good-qapi-init-commands.h',
-  'doc-good-qapi-introspect.c', 
'doc-good-qapi-introspect.h',
-  'doc-good-qapi-types.c', 
'doc-good-qapi-types.h',
-  'doc-good-qapi-visit.c', 
'doc-good-qapi-visit.h' ],
- input: files('doc-good.json'),
- command: [ qapi_gen, '-o', meson.current_build_dir(),
-'-p', 'doc-good-', '@INPUT0@' ],
- depend_files: qapi_gen_depends)
+custom_target('QAPI doc',
+  output: ['doc-good-qapi-commands.c', 'doc-good-qapi-commands.h',
+   'doc-good-qapi-emit-events.c', 
'doc-good-qapi-emit-events.h',
+   'doc-good-qapi-events.c', 'doc-good-qapi-events.h',
+   'doc-good-qapi-init-commands.c', 
'doc-good-qapi-init-commands.h',
+   'doc-good-qapi-introspect.c', 
'doc-good-qapi-introspect.h',
+   'doc-good-qapi-types.c', 'doc-good-qapi-types.h',
+   'doc-good-qapi-visit.c', 'doc-good-qapi-visit.h' ],
+  input: files('doc-good.json'),
+  command: [ qapi_gen, '-o', meson.current_build_dir(),
+ '-p', 'doc-good-', '@INPUT0@' ],
+  depend_files: qapi_gen_depends)
 
 if build_docs
   # Test the document-comment document generation code by running a test schema
-- 
2.37.2





[PULL 14/39] target/i386: DPPS rounding fix

2022-09-01 Thread Paolo Bonzini
The DPPS (Dot Product) instruction is defined to first sum pairs of
intermediate results, then sum those values to get the final result.
i.e. (A+B)+(C+D)

We incrementally sum the results, i.e. ((A+B)+C)+D, which can result
in incorrect rouding.

For consistency, also change the variable names to the ones used
in the Intel SDM and implement DPPD following the manual.

Based on a patch by Paul Brook .

Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 target/i386/ops_sse.h | 67 ++-
 1 file changed, 35 insertions(+), 32 deletions(-)

diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
index 2524db4c25..b12b271fcd 100644
--- a/target/i386/ops_sse.h
+++ b/target/i386/ops_sse.h
@@ -1943,56 +1943,59 @@ SSE_HELPER_I(helper_pblendw, W, 8, FBLENDP)
 
 void glue(helper_dpps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mask)
 {
-float32 iresult = float32_zero;
+float32 prod1, prod2, temp2, temp3, temp4;
 
+/*
+ * We must evaluate (A+B)+(C+D), not ((A+B)+C)+D
+ * to correctly round the intermediate results
+ */
 if (mask & (1 << 4)) {
-iresult = float32_add(iresult,
-  float32_mul(d->ZMM_S(0), s->ZMM_S(0),
-  >sse_status),
-  >sse_status);
+prod1 = float32_mul(d->ZMM_S(0), s->ZMM_S(0), >sse_status);
+} else {
+prod1 = float32_zero;
 }
 if (mask & (1 << 5)) {
-iresult = float32_add(iresult,
-  float32_mul(d->ZMM_S(1), s->ZMM_S(1),
-  >sse_status),
-  >sse_status);
+prod2 = float32_mul(d->ZMM_S(1), s->ZMM_S(1), >sse_status);
+} else {
+prod2 = float32_zero;
 }
+temp2 = float32_add(prod1, prod2, >sse_status);
 if (mask & (1 << 6)) {
-iresult = float32_add(iresult,
-  float32_mul(d->ZMM_S(2), s->ZMM_S(2),
-  >sse_status),
-  >sse_status);
+prod1 = float32_mul(d->ZMM_S(2), s->ZMM_S(2), >sse_status);
+} else {
+prod1 = float32_zero;
 }
 if (mask & (1 << 7)) {
-iresult = float32_add(iresult,
-  float32_mul(d->ZMM_S(3), s->ZMM_S(3),
-  >sse_status),
-  >sse_status);
+prod2 = float32_mul(d->ZMM_S(3), s->ZMM_S(3), >sse_status);
+} else {
+prod2 = float32_zero;
 }
-d->ZMM_S(0) = (mask & (1 << 0)) ? iresult : float32_zero;
-d->ZMM_S(1) = (mask & (1 << 1)) ? iresult : float32_zero;
-d->ZMM_S(2) = (mask & (1 << 2)) ? iresult : float32_zero;
-d->ZMM_S(3) = (mask & (1 << 3)) ? iresult : float32_zero;
+temp3 = float32_add(prod1, prod2, >sse_status);
+temp4 = float32_add(temp2, temp3, >sse_status);
+
+d->ZMM_S(0) = (mask & (1 << 0)) ? temp4 : float32_zero;
+d->ZMM_S(1) = (mask & (1 << 1)) ? temp4 : float32_zero;
+d->ZMM_S(2) = (mask & (1 << 2)) ? temp4 : float32_zero;
+d->ZMM_S(3) = (mask & (1 << 3)) ? temp4 : float32_zero;
 }
 
 void glue(helper_dppd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mask)
 {
-float64 iresult = float64_zero;
+float64 prod1, prod2, temp2;
 
 if (mask & (1 << 4)) {
-iresult = float64_add(iresult,
-  float64_mul(d->ZMM_D(0), s->ZMM_D(0),
-  >sse_status),
-  >sse_status);
+prod1 = float64_mul(d->ZMM_D(0), s->ZMM_D(0), >sse_status);
+} else {
+prod1 = float64_zero;
 }
 if (mask & (1 << 5)) {
-iresult = float64_add(iresult,
-  float64_mul(d->ZMM_D(1), s->ZMM_D(1),
-  >sse_status),
-  >sse_status);
+prod2 = float64_mul(d->ZMM_D(1), s->ZMM_D(1), >sse_status);
+} else {
+prod2 = float64_zero;
 }
-d->ZMM_D(0) = (mask & (1 << 0)) ? iresult : float64_zero;
-d->ZMM_D(1) = (mask & (1 << 1)) ? iresult : float64_zero;
+temp2 = float64_add(prod1, prod2, >sse_status);
+d->ZMM_D(0) = (mask & (1 << 0)) ? temp2 : float64_zero;
+d->ZMM_D(1) = (mask & (1 << 1)) ? temp2 : float64_zero;
 }
 
 void glue(helper_mpsadbw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
-- 
2.37.2





[PULL 05/39] i386: do kvm_put_msr_feature_control() first thing when vCPU is reset

2022-09-01 Thread Paolo Bonzini
From: Vitaly Kuznetsov 

kvm_put_sregs2() fails to reset 'locked' CR4/CR0 bits upon vCPU reset when
it is in VMX root operation. Do kvm_put_msr_feature_control() before
kvm_put_sregs2() to (possibly) kick vCPU out of VMX root operation. It also
seems logical to do kvm_put_msr_feature_control() before
kvm_put_nested_state() and not after it, especially when 'real' nested
state is set.

Signed-off-by: Vitaly Kuznetsov 
Message-Id: <20220818150113.479917-3-vkuzn...@redhat.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/kvm/kvm.c | 17 -
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 4f8dacc1d4..a1fd1f5379 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -4529,6 +4529,18 @@ int kvm_arch_put_registers(CPUState *cpu, int level)
 
 assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
 
+/*
+ * Put MSR_IA32_FEATURE_CONTROL first, this ensures the VM gets out of VMX
+ * root operation upon vCPU reset. kvm_put_msr_feature_control() should 
also
+ * preceed kvm_put_nested_state() when 'real' nested state is set.
+ */
+if (level >= KVM_PUT_RESET_STATE) {
+ret = kvm_put_msr_feature_control(x86_cpu);
+if (ret < 0) {
+return ret;
+}
+}
+
 /* must be before kvm_put_nested_state so that EFER.SVME is set */
 ret = has_sregs2 ? kvm_put_sregs2(x86_cpu) : kvm_put_sregs(x86_cpu);
 if (ret < 0) {
@@ -4540,11 +4552,6 @@ int kvm_arch_put_registers(CPUState *cpu, int level)
 if (ret < 0) {
 return ret;
 }
-
-ret = kvm_put_msr_feature_control(x86_cpu);
-if (ret < 0) {
-return ret;
-}
 }
 
 if (level == KVM_PUT_FULL_STATE) {
-- 
2.37.2





[PULL 10/39] KVM: dirty ring: add missing memory barrier

2022-09-01 Thread Paolo Bonzini
The KVM_DIRTY_GFN_F_DIRTY flag ensures that the entry is valid.  If
the read of the fields are not ordered after the read of the flag,
QEMU might see stale values.

Cc: Gavin Shan 
Reviewed-by: Philippe Mathieu-Daudé 
Reviewed-by: Peter Xu 
Signed-off-by: Paolo Bonzini 
---
 accel/kvm/kvm-all.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 8d81ab74de..136c8eaed3 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -719,7 +719,11 @@ static void kvm_dirty_ring_mark_page(KVMState *s, uint32_t 
as_id,
 
 static bool dirty_gfn_is_dirtied(struct kvm_dirty_gfn *gfn)
 {
-return gfn->flags == KVM_DIRTY_GFN_F_DIRTY;
+/*
+ * Read the flags before the value.  Pairs with barrier in
+ * KVM's kvm_dirty_ring_push() function.
+ */
+return qatomic_load_acquire(>flags) == KVM_DIRTY_GFN_F_DIRTY;
 }
 
 static void dirty_gfn_set_collected(struct kvm_dirty_gfn *gfn)
-- 
2.37.2





[PULL 11/39] tests/tcg: x86_64: improve consistency with i386

2022-09-01 Thread Paolo Bonzini
Include test-i386-bmi2, and specify manually the tests (only one for now)
that need -cpu max.

Reviewed-by: Richard Henderson 
Signed-off-by: Paolo Bonzini 
---
 tests/tcg/i386/Makefile.target   | 2 +-
 tests/tcg/x86_64/Makefile.target | 4 +++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target
index bd73c96d0d..5614838ffc 100644
--- a/tests/tcg/i386/Makefile.target
+++ b/tests/tcg/i386/Makefile.target
@@ -8,7 +8,7 @@ VPATH   += $(I386_SRC)
 I386_SRCS=$(notdir $(wildcard $(I386_SRC)/*.c))
 ALL_X86_TESTS=$(I386_SRCS:.c=)
 SKIP_I386_TESTS=test-i386-ssse3
-X86_64_TESTS:=$(filter test-i386-ssse3, $(ALL_X86_TESTS))
+X86_64_TESTS:=$(filter test-i386-bmi2 test-i386-ssse3, $(ALL_X86_TESTS))
 
 test-i386-sse-exceptions: CFLAGS += -msse4.1 -mfpmath=sse
 run-test-i386-sse-exceptions: QEMU_OPTS += -cpu max
diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target
index b71a6bcd5e..61d9bb426e 100644
--- a/tests/tcg/x86_64/Makefile.target
+++ b/tests/tcg/x86_64/Makefile.target
@@ -14,7 +14,9 @@ TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64
 else
 TESTS=$(MULTIARCH_TESTS)
 endif
-QEMU_OPTS += -cpu max
+
+run-test-i386-ssse3: QEMU_OPTS += -cpu max
+run-plugin-test-i386-ssse3-%: QEMU_OPTS += -cpu max
 
 test-x86_64: LDFLAGS+=-lm -lc
 test-x86_64: test-i386.c test-i386.h test-i386-shift.h test-i386-muldiv.h
-- 
2.37.2





[PULL 04/39] i386: reset KVM nested state upon CPU reset

2022-09-01 Thread Paolo Bonzini
From: Vitaly Kuznetsov 

Make sure env->nested_state is cleaned up when a vCPU is reset, it may
be stale after an incoming migration, kvm_arch_put_registers() may
end up failing or putting vCPU in a weird state.

Reviewed-by: Maxim Levitsky 
Signed-off-by: Vitaly Kuznetsov 
Message-Id: <20220818150113.479917-2-vkuzn...@redhat.com>
Signed-off-by: Paolo Bonzini 
---
 target/i386/kvm/kvm.c | 37 +++--
 1 file changed, 27 insertions(+), 10 deletions(-)

diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index f148a6d52f..4f8dacc1d4 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -1695,6 +1695,30 @@ static void kvm_init_xsave(CPUX86State *env)
env->xsave_buf_len);
 }
 
+static void kvm_init_nested_state(CPUX86State *env)
+{
+struct kvm_vmx_nested_state_hdr *vmx_hdr;
+uint32_t size;
+
+if (!env->nested_state) {
+return;
+}
+
+size = env->nested_state->size;
+
+memset(env->nested_state, 0, size);
+env->nested_state->size = size;
+
+if (cpu_has_vmx(env)) {
+env->nested_state->format = KVM_STATE_NESTED_FORMAT_VMX;
+vmx_hdr = >nested_state->hdr.vmx;
+vmx_hdr->vmxon_pa = -1ull;
+vmx_hdr->vmcs12_pa = -1ull;
+} else if (cpu_has_svm(env)) {
+env->nested_state->format = KVM_STATE_NESTED_FORMAT_SVM;
+}
+}
+
 int kvm_arch_init_vcpu(CPUState *cs)
 {
 struct {
@@ -2122,19 +2146,10 @@ int kvm_arch_init_vcpu(CPUState *cs)
 assert(max_nested_state_len >= offsetof(struct kvm_nested_state, 
data));
 
 if (cpu_has_vmx(env) || cpu_has_svm(env)) {
-struct kvm_vmx_nested_state_hdr *vmx_hdr;
-
 env->nested_state = g_malloc0(max_nested_state_len);
 env->nested_state->size = max_nested_state_len;
 
-if (cpu_has_vmx(env)) {
-env->nested_state->format = KVM_STATE_NESTED_FORMAT_VMX;
-vmx_hdr = >nested_state->hdr.vmx;
-vmx_hdr->vmxon_pa = -1ull;
-vmx_hdr->vmcs12_pa = -1ull;
-} else {
-env->nested_state->format = KVM_STATE_NESTED_FORMAT_SVM;
-}
+kvm_init_nested_state(env);
 }
 }
 
@@ -2199,6 +2214,8 @@ void kvm_arch_reset_vcpu(X86CPU *cpu)
 /* enabled by default */
 env->poll_control_msr = 1;
 
+kvm_init_nested_state(env);
+
 sev_es_set_reset_vector(CPU(cpu));
 }
 
-- 
2.37.2





[PULL 07/39] meson: be strict for boolean options

2022-09-01 Thread Paolo Bonzini
From: Anton Kochkov 

While Meson buildsystem accepts the 'false' as a value
for boolean options, it's not covered by the specification
and in general invalid. Some alternative Meson implementations,
like Muon, do not accept 'false' or 'true' as a valid value
for the boolean options.

See https://mesonbuild.com/Build-options.html

Signed-off-by: Anton Kochkov 
Reviewed-by: Philippe Mathieu-Daudé 
Message-Id: <20220817143538.2107779-1-anton.koch...@proton.me>
Signed-off-by: Paolo Bonzini 
---
 meson_options.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/meson_options.txt b/meson_options.txt
index e58e158396..63f0725174 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -82,9 +82,9 @@ option('tcg', type: 'feature', value: 'enabled',
description: 'TCG support')
 option('tcg_interpreter', type: 'boolean', value: false,
description: 'TCG with bytecode interpreter (slow)')
-option('cfi', type: 'boolean', value: 'false',
+option('cfi', type: 'boolean', value: false,
description: 'Control-Flow Integrity (CFI)')
-option('cfi_debug', type: 'boolean', value: 'false',
+option('cfi_debug', type: 'boolean', value: false,
description: 'Verbose errors in case of CFI violation')
 option('multiprocess', type: 'feature', value: 'auto',
description: 'Out of process device emulation support')
-- 
2.37.2





[PULL 08/39] meson: remove dead code

2022-09-01 Thread Paolo Bonzini
Found with "muon analyze".

Reviewed-by: Marc-André Lureau 
Signed-off-by: Paolo Bonzini 
---
 meson.build |  2 --
 pc-bios/keymaps/meson.build |  1 -
 qapi/meson.build| 15 ---
 target/riscv/meson.build|  2 --
 4 files changed, 20 deletions(-)

diff --git a/meson.build b/meson.build
index 20fddbd707..ca1ba46928 100644
--- a/meson.build
+++ b/meson.build
@@ -3405,7 +3405,6 @@ foreach target : target_dirs
 target_inc += include_directories('linux-headers', is_system: true)
   endif
   if target.endswith('-softmmu')
-qemu_target_name = 'qemu-system-' + target_name
 target_type='system'
 t = target_softmmu_arch[target_base_arch].apply(config_target, strict: 
false)
 arch_srcs += t.sources()
@@ -3422,7 +3421,6 @@ foreach target : target_dirs
 abi = config_target['TARGET_ABI_DIR']
 target_type='user'
 target_inc += common_user_inc
-qemu_target_name = 'qemu-' + target_name
 if target_base_arch in target_user_arch
   t = target_user_arch[target_base_arch].apply(config_target, strict: 
false)
   arch_srcs += t.sources()
diff --git a/pc-bios/keymaps/meson.build b/pc-bios/keymaps/meson.build
index 2837eb34f4..06c75e646b 100644
--- a/pc-bios/keymaps/meson.build
+++ b/pc-bios/keymaps/meson.build
@@ -38,7 +38,6 @@ if meson.is_cross_build() or 'CONFIG_XKBCOMMON' not in 
config_host
 else
   native_qemu_keymap = qemu_keymap
 endif
-cp = find_program('cp')
 
 if native_qemu_keymap.found()
   t = []
diff --git a/qapi/meson.build b/qapi/meson.build
index fd5c93d643..840f1b0e19 100644
--- a/qapi/meson.build
+++ b/qapi/meson.build
@@ -68,21 +68,6 @@ if have_system or have_tools
   ]
 endif
 
-qapi_storage_daemon_modules = [
-  'block-core',
-  'block-export',
-  'char',
-  'common',
-  'control',
-  'crypto',
-  'introspect',
-  'job',
-  'qom',
-  'sockets',
-  'pragma',
-  'transaction',
-]
-
 qapi_nonmodule_outputs = [
   'qapi-introspect.c', 'qapi-introspect.h',
   'qapi-types.c', 'qapi-types.h',
diff --git a/target/riscv/meson.build b/target/riscv/meson.build
index 2c1975e72c..6b9435d69a 100644
--- a/target/riscv/meson.build
+++ b/target/riscv/meson.build
@@ -1,6 +1,4 @@
 # FIXME extra_args should accept files()
-dir = meson.current_source_dir()
-
 gen = [
   decodetree.process('insn16.decode', extra_args: 
['--static-decode=decode_insn16', '--insnwidth=16']),
   decodetree.process('insn32.decode', extra_args: 
'--static-decode=decode_insn32'),
-- 
2.37.2





[PULL 02/39] scsi: Add buf_len parameter to scsi_req_new()

2022-09-01 Thread Paolo Bonzini
From: John Millikin 

When a SCSI command is received from the guest, the CDB length implied
by the first byte might exceed the number of bytes the guest sent. In
this case scsi_req_new() will read uninitialized data, causing
unpredictable behavior.

Adds the buf_len parameter to scsi_req_new() and plumbs it through the
call stack.

Signed-off-by: John Millikin 
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1127
Message-Id: <20220817053458.698416-1-j...@john-millikin.com>
[Fill in correct length for adapters other than ESP. - Paolo]
Signed-off-by: Paolo Bonzini 
---
 hw/scsi/esp.c  |  2 +-
 hw/scsi/lsi53c895a.c   |  2 +-
 hw/scsi/megasas.c  | 10 +-
 hw/scsi/mptsas.c   |  3 ++-
 hw/scsi/scsi-bus.c | 21 +
 hw/scsi/scsi-disk.c|  7 ---
 hw/scsi/scsi-generic.c |  5 +++--
 hw/scsi/spapr_vscsi.c  |  3 ++-
 hw/scsi/virtio-scsi.c  |  5 +++--
 hw/scsi/vmw_pvscsi.c   |  2 +-
 hw/usb/dev-storage.c   |  2 +-
 hw/usb/dev-uas.c   |  5 +++--
 include/hw/scsi/scsi.h | 11 ++-
 13 files changed, 45 insertions(+), 33 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index c799c19bd4..2ff18ce500 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -292,7 +292,7 @@ static void do_command_phase(ESPState *s)
 esp_fifo_pop_buf(>cmdfifo, buf, cmdlen);
 
 current_lun = scsi_device_find(>bus, 0, s->current_dev->id, s->lun);
-s->current_req = scsi_req_new(current_lun, 0, s->lun, buf, s);
+s->current_req = scsi_req_new(current_lun, 0, s->lun, buf, cmdlen, s);
 datalen = scsi_req_enqueue(s->current_req);
 s->ti_size = datalen;
 fifo8_reset(>cmdfifo);
diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
index ad5f5e5f39..05a43ec807 100644
--- a/hw/scsi/lsi53c895a.c
+++ b/hw/scsi/lsi53c895a.c
@@ -864,7 +864,7 @@ static void lsi_do_command(LSIState *s)
 s->current = g_new0(lsi_request, 1);
 s->current->tag = s->select_tag;
 s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun, buf,
-   s->current);
+   s->dbc, s->current);
 
 n = scsi_req_enqueue(s->current->req);
 if (n) {
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index d5dfb412ba..7082456d65 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -1062,7 +1062,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, 
int lun,
 info->inquiry_data[0] = 0x7f; /* Force PQual 0x3, PType 0x1f */
 info->vpd_page83[0] = 0x7f;
 megasas_setup_inquiry(cmdbuf, 0, sizeof(info->inquiry_data));
-cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
+cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, sizeof(cmdbuf), 
cmd);
 if (!cmd->req) {
 trace_megasas_dcmd_req_alloc_failed(cmd->index,
 "PD get info std inquiry");
@@ -1080,7 +1080,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, 
int lun,
 return MFI_STAT_INVALID_STATUS;
 } else if (info->inquiry_data[0] != 0x7f && info->vpd_page83[0] == 0x7f) {
 megasas_setup_inquiry(cmdbuf, 0x83, sizeof(info->vpd_page83));
-cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
+cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, sizeof(cmdbuf), 
cmd);
 if (!cmd->req) {
 trace_megasas_dcmd_req_alloc_failed(cmd->index,
 "PD get info vpd inquiry");
@@ -1268,7 +1268,7 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, 
int lun,
 cmd->iov_buf = g_malloc0(dcmd_size);
 info = cmd->iov_buf;
 megasas_setup_inquiry(cdb, 0x83, sizeof(info->vpd_page83));
-cmd->req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd);
+cmd->req = scsi_req_new(sdev, cmd->index, lun, cdb, sizeof(cdb), cmd);
 if (!cmd->req) {
 trace_megasas_dcmd_req_alloc_failed(cmd->index,
 "LD get info vpd inquiry");
@@ -1748,7 +1748,7 @@ static int megasas_handle_scsi(MegasasState *s, 
MegasasCmd *cmd,
 return MFI_STAT_SCSI_DONE_WITH_ERROR;
 }
 
-cmd->req = scsi_req_new(sdev, cmd->index, lun_id, cdb, cmd);
+cmd->req = scsi_req_new(sdev, cmd->index, lun_id, cdb, cdb_len, cmd);
 if (!cmd->req) {
 trace_megasas_scsi_req_alloc_failed(
 mfi_frame_desc(frame_cmd), target_id, lun_id);
@@ -1823,7 +1823,7 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd 
*cmd, int frame_cmd)
 
 megasas_encode_lba(cdb, lba_start, lba_count, is_write);
 cmd->req = scsi_req_new(sdev, cmd->index,
-lun_id, cdb, cmd);
+lun_id, cdb, cdb_len, cmd);
 if (!cmd->req) {
 trace_megasas_scsi_req_alloc_failed(
 mfi_frame_desc(frame_cmd), target_id, lun_id);
diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c
index 706cf0df3a..a90c2546f1 

[PULL 06/39] configure: improve error for ucontext coroutine backend

2022-09-01 Thread Paolo Bonzini
Instead of using feature_not_found(), which is not a good match because
there is no "remedy" to fix the lack of makecontext(), just print a
custom error.

This happens to remove the last use of feature_not_found(), so remove
the definition and the documentation.

Signed-off-by: Paolo Bonzini 
---
 configure   | 11 +--
 docs/devel/build-system.rst |  5 -
 2 files changed, 1 insertion(+), 15 deletions(-)

diff --git a/configure b/configure
index 72ab03f11a..575dde1c1f 100755
--- a/configure
+++ b/configure
@@ -1468,15 +1468,6 @@ if test "$tcg" = "enabled"; then
 git_submodules="$git_submodules tests/fp/berkeley-softfloat-3"
 fi
 
-feature_not_found() {
-  feature=$1
-  remedy=$2
-
-  error_exit "User requested feature $feature" \
-  "configure was not able to find it." \
-  "$remedy"
-}
-
 # ---
 # big/little endian test
 cat > $TMPC << EOF
@@ -1639,7 +1630,7 @@ else
 ;;
   ucontext)
 if test "$ucontext_works" != "yes"; then
-  feature_not_found "ucontext"
+  error_exit "'ucontext' backend requested but makecontext not available"
 fi
 ;;
   sigaltstack)
diff --git a/docs/devel/build-system.rst b/docs/devel/build-system.rst
index 431caba7aa..1894721743 100644
--- a/docs/devel/build-system.rst
+++ b/docs/devel/build-system.rst
@@ -99,11 +99,6 @@ developers in checking for system features:
Write a minimal C program main() function to the temporary file
indicated by $TMPC
 
-``feature_not_found $NAME $REMEDY``
-   Print a message to stderr that the feature $NAME was not available
-   on the system, suggesting the user try $REMEDY to address the
-   problem.
-
 ``error_exit $MESSAGE $MORE...``
Print $MESSAGE to stderr, followed by $MORE... and then exit from the
configure script with non-zero status
-- 
2.37.2





[PULL 03/39] scsi: Reject commands if the CDB length exceeds buf_len

2022-09-01 Thread Paolo Bonzini
From: John Millikin 

In scsi_req_parse_cdb(), if the CDB length implied by the command type
exceeds the initialized portion of the command buffer, reject the request.

Rejected requests are recorded by the `scsi_req_parse_bad` trace event.

On example of a bug detected by this check is SunOS's use of interleaved
DMA and non-DMA commands. This guest behavior currently causes QEMU to
parse uninitialized memory as a SCSI command, with unpredictable
outcomes.

With the new check in place:

  * QEMU consistently creates a trace event and rejects the request.

  * SunOS retries the request(s) and is able to successfully boot from
disk.

Signed-off-by: John Millikin 
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1127
Message-Id: <20220817053458.698416-2-j...@john-millikin.com>
Signed-off-by: Paolo Bonzini 
---
 hw/scsi/scsi-bus.c | 8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index cc71524024..4403717c4a 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -712,6 +712,11 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, 
uint32_t lun,
 SCSICommand cmd = { .len = 0 };
 int ret;
 
+if (buf_len == 0) {
+trace_scsi_req_parse_bad(d->id, lun, tag, 0);
+goto invalid_opcode;
+}
+
 if ((d->unit_attention.key == UNIT_ATTENTION ||
  bus->unit_attention.key == UNIT_ATTENTION) &&
 (buf[0] != INQUIRY &&
@@ -741,6 +746,7 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, 
uint32_t lun,
 
 if (ret != 0) {
 trace_scsi_req_parse_bad(d->id, lun, tag, buf[0]);
+invalid_opcode:
 req = scsi_req_alloc(_invalid_opcode, d, tag, lun, hba_private);
 } else {
 assert(cmd.len != 0);
@@ -1316,7 +1322,7 @@ int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, 
uint8_t *buf,
 
 cmd->lba = -1;
 len = scsi_cdb_length(buf);
-if (len < 0) {
+if (len < 0 || len > buf_len) {
 return -1;
 }
 
-- 
2.37.2





[PULL 01/39] esp: Handle CMD_BUSRESET by resetting the SCSI bus

2022-09-01 Thread Paolo Bonzini
From: John Millikin 

Per investigation on the linked ticket, SunOS issues a SCSI bus reset
to the ESP as part of its boot sequence. If this ESP command doesn't
cause devices to assert sense flag UNIT ATTENTION, SunOS will consider
the CD-ROM device to be non-compliant with Common Command Set (CCS).
In this condition, the SunOS installer's early userspace doesn't set
the installation source location to sr0 and the miniroot copy fails.

Signed-off-by: John Millikin 
Suggested-by: Bill Paul 
Buglink: https://gitlab.com/qemu-project/qemu/-/issues/1127
Message-Id: <20220817053846.699310-1-j...@john-millikin.com>
Signed-off-by: Paolo Bonzini 
---
 hw/scsi/esp.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 2d3c649567..c799c19bd4 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -939,6 +939,11 @@ static void esp_soft_reset(ESPState *s)
 esp_hard_reset(s);
 }
 
+static void esp_bus_reset(ESPState *s)
+{
+qbus_reset_all(BUS(>bus));
+}
+
 static void parent_esp_reset(ESPState *s, int irq, int level)
 {
 if (level) {
@@ -1067,6 +1072,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t 
val)
 break;
 case CMD_BUSRESET:
 trace_esp_mem_writeb_cmd_bus_reset(val);
+esp_bus_reset(s);
 if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) {
 s->rregs[ESP_RINTR] |= INTR_RST;
 esp_raise_irq(s);
-- 
2.37.2





[PULL 00/39] i386, SCSI, build system changes for 2022-09-01

2022-09-01 Thread Paolo Bonzini
The following changes since commit e93ded1bf6c94ab95015b33e188bc8b0b0c32670:

  Merge tag 'testing-pull-request-2022-08-30' of https://gitlab.com/thuth/qemu 
into staging (2022-08-31 18:19:03 -0400)

are available in the Git repository at:

  https://gitlab.com/bonzini/qemu.git tags/for-upstream

for you to fetch changes up to a64fc269198e09d422da0e89e606f6f12b40af1f:

  target/i386: AVX+AES helpers prep (2022-09-01 20:16:33 +0200)


* SCSI fixes for Mac OS 9
* Fix CPU reset for x86/KVM nested virtualization state
* remove feature_not_found() from the configure script
* Meson cleanups from muon
* improved i386 TCG tests for BMI and SSE
* SSE bugfixes


Anton Kochkov (1):
  meson: be strict for boolean options

John Millikin (3):
  esp: Handle CMD_BUSRESET by resetting the SCSI bus
  scsi: Add buf_len parameter to scsi_req_new()
  scsi: Reject commands if the CDB length exceeds buf_len

Paolo Bonzini (15):
  configure: improve error for ucontext coroutine backend
  meson: remove dead code
  meson: remove dead assignments
  KVM: dirty ring: add missing memory barrier
  tests/tcg: x86_64: improve consistency with i386
  tests/tcg: i386: extend BMI test
  target/i386: fix PHSUB* instructions with dest=src
  target/i386: DPPS rounding fix
  target/i386: do not use MOVL to move data between SSE registers
  target/i386: formatting fixes
  target/i386: check SSE table flags instead of hardcoding opcodes
  target/i386: isolate MMX code more
  target/i386: Add size suffix to vector FP helpers
  target/i386: do not cast gen_helper_* function pointers
  target/i386: rewrite destructive 3DNow operations

Paul Brook (18):
  tests/tcg: i386: add SSE tests
  target/i386: Add ZMM_OFFSET macro
  target/i386: Rework sse_op_table1
  target/i386: Rework sse_op_table6/7
  target/i386: Move 3DNOW decoder
  target/i386: Add CHECK_NO_VEX
  target/i386: Rewrite vector shift helper
  target/i386: Rewrite simple integer vector helpers
  target/i386: Misc integer AVX helper prep
  target/i386: Destructive vector helpers for AVX
  target/i386: Floating point arithmetic helper AVX prep
  target/i386: reimplement AVX comparison helpers
  target/i386: Dot product AVX helper prep
  target/i386: Destructive FP helpers for AVX
  target/i386: Misc AVX helper prep
  target/i386: Rewrite blendv helpers
  target/i386: AVX pclmulqdq prep
  target/i386: AVX+AES helpers prep

Vitaly Kuznetsov (2):
  i386: reset KVM nested state upon CPU reset
  i386: do kvm_put_msr_feature_control() first thing when vCPU is reset

 accel/kvm/kvm-all.c  |6 +-
 configure|   11 +-
 docs/devel/build-system.rst  |5 -
 hw/scsi/esp.c|8 +-
 hw/scsi/lsi53c895a.c |2 +-
 hw/scsi/megasas.c|   10 +-
 hw/scsi/mptsas.c |3 +-
 hw/scsi/scsi-bus.c   |   29 +-
 hw/scsi/scsi-disk.c  |7 +-
 hw/scsi/scsi-generic.c   |5 +-
 hw/scsi/spapr_vscsi.c|3 +-
 hw/scsi/virtio-scsi.c|5 +-
 hw/scsi/vmw_pvscsi.c |2 +-
 hw/usb/dev-storage.c |2 +-
 hw/usb/dev-uas.c |5 +-
 include/hw/scsi/scsi.h   |   11 +-
 meson.build  |2 -
 meson_options.txt|4 +-
 pc-bios/keymaps/meson.build  |1 -
 plugins/meson.build  |2 +-
 qapi/meson.build |   15 -
 target/i386/kvm/kvm.c|   54 +-
 target/i386/ops_sse.h| 1819 +++
 target/i386/ops_sse_header.h |   68 +-
 target/i386/tcg/translate.c  |  831 ---
 target/riscv/meson.build |2 -
 tests/fp/meson.build |2 +-
 tests/qapi-schema/meson.build|   24 +-
 tests/tcg/Makefile.target|2 +-
 tests/tcg/i386/Makefile.target   |   12 +-
 tests/tcg/i386/README|9 +
 tests/tcg/i386/test-avx.c|  330 +++
 tests/tcg/i386/test-avx.py   |  351 +++
 tests/tcg/i386/test-i386-bmi2.c  |  169 +-
 tests/tcg/i386/x86.csv   | 4658 ++
 tests/tcg/x86_64/Makefile.target |5 +-
 36 files changed, 7059 insertions(+), 1415 deletions(-)
 create mode 100644 tests/tcg/i386/test-avx.c
 create mode 100755 tests/tcg/i386/test-avx.py
 create mode 100644 tests/tcg/i386/x86.csv
-- 
2.37.2




Re: QEMU 7.2 release schedule

2022-09-01 Thread Daniel Henrique Barboza




On 8/30/22 18:12, Stefan Hajnoczi wrote:

Hi,
Richard Henderson has tagged QEMU 7.1 and handed over to me for the 7.2
release cycle. Thanks to Richard and Michael Roth their work on 7.1!


Are you going to handle the pull requests for this release cycle? I saw
that you've handled Thomas' PRs.

If that's the case I'll CC you in the PRs instead of Peter/Richard.


Thanks,


Daniel



Please check the proposed release schedule and let me know if they fall
on inconvenient dates:
- 2022-08-30: Beginning of development phase
- 2022-11-1: Soft feature freeze. Only bug fixes after this point. All feature 
changes must be already in a sub maintainer tree and all pull requests from 
submaintainers must have been sent to the list by this date.
- 2022-11-8: Hard feature freeze. Tag rc0
- 2022-11-15: Tag rc1
- 2022-11-22: Tag rc2
- 2022-11-29: Tag rc3
- 2022-12-06: Release; or tag rc4 if needed
- 2022-12-13: Release if we needed an rc4

The release planning page is now available on the wiki:
https://wiki.qemu.org/Planning/7.2

The changelog has been created so you can add items when code is merged:
https://wiki.qemu.org/ChangeLog/7.2

Stefan




[PATCH v1 0/8] migration: introduce dirtylimit capability

2022-09-01 Thread huangy81
From: Hyman Huang(黄勇) 

v1:
- make parameter vcpu-dirty-limit experimental 
- switch dirty limit off when cancel migrate
- add cancel logic in migration test 

Please review, thanks,

Yong 

Abstract


This series added a new migration capability called "dirtylimit".  It can
be enabled when dirty ring is enabled, and it'll improve the vCPU performance
during the process of migration. It is based on the previous patchset:
https://lore.kernel.org/qemu-devel/cover.1656177590.git.huang...@chinatelecom.cn/

As mentioned in patchset "support dirty restraint on vCPU", dirtylimit way of
migration can make the read-process not be penalized. This series wires up the
vcpu dirty limit and wrappers as dirtylimit capability of migration. I introduce
two parameters vcpu-dirtylimit-period and vcpu-dirtylimit to implement the 
setup 
of dirtylimit during live migration.

To validate the implementation, i tested a 32 vCPU vm live migration with such 
model:
Only dirty vcpu0, vcpu1 with heavy memory workoad and leave the rest vcpus
untouched, running unixbench on the vpcu8-vcpu15 by setup the cpu affinity as
the following command:
taskset -c 8-15 ./Run -i 2 -c 8 {unixbench test item}

The following are results:

host cpu: Intel(R) Xeon(R) Platinum 8378A
host interface speed: 1000Mb/s
  |-+++---|
  | UnixBench test item | Normal | Dirtylimit | Auto-converge |
  |-+++---|
  | dhry2reg| 32800  | 32786  | 25292 |
  | whetstone-double| 10326  | 10315  | 9847  |
  | pipe| 15442  | 15271  | 14506 |
  | context1| 7260   | 6235   | 4514  |
  | spawn   | 3663   | 3317   | 3249  |
  | syscall | 4669   | 4667   | 3841  |
  |-+++---|
>From the data above we can draw a conclusion that vcpus that do not dirty 
>memory
in vm are almost unaffected during the dirtylimit migration, but the auto 
converge
way does. 

I also tested the total time of dirtylimit migration with variable dirty memory
size in vm.

senario 1:
host cpu: Intel(R) Xeon(R) Platinum 8378A
host interface speed: 1000Mb/s
  |---++---|
  | dirty memory size(MB) | Dirtylimit(ms) | Auto-converge(ms) |
  |---++---|
  | 60| 2014   | 2131  |
  | 70| 5381   | 12590 |
  | 90| 6037   | 33545 |
  | 110   | 7660   | [*]   |
  |---++---|
  [*]: This case means migration is not convergent. 

senario 2:
host cpu: Intel(R) Xeon(R) CPU E5-2650
host interface speed: 1Mb/s
  |---++---|
  | dirty memory size(MB) | Dirtylimit(ms) | Auto-converge(ms) |
  |---++---|
  | 1600  | 15842  | 27548 |
  | 2000  | 19026  | 38447 |
  | 2400  | 19897  | 46381 |
  | 2800  | 22338  | 57149 |
  |---++---|
Above data shows that dirtylimit way of migration can also reduce the total
time of migration and it achieves convergence more easily in some case.

In addition to implement dirtylimit capability itself, this series
add 3 tests for migration, aiming at playing around for developer simply: 
 1. qtest for dirty limit migration
 2. support dirty ring way of migration for guestperf tool
 3. support dirty limit migration for guestperf tool

Please review, thanks !

Hyman Huang (8):
  qapi/migration: Introduce x-vcpu-dirty-limit-period parameter
  qapi/migration: Introduce x-vcpu-dirty-limit parameters
  migration: Introduce dirty-limit capability
  migration: Implement dirty-limit convergence algo
  migration: Export dirty-limit time info
  tests: Add migration dirty-limit capability test
  tests/migration: Introduce dirty-ring-size option into guestperf
  tests/migration: Introduce dirty-limit into guestperf

 include/sysemu/dirtylimit.h |   2 +
 migration/migration.c   |  51 +++
 migration/migration.h   |   1 +
 migration/ram.c |  53 ---
 migration/trace-events  |   1 +
 monitor/hmp-cmds.c  |  26 ++
 qapi/migration.json |  57 ++--
 softmmu/dirtylimit.c|  33 ++-
 tests/migration/guestperf/comparison.py |  24 +
 tests/migration/guestperf/engine.py |  33 ++-
 tests/migration/guestperf/hardware.py   |   8 +-
 

[PATCH v1 3/8] migration: Introduce dirty-limit capability

2022-09-01 Thread huangy81
From: Hyman Huang(黄勇) 

Introduce migration dirty-limit capability, which can
be turned on before live migration and limit dirty
page rate durty live migration.

Introduce migrate_dirty_limit function to help check
if dirty-limit capability enabled during live migration.

Meanwhile, refactor vcpu_dirty_rate_stat_collect
so that period can be configured instead of hardcoded.

dirty-limit capability is kind of like auto-converge
but using dirty limit instead of traditional cpu-throttle
to throttle guest down. To enable this feature, turn on
the dirty-limit capability before live migration using
migratioin-set-capabilities, and set the parameters
"x-vcpu-dirty-limit-period", "vcpu-dirty-limit" suitably
to speed up convergence.

Signed-off-by: Hyman Huang(黄勇) 
---
 migration/migration.c | 10 ++
 migration/migration.h |  1 +
 qapi/migration.json   |  4 +++-
 softmmu/dirtylimit.c  | 11 ++-
 4 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index a748fe5..d117bb4 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2508,6 +2508,15 @@ bool migrate_auto_converge(void)
 return s->enabled_capabilities[MIGRATION_CAPABILITY_AUTO_CONVERGE];
 }
 
+bool migrate_dirty_limit(void)
+{
+MigrationState *s;
+
+s = migrate_get_current();
+
+return s->enabled_capabilities[MIGRATION_CAPABILITY_DIRTY_LIMIT];
+}
+
 bool migrate_zero_blocks(void)
 {
 MigrationState *s;
@@ -4437,6 +4446,7 @@ static Property migration_properties[] = {
 DEFINE_PROP_MIG_CAP("x-zero-copy-send",
 MIGRATION_CAPABILITY_ZERO_COPY_SEND),
 #endif
+DEFINE_PROP_MIG_CAP("x-dirty-limit", MIGRATION_CAPABILITY_DIRTY_LIMIT),
 
 DEFINE_PROP_END_OF_LIST(),
 };
diff --git a/migration/migration.h b/migration/migration.h
index cdad8ac..7fbb9f8 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -409,6 +409,7 @@ bool migrate_ignore_shared(void);
 bool migrate_validate_uuid(void);
 
 bool migrate_auto_converge(void);
+bool migrate_dirty_limit(void);
 bool migrate_use_multifd(void);
 bool migrate_pause_before_switchover(void);
 int migrate_multifd_channels(void);
diff --git a/qapi/migration.json b/qapi/migration.json
index 8554d33..bc4bc96 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -477,6 +477,8 @@
 #will be handled faster.  This is a performance feature and
 #should not affect the correctness of postcopy migration.
 #(since 7.1)
+# @dirty-limit: Use dirty-limit to throttle down guest if enabled.
+#   (since 7.1)
 #
 # Features:
 # @unstable: Members @x-colo and @x-ignore-shared are experimental.
@@ -492,7 +494,7 @@
'dirty-bitmaps', 'postcopy-blocktime', 'late-block-activate',
{ 'name': 'x-ignore-shared', 'features': [ 'unstable' ] },
'validate-uuid', 'background-snapshot',
-   'zero-copy-send', 'postcopy-preempt'] }
+   'zero-copy-send', 'postcopy-preempt', 'dirty-limit'] }
 
 ##
 # @MigrationCapabilityStatus:
diff --git a/softmmu/dirtylimit.c b/softmmu/dirtylimit.c
index 8d98cb7..1fdd8c6 100644
--- a/softmmu/dirtylimit.c
+++ b/softmmu/dirtylimit.c
@@ -23,6 +23,8 @@
 #include "exec/memory.h"
 #include "hw/boards.h"
 #include "sysemu/kvm.h"
+#include "migration/misc.h"
+#include "migration/migration.h"
 #include "trace.h"
 
 /*
@@ -75,11 +77,18 @@ static bool dirtylimit_quit;
 
 static void vcpu_dirty_rate_stat_collect(void)
 {
+MigrationState *s = migrate_get_current();
 VcpuStat stat;
 int i = 0;
+int64_t period = DIRTYLIMIT_CALC_TIME_MS;
+
+if (migrate_dirty_limit() &&
+migration_is_active(s)) {
+period = s->parameters.x_vcpu_dirty_limit_period;
+}
 
 /* calculate vcpu dirtyrate */
-vcpu_calculate_dirtyrate(DIRTYLIMIT_CALC_TIME_MS,
+vcpu_calculate_dirtyrate(period,
  ,
  GLOBAL_DIRTY_LIMIT,
  false);
-- 
1.8.3.1




[PATCH v1 8/8] tests/migration: Introduce dirty-limit into guestperf

2022-09-01 Thread huangy81
From: Hyman Huang(黄勇) 

Guestperf tool does not cover the dirty-limit migration
currently, support this feature.

To enable dirty-limit, setting x-vcpu-dirty-limit-period
as 500ms and x-vcpu-dirty-limit as 10MB/s:
$ ./tests/migration/guestperf.py \
--dirty-limit --x-vcpu-dirty-limit-period 500 \
--x-vcpu-dirty-limit 10 --output output.json \

To run the entire standardized set of dirty-limit-enabled
comparisons, with unix migration:
$ ./tests/migration/guestperf-batch.py \
--dst-host localhost --transport unix \
--filter compr-dirty-limit* --output outputdir

Signed-off-by: Hyman Huang(黄勇) 
---
 tests/migration/guestperf/comparison.py | 24 
 tests/migration/guestperf/engine.py | 26 ++
 tests/migration/guestperf/progress.py   | 17 +++--
 tests/migration/guestperf/scenario.py   | 11 ++-
 tests/migration/guestperf/shell.py  | 18 +-
 5 files changed, 92 insertions(+), 4 deletions(-)

diff --git a/tests/migration/guestperf/comparison.py 
b/tests/migration/guestperf/comparison.py
index c03b3f6..d082a54 100644
--- a/tests/migration/guestperf/comparison.py
+++ b/tests/migration/guestperf/comparison.py
@@ -135,4 +135,28 @@ def __init__(self, name, scenarios):
 Scenario("compr-multifd-channels-64",
  multifd=True, multifd_channels=64),
 ]),
+
+
+# Looking at effect of dirty-limit with
+# varying x_vcpu_dirty_limit_period
+Comparison("compr-dirty-limit-period", scenarios = [
+Scenario("compr-dirty-limit-period-100",
+ dirty_limit=True, x_vcpu_dirty_limit_period=100),
+Scenario("compr-dirty-limit-period-500",
+ dirty_limit=True, x_vcpu_dirty_limit_period=500),
+Scenario("compr-dirty-limit-period-1000",
+ dirty_limit=True, x_vcpu_dirty_limit_period=1000),
+]),
+
+
+# Looking at effect of dirty-limit with
+# varying x_vcpu_dirty_limit
+Comparison("compr-dirty-limit", scenarios = [
+Scenario("compr-dirty-limit-10MB",
+ dirty_limit=True, x_vcpu_dirty_limit=10),
+Scenario("compr-dirty-limit-20MB",
+ dirty_limit=True, x_vcpu_dirty_limit=20),
+Scenario("compr-dirty-limit-50MB",
+ dirty_limit=True, x_vcpu_dirty_limit=50),
+]),
 ]
diff --git a/tests/migration/guestperf/engine.py 
b/tests/migration/guestperf/engine.py
index 2b98f00..c6b9bb1 100644
--- a/tests/migration/guestperf/engine.py
+++ b/tests/migration/guestperf/engine.py
@@ -103,6 +103,8 @@ def _migrate_progress(self, vm):
 info.get("expected-downtime", 0),
 info.get("setup-time", 0),
 info.get("cpu-throttle-percentage", 0),
+info.get("dirty-limit-throttle-us-per-full", 0),
+info.get("dirty-limit-us-ring-full", 0),
 )
 
 def _migrate(self, hardware, scenario, src, dst, connect_uri):
@@ -204,6 +206,30 @@ def _migrate(self, hardware, scenario, src, dst, 
connect_uri):
 resp = dst.command("migrate-set-parameters",
multifd_channels=scenario._multifd_channels)
 
+if scenario._dirty_limit:
+if not hardware._dirty_ring_size:
+raise Exception("dirty ring size must be configured when "
+"testing dirty limit migration")
+
+resp = src.command("migrate-set-capabilities",
+   capabilities = [
+   { "capability": "dirty-limit",
+ "state": True }
+   ])
+resp = src.command("migrate-set-parameters",
+x_vcpu_dirty_limit_period=scenario._x_vcpu_dirty_limit_period)
+resp = src.command("migrate-set-parameters",
+   x_vcpu_dirty_limit=scenario._x_vcpu_dirty_limit)
+resp = dst.command("migrate-set-capabilities",
+   capabilities = [
+   { "capability": "dirty-limit",
+ "state": True }
+   ])
+resp = dst.command("migrate-set-parameters",
+x_vcpu_dirty_limit_period=scenario._x_vcpu_dirty_limit_period)
+resp = dst.command("migrate-set-parameters",
+   x_vcpu_dirty_limit=scenario._x_vcpu_dirty_limit)
+
 resp = src.command("migrate", uri=connect_uri)
 
 post_copy = False
diff --git a/tests/migration/guestperf/progress.py 
b/tests/migration/guestperf/progress.py
index ab1ee57..dd5d86b 100644
--- a/tests/migration/guestperf/progress.py
+++ b/tests/migration/guestperf/progress.py
@@ -81,7 +81,9 @@ def __init__(self,
  downtime,
  downtime_expected,
  setup_time,
- throttle_pcent):
+ throttle_pcent,
+ 

[PATCH v1 4/8] migration: Implement dirty-limit convergence algo

2022-09-01 Thread huangy81
From: Hyman Huang(黄勇) 

Implement dirty-limit convergence algo for live migration,
which is kind of like auto-converge algo but using dirty-limit
instead of cpu throttle to make migration convergent.

Signed-off-by: Hyman Huang(黄勇) 
---
 migration/migration.c  |  1 +
 migration/ram.c| 53 +-
 migration/trace-events |  1 +
 3 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index d117bb4..64696de 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -239,6 +239,7 @@ void migration_cancel(const Error *error)
 if (error) {
 migrate_set_error(current_migration, error);
 }
+qmp_cancel_vcpu_dirty_limit(false, -1, NULL);
 migrate_fd_cancel(current_migration);
 }
 
diff --git a/migration/ram.c b/migration/ram.c
index dc1de9d..cc19c5e 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -45,6 +45,7 @@
 #include "qapi/error.h"
 #include "qapi/qapi-types-migration.h"
 #include "qapi/qapi-events-migration.h"
+#include "qapi/qapi-commands-migration.h"
 #include "qapi/qmp/qerror.h"
 #include "trace.h"
 #include "exec/ram_addr.h"
@@ -57,6 +58,8 @@
 #include "qemu/iov.h"
 #include "multifd.h"
 #include "sysemu/runstate.h"
+#include "sysemu/dirtylimit.h"
+#include "sysemu/kvm.h"
 
 #include "hw/boards.h" /* for machine_dump_guest_core() */
 
@@ -1139,6 +1142,21 @@ static void migration_update_rates(RAMState *rs, int64_t 
end_time)
 }
 }
 
+/*
+ * Enable dirty-limit to throttle down the guest
+ */
+static void migration_dirty_limit_guest(void)
+{
+if (!dirtylimit_in_service()) {
+MigrationState *s = migrate_get_current();
+int64_t quota_dirtyrate = s->parameters.x_vcpu_dirty_limit;
+
+/* Set quota dirtyrate if dirty limit not in service */
+qmp_set_vcpu_dirty_limit(false, -1, quota_dirtyrate, NULL);
+trace_migration_dirty_limit_guest(quota_dirtyrate);
+}
+}
+
 static void migration_trigger_throttle(RAMState *rs)
 {
 MigrationState *s = migrate_get_current();
@@ -1148,22 +1166,31 @@ static void migration_trigger_throttle(RAMState *rs)
 uint64_t bytes_dirty_period = rs->num_dirty_pages_period * 
TARGET_PAGE_SIZE;
 uint64_t bytes_dirty_threshold = bytes_xfer_period * threshold / 100;
 
-/* During block migration the auto-converge logic incorrectly detects
- * that ram migration makes no progress. Avoid this by disabling the
- * throttling logic during the bulk phase of block migration. */
-if (migrate_auto_converge() && !blk_mig_bulk_active()) {
-/* The following detection logic can be refined later. For now:
-   Check to see if the ratio between dirtied bytes and the approx.
-   amount of bytes that just got transferred since the last time
-   we were in this routine reaches the threshold. If that happens
-   twice, start or increase throttling. */
-
-if ((bytes_dirty_period > bytes_dirty_threshold) &&
-(++rs->dirty_rate_high_cnt >= 2)) {
+/*
+ * The following detection logic can be refined later. For now:
+ * Check to see if the ratio between dirtied bytes and the approx.
+ * amount of bytes that just got transferred since the last time
+ * we were in this routine reaches the threshold. If that happens
+ * twice, start or increase throttling.
+ */
+
+if ((bytes_dirty_period > bytes_dirty_threshold) &&
+(++rs->dirty_rate_high_cnt >= 2)) {
+rs->dirty_rate_high_cnt = 0;
+/*
+ * During block migration the auto-converge logic incorrectly detects
+ * that ram migration makes no progress. Avoid this by disabling the
+ * throttling logic during the bulk phase of block migration
+ */
+
+if (migrate_auto_converge() && !blk_mig_bulk_active()) {
 trace_migration_throttle();
-rs->dirty_rate_high_cnt = 0;
 mig_throttle_guest_down(bytes_dirty_period,
 bytes_dirty_threshold);
+} else if (migrate_dirty_limit() &&
+   kvm_dirty_ring_enabled() &&
+   migration_is_active(s)) {
+migration_dirty_limit_guest();
 }
 }
 }
diff --git a/migration/trace-events b/migration/trace-events
index 57003ed..33a2666 100644
--- a/migration/trace-events
+++ b/migration/trace-events
@@ -91,6 +91,7 @@ migration_bitmap_sync_start(void) ""
 migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64
 migration_bitmap_clear_dirty(char *str, uint64_t start, uint64_t size, 
unsigned long page) "rb %s start 0x%"PRIx64" size 0x%"PRIx64" page 0x%lx"
 migration_throttle(void) ""
+migration_dirty_limit_guest(int64_t dirtyrate) "guest dirty page rate limit %" 
PRIi64 " MB/s"
 ram_discard_range(const char *rbname, uint64_t start, size_t len) "%s: start: 
%" PRIx64 " %zx"
 ram_load_loop(const char *rbname, uint64_t addr, int flags, void *host) "%s: 

[PATCH v1 5/8] migration: Export dirty-limit time info

2022-09-01 Thread huangy81
From: Hyman Huang(黄勇) 

Export dirty limit throttle time and estimated ring full
time, through which we can observe the process of dirty
limit during live migration.

Signed-off-by: Hyman Huang(黄勇) 
---
 include/sysemu/dirtylimit.h |  2 ++
 migration/migration.c   | 10 ++
 monitor/hmp-cmds.c  | 10 ++
 qapi/migration.json | 10 +-
 softmmu/dirtylimit.c| 22 ++
 5 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/include/sysemu/dirtylimit.h b/include/sysemu/dirtylimit.h
index 8d2c1f3..98cc4a6 100644
--- a/include/sysemu/dirtylimit.h
+++ b/include/sysemu/dirtylimit.h
@@ -34,4 +34,6 @@ void dirtylimit_set_vcpu(int cpu_index,
 void dirtylimit_set_all(uint64_t quota,
 bool enable);
 void dirtylimit_vcpu_execute(CPUState *cpu);
+int64_t dirtylimit_throttle_us_per_full(void);
+int64_t dirtylimit_us_ring_full(void);
 #endif
diff --git a/migration/migration.c b/migration/migration.c
index 64696de..22ba197 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -61,6 +61,7 @@
 #include "sysemu/cpus.h"
 #include "yank_functions.h"
 #include "sysemu/qtest.h"
+#include "sysemu/dirtylimit.h"
 
 #define MAX_THROTTLE  (128 << 20)  /* Migration transfer speed throttling 
*/
 
@@ -1110,6 +,15 @@ static void populate_ram_info(MigrationInfo *info, 
MigrationState *s)
 info->ram->remaining = ram_bytes_remaining();
 info->ram->dirty_pages_rate = ram_counters.dirty_pages_rate;
 }
+
+if (migrate_dirty_limit() && dirtylimit_in_service()) {
+info->has_dirty_limit_throttle_us_per_full = true;
+info->dirty_limit_throttle_us_per_full =
+dirtylimit_throttle_us_per_full();
+
+info->has_dirty_limit_us_ring_full = true;
+info->dirty_limit_us_ring_full = dirtylimit_us_ring_full();
+}
 }
 
 static void populate_disk_info(MigrationInfo *info)
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index b362fae..23c3f48 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -358,6 +358,16 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
info->cpu_throttle_percentage);
 }
 
+if (info->has_dirty_limit_throttle_us_per_full) {
+monitor_printf(mon, "dirty-limit throttle time: %" PRIu64 " us\n",
+   info->dirty_limit_throttle_us_per_full);
+}
+
+if (info->has_dirty_limit_us_ring_full) {
+monitor_printf(mon, "dirty-limit ring full time: %" PRIu64 " us\n",
+   info->dirty_limit_us_ring_full);
+}
+
 if (info->has_postcopy_blocktime) {
 monitor_printf(mon, "postcopy blocktime: %u\n",
info->postcopy_blocktime);
diff --git a/qapi/migration.json b/qapi/migration.json
index bc4bc96..c263d54 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -242,6 +242,12 @@
 #   Present and non-empty when migration is blocked.
 #   (since 6.0)
 #
+# @dirty-limit-throttle-us-per-full: Throttle time (us) during the period of
+#dirty ring full (since 7.0)
+#
+# @dirty-limit-us-ring-full: Estimated periodic time (us) of dirty ring full.
+#(since 7.0)
+#
 # Since: 0.14
 ##
 { 'struct': 'MigrationInfo',
@@ -259,7 +265,9 @@
'*postcopy-blocktime' : 'uint32',
'*postcopy-vcpu-blocktime': ['uint32'],
'*compression': 'CompressionStats',
-   '*socket-address': ['SocketAddress'] } }
+   '*socket-address': ['SocketAddress'],
+   '*dirty-limit-throttle-us-per-full': 'int64',
+   '*dirty-limit-us-ring-full': 'int64'} }
 
 ##
 # @query-migrate:
diff --git a/softmmu/dirtylimit.c b/softmmu/dirtylimit.c
index 1fdd8c6..1251b27 100644
--- a/softmmu/dirtylimit.c
+++ b/softmmu/dirtylimit.c
@@ -546,6 +546,28 @@ static struct DirtyLimitInfo *dirtylimit_query_vcpu(int 
cpu_index)
 return info;
 }
 
+/* Pick up first vcpu throttle time by default */
+int64_t dirtylimit_throttle_us_per_full(void)
+{
+CPUState *cpu = first_cpu;
+return cpu->throttle_us_per_full;
+}
+
+/*
+ * Estimate dirty ring full time under current dirty page rate.
+ * Return -1 if guest doesn't dirty memory.
+ */
+int64_t dirtylimit_us_ring_full(void)
+{
+uint64_t curr_rate = vcpu_dirty_rate_get(0);
+
+if (!curr_rate) {
+return -1;
+}
+
+return dirtylimit_dirty_ring_full_time(curr_rate);
+}
+
 static struct DirtyLimitInfoList *dirtylimit_query_all(void)
 {
 int i, index;
-- 
1.8.3.1




[PATCH v1 7/8] tests/migration: Introduce dirty-ring-size option into guestperf

2022-09-01 Thread huangy81
From: Hyman Huang(黄勇) 

Guestperf tool does not enable diry ring feature when test
migration by default.

To support dirty ring migration performance test, introduce
dirty-ring-size option into guestperf tools, which ranges in
[1024, 65536].

To set dirty ring size with 4096 during migration test:
$ ./tests/migration/guestperf.py --dirty-ring-size 4096 xxx

Signed-off-by: Hyman Huang(黄勇) 
---
 tests/migration/guestperf/engine.py   | 7 ++-
 tests/migration/guestperf/hardware.py | 8 ++--
 tests/migration/guestperf/shell.py| 7 ++-
 3 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/tests/migration/guestperf/engine.py 
b/tests/migration/guestperf/engine.py
index 87a6ab2..2b98f00 100644
--- a/tests/migration/guestperf/engine.py
+++ b/tests/migration/guestperf/engine.py
@@ -304,7 +304,6 @@ def _get_common_args(self, hardware, tunnelled=False):
 cmdline = "'" + cmdline + "'"
 
 argv = [
-"-accel", "kvm",
 "-cpu", "host",
 "-kernel", self._kernel,
 "-initrd", self._initrd,
@@ -315,6 +314,12 @@ def _get_common_args(self, hardware, tunnelled=False):
 "-smp", str(hardware._cpus),
 ]
 
+if hardware._dirty_ring_size:
+argv.extend(["-accel", "kvm,dirty-ring-size=%s" %
+ hardware._dirty_ring_size])
+else:
+argv.extend(["-accel", "kvm"])
+
 if self._debug:
 argv.extend(["-device", "sga"])
 
diff --git a/tests/migration/guestperf/hardware.py 
b/tests/migration/guestperf/hardware.py
index 3145785..f779cc0 100644
--- a/tests/migration/guestperf/hardware.py
+++ b/tests/migration/guestperf/hardware.py
@@ -23,7 +23,8 @@ def __init__(self, cpus=1, mem=1,
  src_cpu_bind=None, src_mem_bind=None,
  dst_cpu_bind=None, dst_mem_bind=None,
  prealloc_pages = False,
- huge_pages=False, locked_pages=False):
+ huge_pages=False, locked_pages=False,
+ dirty_ring_size=0):
 self._cpus = cpus
 self._mem = mem # GiB
 self._src_mem_bind = src_mem_bind # List of NUMA nodes
@@ -33,6 +34,7 @@ def __init__(self, cpus=1, mem=1,
 self._prealloc_pages = prealloc_pages
 self._huge_pages = huge_pages
 self._locked_pages = locked_pages
+self._dirty_ring_size = dirty_ring_size
 
 
 def serialize(self):
@@ -46,6 +48,7 @@ def serialize(self):
 "prealloc_pages": self._prealloc_pages,
 "huge_pages": self._huge_pages,
 "locked_pages": self._locked_pages,
+"dirty_ring_size": self._dirty_ring_size,
 }
 
 @classmethod
@@ -59,4 +62,5 @@ def deserialize(cls, data):
 data["dst_mem_bind"],
 data["prealloc_pages"],
 data["huge_pages"],
-data["locked_pages"])
+data["locked_pages"],
+data["dirty_ring_size"])
diff --git a/tests/migration/guestperf/shell.py 
b/tests/migration/guestperf/shell.py
index 8a809e3..559616f 100644
--- a/tests/migration/guestperf/shell.py
+++ b/tests/migration/guestperf/shell.py
@@ -60,6 +60,8 @@ def __init__(self):
 parser.add_argument("--prealloc-pages", dest="prealloc_pages", 
default=False)
 parser.add_argument("--huge-pages", dest="huge_pages", default=False)
 parser.add_argument("--locked-pages", dest="locked_pages", 
default=False)
+parser.add_argument("--dirty-ring-size", dest="dirty_ring_size",
+default=0, type=int)
 
 self._parser = parser
 
@@ -89,7 +91,10 @@ def split_map(value):
 
 locked_pages=args.locked_pages,
 huge_pages=args.huge_pages,
-prealloc_pages=args.prealloc_pages)
+prealloc_pages=args.prealloc_pages,
+
+dirty_ring_size=args.dirty_ring_size)
+
 
 
 class Shell(BaseShell):
-- 
1.8.3.1




[PATCH v1 2/8] qapi/migration: Introduce x-vcpu-dirty-limit parameters

2022-09-01 Thread huangy81
From: Hyman Huang(黄勇) 

Introduce "x-vcpu-dirty-limit" migration parameter used
to limit dirty page rate during live migration.

"x-vcpu-dirty-limit" and "x-vcpu-dirty-limit-period" are
two dirty-limit-related migration parameters, which can
be set before and during live migration by qmp
migrate-set-parameters.

This two parameters are used to help implement the dirty
page rate limit algo of migration.

Signed-off-by: Hyman Huang(黄勇) 
---
 migration/migration.c | 14 ++
 monitor/hmp-cmds.c|  8 
 qapi/migration.json   | 18 +++---
 3 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index a8a8065..a748fe5 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -117,6 +117,7 @@
 #define DEFAULT_MIGRATE_ANNOUNCE_STEP100
 
 #define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD 500 /* ms */
+#define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT1   /* MB/s */
 
 static NotifierList migration_state_notifiers =
 NOTIFIER_LIST_INITIALIZER(migration_state_notifiers);
@@ -967,6 +968,9 @@ MigrationParameters *qmp_query_migrate_parameters(Error 
**errp)
 params->has_x_vcpu_dirty_limit_period = true;
 params->x_vcpu_dirty_limit_period = 
s->parameters.x_vcpu_dirty_limit_period;
 
+params->has_x_vcpu_dirty_limit = true;
+params->x_vcpu_dirty_limit = s->parameters.x_vcpu_dirty_limit;
+
 return params;
 }
 
@@ -1671,6 +1675,10 @@ static void 
migrate_params_test_apply(MigrateSetParameters *params,
 if (params->has_x_vcpu_dirty_limit_period) {
 dest->x_vcpu_dirty_limit_period = params->x_vcpu_dirty_limit_period;
 }
+
+if (params->has_x_vcpu_dirty_limit) {
+dest->x_vcpu_dirty_limit = params->x_vcpu_dirty_limit;
+}
 }
 
 static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
@@ -1797,6 +1805,9 @@ static void migrate_params_apply(MigrateSetParameters 
*params, Error **errp)
 s->parameters.x_vcpu_dirty_limit_period =
 params->x_vcpu_dirty_limit_period;
 }
+if (params->has_x_vcpu_dirty_limit) {
+s->parameters.x_vcpu_dirty_limit = params->x_vcpu_dirty_limit;
+}
 }
 
 void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
@@ -4401,6 +4412,9 @@ static Property migration_properties[] = {
 DEFINE_PROP_UINT64("x-vcpu-dirty-limit-period", MigrationState,
parameters.x_vcpu_dirty_limit_period,
DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD),
+DEFINE_PROP_UINT64("vcpu-dirty-limit", MigrationState,
+   parameters.x_vcpu_dirty_limit,
+   DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT),
 
 /* Migration capabilities */
 DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE),
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 7569859..b362fae 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -536,6 +536,10 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict 
*qdict)
 monitor_printf(mon, "%s: %" PRIu64 " ms\n",
 MigrationParameter_str(MIGRATION_PARAMETER_X_VCPU_DIRTY_LIMIT_PERIOD),
 params->x_vcpu_dirty_limit_period);
+
+monitor_printf(mon, "%s: %" PRIu64 " MB/s\n",
+MigrationParameter_str(MIGRATION_PARAMETER_X_VCPU_DIRTY_LIMIT),
+params->x_vcpu_dirty_limit);
 }
 
 qapi_free_MigrationParameters(params);
@@ -1359,6 +1363,10 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict 
*qdict)
 p->has_x_vcpu_dirty_limit_period = true;
 visit_type_size(v, param, >x_vcpu_dirty_limit_period, );
 break;
+case MIGRATION_PARAMETER_X_VCPU_DIRTY_LIMIT:
+p->has_x_vcpu_dirty_limit = true;
+visit_type_size(v, param, >x_vcpu_dirty_limit, );
+break;
 default:
 assert(0);
 }
diff --git a/qapi/migration.json b/qapi/migration.json
index 332c087..8554d33 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -779,6 +779,9 @@
 # @x-vcpu-dirty-limit-period: Periodic time (ms) of dirty limit during live 
migration.
 # Defaults to 500ms. (Since 7.1)
 #
+# @x-vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration.
+#  Defaults to 1. (Since 7.1)
+#
 # Features:
 # @unstable: Member @x-checkpoint-delay and @x-vcpu-dirty-limit-period
 #are experimental.
@@ -801,7 +804,8 @@
'max-cpu-throttle', 'multifd-compression',
'multifd-zlib-level', 'multifd-zstd-level',
'block-bitmap-mapping',
-   { 'name': 'x-vcpu-dirty-limit-period', 'features': ['unstable'] } ] 
}
+   { 'name': 'x-vcpu-dirty-limit-period', 'features': ['unstable'] },
+   'x-vcpu-dirty-limit'] }
 
 ##
 # @MigrateSetParameters:
@@ -949,6 +953,9 @@
 # @x-vcpu-dirty-limit-period: Periodic time (ms) of dirty limit during live 
migration.
 # Defaults to 500ms. (Since 

Re: [PATCH v7 00/10] parallels: Refactor the code of images checks and fix a bug

2022-09-01 Thread Denis V. Lunev

On 29.08.2022 12:12, Alexander Ivanov wrote:

Fix image inflation when offset in BAT is out of image.

Replace whole BAT syncing by flushing only dirty blocks.

Move all the checks outside the main check function in
separate functions

Use WITH_QEMU_LOCK_GUARD for simplier code.

v7:
1,2: Fix string lengths in the commit messages.
3: Fix a typo in the commit message.

v6:
1: Move the error check inside the loop. Move file size getting
to the function beginning. Skip out-of-image offsets.
2: A new patch - don't let high_off be more than the end of the last cluster.
3: Set data_end without any condition.
7: Move data_end setting to parallels_check_outside_image().
8: Remove s->data_end setting from parallels_check_leak().
Fix 'i' type.

v5:
2: Change the way of data_end fixing.
6,7: Move data_end check to parallels_check_leak().

v4:
1: Move s->data_end fix to parallels_co_check(). Split the check
in parallels_open() and the fix in parallels_co_check() to two patches.
2: A new patch - a part of the patch 1.
Add a fix for data_end to parallels_co_check().
3: Move offset convertation to parallels_set_bat_entry().
4: Fix 'ret' rewriting by bdrv_co_flush() results.
7: Keep 'i' as uint32_t.

v3:

1-8: Fix commit message.

v2:

2: A new patch - a part of the splitted patch 2.
3: Patch order was changed so the replacement is done in parallels_co_check.
Now we use a helper to set BAT entry and mark the block dirty.
4: Revert the condition with s->header_unclean.
5: Move unrelated helper parallels_set_bat_entry creation to a separate patch.
7: Move fragmentation counting code to this function too.
8: Fix an incorrect usage of WITH_QEMU_LOCK_GUARD.


Alexander Ivanov (10):
   parallels: Out of image offset in BAT leads to image inflation
   parallels: Fix high_off calculation in parallels_co_check()
   parallels: Fix data_end after out-of-image check
   parallels: create parallels_set_bat_entry_helper() to assign BAT value
   parallels: Use generic infrastructure for BAT writing in
 parallels_co_check()
   parallels: Move check of unclean image to a separate function
   parallels: Move check of cluster outside image to a separate function
   parallels: Move check of leaks to a separate function
   parallels: Move statistic collection to a separate function
   parallels: Replace qemu_co_mutex_lock by WITH_QEMU_LOCK_GUARD

  block/parallels.c | 193 +-
  1 file changed, 138 insertions(+), 55 deletions(-)


queued, thanks



[PATCH v1 6/8] tests: Add migration dirty-limit capability test

2022-09-01 Thread huangy81
From: Hyman Huang(黄勇) 

Add migration dirty-limit capability test if kernel support
dirty ring.

Migration dirty-limit capability introduce dirty limit
capability, two parameters: x-vcpu-dirty-limit-period and
x-vcpu-dirty-limit are introduced to implement the live
migration with dirty limit.

The test case does the following things:
1. start src, dst vm and enable dirty-limit capability
2. start migrate and set cancel it to check if dirty limit
   stop working.
3. restart dst vm
4. start migrate and enable dirty-limit capability
5. check if migration satisfy the convergence condition
   during pre-switchover phase.

Signed-off-by: Hyman Huang(黄勇) 
---
 tests/qtest/migration-test.c | 154 +++
 1 file changed, 154 insertions(+)

diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 4728d52..f3bfd85 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -2409,6 +2409,158 @@ static void test_vcpu_dirty_limit(void)
 dirtylimit_stop_vm(vm);
 }
 
+static void migrate_dirty_limit_wait_showup(QTestState *from,
+const int64_t period,
+const int64_t value)
+{
+/* Enable dirty limit capability */
+migrate_set_capability(from, "dirty-limit", true);
+
+/* Set dirty limit parameters */
+migrate_set_parameter_int(from, "x-vcpu-dirty-limit-period", period);
+migrate_set_parameter_int(from, "x-vcpu-dirty-limit", value);
+
+/* Make sure migrate can't converge */
+migrate_ensure_non_converge(from);
+
+/* To check limit rate after precopy */
+migrate_set_capability(from, "pause-before-switchover", true);
+
+/* Wait for the serial output from the source */
+wait_for_serial("src_serial");
+}
+
+/*
+ * This test does:
+ *  source   target
+ *   migrate_incoming
+ * migrate
+ * migrate_cancel
+ *   restart target
+ * migrate
+ *
+ *  And see that if dirty limit works correctly
+ */
+static void test_migrate_dirty_limit(void)
+{
+g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+QTestState *from, *to;
+int64_t remaining, throttle_us_per_full;
+/*
+ * We want the test to be stable and as fast as possible.
+ * E.g., with 1Gb/s bandwith migration may pass without dirty limit,
+ * so we need to decrease a bandwidth.
+ */
+const int64_t dirtylimit_period = 1000, dirtylimit_value = 50;
+const int64_t max_bandwidth = 4; /* ~400Mb/s */
+const int64_t downtime_limit = 250; /* 250ms */
+/*
+ * We migrate through unix-socket (> 500Mb/s).
+ * Thus, expected migration speed ~= bandwidth limit (< 500Mb/s).
+ * So, we can predict expected_threshold
+ */
+const int64_t expected_threshold = max_bandwidth * downtime_limit / 1000;
+int max_try_count = 10;
+MigrateCommon args = {
+.start = {
+.hide_stderr = true,
+.use_dirty_ring = true,
+},
+.listen_uri = uri,
+.connect_uri = uri,
+};
+
+/* Start src, dst vm */
+if (test_migrate_start(, , args.listen_uri, )) {
+return;
+}
+
+/* Prepare for dirty limit migration and wait src vm show up */
+migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value);
+
+/* Start migrate */
+migrate_qmp(from, uri, "{}");
+
+/* Wait for dirty limit throttle begin */
+throttle_us_per_full = 0;
+while (throttle_us_per_full == 0) {
+throttle_us_per_full =
+read_migrate_property_int(from, 
"dirty-limit-throttle-us-per-full");
+usleep(100);
+g_assert_false(got_stop);
+}
+
+/* Now cancel migrate and wait for dirty limit throttle switch off */
+migrate_cancel(from);
+wait_for_migration_status(from, "cancelled", NULL);
+
+/* Check if dirty limit throttle switched off, set timeout 1ms */
+do {
+throttle_us_per_full =
+read_migrate_property_int(from, 
"dirty-limit-throttle-us-per-full");
+usleep(100);
+g_assert_false(got_stop);
+} while (throttle_us_per_full != 0 && --max_try_count);
+
+/* Assert dirty limit is not in service */
+g_assert_cmpint(throttle_us_per_full, ==, 0);
+
+args = (MigrateCommon) {
+.start = {
+.only_target = true,
+.use_dirty_ring = true,
+},
+.listen_uri = uri,
+.connect_uri = uri,
+};
+
+/* Restart dst vm, src vm already show up so we needn't wait anymore */
+if (test_migrate_start(, , args.listen_uri, )) {
+return;
+}
+
+/* Start migrate */
+migrate_qmp(from, uri, "{}");
+
+/* Wait for dirty limit throttle begin */
+throttle_us_per_full = 0;
+while (throttle_us_per_full == 0) {
+throttle_us_per_full =
+read_migrate_property_int(from, 
"dirty-limit-throttle-us-per-full");

[PATCH v1 1/8] qapi/migration: Introduce x-vcpu-dirty-limit-period parameter

2022-09-01 Thread huangy81
From: Hyman Huang(黄勇) 

Introduce "x-vcpu-dirty-limit-period" migration experimental
parameter, which is used to make dirtyrate calculation period
configurable.

Signed-off-by: Hyman Huang(黄勇) 
---
 migration/migration.c | 16 
 monitor/hmp-cmds.c|  8 
 qapi/migration.json   | 31 ---
 3 files changed, 48 insertions(+), 7 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index bb8bbdd..a8a8065 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -116,6 +116,8 @@
 #define DEFAULT_MIGRATE_ANNOUNCE_ROUNDS5
 #define DEFAULT_MIGRATE_ANNOUNCE_STEP100
 
+#define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD 500 /* ms */
+
 static NotifierList migration_state_notifiers =
 NOTIFIER_LIST_INITIALIZER(migration_state_notifiers);
 
@@ -962,6 +964,9 @@ MigrationParameters *qmp_query_migrate_parameters(Error 
**errp)
s->parameters.block_bitmap_mapping);
 }
 
+params->has_x_vcpu_dirty_limit_period = true;
+params->x_vcpu_dirty_limit_period = 
s->parameters.x_vcpu_dirty_limit_period;
+
 return params;
 }
 
@@ -1662,6 +1667,10 @@ static void 
migrate_params_test_apply(MigrateSetParameters *params,
 dest->has_block_bitmap_mapping = true;
 dest->block_bitmap_mapping = params->block_bitmap_mapping;
 }
+
+if (params->has_x_vcpu_dirty_limit_period) {
+dest->x_vcpu_dirty_limit_period = params->x_vcpu_dirty_limit_period;
+}
 }
 
 static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
@@ -1784,6 +1793,10 @@ static void migrate_params_apply(MigrateSetParameters 
*params, Error **errp)
 QAPI_CLONE(BitmapMigrationNodeAliasList,
params->block_bitmap_mapping);
 }
+if (params->has_x_vcpu_dirty_limit_period) {
+s->parameters.x_vcpu_dirty_limit_period =
+params->x_vcpu_dirty_limit_period;
+}
 }
 
 void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
@@ -4385,6 +4398,9 @@ static Property migration_properties[] = {
 DEFINE_PROP_STRING("tls-creds", MigrationState, parameters.tls_creds),
 DEFINE_PROP_STRING("tls-hostname", MigrationState, 
parameters.tls_hostname),
 DEFINE_PROP_STRING("tls-authz", MigrationState, parameters.tls_authz),
+DEFINE_PROP_UINT64("x-vcpu-dirty-limit-period", MigrationState,
+   parameters.x_vcpu_dirty_limit_period,
+   DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD),
 
 /* Migration capabilities */
 DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE),
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index c6cd6f9..7569859 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -532,6 +532,10 @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict 
*qdict)
 }
 }
 }
+
+monitor_printf(mon, "%s: %" PRIu64 " ms\n",
+MigrationParameter_str(MIGRATION_PARAMETER_X_VCPU_DIRTY_LIMIT_PERIOD),
+params->x_vcpu_dirty_limit_period);
 }
 
 qapi_free_MigrationParameters(params);
@@ -1351,6 +1355,10 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict 
*qdict)
 error_setg(, "The block-bitmap-mapping parameter can only be set "
"through QMP");
 break;
+case MIGRATION_PARAMETER_X_VCPU_DIRTY_LIMIT_PERIOD:
+p->has_x_vcpu_dirty_limit_period = true;
+visit_type_size(v, param, >x_vcpu_dirty_limit_period, );
+break;
 default:
 assert(0);
 }
diff --git a/qapi/migration.json b/qapi/migration.json
index 81185d4..332c087 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -776,8 +776,12 @@
 #block device name if there is one, and to their node 
name
 #otherwise. (Since 5.2)
 #
+# @x-vcpu-dirty-limit-period: Periodic time (ms) of dirty limit during live 
migration.
+# Defaults to 500ms. (Since 7.1)
+#
 # Features:
-# @unstable: Member @x-checkpoint-delay is experimental.
+# @unstable: Member @x-checkpoint-delay and @x-vcpu-dirty-limit-period
+#are experimental.
 #
 # Since: 2.4
 ##
@@ -795,8 +799,9 @@
'multifd-channels',
'xbzrle-cache-size', 'max-postcopy-bandwidth',
'max-cpu-throttle', 'multifd-compression',
-   'multifd-zlib-level' ,'multifd-zstd-level',
-   'block-bitmap-mapping' ] }
+   'multifd-zlib-level', 'multifd-zstd-level',
+   'block-bitmap-mapping',
+   { 'name': 'x-vcpu-dirty-limit-period', 'features': ['unstable'] } ] 
}
 
 ##
 # @MigrateSetParameters:
@@ -941,8 +946,12 @@
 #block device name if there is one, and to their node 
name
 #otherwise. (Since 5.2)
 #
+# @x-vcpu-dirty-limit-period: Periodic time (ms) of dirty limit during live 
migration.
+# Defaults to 500ms. 

[PATCH 39/42] hw/isa/piix: Unexport PIIXState

2022-09-01 Thread Bernhard Beschow
The - deliberately exported - components can still be accessed
via QOM properties.

Signed-off-by: Bernhard Beschow 
---
 hw/isa/piix.c | 52 +
 include/hw/southbridge/piix.h | 54 ---
 2 files changed, 52 insertions(+), 54 deletions(-)

diff --git a/hw/isa/piix.c b/hw/isa/piix.c
index e413d7e792..c503a6e836 100644
--- a/hw/isa/piix.c
+++ b/hw/isa/piix.c
@@ -26,20 +26,72 @@
 #include "qemu/osdep.h"
 #include "qemu/range.h"
 #include "qapi/error.h"
+#include "qom/object.h"
+#include "hw/acpi/piix4.h"
 #include "hw/dma/i8257.h"
+#include "hw/ide/pci.h"
 #include "hw/intc/i8259.h"
 #include "hw/southbridge/piix.h"
 #include "hw/timer/i8254.h"
 #include "hw/irq.h"
 #include "hw/qdev-properties.h"
 #include "hw/isa/isa.h"
+#include "hw/pci/pci.h"
+#include "hw/qdev-properties.h"
+#include "hw/rtc/mc146818rtc.h"
+#include "hw/usb/hcd-uhci.h"
 #include "hw/xen/xen.h"
 #include "sysemu/runstate.h"
 #include "migration/vmstate.h"
 #include "hw/acpi/acpi_aml_interface.h"
 
+#define PIIX_NUM_PIRQS  4ULL/* PIRQ[A-D] */
 #define XEN_PIIX_NUM_PIRQS  128ULL
 
+struct PIIXState {
+PCIDevice dev;
+
+/*
+ * bitmap to track pic levels.
+ * The pic level is the logical OR of all the PCI irqs mapped to it
+ * So one PIC level is tracked by PIIX_NUM_PIRQS bits.
+ *
+ * PIRQ is mapped to PIC pins, we track it by
+ * PIIX_NUM_PIRQS * ISA_NUM_IRQS = 64 bits with
+ * pic_irq * PIIX_NUM_PIRQS + pirq
+ */
+#if ISA_NUM_IRQS * PIIX_NUM_PIRQS > 64
+#error "unable to encode pic state in 64bit in pic_levels."
+#endif
+uint64_t pic_levels;
+
+/* This member isn't used. Just for save/load compatibility */
+int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
+uint8_t pci_irq_reset_mappings[PIIX_NUM_PIRQS];
+
+ISAPICState pic;
+RTCState rtc;
+PCIIDEState ide;
+UHCIState uhci;
+PIIX4PMState pm;
+
+uint32_t smb_io_base;
+
+/* Reset Control Register contents */
+uint8_t rcr;
+
+/* IO memory region for Reset Control Register (PIIX_RCR_IOPORT) */
+MemoryRegion rcr_mem;
+
+bool has_acpi;
+bool has_usb;
+bool smm_enabled;
+};
+typedef struct PIIXState PIIXState;
+
+DECLARE_INSTANCE_CHECKER(PIIXState, PIIX_PCI_DEVICE,
+ TYPE_PIIX3_PCI_DEVICE)
+
 static void piix_set_irq_pic(PIIXState *piix, int pic_irq)
 {
 qemu_set_irq(piix->pic.in_irqs[pic_irq],
diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h
index c9fa0f1aa6..0edc23710c 100644
--- a/include/hw/southbridge/piix.h
+++ b/include/hw/southbridge/piix.h
@@ -12,14 +12,6 @@
 #ifndef HW_SOUTHBRIDGE_PIIX_H
 #define HW_SOUTHBRIDGE_PIIX_H
 
-#include "hw/pci/pci.h"
-#include "qom/object.h"
-#include "hw/acpi/piix4.h"
-#include "hw/ide/pci.h"
-#include "hw/intc/i8259.h"
-#include "hw/rtc/mc146818rtc.h"
-#include "hw/usb/hcd-uhci.h"
-
 /* PIRQRC[A:D]: PIRQx Route Control Registers */
 #define PIIX_PIRQCA 0x60
 #define PIIX_PIRQCB 0x61
@@ -32,53 +24,7 @@
  */
 #define PIIX_RCR_IOPORT 0xcf9
 
-#define PIIX_NUM_PIRQS  4ULL/* PIRQ[A-D] */
-
-struct PIIXState {
-PCIDevice dev;
-
-/*
- * bitmap to track pic levels.
- * The pic level is the logical OR of all the PCI irqs mapped to it
- * So one PIC level is tracked by PIIX_NUM_PIRQS bits.
- *
- * PIRQ is mapped to PIC pins, we track it by
- * PIIX_NUM_PIRQS * ISA_NUM_IRQS = 64 bits with
- * pic_irq * PIIX_NUM_PIRQS + pirq
- */
-#if ISA_NUM_IRQS * PIIX_NUM_PIRQS > 64
-#error "unable to encode pic state in 64bit in pic_levels."
-#endif
-uint64_t pic_levels;
-
-/* This member isn't used. Just for save/load compatibility */
-int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
-uint8_t pci_irq_reset_mappings[PIIX_NUM_PIRQS];
-
-ISAPICState pic;
-RTCState rtc;
-PCIIDEState ide;
-UHCIState uhci;
-PIIX4PMState pm;
-
-uint32_t smb_io_base;
-
-/* Reset Control Register contents */
-uint8_t rcr;
-
-/* IO memory region for Reset Control Register (PIIX_RCR_IOPORT) */
-MemoryRegion rcr_mem;
-
-bool has_acpi;
-bool has_usb;
-bool smm_enabled;
-};
-typedef struct PIIXState PIIXState;
-
 #define TYPE_PIIX3_PCI_DEVICE "pci-piix3"
-DECLARE_INSTANCE_CHECKER(PIIXState, PIIX_PCI_DEVICE,
- TYPE_PIIX3_PCI_DEVICE)
-
 #define TYPE_PIIX3_DEVICE "PIIX3"
 #define TYPE_PIIX3_XEN_DEVICE "PIIX3-xen"
 #define TYPE_PIIX4_PCI_DEVICE "piix4-isa"
-- 
2.37.3




[PATCH 37/42] hw/isa/piix: Rename functions to be shared for interrupt triggering

2022-09-01 Thread Bernhard Beschow
PIIX4 will get the same optimizations which are already implemented for
PIIX3.

Signed-off-by: Bernhard Beschow 
---
 hw/isa/piix.c | 56 +--
 1 file changed, 28 insertions(+), 28 deletions(-)

diff --git a/hw/isa/piix.c b/hw/isa/piix.c
index af6d920eff..1d516de5cc 100644
--- a/hw/isa/piix.c
+++ b/hw/isa/piix.c
@@ -40,47 +40,47 @@
 
 #define XEN_PIIX_NUM_PIRQS  128ULL
 
-static void piix3_set_irq_pic(PIIXState *piix3, int pic_irq)
+static void piix_set_irq_pic(PIIXState *piix, int pic_irq)
 {
-qemu_set_irq(piix3->pic.in_irqs[pic_irq],
- !!(piix3->pic_levels &
+qemu_set_irq(piix->pic.in_irqs[pic_irq],
+ !!(piix->pic_levels &
 (((1ULL << PIIX_NUM_PIRQS) - 1) <<
  (pic_irq * PIIX_NUM_PIRQS;
 }
 
-static void piix3_set_irq_level_internal(PIIXState *piix3, int pirq, int level)
+static void piix_set_irq_level_internal(PIIXState *piix, int pirq, int level)
 {
 int pic_irq;
 uint64_t mask;
 
-pic_irq = piix3->dev.config[PIIX_PIRQCA + pirq];
+pic_irq = piix->dev.config[PIIX_PIRQCA + pirq];
 if (pic_irq >= ISA_NUM_IRQS) {
 return;
 }
 
 mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq);
-piix3->pic_levels &= ~mask;
-piix3->pic_levels |= mask * !!level;
+piix->pic_levels &= ~mask;
+piix->pic_levels |= mask * !!level;
 }
 
-static void piix3_set_irq_level(PIIXState *piix3, int pirq, int level)
+static void piix_set_irq_level(PIIXState *piix, int pirq, int level)
 {
 int pic_irq;
 
-pic_irq = piix3->dev.config[PIIX_PIRQCA + pirq];
+pic_irq = piix->dev.config[PIIX_PIRQCA + pirq];
 if (pic_irq >= ISA_NUM_IRQS) {
 return;
 }
 
-piix3_set_irq_level_internal(piix3, pirq, level);
+piix_set_irq_level_internal(piix, pirq, level);
 
-piix3_set_irq_pic(piix3, pic_irq);
+piix_set_irq_pic(piix, pic_irq);
 }
 
-static void piix3_set_irq(void *opaque, int pirq, int level)
+static void piix_set_irq(void *opaque, int pirq, int level)
 {
-PIIXState *piix3 = opaque;
-piix3_set_irq_level(piix3, pirq, level);
+PIIXState *piix = opaque;
+piix_set_irq_level(piix, pirq, level);
 }
 
 static void piix4_set_irq(void *opaque, int irq_num, int level)
@@ -157,29 +157,29 @@ static PCIINTxRoute piix3_route_intx_pin_to_irq(void 
*opaque, int pin)
 }
 
 /* irq routing is changed. so rebuild bitmap */
-static void piix3_update_irq_levels(PIIXState *piix3)
+static void piix_update_irq_levels(PIIXState *piix)
 {
-PCIBus *bus = pci_get_bus(>dev);
+PCIBus *bus = pci_get_bus(>dev);
 int pirq;
 
-piix3->pic_levels = 0;
+piix->pic_levels = 0;
 for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
-piix3_set_irq_level(piix3, pirq, pci_bus_get_irq_level(bus, pirq));
+piix_set_irq_level(piix, pirq, pci_bus_get_irq_level(bus, pirq));
 }
 }
 
-static void piix3_write_config(PCIDevice *dev,
-   uint32_t address, uint32_t val, int len)
+static void piix_write_config(PCIDevice *dev, uint32_t address, uint32_t val,
+  int len)
 {
 pci_default_write_config(dev, address, val, len);
 if (ranges_overlap(address, len, PIIX_PIRQCA, 4)) {
-PIIXState *piix3 = PIIX_PCI_DEVICE(dev);
+PIIXState *piix = PIIX_PCI_DEVICE(dev);
 int pic_irq;
 
-pci_bus_fire_intx_routing_notifier(pci_get_bus(>dev));
-piix3_update_irq_levels(piix3);
+pci_bus_fire_intx_routing_notifier(pci_get_bus(>dev));
+piix_update_irq_levels(piix);
 for (pic_irq = 0; pic_irq < ISA_NUM_IRQS; pic_irq++) {
-piix3_set_irq_pic(piix3, pic_irq);
+piix_set_irq_pic(piix, pic_irq);
 }
 }
 }
@@ -201,7 +201,7 @@ static void piix3_write_config_xen(PCIDevice *dev,
 }
 }
 
-piix3_write_config(dev, address, val, len);
+piix_write_config(dev, address, val, len);
 }
 
 static void piix_reset(DeviceState *dev)
@@ -261,7 +261,7 @@ static int piix3_post_load(void *opaque, int version_id)
  */
 piix3->pic_levels = 0;
 for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
-piix3_set_irq_level_internal(piix3, pirq,
+piix_set_irq_level_internal(piix3, pirq,
 pci_bus_get_irq_level(pci_get_bus(>dev), pirq));
 }
 return 0;
@@ -511,7 +511,7 @@ static void piix3_realize(PCIDevice *dev, Error **errp)
 return;
 }
 
-pci_bus_irqs(pci_bus, piix3_set_irq, piix3_pci_slot_get_pirq,
+pci_bus_irqs(pci_bus, piix_set_irq, piix3_pci_slot_get_pirq,
  piix3, PIIX_NUM_PIRQS);
 pci_bus_set_route_irq_fn(pci_bus, piix3_route_intx_pin_to_irq);
 }
@@ -520,7 +520,7 @@ static void piix3_class_init(ObjectClass *klass, void *data)
 {
 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
-k->config_write = piix3_write_config;
+k->config_write = piix_write_config;
 k->realize = piix3_realize;
 }
 
-- 
2.37.3




[PATCH 34/42] hw/isa/piix3: Merge hw/isa/piix4.c

2022-09-01 Thread Bernhard Beschow
Now that the PIIX3 and PIIX4 device models are sufficiently consolidated

Signed-off-by: Bernhard Beschow 
---
 MAINTAINERS |   6 +-
 configs/devices/mips-softmmu/common.mak |   2 +-
 hw/i386/Kconfig |   2 +-
 hw/isa/Kconfig  |  12 +-
 hw/isa/meson.build  |   3 +-
 hw/isa/{piix3.c => piix.c}  | 185 ++
 hw/isa/piix4.c  | 314 
 7 files changed, 192 insertions(+), 332 deletions(-)
 rename hw/isa/{piix3.c => piix.c} (73%)
 delete mode 100644 hw/isa/piix4.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 5ce4227ff6..f727f64a25 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1228,7 +1228,7 @@ Malta
 M: Philippe Mathieu-Daudé 
 R: Aurelien Jarno 
 S: Odd Fixes
-F: hw/isa/piix4.c
+F: hw/isa/piix.c
 F: hw/acpi/piix4.c
 F: hw/mips/malta.c
 F: hw/mips/gt64xxx_pci.c
@@ -1643,7 +1643,7 @@ F: hw/pci-host/pam.c
 F: include/hw/pci-host/i440fx.h
 F: include/hw/pci-host/q35.h
 F: include/hw/pci-host/pam.h
-F: hw/isa/piix3.c
+F: hw/isa/piix.c
 F: hw/isa/lpc_ich9.c
 F: hw/i2c/smbus_ich9.c
 F: hw/acpi/piix4.c
@@ -2302,7 +2302,7 @@ PIIX4 South Bridge (i82371AB)
 M: Hervé Poussineau 
 M: Philippe Mathieu-Daudé 
 S: Maintained
-F: hw/isa/piix4.c
+F: hw/isa/piix.c
 F: include/hw/southbridge/piix.h
 
 Firmware configuration (fw_cfg)
diff --git a/configs/devices/mips-softmmu/common.mak 
b/configs/devices/mips-softmmu/common.mak
index 416161f833..ef3b7390a6 100644
--- a/configs/devices/mips-softmmu/common.mak
+++ b/configs/devices/mips-softmmu/common.mak
@@ -21,7 +21,7 @@ CONFIG_ACPI=y
 CONFIG_ACPI_PIIX4=y
 CONFIG_APM=y
 CONFIG_I8257=y
-CONFIG_PIIX4=y
+CONFIG_PIIX=y
 CONFIG_IDE_ISA=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_I8259=y
diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
index dd247f215c..295693b32b 100644
--- a/hw/i386/Kconfig
+++ b/hw/i386/Kconfig
@@ -73,7 +73,7 @@ config I440FX
 select PC_ACPI
 select ACPI_SMBUS
 select PCI_I440FX
-select PIIX3
+select PIIX
 select DIMM
 select SMBIOS
 select FW_CFG_DMA
diff --git a/hw/isa/Kconfig b/hw/isa/Kconfig
index 1aa10f84f2..000c2312ab 100644
--- a/hw/isa/Kconfig
+++ b/hw/isa/Kconfig
@@ -31,17 +31,7 @@ config PC87312
 select FDC_ISA
 select IDE_ISA
 
-config PIIX3
-bool
-select ACPI_PIIX4
-select I8257
-select I8259
-select IDE_PIIX
-select ISA_BUS
-select MC146818RTC
-select USB_UHCI
-
-config PIIX4
+config PIIX
 bool
 # For historical reasons, SuperIO devices are created in the board
 # for PIIX4.
diff --git a/hw/isa/meson.build b/hw/isa/meson.build
index 8bf678ca0a..314bbd0860 100644
--- a/hw/isa/meson.build
+++ b/hw/isa/meson.build
@@ -3,8 +3,7 @@ softmmu_ss.add(when: 'CONFIG_I82378', if_true: 
files('i82378.c'))
 softmmu_ss.add(when: 'CONFIG_ISA_BUS', if_true: files('isa-bus.c'))
 softmmu_ss.add(when: 'CONFIG_ISA_SUPERIO', if_true: files('isa-superio.c'))
 softmmu_ss.add(when: 'CONFIG_PC87312', if_true: files('pc87312.c'))
-softmmu_ss.add(when: 'CONFIG_PIIX3', if_true: files('piix3.c'))
-softmmu_ss.add(when: 'CONFIG_PIIX4', if_true: files('piix4.c'))
+softmmu_ss.add(when: 'CONFIG_PIIX', if_true: files('piix.c'))
 softmmu_ss.add(when: 'CONFIG_SMC37C669', if_true: files('smc37c669-superio.c'))
 softmmu_ss.add(when: 'CONFIG_VT82C686', if_true: files('vt82c686.c'))
 
diff --git a/hw/isa/piix3.c b/hw/isa/piix.c
similarity index 73%
rename from hw/isa/piix3.c
rename to hw/isa/piix.c
index 75705a1fc1..5d3715b64e 100644
--- a/hw/isa/piix3.c
+++ b/hw/isa/piix.c
@@ -2,6 +2,7 @@
  * QEMU PIIX PCI ISA Bridge Emulation
  *
  * Copyright (c) 2006 Fabrice Bellard
+ * Copyright (c) 2018 Hervé Poussineau
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to 
deal
@@ -26,7 +27,9 @@
 #include "qemu/range.h"
 #include "qapi/error.h"
 #include "hw/dma/i8257.h"
+#include "hw/intc/i8259.h"
 #include "hw/southbridge/piix.h"
+#include "hw/timer/i8254.h"
 #include "hw/irq.h"
 #include "hw/qdev-properties.h"
 #include "hw/isa/isa.h"
@@ -80,6 +83,27 @@ static void piix3_set_irq(void *opaque, int pirq, int level)
 piix3_set_irq_level(piix3, pirq, level);
 }
 
+static void piix4_set_irq(void *opaque, int irq_num, int level)
+{
+int i, pic_irq, pic_level;
+PIIXState *s = opaque;
+PCIBus *bus = pci_get_bus(>dev);
+
+/* now we change the pic irq level according to the piix irq mappings */
+/* XXX: optimize */
+pic_irq = s->dev.config[PIIX_PIRQCA + irq_num];
+if (pic_irq < ISA_NUM_IRQS) {
+/* The pic level is the logical OR of all the PCI irqs mapped to it. */
+pic_level = 0;
+for (i = 0; i < PIIX_NUM_PIRQS; i++) {
+if (pic_irq == s->dev.config[PIIX_PIRQCA + i]) {
+pic_level |= pci_bus_get_irq_level(bus, i);
+}
+}
+qemu_set_irq(s->pic.in_irqs[pic_irq], 

[PATCH 40/42] hw/isa/piix: Share PIIX3 base class with PIIX4

2022-09-01 Thread Bernhard Beschow
Having a common base class allows for substituting PIIX3 with PIIX4
and vice versa. Moreover, it makes PIIX4 implement the
acpi-dev-aml-interface.

Signed-off-by: Bernhard Beschow 
---
 hw/isa/piix.c | 53 +++
 1 file changed, 24 insertions(+), 29 deletions(-)

diff --git a/hw/isa/piix.c b/hw/isa/piix.c
index c503a6e836..25b86ddf17 100644
--- a/hw/isa/piix.c
+++ b/hw/isa/piix.c
@@ -473,13 +473,12 @@ static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml 
*scope)
 }
 }
 
-static void pci_piix3_init(Object *obj)
+static void pci_piix_init(Object *obj)
 {
 PIIXState *d = PIIX_PCI_DEVICE(obj);
 
 object_initialize_child(obj, "pic", >pic, TYPE_ISA_PIC);
 object_initialize_child(obj, "rtc", >rtc, TYPE_MC146818_RTC);
-object_initialize_child(obj, "ide", >ide, "piix3-ide");
 }
 
 static Property pci_piix_props[] = {
@@ -494,7 +493,7 @@ static Property pci_piix_props[] = {
 DEFINE_PROP_END_OF_LIST(),
 };
 
-static void pci_piix3_class_init(ObjectClass *klass, void *data)
+static void pci_piix_class_init(ObjectClass *klass, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(klass);
 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -502,11 +501,8 @@ static void pci_piix3_class_init(ObjectClass *klass, void 
*data)
 
 dc->reset   = piix_reset;
 dc->desc= "ISA bridge";
-dc->vmsd= _piix3;
 dc->hotpluggable   = false;
 k->vendor_id= PCI_VENDOR_ID_INTEL;
-/* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
-k->device_id= PCI_DEVICE_ID_INTEL_82371SB_0;
 k->class_id = PCI_CLASS_BRIDGE_ISA;
 /*
  * Reason: part of PIIX3 southbridge, needs to be wired up by
@@ -517,13 +513,13 @@ static void pci_piix3_class_init(ObjectClass *klass, void 
*data)
 adevc->build_dev_aml = build_pci_isa_aml;
 }
 
-static const TypeInfo piix3_pci_type_info = {
+static const TypeInfo piix_pci_type_info = {
 .name = TYPE_PIIX3_PCI_DEVICE,
 .parent = TYPE_PCI_DEVICE,
 .instance_size = sizeof(PIIXState),
-.instance_init = pci_piix3_init,
+.instance_init = pci_piix_init,
 .abstract = true,
-.class_init = pci_piix3_class_init,
+.class_init = pci_piix_class_init,
 .interfaces = (InterfaceInfo[]) {
 { INTERFACE_CONVENTIONAL_PCI_DEVICE },
 { TYPE_ACPI_DEV_AML_IF },
@@ -547,17 +543,29 @@ static void piix3_realize(PCIDevice *dev, Error **errp)
 pci_bus_set_route_irq_fn(pci_bus, piix3_route_intx_pin_to_irq);
 }
 
+static void piix3_init(Object *obj)
+{
+PIIXState *d = PIIX_PCI_DEVICE(obj);
+
+object_initialize_child(obj, "ide", >ide, "piix3-ide");
+}
+
 static void piix3_class_init(ObjectClass *klass, void *data)
 {
+DeviceClass *dc = DEVICE_CLASS(klass);
 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
 k->config_write = piix_write_config;
 k->realize = piix3_realize;
+/* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
+k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0;
+dc->vmsd = _piix3;
 }
 
 static const TypeInfo piix3_info = {
 .name  = TYPE_PIIX3_DEVICE,
 .parent= TYPE_PIIX3_PCI_DEVICE,
+.instance_init = piix3_init,
 .class_init= piix3_class_init,
 };
 
@@ -584,15 +592,20 @@ static void piix3_xen_realize(PCIDevice *dev, Error 
**errp)
 
 static void piix3_xen_class_init(ObjectClass *klass, void *data)
 {
+DeviceClass *dc = DEVICE_CLASS(klass);
 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
 k->config_write = piix3_write_config_xen;
 k->realize = piix3_xen_realize;
+/* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
+k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0;
+dc->vmsd = _piix3;
 }
 
 static const TypeInfo piix3_xen_info = {
 .name  = TYPE_PIIX3_XEN_DEVICE,
 .parent= TYPE_PIIX3_PCI_DEVICE,
+.instance_init = piix3_init,
 .class_init= piix3_xen_class_init,
 };
 
@@ -624,8 +637,6 @@ static void piix4_init(Object *obj)
 {
 PIIXState *s = PIIX_PCI_DEVICE(obj);
 
-object_initialize_child(obj, "pic", >pic, TYPE_ISA_PIC);
-object_initialize_child(obj, "rtc", >rtc, TYPE_MC146818_RTC);
 object_initialize_child(obj, "ide", >ide, "piix4-ide");
 }
 
@@ -636,36 +647,20 @@ static void piix4_class_init(ObjectClass *klass, void 
*data)
 
 k->config_write = piix_write_config;
 k->realize = piix4_realize;
-k->vendor_id = PCI_VENDOR_ID_INTEL;
 k->device_id = PCI_DEVICE_ID_INTEL_82371AB_0;
-k->class_id = PCI_CLASS_BRIDGE_ISA;
-dc->reset = piix_reset;
-dc->desc = "ISA bridge";
 dc->vmsd = _piix4;
-/*
- * Reason: part of PIIX4 southbridge, needs to be wired up,
- * e.g. by mips_malta_init()
- */
-dc->user_creatable = false;
-dc->hotpluggable = false;
-device_class_set_props(dc, pci_piix_props);
 }
 
 static const TypeInfo piix4_info = {
 .name  = TYPE_PIIX4_PCI_DEVICE,
-.parent= TYPE_PCI_DEVICE,
-.instance_size = sizeof(PIIXState),
+.parent

[PATCH 32/42] hw/isa/piix4: Rename wrongly named method

2022-09-01 Thread Bernhard Beschow
This method post-loads the southbridge, not the IDE device.

Signed-off-by: Bernhard Beschow 
---
 hw/isa/piix4.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c
index e682370887..72bd9ad74d 100644
--- a/hw/isa/piix4.c
+++ b/hw/isa/piix4.c
@@ -128,7 +128,7 @@ static void piix4_isa_reset(DeviceState *dev)
 d->rcr = 0;
 }
 
-static int piix4_ide_post_load(void *opaque, int version_id)
+static int piix4_post_load(void *opaque, int version_id)
 {
 PIIXState *s = opaque;
 
@@ -143,7 +143,7 @@ static const VMStateDescription vmstate_piix4 = {
 .name = "PIIX4",
 .version_id = 3,
 .minimum_version_id = 2,
-.post_load = piix4_ide_post_load,
+.post_load = piix4_post_load,
 .fields = (VMStateField[]) {
 VMSTATE_PCI_DEVICE(dev, PIIXState),
 VMSTATE_UINT8_V(rcr, PIIXState, 3),
-- 
2.37.3




[PATCH 22/42] hw/mips/malta: Reuse dev variable

2022-09-01 Thread Bernhard Beschow
While at it, move the assignments closer to where they are used.

Signed-off-by: Bernhard Beschow 
---
 hw/mips/malta.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/hw/mips/malta.c b/hw/mips/malta.c
index 0e932988e0..0ec2ac2eaf 100644
--- a/hw/mips/malta.c
+++ b/hw/mips/malta.c
@@ -1239,7 +1239,6 @@ void mips_malta_init(MachineState *machine)
 MaltaState *s;
 PCIDevice *piix4;
 DeviceState *dev;
-DeviceState *pm_dev;
 
 s = MIPS_MALTA(qdev_new(TYPE_MIPS_MALTA));
 sysbus_realize_and_unref(SYS_BUS_DEVICE(s), _fatal);
@@ -1405,13 +1404,13 @@ void mips_malta_init(MachineState *machine)
 TYPE_PIIX4_PCI_DEVICE);
 dev = DEVICE(piix4);
 isa_bus = ISA_BUS(qdev_get_child_bus(dev, "isa.0"));
-pm_dev = DEVICE(object_resolve_path_component(OBJECT(dev), "pm"));
-smbus = I2C_BUS(qdev_get_child_bus(pm_dev, "i2c"));
 
 /* Interrupt controller */
 qdev_connect_gpio_out_named(dev, "intr", 0, i8259_irq);
 
 /* generate SPD EEPROM data */
+dev = DEVICE(object_resolve_path_component(OBJECT(piix4), "pm"));
+smbus = I2C_BUS(qdev_get_child_bus(dev, "i2c"));
 generate_eeprom_spd(_eeprom_buf[0 * 256], ram_size);
 generate_eeprom_serial(_eeprom_buf[6 * 256]);
 smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size);
-- 
2.37.3




[PATCH 25/42] hw/isa/piix4: Move pci_ide_create_devs() call to board code

2022-09-01 Thread Bernhard Beschow
For the VIA south bridges there was a comment to have the call in board code.
Move it there for PIIX4 as well for consistency.

Signed-off-by: Bernhard Beschow 
---
 hw/isa/piix4.c  |  1 -
 hw/mips/malta.c | 10 ++
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c
index 9e2f7b9b71..67881e3a75 100644
--- a/hw/isa/piix4.c
+++ b/hw/isa/piix4.c
@@ -256,7 +256,6 @@ static void piix4_realize(PCIDevice *dev, Error **errp)
 if (!qdev_realize(DEVICE(>ide), BUS(pci_bus), errp)) {
 return;
 }
-pci_ide_create_devs(PCI_DEVICE(>ide));
 
 /* USB */
 qdev_prop_set_int32(DEVICE(>uhci), "addr", dev->devfn + 2);
diff --git a/hw/mips/malta.c b/hw/mips/malta.c
index 0ec2ac2eaf..a4b866a2cf 100644
--- a/hw/mips/malta.c
+++ b/hw/mips/malta.c
@@ -39,7 +39,7 @@
 #include "hw/pci/pci.h"
 #include "qemu/log.h"
 #include "hw/mips/bios.h"
-#include "hw/ide.h"
+#include "hw/ide/pci.h"
 #include "hw/irq.h"
 #include "hw/loader.h"
 #include "elf.h"
@@ -1402,11 +1402,13 @@ void mips_malta_init(MachineState *machine)
 /* Southbridge */
 piix4 = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(10, 0), true,
 TYPE_PIIX4_PCI_DEVICE);
-dev = DEVICE(piix4);
-isa_bus = ISA_BUS(qdev_get_child_bus(dev, "isa.0"));
+isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix4), "isa.0"));
+
+dev = DEVICE(object_resolve_path_component(OBJECT(piix4), "ide"));
+pci_ide_create_devs(PCI_DEVICE(dev));
 
 /* Interrupt controller */
-qdev_connect_gpio_out_named(dev, "intr", 0, i8259_irq);
+qdev_connect_gpio_out_named(DEVICE(piix4), "intr", 0, i8259_irq);
 
 /* generate SPD EEPROM data */
 dev = DEVICE(object_resolve_path_component(OBJECT(piix4), "pm"));
-- 
2.37.3




[PATCH 38/42] hw/isa/piix: Consolidate IRQ triggering

2022-09-01 Thread Bernhard Beschow
Speeds up PIIX4 which resolves an old TODO.

Signed-off-by: Bernhard Beschow 
---
 hw/isa/piix.c | 26 +++---
 1 file changed, 3 insertions(+), 23 deletions(-)

diff --git a/hw/isa/piix.c b/hw/isa/piix.c
index 1d516de5cc..e413d7e792 100644
--- a/hw/isa/piix.c
+++ b/hw/isa/piix.c
@@ -83,27 +83,6 @@ static void piix_set_irq(void *opaque, int pirq, int level)
 piix_set_irq_level(piix, pirq, level);
 }
 
-static void piix4_set_irq(void *opaque, int irq_num, int level)
-{
-int i, pic_irq, pic_level;
-PIIXState *s = opaque;
-PCIBus *bus = pci_get_bus(>dev);
-
-/* now we change the pic irq level according to the piix irq mappings */
-/* XXX: optimize */
-pic_irq = s->dev.config[PIIX_PIRQCA + irq_num];
-if (pic_irq < ISA_NUM_IRQS) {
-/* The pic level is the logical OR of all the PCI irqs mapped to it. */
-pic_level = 0;
-for (i = 0; i < PIIX_NUM_PIRQS; i++) {
-if (pic_irq == s->dev.config[PIIX_PIRQCA + i]) {
-pic_level |= pci_bus_get_irq_level(bus, i);
-}
-}
-qemu_set_irq(s->pic.in_irqs[pic_irq], pic_level);
-}
-}
-
 /*
  * Return the global irq number corresponding to a given device irq
  * pin. We could also use the bus number to have a more precise mapping.
@@ -275,7 +254,7 @@ static int piix4_post_load(void *opaque, int version_id)
 s->rcr = 0;
 }
 
-return 0;
+return piix3_post_load(opaque, version_id);
 }
 
 static int piix3_pre_save(void *opaque)
@@ -585,7 +564,7 @@ static void piix4_realize(PCIDevice *dev, Error **errp)
 /* RTC */
 s->rtc.irq = qdev_get_gpio_in(DEVICE(>pic), s->rtc.isairq);
 
-pci_bus_irqs(pci_bus, piix4_set_irq, piix4_pci_slot_get_pirq, s,
+pci_bus_irqs(pci_bus, piix_set_irq, piix4_pci_slot_get_pirq, s,
  PIIX_NUM_PIRQS);
 }
 
@@ -603,6 +582,7 @@ static void piix4_class_init(ObjectClass *klass, void *data)
 DeviceClass *dc = DEVICE_CLASS(klass);
 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
+k->config_write = piix_write_config;
 k->realize = piix4_realize;
 k->vendor_id = PCI_VENDOR_ID_INTEL;
 k->device_id = PCI_DEVICE_ID_INTEL_82371AB_0;
-- 
2.37.3




[PATCH 21/42] hw/isa/piix3: Rename typedef PIIX3State to PIIXState

2022-09-01 Thread Bernhard Beschow
This commit marks the finalization of the PIIX3 preparations
to be merged with PIIX4. In particular, PIIXState is prepared
to be reused in piix4.c.

Signed-off-by: Bernhard Beschow 
---
 hw/isa/piix3.c| 58 +--
 include/hw/southbridge/piix.h |  4 +--
 2 files changed, 31 insertions(+), 31 deletions(-)

diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c
index e5772475be..75705a1fc1 100644
--- a/hw/isa/piix3.c
+++ b/hw/isa/piix3.c
@@ -37,7 +37,7 @@
 
 #define XEN_PIIX_NUM_PIRQS  128ULL
 
-static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
+static void piix3_set_irq_pic(PIIXState *piix3, int pic_irq)
 {
 qemu_set_irq(piix3->pic.in_irqs[pic_irq],
  !!(piix3->pic_levels &
@@ -45,7 +45,7 @@ static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
  (pic_irq * PIIX_NUM_PIRQS;
 }
 
-static void piix3_set_irq_level_internal(PIIX3State *piix3, int pirq, int 
level)
+static void piix3_set_irq_level_internal(PIIXState *piix3, int pirq, int level)
 {
 int pic_irq;
 uint64_t mask;
@@ -60,7 +60,7 @@ static void piix3_set_irq_level_internal(PIIX3State *piix3, 
int pirq, int level)
 piix3->pic_levels |= mask * !!level;
 }
 
-static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
+static void piix3_set_irq_level(PIIXState *piix3, int pirq, int level)
 {
 int pic_irq;
 
@@ -76,7 +76,7 @@ static void piix3_set_irq_level(PIIX3State *piix3, int pirq, 
int level)
 
 static void piix3_set_irq(void *opaque, int pirq, int level)
 {
-PIIX3State *piix3 = opaque;
+PIIXState *piix3 = opaque;
 piix3_set_irq_level(piix3, pirq, level);
 }
 
@@ -93,7 +93,7 @@ static int piix3_pci_slot_get_pirq(PCIDevice *pci_dev, int 
pci_intx)
 
 static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin)
 {
-PIIX3State *piix3 = opaque;
+PIIXState *piix3 = opaque;
 int irq = piix3->dev.config[PIIX_PIRQCA + pin];
 PCIINTxRoute route;
 
@@ -108,7 +108,7 @@ static PCIINTxRoute piix3_route_intx_pin_to_irq(void 
*opaque, int pin)
 }
 
 /* irq routing is changed. so rebuild bitmap */
-static void piix3_update_irq_levels(PIIX3State *piix3)
+static void piix3_update_irq_levels(PIIXState *piix3)
 {
 PCIBus *bus = pci_get_bus(>dev);
 int pirq;
@@ -124,7 +124,7 @@ static void piix3_write_config(PCIDevice *dev,
 {
 pci_default_write_config(dev, address, val, len);
 if (ranges_overlap(address, len, PIIX_PIRQCA, 4)) {
-PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev);
+PIIXState *piix3 = PIIX_PCI_DEVICE(dev);
 int pic_irq;
 
 pci_bus_fire_intx_routing_notifier(pci_get_bus(>dev));
@@ -157,7 +157,7 @@ static void piix3_write_config_xen(PCIDevice *dev,
 
 static void piix_reset(DeviceState *dev)
 {
-PIIX3State *d = PIIX3_PCI_DEVICE(dev);
+PIIXState *d = PIIX_PCI_DEVICE(dev);
 uint8_t *pci_conf = d->dev.config;
 
 pci_conf[0x04] = 0x07; /* master, memory and I/O */
@@ -198,7 +198,7 @@ static void piix_reset(DeviceState *dev)
 
 static int piix3_post_load(void *opaque, int version_id)
 {
-PIIX3State *piix3 = opaque;
+PIIXState *piix3 = opaque;
 int pirq;
 
 /*
@@ -221,7 +221,7 @@ static int piix3_post_load(void *opaque, int version_id)
 static int piix3_pre_save(void *opaque)
 {
 int i;
-PIIX3State *piix3 = opaque;
+PIIXState *piix3 = opaque;
 
 for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) {
 piix3->pci_irq_levels_vmstate[i] =
@@ -233,7 +233,7 @@ static int piix3_pre_save(void *opaque)
 
 static bool piix3_rcr_needed(void *opaque)
 {
-PIIX3State *piix3 = opaque;
+PIIXState *piix3 = opaque;
 
 return (piix3->rcr != 0);
 }
@@ -244,7 +244,7 @@ static const VMStateDescription vmstate_piix3_rcr = {
 .minimum_version_id = 1,
 .needed = piix3_rcr_needed,
 .fields = (VMStateField[]) {
-VMSTATE_UINT8(rcr, PIIX3State),
+VMSTATE_UINT8(rcr, PIIXState),
 VMSTATE_END_OF_LIST()
 }
 };
@@ -256,8 +256,8 @@ static const VMStateDescription vmstate_piix3 = {
 .post_load = piix3_post_load,
 .pre_save = piix3_pre_save,
 .fields = (VMStateField[]) {
-VMSTATE_PCI_DEVICE(dev, PIIX3State),
-VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State,
+VMSTATE_PCI_DEVICE(dev, PIIXState),
+VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIXState,
   PIIX_NUM_PIRQS, 3),
 VMSTATE_END_OF_LIST()
 },
@@ -270,7 +270,7 @@ static const VMStateDescription vmstate_piix3 = {
 
 static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len)
 {
-PIIX3State *d = opaque;
+PIIXState *d = opaque;
 
 if (val & 4) {
 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
@@ -281,7 +281,7 @@ static void rcr_write(void *opaque, hwaddr addr, uint64_t 
val, unsigned len)
 
 static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len)
 {
-PIIX3State *d = opaque;
+  

[PATCH 30/42] hw/isa/piix4: Reuse struct PIIXState from PIIX3

2022-09-01 Thread Bernhard Beschow
Now that PIIX4 also uses the "isa-pic" proxy, both implementations
can share the same struct.

Signed-off-by: Bernhard Beschow 
---
 hw/isa/piix4.c | 61 --
 1 file changed, 19 insertions(+), 42 deletions(-)

diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c
index 128284bd0a..95e4a9f3c1 100644
--- a/hw/isa/piix4.c
+++ b/hw/isa/piix4.c
@@ -41,34 +41,10 @@
 #include "sysemu/runstate.h"
 #include "qom/object.h"
 
-struct PIIX4State {
-PCIDevice dev;
-
-ISAPICState pic;
-RTCState rtc;
-PCIIDEState ide;
-UHCIState uhci;
-PIIX4PMState pm;
-
-uint32_t smb_io_base;
-
-/* Reset Control Register */
-MemoryRegion rcr_mem;
-uint8_t rcr;
-
-uint8_t pci_irq_reset_mappings[PIIX_NUM_PIRQS];
-
-bool has_acpi;
-bool has_usb;
-bool smm_enabled;
-};
-
-OBJECT_DECLARE_SIMPLE_TYPE(PIIX4State, PIIX4_PCI_DEVICE)
-
 static void piix4_set_irq(void *opaque, int irq_num, int level)
 {
 int i, pic_irq, pic_level;
-PIIX4State *s = opaque;
+PIIXState *s = opaque;
 PCIBus *bus = pci_get_bus(>dev);
 
 /* now we change the pic irq level according to the piix irq mappings */
@@ -113,7 +89,7 @@ static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
 
 static void piix4_isa_reset(DeviceState *dev)
 {
-PIIX4State *d = PIIX4_PCI_DEVICE(dev);
+PIIXState *d = PIIX_PCI_DEVICE(dev);
 uint8_t *pci_conf = d->dev.config;
 
 pci_conf[0x04] = 0x07; // master, memory and I/O
@@ -148,12 +124,13 @@ static void piix4_isa_reset(DeviceState *dev)
 pci_conf[0xac] = 0x00;
 pci_conf[0xae] = 0x00;
 
+d->pic_levels = 0; /* not used in PIIX4 */
 d->rcr = 0;
 }
 
 static int piix4_ide_post_load(void *opaque, int version_id)
 {
-PIIX4State *s = opaque;
+PIIXState *s = opaque;
 
 if (version_id == 2) {
 s->rcr = 0;
@@ -168,8 +145,8 @@ static const VMStateDescription vmstate_piix4 = {
 .minimum_version_id = 2,
 .post_load = piix4_ide_post_load,
 .fields = (VMStateField[]) {
-VMSTATE_PCI_DEVICE(dev, PIIX4State),
-VMSTATE_UINT8_V(rcr, PIIX4State, 3),
+VMSTATE_PCI_DEVICE(dev, PIIXState),
+VMSTATE_UINT8_V(rcr, PIIXState, 3),
 VMSTATE_END_OF_LIST()
 }
 };
@@ -177,7 +154,7 @@ static const VMStateDescription vmstate_piix4 = {
 static void piix4_rcr_write(void *opaque, hwaddr addr, uint64_t val,
 unsigned int len)
 {
-PIIX4State *s = opaque;
+PIIXState *s = opaque;
 
 if (val & 4) {
 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
@@ -189,7 +166,7 @@ static void piix4_rcr_write(void *opaque, hwaddr addr, 
uint64_t val,
 
 static uint64_t piix4_rcr_read(void *opaque, hwaddr addr, unsigned int len)
 {
-PIIX4State *s = opaque;
+PIIXState *s = opaque;
 
 return s->rcr;
 }
@@ -206,7 +183,7 @@ static const MemoryRegionOps piix4_rcr_ops = {
 
 static void piix4_realize(PCIDevice *dev, Error **errp)
 {
-PIIX4State *s = PIIX4_PCI_DEVICE(dev);
+PIIXState *s = PIIX_PCI_DEVICE(dev);
 PCIBus *pci_bus = pci_get_bus(dev);
 ISABus *isa_bus;
 
@@ -276,7 +253,7 @@ static void piix4_realize(PCIDevice *dev, Error **errp)
 
 static void piix4_init(Object *obj)
 {
-PIIX4State *s = PIIX4_PCI_DEVICE(obj);
+PIIXState *s = PIIX_PCI_DEVICE(obj);
 
 object_initialize_child(obj, "pic", >pic, TYPE_ISA_PIC);
 object_initialize_child(obj, "rtc", >rtc, TYPE_MC146818_RTC);
@@ -284,14 +261,14 @@ static void piix4_init(Object *obj)
 }
 
 static Property piix4_props[] = {
-DEFINE_PROP_UINT32("smb_io_base", PIIX4State, smb_io_base, 0),
-DEFINE_PROP_UINT8("pirqa", PIIX4State, pci_irq_reset_mappings[0], 0x80),
-DEFINE_PROP_UINT8("pirqb", PIIX4State, pci_irq_reset_mappings[1], 0x80),
-DEFINE_PROP_UINT8("pirqc", PIIX4State, pci_irq_reset_mappings[2], 0x80),
-DEFINE_PROP_UINT8("pirqd", PIIX4State, pci_irq_reset_mappings[3], 0x80),
-DEFINE_PROP_BOOL("has-acpi", PIIX4State, has_acpi, true),
-DEFINE_PROP_BOOL("has-usb", PIIX4State, has_usb, true),
-DEFINE_PROP_BOOL("smm-enabled", PIIX4State, smm_enabled, false),
+DEFINE_PROP_UINT32("smb_io_base", PIIXState, smb_io_base, 0),
+DEFINE_PROP_UINT8("pirqa", PIIXState, pci_irq_reset_mappings[0], 0x80),
+DEFINE_PROP_UINT8("pirqb", PIIXState, pci_irq_reset_mappings[1], 0x80),
+DEFINE_PROP_UINT8("pirqc", PIIXState, pci_irq_reset_mappings[2], 0x80),
+DEFINE_PROP_UINT8("pirqd", PIIXState, pci_irq_reset_mappings[3], 0x80),
+DEFINE_PROP_BOOL("has-acpi", PIIXState, has_acpi, true),
+DEFINE_PROP_BOOL("has-usb", PIIXState, has_usb, true),
+DEFINE_PROP_BOOL("smm-enabled", PIIXState, smm_enabled, false),
 DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -319,7 +296,7 @@ static void piix4_class_init(ObjectClass *klass, void *data)
 static const TypeInfo piix4_info = {
 .name  = TYPE_PIIX4_PCI_DEVICE,
 .parent= TYPE_PCI_DEVICE,
-.instance_size = sizeof(PIIX4State),
+.instance_size 

[PATCH 41/42] hw/isa/piix: Drop the "3" from the PIIX base class

2022-09-01 Thread Bernhard Beschow
Now that the base class is used for both PIIX3 and PIIX4, the "3"
became misleading.

Signed-off-by: Bernhard Beschow 
---
 hw/i386/acpi-build.c  |  2 +-
 hw/isa/piix.c | 10 +-
 include/hw/southbridge/piix.h |  2 +-
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 0355bd3dda..8af75b1e22 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1276,7 +1276,7 @@ static void build_piix4_isa_bridge(Aml *table)
  * once PCI is converted to AcpiDevAmlIf and would be ble to generate
  * AML for bridge itself
  */
-obj = object_resolve_path_type("", TYPE_PIIX3_PCI_DEVICE, );
+obj = object_resolve_path_type("", TYPE_PIIX_PCI_DEVICE, );
 assert(obj && !ambiguous);
 
 scope =  aml_scope("_SB.PCI0");
diff --git a/hw/isa/piix.c b/hw/isa/piix.c
index 25b86ddf17..f70855541b 100644
--- a/hw/isa/piix.c
+++ b/hw/isa/piix.c
@@ -90,7 +90,7 @@ struct PIIXState {
 typedef struct PIIXState PIIXState;
 
 DECLARE_INSTANCE_CHECKER(PIIXState, PIIX_PCI_DEVICE,
- TYPE_PIIX3_PCI_DEVICE)
+ TYPE_PIIX_PCI_DEVICE)
 
 static void piix_set_irq_pic(PIIXState *piix, int pic_irq)
 {
@@ -514,7 +514,7 @@ static void pci_piix_class_init(ObjectClass *klass, void 
*data)
 }
 
 static const TypeInfo piix_pci_type_info = {
-.name = TYPE_PIIX3_PCI_DEVICE,
+.name = TYPE_PIIX_PCI_DEVICE,
 .parent = TYPE_PCI_DEVICE,
 .instance_size = sizeof(PIIXState),
 .instance_init = pci_piix_init,
@@ -564,7 +564,7 @@ static void piix3_class_init(ObjectClass *klass, void *data)
 
 static const TypeInfo piix3_info = {
 .name  = TYPE_PIIX3_DEVICE,
-.parent= TYPE_PIIX3_PCI_DEVICE,
+.parent= TYPE_PIIX_PCI_DEVICE,
 .instance_init = piix3_init,
 .class_init= piix3_class_init,
 };
@@ -604,7 +604,7 @@ static void piix3_xen_class_init(ObjectClass *klass, void 
*data)
 
 static const TypeInfo piix3_xen_info = {
 .name  = TYPE_PIIX3_XEN_DEVICE,
-.parent= TYPE_PIIX3_PCI_DEVICE,
+.parent= TYPE_PIIX_PCI_DEVICE,
 .instance_init = piix3_init,
 .class_init= piix3_xen_class_init,
 };
@@ -653,7 +653,7 @@ static void piix4_class_init(ObjectClass *klass, void *data)
 
 static const TypeInfo piix4_info = {
 .name  = TYPE_PIIX4_PCI_DEVICE,
-.parent= TYPE_PIIX3_PCI_DEVICE,
+.parent= TYPE_PIIX_PCI_DEVICE,
 .instance_init = piix4_init,
 .class_init= piix4_class_init,
 };
diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h
index 0edc23710c..60ff6d222a 100644
--- a/include/hw/southbridge/piix.h
+++ b/include/hw/southbridge/piix.h
@@ -24,7 +24,7 @@
  */
 #define PIIX_RCR_IOPORT 0xcf9
 
-#define TYPE_PIIX3_PCI_DEVICE "pci-piix3"
+#define TYPE_PIIX_PCI_DEVICE "pci-piix"
 #define TYPE_PIIX3_DEVICE "PIIX3"
 #define TYPE_PIIX3_XEN_DEVICE "PIIX3-xen"
 #define TYPE_PIIX4_PCI_DEVICE "piix4-isa"
-- 
2.37.3




  1   2   3   4   >