Re: [PATCH] iotests: Fix up python style in 300

2021-02-28 Thread Markus Armbruster
Vladimir Sementsov-Ogievskiy  writes:

> 16.02.2021 02:21, John Snow wrote:
>> On 2/15/21 5:05 PM, Eric Blake wrote:
>>> Break some long lines, and relax our type hints to be more generic to
>>> any JSON, in order to more easily permit the additional JSON depth now
>>> possible in migration parameters.  Detected by iotest 297.
>>>
>>> Fixes: ca4bfec41d56
>>>   (qemu-iotests: 300: Add test case for modifying persistence of bitmap)
>>> Reported-by: Kevin Wolf 
>>> Signed-off-by: Eric Blake 
>> Reviewed-by: John Snow 
>> 
>>> ---
>>>   tests/qemu-iotests/300 | 10 ++
>>>   1 file changed, 6 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/tests/qemu-iotests/300 b/tests/qemu-iotests/300
>>> index 63036f6a6e13..adb927629747 100755
>>> --- a/tests/qemu-iotests/300
>>> +++ b/tests/qemu-iotests/300
>>> @@ -22,7 +22,7 @@
>>>   import os
>>>   import random
>>>   import re
>>> -from typing import Dict, List, Optional, Union
>>> +from typing import Dict, List, Optional
>>>
>>>   import iotests
>>>
>>> @@ -30,7 +30,7 @@ import iotests
>>>   # pylint: disable=wrong-import-order
>>>   import qemu
>>>
>>> -BlockBitmapMapping = List[Dict[str, Union[str, List[Dict[str, str]
>>> +BlockBitmapMapping = List[Dict[str, object]]
>>>
>> Assuming iotest 297 didn't yap about this, I think this has the
>> necessary power for this file and we don't have to work any harder.
>> If in the future you try to treat e.g. bmap['persistent'] as a
>> particular kind of value (string? bool? int?) mypy will likely
>> complain about that a little, saying it has no insight into the type
>> beyond "object".
>> If *that* becomes annoying, you can degrade this type to use 'Any'
>> instead of 'object' and even those checks will cease.
>
> Probably at some future moment we'll have generated python types for QAPI 
> structures ? :)

Generating Python from the QAPI schema is possible.  I'm not aware of
anyone planning to work on it near term.




Re: [PATCH 48/50] target/i386: Create helper_check_io

2021-02-28 Thread Philippe Mathieu-Daudé
On 3/1/21 12:23 AM, Richard Henderson wrote:
> Drop helper_check_io[bwl] and expose their common
> subroutine to tcg directly.
> 
> Signed-off-by: Richard Henderson 
> ---
>  target/i386/helper.h |  4 +---
>  target/i386/tcg/seg_helper.c | 21 +++--
>  target/i386/tcg/translate.c  | 14 +-
>  3 files changed, 5 insertions(+), 34 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé 



Re: [PATCH 49/50] target/i386: Move helper_check_io to sysemu

2021-02-28 Thread Philippe Mathieu-Daudé
On 3/1/21 12:23 AM, Richard Henderson wrote:
> The we never allow i/o from user-only, and the tss check
> that helper_check_io does will always fail.  Use an ifdef
> within gen_check_io and return false, indicating that an
> exception is known to be raised.
> 
> Signed-off-by: Richard Henderson 
> ---
>  target/i386/helper.h|  2 +-
>  target/i386/tcg/seg_helper.c| 28 
>  target/i386/tcg/sysemu/seg_helper.c | 29 +
>  target/i386/tcg/translate.c | 11 +++
>  4 files changed, 41 insertions(+), 29 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé 



Re: [PATCH 50/50] target/i386: Remove user-only i/o stubs

2021-02-28 Thread Philippe Mathieu-Daudé
On 3/1/21 12:23 AM, Richard Henderson wrote:
> With the previous patch for check_io, we now have enough for
> the compiler to dead-code eliminate all of the i/o helpers.
> 
> Signed-off-by: Richard Henderson 
> ---
>  target/i386/helper.h  |  3 +-
>  target/i386/tcg/translate.c   |  6 
>  target/i386/tcg/user/misc_stubs.c | 55 ---
>  target/i386/tcg/user/meson.build  |  1 -
>  4 files changed, 7 insertions(+), 58 deletions(-)
>  delete mode 100644 target/i386/tcg/user/misc_stubs.c

Reviewed-by: Philippe Mathieu-Daudé 




Re: [PATCH 23/50] target/i386: Reduce DisasContext.vex_[lv] to uint8_t

2021-02-28 Thread Philippe Mathieu-Daudé
On 3/1/21 12:22 AM, Richard Henderson wrote:
> Currently, vex_l is either {0,1}; if in the future we implement
> AVX-512, the max value will be 2.  In vex_v we store a register
> number.  This is 0-15 for SSE, and 0-31 for AVX-512.
> 
> Signed-off-by: Richard Henderson 
> ---
>  target/i386/tcg/translate.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé 




Re: [PATCH v5 1/1] virtio-net: Add check for mac address while peer is vdpa

2021-02-28 Thread Adrian Moreno



On 3/1/21 2:36 AM, Cindy Lu wrote:
> On Mon, Mar 1, 2021 at 4:40 AM Michael S. Tsirkin  wrote:
>>
>> On Thu, Feb 25, 2021 at 02:14:39PM -0500, Michael S. Tsirkin wrote:
>>> On Fri, Feb 26, 2021 at 12:55:06AM +0800, Cindy Lu wrote:
 While peer is vdpa, sometime qemu get an all zero mac address from the 
 hardware,
 This is not a legal value. Add the check for this.if we get an zero mac 
 address.
 qemu will use the default mac address or the mac address from qemu cmdline

 Signed-off-by: Cindy Lu 
>>>
>>> I guess I will have to rewrite the comments and commit log :(
>>>
>>> It is all saying what does the patch do. We want it to rather
>>> give motivation.
>>>
>>> Sean could you please comment on whether this patch fixes your
>>> config?
>>
>> ping. if I'm to try and merge this work around it's critical
>> that someone with access to hardware confirm it actually works.
>>
> Hi Michael, I have tested this patch in qemu+vdpa+mlx environment.
> it's working fine.

I have also verified it. For the record, I'll expand:

Libvirt definition contains:


  
  
  
  
  


Qemu command line contains:

-add-fd set=3,fd=42,opaque=/dev/vhost-vdpa-0 \
-netdev vhost-vdpa,vhostdev=/dev/fdset/3,id=hostnet1 \
-device
virtio-net-pci,netdev=hostnet1,id=net1,mac=52:54:00:8e:a4:12,bus=pci.4,addr=0x0 
\

The vdpa device is created by mlx_vdpa (Connect-X6 DX) on switchdev mode.

The original problem was:
The mac address in struct virtio_net_config in the vdpa device is zero because
it has not been configured. This does not have implications in the traffic
steering since the card will rely on the eswitch flow configuration to perform
smac/dmac filtering (in my case, this is done through ovs + tcflower hw 
offload).

Since we anyhow have to rely on the mac address having been configured
externally on the eswitch, we can also trust that whoever applied such flow
configuration also gave us the correct mac address in the cmd line. Therefore,
exposing such address to the guest seems like a sane way to tell it what mac
address to use.

Until the vdpa framework / iproute2 tool support configuring the
virtio_net_config struct and such mechanism is used externally to align the
virtio device's mac with the one configured in the eswitch, this patch allows
the guest to have connectivity.


>>
 ---
  hw/net/virtio-net.c | 10 ++
  1 file changed, 10 insertions(+)

 diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
 index 9179013ac4..8f36ca5066 100644
 --- a/hw/net/virtio-net.c
 +++ b/hw/net/virtio-net.c
 @@ -126,6 +126,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, 
 uint8_t *config)
  VirtIONet *n = VIRTIO_NET(vdev);
  struct virtio_net_config netcfg;
  NetClientState *nc = qemu_get_queue(n->nic);
 +static const MACAddr zero = { .a = { 0, 0, 0, 0, 0, 0 } };

  int ret = 0;
  memset(, 0 , sizeof(struct virtio_net_config));
 @@ -151,6 +152,15 @@ static void virtio_net_get_config(VirtIODevice *vdev, 
 uint8_t *config)
  ret = vhost_net_get_config(get_vhost_net(nc->peer), (uint8_t 
 *),
 n->config_size);
  if (ret != -1) {
 +/*
 + * Here is a work around, the 0 mac address is not a legal 
 value.
 + * if we got this from hardware, qemu will use the mac address
 + * saved in VirtIONet->mac.
 + */
 +if (memcmp(, , sizeof(zero)) == 0) {
 +info_report("Get an all zero mac address from hardware");

s/Get/Got/?

 +memcpy(netcfg.mac, n->mac, ETH_ALEN);
 +}
  memcpy(config, , n->config_size);
  }
  }
 --
 2.21.3
>>
> 

FWIW:
Tested-by: Adrián Moreno 

-- 
Adrián Moreno




Re: [PATCH 1/2] i386/acpi: fix inconsistent QEMU/OVMF device paths

2021-02-28 Thread Thomas Lamprecht
On 01.03.21 08:20, Michael S. Tsirkin wrote:
> On Mon, Mar 01, 2021 at 08:12:35AM +0100, Thomas Lamprecht wrote:
>> On 28.02.21 21:43, Michael S. Tsirkin wrote:
>>> Sure. The way to do that is to tie old behaviour to old machine
>>> versions. We'll need it in stable too ...
>>
>> Yeah, using machine types is how its meant to be with solving migration
>> breakage, sure.
>> But that means we have to permanently pin the VM, and any backup restored 
>> from
>> that to that machine type *forever*. That'd be new for us as we always could
>> allow a newer machine type for a fresh start (i.e., non migration or the 
>> like)
>> here, and mean that lots of other improvements guarded by a newer machine 
>> type
>> for those VMs will.
> 
> If you don't do that, that is a bug as any virtual hardware
> can change across machine types.

For us a feature, for fresh starts one gets the current virtual HW but for
live migration or our live snapshot code it stays compatible. Works quite
well here for many years, as we can simply test the HW changes on existing
VMs - which failed here due to lack of static IPs in the test bed. So yes,
it has its problems as it is not really  what an OS considers as HW change
so big that it makes it a new device, mostly Windows is a PITA here as seen
in this issue.

I mean, QEMU deprecates very old machines at some point anyway, so even then
it is impossible to keep to the old machine forever, but otoh redoing some
changes after a decade or two can be fine, I guess?

> 
>> And yeah, stable is wanted, but extrapolating from the current stable 
>> releases
>> frequency, where normally there's maximal one after 5-6 months from the .0
>> release, means that this will probably still hit all those distributions I
>> mentioned or is there something more soon planned?
>>
>> Also, is there any regression testing infrastructure around to avoid such
>> changes in the future? This change got undetected for 7 months, which can be
>> pretty the norm for QEMU releases, so some earlier safety net would be good? 
>> Is
>> there anything which dumps various default machine HW layouts and uses them 
>> for
>> an ABI check of some sorts?
> 
> There are various testing efforts the reason this got undetected is
> because it does not affect linux guests, and even for windows
> they kind of recover, there's just some boot slowdown around reconfiguration.
> Not easy to detect automatically given windows has lots of random
> downtime during boot around updates etc etc.
> 

No, Windows does not reconfigure, this is a permanent change, one is just lucky
if one has a DHCP server around in the network accessible for the guest.
As static addresses setup on that virtual NIC before that config is gone,
no recovery whatsoever until manual intervention.

I meant more of a "dump HW layout to .txt file, commit to git, and ensure
there's no diff without and machine version bump" (very boiled down), e.g., like
ABI checks for kernel builds are often done by distros - albeit those are easier
as its quite clear what and how the kernel ABI can be used.




Re: [PATCH 3/3] migration/ram: Optimize ram_save_host_page()

2021-02-28 Thread Kunkun Jiang

On 2021/2/25 20:48, David Edmondson wrote:

On Tuesday, 2021-02-23 at 10:16:45 +08, Kunkun Jiang wrote:


Starting from pss->page, ram_save_host_page() will check every page
and send the dirty pages up to the end of the current host page or
the boundary of used_length of the block. If the host page size is
a huge page, the step "check" will take a lot of time.

This will improve performance to use migration_bitmap_find_dirty().

Signed-off-by: Keqian Zhu 
Signed-off-by: Kunkun Jiang 
---
  migration/ram.c | 14 --
  1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/migration/ram.c b/migration/ram.c
index c7e18dc2fc..c7a2350198 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -1994,6 +1994,8 @@ static int ram_save_host_page(RAMState *rs, 
PageSearchStatus *pss,
  int tmppages, pages = 0;
  size_t pagesize_bits =
  qemu_ram_pagesize(pss->block) >> TARGET_PAGE_BITS;
+unsigned long hostpage_boundary =
+QEMU_ALIGN_UP(pss->page + 1, pagesize_bits);
  unsigned long start_page = pss->page;
  int res;
  
@@ -2005,8 +2007,7 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss,

  do {
  /* Check the pages is dirty and if it is send it */
  if (!migration_bitmap_clear_dirty(rs, pss->block, pss->page)) {
-pss->page++;
-continue;
+goto find_next;
  }
  
  tmppages = ram_save_target_page(rs, pss, last_stage);

@@ -2015,16 +2016,17 @@ static int ram_save_host_page(RAMState *rs, 
PageSearchStatus *pss,
  }
  
  pages += tmppages;

-pss->page++;
  /* Allow rate limiting to happen in the middle of huge pages */
  if (pagesize_bits > 1) {
  migration_rate_limit();
  }
-} while ((pss->page & (pagesize_bits - 1)) &&
+find_next:
+pss->page = migration_bitmap_find_dirty(rs, pss->block, pss->page);
+} while ((pss->page < hostpage_boundary) &&
   offset_in_ramblock(pss->block,
  ((ram_addr_t)pss->page) << TARGET_PAGE_BITS));

This ends up looking very messy, with a goto inside the loop.

Wouldn't it be cleaner to invert the sense of the
migration_bitmap_clear_dirty() test, such that
migration_bitmap_find_dirty() is called after the body of the test?

Sorry for the late reply.
Thanks for your advice.  I will post a v2 as soon as possible.

Best Regards.

Kunkun Jiang


-/* The offset we leave with is the last one we looked at */
-pss->page--;
+/* The offset we leave with is the min boundary of host page and block */
+pss->page = MIN(pss->page, hostpage_boundary) - 1;
  
  res = ram_save_release_protection(rs, pss, start_page);

  return (res < 0 ? res : pages);
--
2.23.0

dme.






Re: [PATCH 1/2] i386/acpi: fix inconsistent QEMU/OVMF device paths

2021-02-28 Thread Michael S. Tsirkin
On Mon, Mar 01, 2021 at 08:12:35AM +0100, Thomas Lamprecht wrote:
> On 28.02.21 21:43, Michael S. Tsirkin wrote:
> > Sure. The way to do that is to tie old behaviour to old machine
> > versions. We'll need it in stable too ...
> 
> Yeah, using machine types is how its meant to be with solving migration
> breakage, sure.
> But that means we have to permanently pin the VM, and any backup restored from
> that to that machine type *forever*. That'd be new for us as we always could
> allow a newer machine type for a fresh start (i.e., non migration or the like)
> here, and mean that lots of other improvements guarded by a newer machine type
> for those VMs will.

If you don't do that, that is a bug as any virtual hardware
can change across machine types.

> Why not a switch + machine type, solves migration and any special cases of it
> but also allows machine updates but also to keep the old behavior?

I am not really sure what you mean here, sound like a new feature -
at a guess it will take a while to formulate and is unlikely
to be backported to stable and so help with historical
releases.

> And yeah, stable is wanted, but extrapolating from the current stable releases
> frequency, where normally there's maximal one after 5-6 months from the .0
> release, means that this will probably still hit all those distributions I
> mentioned or is there something more soon planned?
> 
> Also, is there any regression testing infrastructure around to avoid such
> changes in the future? This change got undetected for 7 months, which can be
> pretty the norm for QEMU releases, so some earlier safety net would be good? 
> Is
> there anything which dumps various default machine HW layouts and uses them 
> for
> an ABI check of some sorts?

There are various testing efforts the reason this got undetected is
because it does not affect linux guests, and even for windows
they kind of recover, there's just some boot slowdown around reconfiguration.
Not easy to detect automatically given windows has lots of random
downtime during boot around updates etc etc.

-- 
MST




Re: [PATCH] rtl8193: switch to use qemu_receive_packet() for loopback

2021-02-28 Thread Jason Wang



On 2021/2/27 2:47 上午, Alexander Bulekov wrote:

This patch switches to use qemu_receive_packet() which can detect
reentrancy and return early.

Buglink: https://bugs.launchpad.net/qemu/+bug/1910826
Signed-off-by: Alexander Bulekov 
---

Although it's not a nc->info->receive() call, maybe this can also go in
this series?

-Alex



Yes, I will add this in this series.

Thanks




  hw/net/rtl8139.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index 4675ac878e..90b4fc63ce 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -1795,7 +1795,7 @@ static void rtl8139_transfer_frame(RTL8139State *s, 
uint8_t *buf, int size,
  }
  
  DPRINTF("+++ transmit loopback mode\n");

-rtl8139_do_receive(qemu_get_queue(s->nic), buf, size, do_interrupt);
+qemu_receive_packet(qemu_get_queue(s->nic), buf, size);
  
  if (iov) {

  g_free(buf2);





Re: [PATCH 1/2] i386/acpi: fix inconsistent QEMU/OVMF device paths

2021-02-28 Thread Thomas Lamprecht
On 28.02.21 21:43, Michael S. Tsirkin wrote:
> Sure. The way to do that is to tie old behaviour to old machine
> versions. We'll need it in stable too ...

Yeah, using machine types is how its meant to be with solving migration
breakage, sure.
But that means we have to permanently pin the VM, and any backup restored from
that to that machine type *forever*. That'd be new for us as we always could
allow a newer machine type for a fresh start (i.e., non migration or the like)
here, and mean that lots of other improvements guarded by a newer machine type
for those VMs will.

Why not a switch + machine type, solves migration and any special cases of it
but also allows machine updates but also to keep the old behavior?

And yeah, stable is wanted, but extrapolating from the current stable releases
frequency, where normally there's maximal one after 5-6 months from the .0
release, means that this will probably still hit all those distributions I
mentioned or is there something more soon planned?

Also, is there any regression testing infrastructure around to avoid such
changes in the future? This change got undetected for 7 months, which can be
pretty the norm for QEMU releases, so some earlier safety net would be good? Is
there anything which dumps various default machine HW layouts and uses them for
an ABI check of some sorts?




[Bug 1917161] Re: Parameter 'type' expects a netdev backend type

2021-02-28 Thread Thomas Huth
What output do you get when you run:

 qemu-system-i386 -netdev help

It's likely that your binary has been compiled without "user" networking
(aka. "slirp") support. If so, please use a binary that has "slirp"
enabled instead.

** Changed in: qemu
   Status: New => Incomplete

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

Title:
  Parameter 'type' expects a netdev backend type

Status in QEMU:
  Incomplete

Bug description:
  When using QEMU on an M1 Mac with Mac OS 11.1, I see this error
  message when trying to enable networking for a guest:

  Parameter 'type' expects a netdev backend type

  Example command:
  qemu-system-i386 -m 700 -hda  -netdev user,id=n0 -device 
rtl8139,netdev=n0

  What should happen is networking should work when issuing the above
  command. What actually happens is QEMU exits immediately.

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



Re: [PATCH] hw/ppc: e500: Add missing in the eTSEC node

2021-02-28 Thread David Gibson
On Sun, Feb 28, 2021 at 03:02:32PM +0800, Bin Meng wrote:
> On Wed, Feb 24, 2021 at 5:28 PM Bin Meng  wrote:
> >
> > From: Bin Meng 
> >
> > The eTSEC node should provide an empty  property in the
> > eTSEC node, otherwise of_translate_address() in the Linux kernel
> > fails to get the eTSEC register base, reporting:
> >
> >   OF: ** translation for device /platform@f/ethernet@0/queue-group 
> > **
> >   OF: bus is default (na=1, ns=1) on /platform@f/ethernet@0
> >   OF: translating address: 
> >   OF: parent bus is default (na=1, ns=1) on /platform@f
> >   OF: no ranges; cannot translate
> >
> > Per devicetree spec v0.3 [1] chapter 2.3.8:
> >
> >   If the property is not present in a bus node, it is assumed that
> >   no mapping exists between children of the node and the parent
> >   address space.
> >
> > This is why of_translate_address() aborts the address translation.
> > Apparently U-Boot devicetree parser seems to be tolerant with
> > missing  as this was not noticed when testing with U-Boot.
> > The empty  property is present in all kernel shipped dtsi
> > files for eTSEC, Let's add it to conform with the spec.
> >
> > [1] 
> > https://github.com/devicetree-org/devicetree-specification/releases/download/v0.3/devicetree-specification-v0.3.pdf
> >
> > Fixes: fdfb7f2cdb2d ("e500: Add support for eTSEC in device tree")
> > Signed-off-by: Bin Meng 
> > ---
> >
> >  hw/ppc/e500.c | 1 +
> >  1 file changed, 1 insertion(+)
> >
> 
> Ping?

Sorry for the delay.  Now applied to ppc-for-6.0.

-- 
David Gibson| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au  | minimalist, thank you.  NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson


signature.asc
Description: PGP signature


Re: [PATCH 1/1] qemu_timer.c: add timer_deadline_ms() helper

2021-02-28 Thread David Gibson
On Fri, Feb 26, 2021 at 03:29:55PM +0100, Paolo Bonzini wrote:
> On 25/02/21 22:29, Daniel Henrique Barboza wrote:
> > The pSeries machine is using QEMUTimer internals to return the timeout
> > in seconds for a timer object, in hw/ppc/spapr.c, function
> > spapr_drc_unplug_timeout_remaining_sec().
> > 
> > Create a helper in qemu-timer.c to retrieve the deadline for a QEMUTimer
> > object, in ms, to avoid exposing timer internals to the PPC code.
> > 
> > CC: Paolo Bonzini 
> > Signed-off-by: Daniel Henrique Barboza 
> > ---
> > 
> > This patch is applicable on top of David's ppc-for-6.0.
> 
> Acked-by: Paolo Bonzini 

With Paolo's ack, I've taken this into the ppc-for-6.0 tree, hope
that's ok.

> 
> >   hw/ppc/spapr_drc.c   |  5 ++---
> >   include/qemu/timer.h |  8 
> >   util/qemu-timer.c| 13 +
> >   3 files changed, 23 insertions(+), 3 deletions(-)
> > 
> > diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
> > index 8c4997d795..98b626acf9 100644
> > --- a/hw/ppc/spapr_drc.c
> > +++ b/hw/ppc/spapr_drc.c
> > @@ -421,9 +421,8 @@ void spapr_drc_unplug_request(SpaprDrc *drc)
> >   int spapr_drc_unplug_timeout_remaining_sec(SpaprDrc *drc)
> >   {
> > -if (drc->unplug_requested && timer_pending(drc->unplug_timeout_timer)) 
> > {
> > -return 
> > (qemu_timeout_ns_to_ms(drc->unplug_timeout_timer->expire_time) -
> > -qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)) / 1000;
> > +if (drc->unplug_requested) {
> > +return timer_deadline_ms(drc->unplug_timeout_timer) / 1000;
> >   }
> >   return 0;
> > diff --git a/include/qemu/timer.h b/include/qemu/timer.h
> > index 1678238384..5e76e3f8c2 100644
> > --- a/include/qemu/timer.h
> > +++ b/include/qemu/timer.h
> > @@ -795,6 +795,14 @@ static inline int64_t get_max_clock_jump(void)
> >   return 60 * NANOSECONDS_PER_SECOND;
> >   }
> > +/**
> > + * timer_deadline_ms:
> > + *
> > + * Returns the remaining miliseconds for @timer to expire, or zero
> > + * if the timer is no longer pending.
> > + */
> > +int64_t timer_deadline_ms(QEMUTimer *timer);
> > +
> >   /*
> >* Low level clock functions
> >*/
> > diff --git a/util/qemu-timer.c b/util/qemu-timer.c
> > index 81c28af517..3a03a63daa 100644
> > --- a/util/qemu-timer.c
> > +++ b/util/qemu-timer.c
> > @@ -243,6 +243,19 @@ int64_t timerlist_deadline_ns(QEMUTimerList 
> > *timer_list)
> >   return delta;
> >   }
> > +/*
> > + * Returns the time remaining for the deadline, in ms.
> > + */
> > +int64_t timer_deadline_ms(QEMUTimer *timer)
> > +{
> > +if (timer_pending(timer)) {
> > +return qemu_timeout_ns_to_ms(timer->expire_time) -
> > +   qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
> > +}
> > +
> > +return 0;
> > +}
> > +
> >   /* Calculate the soonest deadline across all timerlists attached
> >* to the clock. This is used for the icount timeout so we
> >* ignore whether or not the clock should be used in deadline
> > 
> 

-- 
David Gibson| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au  | minimalist, thank you.  NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson


signature.asc
Description: PGP signature


Re: [RFC v2 7/7] vhost: Route host->guest notification through shadow virtqueue

2021-02-28 Thread Jason Wang



On 2021/2/9 11:37 下午, Eugenio Pérez wrote:

Signed-off-by: Eugenio Pérez 
---
  hw/virtio/vhost-shadow-virtqueue.h |  2 ++
  hw/virtio/vhost-shadow-virtqueue.c | 49 ++
  hw/virtio/vhost.c  |  5 ++-
  3 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/hw/virtio/vhost-shadow-virtqueue.h 
b/hw/virtio/vhost-shadow-virtqueue.h
index c45035c4b7..210133434c 100644
--- a/hw/virtio/vhost-shadow-virtqueue.h
+++ b/hw/virtio/vhost-shadow-virtqueue.h
@@ -17,6 +17,8 @@
  
  typedef struct VhostShadowVirtqueue VhostShadowVirtqueue;
  
+EventNotifier *vhost_shadow_vq_get_call_notifier(VhostShadowVirtqueue *vq);

+
  bool vhost_shadow_vq_start_rcu(struct vhost_dev *dev,
 unsigned idx,
 VhostShadowVirtqueue *svq);
diff --git a/hw/virtio/vhost-shadow-virtqueue.c 
b/hw/virtio/vhost-shadow-virtqueue.c
index 01f282d434..61d98ae652 100644
--- a/hw/virtio/vhost-shadow-virtqueue.c
+++ b/hw/virtio/vhost-shadow-virtqueue.c
@@ -24,6 +24,8 @@ typedef struct VhostShadowVirtqueue {
  
  /* Borrowed virtqueue's guest to host notifier. */

  EventNotifier host_notifier;
+/* Host to guest notifier */
+EventNotifier *guest_notifier;
  
  /* Virtio queue shadowing */

  VirtQueue *vq;
@@ -40,6 +42,26 @@ static void vhost_handle_guest_kick(EventNotifier *n)
  }
  }
  
+/* Forward vhost notifications */

+static void vhost_handle_call(EventNotifier *n)
+{
+VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue,
+ call_notifier);
+
+if (event_notifier_test_and_clear(n)) {
+event_notifier_set(svq->guest_notifier);
+}
+}



So I wonder how this is synchonized with virtqueue mask/unmask. Or the 
masking is totally transparent to shadow virtqueue?


Thanks



+
+/*
+ * Get the vhost call notifier of the shadow vq
+ * @vq Shadow virtqueue
+ */
+EventNotifier *vhost_shadow_vq_get_call_notifier(VhostShadowVirtqueue *vq)
+{
+return >call_notifier;
+}
+
  /*
   * Start shadow virtqueue operation.
   * @dev vhost device
@@ -57,6 +79,10 @@ bool vhost_shadow_vq_start_rcu(struct vhost_dev *dev,
  .index = idx,
  .fd = event_notifier_get_fd(>kick_notifier),
  };
+struct vhost_vring_file call_file = {
+.index = idx,
+.fd = event_notifier_get_fd(>call_notifier),
+};
  int r;
  
  /* Check that notifications are still going directly to vhost dev */

@@ -66,6 +92,7 @@ bool vhost_shadow_vq_start_rcu(struct vhost_dev *dev,
 event_notifier_get_fd(vq_host_notifier));
  event_notifier_set_handler(>host_notifier, vhost_handle_guest_kick);
  
+svq->guest_notifier = virtio_queue_get_guest_notifier(svq->vq);

  r = dev->vhost_ops->vhost_set_vring_kick(dev, _file);
  if (unlikely(r != 0)) {
  error_report("Couldn't set kick fd: %s", strerror(errno));
@@ -75,8 +102,19 @@ bool vhost_shadow_vq_start_rcu(struct vhost_dev *dev,
  /* Check for pending notifications from the guest */
  vhost_handle_guest_kick(>host_notifier);
  
+r = dev->vhost_ops->vhost_set_vring_call(dev, _file);

+if (r != 0) {
+error_report("Couldn't set call fd: %s", strerror(errno));
+goto err_set_vring_call;
+}
+
  return true;
  
+err_set_vring_call:

+kick_file.fd = event_notifier_get_fd(vq_host_notifier);
+r = dev->vhost_ops->vhost_set_vring_kick(dev, _file);
+assert(r == 0);
+
  err_set_vring_kick:
  event_notifier_set_handler(>host_notifier, NULL);
  
@@ -108,6 +146,16 @@ void vhost_shadow_vq_stop_rcu(struct vhost_dev *dev,

  assert(r == 0);
  
  event_notifier_set_handler(>host_notifier, NULL);

+
+if (!dev->vqs[idx].notifier_is_masked) {
+EventNotifier *e = vhost_shadow_vq_get_call_notifier(svq);
+
+/* Restore vhost call */
+vhost_virtqueue_mask(dev, dev->vdev, dev->vq_index + idx, false);
+
+/* Check for pending calls */
+vhost_handle_call(e);
+}
  }
  
  /*

@@ -136,6 +184,7 @@ VhostShadowVirtqueue *vhost_shadow_vq_new(struct vhost_dev 
*dev, int idx)
  goto err_init_call_notifier;
  }
  
+event_notifier_set_handler(>call_notifier, vhost_handle_call);

  return g_steal_pointer();
  
  err_init_call_notifier:

diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 9d4728e545..0dc95679e9 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -975,7 +975,6 @@ static int vhost_sw_live_migration_start(struct vhost_dev 
*dev)
  for (idx = 0; idx < dev->nvqs; ++idx) {
  bool ok = vhost_shadow_vq_start_rcu(dev, idx,
  dev->shadow_vqs[idx]);
-
  if (!ok) {
  int stop_idx = idx;
  
@@ -1608,6 +1607,10 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,

  if (mask) {
  assert(vdev->use_guest_notifier_mask);
  

Re: [PATCH v3 1/3] vfio: Move the saving of the config space to the right place in VFIO migration

2021-02-28 Thread Kirti Wankhede



Reviewed-by: Kirti Wankhede 

On 2/23/2021 7:52 AM, Shenming Lu wrote:

On ARM64 the VFIO SET_IRQS ioctl is dependent on the VM interrupt
setup, if the restoring of the VFIO PCI device config space is
before the VGIC, an error might occur in the kernel.

So we move the saving of the config space to the non-iterable
process, thus it will be called after the VGIC according to
their priorities.

As for the possible dependence of the device specific migration
data on it's config space, we can let the vendor driver to
include any config info it needs in its own data stream.

Signed-off-by: Shenming Lu 
---
  hw/vfio/migration.c | 25 +++--
  1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c
index 00daa50ed8..f5bf67f642 100644
--- a/hw/vfio/migration.c
+++ b/hw/vfio/migration.c
@@ -575,11 +575,6 @@ static int vfio_save_complete_precopy(QEMUFile *f, void 
*opaque)
  return ret;
  }
  
-ret = vfio_save_device_config_state(f, opaque);

-if (ret) {
-return ret;
-}
-
  ret = vfio_update_pending(vbasedev);
  if (ret) {
  return ret;
@@ -620,6 +615,19 @@ static int vfio_save_complete_precopy(QEMUFile *f, void 
*opaque)
  return ret;
  }
  
+static void vfio_save_state(QEMUFile *f, void *opaque)

+{
+VFIODevice *vbasedev = opaque;
+int ret;
+
+ret = vfio_save_device_config_state(f, opaque);
+if (ret) {
+error_report("%s: Failed to save device config space",
+ vbasedev->name);
+qemu_file_set_error(f, ret);
+}
+}
+
  static int vfio_load_setup(QEMUFile *f, void *opaque)
  {
  VFIODevice *vbasedev = opaque;
@@ -670,11 +678,7 @@ static int vfio_load_state(QEMUFile *f, void *opaque, int 
version_id)
  switch (data) {
  case VFIO_MIG_FLAG_DEV_CONFIG_STATE:
  {
-ret = vfio_load_device_config_state(f, opaque);
-if (ret) {
-return ret;
-}
-break;
+return vfio_load_device_config_state(f, opaque);
  }
  case VFIO_MIG_FLAG_DEV_SETUP_STATE:
  {
@@ -720,6 +724,7 @@ static SaveVMHandlers savevm_vfio_handlers = {
  .save_live_pending = vfio_save_pending,
  .save_live_iterate = vfio_save_iterate,
  .save_live_complete_precopy = vfio_save_complete_precopy,
+.save_state = vfio_save_state,
  .load_setup = vfio_load_setup,
  .load_cleanup = vfio_load_cleanup,
  .load_state = vfio_load_state,





Re: [PATCH V3 7/8] hw/block/nvme: support changed namespace asyncrohous event

2021-02-28 Thread Klaus Jensen
On Mar  1 01:10, Minwoo Im wrote:
> If namespace inventory is changed due to some reasons (e.g., namespace
> attachment/detachment), controller can send out event notifier to the
> host to manage namespaces.
> 
> This patch sends out the AEN to the host after either attach or detach
> namespaces from controllers.  To support clear of the event from the
> controller, this patch also implemented Get Log Page command for Changed
> Namespace List log type.  To return namespace id list through the
> command, when namespace inventory is updated, id is added to the
> per-controller list (changed_ns_list).
> 
> To indicate the support of this async event, this patch set
> OAES(Optional Asynchronous Events Supported) in Identify Controller data
> structure.
> 
> Signed-off-by: Minwoo Im 
> ---
>  hw/block/nvme.c  | 44 
>  hw/block/nvme.h  |  7 +++
>  include/block/nvme.h |  7 +++
>  3 files changed, 58 insertions(+)
> 
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 68c2e63d9412..fc06f806e58e 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -2980,6 +2980,32 @@ static uint16_t nvme_error_info(NvmeCtrl *n, uint8_t 
> rae, uint32_t buf_len,
>  DMA_DIRECTION_FROM_DEVICE, req);
>  }
>  
> +static uint16_t nvme_changed_nslist(NvmeCtrl *n, uint8_t rae, uint32_t 
> buf_len,
> +uint64_t off, NvmeRequest *req)
> +{
> +uint32_t nslist[1024];
> +uint32_t trans_len;
> +NvmeChangedNs *ns, *next;
> +int i = 0;
> +
> +memset(nslist, 0x0, sizeof(nslist));
> +trans_len = MIN(sizeof(nslist) - off, buf_len);
> +
> +QTAILQ_FOREACH_SAFE(ns, >changed_ns_list, entry, next) {
> +nslist[i++] = ns->nsid;
> +
> +QTAILQ_REMOVE(>changed_ns_list, ns, entry);
> +g_free(ns);
> +}
> +
> +if (!rae) {
> +nvme_clear_events(n, NVME_AER_TYPE_NOTICE);
> +}
> +
> +return nvme_dma(n, ((uint8_t *)nslist) + off, trans_len,
> +DMA_DIRECTION_FROM_DEVICE, req);
> +}
> +
>  static uint16_t nvme_cmd_effects(NvmeCtrl *n, uint8_t csi, uint32_t buf_len,
>   uint64_t off, NvmeRequest *req)
>  {
> @@ -3064,6 +3090,8 @@ static uint16_t nvme_get_log(NvmeCtrl *n, NvmeRequest 
> *req)
>  return nvme_smart_info(n, rae, len, off, req);
>  case NVME_LOG_FW_SLOT_INFO:
>  return nvme_fw_log_info(n, len, off, req);
> +case NVME_LOG_CHANGED_NSLIST:
> +return nvme_changed_nslist(n, rae, len, off, req);
>  case NVME_LOG_CMD_EFFECTS:
>  return nvme_cmd_effects(n, csi, len, off, req);
>  default:
> @@ -3882,6 +3910,7 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, 
> NvmeRequest *req)
>  uint16_t *ids = [1];
>  uint16_t ret;
>  int i;
> +NvmeChangedNs *changed_nsid;
>  
>  trace_pci_nvme_ns_attachment(nvme_cid(req), dw10 & 0xf);
>  
> @@ -3920,6 +3949,18 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, 
> NvmeRequest *req)
>  
>  nvme_ns_detach(ctrl, ns);
>  }
> +
> +/*
> + * Add namespace id to the changed namespace id list for event 
> clearing
> + * via Get Log Page command.
> + */
> +changed_nsid = g_new(NvmeChangedNs, 1);
> +changed_nsid->nsid = nsid;
> +QTAILQ_INSERT_TAIL(>changed_ns_list, changed_nsid, entry);
> +
> +nvme_enqueue_event(ctrl, NVME_AER_TYPE_NOTICE,
> +   NVME_AER_INFO_NOTICE_NS_ATTR_CHANGED,
> +   NVME_LOG_CHANGED_NSLIST);
>  }

If one just keeps attaching/detaching we end up with more than 1024
entries here and go out of bounds in nvme_changed_nslist.

How about having the QTAILQ_ENTRY directly on the NvmeNamespace struct
and use QTAILQ_IN_USE to check if the namespace is already in the list?

>  
>  return NVME_SUCCESS;
> @@ -4714,6 +4755,7 @@ static void nvme_init_state(NvmeCtrl *n)
>  n->features.temp_thresh_hi = NVME_TEMPERATURE_WARNING;
>  n->starttime_ms = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
>  n->aer_reqs = g_new0(NvmeRequest *, n->params.aerl + 1);
> +QTAILQ_INIT(>changed_ns_list);
>  }
>  
>  static int nvme_attach_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error 
> **errp)
> @@ -4910,6 +4952,8 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice 
> *pci_dev)
>  
>  id->cntlid = cpu_to_le16(n->cntlid);
>  
> +id->oaes = cpu_to_le32(NVME_OAES_NS_ATTR);
> +
>  id->rab = 6;
>  
>  if (n->params.use_intel_id) {
> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> index 74a00ab21a55..d5eaea003ea5 100644
> --- a/hw/block/nvme.h
> +++ b/hw/block/nvme.h
> @@ -132,6 +132,11 @@ typedef struct NvmeFeatureVal {
>  uint32_tasync_config;
>  } NvmeFeatureVal;
>  
> +typedef struct NvmeChangedNs {
> +uint32_t nsid;
> +QTAILQ_ENTRY(NvmeChangedNs) entry;
> +} NvmeChangedNs;
> +
>  typedef struct NvmeCtrl {
>  PCIDeviceparent_obj;
>  

[PATCH 1/1] i386/cpu: Expose AVX_VNNI instruction to guset

2021-02-28 Thread Yang Zhong
Expose AVX (VEX-encoded) versions of the Vector Neural Network
Instructions to guest.

The bit definition:
CPUID.(EAX=7,ECX=1):EAX[bit 4] AVX_VNNI

The following instructions are available when this feature is
present in the guest.
  1. VPDPBUS: Multiply and Add Unsigned and Signed Bytes
  2. VPDPBUSDS: Multiply and Add Unsigned and Signed Bytes with Saturation
  3. VPDPWSSD: Multiply and Add Signed Word Integers
  4. VPDPWSSDS: Multiply and Add Signed Integers with Saturation

The release document ref below link:
https://software.intel.com/content/www/us/en/develop/download/\
intel-architecture-instruction-set-extensions-programming-reference.html

Signed-off-by: Yang Zhong 
---
 target/i386/cpu.c | 4 ++--
 target/i386/cpu.h | 2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 6a53446e6a..55545d8692 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -996,7 +996,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
 .type = CPUID_FEATURE_WORD,
 .feat_names = {
 NULL, NULL, NULL, NULL,
-NULL, "avx512-bf16", NULL, NULL,
+"avx-vnni", "avx512-bf16", NULL, NULL,
 NULL, NULL, NULL, NULL,
 NULL, NULL, NULL, NULL,
 NULL, NULL, NULL, NULL,
@@ -3273,7 +3273,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
 MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO |
 MSR_ARCH_CAP_PSCHANGE_MC_NO | MSR_ARCH_CAP_TAA_NO,
 .features[FEAT_7_1_EAX] =
-CPUID_7_1_EAX_AVX512_BF16,
+CPUID_7_1_EAX_AVX_VNNI | CPUID_7_1_EAX_AVX512_BF16,
 /*
  * Missing: XSAVES (not supported by some Linux versions,
  * including v4.1 to v4.12).
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 8be39cfb62..ef5f145626 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -803,6 +803,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS];
 /* Speculative Store Bypass Disable */
 #define CPUID_7_0_EDX_SPEC_CTRL_SSBD(1U << 31)
 
+/* AVX VNNI Instruction */
+#define CPUID_7_1_EAX_AVX_VNNI  (1U << 4)
 /* AVX512 BFloat16 Instruction */
 #define CPUID_7_1_EAX_AVX512_BF16   (1U << 5)
 
-- 
2.29.2.334.gfaefdd61ec




[PATCH 0/1] Expose AVX_VNNI instruction to guset

2021-02-28 Thread Yang Zhong
This patch will expose AVX_VNNI features to the guest. The related
kvm/kernel patches series have been queued as below link:
https://lore.kernel.org/kvm/eee07399-df81-83ed-d410-18b42d51e...@redhat.com/


Yang Zhong (1):
  i386/cpu: Expose AVX_VNNI instruction to guset

 target/i386/cpu.c | 4 ++--
 target/i386/cpu.h | 2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)

-- 
2.29.2.334.gfaefdd61ec




Re: [PATCH v2 19/24] hw/arm/mps2-tz: Get armv7m_load_kernel() size argument from RAMInfo

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

The armv7m_load_kernel() function takes a mem_size argument which it
expects to be the size of the memory region at guest address 0.  (It
uses this argument only as a limit on how large a raw image file it
can load at address zero).

Instead of hardcoding this value, find the RAMInfo corresponding to
the 0 address and extract its size.

Signed-off-by: Peter Maydell
Reviewed-by: Philippe Mathieu-Daudé
---
  hw/arm/mps2-tz.c | 17 -
  1 file changed, 16 insertions(+), 1 deletion(-)


Reviewed-by: Richard Henderson 

r~




Re: [PATCH v2 18/24] hw/arm/mps2-tz: Support ROMs as well as RAMs

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

The AN505 and AN521 don't have any read-only memory, but the AN524
does; add a flag to ROMInfo to mark a region as ROM.

Signed-off-by: Peter Maydell
---
  hw/arm/mps2-tz.c | 6 ++
  1 file changed, 6 insertions(+)


Reviewed-by: Richard Henderson 

r~




Re: [PATCH v2 17/24] hw/arm/mps2-tz: Set MachineClass default_ram info from RAMInfo data

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

Instead of hardcoding the MachineClass default_ram_size and
default_ram_id fields, set them on class creation by finding the
entry in the RAMInfo array which is marked as being the QEMU system
RAM.

Signed-off-by: Peter Maydell
---
  hw/arm/mps2-tz.c | 24 ++--
  1 file changed, 22 insertions(+), 2 deletions(-)


Reviewed-by: Richard Henderson 

r~



Re: [PATCH v2 16/24] hw/arm/mps2-tz: Make RAM arrangement board-specific

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

The AN505 and AN521 have the same layout of RAM; the AN524 does not.
Replace the current hard-coding of where the RAM is and which parts
of it are behind which MPCs with a data-driven approach.

Signed-off-by: Peter Maydell
---
  hw/arm/mps2-tz.c | 175 +--
  1 file changed, 138 insertions(+), 37 deletions(-)


Reviewed-by: Richard Henderson 

r~




Re: [PATCH v2 15/24] hw/arm/mps2-tz: Allow boards to have different PPCInfo data

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

@@ -544,7 +546,7 @@ static void mps2tz_common_init(MachineState *machine)
   *  + wire up the PPC's control lines to the IoTKit object
   */
  
-const PPCInfo ppcs[] = { {

+const PPCInfo an505_ppcs[] = { {
  .name = "apb_ppcexp0",
  .ports = {
  { "ssram-0", make_mpc, >ssram_mpc[0], 0x58007000, 0x1000 
},


Existing nit, but about to be exacerbated by another array.  I'm not a fan of 
large, initialized, on-stack arrays.  Do you really need the pointer into the 
runtime variable mms?  Perhaps arrange for it to be an offsetof?  Then the 
whole thing can be static const.


That said, the change in this patch is ok.
Reviewed-by: Richard Henderson 

r~




Re: [PATCH v2 14/24] hw/arm/mps2-tz: Size the uart-irq-orgate based on the number of UARTs

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

We create an OR gate to wire together the overflow IRQs for all the
UARTs on the board; this has to have twice the number of inputs as
there are UARTs, since each UART feeds it a TX overflow and an RX
overflow interrupt line.  Replace the hardcoded '10' with a
calculation based on the size of the uart[] array in the
MPS2TZMachineState.  (We rely on OR gate inputs that are never wired
up or asserted being treated as always-zero.)

Signed-off-by: Peter Maydell
---
  hw/arm/mps2-tz.c | 11 ---
  1 file changed, 8 insertions(+), 3 deletions(-)


Reviewed-by: Richard Henderson 

r~




Re: [PATCH v2 13/24] hw/arm/mps2-tz: Move device IRQ info to data structures

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

Move the specification of the IRQ information for the uart, ethernet,
dma and spi devices to the data structures.  (The other devices
handled by the PPCPortInfo structures don't have any interrupt lines
we need to wire up.)

Signed-off-by: Peter Maydell
---
  hw/arm/mps2-tz.c | 52 +++-
  1 file changed, 25 insertions(+), 27 deletions(-)


Reviewed-by: Richard Henderson 

r~




Re: [PATCH v2 12/24] hw/arm/mps2-tz: Allow PPCPortInfo structures to specify device interrupts

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

The mps2-tz code uses PPCPortInfo data structures to define what
devices are present and how they are wired up.  Currently we use
these to specify device types and addresses, but hard-code the
interrupt line wiring in each make_* helper function.  This works for
the two boards we have at the moment, but the AN524 has some devices
with different interrupt assignments.

This commit adds the framework to allow PPCPortInfo structures to
specify interrupt numbers.  We add an array of interrupt numbers to
the PPCPortInfo struct, and pass it through to the make_* helpers.
The following commit will change the make_* helpers over to using the
framework.

Signed-off-by: Peter Maydell
---
  hw/arm/mps2-tz.c | 36 
  1 file changed, 24 insertions(+), 12 deletions(-)


Reviewed-by: Richard Henderson 

r~




Re: [PATCH v2 11/24] hw/arm/mps2-tz: Correct wrong interrupt numbers for DMA and SPI

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

On the MPS2 boards, the first 32 interrupt lines are entirely
internal to the SSE; interrupt lines for devices outside the SSE
start at 32.  In the application notes that document each FPGA image,
the interrupt wiring is documented from the point of view of the CPU,
so '0' is the first of the SSE's interrupts and the devices in the
FPGA image itself are '32' and up: so the UART 0 Receive interrupt is
32, the SPI #0 interrupt is 51, and so on.

Within our implementation, because the external interrupts must be
connected to the EXP_IRQ[0...n] lines of the SSE object, we made the
get_sse_irq_in() function take an irqno whose values start at 0 for
the first FPGA device interrupt.  In this numbering scheme the UART 0
Receive interrupt is 0, the SPI #0 interrupt is 19, and so on.

The result of these two different numbering schemes has been that
half of the devices were wired up to the wrong IRQs: the UART IRQs
are wired up correctly, but the DMA and SPI devices were passing
start-at-32 values to get_sse_irq_in() and so being mis-connected.

Fix the bug by making get_sse_irq_in() take values specified with the
same scheme that the hardware manuals use, to avoid confusion.

Signed-off-by: Peter Maydell
---
  hw/arm/mps2-tz.c | 24 +---
  1 file changed, 17 insertions(+), 7 deletions(-)


Reviewed-by: Richard Henderson 

r~




Re: [PATCH v2 10/24] hw/misc/mps2-scc: Implement CFG_REG5 and CFG_REG6 for MPS3 AN524

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

The AN524 version of the SCC interface has different behaviour for
some of the CFG registers; implement it.

Each board in this family can have minor differences in the meaning
of the CFG registers, so rather than trying to specify all the
possible semantics via individual device properties, we make the
behaviour conditional on the part-number field of the SCC_ID register
which the board code already passes us.

For the AN524, the differences are:
  * CFG3 is reserved rather than being board switches
  * CFG5 is a new register ("ACLK Frequency in Hz")
  * CFG6 is a new register ("Clock divider for BRAM")

We implement both of the new registers as reads-as-written.

Signed-off-by: Peter Maydell
---
  include/hw/misc/mps2-scc.h |  3 ++
  hw/misc/mps2-scc.c | 71 --
  2 files changed, 72 insertions(+), 2 deletions(-)


Reviewed-by: Richard Henderson 

r~




Re: [PATCH v2 09/24] hw/arm/mps2-tz: Make number of IRQs board-specific

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

The AN524 has more interrupt lines than the AN505 and AN521; make
numirq board-specific rather than a compile-time constant.

Since the difference is small (92 on the current boards and 95 on the
new one) we don't dynamically allocate the cpu_irq_splitter[] array
but leave it as a fixed length array whose size is the maximum needed
for any of the boards.

Signed-off-by: Peter Maydell
Reviewed-by: Philippe Mathieu-Daudé
---
  hw/arm/mps2-tz.c | 15 ++-
  1 file changed, 10 insertions(+), 5 deletions(-)


Reviewed-by: Richard Henderson 

r~




Re: [PATCH v2 07/24] hw/arm/mps2-tz: Make FPGAIO switch and LED config per-board

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

Set the FPGAIO num-leds and have-switches properties explicitly
per-board, rather than relying on the defaults.  The AN505 and AN521
both have the same settings as the default values, but the AN524 will
be different.

Signed-off-by: Peter Maydell
Reviewed-by: Philippe Mathieu-Daudé
---
  hw/arm/mps2-tz.c | 9 +
  1 file changed, 9 insertions(+)


Reviewed-by: Richard Henderson 

r~




Re: [PATCH v2 06/24] hw/misc/mps2-fpgaio: Support SWITCH register

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

MPS3 boards have an extra SWITCH register in the FPGAIO block which
reports the value of some switches.  Implement this, governed by a
property the board code can use to specify whether whether it exists.

Signed-off-by: Peter Maydell
Reviewed-by: Philippe Mathieu-Daudé
---
  include/hw/misc/mps2-fpgaio.h |  1 +
  hw/misc/mps2-fpgaio.c | 10 ++
  2 files changed, 11 insertions(+)


Reviewed-by: Richard Henderson 

r~




Re: [PATCH v2 05/24] hw/misc/mps2-fpgaio: Make number of LEDs configurable by board

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

The MPS2 board has 2 LEDs, but the MPS3 board has 10 LEDs.  The
FPGAIO device is similar on both sets of boards, but the LED0
register has correspondingly more bits that have an effect.  Add a
device property for number of LEDs.

Signed-off-by: Peter Maydell
Reviewed-by: Philippe Mathieu-Daudé
---
  include/hw/misc/mps2-fpgaio.h |  5 -
  hw/misc/mps2-fpgaio.c | 31 +++
  2 files changed, 27 insertions(+), 9 deletions(-)


Similar comment with 'int i' / 'uint32_t num_leds'.  Otherwise,

Reviewed-by: Richard Henderson 

r~




Re: [PATCH v2 04/24] hw/arm/mps2-tz: Make the OSCCLK settings be configurable per-board

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

+uint32_t len_oscclk;

...

+int i;

...

+for (i = 0; i < mmc->len_oscclk; i++) {


Shouldn't mix types.  I'm surprised you didn't see a warning.

Otherwise,
Reviewed-by: Richard Henderson 

r~



Re: [PATCH v2 1/2] target/i386: add "-cpu, lbr-fmt=*" support to enable guest LBR

2021-02-28 Thread Like Xu

Hi Paolo & Eduardo,

Do we have any comment for the QEMU LBR enabling patches?

https://lore.kernel.org/qemu-devel/20210201045453.240258-1-like...@linux.intel.com/

On 2021/2/1 12:54, Like Xu wrote:

The last branch recording (LBR) is a performance monitor unit (PMU)
feature on Intel processors that records a running trace of the most
recent branches taken by the processor in the LBR stack. The QEMU
could configure whether it's enabled or not for each guest via CLI.

The LBR feature would be enabled on the guest if:
- the KVM is enabled and the PMU is enabled and,
- the msr-based-feature IA32_PERF_CAPABILITIES is supporterd on KVM and,
- the supported returned value for lbr_fmt from this msr is not zero and,
- the requested guest vcpu model does support FEAT_1_ECX.CPUID_EXT_PDCM,
- the configured lbr-fmt value is the same as the host lbr_fmt value
   or use the QEMU option "-cpu host,migratable=no".

Cc: Eduardo Habkost 
Cc: Paolo Bonzini 
Signed-off-by: Like Xu 
---
  target/i386/cpu.c | 16 
  target/i386/cpu.h | 10 ++
  target/i386/kvm/kvm.c |  5 +++--
  3 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index ae89024d36..80a5d3f0c2 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -6504,6 +6504,13 @@ static void x86_cpu_filter_features(X86CPU *cpu, bool 
verbose)
  x86_cpu_get_supported_feature_word(w, false);
  uint64_t requested_features = env->features[w];
  uint64_t unavailable_features = requested_features & ~host_feat;
+if (kvm_enabled() && w == FEAT_PERF_CAPABILITIES &&
+(requested_features & PERF_CAP_LBR_FMT)) {
+if ((host_feat & PERF_CAP_LBR_FMT) !=
+(requested_features & PERF_CAP_LBR_FMT)) {
+unavailable_features |= PERF_CAP_LBR_FMT;
+}
+}
  mark_unavailable_features(cpu, w, unavailable_features, prefix);
  }
  
@@ -6611,6 +6618,14 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)

  }
  }
  
+if (cpu->lbr_fmt) {

+if (!cpu->enable_pmu) {
+error_setg(errp, "LBR is unsupported since guest PMU is 
disabled.");
+return;
+}
+env->features[FEAT_PERF_CAPABILITIES] |= cpu->lbr_fmt;
+}
+
  /* mwait extended info: needed for Core compatibility */
  /* We always wake on interrupt even if host does not have the capability 
*/
  cpu->mwait.ecx |= CPUID_MWAIT_EMX | CPUID_MWAIT_IBE;
@@ -7184,6 +7199,7 @@ static Property x86_cpu_properties[] = {
  #endif
  DEFINE_PROP_INT32("node-id", X86CPU, node_id, CPU_UNSET_NUMA_NODE_ID),
  DEFINE_PROP_BOOL("pmu", X86CPU, enable_pmu, false),
+DEFINE_PROP_UINT8("lbr-fmt", X86CPU, lbr_fmt, 0),
  
  DEFINE_PROP_UINT32("hv-spinlocks", X86CPU, hyperv_spinlock_attempts,

 HYPERV_SPINLOCK_NEVER_NOTIFY),
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index d23a5b340a..64320bced2 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -354,6 +354,7 @@ typedef enum X86Seg {
  #define ARCH_CAP_TSX_CTRL_MSR (1<<7)
  
  #define MSR_IA32_PERF_CAPABILITIES  0x345

+#define PERF_CAP_LBR_FMT  0x3f
  
  #define MSR_IA32_TSX_CTRL		0x122

  #define MSR_IA32_TSCDEADLINE0x6e0
@@ -1709,6 +1710,15 @@ struct X86CPU {
   */
  bool enable_pmu;
  
+/*

+ * Configure LBR_FMT bits on IA32_PERF_CAPABILITIES MSR.
+ * This can't be enabled by default yet because it doesn't have
+ * ABI stability guarantees, as it is only allowed to pass all
+ * LBR_FMT bits returned by kvm_arch_get_supported_msr_feature()
+ * (that depends on host CPU and kernel capabilities) to the guest.
+ */
+uint8_t lbr_fmt;
+
  /* LMCE support can be enabled/disabled via cpu option 'lmce=on/off'. It 
is
   * disabled by default to avoid breaking migration between QEMU with
   * different LMCE configurations.
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 6dc1ee052d..49745efb78 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -2705,8 +2705,9 @@ static void kvm_msr_entry_add_perf(X86CPU *cpu, 
FeatureWordArray f)
 MSR_IA32_PERF_CAPABILITIES);
  
  if (kvm_perf_cap) {

-kvm_msr_entry_add(cpu, MSR_IA32_PERF_CAPABILITIES,
-kvm_perf_cap & f[FEAT_PERF_CAPABILITIES]);
+kvm_perf_cap = cpu->migratable ?
+(kvm_perf_cap & f[FEAT_PERF_CAPABILITIES]) : kvm_perf_cap;
+kvm_msr_entry_add(cpu, MSR_IA32_PERF_CAPABILITIES, kvm_perf_cap);
  }
  }
  






Re: [PATCH v2 03/24] hw/arm/mps2-tz: Correct the OSCCLK settings for mps2-an505 and mps2-an511

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

We were previously using the default OSCCLK settings, which are
correct for the older MPS2 boards (mps2-an385, mps2-an386,
mps2-an500, mps2-an511), but wrong for the mps2-an505 and mps2-511
implemented in mps2-tz.c.  Now we're setting the values explicitly we
can fix them to be correct.

Signed-off-by: Peter Maydell
Reviewed-by: Philippe Mathieu-Daudé
---
  hw/arm/mps2-tz.c | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)


Reviewed-by: Richard Henderson 

r~




Re: [PATCH v2 02/24] hw/misc/mps2-scc: Support configurable number of OSCCLK values

2021-02-28 Thread Richard Henderson

On 2/15/21 3:51 AM, Peter Maydell wrote:

Currently the MPS2 SCC device implements a fixed number of OSCCLK
values (3).  The variant of this device in the MPS3 AN524 board has 6
OSCCLK values.  Switch to using a PROP_ARRAY, which allows board code
to specify how large the OSCCLK array should be as well as its
values.

With a variable-length property array, the SCC no longer specifies
default values for the OSCCLKs, so we must set them explicitly in the
board code.  This defaults are actually incorrect for the an521 and
an505; we will correct this bug in a following patch.

This is a migration compatibility break for all the mps boards.

Signed-off-by: Peter Maydell
---
It would be possible to avoid the compat break, but we've already
broken compat for the mps boards this release cycle (eg in commit
eeae0b2bf4e69de2) when we added Clock support to the armsse code, so
there's no point in trying to keep compat for this change.
Reviewed-by: Philippe Mathieu-Daudé
---
  include/hw/misc/mps2-scc.h |  7 +++
  hw/arm/mps2-tz.c   |  5 +
  hw/arm/mps2.c  |  5 +
  hw/misc/mps2-scc.c | 24 +---
  4 files changed, 26 insertions(+), 15 deletions(-)


Reviewed-by: Richard Henderson 

r~




[RESEND][BUG FIX HELP] QEMU main thread endlessly hangs in __ppoll()

2021-02-28 Thread Like Xu

Hi Genius,

I am a user of QEMU v4.2.0 and stuck in an interesting bug, which may still 
exist in the mainline.

Thanks in advance to heroes who can take a look and share understanding.

The qemu main thread endlessly hangs in the handle of the qmp statement:
{'execute': 'human-monitor-command', 'arguments':{ 'command-line': 
'drive_del replication0' } }

and we have the call trace looks like:

#0 0x7f3c22045bf6 in __ppoll (fds=0x555611328410, nfds=1, 
timeout=, timeout@entry=0x7ffc56c66db0,

sigmask=sigmask@entry=0x0) at ../sysdeps/unix/sysv/linux/ppoll.c:44
#1 0x55561021f415 in ppoll (__ss=0x0, __timeout=0x7ffc56c66db0, 
__nfds=, __fds=)

at /usr/include/x86_64-linux-gnu/bits/poll2.h:77
#2 qemu_poll_ns (fds=, nfds=, 
timeout=) at util/qemu-timer.c:348
#3 0x555610221430 in aio_poll (ctx=ctx@entry=0x5556113010f0, 
blocking=blocking@entry=true) at util/aio-posix.c:669
#4 0x55561019268d in bdrv_do_drained_begin (poll=true, 
ignore_bds_parents=false, parent=0x0, recursive=false,

bs=0x55561138b0a0) at block/io.c:430
#5 bdrv_do_drained_begin (bs=0x55561138b0a0, recursive=, 
parent=0x0, ignore_bds_parents=,

poll=) at block/io.c:396
#6 0x55561017b60b in quorum_del_child (bs=0x55561138b0a0, 
child=0x7f36dc0ce380, errp=)

at block/quorum.c:1063
#7 0x55560ff5836b in qmp_x_blockdev_change (parent=0x555612373120 
"colo-disk0", has_child=,
child=0x5556112df3e0 "children.1", has_node=, node=0x0, 
errp=0x7ffc56c66f98) at blockdev.c:4494
#8 0x5556100f8f57 in qmp_marshal_x_blockdev_change (args=out>, ret=, errp=0x7ffc56c67018)

at qapi/qapi-commands-block-core.c:1538
#9 0x5556101d8290 in do_qmp_dispatch (errp=0x7ffc56c67010, 
allow_oob=, request=,

cmds=0x5556109c69a0 ) at qapi/qmp-dispatch.c:132
#10 qmp_dispatch (cmds=0x5556109c69a0 , request=out>, allow_oob=)

at qapi/qmp-dispatch.c:175
#11 0x5556100d4c4d in monitor_qmp_dispatch (mon=0x5556113a6f40, 
req=) at monitor/qmp.c:145
#12 0x5556100d5437 in monitor_qmp_bh_dispatcher (data=) 
at monitor/qmp.c:234
#13 0x55561021dbec in aio_bh_call (bh=0x5556112164bGrateful0) at 
util/async.c:117

#14 aio_bh_poll (ctx=ctx@entry=0x5556112151b0) at util/async.c:117
#15 0x5556102212c4 in aio_dispatch (ctx=0x5556112151b0) at 
util/aio-posix.c:459
#16 0x55561021dab2 in aio_ctx_dispatch (source=, 
callback=, user_data=)

at util/async.c:260
#17 0x7f3c22302fbd in g_main_context_dispatch () from 
/lib/x86_64-linux-gnu/libglib-2.0.so.0

#18 0x555610220358 in glib_pollfds_poll () at util/main-loop.c:219
#19 os_host_main_loop_wait (timeout=) at util/main-loop.c:242
#20 main_loop_wait (nonblocking=) at util/main-loop.c:518
#21 0x55560ff600fe in main_loop () at vl.c:1814
#22 0x55560fddbce9 in main (argc=, argv=, 
envp=) at vl.c:4503


We found that we're doing endless check in the line of 
block/io.c:bdrv_do_drained_begin():

BDRV_POLL_WHILE(bs, bdrv_drain_poll_top_level(bs, recursive, parent));
and it turns out that the bdrv_drain_poll() always get true from:
- bdrv_parent_drained_poll(bs, ignore_parent, ignore_bds_parents)
- AND atomic_read(>in_flight)

I personally think this is a deadlock issue in the a QEMU block layer
(as we know, we have some #FIXME comments in related codes, such as block 
permisson update).

Any comments are welcome and appreciated.

---
thx,likexu



Re: [PATCH] vfio/migrate: Move switch of dirty tracking into vfio_memory_listener

2021-02-28 Thread Keqian Zhu
Hi Kirti,

What's your opinion about this? Thanks.

Keqian

On 2021/1/30 14:30, Keqian Zhu wrote:
> Hi Kirti,
> 
> On 2021/1/28 5:03, Kirti Wankhede wrote:
>>
>>
>> On 1/11/2021 1:04 PM, Keqian Zhu wrote:
>>> For now the switch of vfio dirty page tracking is integrated into
>>> the vfio_save_handler, it causes some problems [1].
>>>
>>
>> Sorry, I missed [1] mail, somehow it didn't landed in my inbox.
>>
>>> The object of dirty tracking is guest memory, but the object of
>>> the vfio_save_handler is device state. This mixed logic produces
>>> unnecessary coupling and conflicts:
>>>
>>> 1. Coupling: Their saving granule is different (perVM vs perDevice).
>>> vfio will enable dirty_page_tracking for each devices, actually
>>> once is enough.
>>
>> That's correct, enabling dirty page tracking once is enough. But log_start 
>> and log_stop gets called on address space update transaction, region_add() 
>> or region_del(), at this point migration may not be active. We don't want to 
>> allocate bitmap memory in kernel for lifetime of VM, without knowing 
>> migration will be happen or not. vfio_iommu_type1 module should allocate 
>> bitmap memory only while migration is active.
>>
> Yeah, we can use global start/stop callbacks as suggested by Paolo, which 
> solves this problem.
> 
>> Paolo's suggestion here to use log_global_start and log_global_stop 
>> callbacks seems correct here. But at this point vfio device state is not yet 
>> changed to |_SAVING as you had identified it in [1]. May be we can start 
>> tracking bitmap in iommu_type1 module while device is not yet _SAVING, but 
>> getting dirty bitmap while device is yet not in _SAVING|_RUNNING state 
>> doesn't seem optimal solution.
>>
>> Pasting here your question from [1]
>>
>>> Before start dirty tracking, we will check and ensure that the device
>>>  is at _SAVING state and return error otherwise.  But the question is
>>>  that what is the rationale?  Why does the VFIO_IOMMU_DIRTY_PAGES
>>> ioctl have something to do with the device state?
>>
>> Lets walk through the types of devices we are supporting:
>> 1. mdev devices without IOMMU backed device
>> Vendor driver pins pages as and when required during runtime. We can say 
>> that vendor driver is smart which identifies the pages to pin. We are good 
>> here.
>>
>> 2. mdev device with IOMMU backed device
>> This is similar to vfio-pci, direct assigned device, where all pages are 
>> pinned at VM bootup. Vendor driver is not smart, so bitmap query will report 
>> all pages dirty always. If --auto-converge is not set, VM stucks infinitely 
>> in pre-copy phase. This is known to us.
>>
> little question here ;-) . Why auto-converge (slow down vCPU) helps to ease 
> the case of full dirty?
> 
>> 3. mdev device with IOMMU backed device with smart vendor driver
>> In this case as well all pages are pinned at VM bootup, but vendor 
>> driver is smart to identify the pages and pin them explicitly.
>> Pages can be pinned anytime, i.e. during normal VM runtime or on setting 
>> _SAVING flag (entering pre-copy phase) or while in iterative pre-copy phase. 
>> There is no restriction based on these phases for calling vfio_pin_pages(). 
>> Vendor driver can start pinning pages based on its device state when _SAVING 
>> flag is set. In that case, if dirty bitmap is queried before that then it 
>> will report all sysmem as dirty with an unnecessary copy of sysmem.
>> As an optimal solution, I think its better to query bitmap only after all 
>> vfio devices are in pre-copy phase, i.e. after _SAVING flag is set.
> OK, I get your idea. But Qemu assumes all pages are dirty initially, this 
> seems not a problem.
> Let's assume we have a device of type 3, and this device starts to pin pages 
> on setting _SAVING flag.
> 
> Before this patch, the work flow is:
> {
> ram_save_setup()
> memory_global_dirty_log_start():  start dirty tracking excludes vfio part.
> migration_bitmap_sync_precopy():  try to sync dirty log from kvm, vhost 
> etc, including vfio (as all device saving is not satisfied, fail to get log 
> from vfio). The result is that bitmap of ramblock is all dirty.
> 
> vfio_save_setup() of this device
> vfio_migration_set_state(): Add SAVING state to this device, and vfio 
> starts to log dirty page of this device.
> 
> first round (i.e. bulk stage) of ram saving: only handle dirty log which is 
> collected from the first call of migration_bitmap_sync_precopy().
> 
> iterative stage of ram saving: when the remaining dirty log is less than 
> threshold, call migration_bitmap_sync_precopy() again. At this stage, all 
> device is saving, so success to get log from vfio.
> }
> 
> With this patch, the work flow is:
> {
> ram_save_setup()
> memory_global_dirty_log_start():  start dirty tracking includes vfio part.
> migration_bitmap_sync_precopy():  try to sync dirty log from kvm, vhost 
> etc, including vfio (as all device saving is not checked, success to get full 
> dirty 

Re: [PATCH 0/2] tcg/aarch64: Fixes to vector ops

2021-02-28 Thread Richard Henderson

Ping.

On 2/20/21 1:29 PM, Richard Henderson wrote:

I guess it has been a while since I've run aa32 risu on aa64 host.

The launchpad bug is something that should have been seen from the
beginning, but the similar aa64 operations are expanded as integer
code, not vector code.  The aa32 neon code has only recently been
converted to use gvecs.

The cmle0 (zero) bug has been exposed by the recent constant
propagation improvements; previously we saw a reg/reg compare.


r~


Richard Henderson (2):
   tcg/aarch64: Fix I3617_CMLE0
   tcg/aarch64: Fix generation of "scalar" vector operations

  tcg/aarch64/tcg-target.c.inc | 213 ++-
  1 file changed, 182 insertions(+), 31 deletions(-)






Re: [PATCH v5 1/1] virtio-net: Add check for mac address while peer is vdpa

2021-02-28 Thread Cindy Lu
On Mon, Mar 1, 2021 at 4:40 AM Michael S. Tsirkin  wrote:
>
> On Thu, Feb 25, 2021 at 02:14:39PM -0500, Michael S. Tsirkin wrote:
> > On Fri, Feb 26, 2021 at 12:55:06AM +0800, Cindy Lu wrote:
> > > While peer is vdpa, sometime qemu get an all zero mac address from the 
> > > hardware,
> > > This is not a legal value. Add the check for this.if we get an zero mac 
> > > address.
> > > qemu will use the default mac address or the mac address from qemu cmdline
> > >
> > > Signed-off-by: Cindy Lu 
> >
> > I guess I will have to rewrite the comments and commit log :(
> >
> > It is all saying what does the patch do. We want it to rather
> > give motivation.
> >
> > Sean could you please comment on whether this patch fixes your
> > config?
>
> ping. if I'm to try and merge this work around it's critical
> that someone with access to hardware confirm it actually works.
>
Hi Michael, I have tested this patch in qemu+vdpa+mlx environment.
it's working fine.
>
> > > ---
> > >  hw/net/virtio-net.c | 10 ++
> > >  1 file changed, 10 insertions(+)
> > >
> > > diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> > > index 9179013ac4..8f36ca5066 100644
> > > --- a/hw/net/virtio-net.c
> > > +++ b/hw/net/virtio-net.c
> > > @@ -126,6 +126,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, 
> > > uint8_t *config)
> > >  VirtIONet *n = VIRTIO_NET(vdev);
> > >  struct virtio_net_config netcfg;
> > >  NetClientState *nc = qemu_get_queue(n->nic);
> > > +static const MACAddr zero = { .a = { 0, 0, 0, 0, 0, 0 } };
> > >
> > >  int ret = 0;
> > >  memset(, 0 , sizeof(struct virtio_net_config));
> > > @@ -151,6 +152,15 @@ static void virtio_net_get_config(VirtIODevice 
> > > *vdev, uint8_t *config)
> > >  ret = vhost_net_get_config(get_vhost_net(nc->peer), (uint8_t 
> > > *),
> > > n->config_size);
> > >  if (ret != -1) {
> > > +/*
> > > + * Here is a work around, the 0 mac address is not a legal 
> > > value.
> > > + * if we got this from hardware, qemu will use the mac 
> > > address
> > > + * saved in VirtIONet->mac.
> > > + */
> > > +if (memcmp(, , sizeof(zero)) == 0) {
> > > +info_report("Get an all zero mac address from hardware");
> > > +memcpy(netcfg.mac, n->mac, ETH_ALEN);
> > > +}
> > >  memcpy(config, , n->config_size);
> > >  }
> > >  }
> > > --
> > > 2.21.3
>




[PATCH v2 5/5] hw/misc: Model KCS devices in the Aspeed LPC controller

2021-02-28 Thread Andrew Jeffery
Keyboard-Controller-Style devices for IPMI purposes are exposed via LPC
IO cycles from the BMC to the host.

Expose support on the BMC side by implementing the usual MMIO
behaviours, and expose the ability to inspect the KCS registers in
"host" style by accessing QOM properties associated with each register.

The model caters to the IRQ style of both the AST2600 and the earlier
SoCs (AST2400 and AST2500). The AST2600 allocates an IRQ for each LPC
sub-device, while there is a single IRQ shared across all subdevices on
the AST2400 and AST2500.

Signed-off-by: Andrew Jeffery 
---
 hw/arm/aspeed_ast2600.c  |  28 ++-
 hw/arm/aspeed_soc.c  |  24 ++-
 hw/misc/aspeed_lpc.c | 359 ++-
 include/hw/arm/aspeed_soc.h  |   1 +
 include/hw/misc/aspeed_lpc.h |  17 +-
 5 files changed, 424 insertions(+), 5 deletions(-)

diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index 60152de001e6..fd463775d281 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -104,7 +104,7 @@ static const int aspeed_soc_ast2600_irqmap[] = {
 [ASPEED_DEV_ETH2]  = 3,
 [ASPEED_DEV_ETH3]  = 32,
 [ASPEED_DEV_ETH4]  = 33,
-
+[ASPEED_DEV_KCS]   = 138,   /* 138 -> 142 */
 };
 
 static qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int ctrl)
@@ -477,8 +477,34 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, 
Error **errp)
 return;
 }
 sysbus_mmio_map(SYS_BUS_DEVICE(>lpc), 0, sc->memmap[ASPEED_DEV_LPC]);
+
+/* Connect the LPC IRQ to the GIC. It is otherwise unused. */
 sysbus_connect_irq(SYS_BUS_DEVICE(>emmc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_LPC));
+
+/*
+ * On the AST2600 LPC subdevice IRQs are connected straight to the GIC.
+ *
+ * LPC subdevice IRQ sources are offset from 1 because the LPC model caters
+ * to the AST2400 and AST2500. SoCs before the AST2600 have one LPC IRQ
+ * shared across the subdevices, and the shared IRQ output to the VIC is at
+ * offset 0.
+ */
+sysbus_connect_irq(SYS_BUS_DEVICE(>lpc), 1 + aspeed_lpc_kcs_1,
+   qdev_get_gpio_in(DEVICE(>a7mpcore),
+sc->irqmap[ASPEED_DEV_KCS] + 
aspeed_lpc_kcs_1));
+
+sysbus_connect_irq(SYS_BUS_DEVICE(>lpc), 1 + aspeed_lpc_kcs_2,
+   qdev_get_gpio_in(DEVICE(>a7mpcore),
+sc->irqmap[ASPEED_DEV_KCS] + 
aspeed_lpc_kcs_2));
+
+sysbus_connect_irq(SYS_BUS_DEVICE(>lpc), 1 + aspeed_lpc_kcs_3,
+   qdev_get_gpio_in(DEVICE(>a7mpcore),
+sc->irqmap[ASPEED_DEV_KCS] + 
aspeed_lpc_kcs_3));
+
+sysbus_connect_irq(SYS_BUS_DEVICE(>lpc), 1 + aspeed_lpc_kcs_4,
+   qdev_get_gpio_in(DEVICE(>a7mpcore),
+sc->irqmap[ASPEED_DEV_KCS] + 
aspeed_lpc_kcs_4));
 }
 
 static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data)
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
index 4f098da437ac..057d053c8478 100644
--- a/hw/arm/aspeed_soc.c
+++ b/hw/arm/aspeed_soc.c
@@ -112,7 +112,6 @@ static const int aspeed_soc_ast2400_irqmap[] = {
 [ASPEED_DEV_WDT]= 27,
 [ASPEED_DEV_PWM]= 28,
 [ASPEED_DEV_LPC]= 8,
-[ASPEED_DEV_IBT]= 8, /* LPC */
 [ASPEED_DEV_I2C]= 12,
 [ASPEED_DEV_ETH1]   = 2,
 [ASPEED_DEV_ETH2]   = 3,
@@ -401,8 +400,31 @@ static void aspeed_soc_realize(DeviceState *dev, Error 
**errp)
 return;
 }
 sysbus_mmio_map(SYS_BUS_DEVICE(>lpc), 0, sc->memmap[ASPEED_DEV_LPC]);
+
+/* Connect the LPC IRQ to the VIC */
 sysbus_connect_irq(SYS_BUS_DEVICE(>lpc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_LPC));
+
+/*
+ * On the AST2400 and AST2500 the one LPC IRQ is shared between all of the
+ * subdevices. Connect the LPC subdevice IRQs to the LPC controller IRQ (by
+ * contrast, on the AST2600, the subdevice IRQs are connected straight to
+ * the GIC).
+ *
+ * LPC subdevice IRQ sources are offset from 1 because the shared IRQ 
output
+ * to the VIC is at offset 0.
+ */
+sysbus_connect_irq(SYS_BUS_DEVICE(>lpc), 1 + aspeed_lpc_kcs_1,
+   qdev_get_gpio_in(DEVICE(>lpc), aspeed_lpc_kcs_1));
+
+sysbus_connect_irq(SYS_BUS_DEVICE(>lpc), 1 + aspeed_lpc_kcs_2,
+   qdev_get_gpio_in(DEVICE(>lpc), aspeed_lpc_kcs_2));
+
+sysbus_connect_irq(SYS_BUS_DEVICE(>lpc), 1 + aspeed_lpc_kcs_3,
+   qdev_get_gpio_in(DEVICE(>lpc), aspeed_lpc_kcs_3));
+
+sysbus_connect_irq(SYS_BUS_DEVICE(>lpc), 1 + aspeed_lpc_kcs_4,
+   qdev_get_gpio_in(DEVICE(>lpc), aspeed_lpc_kcs_4));
 }
 static Property aspeed_soc_properties[] = {
 DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION,
diff --git a/hw/misc/aspeed_lpc.c b/hw/misc/aspeed_lpc.c
index e668e985ff04..2dddb27c35d0 100644
--- a/hw/misc/aspeed_lpc.c

[PATCH v2 3/5] hw/arm: ast2600: Correct the iBT interrupt ID

2021-02-28 Thread Andrew Jeffery
The AST2600 allocates distinct GIC IRQs for the LPC subdevices such as
the iBT device. Previously on the AST2400 and AST2500 the LPC subdevices
shared a single LPC IRQ.

Signed-off-by: Andrew Jeffery 
---
 hw/arm/aspeed_ast2600.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index 22fcb5b0edbe..2125a96ef317 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -98,7 +98,7 @@ static const int aspeed_soc_ast2600_irqmap[] = {
 [ASPEED_DEV_WDT]   = 24,
 [ASPEED_DEV_PWM]   = 44,
 [ASPEED_DEV_LPC]   = 35,
-[ASPEED_DEV_IBT]   = 35,/* LPC */
+[ASPEED_DEV_IBT]   = 143,
 [ASPEED_DEV_I2C]   = 110,   /* 110 -> 125 */
 [ASPEED_DEV_ETH1]  = 2,
 [ASPEED_DEV_ETH2]  = 3,
-- 
2.27.0




[PATCH v2 4/5] hw/misc: Add a basic Aspeed LPC controller model

2021-02-28 Thread Andrew Jeffery
From: Cédric Le Goater 

This is a very minimal framework to access registers which are used to
configure the AHB memory mapping of the flash chips on the LPC HC
Firmware address space.

Signed-off-by: Cédric Le Goater 
Signed-off-by: Andrew Jeffery 
---
 docs/system/arm/aspeed.rst   |   2 +-
 hw/arm/aspeed_ast2600.c  |  10 +++
 hw/arm/aspeed_soc.c  |  10 +++
 hw/misc/aspeed_lpc.c | 131 +++
 hw/misc/meson.build  |   7 +-
 include/hw/arm/aspeed_soc.h  |   2 +
 include/hw/misc/aspeed_lpc.h |  32 +
 7 files changed, 192 insertions(+), 2 deletions(-)
 create mode 100644 hw/misc/aspeed_lpc.c
 create mode 100644 include/hw/misc/aspeed_lpc.h

diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst
index 690bada7842b..2f6fa8938d02 100644
--- a/docs/system/arm/aspeed.rst
+++ b/docs/system/arm/aspeed.rst
@@ -48,6 +48,7 @@ Supported devices
  * UART
  * Ethernet controllers
  * Front LEDs (PCA9552 on I2C bus)
+ * LPC Peripheral Controller (a subset of subdevices are supported)
 
 
 Missing devices
@@ -56,7 +57,6 @@ Missing devices
  * Coprocessor support
  * ADC (out of tree implementation)
  * PWM and Fan Controller
- * LPC Bus Controller
  * Slave GPIO Controller
  * Super I/O Controller
  * Hash/Crypto Engine
diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index 2125a96ef317..60152de001e6 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -211,6 +211,8 @@ static void aspeed_soc_ast2600_init(Object *obj)
 
 object_initialize_child(obj, "emmc-controller.sdhci", >emmc.slots[0],
 TYPE_SYSBUS_SDHCI);
+
+object_initialize_child(obj, "lpc", >lpc, TYPE_ASPEED_LPC);
 }
 
 /*
@@ -469,6 +471,14 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, 
Error **errp)
 sysbus_mmio_map(SYS_BUS_DEVICE(>emmc), 0, sc->memmap[ASPEED_DEV_EMMC]);
 sysbus_connect_irq(SYS_BUS_DEVICE(>emmc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_EMMC));
+
+/* LPC */
+if (!sysbus_realize(SYS_BUS_DEVICE(>lpc), errp)) {
+return;
+}
+sysbus_mmio_map(SYS_BUS_DEVICE(>lpc), 0, sc->memmap[ASPEED_DEV_LPC]);
+sysbus_connect_irq(SYS_BUS_DEVICE(>emmc), 0,
+   aspeed_soc_get_irq(s, ASPEED_DEV_LPC));
 }
 
 static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data)
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
index 7eefd54ac07a..4f098da437ac 100644
--- a/hw/arm/aspeed_soc.c
+++ b/hw/arm/aspeed_soc.c
@@ -211,6 +211,8 @@ static void aspeed_soc_init(Object *obj)
 object_initialize_child(obj, "sdhci[*]", >sdhci.slots[i],
 TYPE_SYSBUS_SDHCI);
 }
+
+object_initialize_child(obj, "lpc", >lpc, TYPE_ASPEED_LPC);
 }
 
 static void aspeed_soc_realize(DeviceState *dev, Error **errp)
@@ -393,6 +395,14 @@ static void aspeed_soc_realize(DeviceState *dev, Error 
**errp)
 sc->memmap[ASPEED_DEV_SDHCI]);
 sysbus_connect_irq(SYS_BUS_DEVICE(>sdhci), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_SDHCI));
+
+/* LPC */
+if (!sysbus_realize(SYS_BUS_DEVICE(>lpc), errp)) {
+return;
+}
+sysbus_mmio_map(SYS_BUS_DEVICE(>lpc), 0, sc->memmap[ASPEED_DEV_LPC]);
+sysbus_connect_irq(SYS_BUS_DEVICE(>lpc), 0,
+   aspeed_soc_get_irq(s, ASPEED_DEV_LPC));
 }
 static Property aspeed_soc_properties[] = {
 DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION,
diff --git a/hw/misc/aspeed_lpc.c b/hw/misc/aspeed_lpc.c
new file mode 100644
index ..e668e985ff04
--- /dev/null
+++ b/hw/misc/aspeed_lpc.c
@@ -0,0 +1,131 @@
+/*
+ *  ASPEED LPC Controller
+ *
+ *  Copyright (C) 2017-2018 IBM Corp.
+ *
+ * This code is licensed under the GPL version 2 or later.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/error-report.h"
+#include "hw/misc/aspeed_lpc.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+
+#define TO_REG(offset) ((offset) >> 2)
+
+#define HICR0TO_REG(0x00)
+#define HICR1TO_REG(0x04)
+#define HICR2TO_REG(0x08)
+#define HICR3TO_REG(0x0C)
+#define HICR4TO_REG(0x10)
+#define HICR5TO_REG(0x80)
+#define HICR6TO_REG(0x84)
+#define HICR7TO_REG(0x88)
+#define HICR8TO_REG(0x8C)
+
+static uint64_t aspeed_lpc_read(void *opaque, hwaddr offset, unsigned size)
+{
+AspeedLPCState *s = ASPEED_LPC(opaque);
+int reg = TO_REG(offset);
+
+if (reg >= ARRAY_SIZE(s->regs)) {
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
+  __func__, offset);
+return 0;
+}
+
+return s->regs[reg];
+}
+
+static void aspeed_lpc_write(void *opaque, hwaddr offset, 

[PATCH v2 0/5] aspeed: LPC peripheral controller devices

2021-02-28 Thread Andrew Jeffery
Hello,

This series adds support for some of the LPC[1] peripherals found in Aspeed BMC
SoCs.

v2 addresses some minor feedback from Philippe and Cédric. v1 can be found here:

https://lore.kernel.org/qemu-devel/20210226065758.547824-1-and...@aj.id.au/T/#m28b4392d0672e85fbfaaf6565a2da2e82de1691d

BMCs typically provide a number of features to their host via LPC that include
but are not limited to:

1. Mapping LPC firmware cycles to BMC-controlled flash devices
2. UART(s) for system console routing
3. POST code routing
4. Keyboard-Controller-Style (KCS) IPMI devices
5. Block Transfer (BT) IPMI devices
6. A SuperIO controller for management of LPC devices and miscellaneous
   functionality

[1] 
https://www.intel.com/content/dam/www/program/design/us/en/documents/low-pin-count-interface-specification.pdf

Specifically, this series adds basic support for functions 1 and 4 above,
handling the BMC firmware configuring the bridge mapping LPC firmware cycles
onto its AHB as well as support for four KCS devices.

Aspeed's LPC controller is not a straight-forward device by any stretch. It
contains at least the capabilities outlined above, in the sense that it's not
possible to cleanly separate the different functions into distinct MMIO
sub-regions: Registers for the various bits of functionality have the feel of
arbitrary placement with a nod to feature-creep and backwards compatibility.
Further, the conceptually coherent pieces of functionality often come with the
ability to issue interrupts, though for the AST2400 and AST2500 there is one
shared VIC IRQ for all LPC "subdevices". By contrast the AST2600 gives each
subdevice a distinct IRQ via the GIC.

All this combined leads to some complexity regarding the interrupts and handling
the MMIO accesses (in terms of mapping the access back to the function it's
affecting).

Finally, as a point of clarity, Aspeed BMCs also contain an LPC Host Controller
to drive the LPC bus. This series does not concern itself with the LPC Host
Controller function, only with a subset of the peripheral devices the BMC
presents to the host.

I've tested the series using a combination of the ast2600-evb, witherspoon-bmc
and romulus-bmc machines along with a set of recently-posted patches for
Linux[2].

Please review!

Andrew

[2] 
https://lore.kernel.org/openbmc/20210219142523.3464540-1-and...@aj.id.au/T/#m1e2029e7aa2be3056320e8d46b3b5b1539a776b4

Andrew Jeffery (4):
  arm: ast2600: Force a multiple of 32 of IRQs for the GIC
  hw/arm: ast2600: Set AST2600_MAX_IRQ to value from datasheet
  hw/arm: ast2600: Correct the iBT interrupt ID
  hw/misc: Model KCS devices in the Aspeed LPC controller

Cédric Le Goater (1):
  hw/misc: Add a basic Aspeed LPC controller model

 docs/system/arm/aspeed.rst   |   2 +-
 hw/arm/aspeed_ast2600.c  |  44 +++-
 hw/arm/aspeed_soc.c  |  34 ++-
 hw/misc/aspeed_lpc.c | 486 +++
 hw/misc/meson.build  |   7 +-
 include/hw/arm/aspeed_soc.h  |   3 +
 include/hw/misc/aspeed_lpc.h |  47 
 7 files changed, 616 insertions(+), 7 deletions(-)
 create mode 100644 hw/misc/aspeed_lpc.c
 create mode 100644 include/hw/misc/aspeed_lpc.h


base-commit: 51db2d7cf26d05a961ec0ee0eb773594b32cc4a1
-- 
2.27.0




[PATCH v2 2/5] hw/arm: ast2600: Set AST2600_MAX_IRQ to value from datasheet

2021-02-28 Thread Andrew Jeffery
The datasheet says we have 197 IRQs allocated, and we need more than 128
to describe IRQs from LPC devices. Raise the value now to allow
modelling of the LPC devices.

Signed-off-by: Andrew Jeffery 
---
 hw/arm/aspeed_ast2600.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index bc0eeb058b24..22fcb5b0edbe 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -65,7 +65,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = {
 
 #define ASPEED_A7MPCORE_ADDR 0x4046
 
-#define AST2600_MAX_IRQ 128
+#define AST2600_MAX_IRQ 197
 
 /* Shared Peripheral Interrupt values below are offset by -32 from datasheet */
 static const int aspeed_soc_ast2600_irqmap[] = {
-- 
2.27.0




[PATCH v2 1/5] arm: ast2600: Force a multiple of 32 of IRQs for the GIC

2021-02-28 Thread Andrew Jeffery
This appears to be a requirement of the GIC model. The AST2600 allocates
197 GIC IRQs, which we will adjust shortly.

Signed-off-by: Andrew Jeffery 
---
 hw/arm/aspeed_ast2600.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index bf31ca351feb..bc0eeb058b24 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -65,7 +65,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = {
 
 #define ASPEED_A7MPCORE_ADDR 0x4046
 
-#define ASPEED_SOC_AST2600_MAX_IRQ 128
+#define AST2600_MAX_IRQ 128
 
 /* Shared Peripheral Interrupt values below are offset by -32 from datasheet */
 static const int aspeed_soc_ast2600_irqmap[] = {
@@ -267,7 +267,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, 
Error **errp)
 object_property_set_int(OBJECT(>a7mpcore), "num-cpu", sc->num_cpus,
 _abort);
 object_property_set_int(OBJECT(>a7mpcore), "num-irq",
-ASPEED_SOC_AST2600_MAX_IRQ + GIC_INTERNAL,
+ROUND_UP(AST2600_MAX_IRQ + GIC_INTERNAL, 32),
 _abort);
 
 sysbus_realize(SYS_BUS_DEVICE(>a7mpcore), _abort);
-- 
2.27.0




Re: [PATCH 00/50] i386 cleanup part 3

2021-02-28 Thread no-reply
Patchew URL: 
https://patchew.org/QEMU/20210228232321.322053-1-richard.hender...@linaro.org/



Hi,

This series seems to have some coding style problems. See output below for
more information:

Type: series
Message-id: 20210228232321.322053-1-richard.hender...@linaro.org
Subject: [PATCH 00/50] i386 cleanup part 3

=== TEST SCRIPT BEGIN ===
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
From https://github.com/patchew-project/qemu
 * [new tag] 
patchew/20210228232321.322053-1-richard.hender...@linaro.org -> 
patchew/20210228232321.322053-1-richard.hender...@linaro.org
Switched to a new branch 'test'
797745d target/i386: Remove user-only i/o stubs
0f9b7df target/i386: Move helper_check_io to sysemu
0e6e2ee target/i386: Create helper_check_io
39f9f44 target/i386: Pass in port to gen_check_io
525360d target/i386: Tidy gen_check_io
b73f019 target/i386: Exit tb after wrmsr
77f4315 target/i386: Eliminate user stubs for read/write_crN, rd/wrmsr
c4f25ef target/i386: Inline user cpu_svm_check_intercept_param
be9d50c target/i386: Unify invlpg, invlpga
f3f94a0 target/i386: Move invlpg, hlt, monitor, mwait to sysemu
7f8853c target/i386: Pass env to do_pause and do_hlt
59992b7 target/i386: Cleanup read_crN, write_crN, lmsw
fbd9bfe target/i386: Remove user stub for cpu_vmexit
cec5742 target/i386: Remove pc_start argument to gen_svm_check_intercept
3e11484 target/i386: Tidy svm_check_intercept from tcg
018250c target/i386: Simplify gen_debug usage
bbe73ae target/i386: Mark some helpers as noreturn
1be7681 target/i386: Eliminate SVM helpers for user-only
37a998e target/i386: Implement skinit in translate.c
da48236 target/i386: Assert !GUEST for user-only
f4e4fe9 target/i386: Assert !SVME for user-only
d1d5637 target/i386: Add stub generator for helper_set_dr
a18d075 target/i386: Reorder DisasContext members
88fdc49 target/i386: Fix the comment for repz_opt
861b00b target/i386: Reduce DisasContext jmp_opt, repz_opt to bool
3783316 target/i386: Leave TF in DisasContext.flags
a6b8724 target/i386: Reduce DisasContext popl_esp_hack and rip_offset to uint8_t
6920aee target/i386: Reduce DisasContext.vex_[lv] to uint8_t
4f6954b target/i386: Reduce DisasContext.prefix to uint8_t
07cc331 target/i386: Reduce DisasContext.override to int8_t
6aba639 target/i386: Reduce DisasContext.flags to uint32_t
d507f0d target/i386: Remove DisasContext.f_st as unused
ac8f26e target/i386: Move rex_w into DisasContext
60f3d0b target/i386: Move rex_r into DisasContext
ca272c1 target/i386: Tidy REX_B, REX_X definition
f573f9b9 target/i386: Introduce REX_PREFIX
3d69364 target/i386: Assert !ADDSEG for x86_64 user-only
b9bc34b target/i386: Assert LMA for x86_64 user-only
543c705 target/i386: Assert CODE64 for x86_64 user-only
e81aa02 target/i386: Assert SS32 for x86_64 user-only
4a3d9a1 target/i386: Assert CODE32 for x86_64 user-only
272ed3d target/i386: Assert !VM86 for x86_64 user-only
3d6b13d target/i386: Assert IOPL is 0 for user-only
d11abdc target/i386: Assert CPL is 3 for user-only
161425f target/i386: Assert PE is set for user-only
1b4f01f target/i386: Split out check_iopl
ab7b71b target/i386: Split out check_vm86_iopl
ffbb88b target/i386: Unify code paths for IRET
245e7e4 target/i386: Split out check_cpl0
41f02f9 target/i386: Split out gen_exception_gpf

=== OUTPUT BEGIN ===
1/50 Checking commit 41f02f906d16 (target/i386: Split out gen_exception_gpf)
2/50 Checking commit 245e7e4367bb (target/i386: Split out check_cpl0)
3/50 Checking commit ffbb88b887c7 (target/i386: Unify code paths for IRET)
4/50 Checking commit ab7b71b2b03e (target/i386: Split out check_vm86_iopl)
5/50 Checking commit 1b4f01f45cb1 (target/i386: Split out check_iopl)
6/50 Checking commit 161425f462f3 (target/i386: Assert PE is set for user-only)
ERROR: braces {} are necessary for all arms of this statement
#129: FILE: target/i386/tcg/translate.c:7304:
+if (!PE(s) || s->vm86)
[...]

ERROR: braces {} are necessary for all arms of this statement
#147: FILE: target/i386/tcg/translate.c:7323:
+if (!PE(s) || s->vm86)
[...]

ERROR: braces {} are necessary for all arms of this statement
#165: FILE: target/i386/tcg/translate.c:7343:
+if (!PE(s) || s->vm86)
[...]

ERROR: braces {} are necessary for all arms of this statement
#237: FILE: target/i386/tcg/translate.c:7714:
+if (!PE(s) || s->vm86)
[...]

ERROR: braces {} are necessary for all arms of this statement
#246: FILE: target/i386/tcg/translate.c:7762:
+if (!PE(s) || s->vm86)
[...]

total: 5 errors, 0 warnings, 244 lines checked

Patch 6/50 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

7/50 Checking commit d11abdcfe8e1 (target/i386: 

Re: [PATCH 1/4] arm: ast2600: Force a multiple of 32 of IRQs for the GIC

2021-02-28 Thread Andrew Jeffery



On Mon, 1 Mar 2021, at 09:37, Andrew Jeffery wrote:
> 
> 
> On Fri, 26 Feb 2021, at 19:26, Philippe Mathieu-Daudé wrote:
> > On 2/26/21 7:57 AM, Andrew Jeffery wrote:
> > > This appears to be a requirement of the GIC model.
> > 
> > If so this should be adjusted in the GIC or a15mp_priv_realize(),
> > not in each caller, isn't it?
> > 
> 
> Maybe, let me look into it. I'll clean it up in v2 if it makes sense.

So the current behaviour has been around since 2009, originating in 
41c1e2f54e6f ("arm: make sure that number of irqs can be represented in 
GICD_TYPER."). The GIC architecture specification says:

"The GICD_TYPER.ITLinesNumber field identifies the number of 
implemented GICD_ISENABLERns, and therefore the maximum number of SPIs 
that might be supported."

While the code says:

/* ITLinesNumber is represented as (N / 32) - 1 (see
 * gic_dist_readb) so this is an implementation imposed
 * restriction, not an architectural one:
 */
if (s->num_irq < 32 || (s->num_irq % 32)) {
error_setg(errp,
   "%d interrupt lines unsupported: not divisible by 
32",
   num_irq);
return;
}

My feeling is that it's better to be explicit in the models that are 
affected (i.e. leave the ROUND_UP() as I have it in this patch). This 
way if the implementation restriction is ever lifted, we know which 
models we can clean up. I won't be reworking the GIC to remove the 
restriction in this series, so unless you have a particularly strong 
preference/justification for the implicit ROUND_UP(), I plan to leave 
it as is.

Cheers,

Andrew



Re: [PATCH 0/5] tcg/tci: Merge identical cases in generation

2021-02-28 Thread Richard Henderson
On 2/18/21 3:28 PM, Philippe Mathieu-Daudé wrote:
> Hi Richard,
> 
> This is your patch (#4/71 of v4 [*]) split in 5 parts for
> easier review. Please consider using this series instead of
> your original patch.

Done.

r~



[PATCH 49/50] target/i386: Move helper_check_io to sysemu

2021-02-28 Thread Richard Henderson
The we never allow i/o from user-only, and the tss check
that helper_check_io does will always fail.  Use an ifdef
within gen_check_io and return false, indicating that an
exception is known to be raised.

Signed-off-by: Richard Henderson 
---
 target/i386/helper.h|  2 +-
 target/i386/tcg/seg_helper.c| 28 
 target/i386/tcg/sysemu/seg_helper.c | 29 +
 target/i386/tcg/translate.c | 11 +++
 4 files changed, 41 insertions(+), 29 deletions(-)

diff --git a/target/i386/helper.h b/target/i386/helper.h
index 47d0d67699..3fd0253298 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -86,7 +86,6 @@ DEF_HELPER_1(rdtsc, void, env)
 DEF_HELPER_1(rdtscp, void, env)
 DEF_HELPER_FLAGS_1(rdpmc, TCG_CALL_NO_WG, noreturn, env)
 
-DEF_HELPER_FLAGS_3(check_io, TCG_CALL_NO_WG, void, env, i32, i32)
 DEF_HELPER_3(outb, void, env, i32, i32)
 DEF_HELPER_2(inb, tl, env, i32)
 DEF_HELPER_3(outw, void, env, i32, i32)
@@ -95,6 +94,7 @@ DEF_HELPER_3(outl, void, env, i32, i32)
 DEF_HELPER_2(inl, tl, env, i32)
 
 #ifndef CONFIG_USER_ONLY
+DEF_HELPER_FLAGS_3(check_io, TCG_CALL_NO_WG, void, env, i32, i32)
 DEF_HELPER_FLAGS_4(bpt_io, TCG_CALL_NO_WG, void, env, i32, i32, tl)
 DEF_HELPER_2(svm_check_intercept, void, env, i32)
 DEF_HELPER_4(svm_check_io, void, env, i32, i32, i32)
diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c
index 69d6e8f602..2f6cdc8239 100644
--- a/target/i386/tcg/seg_helper.c
+++ b/target/i386/tcg/seg_helper.c
@@ -2416,31 +2416,3 @@ void helper_verw(CPUX86State *env, target_ulong 
selector1)
 }
 CC_SRC = eflags | CC_Z;
 }
-
-/* check if Port I/O is allowed in TSS */
-void helper_check_io(CPUX86State *env, uint32_t addr, uint32_t size)
-{
-uintptr_t retaddr = GETPC();
-uint32_t io_offset, val, mask;
-
-/* TSS must be a valid 32 bit one */
-if (!(env->tr.flags & DESC_P_MASK) ||
-((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
-env->tr.limit < 103) {
-goto fail;
-}
-io_offset = cpu_lduw_kernel_ra(env, env->tr.base + 0x66, retaddr);
-io_offset += (addr >> 3);
-/* Note: the check needs two bytes */
-if ((io_offset + 1) > env->tr.limit) {
-goto fail;
-}
-val = cpu_lduw_kernel_ra(env, env->tr.base + io_offset, retaddr);
-val >>= (addr & 7);
-mask = (1 << size) - 1;
-/* all bits must be zero to allow the I/O */
-if ((val & mask) != 0) {
-fail:
-raise_exception_err_ra(env, EXCP0D_GPF, 0, retaddr);
-}
-}
diff --git a/target/i386/tcg/sysemu/seg_helper.c 
b/target/i386/tcg/sysemu/seg_helper.c
index 10076d1341..b2e3ba8195 100644
--- a/target/i386/tcg/sysemu/seg_helper.c
+++ b/target/i386/tcg/sysemu/seg_helper.c
@@ -23,6 +23,7 @@
 #include "exec/helper-proto.h"
 #include "exec/cpu_ldst.h"
 #include "tcg/helper-tcg.h"
+#include "../seg_helper.h"
 
 #ifdef TARGET_X86_64
 void helper_syscall(CPUX86State *env, int next_eip_addend)
@@ -123,3 +124,31 @@ void x86_cpu_do_interrupt(CPUState *cs)
 env->old_exception = -1;
 }
 }
+
+/* check if Port I/O is allowed in TSS */
+void helper_check_io(CPUX86State *env, uint32_t addr, uint32_t size)
+{
+uintptr_t retaddr = GETPC();
+uint32_t io_offset, val, mask;
+
+/* TSS must be a valid 32 bit one */
+if (!(env->tr.flags & DESC_P_MASK) ||
+((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
+env->tr.limit < 103) {
+goto fail;
+}
+io_offset = cpu_lduw_kernel_ra(env, env->tr.base + 0x66, retaddr);
+io_offset += (addr >> 3);
+/* Note: the check needs two bytes */
+if ((io_offset + 1) > env->tr.limit) {
+goto fail;
+}
+val = cpu_lduw_kernel_ra(env, env->tr.base + io_offset, retaddr);
+val >>= (addr & 7);
+mask = (1 << size) - 1;
+/* all bits must be zero to allow the I/O */
+if ((val & mask) != 0) {
+fail:
+raise_exception_err_ra(env, EXCP0D_GPF, 0, retaddr);
+}
+}
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index d395ae090e..2276e75d92 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -193,6 +193,7 @@ typedef struct DisasContext {
 { qemu_build_not_reached(); }
 
 #ifdef CONFIG_USER_ONLY
+STUB_HELPER(check_io, TCGv_env env, TCGv_i32 port, TCGv_i32 size)
 STUB_HELPER(clgi, TCGv_env env)
 STUB_HELPER(flush_page, TCGv_env env, TCGv addr)
 STUB_HELPER(hlt, TCGv_env env, TCGv_i32 pc_ofs)
@@ -217,6 +218,7 @@ static void gen_jr(DisasContext *s, TCGv dest);
 static void gen_jmp(DisasContext *s, target_ulong eip);
 static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num);
 static void gen_op(DisasContext *s1, int op, MemOp ot, int d);
+static void gen_exception_gpf(DisasContext *s);
 
 /* i386 arith/logic operations */
 enum {
@@ -681,6 +683,14 @@ static void gen_helper_out_func(MemOp ot, TCGv_i32 v, 
TCGv_i32 n)
 static bool gen_check_io(DisasContext *s, MemOp ot, TCGv_i32 port,
 

[PATCH 45/50] target/i386: Exit tb after wrmsr

2021-02-28 Thread Richard Henderson
At minimum, wrmsr can change efer, which affects HF_LMA.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 2493d39f0b..dc31d8667f 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -7254,6 +7254,8 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 gen_helper_rdmsr(cpu_env);
 } else {
 gen_helper_wrmsr(cpu_env);
+gen_jmp_im(s, s->pc - s->cs_base);
+gen_eob(s);
 }
 }
 break;
-- 
2.25.1




[PATCH 40/50] target/i386: Pass env to do_pause and do_hlt

2021-02-28 Thread Richard Henderson
Having the callers upcast to X86CPU is a waste, since we
don't need it.  We even have to recover env in do_hlt.

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

diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c
index b0d3c61f13..20bf4771e7 100644
--- a/target/i386/tcg/misc_helper.c
+++ b/target/i386/tcg/misc_helper.c
@@ -100,19 +100,18 @@ void QEMU_NORETURN helper_rdpmc(CPUX86State *env)
 raise_exception_err(env, EXCP06_ILLOP, 0);
 }
 
-static QEMU_NORETURN void do_pause(X86CPU *cpu)
+static void QEMU_NORETURN do_pause(CPUX86State *env)
 {
-CPUState *cs = CPU(cpu);
+CPUState *cs = env_cpu(env);
 
 /* Just let another CPU run.  */
 cs->exception_index = EXCP_INTERRUPT;
 cpu_loop_exit(cs);
 }
 
-static QEMU_NORETURN void do_hlt(X86CPU *cpu)
+static void QEMU_NORETURN do_hlt(CPUX86State *env)
 {
-CPUState *cs = CPU(cpu);
-CPUX86State *env = >env;
+CPUState *cs = env_cpu(env);
 
 env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
 cs->halted = 1;
@@ -122,12 +121,10 @@ static QEMU_NORETURN void do_hlt(X86CPU *cpu)
 
 void QEMU_NORETURN helper_hlt(CPUX86State *env, int next_eip_addend)
 {
-X86CPU *cpu = env_archcpu(env);
-
 cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0, GETPC());
 env->eip += next_eip_addend;
 
-do_hlt(cpu);
+do_hlt(env);
 }
 
 void helper_monitor(CPUX86State *env, target_ulong ptr)
@@ -142,7 +139,6 @@ void helper_monitor(CPUX86State *env, target_ulong ptr)
 void QEMU_NORETURN helper_mwait(CPUX86State *env, int next_eip_addend)
 {
 CPUState *cs = env_cpu(env);
-X86CPU *cpu = env_archcpu(env);
 
 if ((uint32_t)env->regs[R_ECX] != 0) {
 raise_exception_ra(env, EXCP0D_GPF, GETPC());
@@ -152,20 +148,18 @@ void QEMU_NORETURN helper_mwait(CPUX86State *env, int 
next_eip_addend)
 
 /* XXX: not complete but not completely erroneous */
 if (cs->cpu_index != 0 || CPU_NEXT(cs) != NULL) {
-do_pause(cpu);
+do_pause(env);
 } else {
-do_hlt(cpu);
+do_hlt(env);
 }
 }
 
 void QEMU_NORETURN helper_pause(CPUX86State *env, int next_eip_addend)
 {
-X86CPU *cpu = env_archcpu(env);
-
 cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0, GETPC());
 env->eip += next_eip_addend;
 
-do_pause(cpu);
+do_pause(env);
 }
 
 void QEMU_NORETURN helper_debug(CPUX86State *env)
-- 
2.25.1




[PATCH 39/50] target/i386: Cleanup read_crN, write_crN, lmsw

2021-02-28 Thread Richard Henderson
Pull the svm intercept check into the translator.
Pull the entire implementation of lmsw into the translator.
Push the check for CR8LEG into the regno validation switch.
Unify the gen_io_start check between read/write.

Signed-off-by: Richard Henderson 
---
 target/i386/helper.h |  5 +-
 target/i386/tcg/misc_helper.c|  8 ---
 target/i386/tcg/sysemu/misc_helper.c |  2 -
 target/i386/tcg/translate.c  | 97 +++-
 4 files changed, 54 insertions(+), 58 deletions(-)

diff --git a/target/i386/helper.h b/target/i386/helper.h
index 86484a4ec4..ebfaca66dd 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -42,9 +42,8 @@ DEF_HELPER_5(lcall_protected, void, env, int, tl, int, tl)
 DEF_HELPER_2(iret_real, void, env, int)
 DEF_HELPER_3(iret_protected, void, env, int, int)
 DEF_HELPER_3(lret_protected, void, env, int, int)
-DEF_HELPER_2(read_crN, tl, env, int)
-DEF_HELPER_3(write_crN, void, env, int, tl)
-DEF_HELPER_2(lmsw, void, env, tl)
+DEF_HELPER_FLAGS_2(read_crN, TCG_CALL_NO_RWG, tl, env, int)
+DEF_HELPER_FLAGS_3(write_crN, TCG_CALL_NO_RWG, void, env, int, tl)
 DEF_HELPER_1(clts, void, env)
 
 #ifndef CONFIG_USER_ONLY
diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c
index 1ca9ace3dc..b0d3c61f13 100644
--- a/target/i386/tcg/misc_helper.c
+++ b/target/i386/tcg/misc_helper.c
@@ -60,14 +60,6 @@ void helper_cpuid(CPUX86State *env)
 env->regs[R_EDX] = edx;
 }
 
-void helper_lmsw(CPUX86State *env, target_ulong t0)
-{
-/* only 4 lower bits of CR0 are modified. PE cannot be set to zero
-   if already set to one. */
-t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
-helper_write_crN(env, 0, t0);
-}
-
 void helper_invlpg(CPUX86State *env, target_ulong addr)
 {
 X86CPU *cpu = env_archcpu(env);
diff --git a/target/i386/tcg/sysemu/misc_helper.c 
b/target/i386/tcg/sysemu/misc_helper.c
index 6a88840cf2..ebf15e3dde 100644
--- a/target/i386/tcg/sysemu/misc_helper.c
+++ b/target/i386/tcg/sysemu/misc_helper.c
@@ -65,7 +65,6 @@ target_ulong helper_read_crN(CPUX86State *env, int reg)
 {
 target_ulong val;
 
-cpu_svm_check_intercept_param(env, SVM_EXIT_READ_CR0 + reg, 0, GETPC());
 switch (reg) {
 default:
 val = env->cr[reg];
@@ -83,7 +82,6 @@ target_ulong helper_read_crN(CPUX86State *env, int reg)
 
 void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
 {
-cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0, GETPC());
 switch (reg) {
 case 0:
 cpu_x86_update_cr0(env, t0);
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 33faffe00f..708059ac15 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -7648,13 +7648,22 @@ static target_ulong disas_insn(DisasContext *s, 
CPUState *cpu)
 tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]);
 gen_helper_wrpkru(cpu_env, s->tmp2_i32, s->tmp1_i64);
 break;
+
 CASE_MODRM_OP(6): /* lmsw */
 if (!check_cpl0(s)) {
 break;
 }
 gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0);
 gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
-gen_helper_lmsw(cpu_env, s->T0);
+/*
+ * Only the 4 lower bits of CR0 are modified.
+ * PE cannot be set to zero if already set to one.
+ */
+tcg_gen_ld_tl(s->T1, cpu_env, offsetof(CPUX86State, cr[0]));
+tcg_gen_andi_tl(s->T0, s->T0, 0xf);
+tcg_gen_andi_tl(s->T1, s->T1, ~0xe);
+tcg_gen_or_tl(s->T0, s->T0, s->T1);
+gen_helper_write_crN(cpu_env, tcg_constant_i32(0), s->T0);
 gen_jmp_im(s, s->pc - s->cs_base);
 gen_eob(s);
 break;
@@ -8028,58 +8037,56 @@ static target_ulong disas_insn(DisasContext *s, 
CPUState *cpu)
 modrm = x86_ldub_code(env, s);
 gen_nop_modrm(env, s, modrm);
 break;
+
 case 0x120: /* mov reg, crN */
 case 0x122: /* mov crN, reg */
-if (check_cpl0(s)) {
-modrm = x86_ldub_code(env, s);
-/* Ignore the mod bits (assume (modrm&0xc0)==0xc0).
- * AMD documentation (24594.pdf) and testing of
- * intel 386 and 486 processors all show that the mod bits
- * are assumed to be 1's, regardless of actual values.
- */
-rm = (modrm & 7) | REX_B(s);
-reg = ((modrm >> 3) & 7) | REX_R(s);
-if (CODE64(s))
-ot = MO_64;
-else
-ot = MO_32;
-if ((prefixes & PREFIX_LOCK) && (reg == 0) &&
+if (!check_cpl0(s)) {
+break;
+}
+modrm = x86_ldub_code(env, s);
+/*
+ * Ignore the mod bits (assume (modrm&0xc0)==0xc0).
+ * AMD documentation (24594.pdf) and testing of Intel 386 and 486
+ * processors all show that the mod bits are assumed to be 1's,
+

[PATCH 36/50] target/i386: Tidy svm_check_intercept from tcg

2021-02-28 Thread Richard Henderson
The param argument to helper_svm_check_intercept_param is always 0;
eliminate it and rename to helper_svm_check_intercept.  Fold
gen_sve_check_intercept_param into gen_svm_check_intercept.

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

diff --git a/target/i386/helper.h b/target/i386/helper.h
index f794d1c7c7..86484a4ec4 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -107,7 +107,7 @@ DEF_HELPER_2(inl, tl, env, i32)
 
 #ifndef CONFIG_USER_ONLY
 DEF_HELPER_FLAGS_4(bpt_io, TCG_CALL_NO_WG, void, env, i32, i32, tl)
-DEF_HELPER_3(svm_check_intercept_param, void, env, i32, i64)
+DEF_HELPER_2(svm_check_intercept, void, env, i32)
 DEF_HELPER_4(svm_check_io, void, env, i32, i32, i32)
 DEF_HELPER_3(vmrun, void, env, int, int)
 DEF_HELPER_1(vmmcall, void, env)
diff --git a/target/i386/tcg/sysemu/svm_helper.c 
b/target/i386/tcg/sysemu/svm_helper.c
index ca5a781a7e..86a0b3c4be 100644
--- a/target/i386/tcg/sysemu/svm_helper.c
+++ b/target/i386/tcg/sysemu/svm_helper.c
@@ -517,10 +517,9 @@ void cpu_svm_check_intercept_param(CPUX86State *env, 
uint32_t type,
 }
 }
 
-void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
-  uint64_t param)
+void helper_svm_check_intercept(CPUX86State *env, uint32_t type)
 {
-cpu_svm_check_intercept_param(env, type, param, GETPC());
+cpu_svm_check_intercept_param(env, type, 0, GETPC());
 }
 
 void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index c135be9063..cbc0cc3ccc 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -197,7 +197,7 @@ STUB_HELPER(clgi, TCGv_env env)
 STUB_HELPER(invlpga, TCGv_env env, TCGv_i32 aflag)
 STUB_HELPER(set_dr, TCGv_env env, TCGv_i32 reg, TCGv val)
 STUB_HELPER(stgi, TCGv_env env)
-STUB_HELPER(svm_check_intercept_param, TCGv_env env, TCGv_i32 t, TCGv_i64 p)
+STUB_HELPER(svm_check_intercept, TCGv_env env, TCGv_i32 type)
 STUB_HELPER(svm_check_io, TCGv_env env, TCGv_i32 port, TCGv_i32 p, TCGv_i32 a)
 STUB_HELPER(vmload, TCGv_env env, TCGv_i32 aflag)
 STUB_HELPER(vmmcall, TCGv_env env)
@@ -2423,9 +2423,8 @@ static inline int svm_is_rep(int prefixes)
 return ((prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) ? 8 : 0);
 }
 
-static inline void
-gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start,
-  uint32_t type, uint64_t param)
+static void gen_svm_check_intercept(DisasContext *s, target_ulong pc_start,
+uint32_t type)
 {
 /* no SVM activated; fast case */
 if (likely(!GUEST(s))) {
@@ -2433,14 +2432,7 @@ gen_svm_check_intercept_param(DisasContext *s, 
target_ulong pc_start,
 }
 gen_update_cc_op(s);
 gen_jmp_im(s, pc_start - s->cs_base);
-gen_helper_svm_check_intercept_param(cpu_env, tcg_const_i32(type),
- tcg_const_i64(param));
-}
-
-static inline void
-gen_svm_check_intercept(DisasContext *s, target_ulong pc_start, uint64_t type)
-{
-gen_svm_check_intercept_param(s, pc_start, type, 0);
+gen_helper_svm_check_intercept(cpu_env, tcg_constant_i32(type));
 }
 
 static inline void gen_stack_update(DisasContext *s, int addend)
-- 
2.25.1




[PATCH 37/50] target/i386: Remove pc_start argument to gen_svm_check_intercept

2021-02-28 Thread Richard Henderson
When exiting helper_svm_check_intercept via exception, cpu_vmexit
calls cpu_restore_state, which will recover eip and cc_op via unwind.
Therefore we do not need to store eip or cc_op before the call.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index cbc0cc3ccc..33faffe00f 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -2423,15 +2423,12 @@ static inline int svm_is_rep(int prefixes)
 return ((prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) ? 8 : 0);
 }
 
-static void gen_svm_check_intercept(DisasContext *s, target_ulong pc_start,
-uint32_t type)
+static void gen_svm_check_intercept(DisasContext *s, uint32_t type)
 {
 /* no SVM activated; fast case */
 if (likely(!GUEST(s))) {
 return;
 }
-gen_update_cc_op(s);
-gen_jmp_im(s, pc_start - s->cs_base);
 gen_helper_svm_check_intercept(cpu_env, tcg_constant_i32(type));
 }
 
@@ -6633,7 +6630,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 val = 0;
 goto do_lret;
 case 0xcf: /* iret */
-gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET);
+gen_svm_check_intercept(s, SVM_EXIT_IRET);
 if (!PE(s) || VM86(s)) {
 /* real mode or vm86 mode */
 if (!check_vm86_iopl(s)) {
@@ -6755,7 +6752,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 //
 /* flags */
 case 0x9c: /* pushf */
-gen_svm_check_intercept(s, pc_start, SVM_EXIT_PUSHF);
+gen_svm_check_intercept(s, SVM_EXIT_PUSHF);
 if (check_vm86_iopl(s)) {
 gen_update_cc_op(s);
 gen_helper_read_eflags(s->T0, cpu_env);
@@ -6763,7 +6760,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 }
 break;
 case 0x9d: /* popf */
-gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF);
+gen_svm_check_intercept(s, SVM_EXIT_POPF);
 if (check_vm86_iopl(s)) {
 ot = gen_pop_T0(s);
 if (CPL(s) == 0) {
@@ -7137,7 +7134,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 break;
 #ifdef WANT_ICEBP
 case 0xf1: /* icebp (undocumented, exits to external debugger) */
-gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP);
+gen_svm_check_intercept(s, SVM_EXIT_ICEBP);
 gen_debug(s);
 break;
 #endif
@@ -7341,7 +7338,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 0: /* sldt */
 if (!PE(s) || VM86(s))
 goto illegal_op;
-gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_READ);
+gen_svm_check_intercept(s, SVM_EXIT_LDTR_READ);
 tcg_gen_ld32u_tl(s->T0, cpu_env,
  offsetof(CPUX86State, ldt.selector));
 ot = mod == 3 ? dflag : MO_16;
@@ -7351,7 +7348,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 if (!PE(s) || VM86(s))
 goto illegal_op;
 if (check_cpl0(s)) {
-gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_WRITE);
+gen_svm_check_intercept(s, SVM_EXIT_LDTR_WRITE);
 gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 gen_helper_lldt(cpu_env, s->tmp2_i32);
@@ -7360,7 +7357,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 1: /* str */
 if (!PE(s) || VM86(s))
 goto illegal_op;
-gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_READ);
+gen_svm_check_intercept(s, SVM_EXIT_TR_READ);
 tcg_gen_ld32u_tl(s->T0, cpu_env,
  offsetof(CPUX86State, tr.selector));
 ot = mod == 3 ? dflag : MO_16;
@@ -7370,7 +7367,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 if (!PE(s) || VM86(s))
 goto illegal_op;
 if (check_cpl0(s)) {
-gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_WRITE);
+gen_svm_check_intercept(s, SVM_EXIT_TR_WRITE);
 gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 gen_helper_ltr(cpu_env, s->tmp2_i32);
@@ -7398,7 +7395,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 modrm = x86_ldub_code(env, s);
 switch (modrm) {
 CASE_MODRM_MEM_OP(0): /* sgdt */
-gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ);
+gen_svm_check_intercept(s, SVM_EXIT_GDTR_READ);
 gen_lea_modrm(env, s, modrm);
 tcg_gen_ld32u_tl(s->T0,
 

[PATCH 38/50] target/i386: Remove user stub for cpu_vmexit

2021-02-28 Thread Richard Henderson
This function is only called from tcg/sysemu/.
There is no need for a stub in tcg/user/.

Signed-off-by: Richard Henderson 
---
 target/i386/tcg/helper-tcg.h | 4 +++-
 target/i386/tcg/user/svm_stubs.c | 6 --
 2 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h
index 3d47cb83cd..e848c3b4b9 100644
--- a/target/i386/tcg/helper-tcg.h
+++ b/target/i386/tcg/helper-tcg.h
@@ -81,10 +81,12 @@ extern const uint8_t parity_table[256];
 /* misc_helper.c */
 void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask);
 
-/* svm_helper.c */
+/* sysemu/svm_helper.c */
+#ifndef CONFIG_USER_ONLY
 void QEMU_NORETURN cpu_vmexit(CPUX86State *nenv, uint32_t exit_code,
   uint64_t exit_info_1, uintptr_t retaddr);
 void do_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1);
+#endif
 
 /* seg_helper.c */
 void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw);
diff --git a/target/i386/tcg/user/svm_stubs.c b/target/i386/tcg/user/svm_stubs.c
index 48a43bdcea..db818f89a8 100644
--- a/target/i386/tcg/user/svm_stubs.c
+++ b/target/i386/tcg/user/svm_stubs.c
@@ -22,12 +22,6 @@
 #include "exec/helper-proto.h"
 #include "tcg/helper-tcg.h"
 
-void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1,
-uintptr_t retaddr)
-{
-assert(0);
-}
-
 void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
uint64_t param, uintptr_t retaddr)
 {
-- 
2.25.1




[PATCH 34/50] target/i386: Mark some helpers as noreturn

2021-02-28 Thread Richard Henderson
Any helper that always raises an exception or interrupt,
or simply exits to the main loop, can be so marked.

Signed-off-by: Richard Henderson 
---
 target/i386/helper.h  | 18 +-
 target/i386/tcg/bpt_helper.c  |  2 +-
 target/i386/tcg/excp_helper.c | 18 ++
 target/i386/tcg/misc_helper.c | 14 +++---
 target/i386/tcg/translate.c   |  3 ++-
 5 files changed, 29 insertions(+), 26 deletions(-)

diff --git a/target/i386/helper.h b/target/i386/helper.h
index d0f7f07c6c..f794d1c7c7 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -60,14 +60,14 @@ DEF_HELPER_2(sysexit, void, env, int)
 DEF_HELPER_2(syscall, void, env, int)
 DEF_HELPER_2(sysret, void, env, int)
 #endif
-DEF_HELPER_2(hlt, void, env, int)
-DEF_HELPER_2(monitor, void, env, tl)
-DEF_HELPER_2(mwait, void, env, int)
-DEF_HELPER_2(pause, void, env, int)
-DEF_HELPER_1(debug, void, env)
+DEF_HELPER_FLAGS_2(hlt, TCG_CALL_NO_WG, noreturn, env, int)
+DEF_HELPER_FLAGS_2(monitor, TCG_CALL_NO_WG, void, env, tl)
+DEF_HELPER_FLAGS_2(mwait, TCG_CALL_NO_WG, noreturn, env, int)
+DEF_HELPER_FLAGS_2(pause, TCG_CALL_NO_WG, noreturn, env, int)
+DEF_HELPER_FLAGS_1(debug, TCG_CALL_NO_WG, noreturn, env)
 DEF_HELPER_1(reset_rf, void, env)
-DEF_HELPER_3(raise_interrupt, void, env, int, int)
-DEF_HELPER_2(raise_exception, void, env, int)
+DEF_HELPER_FLAGS_3(raise_interrupt, TCG_CALL_NO_WG, noreturn, env, int, int)
+DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, int)
 DEF_HELPER_1(cli, void, env)
 DEF_HELPER_1(sti, void, env)
 DEF_HELPER_1(clac, void, env)
@@ -86,12 +86,12 @@ DEF_HELPER_2(cmpxchg8b, void, env, tl)
 DEF_HELPER_2(cmpxchg16b_unlocked, void, env, tl)
 DEF_HELPER_2(cmpxchg16b, void, env, tl)
 #endif
-DEF_HELPER_1(single_step, void, env)
+DEF_HELPER_FLAGS_1(single_step, TCG_CALL_NO_WG, noreturn, env)
 DEF_HELPER_1(rechecking_single_step, void, env)
 DEF_HELPER_1(cpuid, void, env)
 DEF_HELPER_1(rdtsc, void, env)
 DEF_HELPER_1(rdtscp, void, env)
-DEF_HELPER_1(rdpmc, void, env)
+DEF_HELPER_FLAGS_1(rdpmc, TCG_CALL_NO_WG, noreturn, env)
 DEF_HELPER_1(rdmsr, void, env)
 DEF_HELPER_1(wrmsr, void, env)
 
diff --git a/target/i386/tcg/bpt_helper.c b/target/i386/tcg/bpt_helper.c
index fb2a65ac9c..83cd89581e 100644
--- a/target/i386/tcg/bpt_helper.c
+++ b/target/i386/tcg/bpt_helper.c
@@ -22,7 +22,7 @@
 #include "exec/helper-proto.h"
 #include "helper-tcg.h"
 
-void helper_single_step(CPUX86State *env)
+void QEMU_NORETURN helper_single_step(CPUX86State *env)
 {
 #ifndef CONFIG_USER_ONLY
 check_hw_breakpoints(env, true);
diff --git a/target/i386/tcg/excp_helper.c b/target/i386/tcg/excp_helper.c
index 0183f3932e..bdae887d0a 100644
--- a/target/i386/tcg/excp_helper.c
+++ b/target/i386/tcg/excp_helper.c
@@ -25,12 +25,13 @@
 #include "exec/helper-proto.h"
 #include "helper-tcg.h"
 
-void helper_raise_interrupt(CPUX86State *env, int intno, int next_eip_addend)
+void QEMU_NORETURN helper_raise_interrupt(CPUX86State *env, int intno,
+  int next_eip_addend)
 {
 raise_interrupt(env, intno, 1, 0, next_eip_addend);
 }
 
-void helper_raise_exception(CPUX86State *env, int exception_index)
+void QEMU_NORETURN helper_raise_exception(CPUX86State *env, int 
exception_index)
 {
 raise_exception(env, exception_index);
 }
@@ -116,24 +117,25 @@ void QEMU_NORETURN raise_interrupt(CPUX86State *env, int 
intno, int is_int,
 raise_interrupt2(env, intno, is_int, error_code, next_eip_addend, 0);
 }
 
-void raise_exception_err(CPUX86State *env, int exception_index,
- int error_code)
+void QEMU_NORETURN raise_exception_err(CPUX86State *env, int exception_index,
+   int error_code)
 {
 raise_interrupt2(env, exception_index, 0, error_code, 0, 0);
 }
 
-void raise_exception_err_ra(CPUX86State *env, int exception_index,
-int error_code, uintptr_t retaddr)
+void QEMU_NORETURN raise_exception_err_ra(CPUX86State *env, int 
exception_index,
+  int error_code, uintptr_t retaddr)
 {
 raise_interrupt2(env, exception_index, 0, error_code, 0, retaddr);
 }
 
-void raise_exception(CPUX86State *env, int exception_index)
+void QEMU_NORETURN raise_exception(CPUX86State *env, int exception_index)
 {
 raise_interrupt2(env, exception_index, 0, 0, 0, 0);
 }
 
-void raise_exception_ra(CPUX86State *env, int exception_index, uintptr_t 
retaddr)
+void QEMU_NORETURN raise_exception_ra(CPUX86State *env, int exception_index,
+  uintptr_t retaddr)
 {
 raise_interrupt2(env, exception_index, 0, 0, 0, retaddr);
 }
diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c
index 82fb7037ac..1ca9ace3dc 100644
--- a/target/i386/tcg/misc_helper.c
+++ b/target/i386/tcg/misc_helper.c
@@ -96,7 +96,7 @@ void helper_rdtscp(CPUX86State *env)
 env->regs[R_ECX] = (uint32_t)(env->tsc_aux);
 }
 
-void 

[PATCH 30/50] target/i386: Assert !SVME for user-only

2021-02-28 Thread Richard Henderson
Most of the VMM instructions are already disabled for
user-only, by being usable only from ring 0.

The spec is intentionally loose for VMMCALL, allowing
the VMM to define syscalls for user-only.  However,
linux does not do so; VMMCALL is illegal.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 42b96a2669..3779da9042 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -138,10 +138,12 @@ typedef struct DisasContext {
 #define PE(S) true
 #define CPL(S)3
 #define IOPL(S)   0
+#define SVME(S)   false
 #else
 #define PE(S) (((S)->flags & HF_PE_MASK) != 0)
 #define CPL(S)((S)->cpl)
 #define IOPL(S)   ((S)->iopl)
+#define SVME(S)   (((S)->flags & HF_SVME_MASK) != 0)
 #endif
 #if defined(CONFIG_USER_ONLY) && defined(TARGET_X86_64)
 #define VM86(S)   false
@@ -7489,7 +7491,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 break;
 
 case 0xd8: /* VMRUN */
-if (!(s->flags & HF_SVME_MASK) || !PE(s)) {
+if (!SVME(s) || !PE(s)) {
 goto illegal_op;
 }
 if (!check_cpl0(s)) {
@@ -7504,7 +7506,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 break;
 
 case 0xd9: /* VMMCALL */
-if (!(s->flags & HF_SVME_MASK)) {
+if (!SVME(s)) {
 goto illegal_op;
 }
 gen_update_cc_op(s);
@@ -7513,7 +7515,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 break;
 
 case 0xda: /* VMLOAD */
-if (!(s->flags & HF_SVME_MASK) || !PE(s)) {
+if (!SVME(s) || !PE(s)) {
 goto illegal_op;
 }
 if (!check_cpl0(s)) {
@@ -7525,7 +7527,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 break;
 
 case 0xdb: /* VMSAVE */
-if (!(s->flags & HF_SVME_MASK) || !PE(s)) {
+if (!SVME(s) || !PE(s)) {
 goto illegal_op;
 }
 if (!check_cpl0(s)) {
@@ -7537,8 +7539,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 break;
 
 case 0xdc: /* STGI */
-if ((!(s->flags & HF_SVME_MASK)
-   && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT))
+if ((!SVME(s) && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT))
 || !PE(s)) {
 goto illegal_op;
 }
@@ -7552,7 +7553,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 break;
 
 case 0xdd: /* CLGI */
-if (!(s->flags & HF_SVME_MASK) || !PE(s)) {
+if (!SVME(s) || !PE(s)) {
 goto illegal_op;
 }
 if (!check_cpl0(s)) {
@@ -7564,8 +7565,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 break;
 
 case 0xde: /* SKINIT */
-if ((!(s->flags & HF_SVME_MASK)
- && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT))
+if ((!SVME(s) && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT))
 || !PE(s)) {
 goto illegal_op;
 }
@@ -7575,7 +7575,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 break;
 
 case 0xdf: /* INVLPGA */
-if (!(s->flags & HF_SVME_MASK) || !PE(s)) {
+if (!SVME(s) || !PE(s)) {
 goto illegal_op;
 }
 if (!check_cpl0(s)) {
@@ -8510,6 +8510,7 @@ static void i386_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cpu)
 g_assert(SS32(dc) == ((flags & HF_SS32_MASK) != 0));
 g_assert(LMA(dc) == ((flags & HF_LMA_MASK) != 0));
 g_assert(ADDSEG(dc) == ((flags & HF_ADDSEG_MASK) != 0));
+g_assert(SVME(dc) == ((flags & HF_SVME_MASK) != 0));
 
 dc->cc_op = CC_OP_DYNAMIC;
 dc->cc_op_dirty = false;
-- 
2.25.1




[PATCH 28/50] target/i386: Reorder DisasContext members

2021-02-28 Thread Richard Henderson
Sort all of the single-byte members to the same area
of the structure, eliminating 8 bytes of padding.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 36dee5c0c7..f0bc2df98c 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -76,20 +76,24 @@ static TCGv_i64 cpu_bndu[4];
 typedef struct DisasContext {
 DisasContextBase base;
 
-/* current insn context */
-int8_t override; /* -1 if no override, else R_CS, R_DS, etc */
-uint8_t prefix;
+target_ulong pc;   /* pc = eip + cs_base */
+target_ulong pc_start; /* pc at TB entry */
+target_ulong cs_base;  /* base of CS segment */
+
 MemOp aflag;
 MemOp dflag;
-target_ulong pc_start;
-target_ulong pc; /* pc = eip + cs_base */
-/* current block context */
-target_ulong cs_base; /* base of CS segment */
+
+int8_t override; /* -1 if no override, else R_CS, R_DS, etc */
+uint8_t prefix;
 
 #ifndef CONFIG_USER_ONLY
 uint8_t cpl;   /* code priv level */
 uint8_t iopl;  /* i/o priv level */
 #endif
+uint8_t vex_l;  /* vex vector length */
+uint8_t vex_v;  /* vex  register, without 1's complement.  */
+uint8_t popl_esp_hack; /* for correct popl with esp base handling */
+uint8_t rip_offset; /* only used in x86_64, but left for simplicity */
 
 #ifdef TARGET_X86_64
 uint8_t rex_r;
@@ -97,16 +101,13 @@ typedef struct DisasContext {
 uint8_t rex_b;
 bool rex_w;
 #endif
-uint8_t vex_l;  /* vex vector length */
-uint8_t vex_v;  /* vex  register, without 1's complement.  */
-CCOp cc_op;  /* current CC operation */
-bool cc_op_dirty;
 bool jmp_opt; /* use direct block chaining for direct jumps */
 bool repz_opt; /* optimize jumps within repz instructions */
+bool cc_op_dirty;
+
+CCOp cc_op;  /* current CC operation */
 int mem_index; /* select memory access functions */
 uint32_t flags; /* all execution flags */
-uint8_t popl_esp_hack; /* for correct popl with esp base handling */
-uint8_t rip_offset; /* only used in x86_64, but left for simplicity */
 int cpuid_features;
 int cpuid_ext_features;
 int cpuid_ext2_features;
-- 
2.25.1




[PATCH 27/50] target/i386: Fix the comment for repz_opt

2021-02-28 Thread Richard Henderson
After fixing a typo in the comment, fixup for CODING_STYLE.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 6877873bee..36dee5c0c7 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -8515,15 +8515,16 @@ static void i386_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cpu)
 dc->cpuid_xsave_features = env->features[FEAT_XSAVE];
 dc->jmp_opt = !(dc->base.singlestep_enabled ||
 (flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK)));
-/* Do not optimize repz jumps at all in icount mode, because
-   rep movsS instructions are execured with different paths
-   in !repz_opt and repz_opt modes. The first one was used
-   always except single step mode. And this setting
-   disables jumps optimization and control paths become
-   equivalent in run and single step modes.
-   Now there will be no jump optimization for repz in
-   record/replay modes and there will always be an
-   additional step for ecx=0 when icount is enabled.
+/*
+ * Do not optimize repz jumps at all in icount mode, because
+ * rep movsS instructions are executed with different paths
+ * in !repz_opt and repz_opt modes. The first one was used
+ * always except single step mode. And this setting
+ * disables jumps optimization and control paths become
+ * equivalent in run and single step modes.
+ * Now there will be no jump optimization for repz in
+ * record/replay modes and there will always be an
+ * additional step for ecx=0 when icount is enabled.
  */
 dc->repz_opt = !dc->jmp_opt && !(tb_cflags(dc->base.tb) & CF_USE_ICOUNT);
 
-- 
2.25.1




[PATCH 50/50] target/i386: Remove user-only i/o stubs

2021-02-28 Thread Richard Henderson
With the previous patch for check_io, we now have enough for
the compiler to dead-code eliminate all of the i/o helpers.

Signed-off-by: Richard Henderson 
---
 target/i386/helper.h  |  3 +-
 target/i386/tcg/translate.c   |  6 
 target/i386/tcg/user/misc_stubs.c | 55 ---
 target/i386/tcg/user/meson.build  |  1 -
 4 files changed, 7 insertions(+), 58 deletions(-)
 delete mode 100644 target/i386/tcg/user/misc_stubs.c

diff --git a/target/i386/helper.h b/target/i386/helper.h
index 3fd0253298..f3d8c3f949 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -86,14 +86,13 @@ DEF_HELPER_1(rdtsc, void, env)
 DEF_HELPER_1(rdtscp, void, env)
 DEF_HELPER_FLAGS_1(rdpmc, TCG_CALL_NO_WG, noreturn, env)
 
+#ifndef CONFIG_USER_ONLY
 DEF_HELPER_3(outb, void, env, i32, i32)
 DEF_HELPER_2(inb, tl, env, i32)
 DEF_HELPER_3(outw, void, env, i32, i32)
 DEF_HELPER_2(inw, tl, env, i32)
 DEF_HELPER_3(outl, void, env, i32, i32)
 DEF_HELPER_2(inl, tl, env, i32)
-
-#ifndef CONFIG_USER_ONLY
 DEF_HELPER_FLAGS_3(check_io, TCG_CALL_NO_WG, void, env, i32, i32)
 DEF_HELPER_FLAGS_4(bpt_io, TCG_CALL_NO_WG, void, env, i32, i32, tl)
 DEF_HELPER_2(svm_check_intercept, void, env, i32)
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 2276e75d92..1d08e10f38 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -197,8 +197,14 @@ STUB_HELPER(check_io, TCGv_env env, TCGv_i32 port, 
TCGv_i32 size)
 STUB_HELPER(clgi, TCGv_env env)
 STUB_HELPER(flush_page, TCGv_env env, TCGv addr)
 STUB_HELPER(hlt, TCGv_env env, TCGv_i32 pc_ofs)
+STUB_HELPER(inb, TCGv ret, TCGv_env env, TCGv_i32 port)
+STUB_HELPER(inw, TCGv ret, TCGv_env env, TCGv_i32 port)
+STUB_HELPER(inl, TCGv ret, TCGv_env env, TCGv_i32 port)
 STUB_HELPER(monitor, TCGv_env env, TCGv addr)
 STUB_HELPER(mwait, TCGv_env env, TCGv_i32 pc_ofs)
+STUB_HELPER(outb, TCGv_env env, TCGv_i32 port, TCGv_i32 val)
+STUB_HELPER(outw, TCGv_env env, TCGv_i32 port, TCGv_i32 val)
+STUB_HELPER(outl, TCGv_env env, TCGv_i32 port, TCGv_i32 val)
 STUB_HELPER(rdmsr, TCGv_env env)
 STUB_HELPER(read_crN, TCGv ret, TCGv_env env, TCGv_i32 reg)
 STUB_HELPER(set_dr, TCGv_env env, TCGv_i32 reg, TCGv val)
diff --git a/target/i386/tcg/user/misc_stubs.c 
b/target/i386/tcg/user/misc_stubs.c
deleted file mode 100644
index df38b44d6e..00
--- a/target/i386/tcg/user/misc_stubs.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *  x86 misc helpers
- *
- *  Copyright (c) 2003 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see .
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "exec/helper-proto.h"
-
-void helper_outb(CPUX86State *env, uint32_t port, uint32_t data)
-{
-g_assert_not_reached();
-}
-
-target_ulong helper_inb(CPUX86State *env, uint32_t port)
-{
-g_assert_not_reached();
-return 0;
-}
-
-void helper_outw(CPUX86State *env, uint32_t port, uint32_t data)
-{
-g_assert_not_reached();
-}
-
-target_ulong helper_inw(CPUX86State *env, uint32_t port)
-{
-g_assert_not_reached();
-return 0;
-}
-
-void helper_outl(CPUX86State *env, uint32_t port, uint32_t data)
-{
-g_assert_not_reached();
-}
-
-target_ulong helper_inl(CPUX86State *env, uint32_t port)
-{
-g_assert_not_reached();
-return 0;
-}
diff --git a/target/i386/tcg/user/meson.build b/target/i386/tcg/user/meson.build
index 16a0be1ae6..2b059d0baf 100644
--- a/target/i386/tcg/user/meson.build
+++ b/target/i386/tcg/user/meson.build
@@ -1,6 +1,5 @@
 i386_user_ss.add(when: ['CONFIG_TCG', 'CONFIG_USER_ONLY'], if_true: files(
   'excp_helper.c',
-  'misc_stubs.c',
   'fpu_helper.c',
   'seg_helper.c',
 ))
-- 
2.25.1




[PATCH] tcg/aarch64: Fix constant subtraction in tcg_out_addsub2

2021-02-28 Thread Richard Henderson
An hppa guest executing

0xe05c:  ldil L%1,r4
0xe060:  ldo 0(r4),r4
0xe064:  sub r3,r4,sp

produces

  e064 e068
 sub2_i32 tmp0,tmp4,r3,$0x1,$0x1,$0x0

after folding and constant propagation.  Then we hit

tcg-target.c.inc:640: tcg_out_insn_3401: Assertion `aimm <= 0xfff' failed.

because aimm is in fact -16, but unsigned.

The ((bl < 0) ^ sub) condition which negates bl is incorrect and will
always lead to this abort.  If the constant is positive, sub will make
it negative; if the constant is negative, sub will keep it negative.

Signed-off-by: Richard Henderson 
---
 tcg/aarch64/tcg-target.c.inc | 16 +---
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
index 1376cdc404..ec0a86d9d8 100644
--- a/tcg/aarch64/tcg-target.c.inc
+++ b/tcg/aarch64/tcg-target.c.inc
@@ -1410,10 +1410,10 @@ static void tcg_out_addsubi(TCGContext *s, int ext, 
TCGReg rd,
 }
 }
 
-static inline void tcg_out_addsub2(TCGContext *s, TCGType ext, TCGReg rl,
-   TCGReg rh, TCGReg al, TCGReg ah,
-   tcg_target_long bl, tcg_target_long bh,
-   bool const_bl, bool const_bh, bool sub)
+static void tcg_out_addsub2(TCGContext *s, TCGType ext, TCGReg rl,
+TCGReg rh, TCGReg al, TCGReg ah,
+tcg_target_long bl, tcg_target_long bh,
+bool const_bl, bool const_bh, bool sub)
 {
 TCGReg orig_rl = rl;
 AArch64Insn insn;
@@ -1423,11 +1423,13 @@ static inline void tcg_out_addsub2(TCGContext *s, 
TCGType ext, TCGReg rl,
 }
 
 if (const_bl) {
-insn = I3401_ADDSI;
-if ((bl < 0) ^ sub) {
-insn = I3401_SUBSI;
+if (bl < 0) {
 bl = -bl;
+insn = sub ? I3401_ADDSI : I3401_SUBSI;
+} else {
+insn = sub ? I3401_SUBSI : I3401_ADDSI;
 }
+
 if (unlikely(al == TCG_REG_XZR)) {
 /* ??? We want to allow al to be zero for the benefit of
negation via subtraction.  However, that leaves open the
-- 
2.25.1




[PATCH 47/50] target/i386: Pass in port to gen_check_io

2021-02-28 Thread Richard Henderson
Pass in a pre-truncated TCGv_i32 value.  We were doing the
truncation of EDX in multiple places, now only once per insn.
While all callers use s->tmp2_i32, for cleanliness of the
subroutine, use a parameter anyway.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 83bcf5..0937c136ff 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -674,19 +674,23 @@ static void gen_helper_out_func(MemOp ot, TCGv_i32 v, 
TCGv_i32 n)
 }
 }
 
-static bool gen_check_io(DisasContext *s, MemOp ot, uint32_t svm_flags)
+/*
+ * Validate that access to [port, port + 1T0);
 if (PE(s) && (CPL(s) > IOPL(s) || VM86(s))) {
 switch (ot) {
 case MO_8:
-gen_helper_check_iob(cpu_env, s->tmp2_i32);
+gen_helper_check_iob(cpu_env, port);
 break;
 case MO_16:
-gen_helper_check_iow(cpu_env, s->tmp2_i32);
+gen_helper_check_iow(cpu_env, port);
 break;
 case MO_32:
-gen_helper_check_iol(cpu_env, s->tmp2_i32);
+gen_helper_check_iol(cpu_env, port);
 break;
 default:
 tcg_abort();
@@ -702,7 +706,7 @@ static bool gen_check_io(DisasContext *s, MemOp ot, 
uint32_t svm_flags)
 svm_flags |= SVM_IOIO_REP_MASK;
 }
 svm_flags |= 1 << (SVM_IOIO_SIZE_SHIFT + ot);
-gen_helper_svm_check_io(cpu_env, s->tmp2_i32,
+gen_helper_svm_check_io(cpu_env, port,
 tcg_constant_i32(svm_flags),
 tcg_constant_i32(next_eip - cur_eip));
 }
@@ -6473,8 +6477,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 0x6c: /* insS */
 case 0x6d:
 ot = mo_b_d32(b, dflag);
-tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]);
-if (!gen_check_io(s, ot, SVM_IOIO_TYPE_MASK | SVM_IOIO_STR_MASK)) {
+tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]);
+tcg_gen_ext16u_i32(s->tmp2_i32, s->tmp2_i32);
+if (!gen_check_io(s, ot, s->tmp2_i32,
+  SVM_IOIO_TYPE_MASK | SVM_IOIO_STR_MASK)) {
 break;
 }
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
@@ -6493,8 +6499,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 0x6e: /* outsS */
 case 0x6f:
 ot = mo_b_d32(b, dflag);
-tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]);
-if (!gen_check_io(s, ot, SVM_IOIO_STR_MASK)) {
+tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]);
+tcg_gen_ext16u_i32(s->tmp2_i32, s->tmp2_i32);
+if (!gen_check_io(s, ot, s->tmp2_i32, SVM_IOIO_STR_MASK)) {
 break;
 }
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
@@ -6518,14 +6525,13 @@ static target_ulong disas_insn(DisasContext *s, 
CPUState *cpu)
 case 0xe5:
 ot = mo_b_d32(b, dflag);
 val = x86_ldub_code(env, s);
-tcg_gen_movi_tl(s->T0, val);
-if (!gen_check_io(s, ot, SVM_IOIO_TYPE_MASK)) {
+tcg_gen_movi_i32(s->tmp2_i32, val);
+if (!gen_check_io(s, ot, s->tmp2_i32, SVM_IOIO_TYPE_MASK)) {
 break;
 }
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
 }
-tcg_gen_movi_i32(s->tmp2_i32, val);
 gen_helper_in_func(ot, s->T1, s->tmp2_i32);
 gen_op_mov_reg_v(s, ot, R_EAX, s->T1);
 gen_bpt_io(s, s->tmp2_i32, ot);
@@ -6537,16 +6543,14 @@ static target_ulong disas_insn(DisasContext *s, 
CPUState *cpu)
 case 0xe7:
 ot = mo_b_d32(b, dflag);
 val = x86_ldub_code(env, s);
-tcg_gen_movi_tl(s->T0, val);
-if (!gen_check_io(s, ot, 0)) {
+tcg_gen_movi_i32(s->tmp2_i32, val);
+if (!gen_check_io(s, ot, s->tmp2_i32, 0)) {
 break;
 }
-gen_op_mov_v_reg(s, ot, s->T1, R_EAX);
-
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
 }
-tcg_gen_movi_i32(s->tmp2_i32, val);
+gen_op_mov_v_reg(s, ot, s->T1, R_EAX);
 tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1);
 gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32);
 gen_bpt_io(s, s->tmp2_i32, ot);
@@ -6557,14 +6561,14 @@ static target_ulong disas_insn(DisasContext *s, 
CPUState *cpu)
 case 0xec:
 case 0xed:
 ot = mo_b_d32(b, dflag);
-tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]);
-if (!gen_check_io(s, ot, SVM_IOIO_TYPE_MASK)) {
+tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]);
+tcg_gen_ext16u_i32(s->tmp2_i32, s->tmp2_i32);
+if (!gen_check_io(s, ot, s->tmp2_i32, SVM_IOIO_TYPE_MASK)) {
 break;
 }
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
 }

[PATCH 24/50] target/i386: Reduce DisasContext popl_esp_hack and rip_offset to uint8_t

2021-02-28 Thread Richard Henderson
Both of these fields store the size of a single memory access,
so the range of values is 0-8.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 3b7660a019..9004f83c52 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -106,8 +106,8 @@ typedef struct DisasContext {
 int repz_opt; /* optimize jumps within repz instructions */
 int mem_index; /* select memory access functions */
 uint32_t flags; /* all execution flags */
-int popl_esp_hack; /* for correct popl with esp base handling */
-int rip_offset; /* only used in x86_64, but left for simplicity */
+uint8_t popl_esp_hack; /* for correct popl with esp base handling */
+uint8_t rip_offset; /* only used in x86_64, but left for simplicity */
 int cpuid_features;
 int cpuid_ext_features;
 int cpuid_ext2_features;
-- 
2.25.1




[PATCH 43/50] target/i386: Inline user cpu_svm_check_intercept_param

2021-02-28 Thread Richard Henderson
The user-version is a no-op.  This lets us completely
remove tcg/user/svm_stubs.c.

Signed-off-by: Richard Henderson 
---
 target/i386/cpu.h|  8 
 target/i386/tcg/user/svm_stubs.c | 28 
 target/i386/tcg/user/meson.build |  1 -
 3 files changed, 8 insertions(+), 29 deletions(-)
 delete mode 100644 target/i386/tcg/user/svm_stubs.c

diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index a1268abe9f..70b26991dd 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2129,8 +2129,16 @@ static inline void cpu_set_fpuc(CPUX86State *env, 
uint16_t fpuc)
 void helper_lock_init(void);
 
 /* svm_helper.c */
+#ifdef CONFIG_USER_ONLY
+static inline void
+cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type,
+  uint64_t param, uintptr_t retaddr)
+{ /* no-op */ }
+#else
 void cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type,
uint64_t param, uintptr_t retaddr);
+#endif
+
 /* apic.c */
 void cpu_report_tpr_access(CPUX86State *env, TPRAccess access);
 void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip,
diff --git a/target/i386/tcg/user/svm_stubs.c b/target/i386/tcg/user/svm_stubs.c
deleted file mode 100644
index db818f89a8..00
--- a/target/i386/tcg/user/svm_stubs.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *  x86 SVM helpers (user-mode)
- *
- *  Copyright (c) 2003 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see .
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "exec/helper-proto.h"
-#include "tcg/helper-tcg.h"
-
-void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
-   uint64_t param, uintptr_t retaddr)
-{
-}
diff --git a/target/i386/tcg/user/meson.build b/target/i386/tcg/user/meson.build
index 345294c096..16a0be1ae6 100644
--- a/target/i386/tcg/user/meson.build
+++ b/target/i386/tcg/user/meson.build
@@ -2,6 +2,5 @@ i386_user_ss.add(when: ['CONFIG_TCG', 'CONFIG_USER_ONLY'], 
if_true: files(
   'excp_helper.c',
   'misc_stubs.c',
   'fpu_helper.c',
-  'svm_stubs.c',
   'seg_helper.c',
 ))
-- 
2.25.1




[PATCH 48/50] target/i386: Create helper_check_io

2021-02-28 Thread Richard Henderson
Drop helper_check_io[bwl] and expose their common
subroutine to tcg directly.

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

diff --git a/target/i386/helper.h b/target/i386/helper.h
index 1d85f033df..47d0d67699 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -86,9 +86,7 @@ DEF_HELPER_1(rdtsc, void, env)
 DEF_HELPER_1(rdtscp, void, env)
 DEF_HELPER_FLAGS_1(rdpmc, TCG_CALL_NO_WG, noreturn, env)
 
-DEF_HELPER_2(check_iob, void, env, i32)
-DEF_HELPER_2(check_iow, void, env, i32)
-DEF_HELPER_2(check_iol, void, env, i32)
+DEF_HELPER_FLAGS_3(check_io, TCG_CALL_NO_WG, void, env, i32, i32)
 DEF_HELPER_3(outb, void, env, i32, i32)
 DEF_HELPER_2(inb, tl, env, i32)
 DEF_HELPER_3(outw, void, env, i32, i32)
diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c
index cf3f051524..69d6e8f602 100644
--- a/target/i386/tcg/seg_helper.c
+++ b/target/i386/tcg/seg_helper.c
@@ -2418,10 +2418,10 @@ void helper_verw(CPUX86State *env, target_ulong 
selector1)
 }
 
 /* check if Port I/O is allowed in TSS */
-static inline void check_io(CPUX86State *env, int addr, int size,
-uintptr_t retaddr)
+void helper_check_io(CPUX86State *env, uint32_t addr, uint32_t size)
 {
-int io_offset, val, mask;
+uintptr_t retaddr = GETPC();
+uint32_t io_offset, val, mask;
 
 /* TSS must be a valid 32 bit one */
 if (!(env->tr.flags & DESC_P_MASK) ||
@@ -2444,18 +2444,3 @@ static inline void check_io(CPUX86State *env, int addr, 
int size,
 raise_exception_err_ra(env, EXCP0D_GPF, 0, retaddr);
 }
 }
-
-void helper_check_iob(CPUX86State *env, uint32_t t0)
-{
-check_io(env, t0, 1, GETPC());
-}
-
-void helper_check_iow(CPUX86State *env, uint32_t t0)
-{
-check_io(env, t0, 2, GETPC());
-}
-
-void helper_check_iol(CPUX86State *env, uint32_t t0)
-{
-check_io(env, t0, 4, GETPC());
-}
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 0937c136ff..d395ae090e 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -682,19 +682,7 @@ static bool gen_check_io(DisasContext *s, MemOp ot, 
TCGv_i32 port,
  uint32_t svm_flags)
 {
 if (PE(s) && (CPL(s) > IOPL(s) || VM86(s))) {
-switch (ot) {
-case MO_8:
-gen_helper_check_iob(cpu_env, port);
-break;
-case MO_16:
-gen_helper_check_iow(cpu_env, port);
-break;
-case MO_32:
-gen_helper_check_iol(cpu_env, port);
-break;
-default:
-tcg_abort();
-}
+gen_helper_check_io(cpu_env, port, tcg_constant_i32(1 << ot));
 }
 if (GUEST(s)) {
 target_ulong cur_eip = s->base.pc_next - s->cs_base;
-- 
2.25.1




[PATCH 42/50] target/i386: Unify invlpg, invlpga

2021-02-28 Thread Richard Henderson
Use a single helper, flush_page, to do the work.
Use gen_svm_check_intercept.
Perform the zero-extension for invlpga inline.

Signed-off-by: Richard Henderson 
---
 target/i386/helper.h |  3 +--
 target/i386/tcg/sysemu/misc_helper.c |  7 ++-
 target/i386/tcg/sysemu/svm_helper.c  | 18 --
 target/i386/tcg/translate.c  | 20 
 4 files changed, 15 insertions(+), 33 deletions(-)

diff --git a/target/i386/helper.h b/target/i386/helper.h
index ab72eba52a..0264fba335 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -110,8 +110,7 @@ DEF_HELPER_2(vmload, void, env, int)
 DEF_HELPER_2(vmsave, void, env, int)
 DEF_HELPER_1(stgi, void, env)
 DEF_HELPER_1(clgi, void, env)
-DEF_HELPER_2(invlpga, void, env, int)
-DEF_HELPER_2(invlpg, void, env, tl)
+DEF_HELPER_FLAGS_2(flush_page, TCG_CALL_NO_RWG, void, env, tl)
 DEF_HELPER_FLAGS_2(hlt, TCG_CALL_NO_WG, noreturn, env, int)
 DEF_HELPER_FLAGS_2(monitor, TCG_CALL_NO_WG, void, env, tl)
 DEF_HELPER_FLAGS_2(mwait, TCG_CALL_NO_WG, noreturn, env, int)
diff --git a/target/i386/tcg/sysemu/misc_helper.c 
b/target/i386/tcg/sysemu/misc_helper.c
index 1d8b651212..b7146092f1 100644
--- a/target/i386/tcg/sysemu/misc_helper.c
+++ b/target/i386/tcg/sysemu/misc_helper.c
@@ -435,12 +435,9 @@ void helper_rdmsr(CPUX86State *env)
 env->regs[R_EDX] = (uint32_t)(val >> 32);
 }
 
-void helper_invlpg(CPUX86State *env, target_ulong addr)
+void helper_flush_page(CPUX86State *env, target_ulong addr)
 {
-X86CPU *cpu = env_archcpu(env);
-
-cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0, GETPC());
-tlb_flush_page(CPU(cpu), addr);
+tlb_flush_page(env_cpu(env), addr);
 }
 
 static void QEMU_NORETURN do_hlt(CPUX86State *env)
diff --git a/target/i386/tcg/sysemu/svm_helper.c 
b/target/i386/tcg/sysemu/svm_helper.c
index 86a0b3c4be..a8a671aa33 100644
--- a/target/i386/tcg/sysemu/svm_helper.c
+++ b/target/i386/tcg/sysemu/svm_helper.c
@@ -423,24 +423,6 @@ void helper_clgi(CPUX86State *env)
 env->hflags2 &= ~HF2_GIF_MASK;
 }
 
-void helper_invlpga(CPUX86State *env, int aflag)
-{
-X86CPU *cpu = env_archcpu(env);
-target_ulong addr;
-
-cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPGA, 0, GETPC());
-
-if (aflag == 2) {
-addr = env->regs[R_EAX];
-} else {
-addr = (uint32_t)env->regs[R_EAX];
-}
-
-/* XXX: could use the ASID to see if it is needed to do the
-   flush */
-tlb_flush_page(CPU(cpu), addr);
-}
-
 void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
uint64_t param, uintptr_t retaddr)
 {
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index aa6a8c4813..9d2171aa3a 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -194,9 +194,8 @@ typedef struct DisasContext {
 
 #ifdef CONFIG_USER_ONLY
 STUB_HELPER(clgi, TCGv_env env)
+STUB_HELPER(flush_page, TCGv_env env, TCGv addr)
 STUB_HELPER(hlt, TCGv_env env, TCGv_i32 pc_ofs)
-STUB_HELPER(invlpga, TCGv_env env, TCGv_i32 aflag)
-STUB_HELPER(invlpg, TCGv_env env, TCGv addr)
 STUB_HELPER(monitor, TCGv_env env, TCGv addr)
 STUB_HELPER(mwait, TCGv_env env, TCGv_i32 pc_ofs)
 STUB_HELPER(set_dr, TCGv_env env, TCGv_i32 reg, TCGv val)
@@ -7586,9 +7585,15 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 if (!check_cpl0(s)) {
 break;
 }
-gen_update_cc_op(s);
-gen_jmp_im(s, pc_start - s->cs_base);
-gen_helper_invlpga(cpu_env, tcg_const_i32(s->aflag - 1));
+gen_svm_check_intercept(s, SVM_EXIT_INVLPGA);
+if (s->aflag == MO_64) {
+tcg_gen_mov_tl(s->A0, cpu_regs[R_EAX]);
+} else {
+tcg_gen_ext32u_tl(s->A0, cpu_regs[R_EAX]);
+}
+gen_helper_flush_page(cpu_env, s->A0);
+gen_jmp_im(s, s->pc - s->cs_base);
+gen_eob(s);
 break;
 
 CASE_MODRM_MEM_OP(2): /* lgdt */
@@ -7676,10 +7681,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 if (!check_cpl0(s)) {
 break;
 }
-gen_update_cc_op(s);
-gen_jmp_im(s, pc_start - s->cs_base);
+gen_svm_check_intercept(s, SVM_EXIT_INVLPG);
 gen_lea_modrm(env, s, modrm);
-gen_helper_invlpg(cpu_env, s->A0);
+gen_helper_flush_page(cpu_env, s->A0);
 gen_jmp_im(s, s->pc - s->cs_base);
 gen_eob(s);
 break;
-- 
2.25.1




[PATCH 20/50] target/i386: Reduce DisasContext.flags to uint32_t

2021-02-28 Thread Richard Henderson
The value comes from tb->flags, which is uint32_t.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index f4af92886f..39af69585f 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -105,7 +105,7 @@ typedef struct DisasContext {
 int jmp_opt; /* use direct block chaining for direct jumps */
 int repz_opt; /* optimize jumps within repz instructions */
 int mem_index; /* select memory access functions */
-uint64_t flags; /* all execution flags */
+uint32_t flags; /* all execution flags */
 int popl_esp_hack; /* for correct popl with esp base handling */
 int rip_offset; /* only used in x86_64, but left for simplicity */
 int cpuid_features;
-- 
2.25.1




[PATCH 35/50] target/i386: Simplify gen_debug usage

2021-02-28 Thread Richard Henderson
Both invocations pass the start of the current instruction,
which is available as s->base.pc_next.  The function sets
is_jmp, so we can eliminate a second setting.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index c2bc3c4b22..c135be9063 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -2614,10 +2614,10 @@ static void gen_interrupt(DisasContext *s, int intno,
 s->base.is_jmp = DISAS_NORETURN;
 }
 
-static void gen_debug(DisasContext *s, target_ulong cur_eip)
+static void gen_debug(DisasContext *s)
 {
 gen_update_cc_op(s);
-gen_jmp_im(s, cur_eip);
+gen_jmp_im(s, s->base.pc_next - s->cs_base);
 gen_helper_debug(cpu_env);
 s->base.is_jmp = DISAS_NORETURN;
 }
@@ -7146,7 +7146,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 #ifdef WANT_ICEBP
 case 0xf1: /* icebp (undocumented, exits to external debugger) */
 gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP);
-gen_debug(s, pc_start - s->cs_base);
+gen_debug(s);
 break;
 #endif
 case 0xfa: /* cli */
@@ -8586,8 +8586,7 @@ static bool i386_tr_breakpoint_check(DisasContextBase 
*dcbase, CPUState *cpu,
 /* If RF is set, suppress an internally generated breakpoint.  */
 int flags = dc->base.tb->flags & HF_RF_MASK ? BP_GDB : BP_ANY;
 if (bp->flags & flags) {
-gen_debug(dc, dc->base.pc_next - dc->cs_base);
-dc->base.is_jmp = DISAS_NORETURN;
+gen_debug(dc);
 /* The address covered by the breakpoint must be included in
[tb->pc, tb->pc + tb->size) in order to for it to be
properly cleared -- thus we increment the PC here so that
-- 
2.25.1




[PATCH 33/50] target/i386: Eliminate SVM helpers for user-only

2021-02-28 Thread Richard Henderson
Use STUB_HELPER to ensure that such calls are always eliminated.

Signed-off-by: Richard Henderson 
---
 target/i386/helper.h |  3 +--
 target/i386/tcg/translate.c  |  9 
 target/i386/tcg/user/svm_stubs.c | 38 
 3 files changed, 10 insertions(+), 40 deletions(-)

diff --git a/target/i386/helper.h b/target/i386/helper.h
index 7a09efd55b..d0f7f07c6c 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -107,8 +107,6 @@ DEF_HELPER_2(inl, tl, env, i32)
 
 #ifndef CONFIG_USER_ONLY
 DEF_HELPER_FLAGS_4(bpt_io, TCG_CALL_NO_WG, void, env, i32, i32, tl)
-#endif /* !CONFIG_USER_ONLY */
-
 DEF_HELPER_3(svm_check_intercept_param, void, env, i32, i64)
 DEF_HELPER_4(svm_check_io, void, env, i32, i32, i32)
 DEF_HELPER_3(vmrun, void, env, int, int)
@@ -118,6 +116,7 @@ DEF_HELPER_2(vmsave, void, env, int)
 DEF_HELPER_1(stgi, void, env)
 DEF_HELPER_1(clgi, void, env)
 DEF_HELPER_2(invlpga, void, env, int)
+#endif /* !CONFIG_USER_ONLY */
 
 /* x86 FPU */
 
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 92e85e1872..8c77c9cbe6 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -193,7 +193,16 @@ typedef struct DisasContext {
 { qemu_build_not_reached(); }
 
 #ifdef CONFIG_USER_ONLY
+STUB_HELPER(clgi, TCGv_env env)
+STUB_HELPER(invlpga, TCGv_env env, TCGv_i32 aflag)
 STUB_HELPER(set_dr, TCGv_env env, TCGv_i32 reg, TCGv val)
+STUB_HELPER(stgi, TCGv_env env)
+STUB_HELPER(svm_check_intercept_param, TCGv_env env, TCGv_i32 t, TCGv_i64 p)
+STUB_HELPER(svm_check_io, TCGv_env env, TCGv_i32 port, TCGv_i32 p, TCGv_i32 a)
+STUB_HELPER(vmload, TCGv_env env, TCGv_i32 aflag)
+STUB_HELPER(vmmcall, TCGv_env env)
+STUB_HELPER(vmrun, TCGv_env env, TCGv_i32 aflag, TCGv_i32 pc_ofs)
+STUB_HELPER(vmsave, TCGv_env env, TCGv_i32 aflag)
 #endif
 
 static void gen_eob(DisasContext *s);
diff --git a/target/i386/tcg/user/svm_stubs.c b/target/i386/tcg/user/svm_stubs.c
index 63b37f0de6..48a43bdcea 100644
--- a/target/i386/tcg/user/svm_stubs.c
+++ b/target/i386/tcg/user/svm_stubs.c
@@ -22,51 +22,13 @@
 #include "exec/helper-proto.h"
 #include "tcg/helper-tcg.h"
 
-void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
-{
-}
-
-void helper_vmmcall(CPUX86State *env)
-{
-}
-
-void helper_vmload(CPUX86State *env, int aflag)
-{
-}
-
-void helper_vmsave(CPUX86State *env, int aflag)
-{
-}
-
-void helper_stgi(CPUX86State *env)
-{
-}
-
-void helper_clgi(CPUX86State *env)
-{
-}
-
-void helper_invlpga(CPUX86State *env, int aflag)
-{
-}
-
 void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1,
 uintptr_t retaddr)
 {
 assert(0);
 }
 
-void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
-  uint64_t param)
-{
-}
-
 void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
uint64_t param, uintptr_t retaddr)
 {
 }
-
-void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
- uint32_t next_eip_addend)
-{
-}
-- 
2.25.1




[PATCH 21/50] target/i386: Reduce DisasContext.override to int8_t

2021-02-28 Thread Richard Henderson
The range of values is -1 (none) to 5 (R_GS).

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 39af69585f..19c2034344 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -77,7 +77,7 @@ typedef struct DisasContext {
 DisasContextBase base;
 
 /* current insn context */
-int override; /* -1 if no override */
+int8_t override; /* -1 if no override, else R_CS, R_DS, etc */
 int prefix;
 MemOp aflag;
 MemOp dflag;
-- 
2.25.1




[PATCH 29/50] target/i386: Add stub generator for helper_set_dr

2021-02-28 Thread Richard Henderson
This removes an ifdef from the middle of disas_insn,
and ensures that the branch is not reachable.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index f0bc2df98c..42b96a2669 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -179,6 +179,19 @@ typedef struct DisasContext {
 #define REX_B(S)   0
 #endif
 
+/*
+ * Many sysemu-only helpers are not reachable for user-only.
+ * Define stub generators here, so that we need not either sprinkle
+ * ifdefs through the translator, nor provide the helper function.
+ */
+#define STUB_HELPER(NAME, ...) \
+static inline void gen_helper_##NAME(__VA_ARGS__) \
+{ qemu_build_not_reached(); }
+
+#ifdef CONFIG_USER_ONLY
+STUB_HELPER(set_dr, TCGv_env env, TCGv_i32 reg, TCGv val)
+#endif
+
 static void gen_eob(DisasContext *s);
 static void gen_jr(DisasContext *s, TCGv dest);
 static void gen_jmp(DisasContext *s, target_ulong eip);
@@ -8069,7 +8082,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 0x121: /* mov reg, drN */
 case 0x123: /* mov drN, reg */
 if (check_cpl0(s)) {
-#ifndef CONFIG_USER_ONLY
 modrm = x86_ldub_code(env, s);
 /* Ignore the mod bits (assume (modrm&0xc0)==0xc0).
  * AMD documentation (24594.pdf) and testing of
@@ -8098,7 +8110,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 gen_helper_get_dr(s->T0, cpu_env, s->tmp2_i32);
 gen_op_mov_reg_v(s, ot, rm, s->T0);
 }
-#endif /* !CONFIG_USER_ONLY */
 }
 break;
 case 0x106: /* clts */
-- 
2.25.1




[PATCH 46/50] target/i386: Tidy gen_check_io

2021-02-28 Thread Richard Henderson
Get cur_eip from DisasContext.  Do not require the caller
to use svm_is_rep; get prefix from DisasContext.  Use the
proper symbolic constants for SVM_IOIO_*.

While we're touching all call sites, return bool in
preparation for gen_check_io raising #GP.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index dc31d8667f..83bcf5 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -674,13 +674,10 @@ static void gen_helper_out_func(MemOp ot, TCGv_i32 v, 
TCGv_i32 n)
 }
 }
 
-static void gen_check_io(DisasContext *s, MemOp ot, target_ulong cur_eip,
- uint32_t svm_flags)
+static bool gen_check_io(DisasContext *s, MemOp ot, uint32_t svm_flags)
 {
-target_ulong next_eip;
-
+tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 if (PE(s) && (CPL(s) > IOPL(s) || VM86(s))) {
-tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 switch (ot) {
 case MO_8:
 gen_helper_check_iob(cpu_env, s->tmp2_i32);
@@ -696,15 +693,20 @@ static void gen_check_io(DisasContext *s, MemOp ot, 
target_ulong cur_eip,
 }
 }
 if (GUEST(s)) {
+target_ulong cur_eip = s->base.pc_next - s->cs_base;
+target_ulong next_eip = s->pc - s->cs_base;
+
 gen_update_cc_op(s);
 gen_jmp_im(s, cur_eip);
-svm_flags |= (1 << (4 + ot));
-next_eip = s->pc - s->cs_base;
-tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
+if (s->prefix & (PREFIX_REPZ | PREFIX_REPNZ)) {
+svm_flags |= SVM_IOIO_REP_MASK;
+}
+svm_flags |= 1 << (SVM_IOIO_SIZE_SHIFT + ot);
 gen_helper_svm_check_io(cpu_env, s->tmp2_i32,
-tcg_const_i32(svm_flags),
-tcg_const_i32(next_eip - cur_eip));
+tcg_constant_i32(svm_flags),
+tcg_constant_i32(next_eip - cur_eip));
 }
+return true;
 }
 
 static inline void gen_movs(DisasContext *s, MemOp ot)
@@ -2425,11 +2427,6 @@ static void gen_movl_seg_T0(DisasContext *s, X86Seg 
seg_reg)
 }
 }
 
-static inline int svm_is_rep(int prefixes)
-{
-return ((prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) ? 8 : 0);
-}
-
 static void gen_svm_check_intercept(DisasContext *s, uint32_t type)
 {
 /* no SVM activated; fast case */
@@ -6477,8 +6474,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 0x6d:
 ot = mo_b_d32(b, dflag);
 tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]);
-gen_check_io(s, ot, pc_start - s->cs_base, 
- SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | 4);
+if (!gen_check_io(s, ot, SVM_IOIO_TYPE_MASK | SVM_IOIO_STR_MASK)) {
+break;
+}
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
 }
@@ -6496,8 +6494,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 0x6f:
 ot = mo_b_d32(b, dflag);
 tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]);
-gen_check_io(s, ot, pc_start - s->cs_base,
- svm_is_rep(prefixes) | 4);
+if (!gen_check_io(s, ot, SVM_IOIO_STR_MASK)) {
+break;
+}
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
 }
@@ -6520,8 +6519,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 ot = mo_b_d32(b, dflag);
 val = x86_ldub_code(env, s);
 tcg_gen_movi_tl(s->T0, val);
-gen_check_io(s, ot, pc_start - s->cs_base,
- SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
+if (!gen_check_io(s, ot, SVM_IOIO_TYPE_MASK)) {
+break;
+}
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
 }
@@ -6538,8 +6538,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 ot = mo_b_d32(b, dflag);
 val = x86_ldub_code(env, s);
 tcg_gen_movi_tl(s->T0, val);
-gen_check_io(s, ot, pc_start - s->cs_base,
- svm_is_rep(prefixes));
+if (!gen_check_io(s, ot, 0)) {
+break;
+}
 gen_op_mov_v_reg(s, ot, s->T1, R_EAX);
 
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
@@ -6557,8 +6558,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 0xed:
 ot = mo_b_d32(b, dflag);
 tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]);
-gen_check_io(s, ot, pc_start - s->cs_base,
- SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
+if (!gen_check_io(s, ot, SVM_IOIO_TYPE_MASK)) {
+break;
+}
 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
 }
@@ -6574,8 +6576,9 @@ static target_ulong 

[PATCH 25/50] target/i386: Leave TF in DisasContext.flags

2021-02-28 Thread Richard Henderson
It's just as easy to clear the flag with AND than assignment.
In two cases the test for the bit can be folded together with
the test for HF_INHIBIT_IRQ_MASK.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 9004f83c52..92669bc142 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -101,7 +101,6 @@ typedef struct DisasContext {
 uint8_t vex_v;  /* vex  register, without 1's complement.  */
 CCOp cc_op;  /* current CC operation */
 bool cc_op_dirty;
-int tf; /* TF cpu flag */
 int jmp_opt; /* use direct block chaining for direct jumps */
 int repz_opt; /* optimize jumps within repz instructions */
 int mem_index; /* select memory access functions */
@@ -2656,7 +2655,7 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool 
recheck_tf, bool jr)
 } else if (recheck_tf) {
 gen_helper_rechecking_single_step(cpu_env);
 tcg_gen_exit_tb(NULL, 0);
-} else if (s->tf) {
+} else if (s->flags & HF_TF_MASK) {
 gen_helper_single_step(cpu_env);
 } else if (jr) {
 tcg_gen_lookup_and_goto_ptr();
@@ -5534,7 +5533,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 if (s->base.is_jmp) {
 gen_jmp_im(s, s->pc - s->cs_base);
 if (reg == R_SS) {
-s->tf = 0;
+s->flags &= ~HF_TF_MASK;
 gen_eob_inhibit_irq(s, true);
 } else {
 gen_eob(s);
@@ -5600,7 +5599,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 if (s->base.is_jmp) {
 gen_jmp_im(s, s->pc - s->cs_base);
 if (reg == R_SS) {
-s->tf = 0;
+s->flags &= ~HF_TF_MASK;
 gen_eob_inhibit_irq(s, true);
 } else {
 gen_eob(s);
@@ -8500,7 +8499,6 @@ static void i386_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cpu)
 g_assert(LMA(dc) == ((flags & HF_LMA_MASK) != 0));
 g_assert(ADDSEG(dc) == ((flags & HF_ADDSEG_MASK) != 0));
 
-dc->tf = (flags >> TF_SHIFT) & 1;
 dc->cc_op = CC_OP_DYNAMIC;
 dc->cc_op_dirty = false;
 dc->popl_esp_hack = 0;
@@ -8515,8 +8513,8 @@ static void i386_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cpu)
 dc->cpuid_ext3_features = env->features[FEAT_8000_0001_ECX];
 dc->cpuid_7_0_ebx_features = env->features[FEAT_7_0_EBX];
 dc->cpuid_xsave_features = env->features[FEAT_XSAVE];
-dc->jmp_opt = !(dc->tf || dc->base.singlestep_enabled ||
-(flags & HF_INHIBIT_IRQ_MASK));
+dc->jmp_opt = !(dc->base.singlestep_enabled ||
+(flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK)));
 /* Do not optimize repz jumps at all in icount mode, because
rep movsS instructions are execured with different paths
in !repz_opt and repz_opt modes. The first one was used
@@ -8591,7 +8589,7 @@ static void i386_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cpu)
 
 pc_next = disas_insn(dc, cpu);
 
-if (dc->tf || (dc->base.tb->flags & HF_INHIBIT_IRQ_MASK)) {
+if (dc->flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK)) {
 /* if single step mode, we generate only one instruction and
generate an exception */
 /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
-- 
2.25.1




[PATCH 22/50] target/i386: Reduce DisasContext.prefix to uint8_t

2021-02-28 Thread Richard Henderson
The highest bit in this set is 0x40 (PREFIX_REX).

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 19c2034344..79f987b2cf 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -78,7 +78,7 @@ typedef struct DisasContext {
 
 /* current insn context */
 int8_t override; /* -1 if no override, else R_CS, R_DS, etc */
-int prefix;
+uint8_t prefix;
 MemOp aflag;
 MemOp dflag;
 target_ulong pc_start;
-- 
2.25.1




[PATCH 44/50] target/i386: Eliminate user stubs for read/write_crN, rd/wrmsr

2021-02-28 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/i386/helper.h  |  8 
 target/i386/tcg/translate.c   |  4 
 target/i386/tcg/user/misc_stubs.c | 20 
 3 files changed, 8 insertions(+), 24 deletions(-)

diff --git a/target/i386/helper.h b/target/i386/helper.h
index 0264fba335..1d85f033df 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -42,8 +42,6 @@ DEF_HELPER_5(lcall_protected, void, env, int, tl, int, tl)
 DEF_HELPER_2(iret_real, void, env, int)
 DEF_HELPER_3(iret_protected, void, env, int, int)
 DEF_HELPER_3(lret_protected, void, env, int, int)
-DEF_HELPER_FLAGS_2(read_crN, TCG_CALL_NO_RWG, tl, env, int)
-DEF_HELPER_FLAGS_3(write_crN, TCG_CALL_NO_RWG, void, env, int, tl)
 DEF_HELPER_1(clts, void, env)
 
 #ifndef CONFIG_USER_ONLY
@@ -87,8 +85,6 @@ DEF_HELPER_1(cpuid, void, env)
 DEF_HELPER_1(rdtsc, void, env)
 DEF_HELPER_1(rdtscp, void, env)
 DEF_HELPER_FLAGS_1(rdpmc, TCG_CALL_NO_WG, noreturn, env)
-DEF_HELPER_1(rdmsr, void, env)
-DEF_HELPER_1(wrmsr, void, env)
 
 DEF_HELPER_2(check_iob, void, env, i32)
 DEF_HELPER_2(check_iow, void, env, i32)
@@ -114,6 +110,10 @@ DEF_HELPER_FLAGS_2(flush_page, TCG_CALL_NO_RWG, void, env, 
tl)
 DEF_HELPER_FLAGS_2(hlt, TCG_CALL_NO_WG, noreturn, env, int)
 DEF_HELPER_FLAGS_2(monitor, TCG_CALL_NO_WG, void, env, tl)
 DEF_HELPER_FLAGS_2(mwait, TCG_CALL_NO_WG, noreturn, env, int)
+DEF_HELPER_1(rdmsr, void, env)
+DEF_HELPER_1(wrmsr, void, env)
+DEF_HELPER_FLAGS_2(read_crN, TCG_CALL_NO_RWG, tl, env, int)
+DEF_HELPER_FLAGS_3(write_crN, TCG_CALL_NO_RWG, void, env, int, tl)
 #endif /* !CONFIG_USER_ONLY */
 
 /* x86 FPU */
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 9d2171aa3a..2493d39f0b 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -198,6 +198,8 @@ STUB_HELPER(flush_page, TCGv_env env, TCGv addr)
 STUB_HELPER(hlt, TCGv_env env, TCGv_i32 pc_ofs)
 STUB_HELPER(monitor, TCGv_env env, TCGv addr)
 STUB_HELPER(mwait, TCGv_env env, TCGv_i32 pc_ofs)
+STUB_HELPER(rdmsr, TCGv_env env)
+STUB_HELPER(read_crN, TCGv ret, TCGv_env env, TCGv_i32 reg)
 STUB_HELPER(set_dr, TCGv_env env, TCGv_i32 reg, TCGv val)
 STUB_HELPER(stgi, TCGv_env env)
 STUB_HELPER(svm_check_intercept, TCGv_env env, TCGv_i32 type)
@@ -206,6 +208,8 @@ STUB_HELPER(vmload, TCGv_env env, TCGv_i32 aflag)
 STUB_HELPER(vmmcall, TCGv_env env)
 STUB_HELPER(vmrun, TCGv_env env, TCGv_i32 aflag, TCGv_i32 pc_ofs)
 STUB_HELPER(vmsave, TCGv_env env, TCGv_i32 aflag)
+STUB_HELPER(write_crN, TCGv_env env, TCGv_i32 reg, TCGv val)
+STUB_HELPER(wrmsr, TCGv_env env)
 #endif
 
 static void gen_eob(DisasContext *s);
diff --git a/target/i386/tcg/user/misc_stubs.c 
b/target/i386/tcg/user/misc_stubs.c
index 84df4e65ff..df38b44d6e 100644
--- a/target/i386/tcg/user/misc_stubs.c
+++ b/target/i386/tcg/user/misc_stubs.c
@@ -53,23 +53,3 @@ target_ulong helper_inl(CPUX86State *env, uint32_t port)
 g_assert_not_reached();
 return 0;
 }
-
-target_ulong helper_read_crN(CPUX86State *env, int reg)
-{
-g_assert_not_reached();
-}
-
-void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
-{
-g_assert_not_reached();
-}
-
-void helper_wrmsr(CPUX86State *env)
-{
-g_assert_not_reached();
-}
-
-void helper_rdmsr(CPUX86State *env)
-{
-g_assert_not_reached();
-}
-- 
2.25.1




[PATCH 18/50] target/i386: Move rex_w into DisasContext

2021-02-28 Thread Richard Henderson
Treat this flag exactly like we treat the other rex bits.
The -1 initialization is unused; the two tests are > 0 and == 1,
so the value can be reduced to a bool.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index aa10d0ba99..deb1e43430 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -95,6 +95,7 @@ typedef struct DisasContext {
 uint8_t rex_r;
 uint8_t rex_x;
 uint8_t rex_b;
+bool rex_w;
 #endif
 int vex_l;  /* vex vector length */
 int vex_v;  /* vex  register, without 1's complement.  */
@@ -167,11 +168,13 @@ typedef struct DisasContext {
 
 #ifdef TARGET_X86_64
 #define REX_PREFIX(S)  (((S)->prefix & PREFIX_REX) != 0)
+#define REX_W(S)   ((S)->rex_w)
 #define REX_R(S)   ((S)->rex_r + 0)
 #define REX_X(S)   ((S)->rex_x + 0)
 #define REX_B(S)   ((S)->rex_b + 0)
 #else
 #define REX_PREFIX(S)  false
+#define REX_W(S)   false
 #define REX_R(S)   0
 #define REX_X(S)   0
 #define REX_B(S)   0
@@ -4552,12 +4555,12 @@ static target_ulong disas_insn(DisasContext *s, 
CPUState *cpu)
 MemOp ot, aflag, dflag;
 int modrm, reg, rm, mod, op, opreg, val;
 target_ulong next_eip, tval;
-int rex_w;
 target_ulong pc_start = s->base.pc_next;
 
 s->pc_start = s->pc = pc_start;
 s->override = -1;
 #ifdef TARGET_X86_64
+s->rex_w = false;
 s->rex_r = 0;
 s->rex_x = 0;
 s->rex_b = 0;
@@ -4571,7 +4574,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 }
 
 prefixes = 0;
-rex_w = -1;
 
  next_byte:
 b = x86_ldub_code(env, s);
@@ -4615,7 +4617,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 if (CODE64(s)) {
 /* REX prefix */
 prefixes |= PREFIX_REX;
-rex_w = (b >> 3) & 1;
+s->rex_w = (b >> 3) & 1;
 s->rex_r = (b & 0x4) << 1;
 s->rex_x = (b & 0x2) << 2;
 s->rex_b = (b & 0x1) << 3;
@@ -4654,12 +4656,12 @@ static target_ulong disas_insn(DisasContext *s, 
CPUState *cpu)
 b = x86_ldub_code(env, s) | 0x100;
 } else {
 /* 3-byte VEX prefix: RXBm wlpp */
+vex3 = x86_ldub_code(env, s);
 #ifdef TARGET_X86_64
 s->rex_x = (~vex2 >> 3) & 8;
 s->rex_b = (~vex2 >> 2) & 8;
+s->rex_w = (vex3 >> 7) & 1;
 #endif
-vex3 = x86_ldub_code(env, s);
-rex_w = (vex3 >> 7) & 1;
 switch (vex2 & 0x1f) {
 case 0x01: /* Implied 0f leading opcode bytes.  */
 b = x86_ldub_code(env, s) | 0x100;
@@ -4686,7 +4688,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 /* In 64-bit mode, the default data size is 32-bit.  Select 64-bit
data with rex_w, and 16-bit data with 0x66; rex_w takes precedence
over 0x66 if both are present.  */
-dflag = (rex_w > 0 ? MO_64 : prefixes & PREFIX_DATA ? MO_16 : MO_32);
+dflag = (REX_W(s) ? MO_64 : prefixes & PREFIX_DATA ? MO_16 : MO_32);
 /* In 64-bit mode, 0x67 selects 32-bit addressing.  */
 aflag = (prefixes & PREFIX_ADR ? MO_32 : MO_64);
 } else {
@@ -5082,7 +5084,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 /* operand size for jumps is 64 bit */
 ot = MO_64;
 } else if (op == 3 || op == 5) {
-ot = dflag != MO_16 ? MO_32 + (rex_w == 1) : MO_16;
+ot = dflag != MO_16 ? MO_32 + REX_W(s) : MO_16;
 } else if (op == 6) {
 /* default push size is 64 bit */
 ot = mo_pushpop(s, dflag);
-- 
2.25.1




[PATCH 26/50] target/i386: Reduce DisasContext jmp_opt, repz_opt to bool

2021-02-28 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 92669bc142..6877873bee 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -101,8 +101,8 @@ typedef struct DisasContext {
 uint8_t vex_v;  /* vex  register, without 1's complement.  */
 CCOp cc_op;  /* current CC operation */
 bool cc_op_dirty;
-int jmp_opt; /* use direct block chaining for direct jumps */
-int repz_opt; /* optimize jumps within repz instructions */
+bool jmp_opt; /* use direct block chaining for direct jumps */
+bool repz_opt; /* optimize jumps within repz instructions */
 int mem_index; /* select memory access functions */
 uint32_t flags; /* all execution flags */
 uint8_t popl_esp_hack; /* for correct popl with esp base handling */
-- 
2.25.1




[PATCH 14/50] target/i386: Assert !ADDSEG for x86_64 user-only

2021-02-28 Thread Richard Henderson
LMA disables traditional segmentation, exposing a flat address space.
This means that ADDSEG is off.

Since we're adding an accessor macro, pull the value directly out
of flags otherwise.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index c8728397d0..33da97d0a6 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -108,7 +108,6 @@ typedef struct DisasContext {
 #ifdef TARGET_X86_64
 bool x86_64_hregs;
 #endif
-int addseg; /* non zero if either DS/ES/SS have a non zero base */
 int f_st;   /* currently unused */
 int tf; /* TF cpu flag */
 int jmp_opt; /* use direct block chaining for direct jumps */
@@ -156,10 +155,12 @@ typedef struct DisasContext {
 #define VM86(S)   false
 #define CODE32(S) true
 #define SS32(S)   true
+#define ADDSEG(S) false
 #else
 #define VM86(S)   (((S)->flags & HF_VM_MASK) != 0)
 #define CODE32(S) (((S)->flags & HF_CS32_MASK) != 0)
 #define SS32(S)   (((S)->flags & HF_SS32_MASK) != 0)
+#define ADDSEG(S) (((S)->flags & HF_ADDSEG_MASK) != 0)
 #endif
 #if !defined(TARGET_X86_64)
 #define CODE64(S) false
@@ -492,7 +493,7 @@ static void gen_lea_v_seg(DisasContext *s, MemOp aflag, 
TCGv a0,
 #endif
 case MO_32:
 /* 32 bit address */
-if (ovr_seg < 0 && s->addseg) {
+if (ovr_seg < 0 && ADDSEG(s)) {
 ovr_seg = def_seg;
 }
 if (ovr_seg < 0) {
@@ -505,7 +506,7 @@ static void gen_lea_v_seg(DisasContext *s, MemOp aflag, 
TCGv a0,
 tcg_gen_ext16u_tl(s->A0, a0);
 a0 = s->A0;
 if (ovr_seg < 0) {
-if (s->addseg) {
+if (ADDSEG(s)) {
 ovr_seg = def_seg;
 } else {
 return;
@@ -2429,7 +2430,7 @@ static void gen_push_v(DisasContext *s, TCGv val)
 tcg_gen_subi_tl(s->A0, cpu_regs[R_ESP], size);
 
 if (!CODE64(s)) {
-if (s->addseg) {
+if (ADDSEG(s)) {
 new_esp = s->tmp4;
 tcg_gen_mov_tl(new_esp, s->A0);
 }
@@ -8500,8 +8501,8 @@ static void i386_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cpu)
 g_assert(CODE64(dc) == ((flags & HF_CS64_MASK) != 0));
 g_assert(SS32(dc) == ((flags & HF_SS32_MASK) != 0));
 g_assert(LMA(dc) == ((flags & HF_LMA_MASK) != 0));
+g_assert(ADDSEG(dc) == ((flags & HF_ADDSEG_MASK) != 0));
 
-dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1;
 dc->f_st = 0;
 dc->tf = (flags >> TF_SHIFT) & 1;
 dc->cc_op = CC_OP_DYNAMIC;
-- 
2.25.1




[PATCH 15/50] target/i386: Introduce REX_PREFIX

2021-02-28 Thread Richard Henderson
The existing flag, x86_64_hregs, does not accurately describe
its setting.  It is true if and only if a REX prefix has been
seen.  Yes, that affects the "h" regs, but that's secondary.

Add PREFIX_REX and include this bit in s->prefix.  Add REX_PREFIX
so that the check folds away when x86_64 is compiled out.

Fold away the reg >= 8 check, because bit 3 of the register
number comes from the REX prefix in the first place.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 33da97d0a6..31b128d4fe 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -39,6 +39,7 @@
 #define PREFIX_DATA   0x08
 #define PREFIX_ADR0x10
 #define PREFIX_VEX0x20
+#define PREFIX_REX0x40
 
 #ifdef TARGET_X86_64
 #define REX_X(s) ((s)->rex_x)
@@ -105,9 +106,6 @@ typedef struct DisasContext {
 int vex_v;  /* vex  register, without 1's complement.  */
 CCOp cc_op;  /* current CC operation */
 bool cc_op_dirty;
-#ifdef TARGET_X86_64
-bool x86_64_hregs;
-#endif
 int f_st;   /* currently unused */
 int tf; /* TF cpu flag */
 int jmp_opt; /* use direct block chaining for direct jumps */
@@ -173,6 +171,12 @@ typedef struct DisasContext {
 #define LMA(S)(((S)->flags & HF_LMA_MASK) != 0)
 #endif
 
+#ifdef TARGET_X86_64
+#define REX_PREFIX(S)  (((S)->prefix & PREFIX_REX) != 0)
+#else
+#define REX_PREFIX(S)  false
+#endif
+
 static void gen_eob(DisasContext *s);
 static void gen_jr(DisasContext *s, TCGv dest);
 static void gen_jmp(DisasContext *s, target_ulong eip);
@@ -336,14 +340,10 @@ static void gen_update_cc_op(DisasContext *s)
  */
 static inline bool byte_reg_is_xH(DisasContext *s, int reg)
 {
-if (reg < 4) {
+/* Any time the REX prefix is present, byte registers are uniform */
+if (reg < 4 || REX_PREFIX(s)) {
 return false;
 }
-#ifdef TARGET_X86_64
-if (reg >= 8 || s->x86_64_hregs) {
-return false;
-}
-#endif
 return true;
 }
 
@@ -4559,7 +4559,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 #ifdef TARGET_X86_64
 s->rex_x = 0;
 s->rex_b = 0;
-s->x86_64_hregs = false;
 #endif
 s->rip_offset = 0; /* for relative ip address */
 s->vex_l = 0;
@@ -4614,12 +4613,11 @@ static target_ulong disas_insn(DisasContext *s, 
CPUState *cpu)
 case 0x40 ... 0x4f:
 if (CODE64(s)) {
 /* REX prefix */
+prefixes |= PREFIX_REX;
 rex_w = (b >> 3) & 1;
 rex_r = (b & 0x4) << 1;
 s->rex_x = (b & 0x2) << 2;
 REX_B(s) = (b & 0x1) << 3;
-/* select uniform byte register addressing */
-s->x86_64_hregs = true;
 goto next_byte;
 }
 break;
@@ -4643,14 +4641,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 
 /* 4.1.1-4.1.3: No preceding lock, 66, f2, f3, or rex prefixes. */
 if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ
-| PREFIX_LOCK | PREFIX_DATA)) {
+| PREFIX_LOCK | PREFIX_DATA | PREFIX_REX)) {
 goto illegal_op;
 }
-#ifdef TARGET_X86_64
-if (s->x86_64_hregs) {
-goto illegal_op;
-}
-#endif
 rex_r = (~vex2 >> 4) & 8;
 if (b == 0xc5) {
 /* 2-byte VEX prefix: Rlpp, implied 0f leading opcode byte 
*/
-- 
2.25.1




[PATCH 41/50] target/i386: Move invlpg, hlt, monitor, mwait to sysemu

2021-02-28 Thread Richard Henderson
These instructions are all privileged.

Signed-off-by: Richard Henderson 
---
 target/i386/helper.h |  8 ++--
 target/i386/tcg/helper-tcg.h |  1 +
 target/i386/tcg/misc_helper.c| 55 +---
 target/i386/tcg/sysemu/misc_helper.c | 53 +++
 target/i386/tcg/translate.c  |  4 ++
 5 files changed, 63 insertions(+), 58 deletions(-)

diff --git a/target/i386/helper.h b/target/i386/helper.h
index ebfaca66dd..ab72eba52a 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -51,7 +51,6 @@ DEF_HELPER_FLAGS_3(set_dr, TCG_CALL_NO_WG, void, env, int, tl)
 #endif /* !CONFIG_USER_ONLY */
 
 DEF_HELPER_FLAGS_2(get_dr, TCG_CALL_NO_WG, tl, env, int)
-DEF_HELPER_2(invlpg, void, env, tl)
 
 DEF_HELPER_1(sysenter, void, env)
 DEF_HELPER_2(sysexit, void, env, int)
@@ -59,9 +58,6 @@ DEF_HELPER_2(sysexit, void, env, int)
 DEF_HELPER_2(syscall, void, env, int)
 DEF_HELPER_2(sysret, void, env, int)
 #endif
-DEF_HELPER_FLAGS_2(hlt, TCG_CALL_NO_WG, noreturn, env, int)
-DEF_HELPER_FLAGS_2(monitor, TCG_CALL_NO_WG, void, env, tl)
-DEF_HELPER_FLAGS_2(mwait, TCG_CALL_NO_WG, noreturn, env, int)
 DEF_HELPER_FLAGS_2(pause, TCG_CALL_NO_WG, noreturn, env, int)
 DEF_HELPER_FLAGS_1(debug, TCG_CALL_NO_WG, noreturn, env)
 DEF_HELPER_1(reset_rf, void, env)
@@ -115,6 +111,10 @@ DEF_HELPER_2(vmsave, void, env, int)
 DEF_HELPER_1(stgi, void, env)
 DEF_HELPER_1(clgi, void, env)
 DEF_HELPER_2(invlpga, void, env, int)
+DEF_HELPER_2(invlpg, void, env, tl)
+DEF_HELPER_FLAGS_2(hlt, TCG_CALL_NO_WG, noreturn, env, int)
+DEF_HELPER_FLAGS_2(monitor, TCG_CALL_NO_WG, void, env, tl)
+DEF_HELPER_FLAGS_2(mwait, TCG_CALL_NO_WG, noreturn, env, int)
 #endif /* !CONFIG_USER_ONLY */
 
 /* x86 FPU */
diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h
index e848c3b4b9..cce350aa0b 100644
--- a/target/i386/tcg/helper-tcg.h
+++ b/target/i386/tcg/helper-tcg.h
@@ -80,6 +80,7 @@ extern const uint8_t parity_table[256];
 
 /* misc_helper.c */
 void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask);
+void do_pause(CPUX86State *env) QEMU_NORETURN;
 
 /* sysemu/svm_helper.c */
 #ifndef CONFIG_USER_ONLY
diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c
index 20bf4771e7..180bed9021 100644
--- a/target/i386/tcg/misc_helper.c
+++ b/target/i386/tcg/misc_helper.c
@@ -60,14 +60,6 @@ void helper_cpuid(CPUX86State *env)
 env->regs[R_EDX] = edx;
 }
 
-void helper_invlpg(CPUX86State *env, target_ulong addr)
-{
-X86CPU *cpu = env_archcpu(env);
-
-cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0, GETPC());
-tlb_flush_page(CPU(cpu), addr);
-}
-
 void helper_rdtsc(CPUX86State *env)
 {
 uint64_t val;
@@ -100,7 +92,7 @@ void QEMU_NORETURN helper_rdpmc(CPUX86State *env)
 raise_exception_err(env, EXCP06_ILLOP, 0);
 }
 
-static void QEMU_NORETURN do_pause(CPUX86State *env)
+void QEMU_NORETURN do_pause(CPUX86State *env)
 {
 CPUState *cs = env_cpu(env);
 
@@ -109,51 +101,6 @@ static void QEMU_NORETURN do_pause(CPUX86State *env)
 cpu_loop_exit(cs);
 }
 
-static void QEMU_NORETURN do_hlt(CPUX86State *env)
-{
-CPUState *cs = env_cpu(env);
-
-env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
-cs->halted = 1;
-cs->exception_index = EXCP_HLT;
-cpu_loop_exit(cs);
-}
-
-void QEMU_NORETURN helper_hlt(CPUX86State *env, int next_eip_addend)
-{
-cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0, GETPC());
-env->eip += next_eip_addend;
-
-do_hlt(env);
-}
-
-void helper_monitor(CPUX86State *env, target_ulong ptr)
-{
-if ((uint32_t)env->regs[R_ECX] != 0) {
-raise_exception_ra(env, EXCP0D_GPF, GETPC());
-}
-/* XXX: store address? */
-cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0, GETPC());
-}
-
-void QEMU_NORETURN helper_mwait(CPUX86State *env, int next_eip_addend)
-{
-CPUState *cs = env_cpu(env);
-
-if ((uint32_t)env->regs[R_ECX] != 0) {
-raise_exception_ra(env, EXCP0D_GPF, GETPC());
-}
-cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0, GETPC());
-env->eip += next_eip_addend;
-
-/* XXX: not complete but not completely erroneous */
-if (cs->cpu_index != 0 || CPU_NEXT(cs) != NULL) {
-do_pause(env);
-} else {
-do_hlt(env);
-}
-}
-
 void QEMU_NORETURN helper_pause(CPUX86State *env, int next_eip_addend)
 {
 cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0, GETPC());
diff --git a/target/i386/tcg/sysemu/misc_helper.c 
b/target/i386/tcg/sysemu/misc_helper.c
index ebf15e3dde..1d8b651212 100644
--- a/target/i386/tcg/sysemu/misc_helper.c
+++ b/target/i386/tcg/sysemu/misc_helper.c
@@ -434,3 +434,56 @@ void helper_rdmsr(CPUX86State *env)
 env->regs[R_EAX] = (uint32_t)(val);
 env->regs[R_EDX] = (uint32_t)(val >> 32);
 }
+
+void helper_invlpg(CPUX86State *env, target_ulong addr)
+{
+X86CPU *cpu = env_archcpu(env);
+
+cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0, 

[PATCH 16/50] target/i386: Tidy REX_B, REX_X definition

2021-02-28 Thread Richard Henderson
Change the storage from int to uint8_t since the value is in {0,8}.
For x86_64 add 0 in the macros to (1) promote the type back to int,
and (2) make the macro an rvalue.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 31b128d4fe..605b80229a 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -41,14 +41,6 @@
 #define PREFIX_VEX0x20
 #define PREFIX_REX0x40
 
-#ifdef TARGET_X86_64
-#define REX_X(s) ((s)->rex_x)
-#define REX_B(s) ((s)->rex_b)
-#else
-#define REX_X(s) 0
-#define REX_B(s) 0
-#endif
-
 #ifdef TARGET_X86_64
 # define ctztl  ctz64
 # define clztl  clz64
@@ -100,7 +92,8 @@ typedef struct DisasContext {
 #endif
 
 #ifdef TARGET_X86_64
-int rex_x, rex_b;
+uint8_t rex_x;
+uint8_t rex_b;
 #endif
 int vex_l;  /* vex vector length */
 int vex_v;  /* vex  register, without 1's complement.  */
@@ -173,8 +166,12 @@ typedef struct DisasContext {
 
 #ifdef TARGET_X86_64
 #define REX_PREFIX(S)  (((S)->prefix & PREFIX_REX) != 0)
+#define REX_X(S)   ((S)->rex_x + 0)
+#define REX_B(S)   ((S)->rex_b + 0)
 #else
 #define REX_PREFIX(S)  false
+#define REX_X(S)   0
+#define REX_B(S)   0
 #endif
 
 static void gen_eob(DisasContext *s);
@@ -4617,7 +4614,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 rex_w = (b >> 3) & 1;
 rex_r = (b & 0x4) << 1;
 s->rex_x = (b & 0x2) << 2;
-REX_B(s) = (b & 0x1) << 3;
+s->rex_b = (b & 0x1) << 3;
 goto next_byte;
 }
 break;
-- 
2.25.1




[PATCH 13/50] target/i386: Assert LMA for x86_64 user-only

2021-02-28 Thread Richard Henderson
LMA is a pre-requisite for CODE64, so there is no way to disable it
for x86_64-linux-user, and there is no way to enable it for i386.

Since we're adding an accessor macro, pull the value directly out
of flags when we're not assuming a constant.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index e7f4392d55..c8728397d0 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -99,7 +99,6 @@ typedef struct DisasContext {
 #endif
 
 #ifdef TARGET_X86_64
-int lma;/* long mode active */
 int rex_x, rex_b;
 #endif
 int vex_l;  /* vex vector length */
@@ -164,10 +163,13 @@ typedef struct DisasContext {
 #endif
 #if !defined(TARGET_X86_64)
 #define CODE64(S) false
+#define LMA(S)false
 #elif defined(CONFIG_USER_ONLY)
 #define CODE64(S) true
+#define LMA(S)true
 #else
 #define CODE64(S) (((S)->flags & HF_CS64_MASK) != 0)
+#define LMA(S)(((S)->flags & HF_LMA_MASK) != 0)
 #endif
 
 static void gen_eob(DisasContext *s);
@@ -7289,7 +7291,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 } else {
 gen_helper_sysret(cpu_env, tcg_const_i32(dflag - 1));
 /* condition codes are modified only in long mode */
-if (s->lma) {
+if (LMA(s)) {
 set_cc_op(s, CC_OP_EFLAGS);
 }
 /* TF handling for the sysret insn is different. The TF bit is
@@ -8497,6 +8499,7 @@ static void i386_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cpu)
 g_assert(CODE32(dc) == ((flags & HF_CS32_MASK) != 0));
 g_assert(CODE64(dc) == ((flags & HF_CS64_MASK) != 0));
 g_assert(SS32(dc) == ((flags & HF_SS32_MASK) != 0));
+g_assert(LMA(dc) == ((flags & HF_LMA_MASK) != 0));
 
 dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1;
 dc->f_st = 0;
@@ -8515,9 +8518,6 @@ static void i386_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cpu)
 dc->cpuid_ext3_features = env->features[FEAT_8000_0001_ECX];
 dc->cpuid_7_0_ebx_features = env->features[FEAT_7_0_EBX];
 dc->cpuid_xsave_features = env->features[FEAT_XSAVE];
-#ifdef TARGET_X86_64
-dc->lma = (flags >> HF_LMA_SHIFT) & 1;
-#endif
 dc->jmp_opt = !(dc->tf || dc->base.singlestep_enabled ||
 (flags & HF_INHIBIT_IRQ_MASK));
 /* Do not optimize repz jumps at all in icount mode, because
-- 
2.25.1




[PATCH 32/50] target/i386: Implement skinit in translate.c

2021-02-28 Thread Richard Henderson
Our sysemu implementation is a stub.  We can already intercept
instructions for vmexit, and raising #UD is trivial.

Signed-off-by: Richard Henderson 
---
 target/i386/helper.h| 1 -
 target/i386/tcg/sysemu/svm_helper.c | 7 ---
 target/i386/tcg/translate.c | 7 +++
 target/i386/tcg/user/svm_stubs.c| 4 
 4 files changed, 3 insertions(+), 16 deletions(-)

diff --git a/target/i386/helper.h b/target/i386/helper.h
index 095520f81f..7a09efd55b 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -117,7 +117,6 @@ DEF_HELPER_2(vmload, void, env, int)
 DEF_HELPER_2(vmsave, void, env, int)
 DEF_HELPER_1(stgi, void, env)
 DEF_HELPER_1(clgi, void, env)
-DEF_HELPER_1(skinit, void, env)
 DEF_HELPER_2(invlpga, void, env, int)
 
 /* x86 FPU */
diff --git a/target/i386/tcg/sysemu/svm_helper.c 
b/target/i386/tcg/sysemu/svm_helper.c
index 5b9c6f18be..ca5a781a7e 100644
--- a/target/i386/tcg/sysemu/svm_helper.c
+++ b/target/i386/tcg/sysemu/svm_helper.c
@@ -423,13 +423,6 @@ void helper_clgi(CPUX86State *env)
 env->hflags2 &= ~HF2_GIF_MASK;
 }
 
-void helper_skinit(CPUX86State *env)
-{
-cpu_svm_check_intercept_param(env, SVM_EXIT_SKINIT, 0, GETPC());
-/* XXX: not implemented */
-raise_exception(env, EXCP06_ILLOP);
-}
-
 void helper_invlpga(CPUX86State *env, int aflag)
 {
 X86CPU *cpu = env_archcpu(env);
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index cd376a2c07..92e85e1872 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -7572,10 +7572,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 || !PE(s)) {
 goto illegal_op;
 }
-gen_update_cc_op(s);
-gen_jmp_im(s, pc_start - s->cs_base);
-gen_helper_skinit(cpu_env);
-break;
+gen_svm_check_intercept(s, pc_start, SVM_EXIT_SKINIT);
+/* If not intercepted, not implemented -- raise #UD. */
+goto illegal_op;
 
 case 0xdf: /* INVLPGA */
 if (!SVME(s) || !PE(s)) {
diff --git a/target/i386/tcg/user/svm_stubs.c b/target/i386/tcg/user/svm_stubs.c
index 97528b56ad..63b37f0de6 100644
--- a/target/i386/tcg/user/svm_stubs.c
+++ b/target/i386/tcg/user/svm_stubs.c
@@ -46,10 +46,6 @@ void helper_clgi(CPUX86State *env)
 {
 }
 
-void helper_skinit(CPUX86State *env)
-{
-}
-
 void helper_invlpga(CPUX86State *env, int aflag)
 {
 }
-- 
2.25.1




[PATCH 17/50] target/i386: Move rex_r into DisasContext

2021-02-28 Thread Richard Henderson
Treat this flag exactly like we treat rex_b and rex_x.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 605b80229a..aa10d0ba99 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -92,6 +92,7 @@ typedef struct DisasContext {
 #endif
 
 #ifdef TARGET_X86_64
+uint8_t rex_r;
 uint8_t rex_x;
 uint8_t rex_b;
 #endif
@@ -166,10 +167,12 @@ typedef struct DisasContext {
 
 #ifdef TARGET_X86_64
 #define REX_PREFIX(S)  (((S)->prefix & PREFIX_REX) != 0)
+#define REX_R(S)   ((S)->rex_r + 0)
 #define REX_X(S)   ((S)->rex_x + 0)
 #define REX_B(S)   ((S)->rex_b + 0)
 #else
 #define REX_PREFIX(S)  false
+#define REX_R(S)   0
 #define REX_X(S)   0
 #define REX_B(S)   0
 #endif
@@ -3094,7 +3097,7 @@ static const struct SSEOpHelper_eppi sse_op_table7[256] = 
{
 };
 
 static void gen_sse(CPUX86State *env, DisasContext *s, int b,
-target_ulong pc_start, int rex_r)
+target_ulong pc_start)
 {
 int b1, op1_offset, op2_offset, is_xmm, val;
 int modrm, mod, rm, reg;
@@ -3164,8 +3167,9 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 
 modrm = x86_ldub_code(env, s);
 reg = ((modrm >> 3) & 7);
-if (is_xmm)
-reg |= rex_r;
+if (is_xmm) {
+reg |= REX_R(s);
+}
 mod = (modrm >> 6) & 3;
 if (sse_fn_epp == SSE_SPECIAL) {
 b |= (b1 << 8);
@@ -3699,7 +3703,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 tcg_gen_ld16u_tl(s->T0, cpu_env,
 
offsetof(CPUX86State,fpregs[rm].mmx.MMX_W(val)));
 }
-reg = ((modrm >> 3) & 7) | rex_r;
+reg = ((modrm >> 3) & 7) | REX_R(s);
 gen_op_mov_reg_v(s, ot, reg, s->T0);
 break;
 case 0x1d6: /* movq ea, xmm */
@@ -3743,7 +3747,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
  offsetof(CPUX86State, fpregs[rm].mmx));
 gen_helper_pmovmskb_mmx(s->tmp2_i32, cpu_env, s->ptr0);
 }
-reg = ((modrm >> 3) & 7) | rex_r;
+reg = ((modrm >> 3) & 7) | REX_R(s);
 tcg_gen_extu_i32_tl(cpu_regs[reg], s->tmp2_i32);
 break;
 
@@ -3755,7 +3759,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 }
 modrm = x86_ldub_code(env, s);
 rm = modrm & 7;
-reg = ((modrm >> 3) & 7) | rex_r;
+reg = ((modrm >> 3) & 7) | REX_R(s);
 mod = (modrm >> 6) & 3;
 if (b1 >= 2) {
 goto unknown_op;
@@ -3831,7 +3835,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 /* Various integer extensions at 0f 38 f[0-f].  */
 b = modrm | (b1 << 8);
 modrm = x86_ldub_code(env, s);
-reg = ((modrm >> 3) & 7) | rex_r;
+reg = ((modrm >> 3) & 7) | REX_R(s);
 
 switch (b) {
 case 0x3f0: /* crc32 Gd,Eb */
@@ -4185,7 +4189,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 b = modrm;
 modrm = x86_ldub_code(env, s);
 rm = modrm & 7;
-reg = ((modrm >> 3) & 7) | rex_r;
+reg = ((modrm >> 3) & 7) | REX_R(s);
 mod = (modrm >> 6) & 3;
 if (b1 >= 2) {
 goto unknown_op;
@@ -4205,7 +4209,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 rm = (modrm & 7) | REX_B(s);
 if (mod != 3)
 gen_lea_modrm(env, s, modrm);
-reg = ((modrm >> 3) & 7) | rex_r;
+reg = ((modrm >> 3) & 7) | REX_R(s);
 val = x86_ldub_code(env, s);
 switch (b) {
 case 0x14: /* pextrb */
@@ -4374,7 +4378,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
 /* Various integer extensions at 0f 3a f[0-f].  */
 b = modrm | (b1 << 8);
 modrm = x86_ldub_code(env, s);
-reg = ((modrm >> 3) & 7) | rex_r;
+reg = ((modrm >> 3) & 7) | REX_R(s);
 
 switch (b) {
 case 0x3f0: /* rorx Gy,Ey, Ib */
@@ -4548,12 +4552,13 @@ static target_ulong disas_insn(DisasContext *s, 
CPUState *cpu)
 MemOp ot, aflag, dflag;
 int modrm, reg, rm, mod, op, opreg, val;
 target_ulong next_eip, tval;
-int rex_w, rex_r;
+int rex_w;
 target_ulong pc_start = s->base.pc_next;
 
 s->pc_start = s->pc = pc_start;
 s->override = -1;
 #ifdef TARGET_X86_64
+s->rex_r = 0;
 s->rex_x = 0;
 s->rex_b = 0;
 #endif
@@ -4567,7 +4572,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 
 prefixes = 0;
 rex_w = -1;
-  

[PATCH 09/50] target/i386: Assert !VM86 for x86_64 user-only

2021-02-28 Thread Richard Henderson
For i386-linux-user, we can enter vm86 mode via the vm86(2) syscall.
That syscall explicitly returns to 32-bit mode, and the syscall does
not exist for a 64-bit x86_64 executable.

Since we're adding an accessor macro, pull the value directly out of
flags otherwise.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 5f24615826..0e4f34f201 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -116,7 +116,6 @@ typedef struct DisasContext {
 #endif
 int addseg; /* non zero if either DS/ES/SS have a non zero base */
 int f_st;   /* currently unused */
-int vm86;   /* vm86 mode */
 int tf; /* TF cpu flag */
 int jmp_opt; /* use direct block chaining for direct jumps */
 int repz_opt; /* optimize jumps within repz instructions */
@@ -159,6 +158,11 @@ typedef struct DisasContext {
 #define CPL(S)((S)->cpl)
 #define IOPL(S)   ((S)->iopl)
 #endif
+#if defined(CONFIG_USER_ONLY) && defined(TARGET_X86_64)
+#define VM86(S)   false
+#else
+#define VM86(S)   (((S)->flags & HF_VM_MASK) != 0)
+#endif
 
 static void gen_eob(DisasContext *s);
 static void gen_jr(DisasContext *s, TCGv dest);
@@ -631,7 +635,7 @@ static void gen_check_io(DisasContext *s, MemOp ot, 
target_ulong cur_eip,
 {
 target_ulong next_eip;
 
-if (PE(s) && (CPL(s) > IOPL(s) || s->vm86)) {
+if (PE(s) && (CPL(s) > IOPL(s) || VM86(s))) {
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 switch (ot) {
 case MO_8:
@@ -1309,7 +1313,7 @@ static bool check_cpl0(DisasContext *s)
 /* If vm86, check for iopl == 3; if not, raise #GP and return false. */
 static bool check_vm86_iopl(DisasContext *s)
 {
-if (!s->vm86 || IOPL(s) == 3) {
+if (!VM86(s) || IOPL(s) == 3) {
 return true;
 }
 gen_exception_gpf(s);
@@ -1319,7 +1323,7 @@ static bool check_vm86_iopl(DisasContext *s)
 /* Check for iopl allowing access; if not, raise #GP and return false. */
 static bool check_iopl(DisasContext *s)
 {
-if (s->vm86 ? IOPL(s) == 3 : CPL(s) <= IOPL(s)) {
+if (VM86(s) ? IOPL(s) == 3 : CPL(s) <= IOPL(s)) {
 return true;
 }
 gen_exception_gpf(s);
@@ -2359,7 +2363,7 @@ static inline void gen_op_movl_seg_T0_vm(DisasContext *s, 
X86Seg seg_reg)
call this function with seg_reg == R_CS */
 static void gen_movl_seg_T0(DisasContext *s, X86Seg seg_reg)
 {
-if (PE(s) && !s->vm86) {
+if (PE(s) && !VM86(s)) {
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 gen_helper_load_seg(cpu_env, tcg_const_i32(seg_reg), s->tmp2_i32);
 /* abort translation because the addseg value may change or
@@ -4615,7 +4619,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 0xc4: /* 3-byte VEX */
 /* VEX prefixes cannot be used except in 32-bit mode.
Otherwise the instruction is LES or LDS.  */
-if (s->code32 && !s->vm86) {
+if (s->code32 && !VM86(s)) {
 static const int pp_prefix[4] = {
 0, PREFIX_DATA, PREFIX_REPZ, PREFIX_REPNZ
 };
@@ -5119,7 +5123,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 gen_add_A0_im(s, 1 << ot);
 gen_op_ld_v(s, MO_16, s->T0, s->A0);
 do_lcall:
-if (PE(s) && !s->vm86) {
+if (PE(s) && !VM86(s)) {
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 gen_helper_lcall_protected(cpu_env, s->tmp2_i32, s->T1,
tcg_const_i32(dflag - 1),
@@ -5146,7 +5150,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 gen_add_A0_im(s, 1 << ot);
 gen_op_ld_v(s, MO_16, s->T0, s->A0);
 do_ljmp:
-if (PE(s) && !s->vm86) {
+if (PE(s) && !VM86(s)) {
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 gen_helper_ljmp_protected(cpu_env, s->tmp2_i32, s->T1,
   tcg_const_tl(s->pc - s->cs_base));
@@ -6579,7 +6583,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 0xca: /* lret im */
 val = x86_ldsw_code(env, s);
 do_lret:
-if (PE(s) && !s->vm86) {
+if (PE(s) && !VM86(s)) {
 gen_update_cc_op(s);
 gen_jmp_im(s, pc_start - s->cs_base);
 gen_helper_lret_protected(cpu_env, tcg_const_i32(dflag - 1),
@@ -6605,7 +6609,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 goto do_lret;
 case 0xcf: /* iret */
 gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET);
-if (!PE(s) || s->vm86) {
+if (!PE(s) || VM86(s)) {
 /* real mode or vm86 mode */
 if (!check_vm86_iopl(s)) {
 break;
@@ -7309,7 +7313,7 @@ static target_ulong 

[PATCH 31/50] target/i386: Assert !GUEST for user-only

2021-02-28 Thread Richard Henderson
For user-only, we do not need to check for VMM intercept.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 3779da9042..cd376a2c07 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -139,11 +139,13 @@ typedef struct DisasContext {
 #define CPL(S)3
 #define IOPL(S)   0
 #define SVME(S)   false
+#define GUEST(S)  false
 #else
 #define PE(S) (((S)->flags & HF_PE_MASK) != 0)
 #define CPL(S)((S)->cpl)
 #define IOPL(S)   ((S)->iopl)
 #define SVME(S)   (((S)->flags & HF_SVME_MASK) != 0)
+#define GUEST(S)  (((S)->flags & HF_GUEST_MASK) != 0)
 #endif
 #if defined(CONFIG_USER_ONLY) && defined(TARGET_X86_64)
 #define VM86(S)   false
@@ -677,7 +679,7 @@ static void gen_check_io(DisasContext *s, MemOp ot, 
target_ulong cur_eip,
 tcg_abort();
 }
 }
-if(s->flags & HF_GUEST_MASK) {
+if (GUEST(s)) {
 gen_update_cc_op(s);
 gen_jmp_im(s, cur_eip);
 svm_flags |= (1 << (4 + ot));
@@ -2417,8 +2419,9 @@ gen_svm_check_intercept_param(DisasContext *s, 
target_ulong pc_start,
   uint32_t type, uint64_t param)
 {
 /* no SVM activated; fast case */
-if (likely(!(s->flags & HF_GUEST_MASK)))
+if (likely(!GUEST(s))) {
 return;
+}
 gen_update_cc_op(s);
 gen_jmp_im(s, pc_start - s->cs_base);
 gen_helper_svm_check_intercept_param(cpu_env, tcg_const_i32(type),
@@ -8511,6 +8514,7 @@ static void i386_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cpu)
 g_assert(LMA(dc) == ((flags & HF_LMA_MASK) != 0));
 g_assert(ADDSEG(dc) == ((flags & HF_ADDSEG_MASK) != 0));
 g_assert(SVME(dc) == ((flags & HF_SVME_MASK) != 0));
+g_assert(GUEST(dc) == ((flags & HF_GUEST_MASK) != 0));
 
 dc->cc_op = CC_OP_DYNAMIC;
 dc->cc_op_dirty = false;
-- 
2.25.1




[PATCH 12/50] target/i386: Assert CODE64 for x86_64 user-only

2021-02-28 Thread Richard Henderson
For x86_64 user-only, there is no way to leave 64-bit mode.

Without x86_64, there is no way to enter 64-bit mode.  There is
an existing macro to aid with that; simply place it in the right
place in the ifdef chain.

Since we're adding an accessor macro, pull the value directly out
of flags when we're not assuming a constant.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index ede6e4c5cd..e7f4392d55 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -41,11 +41,9 @@
 #define PREFIX_VEX0x20
 
 #ifdef TARGET_X86_64
-#define CODE64(s) ((s)->code64)
 #define REX_X(s) ((s)->rex_x)
 #define REX_B(s) ((s)->rex_b)
 #else
-#define CODE64(s) 0
 #define REX_X(s) 0
 #define REX_B(s) 0
 #endif
@@ -102,7 +100,6 @@ typedef struct DisasContext {
 
 #ifdef TARGET_X86_64
 int lma;/* long mode active */
-int code64; /* 64 bit code segment */
 int rex_x, rex_b;
 #endif
 int vex_l;  /* vex vector length */
@@ -165,6 +162,13 @@ typedef struct DisasContext {
 #define CODE32(S) (((S)->flags & HF_CS32_MASK) != 0)
 #define SS32(S)   (((S)->flags & HF_SS32_MASK) != 0)
 #endif
+#if !defined(TARGET_X86_64)
+#define CODE64(S) false
+#elif defined(CONFIG_USER_ONLY)
+#define CODE64(S) true
+#else
+#define CODE64(S) (((S)->flags & HF_CS64_MASK) != 0)
+#endif
 
 static void gen_eob(DisasContext *s);
 static void gen_jr(DisasContext *s, TCGv dest);
@@ -8491,6 +8495,7 @@ static void i386_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cpu)
 g_assert(IOPL(dc) == iopl);
 g_assert(VM86(dc) == ((flags & HF_VM_MASK) != 0));
 g_assert(CODE32(dc) == ((flags & HF_CS32_MASK) != 0));
+g_assert(CODE64(dc) == ((flags & HF_CS64_MASK) != 0));
 g_assert(SS32(dc) == ((flags & HF_SS32_MASK) != 0));
 
 dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1;
@@ -8512,7 +8517,6 @@ static void i386_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cpu)
 dc->cpuid_xsave_features = env->features[FEAT_XSAVE];
 #ifdef TARGET_X86_64
 dc->lma = (flags >> HF_LMA_SHIFT) & 1;
-dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
 #endif
 dc->jmp_opt = !(dc->tf || dc->base.singlestep_enabled ||
 (flags & HF_INHIBIT_IRQ_MASK));
-- 
2.25.1




[PATCH 07/50] target/i386: Assert CPL is 3 for user-only

2021-02-28 Thread Richard Henderson
A user-mode executable always runs in ring 3.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 8477797798..50dc693edc 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -94,6 +94,11 @@ typedef struct DisasContext {
 target_ulong pc; /* pc = eip + cs_base */
 /* current block context */
 target_ulong cs_base; /* base of CS segment */
+
+#ifndef CONFIG_USER_ONLY
+uint8_t cpl;   /* code priv level */
+#endif
+
 int code32; /* 32 bit code segment */
 #ifdef TARGET_X86_64
 int lma;/* long mode active */
@@ -111,7 +116,6 @@ typedef struct DisasContext {
 int addseg; /* non zero if either DS/ES/SS have a non zero base */
 int f_st;   /* currently unused */
 int vm86;   /* vm86 mode */
-int cpl;
 int iopl;
 int tf; /* TF cpu flag */
 int jmp_opt; /* use direct block chaining for direct jumps */
@@ -148,8 +152,10 @@ typedef struct DisasContext {
 /* The environment in which user-only runs is constrained. */
 #ifdef CONFIG_USER_ONLY
 #define PE(S) true
+#define CPL(S)3
 #else
 #define PE(S) (((S)->flags & HF_PE_MASK) != 0)
+#define CPL(S)((S)->cpl)
 #endif
 
 static void gen_eob(DisasContext *s);
@@ -623,7 +629,7 @@ static void gen_check_io(DisasContext *s, MemOp ot, 
target_ulong cur_eip,
 {
 target_ulong next_eip;
 
-if (PE(s) && (s->cpl > s->iopl || s->vm86)) {
+if (PE(s) && (CPL(s) > s->iopl || s->vm86)) {
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 switch (ot) {
 case MO_8:
@@ -1291,7 +1297,7 @@ static void gen_exception_gpf(DisasContext *s)
 /* Check for cpl == 0; if not, raise #GP and return false. */
 static bool check_cpl0(DisasContext *s)
 {
-if (s->cpl == 0) {
+if (CPL(s) == 0) {
 return true;
 }
 gen_exception_gpf(s);
@@ -1311,7 +1317,7 @@ static bool check_vm86_iopl(DisasContext *s)
 /* Check for iopl allowing access; if not, raise #GP and return false. */
 static bool check_iopl(DisasContext *s)
 {
-if (s->vm86 ? s->iopl == 3 : s->cpl <= s->iopl) {
+if (s->vm86 ? s->iopl == 3 : CPL(s) <= s->iopl) {
 return true;
 }
 gen_exception_gpf(s);
@@ -6729,7 +6735,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF);
 if (check_vm86_iopl(s)) {
 ot = gen_pop_T0(s);
-if (s->cpl == 0) {
+if (CPL(s) == 0) {
 if (dflag != MO_16) {
 gen_helper_write_eflags(cpu_env, s->T0,
 tcg_const_i32((TF_MASK | AC_MASK |
@@ -6744,7 +6750,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
   & 0x));
 }
 } else {
-if (s->cpl <= s->iopl) {
+if (CPL(s) <= s->iopl) {
 if (dflag != MO_16) {
 gen_helper_write_eflags(cpu_env, s->T0,
 tcg_const_i32((TF_MASK |
@@ -7374,7 +7380,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 break;
 
 case 0xc8: /* monitor */
-if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) {
+if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || CPL(s) != 0) {
 goto illegal_op;
 }
 gen_update_cc_op(s);
@@ -7386,7 +7392,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 break;
 
 case 0xc9: /* mwait */
-if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) {
+if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || CPL(s) != 0) {
 goto illegal_op;
 }
 gen_update_cc_op(s);
@@ -7397,7 +7403,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 
 case 0xca: /* clac */
 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP)
-|| s->cpl != 0) {
+|| CPL(s) != 0) {
 goto illegal_op;
 }
 gen_helper_clac(cpu_env);
@@ -7407,7 +7413,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 
 case 0xcb: /* stac */
 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP)
-|| s->cpl != 0) {
+|| CPL(s) != 0) {
 goto illegal_op;
 }
 gen_helper_stac(cpu_env);
@@ -8461,19 +8467,23 @@ static void i386_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cpu)
 DisasContext *dc = container_of(dcbase, DisasContext, base);
 CPUX86State *env = cpu->env_ptr;
 uint32_t flags = dc->base.tb->flags;
+int cpl = 

[PATCH 10/50] target/i386: Assert CODE32 for x86_64 user-only

2021-02-28 Thread Richard Henderson
For user-only, CODE32 == !VM86, because we are never in real-mode.
Since we cannot enter vm86 mode for x86_64 user-only, CODE32 is
always set.

Since we're adding an accessor macro, pull the value directly out
of flags otherwise.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 0e4f34f201..d46ebc1dc2 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -100,7 +100,6 @@ typedef struct DisasContext {
 uint8_t iopl;  /* i/o priv level */
 #endif
 
-int code32; /* 32 bit code segment */
 #ifdef TARGET_X86_64
 int lma;/* long mode active */
 int code64; /* 64 bit code segment */
@@ -160,8 +159,10 @@ typedef struct DisasContext {
 #endif
 #if defined(CONFIG_USER_ONLY) && defined(TARGET_X86_64)
 #define VM86(S)   false
+#define CODE32(S) true
 #else
 #define VM86(S)   (((S)->flags & HF_VM_MASK) != 0)
+#define CODE32(S) (((S)->flags & HF_CS32_MASK) != 0)
 #endif
 
 static void gen_eob(DisasContext *s);
@@ -2370,7 +2371,7 @@ static void gen_movl_seg_T0(DisasContext *s, X86Seg 
seg_reg)
because ss32 may change. For R_SS, translation must always
stop as a special handling must be done to disable hardware
interrupts for the next instruction */
-if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS)) {
+if (seg_reg == R_SS || (CODE32(s) && seg_reg < R_FS)) {
 s->base.is_jmp = DISAS_TOO_MANY;
 }
 } else {
@@ -4619,7 +4620,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 0xc4: /* 3-byte VEX */
 /* VEX prefixes cannot be used except in 32-bit mode.
Otherwise the instruction is LES or LDS.  */
-if (s->code32 && !VM86(s)) {
+if (CODE32(s) && !VM86(s)) {
 static const int pp_prefix[4] = {
 0, PREFIX_DATA, PREFIX_REPZ, PREFIX_REPNZ
 };
@@ -4686,13 +4687,13 @@ static target_ulong disas_insn(DisasContext *s, 
CPUState *cpu)
 aflag = (prefixes & PREFIX_ADR ? MO_32 : MO_64);
 } else {
 /* In 16/32-bit mode, 0x66 selects the opposite data size.  */
-if (s->code32 ^ ((prefixes & PREFIX_DATA) != 0)) {
+if (CODE32(s) ^ ((prefixes & PREFIX_DATA) != 0)) {
 dflag = MO_32;
 } else {
 dflag = MO_16;
 }
 /* In 16/32-bit mode, 0x67 selects the opposite addressing.  */
-if (s->code32 ^ ((prefixes & PREFIX_ADR) != 0)) {
+if (CODE32(s) ^ ((prefixes & PREFIX_ADR) != 0)) {
 aflag = MO_32;
 }  else {
 aflag = MO_16;
@@ -8488,8 +8489,8 @@ static void i386_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cpu)
 g_assert(CPL(dc) == cpl);
 g_assert(IOPL(dc) == iopl);
 g_assert(VM86(dc) == ((flags & HF_VM_MASK) != 0));
+g_assert(CODE32(dc) == ((flags & HF_CS32_MASK) != 0));
 
-dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
 dc->ss32 = (flags >> HF_SS32_SHIFT) & 1;
 dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1;
 dc->f_st = 0;
-- 
2.25.1




[PATCH 03/50] target/i386: Unify code paths for IRET

2021-02-28 Thread Richard Henderson
In vm86 mode, we use the same helper as real-mode, but with
an extra check for IOPL.  All non-exceptional paths set EFLAGS.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 5703b253a1..59c1212625 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -6571,22 +6571,18 @@ static target_ulong disas_insn(DisasContext *s, 
CPUState *cpu)
 goto do_lret;
 case 0xcf: /* iret */
 gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET);
-if (!s->pe) {
-/* real mode */
-gen_helper_iret_real(cpu_env, tcg_const_i32(dflag - 1));
-set_cc_op(s, CC_OP_EFLAGS);
-} else if (s->vm86) {
-if (s->iopl != 3) {
+if (!s->pe || s->vm86) {
+/* real mode or vm86 mode */
+if (s->vm86 && s->iopl != 3) {
 gen_exception_gpf(s);
-} else {
-gen_helper_iret_real(cpu_env, tcg_const_i32(dflag - 1));
-set_cc_op(s, CC_OP_EFLAGS);
+break;
 }
+gen_helper_iret_real(cpu_env, tcg_const_i32(dflag - 1));
 } else {
 gen_helper_iret_protected(cpu_env, tcg_const_i32(dflag - 1),
   tcg_const_i32(s->pc - s->cs_base));
-set_cc_op(s, CC_OP_EFLAGS);
 }
+set_cc_op(s, CC_OP_EFLAGS);
 gen_eob(s);
 break;
 case 0xe8: /* call im */
-- 
2.25.1




[PATCH 23/50] target/i386: Reduce DisasContext.vex_[lv] to uint8_t

2021-02-28 Thread Richard Henderson
Currently, vex_l is either {0,1}; if in the future we implement
AVX-512, the max value will be 2.  In vex_v we store a register
number.  This is 0-15 for SSE, and 0-31 for AVX-512.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 79f987b2cf..3b7660a019 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -97,8 +97,8 @@ typedef struct DisasContext {
 uint8_t rex_b;
 bool rex_w;
 #endif
-int vex_l;  /* vex vector length */
-int vex_v;  /* vex  register, without 1's complement.  */
+uint8_t vex_l;  /* vex vector length */
+uint8_t vex_v;  /* vex  register, without 1's complement.  */
 CCOp cc_op;  /* current CC operation */
 bool cc_op_dirty;
 int tf; /* TF cpu flag */
-- 
2.25.1




[PATCH 06/50] target/i386: Assert PE is set for user-only

2021-02-28 Thread Richard Henderson
A user-mode executable is never in real-mode.  Since we're adding
an accessor macro, pull the value directly out of flags for sysemu.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 176c95c02b..8477797798 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -94,7 +94,6 @@ typedef struct DisasContext {
 target_ulong pc; /* pc = eip + cs_base */
 /* current block context */
 target_ulong cs_base; /* base of CS segment */
-int pe; /* protected mode */
 int code32; /* 32 bit code segment */
 #ifdef TARGET_X86_64
 int lma;/* long mode active */
@@ -146,6 +145,13 @@ typedef struct DisasContext {
 sigjmp_buf jmpbuf;
 } DisasContext;
 
+/* The environment in which user-only runs is constrained. */
+#ifdef CONFIG_USER_ONLY
+#define PE(S) true
+#else
+#define PE(S) (((S)->flags & HF_PE_MASK) != 0)
+#endif
+
 static void gen_eob(DisasContext *s);
 static void gen_jr(DisasContext *s, TCGv dest);
 static void gen_jmp(DisasContext *s, target_ulong eip);
@@ -617,7 +623,7 @@ static void gen_check_io(DisasContext *s, MemOp ot, 
target_ulong cur_eip,
 {
 target_ulong next_eip;
 
-if (s->pe && (s->cpl > s->iopl || s->vm86)) {
+if (PE(s) && (s->cpl > s->iopl || s->vm86)) {
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 switch (ot) {
 case MO_8:
@@ -2345,7 +2351,7 @@ static inline void gen_op_movl_seg_T0_vm(DisasContext *s, 
X86Seg seg_reg)
call this function with seg_reg == R_CS */
 static void gen_movl_seg_T0(DisasContext *s, X86Seg seg_reg)
 {
-if (s->pe && !s->vm86) {
+if (PE(s) && !s->vm86) {
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 gen_helper_load_seg(cpu_env, tcg_const_i32(seg_reg), s->tmp2_i32);
 /* abort translation because the addseg value may change or
@@ -5105,7 +5111,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 gen_add_A0_im(s, 1 << ot);
 gen_op_ld_v(s, MO_16, s->T0, s->A0);
 do_lcall:
-if (s->pe && !s->vm86) {
+if (PE(s) && !s->vm86) {
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 gen_helper_lcall_protected(cpu_env, s->tmp2_i32, s->T1,
tcg_const_i32(dflag - 1),
@@ -5132,7 +5138,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 gen_add_A0_im(s, 1 << ot);
 gen_op_ld_v(s, MO_16, s->T0, s->A0);
 do_ljmp:
-if (s->pe && !s->vm86) {
+if (PE(s) && !s->vm86) {
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 gen_helper_ljmp_protected(cpu_env, s->tmp2_i32, s->T1,
   tcg_const_tl(s->pc - s->cs_base));
@@ -6565,7 +6571,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 0xca: /* lret im */
 val = x86_ldsw_code(env, s);
 do_lret:
-if (s->pe && !s->vm86) {
+if (PE(s) && !s->vm86) {
 gen_update_cc_op(s);
 gen_jmp_im(s, pc_start - s->cs_base);
 gen_helper_lret_protected(cpu_env, tcg_const_i32(dflag - 1),
@@ -6591,7 +6597,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 goto do_lret;
 case 0xcf: /* iret */
 gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET);
-if (!s->pe || s->vm86) {
+if (!PE(s) || s->vm86) {
 /* real mode or vm86 mode */
 if (!check_vm86_iopl(s)) {
 break;
@@ -7230,7 +7236,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 /* For Intel SYSENTER is valid on 64-bit */
 if (CODE64(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1)
 goto illegal_op;
-if (!s->pe) {
+if (!PE(s)) {
 gen_exception_gpf(s);
 } else {
 gen_helper_sysenter(cpu_env);
@@ -7241,7 +7247,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 /* For Intel SYSEXIT is valid on 64-bit */
 if (CODE64(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1)
 goto illegal_op;
-if (!s->pe) {
+if (!PE(s)) {
 gen_exception_gpf(s);
 } else {
 gen_helper_sysexit(cpu_env, tcg_const_i32(dflag - 1));
@@ -7260,7 +7266,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 gen_eob_worker(s, false, true);
 break;
 case 0x107: /* sysret */
-if (!s->pe) {
+if (!PE(s)) {
 gen_exception_gpf(s);
 } else {
 gen_helper_sysret(cpu_env, tcg_const_i32(dflag - 1));
@@ -7295,7 +7301,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 op = (modrm >> 3) & 7;
 switch(op) {
 

[PATCH 04/50] target/i386: Split out check_vm86_iopl

2021-02-28 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 25 ++---
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 59c1212625..75ee87fe84 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -1292,6 +1292,16 @@ static bool check_cpl0(DisasContext *s)
 return false;
 }
 
+/* If vm86, check for iopl == 3; if not, raise #GP and return false. */
+static bool check_vm86_iopl(DisasContext *s)
+{
+if (!s->vm86 || s->iopl == 3) {
+return true;
+}
+gen_exception_gpf(s);
+return false;
+}
+
 /* if d == OR_TMP0, it means memory operand (address in A0) */
 static void gen_op(DisasContext *s1, int op, MemOp ot, int d)
 {
@@ -6573,8 +6583,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET);
 if (!s->pe || s->vm86) {
 /* real mode or vm86 mode */
-if (s->vm86 && s->iopl != 3) {
-gen_exception_gpf(s);
+if (!check_vm86_iopl(s)) {
 break;
 }
 gen_helper_iret_real(cpu_env, tcg_const_i32(dflag - 1));
@@ -6694,9 +6703,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 /* flags */
 case 0x9c: /* pushf */
 gen_svm_check_intercept(s, pc_start, SVM_EXIT_PUSHF);
-if (s->vm86 && s->iopl != 3) {
-gen_exception_gpf(s);
-} else {
+if (check_vm86_iopl(s)) {
 gen_update_cc_op(s);
 gen_helper_read_eflags(s->T0, cpu_env);
 gen_push_v(s, s->T0);
@@ -6704,9 +6711,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 break;
 case 0x9d: /* popf */
 gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF);
-if (s->vm86 && s->iopl != 3) {
-gen_exception_gpf(s);
-} else {
+if (check_vm86_iopl(s)) {
 ot = gen_pop_T0(s);
 if (s->cpl == 0) {
 if (dflag != MO_16) {
@@ -7066,9 +7071,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 break;
 case 0xcd: /* int N */
 val = x86_ldub_code(env, s);
-if (s->vm86 && s->iopl != 3) {
-gen_exception_gpf(s);
-} else {
+if (check_vm86_iopl(s)) {
 gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
 }
 break;
-- 
2.25.1




[PATCH 08/50] target/i386: Assert IOPL is 0 for user-only

2021-02-28 Thread Richard Henderson
On real hardware, the linux kernel has the iopl(2) syscall which
can set IOPL to 3, to allow e.g. the xserver to briefly disable
interrupts while programming the graphics card.

However, QEMU cannot and does not implement this syscall, so the
IOPL is never changed from 0.  Which means that all of the checks
vs CPL <= IOPL are false for user-only.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 50dc693edc..5f24615826 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -97,6 +97,7 @@ typedef struct DisasContext {
 
 #ifndef CONFIG_USER_ONLY
 uint8_t cpl;   /* code priv level */
+uint8_t iopl;  /* i/o priv level */
 #endif
 
 int code32; /* 32 bit code segment */
@@ -116,7 +117,6 @@ typedef struct DisasContext {
 int addseg; /* non zero if either DS/ES/SS have a non zero base */
 int f_st;   /* currently unused */
 int vm86;   /* vm86 mode */
-int iopl;
 int tf; /* TF cpu flag */
 int jmp_opt; /* use direct block chaining for direct jumps */
 int repz_opt; /* optimize jumps within repz instructions */
@@ -153,9 +153,11 @@ typedef struct DisasContext {
 #ifdef CONFIG_USER_ONLY
 #define PE(S) true
 #define CPL(S)3
+#define IOPL(S)   0
 #else
 #define PE(S) (((S)->flags & HF_PE_MASK) != 0)
 #define CPL(S)((S)->cpl)
+#define IOPL(S)   ((S)->iopl)
 #endif
 
 static void gen_eob(DisasContext *s);
@@ -629,7 +631,7 @@ static void gen_check_io(DisasContext *s, MemOp ot, 
target_ulong cur_eip,
 {
 target_ulong next_eip;
 
-if (PE(s) && (CPL(s) > s->iopl || s->vm86)) {
+if (PE(s) && (CPL(s) > IOPL(s) || s->vm86)) {
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
 switch (ot) {
 case MO_8:
@@ -1307,7 +1309,7 @@ static bool check_cpl0(DisasContext *s)
 /* If vm86, check for iopl == 3; if not, raise #GP and return false. */
 static bool check_vm86_iopl(DisasContext *s)
 {
-if (!s->vm86 || s->iopl == 3) {
+if (!s->vm86 || IOPL(s) == 3) {
 return true;
 }
 gen_exception_gpf(s);
@@ -1317,7 +1319,7 @@ static bool check_vm86_iopl(DisasContext *s)
 /* Check for iopl allowing access; if not, raise #GP and return false. */
 static bool check_iopl(DisasContext *s)
 {
-if (s->vm86 ? s->iopl == 3 : CPL(s) <= s->iopl) {
+if (s->vm86 ? IOPL(s) == 3 : CPL(s) <= IOPL(s)) {
 return true;
 }
 gen_exception_gpf(s);
@@ -6750,7 +6752,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
   & 0x));
 }
 } else {
-if (CPL(s) <= s->iopl) {
+if (CPL(s) <= IOPL(s)) {
 if (dflag != MO_16) {
 gen_helper_write_eflags(cpu_env, s->T0,
 tcg_const_i32((TF_MASK |
@@ -8468,23 +8470,25 @@ static void i386_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cpu)
 CPUX86State *env = cpu->env_ptr;
 uint32_t flags = dc->base.tb->flags;
 int cpl = (flags >> HF_CPL_SHIFT) & 3;
+int iopl = (flags >> IOPL_SHIFT) & 3;
 
 dc->cs_base = dc->base.tb->cs_base;
 dc->flags = flags;
 #ifndef CONFIG_USER_ONLY
 dc->cpl = cpl;
+dc->iopl = iopl;
 #endif
 
 /* We make some simplifying assumptions; validate they're correct. */
 g_assert(PE(dc) == ((flags & HF_PE_MASK) != 0));
 g_assert(CPL(dc) == cpl);
+g_assert(IOPL(dc) == iopl);
 
 dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
 dc->ss32 = (flags >> HF_SS32_SHIFT) & 1;
 dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1;
 dc->f_st = 0;
 dc->vm86 = (flags >> VM_SHIFT) & 1;
-dc->iopl = (flags >> IOPL_SHIFT) & 3;
 dc->tf = (flags >> TF_SHIFT) & 1;
 dc->cc_op = CC_OP_DYNAMIC;
 dc->cc_op_dirty = false;
-- 
2.25.1




[PATCH 19/50] target/i386: Remove DisasContext.f_st as unused

2021-02-28 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index deb1e43430..f4af92886f 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -101,7 +101,6 @@ typedef struct DisasContext {
 int vex_v;  /* vex  register, without 1's complement.  */
 CCOp cc_op;  /* current CC operation */
 bool cc_op_dirty;
-int f_st;   /* currently unused */
 int tf; /* TF cpu flag */
 int jmp_opt; /* use direct block chaining for direct jumps */
 int repz_opt; /* optimize jumps within repz instructions */
@@ -8501,7 +8500,6 @@ static void i386_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cpu)
 g_assert(LMA(dc) == ((flags & HF_LMA_MASK) != 0));
 g_assert(ADDSEG(dc) == ((flags & HF_ADDSEG_MASK) != 0));
 
-dc->f_st = 0;
 dc->tf = (flags >> TF_SHIFT) & 1;
 dc->cc_op = CC_OP_DYNAMIC;
 dc->cc_op_dirty = false;
-- 
2.25.1




[PATCH 01/50] target/i386: Split out gen_exception_gpf

2021-02-28 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/i386/tcg/translate.c | 68 -
 1 file changed, 37 insertions(+), 31 deletions(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 6ecbbfa6c1..6af8bd219b 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -1276,6 +1276,12 @@ static void gen_illegal_opcode(DisasContext *s)
 gen_exception(s, EXCP06_ILLOP, s->pc_start - s->cs_base);
 }
 
+/* Generate #GP for the current instruction. */
+static void gen_exception_gpf(DisasContext *s)
+{
+gen_exception(s, EXCP0D_GPF, s->pc_start - s->cs_base);
+}
+
 /* if d == OR_TMP0, it means memory operand (address in A0) */
 static void gen_op(DisasContext *s1, int op, MemOp ot, int d)
 {
@@ -4502,7 +4508,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 s->vex_l = 0;
 s->vex_v = 0;
 if (sigsetjmp(s->jmpbuf, 0) != 0) {
-gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+gen_exception_gpf(s);
 return s->pc;
 }
 
@@ -6561,7 +6567,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 set_cc_op(s, CC_OP_EFLAGS);
 } else if (s->vm86) {
 if (s->iopl != 3) {
-gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+gen_exception_gpf(s);
 } else {
 gen_helper_iret_real(cpu_env, tcg_const_i32(dflag - 1));
 set_cc_op(s, CC_OP_EFLAGS);
@@ -6683,7 +6689,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 0x9c: /* pushf */
 gen_svm_check_intercept(s, pc_start, SVM_EXIT_PUSHF);
 if (s->vm86 && s->iopl != 3) {
-gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+gen_exception_gpf(s);
 } else {
 gen_update_cc_op(s);
 gen_helper_read_eflags(s->T0, cpu_env);
@@ -6693,7 +6699,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 0x9d: /* popf */
 gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF);
 if (s->vm86 && s->iopl != 3) {
-gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+gen_exception_gpf(s);
 } else {
 ot = gen_pop_T0(s);
 if (s->cpl == 0) {
@@ -7055,7 +7061,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 0xcd: /* int N */
 val = x86_ldub_code(env, s);
 if (s->vm86 && s->iopl != 3) {
-gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+gen_exception_gpf(s);
 } else {
 gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
 }
@@ -7078,13 +7084,13 @@ static target_ulong disas_insn(DisasContext *s, 
CPUState *cpu)
 if (s->cpl <= s->iopl) {
 gen_helper_cli(cpu_env);
 } else {
-gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+gen_exception_gpf(s);
 }
 } else {
 if (s->iopl == 3) {
 gen_helper_cli(cpu_env);
 } else {
-gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+gen_exception_gpf(s);
 }
 }
 break;
@@ -7095,7 +7101,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 gen_jmp_im(s, s->pc - s->cs_base);
 gen_eob_inhibit_irq(s, true);
 } else {
-gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+gen_exception_gpf(s);
 }
 break;
 case 0x62: /* bound */
@@ -7188,7 +7194,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 0x130: /* wrmsr */
 case 0x132: /* rdmsr */
 if (s->cpl != 0) {
-gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+gen_exception_gpf(s);
 } else {
 gen_update_cc_op(s);
 gen_jmp_im(s, pc_start - s->cs_base);
@@ -7220,7 +7226,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 if (CODE64(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1)
 goto illegal_op;
 if (!s->pe) {
-gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+gen_exception_gpf(s);
 } else {
 gen_helper_sysenter(cpu_env);
 gen_eob(s);
@@ -7231,7 +7237,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 if (CODE64(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1)
 goto illegal_op;
 if (!s->pe) {
-gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+gen_exception_gpf(s);
 } else {
 gen_helper_sysexit(cpu_env, tcg_const_i32(dflag - 1));
 gen_eob(s);
@@ -7250,7 +7256,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 break;
 case 0x107: /* sysret */
 if 

[PATCH 02/50] target/i386: Split out check_cpl0

2021-02-28 Thread Richard Henderson
Split out the check for CPL != 0 and the raising of #GP.

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 6af8bd219b..5703b253a1 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -1282,6 +1282,16 @@ static void gen_exception_gpf(DisasContext *s)
 gen_exception(s, EXCP0D_GPF, s->pc_start - s->cs_base);
 }
 
+/* Check for cpl == 0; if not, raise #GP and return false. */
+static bool check_cpl0(DisasContext *s)
+{
+if (s->cpl == 0) {
+return true;
+}
+gen_exception_gpf(s);
+return false;
+}
+
 /* if d == OR_TMP0, it means memory operand (address in A0) */
 static void gen_op(DisasContext *s1, int op, MemOp ot, int d)
 {
@@ -7193,9 +7203,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 break;
 case 0x130: /* wrmsr */
 case 0x132: /* rdmsr */
-if (s->cpl != 0) {
-gen_exception_gpf(s);
-} else {
+if (check_cpl0(s)) {
 gen_update_cc_op(s);
 gen_jmp_im(s, pc_start - s->cs_base);
 if (b & 2) {
@@ -7277,9 +7285,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 gen_helper_cpuid(cpu_env);
 break;
 case 0xf4: /* hlt */
-if (s->cpl != 0) {
-gen_exception_gpf(s);
-} else {
+if (check_cpl0(s)) {
 gen_update_cc_op(s);
 gen_jmp_im(s, pc_start - s->cs_base);
 gen_helper_hlt(cpu_env, tcg_const_i32(s->pc - pc_start));
@@ -7303,9 +7309,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 2: /* lldt */
 if (!s->pe || s->vm86)
 goto illegal_op;
-if (s->cpl != 0) {
-gen_exception_gpf(s);
-} else {
+if (check_cpl0(s)) {
 gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_WRITE);
 gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
@@ -7324,9 +7328,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 case 3: /* ltr */
 if (!s->pe || s->vm86)
 goto illegal_op;
-if (s->cpl != 0) {
-gen_exception_gpf(s);
-} else {
+if (check_cpl0(s)) {
 gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_WRITE);
 gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
@@ -7440,8 +7442,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
  | PREFIX_REPZ | PREFIX_REPNZ))) {
 goto illegal_op;
 }
-if (s->cpl != 0) {
-gen_exception_gpf(s);
+if (!check_cpl0(s)) {
 break;
 }
 tcg_gen_concat_tl_i64(s->tmp1_i64, cpu_regs[R_EAX],
@@ -7457,8 +7458,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 if (!(s->flags & HF_SVME_MASK) || !s->pe) {
 goto illegal_op;
 }
-if (s->cpl != 0) {
-gen_exception_gpf(s);
+if (!check_cpl0(s)) {
 break;
 }
 gen_update_cc_op(s);
@@ -7482,8 +7482,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 if (!(s->flags & HF_SVME_MASK) || !s->pe) {
 goto illegal_op;
 }
-if (s->cpl != 0) {
-gen_exception_gpf(s);
+if (!check_cpl0(s)) {
 break;
 }
 gen_update_cc_op(s);
@@ -7495,8 +7494,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 if (!(s->flags & HF_SVME_MASK) || !s->pe) {
 goto illegal_op;
 }
-if (s->cpl != 0) {
-gen_exception_gpf(s);
+if (!check_cpl0(s)) {
 break;
 }
 gen_update_cc_op(s);
@@ -7510,8 +7508,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 || !s->pe) {
 goto illegal_op;
 }
-if (s->cpl != 0) {
-gen_exception_gpf(s);
+if (!check_cpl0(s)) {
 break;
 }
 gen_update_cc_op(s);
@@ -7524,8 +7521,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
 if (!(s->flags & HF_SVME_MASK) || !s->pe) {
 goto illegal_op;
 }
-if (s->cpl != 0) {
-gen_exception_gpf(s);
+if (!check_cpl0(s)) {
 break;
 }
 gen_update_cc_op(s);
@@ -7548,8 +7544,7 @@ static target_ulong 

[PATCH 05/50] target/i386: Split out check_iopl

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

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 75ee87fe84..176c95c02b 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -1302,6 +1302,16 @@ static bool check_vm86_iopl(DisasContext *s)
 return false;
 }
 
+/* Check for iopl allowing access; if not, raise #GP and return false. */
+static bool check_iopl(DisasContext *s)
+{
+if (s->vm86 ? s->iopl == 3 : s->cpl <= s->iopl) {
+return true;
+}
+gen_exception_gpf(s);
+return false;
+}
+
 /* if d == OR_TMP0, it means memory operand (address in A0) */
 static void gen_op(DisasContext *s1, int op, MemOp ot, int d)
 {
@@ -7089,28 +7099,16 @@ static target_ulong disas_insn(DisasContext *s, 
CPUState *cpu)
 break;
 #endif
 case 0xfa: /* cli */
-if (!s->vm86) {
-if (s->cpl <= s->iopl) {
-gen_helper_cli(cpu_env);
-} else {
-gen_exception_gpf(s);
-}
-} else {
-if (s->iopl == 3) {
-gen_helper_cli(cpu_env);
-} else {
-gen_exception_gpf(s);
-}
+if (check_iopl(s)) {
+gen_helper_cli(cpu_env);
 }
 break;
 case 0xfb: /* sti */
-if (s->vm86 ? s->iopl == 3 : s->cpl <= s->iopl) {
+if (check_iopl(s)) {
 gen_helper_sti(cpu_env);
 /* interruptions are enabled only the first insn after sti */
 gen_jmp_im(s, s->pc - s->cs_base);
 gen_eob_inhibit_irq(s, true);
-} else {
-gen_exception_gpf(s);
 }
 break;
 case 0x62: /* bound */
-- 
2.25.1




  1   2   >