[RESEND PATCH 32/32] doc: Add the SGX doc

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 docs/intel-sgx.txt | 173 +
 1 file changed, 173 insertions(+)
 create mode 100644 docs/intel-sgx.txt

diff --git a/docs/intel-sgx.txt b/docs/intel-sgx.txt
new file mode 100644
index 00..4fc3fd3564
--- /dev/null
+++ b/docs/intel-sgx.txt
@@ -0,0 +1,173 @@
+===
+Software Guard eXtensions (SGX)
+===
+
+Overview
+
+
+Intel Software Guard eXtensions (SGX) is a set of instructions and mechanisms
+for memory accesses in order to provide security accesses for sensitive
+applications and data. SGX allows an application to use it's pariticular
+address space as an *enclave*, which is a protected area provides 
confidentiality
+and integrity even in the presence of privileged malware. Accesses to the
+enclave memory area from any software not resident in the enclave are 
prevented,
+including those from privileged software.
+
+Virtual SGX
+===
+
+SGX feature is exposed to guest via SGX CPUID. Looking at SGX CPUID, we can
+report the same CPUID info to guest as on host for most of SGX CPUID. With
+reporting the same CPUID guest is able to use full capacity of SGX, and KVM
+doesn't need to emulate those info.
+
+The guest's EPC base and size are determined by Qemu, and KVM needs Qemu to
+notify such info to it before it can initialize SGX for guest.
+
+Virtual EPC
+---
+
+By default, Qemu does not assign EPC to a VM, i.e. fully enabling SGX in a VM
+requires explicit allocation of EPC to the VM. Similar to other specialized
+memory types, e.g. hugetlbfs, EPC is exposed as a memory backend. For a number
+of reasons, a EPC memory backend can only be realized via an 'sgx-epc' device.
+Standard memory backend options such as prealloc are supported by EPC.
+
+SGX EPC is enumerated through CPUID, i.e. EPC "devices" need to be realized
+prior to realizing the vCPUs themselves, which occurs long before generic
+devices are parsed and realized.  Because of this, 'sgx-epc' devices must be
+created via the dedicated -sgx-epc command, i.e. cannot be created through
+the generic -devices command.  On the plus side, this limitation means that
+EPC does not require -maxmem as EPC is not treated as {cold,hot}plugged memory.
+
+Qemu does not artificially restrict the number of EPC sections exposed to a
+guest, e.g. Qemu will happily allow you to create 64 1M EPC sections. Be aware
+that some kernels may not recognize all EPC sections, e.g. the Linux SGX driver
+is hardwired to support only 8 EPC sections.
+
+The following Qemu snippet creates two EPC sections, with 64M pre-allocated
+to the VM and an additional 28M mapped but not allocated:
+
+ -object memory-backend-epc,id=mem1,size=64M,prealloc=on \
+ -sgx-epc id=epc1,memdev=mem1 \
+ -object memory-backend-epc,id=mem2,size=28M \
+ -sgx-epc id=epc2,memdev=mem2
+
+Note:
+
+The size and location of the virtual EPC are far less restricted compared
+to physical EPC. Because physical EPC is protected via range registers,
+the size of the physical EPC must be a power of two (though software sees
+a subset of the full EPC, e.g. 92M or 128M) and the EPC must be naturally
+aligned.  KVM SGX's virtual EPC is purely a software construct and only
+requires the size and location to be page aligned. Qemu enforces the EPC
+size is a multiple of 4k and will ensure the base of the EPC is 4k aligned.
+To simplify the implementation, EPC is always located above 4g in the guest
+physical address space.
+
+Migration
+-
+
+Qemu/KVM doesn't prevent live migrating SGX VMs, although from hardware's
+perspective, SGX doesn't support live migration, since both EPC and the SGX
+key hierarchy are bound to the physical platform. However live migration
+can be supported in the sense if guest software stack can support recreating
+enclaves when it suffers sudden lose of EPC; and if guest enclaves can detect
+SGX keys being changed, and handle gracefully. For instance, when ERESUME fails
+with #PF.SGX, guest software can gracefully detect it and recreate enclaves;
+and when enclave fails to unseal sensitive information from outside, it can
+detect such error and sensitive information can be provisioned to it again.
+
+CPUID
+-
+
+Due to its myriad dependencies, SGX is currently not listed as supported
+in any of Qemu's built-in CPU configuration. To expose SGX (and SGX Launch
+Control) to a guest, you must either use `-cpu host` to pass-through the
+host CPU model, or explicitly enable SGX when using a built-in CPU model,
+e.g. via `-cpu ,+sgx` or `-cpu ,+sgx,+sgxlc`.
+
+All SGX sub-features enumerated through CPUID, e.g. SGX2, MISCSELECT,
+ATTRIBUTES, etc... can be restricted via CPUID flags. Be aware that enforcing
+restriction of MISCSELECT, ATTRIBUTES and XFRM requires intercepting ECREATE,
+i.e. may marginally reduce SGX performance in the guest. All SGX sub-features
+controlle

[RESEND PATCH 30/32] Kconfig: Add CONFIG_SGX support

2021-04-29 Thread Yang Zhong
Add new CONFIG_SGX for sgx support in the Qemu, and the Kconfig
default enable sgx in the i386 platform.

Signed-off-by: Yang Zhong 
---
 backends/meson.build |  2 +-
 default-configs/devices/i386-softmmu.mak |  1 +
 hw/i386/Kconfig  |  5 +
 hw/i386/meson.build  |  2 +-
 hw/i386/sgx-stub.c   | 13 +
 5 files changed, 21 insertions(+), 2 deletions(-)
 create mode 100644 hw/i386/sgx-stub.c

diff --git a/backends/meson.build b/backends/meson.build
index 46fd16b269..6e68945528 100644
--- a/backends/meson.build
+++ b/backends/meson.build
@@ -16,6 +16,6 @@ softmmu_ss.add(when: ['CONFIG_VHOST_USER', 'CONFIG_VIRTIO'], 
if_true: files('vho
 softmmu_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: 
files('cryptodev-vhost.c'))
 softmmu_ss.add(when: ['CONFIG_VIRTIO_CRYPTO', 'CONFIG_VHOST_CRYPTO'], if_true: 
files('cryptodev-vhost-user.c'))
 softmmu_ss.add(when: 'CONFIG_GIO', if_true: [files('dbus-vmstate.c'), gio])
-softmmu_ss.add(when: 'CONFIG_LINUX', if_true: files('hostmem-epc.c'))
+softmmu_ss.add(when: 'CONFIG_SGX', if_true: files('hostmem-epc.c'))
 
 subdir('tpm')
diff --git a/default-configs/devices/i386-softmmu.mak 
b/default-configs/devices/i386-softmmu.mak
index 84d1a2487c..598c6646df 100644
--- a/default-configs/devices/i386-softmmu.mak
+++ b/default-configs/devices/i386-softmmu.mak
@@ -22,6 +22,7 @@
 #CONFIG_TPM_CRB=n
 #CONFIG_TPM_TIS_ISA=n
 #CONFIG_VTD=n
+#CONFIG_SGX=n
 
 # Boards:
 #
diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
index 7f91f30877..581526be44 100644
--- a/hw/i386/Kconfig
+++ b/hw/i386/Kconfig
@@ -2,6 +2,10 @@ config SEV
 bool
 depends on KVM
 
+config SGX
+bool
+depends on KVM
+
 config PC
 bool
 imply APPLESMC
@@ -17,6 +21,7 @@ config PC
 imply PVPANIC_ISA
 imply QXL
 imply SEV
+imply SGX
 imply SGA
 imply TEST_DEVICES
 imply TPM_CRB
diff --git a/hw/i386/meson.build b/hw/i386/meson.build
index 087426c75c..f79f1bafab 100644
--- a/hw/i386/meson.build
+++ b/hw/i386/meson.build
@@ -5,7 +5,6 @@ i386_ss.add(files(
   'e820_memory_layout.c',
   'multiboot.c',
   'x86.c',
-  'sgx-epc.c',
 ))
 
 i386_ss.add(when: 'CONFIG_X86_IOMMU', if_true: files('x86-iommu.c'),
@@ -17,6 +16,7 @@ i386_ss.add(when: 'CONFIG_Q35', if_true: files('pc_q35.c'))
 i386_ss.add(when: 'CONFIG_VMMOUSE', if_true: files('vmmouse.c'))
 i386_ss.add(when: 'CONFIG_VMPORT', if_true: files('vmport.c'))
 i386_ss.add(when: 'CONFIG_VTD', if_true: files('intel_iommu.c'))
+i386_ss.add(when: 'CONFIG_SGX', if_true: files('sgx-epc.c'), if_false: 
files('sgx-stub.c'))
 
 i386_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-common.c'))
 i386_ss.add(when: 'CONFIG_ACPI_HW_REDUCED', if_true: 
files('generic_event_device_x86.c'))
diff --git a/hw/i386/sgx-stub.c b/hw/i386/sgx-stub.c
new file mode 100644
index 00..edf17c3309
--- /dev/null
+++ b/hw/i386/sgx-stub.c
@@ -0,0 +1,13 @@
+#include "qemu/osdep.h"
+#include "hw/i386/pc.h"
+#include "hw/i386/sgx-epc.h"
+
+void pc_machine_init_sgx_epc(PCMachineState *pcms)
+{
+return;
+}
+
+int sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size)
+{
+return 1;
+}
-- 
2.29.2.334.gfaefdd61ec




Re: [RFC PATCH v2 2/4] hw/arm/virt: Parse -smp cluster parameter in virt_smp_parse

2021-04-29 Thread Andrew Jones
On Fri, Apr 30, 2021 at 01:09:00PM +0800, wangyanan (Y) wrote:
> Hi Drew,
> 
> On 2021/4/29 19:02, Andrew Jones wrote:
> > On Thu, Apr 29, 2021 at 04:56:06PM +0800, wangyanan (Y) wrote:
> > > On 2021/4/29 15:16, Andrew Jones wrote:
> > > > On Thu, Apr 29, 2021 at 10:14:37AM +0800, wangyanan (Y) wrote:
> > > > > On 2021/4/28 18:31, Andrew Jones wrote:
> > > > > > On Tue, Apr 13, 2021 at 04:31:45PM +0800, Yanan Wang wrote:
> > > > > > > } else if (sockets == 0) {
> > > > > > > threads = threads > 0 ? threads : 1;
> > > > > > > -sockets = cpus / (cores * threads);
> > > > > > > +sockets = cpus / (clusters * cores * threads);
> > > > > > > sockets = sockets > 0 ? sockets : 1;
> > > > > > If we initialize clusters to zero instead of one and add lines in
> > > > > > 'cpus == 0 || cores == 0' and 'sockets == 0' like
> > > > > > 'clusters = clusters > 0 ? clusters : 1' as needed, then I think we 
> > > > > > can
> > > > > > add
> > > > > > 
> > > > > > } else if (clusters == 0) {
> > > > > > threads = threads > 0 ? threads : 1;
> > > > > > clusters = cpus / (sockets * cores * thread);
> > > > > > clusters = clusters > 0 ? clusters : 1;
> > > > > > }
> > > > > > 
> > > > > > here.
> > > > > I have thought about this kind of format before, but there is a 
> > > > > little bit
> > > > > difference between these two ways. Let's chose the better and more
> > > > > reasonable one of the two.
> > > > > 
> > > > > Way A currently in this patch:
> > > > > If value of clusters is not explicitly specified in -smp command 
> > > > > line, we
> > > > > assume
> > > > > that users don't want to support clusters, for compatibility we 
> > > > > initialized
> > > > > the
> > > > > value to 1. So that with cmdline "-smp cpus=24, sockets=2, cores=6", 
> > > > > we will
> > > > > parse out the topology description like below:
> > > > > cpus=24, sockets=2, clusters=1, cores=6, threads=2
> > > > > 
> > > > > Way B that you suggested for this patch:
> > > > > Whether value of clusters is explicitly specified in -smp command 
> > > > > line or
> > > > > not,
> > > > > we assume that clusters are supported and calculate the value. So 
> > > > > that with
> > > > > cmdline "-smp cpus=24, sockets=2, cores=6", we will parse out the 
> > > > > topology
> > > > > description like below:
> > > > > cpus =24, sockets=2, clusters=2, cores=6, threads=1
> > > > > 
> > > > > But I think maybe we should not assume too much about what users think
> > > > > through the -smp command line. We should just assume that all levels 
> > > > > of
> > > > > cpu topology are supported and calculate them, and users should be 
> > > > > more
> > > > > careful if they want to get the expected results with not so complete
> > > > > cmdline.
> > > > > If I'm right, then Way B should be better. :)
> > > > > 
> > > > Hi Yanan,
> > > > 
> > > > We're already assuming the user wants to describe clusters to the guest
> > > > because we require at least one per socket. If we want the user to have 
> > > > a
> > > > choice between using clusters or not, then I guess we need to change the
> > > > logic in the PPTT and the cpu-map to only generate the cluster level 
> > > > when
> > > > the number of clusters is not zero. And then change this parser to not
> > > > require clusters at all.
> > > Hi Drew,
> > > 
> > > I think this kind of change will introduce more complexity and actually is
> > > not necessary.
> > > Not generating cluster level at all and generating cluster level (one per
> > > socket) are same
> > > to kernel. Without cluster description provided, kernel will initialize 
> > > all
> > > cores in the same
> > > cluster which also means one cluster per socket.
> > Which kernel? All kernels? One without the cluster support patches [1]?
> > 
> > [1] 
> > https://lore.kernel.org/lkml/20210420001844.9116-1-song.bao@hisilicon.com/#t
> I'm sorry, I didn't make it clear. :)
> I actually mean the ARM64 kernel, with or without [1].
> 
> Without [1]: Kernel doesn't care about cluster. When populating cpu
> topology, it directly
> finds the hierarchy node with "physical package flag" as package when
> parsing ACPI, and
> finds the core node's parent as package when parsing DT. So even we provide
> cluster level
> description (one per socket), the parsing results will be the same as not
> providing at all.
> 
> With [1]: Kernel finds the core hierarchy node's parent as cluster when
> parsing ACPI. So if
> we don't provide cluster level description, package will be taken as
> cluster. And if we provide
> the description (one per socket), the parsing result will also be the same.
> 
> That's why I said that we just need to provide description of cluster (one
> per socket) if we
> don't want to make use of it in VMs.

OK, that sounds good.

> 
> [1] 
> https://lore.kernel.org/lkml/20210420001844.9116-1-song.bao@hisilicon.com/#t
> > > So we should only ensure value of c

[RESEND PATCH 31/32] sgx-epc: Add the fill_device_info() callback support

2021-04-29 Thread Yang Zhong
Since there is no fill_device_info() callback support, and when we
execute "info memory-devices" command in the monitor, the segfault
will be found.

This patch will add this callback support and "info memory-devices"
will show sgx epc memory exposed to guest. The result as below:

qemu) info memory-devices
Memory device [sgx-epc]: "epc1"
  memaddr: 0x18000
  size: 29360128
  memdev: /objects/mem1
Memory device [sgx-epc]: "epc2"
  memaddr: 0x181c0
  size: 10485760
  memdev: /objects/mem2

Signed-off-by: Yang Zhong 
---
 hw/i386/sgx-epc.c  | 17 -
 monitor/hmp-cmds.c | 10 ++
 qapi/machine.json  | 26 +-
 3 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/hw/i386/sgx-epc.c b/hw/i386/sgx-epc.c
index 0995956f99..f9ebc8ab7f 100644
--- a/hw/i386/sgx-epc.c
+++ b/hw/i386/sgx-epc.c
@@ -208,7 +208,22 @@ static MemoryRegion 
*sgx_epc_md_get_memory_region(MemoryDeviceState *md,
 static void sgx_epc_md_fill_device_info(const MemoryDeviceState *md,
 MemoryDeviceInfo *info)
 {
-/* TODO */
+SgxEPCDeviceInfo *se = g_new0(SgxEPCDeviceInfo, 1);
+SGXEPCDevice *epc = SGX_EPC(md);
+const DeviceState *dev = DEVICE(md);
+
+if (dev->id) {
+se->has_id = true;
+se->id = g_strdup(dev->id);
+}
+
+se->memaddr = epc->addr;
+se->size = object_property_get_uint(OBJECT(epc), SGX_EPC_SIZE_PROP,
+NULL);
+se->memdev = object_get_canonical_path(OBJECT(epc->hostmem));
+
+info->u.sgx_epc.data = se;
+info->type = MEMORY_DEVICE_INFO_KIND_SGX_EPC;
 }
 
 static void sgx_epc_class_init(ObjectClass *oc, void *data)
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index bd539e0c1e..974892e73d 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -1819,6 +1819,7 @@ void hmp_info_memory_devices(Monitor *mon, const QDict 
*qdict)
 VirtioMEMDeviceInfo *vmi;
 MemoryDeviceInfo *value;
 PCDIMMDeviceInfo *di;
+SgxEPCDeviceInfo *se;
 
 for (info = info_list; info; info = info->next) {
 value = info->value;
@@ -1866,6 +1867,15 @@ void hmp_info_memory_devices(Monitor *mon, const QDict 
*qdict)
vmi->block_size);
 monitor_printf(mon, "  memdev: %s\n", vmi->memdev);
 break;
+case MEMORY_DEVICE_INFO_KIND_SGX_EPC:
+se = value->u.sgx_epc.data;
+monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
+   MemoryDeviceInfoKind_str(value->type),
+   se->id ? se->id : "");
+monitor_printf(mon, "  memaddr: 0x%" PRIx64 "\n", se->memaddr);
+monitor_printf(mon, "  size: %" PRIu64 "\n", se->size);
+monitor_printf(mon, "  memdev: %s\n", se->memdev);
+break;
 default:
 g_assert_not_reached();
 }
diff --git a/qapi/machine.json b/qapi/machine.json
index 6e90d463fc..3f2c2da92f 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -1184,6 +1184,29 @@
   }
 }
 
+##
+# @SgxEPCDeviceInfo:
+#
+# Sgx EPC state information
+#
+# @id: device's ID
+#
+# @memaddr: physical address in memory, where device is mapped
+#
+# @size: size of memory that the device provides
+#
+# @memdev: memory backend linked with device
+#
+# Since: 5.1
+##
+{ 'struct': 'SgxEPCDeviceInfo',
+  'data': { '*id': 'str',
+'memaddr': 'size',
+'size': 'size',
+'memdev': 'str'
+  }
+}
+
 ##
 # @MemoryDeviceInfo:
 #
@@ -1198,7 +1221,8 @@
   'data': { 'dimm': 'PCDIMMDeviceInfo',
 'nvdimm': 'PCDIMMDeviceInfo',
 'virtio-pmem': 'VirtioPMEMDeviceInfo',
-'virtio-mem': 'VirtioMEMDeviceInfo'
+'virtio-mem': 'VirtioMEMDeviceInfo',
+'sgx-epc': 'SgxEPCDeviceInfo'
   }
 }
 
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 28/32] bitops: Support 32 and 64 bit mask macro

2021-04-29 Thread Yang Zhong
The Qemu should enable bit mask macro like Linux did in the
kernel, the GENMASK(h, l) and GENMASK_ULL(h, l) will set the
bit to 1 from l to h bit in the 32 bit or 64 bit long type.

Signed-off-by: Yang Zhong 
---
 include/qemu/bitops.h | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
index 3acbf3384c..8678c8dcd5 100644
--- a/include/qemu/bitops.h
+++ b/include/qemu/bitops.h
@@ -18,6 +18,7 @@
 
 #define BITS_PER_BYTE   CHAR_BIT
 #define BITS_PER_LONG   (sizeof (unsigned long) * BITS_PER_BYTE)
+#define BITS_PER_LONG_LONG   64
 
 #define BIT(nr) (1UL << (nr))
 #define BIT_ULL(nr) (1ULL << (nr))
@@ -28,6 +29,12 @@
 #define MAKE_64BIT_MASK(shift, length) \
 (((~0ULL) >> (64 - (length))) << (shift))
 
+#define GENMASK(h, l) \
+(((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h
+
+#define GENMASK_ULL(h, l) \
+(((~0ULL) << (l)) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h
+
 /**
  * set_bit - Set a bit in memory
  * @nr: the bit to set
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 29/32] qmp: Add the qmp_query_sgx_capabilities()

2021-04-29 Thread Yang Zhong
The libvirt can use qmp_query_sgx_capabilities() to get the host
sgx capabilitis.

Signed-off-by: Yang Zhong 
---
 hw/i386/sgx-epc.c  | 66 ++
 include/hw/i386/pc.h   |  1 +
 monitor/qmp-cmds.c |  5 +++
 qapi/misc.json | 19 +++
 stubs/sgx-stub.c   |  5 +++
 tests/qtest/qmp-cmd-test.c |  1 +
 6 files changed, 97 insertions(+)

diff --git a/hw/i386/sgx-epc.c b/hw/i386/sgx-epc.c
index 7daea0613b..0995956f99 100644
--- a/hw/i386/sgx-epc.c
+++ b/hw/i386/sgx-epc.c
@@ -27,6 +27,14 @@
 
 uint32_t epc_num;
 
+#define SGX_MAX_EPC_SECTIONS8
+#define SGX_CPUID_EPC_INVALID   0x0
+
+/* A valid EPC section. */
+#define SGX_CPUID_EPC_SECTION   0x1
+
+#define SGX_CPUID_EPC_MASK  GENMASK(3, 0)
+
 static Property sgx_epc_properties[] = {
 DEFINE_PROP_UINT64(SGX_EPC_ADDR_PROP, SGXEPCDevice, addr, 0),
 DEFINE_PROP_LINK(SGX_EPC_MEMDEV_PROP, SGXEPCDevice, hostmem,
@@ -344,6 +352,64 @@ SGXInfo *sgx_get_info(void)
 return info;
 }
 
+static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high)
+{
+return (low & GENMASK_ULL(31, 12)) +
+   ((high & GENMASK_ULL(19, 0)) << 32);
+}
+
+static uint64_t sgx_calc_host_epc_section_size(void)
+{
+uint32_t i, type;
+uint32_t eax, ebx, ecx, edx;
+uint64_t size = 0;
+
+for (i = 0; i < SGX_MAX_EPC_SECTIONS; i++) {
+host_cpuid(0x12, i + 2, &eax, &ebx, &ecx, &edx);
+
+type = eax & SGX_CPUID_EPC_MASK;
+if (type == SGX_CPUID_EPC_INVALID) {
+break;
+}
+
+if (type != SGX_CPUID_EPC_SECTION) {
+break;
+}
+
+size += sgx_calc_section_metric(ecx, edx);
+}
+
+return size;
+}
+
+SGXInfo *sgx_get_capabilities(Error **errp)
+{
+SGXInfo *info = NULL;
+uint32_t eax, ebx, ecx, edx;
+
+int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
+if (fd < 0) {
+error_setg(errp, "SGX is not enabled in KVM");
+return NULL;
+}
+
+info = g_new0(SGXInfo, 1);
+host_cpuid(0x7, 0, &eax, &ebx, &ecx, &edx);
+
+info->sgx = ebx & (1U << 2) ? true : false;
+info->flc = ecx & (1U << 30) ? true : false;
+
+host_cpuid(0x12, 0, &eax, &ebx, &ecx, &edx);
+info->sgx1 = eax & (1U << 0) ? true : false;
+info->sgx2 = eax & (1U << 1) ? true : false;
+
+info->section_size = sgx_calc_host_epc_section_size();
+
+close(fd);
+
+return info;
+}
+
 static QemuOptsList sgx_epc_opts = {
 .name = "sgx-epc",
 .implied_opt_name = "id",
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index cb74298117..a66795da0f 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -205,6 +205,7 @@ void pc_machine_init_sgx_epc(PCMachineState *pcms);
 void sgx_memory_backend_reset(HostMemoryBackend *backend, int fd,
   Error **errp);
 SGXInfo *sgx_get_info(void);
+SGXInfo *sgx_get_capabilities(Error **errp);
 
 extern GlobalProperty pc_compat_5_2[];
 extern const size_t pc_compat_5_2_len;
diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c
index 48f7708ffe..f1360e9f4e 100644
--- a/monitor/qmp-cmds.c
+++ b/monitor/qmp-cmds.c
@@ -365,3 +365,8 @@ SGXInfo *qmp_query_sgx(Error **errp)
 
 return info;
 }
+
+SGXInfo *qmp_query_sgx_capabilities(Error **errp)
+{
+return sgx_get_capabilities(errp);
+}
diff --git a/qapi/misc.json b/qapi/misc.json
index 112a2f71cf..3f50b42d37 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -561,3 +561,22 @@
 #
 ##
 { 'command': 'query-sgx', 'returns': 'SGXInfo' }
+
+
+##
+# @query-sgx-capabilities:
+#
+# Returns information from host SGX capabilities
+#
+# Returns: @SGXInfo
+#
+# Since: 5.1
+#
+# Example:
+#
+# -> { "execute": "query-sgx-capabilities" }
+# <- { "return": { "sgx": true, "sgx1" : true, "sgx2" : true,
+#  "flc": true, "section-size" : 0 } }
+#
+##
+{ 'command': 'query-sgx-capabilities', 'returns': 'SGXInfo' }
diff --git a/stubs/sgx-stub.c b/stubs/sgx-stub.c
index c2b59a88fd..1dedf3f3db 100644
--- a/stubs/sgx-stub.c
+++ b/stubs/sgx-stub.c
@@ -5,3 +5,8 @@ SGXInfo *sgx_get_info(void)
 {
 return NULL;
 }
+
+SGXInfo *sgx_get_capabilities(Error **errp)
+{
+return NULL;
+}
diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c
index b75f3364f3..1af2f74c28 100644
--- a/tests/qtest/qmp-cmd-test.c
+++ b/tests/qtest/qmp-cmd-test.c
@@ -101,6 +101,7 @@ static bool query_is_ignored(const char *cmd)
 "query-sev",
 "query-sev-capabilities",
 "query-sgx",
+"query-sgx-capabilities",
 NULL
 };
 int i;
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 24/32] sgx-epc: Add the reset interface for sgx-epc virt device

2021-04-29 Thread Yang Zhong
If the VM is reset, we need make sure sgx virt epc in clean status.
Once the VM is reset, and sgx epc virt device will be reseted by
reset callback registered by qemu_register_reset(). Since this epc
virt device depend on backend, this reset will call backend reset
interface to re-mmap epc to guest.

Signed-off-by: Yang Zhong 
---
 hw/i386/sgx-epc.c | 94 ---
 1 file changed, 81 insertions(+), 13 deletions(-)

diff --git a/hw/i386/sgx-epc.c b/hw/i386/sgx-epc.c
index d5ba7bb68c..fbacec6e00 100644
--- a/hw/i386/sgx-epc.c
+++ b/hw/i386/sgx-epc.c
@@ -23,6 +23,9 @@
 #include "qemu/units.h"
 #include "target/i386/cpu.h"
 #include "exec/address-spaces.h"
+#include "sysemu/reset.h"
+
+uint32_t epc_num;
 
 static Property sgx_epc_properties[] = {
 DEFINE_PROP_UINT64(SGX_EPC_ADDR_PROP, SGXEPCDevice, addr, 0),
@@ -52,12 +55,84 @@ static void sgx_epc_init(Object *obj)
 NULL, NULL, NULL);
 }
 
+static void sgx_epc_del_subregion(DeviceState *dev)
+{
+PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
+SGXEPCState *sgx_epc = pcms->sgx_epc;
+SGXEPCDevice *epc = SGX_EPC(dev);
+
+/* del subregion and related operations */
+memory_region_del_subregion(&sgx_epc->mr,
+host_memory_backend_get_memory(epc->hostmem));
+host_memory_backend_set_mapped(epc->hostmem, false);
+g_free(sgx_epc->sections);
+sgx_epc->sections = NULL;
+
+/* multiple epc devices, only zero the first time */
+if (epc_num == sgx_epc->nr_sections) {
+sgx_epc->size = 0;
+sgx_epc->nr_sections = 0;
+}
+}
+
+static void sgx_epc_initialization(DeviceState *dev)
+{
+PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
+SGXEPCState *sgx_epc = pcms->sgx_epc;
+MemoryDeviceState *md = MEMORY_DEVICE(dev);
+SGXEPCDevice *epc = SGX_EPC(dev);
+Error *errp = NULL;
+
+if (!epc->hostmem) {
+error_setg(&errp, "'" SGX_EPC_MEMDEV_PROP "' property is not set");
+return;
+}
+
+epc->addr = sgx_epc->base + sgx_epc->size;
+
+memory_region_add_subregion(&sgx_epc->mr, epc->addr - sgx_epc->base,
+host_memory_backend_get_memory(epc->hostmem));
+
+host_memory_backend_set_mapped(epc->hostmem, true);
+
+sgx_epc->sections = g_renew(SGXEPCDevice *, sgx_epc->sections,
+sgx_epc->nr_sections + 1);
+sgx_epc->sections[sgx_epc->nr_sections++] = epc;
+
+sgx_epc->size += memory_device_get_region_size(md, &errp);
+}
+
+static void sgx_epc_reset(void *opaque)
+{
+DeviceState *dev = opaque;
+SGXEPCDevice *epc = SGX_EPC(dev);
+Error *errp = NULL;
+int fd;
+
+if (!epc->hostmem) {
+error_setg(&errp, "'" SGX_EPC_MEMDEV_PROP "' property is not set");
+return;
+}
+
+/* delete subregion and related operations */
+sgx_epc_del_subregion(dev);
+
+/* reset sgx backend */
+fd = memory_region_get_fd(host_memory_backend_get_memory(epc->hostmem));
+sgx_memory_backend_reset(epc->hostmem, fd, &errp);
+if (errp) {
+error_setg(&errp, "failed to call sgx_memory_backend_reset");
+return;
+}
+
+/* re-add subregion and related operations */
+sgx_epc_initialization(dev);
+}
+
 static void sgx_epc_realize(DeviceState *dev, Error **errp)
 {
 PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
 X86MachineState *x86ms = X86_MACHINE(pcms);
-MemoryDeviceState *md = MEMORY_DEVICE(dev);
-SGXEPCState *sgx_epc = pcms->sgx_epc;
 SGXEPCDevice *epc = SGX_EPC(dev);
 const char *path;
 
@@ -76,18 +151,11 @@ static void sgx_epc_realize(DeviceState *dev, Error **errp)
 return;
 }
 
-epc->addr = sgx_epc->base + sgx_epc->size;
-
-memory_region_add_subregion(&sgx_epc->mr, epc->addr - sgx_epc->base,
-host_memory_backend_get_memory(epc->hostmem));
-
-host_memory_backend_set_mapped(epc->hostmem, true);
-
-sgx_epc->sections = g_renew(SGXEPCDevice *, sgx_epc->sections,
-sgx_epc->nr_sections + 1);
-sgx_epc->sections[sgx_epc->nr_sections++] = epc;
+sgx_epc_initialization(dev);
+epc_num++;
 
-sgx_epc->size += memory_device_get_region_size(md, errp);
+/* register the reset callback for sgx reset */
+qemu_register_reset(sgx_epc_reset, dev);
 }
 
 static void sgx_epc_unrealize(DeviceState *dev)
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 27/32] i386: Add sgx_get_info() interface

2021-04-29 Thread Yang Zhong
Add the sgx_get_info() interface for hmp and QMP usage, which
will get the SGX info from this API.

Signed-off-by: Yang Zhong 
---
 hw/i386/sgx-epc.c | 22 ++
 include/hw/i386/pc.h  |  1 +
 include/hw/i386/sgx-epc.h |  1 +
 monitor/hmp-cmds.c| 20 ++--
 monitor/qmp-cmds.c| 12 ++--
 stubs/meson.build |  1 +
 stubs/sgx-stub.c  |  7 +++
 7 files changed, 60 insertions(+), 4 deletions(-)
 create mode 100644 stubs/sgx-stub.c

diff --git a/hw/i386/sgx-epc.c b/hw/i386/sgx-epc.c
index fbacec6e00..7daea0613b 100644
--- a/hw/i386/sgx-epc.c
+++ b/hw/i386/sgx-epc.c
@@ -322,6 +322,28 @@ void pc_machine_init_sgx_epc(PCMachineState *pcms)
 memory_region_set_size(&sgx_epc->mr, sgx_epc->size);
 }
 
+SGXInfo *sgx_get_info(void)
+{
+SGXInfo *info;
+
+info = g_new0(SGXInfo, 1);
+if (sgx_epc_enabled) {
+PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
+SGXEPCState *sgx_epc = pcms->sgx_epc;
+
+info->sgx = true;
+info->sgx1 = true;
+info->sgx2 = true;
+info->flc = true;
+
+if (sgx_epc) {
+info->section_size = sgx_epc->size;
+}
+}
+
+return info;
+}
+
 static QemuOptsList sgx_epc_opts = {
 .name = "sgx-epc",
 .implied_opt_name = "id",
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 44b8c5d271..cb74298117 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -204,6 +204,7 @@ void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
 void pc_machine_init_sgx_epc(PCMachineState *pcms);
 void sgx_memory_backend_reset(HostMemoryBackend *backend, int fd,
   Error **errp);
+SGXInfo *sgx_get_info(void);
 
 extern GlobalProperty pc_compat_5_2[];
 extern const size_t pc_compat_5_2_len;
diff --git a/include/hw/i386/sgx-epc.h b/include/hw/i386/sgx-epc.h
index 743d0a943c..30a1c61b60 100644
--- a/include/hw/i386/sgx-epc.h
+++ b/include/hw/i386/sgx-epc.h
@@ -13,6 +13,7 @@
 #define QEMU_SGX_EPC_H
 
 #include "sysemu/hostmem.h"
+#include "qapi/qapi-types-misc.h"
 
 #define TYPE_SGX_EPC "sgx-epc"
 #define SGX_EPC(obj) \
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 1d1efca713..bd539e0c1e 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -2229,6 +2229,22 @@ void hmp_info_memory_size_summary(Monitor *mon, const 
QDict *qdict)
 
 void hmp_info_sgx(Monitor *mon, const QDict *qdict)
 {
-error_setg(errp, QERR_FEATURE_DISABLED, "query-sgx");
-return NULL;
+SGXInfo *info = qmp_query_sgx(NULL);
+
+if (info && info->sgx) {
+monitor_printf(mon, "SGX support: %s\n",
+   info->sgx ? "enabled" : "disabled");
+monitor_printf(mon, "SGX1 support: %s\n",
+   info->sgx1 ? "enabled" : "disabled");
+monitor_printf(mon, "SGX2 support: %s\n",
+   info->sgx2 ? "enabled" : "disabled");
+monitor_printf(mon, "FLC support: %s\n",
+   info->flc ? "enabled" : "disabled");
+monitor_printf(mon, "size: %" PRIu64 "\n",
+   info->section_size);
+} else {
+monitor_printf(mon, "SGX is not enabled\n");
+}
+
+qapi_free_SGXInfo(info);
 }
diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c
index d63d59149f..48f7708ffe 100644
--- a/monitor/qmp-cmds.c
+++ b/monitor/qmp-cmds.c
@@ -40,6 +40,7 @@
 #include "qapi/qmp/qerror.h"
 #include "hw/mem/memory-device.h"
 #include "hw/acpi/acpi_dev_interface.h"
+#include "hw/i386/pc.h"
 
 NameInfo *qmp_query_name(Error **errp)
 {
@@ -354,6 +355,13 @@ void qmp_display_reload(DisplayReloadOptions *arg, Error 
**errp)
 
 SGXInfo *qmp_query_sgx(Error **errp)
 {
-error_setg(errp, QERR_FEATURE_DISABLED, "query-sgx");
-return NULL;
+SGXInfo *info;
+
+info = sgx_get_info();
+if (!info) {
+error_setg(errp, "SGX features are not available");
+return NULL;
+}
+
+return info;
 }
diff --git a/stubs/meson.build b/stubs/meson.build
index be6f6d609e..1cba20a9a8 100644
--- a/stubs/meson.build
+++ b/stubs/meson.build
@@ -54,3 +54,4 @@ if have_system
 else
   stub_ss.add(files('qdev.c'))
 endif
+stub_ss.add(files('sgx-stub.c'))
diff --git a/stubs/sgx-stub.c b/stubs/sgx-stub.c
new file mode 100644
index 00..c2b59a88fd
--- /dev/null
+++ b/stubs/sgx-stub.c
@@ -0,0 +1,7 @@
+#include "qemu/osdep.h"
+#include "hw/i386/pc.h"
+
+SGXInfo *sgx_get_info(void)
+{
+return NULL;
+}
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 26/32] hmp: Add 'info sgx' command

2021-04-29 Thread Yang Zhong
The command can be used to show the SGX information in the monitor
when SGX is enabled on intel platform.

Signed-off-by: Yang Zhong 
---
 hmp-commands-info.hx  | 15 +++
 include/monitor/hmp.h |  1 +
 monitor/hmp-cmds.c|  6 ++
 3 files changed, 22 insertions(+)

diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index ab0c7aa5ee..20fbca18cd 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -880,3 +880,18 @@ SRST
   ``info replay``
 Display the record/replay information: mode and the current icount.
 ERST
+
+#if defined(TARGET_I386)
+{
+.name   = "sgx",
+.args_type  = "",
+.params = "",
+.help   = "show intel SGX information",
+.cmd= hmp_info_sgx,
+},
+#endif
+
+SRST
+  ``info sgx``
+Show intel SGX information.
+ERST
diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h
index 605d57287a..a65cf71100 100644
--- a/include/monitor/hmp.h
+++ b/include/monitor/hmp.h
@@ -129,5 +129,6 @@ void hmp_info_replay(Monitor *mon, const QDict *qdict);
 void hmp_replay_break(Monitor *mon, const QDict *qdict);
 void hmp_replay_delete_break(Monitor *mon, const QDict *qdict);
 void hmp_replay_seek(Monitor *mon, const QDict *qdict);
+void hmp_info_sgx(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 0ad5b77477..1d1efca713 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -2226,3 +2226,9 @@ void hmp_info_memory_size_summary(Monitor *mon, const 
QDict *qdict)
 }
 hmp_handle_error(mon, err);
 }
+
+void hmp_info_sgx(Monitor *mon, const QDict *qdict)
+{
+error_setg(errp, QERR_FEATURE_DISABLED, "query-sgx");
+return NULL;
+}
-- 
2.29.2.334.gfaefdd61ec




Re: Let's remove some deprecated stuff

2021-04-29 Thread Markus Armbruster
Daniel P. Berrangé  writes:

> On Thu, Apr 29, 2021 at 11:59:41AM +0200, Markus Armbruster wrote:
>> Myself, but I only documented it; it's actually Kevin Wolf:
>> 
>> ``blockdev-open-tray``, ``blockdev-close-tray`` argument ``device`` 
>> (since 2.8.0)
>> 
>> '
>> 
>> Use argument ``id`` instead.
>> 
>> ``eject`` argument ``device`` (since 2.8.0)
>> '''
>> 
>> Use argument ``id`` instead.
>> 
>> ``blockdev-change-medium`` argument ``device`` (since 2.8.0)
>> 
>> 
>> Use argument ``id`` instead.
>> 
>> ``block_set_io_throttle`` argument ``device`` (since 2.8.0)
>> '''
>> 
>> Use argument ``id`` instead.
>
> FYI, I did prepare patches for these already, but they broke the iotests.
>
> I found it difficult to figure out the right fix for the iotests, becuase
> IIUC "device" and "id" values are different, and I didn't see what "id"
> to use when args are still using -drive, not -blockdev.

Rebase and post as RFC to solicit clues or even fixes?

[...]




[RESEND PATCH 23/32] hostmem: Add the reset interface for EPC backend reset

2021-04-29 Thread Yang Zhong
Add the sgx_memory_backend_reset() interface to handle EPC backend
reset when VM is reset. This reset function will destroy previous
backend memory region and re-mmap the EPC section for guest.

Signed-off-by: Yang Zhong 
---
 backends/hostmem-epc.c | 16 
 include/hw/i386/pc.h   |  2 ++
 2 files changed, 18 insertions(+)

diff --git a/backends/hostmem-epc.c b/backends/hostmem-epc.c
index f267cf9f91..f12f26d39f 100644
--- a/backends/hostmem-epc.c
+++ b/backends/hostmem-epc.c
@@ -16,6 +16,7 @@
 #include "qom/object_interfaces.h"
 #include "qapi/error.h"
 #include "sysemu/hostmem.h"
+#include "hw/i386/pc.h"
 
 #define TYPE_MEMORY_BACKEND_EPC "memory-backend-epc"
 
@@ -53,6 +54,21 @@ sgx_epc_backend_memory_alloc(HostMemoryBackend *backend, 
Error **errp)
 g_free(name);
 }
 
+void sgx_memory_backend_reset(HostMemoryBackend *backend, int fd,
+  Error **errp)
+{
+MemoryRegion *mr = &backend->mr;
+
+mr->enabled = false;
+
+/* destroy the old memory region if it exist */
+if (fd > 0 && mr->destructor) {
+mr->destructor(mr);
+}
+
+sgx_epc_backend_memory_alloc(backend, errp);
+}
+
 static void sgx_epc_backend_instance_init(Object *obj)
 {
 HostMemoryBackend *m = MEMORY_BACKEND(obj);
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 71e2fc6f26..44b8c5d271 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -202,6 +202,8 @@ void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
 
 /* sgx-epc.c */
 void pc_machine_init_sgx_epc(PCMachineState *pcms);
+void sgx_memory_backend_reset(HostMemoryBackend *backend, int fd,
+  Error **errp);
 
 extern GlobalProperty pc_compat_5_2[];
 extern const size_t pc_compat_5_2_len;
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 20/32] i386: acpi: Add SGX EPC entry to ACPI tables

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

The ACPI Device entry for SGX EPC is essentially a hack whose primary
purpose is to provide software with a way to autoprobe SGX support,
e.g. to allow software to implement SGX support as a driver.  Details
on the individual EPC sections are not enumerated through ACPI tables,
i.e. software must enumerate the EPC sections via CPUID.  Furthermore,
software expects to see only a single EPC Device in the ACPI tables
regardless of the number of EPC sections in the system.

However, several versions of Windows do rely on the ACPI tables to
enumerate the address and size of the EPC.  So, regardless of the number
of EPC sections exposed to the guest, create exactly *one* EPC device
with a _CRS entry that spans the entirety of all EPC sections (which are
guaranteed to be contiguous in Qemu).

Note, NUMA support for EPC memory is intentionally not considered as
enumerating EPC NUMA information is not yet defined for bare metal.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 hw/i386/acpi-build.c | 22 ++
 1 file changed, 22 insertions(+)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index de98750aef..cbcf6ba740 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1801,6 +1801,28 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
 aml_append(sb_scope, dev);
 }
 
+if (pcms->sgx_epc) {
+uint64_t epc_base = pcms->sgx_epc->base;
+uint64_t epc_size = pcms->sgx_epc->size;
+
+dev = aml_device("EPC");
+aml_append(dev, aml_name_decl("_HID", aml_eisaid("INT0E0C")));
+aml_append(dev, aml_name_decl("_STR",
+  aml_unicode("Enclave Page Cache 1.0")));
+crs = aml_resource_template();
+aml_append(crs,
+   aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED,
+AML_MAX_FIXED, AML_NON_CACHEABLE,
+AML_READ_WRITE, 0, epc_base,
+epc_base + epc_size - 1, 0, epc_size));
+aml_append(dev, aml_name_decl("_CRS", crs));
+
+method = aml_method("_STA", 0, AML_NOTSERIALIZED);
+aml_append(method, aml_return(aml_int(0x0f)));
+aml_append(dev, method);
+
+aml_append(sb_scope, dev);
+}
 aml_append(dsdt, sb_scope);
 
 /* copy AML table into ACPI tables blob and patch header there */
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 21/32] q35: Add support for SGX EPC

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

Enable SGX EPC virtualization, which is currently only support by KVM.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 hw/i386/pc_q35.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 53450190f5..e7af29a94b 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -177,6 +177,9 @@ static void pc_q35_init(MachineState *machine)
 x86ms->below_4g_mem_size = machine->ram_size;
 }
 
+if (sgx_epc_enabled) {
+pc_machine_init_sgx_epc(pcms);
+}
 x86_cpus_init(x86ms, pcmc->default_cpu_version);
 
 kvmclock_create(pcmc->kvmclock_create_always);
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 15/32] i386: Propagate SGX CPUID sub-leafs to KVM

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

The SGX sub-leafs are enumerated at CPUID 0x12.  Indices 0 and 1 are
always present when SGX is supported, and enumerate SGX features and
capabilities.  Indices >=2 are directly correlated with the platform's
EPC sections.  Because the number of EPC sections is dynamic and user
defined, the number of SGX sub-leafs is "NULL" terminated.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 target/i386/kvm/kvm.c | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index c2fba39bd4..ecb5f56d95 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -1615,6 +1615,25 @@ int kvm_arch_init_vcpu(CPUState *cs)
 }
 break;
 case 0x7:
+case 0x12:
+for (j = 0; ; j++) {
+c->function = i;
+c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+c->index = j;
+cpu_x86_cpuid(env, i, j, &c->eax, &c->ebx, &c->ecx, &c->edx);
+
+if (j > 1 && (c->eax & 0xf) != 1) {
+break;
+}
+
+if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
+fprintf(stderr, "cpuid_data is full, no space for "
+"cpuid(eax:0x12,ecx:0x%x)\n", j);
+abort();
+}
+c = &cpuid_data.entries[cpuid_i++];
+}
+break;
 case 0x14: {
 uint32_t times;
 
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 12/32] i386: Update SGX CPUID info according to hardware/KVM/user input

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

Expose SGX to the guest if and only if KVM is enabled and supports
virtualization of SGX.  While the majority of ENCLS can be emulated to
some degree, because SGX uses a hardware-based root of trust, the
attestation aspects of SGX cannot be emulated in software, i.e.
ultimately emulation will fail as software cannot generate a valid
quote/report.  The complexity of partially emulating SGX in Qemu far
outweighs the value added, e.g. an SGX specific simulator for userspace
applications can emulate SGX for development and testing purposes.

Note, access to the PROVISIONKEY is not yet advertised to the guest as
KVM blocks access to the PROVISIONKEY by default and requires userspace
to provide additional credentials (via ioctl()) to expose PROVISIONKEY.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 hw/i386/sgx-epc.c | 17 +
 include/hw/i386/sgx-epc.h |  2 +
 target/i386/cpu.c | 77 +++
 3 files changed, 96 insertions(+)

diff --git a/hw/i386/sgx-epc.c b/hw/i386/sgx-epc.c
index 0858819a71..d5ba7bb68c 100644
--- a/hw/i386/sgx-epc.c
+++ b/hw/i386/sgx-epc.c
@@ -173,6 +173,23 @@ static void sgx_epc_register_types(void)
 
 type_init(sgx_epc_register_types)
 
+int sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size)
+{
+PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
+SGXEPCDevice *epc;
+
+if (pcms->sgx_epc == NULL || pcms->sgx_epc->nr_sections <= section_nr) {
+return 1;
+}
+
+epc = pcms->sgx_epc->sections[section_nr];
+
+*addr = epc->addr;
+*size = memory_device_get_region_size(MEMORY_DEVICE(epc), &error_fatal);
+
+return 0;
+}
+
 
 static int sgx_epc_set_property(void *opaque, const char *name,
 const char *value, Error **errp)
diff --git a/include/hw/i386/sgx-epc.h b/include/hw/i386/sgx-epc.h
index 1f7dd17c17..8d80b34fb7 100644
--- a/include/hw/i386/sgx-epc.h
+++ b/include/hw/i386/sgx-epc.h
@@ -57,4 +57,6 @@ typedef struct SGXEPCState {
 
 extern int sgx_epc_enabled;
 
+int sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size);
+
 #endif
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 43e6fdf162..e630e57f03 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -60,6 +60,7 @@
 #include "exec/address-spaces.h"
 #include "hw/i386/apic_internal.h"
 #include "hw/boards.h"
+#include "hw/i386/sgx-epc.h"
 #endif
 
 #include "disas/capstone.h"
@@ -5807,6 +5808,25 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, 
uint32_t count,
 *ecx |= CPUID_7_0_ECX_OSPKE;
 }
 *edx = env->features[FEAT_7_0_EDX]; /* Feature flags */
+
+/*
+ * SGX cannot be emulated in software.  If hardware does not
+ * support enabling SGX and/or SGX flexible launch control,
+ * then we need to update the VM's CPUID values accordingly.
+ */
+if ((*ebx & CPUID_7_0_EBX_SGX) &&
+(!kvm_enabled() ||
+ !(kvm_arch_get_supported_cpuid(cs->kvm_state, 0x7, 0, R_EBX) &
+CPUID_7_0_EBX_SGX))) {
+*ebx &= ~CPUID_7_0_EBX_SGX;
+}
+
+if ((*ecx & CPUID_7_0_ECX_SGX_LC) &&
+(!(*ebx & CPUID_7_0_EBX_SGX) || !kvm_enabled() ||
+ !(kvm_arch_get_supported_cpuid(cs->kvm_state, 0x7, 0, R_ECX) &
+CPUID_7_0_ECX_SGX_LC))) {
+*ecx &= ~CPUID_7_0_ECX_SGX_LC;
+}
 } else if (count == 1) {
 *eax = env->features[FEAT_7_1_EAX];
 *ebx = 0;
@@ -5942,6 +5962,63 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, 
uint32_t count,
 }
 break;
 }
+case 0x12:
+#ifndef CONFIG_USER_ONLY
+if (!kvm_enabled() ||
+!(env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_SGX)) {
+*eax = *ebx = *ecx = *edx = 0;
+break;
+}
+
+/*
+ * SGX sub-leafs CPUID.0x12.{0x2..N} enumerate EPC sections.  Retrieve
+ * the EPC properties, e.g. confidentiality and integrity, from the
+ * host's first EPC section, i.e. assume there is one EPC section or
+ * that all EPC sections have the same security properties.
+ */
+if (count > 1) {
+uint64_t epc_addr, epc_size;
+
+if (sgx_epc_get_section(count - 2, &epc_addr, &epc_size)) {
+*eax = *ebx = *ecx = *edx = 0;
+break;
+}
+host_cpuid(index, 2, eax, ebx, ecx, edx);
+*eax = (uint32_t)(epc_addr & 0xf000) | 0x1;
+*ebx = (uint32_t)(epc_addr >> 32);
+*ecx = (uint32_t)(epc_size & 0xf000) | (*ecx & 0xf);
+*edx = (uint32_t)(epc_size >> 32);
+break;
+}
+
+/*
+ * SGX sub-leafs CPUID.0x12.{0x0,0x1} are heavily dependent on hardware
+ * and KVM, i.e. QE

[RESEND PATCH 18/32] hw/i386/pc: Account for SGX EPC sections when calculating device memory

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

Add helpers to detect if SGX EPC exists above 4g, and if so, where SGX
EPC above 4g ends.  Use the helpers to adjust the device memory range
if SGX EPC exists above 4g.

For multiple virtual EPC sections, we just put them together physically
contiguous for the simplicity because we don't support EPC NUMA affinity
now. Once the SGX EPC NUMA support in the kernel SGX driver, we will
support this in the future.

Note that SGX EPC is currently hardcoded to reside above 4g.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 hw/i386/pc.c  | 11 ++-
 include/hw/i386/sgx-epc.h |  7 +++
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 8a84b25a03..90585a2471 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -925,8 +925,15 @@ void pc_memory_init(PCMachineState *pcms,
 exit(EXIT_FAILURE);
 }
 
+if (pcms->sgx_epc != NULL) {
+machine->device_memory->base = sgx_epc_above_4g_end(pcms->sgx_epc);
+} else {
+machine->device_memory->base =
+0x1ULL + x86ms->above_4g_mem_size;
+}
+
 machine->device_memory->base =
-ROUND_UP(0x1ULL + x86ms->above_4g_mem_size, 1 * GiB);
+ROUND_UP(machine->device_memory->base, 1 * GiB);
 
 if (pcmc->enforce_aligned_dimm) {
 /* size device region assuming 1G page max alignment per slot */
@@ -1011,6 +1018,8 @@ uint64_t pc_pci_hole64_start(void)
 if (!pcmc->broken_reserved_end) {
 hole64_start += memory_region_size(&ms->device_memory->mr);
 }
+} else if (pcms->sgx_epc != NULL) {
+hole64_start = sgx_epc_above_4g_end(pcms->sgx_epc);
 } else {
 hole64_start = 0x1ULL + x86ms->above_4g_mem_size;
 }
diff --git a/include/hw/i386/sgx-epc.h b/include/hw/i386/sgx-epc.h
index 8d80b34fb7..743d0a943c 100644
--- a/include/hw/i386/sgx-epc.h
+++ b/include/hw/i386/sgx-epc.h
@@ -59,4 +59,11 @@ extern int sgx_epc_enabled;
 
 int sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size);
 
+static inline uint64_t sgx_epc_above_4g_end(SGXEPCState *sgx_epc)
+{
+assert(sgx_epc != NULL && sgx_epc->base >= 0x1ULL);
+
+return sgx_epc->base + sgx_epc->size;
+}
+
 #endif
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 14/32] i386: kvm: Add support for exposing PROVISIONKEY to guest

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

If the guest want to fully use SGX, the guest needs to be able to
access provisioning key. Add a new KVM_CAP_SGX_ATTRIBUTE to KVM to
support provisioning key to KVM guests.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 target/i386/cpu.c  |  5 -
 target/i386/kvm/kvm.c  | 29 +
 target/i386/kvm/kvm_i386.h |  2 ++
 3 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index e630e57f03..63253bf606 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -6015,7 +6015,10 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, 
uint32_t count,
 *ecx |= XSTATE_FP_MASK | XSTATE_SSE_MASK;
 
 /* Access to PROVISIONKEY requires additional credentials. */
-*eax &= ~(1U << 4);
+if ((*eax & (1U << 4)) &&
+!kvm_enable_sgx_provisioning(cs->kvm_state)) {
+*eax &= ~(1U << 4);
+}
 }
 #endif
 break;
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index fa495a6f9e..c2fba39bd4 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -4555,6 +4555,35 @@ void kvm_arch_update_guest_debug(CPUState *cpu, struct 
kvm_guest_debug *dbg)
 }
 }
 
+static bool has_sgx_provisioning;
+
+static bool __kvm_enable_sgx_provisioning(KVMState *s)
+{
+int fd, ret;
+
+if (!kvm_vm_check_extension(s, KVM_CAP_SGX_ATTRIBUTE)) {
+return false;
+}
+
+fd = qemu_open_old("/dev/sgx_provision", O_RDONLY);
+if (fd < 0) {
+return false;
+}
+
+ret = kvm_vm_enable_cap(s, KVM_CAP_SGX_ATTRIBUTE, 0, fd);
+if (ret) {
+error_report("Could not enable SGX PROVISIONKEY: %s", strerror(-ret));
+exit(1);
+}
+close(fd);
+return true;
+}
+
+bool kvm_enable_sgx_provisioning(KVMState *s)
+{
+return MEMORIZE(__kvm_enable_sgx_provisioning(s), has_sgx_provisioning);
+}
+
 static bool host_supports_vmx(void)
 {
 uint32_t ecx, unused;
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index dc72508389..7bab91aecb 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -50,4 +50,6 @@ bool kvm_hv_vpindex_settable(void);
 
 uint64_t kvm_swizzle_msi_ext_dest_id(uint64_t address);
 
+bool kvm_enable_sgx_provisioning(KVMState *s);
+
 #endif
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 16/32] Adjust min CPUID level to 0x12 when SGX is enabled

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

SGX capabilities are enumerated through CPUID_0x12.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 target/i386/cpu.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 63253bf606..41050960c5 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -6741,6 +6741,11 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error 
**errp)
 if (sev_enabled()) {
 x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel, 0x801F);
 }
+
+/* SGX requires CPUID[0x12] for EPC enumeration */
+if (env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_SGX) {
+x86_cpu_adjust_level(cpu, &env->cpuid_min_level, 0x12);
+}
 }
 
 /* Set cpuid_*level* based on cpuid_min_*level, if not explicitly set */
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 09/32] i386: Add SGX CPUID leaf FEAT_SGX_12_1_EAX

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

CPUID leaf 12_1_EAX is an Intel-defined feature bits leaf enumerating
the platform's SGX capabilities that may be utilized by an enclave, e.g.
whether or not an enclave can gain access to the provision key.
Currently there are six capabilities:

  - INIT: set when the enclave has has been initialized by EINIT.  Cannot
  be set by software, i.e. forced to zero in CPUID.
  - DEBUG: permits a debugger to read/write into the enclave.
  - MODE64BIT: the enclave runs in 64-bit mode
  - PROVISIONKEY: grants has access to the provision key
  - EINITTOKENKEY: grants access to the EINIT token key, i.e. the
   enclave can generate EINIT tokens
  - KSS: Key Separation and Sharing enabled for the enclave.

Note that the entirety of CPUID.0x12.0x1, i.e. all registers, enumerates
the allowed ATTRIBUTES (128 bits), but only bits 31:0 are directly
exposed to the user (via FEAT_12_1_EAX).  Bits 63:32 are currently all
reserved and bits 127:64 correspond to the allowed XSAVE Feature Request
Mask, which is calculated based on other CPU features, e.g. XSAVE, MPX,
AVX, etc... and is not exposed to the user.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 target/i386/cpu.c | 21 +
 target/i386/cpu.h |  1 +
 2 files changed, 22 insertions(+)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index e723f52e22..ec12e12a33 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -678,6 +678,7 @@ static void x86_cpu_vendor_words2str(char *dst, uint32_t 
vendor1,
 #define TCG_14_0_ECX_FEATURES 0
 #define TCG_SGX_12_0_EAX_FEATURES 0
 #define TCG_SGX_12_0_EBX_FEATURES 0
+#define TCG_SGX_12_1_EAX_FEATURES 0
 
 typedef enum FeatureWordType {
CPUID_FEATURE_WORD,
@@ -1366,6 +1367,26 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] 
= {
 },
 .tcg_features = TCG_SGX_12_0_EBX_FEATURES,
 },
+
+[FEAT_SGX_12_1_EAX] = {
+.type = CPUID_FEATURE_WORD,
+.feat_names = {
+NULL, "sgx-debug", "sgx-mode64", NULL,
+"sgx-provisionkey", "sgx-tokenkey", NULL, "sgx-kss",
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+},
+.cpuid = {
+.eax = 0x12,
+.needs_ecx = true, .ecx = 1,
+.reg = R_EAX,
+},
+.tcg_features = TCG_SGX_12_1_EAX_FEATURES,
+},
 };
 
 typedef struct FeatureMask {
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index a3c91d5848..9df748119f 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -551,6 +551,7 @@ typedef enum FeatureWord {
 FEAT_14_0_ECX,
 FEAT_SGX_12_0_EAX,  /* CPUID[EAX=0x12,ECX=0].EAX (SGX) */
 FEAT_SGX_12_0_EBX,  /* CPUID[EAX=0x12,ECX=0].EBX (SGX MISCSELECT[31:0]) */
+FEAT_SGX_12_1_EAX,  /* CPUID[EAX=0x12,ECX=1].EAX (SGX ATTRIBUTES[31:0]) */
 FEATURE_WORDS,
 } FeatureWord;
 
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 13/32] linux-headers: Add placeholder for KVM_CAP_SGX_ATTRIBUTE

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

KVM_CAP_SGX_ATTRIBUTE is a proposed capability for Intel SGX that can be
used by userspace to enable privileged attributes, e.g. access to the
PROVISIONKEY.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 linux-headers/linux/kvm.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 020b62a619..0961b03007 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -1056,6 +1056,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_ENFORCE_PV_FEATURE_CPUID 190
 #define KVM_CAP_SYS_HYPERV_CPUID 191
 #define KVM_CAP_DIRTY_LOG_RING 192
+#define KVM_CAP_SGX_ATTRIBUTE 195
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 25/32] qmp: Add query-sgx command

2021-04-29 Thread Yang Zhong
This QMP query command can be used by some userspaces to retrieve
the SGX information when SGX is enabled on Intel platform.

Signed-off-by: Yang Zhong 
---
 monitor/qmp-cmds.c |  6 ++
 qapi/misc.json | 42 ++
 tests/qtest/qmp-cmd-test.c |  1 +
 3 files changed, 49 insertions(+)

diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c
index f7d64a6457..d63d59149f 100644
--- a/monitor/qmp-cmds.c
+++ b/monitor/qmp-cmds.c
@@ -351,3 +351,9 @@ void qmp_display_reload(DisplayReloadOptions *arg, Error 
**errp)
 abort();
 }
 }
+
+SGXInfo *qmp_query_sgx(Error **errp)
+{
+error_setg(errp, QERR_FEATURE_DISABLED, "query-sgx");
+return NULL;
+}
diff --git a/qapi/misc.json b/qapi/misc.json
index 156f98203e..112a2f71cf 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -519,3 +519,45 @@
  'data': { '*option': 'str' },
  'returns': ['CommandLineOptionInfo'],
  'allow-preconfig': true }
+
+##
+# @SGXInfo:
+#
+# Information about intel Safe Guard eXtension (SGX) support
+#
+# @sgx: true if SGX is support
+#
+# @sgx1: true if SGX1 is support
+#
+# @sgx2: true if SGX2 is support
+#
+# @flc: true if FLC is support
+#
+# @section-size: The EPC section size for guest
+#
+# Since: 5.1
+##
+{ 'struct': 'SGXInfo',
+  'data': { 'sgx': 'bool',
+'sgx1': 'bool',
+'sgx2': 'bool',
+'flc': 'bool',
+'section-size': 'uint64'}}
+
+##
+# @query-sgx:
+#
+# Returns information about SGX
+#
+# Returns: @SGXInfo
+#
+# Since: 5.1
+#
+# Example:
+#
+# -> { "execute": "query-sgx" }
+# <- { "return": { "sgx": true, "sgx1" : true, "sgx2" : true,
+#  "flc": true, "section-size" : 0 } }
+#
+##
+{ 'command': 'query-sgx', 'returns': 'SGXInfo' }
diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c
index c98b78d033..b75f3364f3 100644
--- a/tests/qtest/qmp-cmd-test.c
+++ b/tests/qtest/qmp-cmd-test.c
@@ -100,6 +100,7 @@ static bool query_is_ignored(const char *cmd)
 /* Success depends on Host or Hypervisor SEV support */
 "query-sev",
 "query-sev-capabilities",
+"query-sgx",
 NULL
 };
 int i;
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 17/32] hw/i386/fw_cfg: Set SGX bits in feature control fw_cfg accordingly

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

Request SGX an SGX Launch Control to be enabled in FEATURE_CONTROL
when the features are exposed to the guest. Our design is the SGX
Launch Control bit will be unconditionally set in FEATURE_CONTROL,
which is unlike host bios.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 hw/i386/fw_cfg.c | 10 +-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c
index e48a54fa36..ec99743c22 100644
--- a/hw/i386/fw_cfg.c
+++ b/hw/i386/fw_cfg.c
@@ -157,7 +157,7 @@ void fw_cfg_build_feature_control(MachineState *ms, 
FWCfgState *fw_cfg)
 {
 X86CPU *cpu = X86_CPU(ms->possible_cpus->cpus[0].cpu);
 CPUX86State *env = &cpu->env;
-uint32_t unused, ecx, edx;
+uint32_t unused, ebx, ecx, edx;
 uint64_t feature_control_bits = 0;
 uint64_t *val;
 
@@ -172,6 +172,14 @@ void fw_cfg_build_feature_control(MachineState *ms, 
FWCfgState *fw_cfg)
 feature_control_bits |= FEATURE_CONTROL_LMCE;
 }
 
+cpu_x86_cpuid(env, 0x7, 0, &unused, &ebx, &ecx, &unused);
+if (ebx & CPUID_7_0_EBX_SGX) {
+feature_control_bits |= FEATURE_CONTROL_SGX;
+}
+if (ecx & CPUID_7_0_ECX_SGX_LC) {
+feature_control_bits |= FEATURE_CONTROL_SGX_LC;
+}
+
 if (!feature_control_bits) {
 return;
 }
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 08/32] i386: Add SGX CPUID leaf FEAT_SGX_12_0_EBX

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

CPUID leaf 12_0_EBX is an Intel-defined feature bits leaf enumerating
the platform's SGX extended capabilities.  Currently there is a single
capabilitiy:

  - EXINFO: record information about #PFs and #GPs in the enclave's SSA

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 target/i386/cpu.c | 21 +
 target/i386/cpu.h |  1 +
 2 files changed, 22 insertions(+)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 5443f69fa5..e723f52e22 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -677,6 +677,7 @@ static void x86_cpu_vendor_words2str(char *dst, uint32_t 
vendor1,
   CPUID_XSAVE_XSAVEC, CPUID_XSAVE_XSAVES */
 #define TCG_14_0_ECX_FEATURES 0
 #define TCG_SGX_12_0_EAX_FEATURES 0
+#define TCG_SGX_12_0_EBX_FEATURES 0
 
 typedef enum FeatureWordType {
CPUID_FEATURE_WORD,
@@ -1345,6 +1346,26 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] 
= {
 },
 .tcg_features = TCG_SGX_12_0_EAX_FEATURES,
 },
+
+[FEAT_SGX_12_0_EBX] = {
+.type = CPUID_FEATURE_WORD,
+.feat_names = {
+"sgx-exinfo" , NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+},
+.cpuid = {
+.eax = 0x12,
+.needs_ecx = true, .ecx = 0,
+.reg = R_EBX,
+},
+.tcg_features = TCG_SGX_12_0_EBX_FEATURES,
+},
 };
 
 typedef struct FeatureMask {
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 7aba71a982..a3c91d5848 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -550,6 +550,7 @@ typedef enum FeatureWord {
 FEAT_VMX_VMFUNC,
 FEAT_14_0_ECX,
 FEAT_SGX_12_0_EAX,  /* CPUID[EAX=0x12,ECX=0].EAX (SGX) */
+FEAT_SGX_12_0_EBX,  /* CPUID[EAX=0x12,ECX=0].EBX (SGX MISCSELECT[31:0]) */
 FEATURE_WORDS,
 } FeatureWord;
 
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 10/32] i386: Add get/set/migrate support for SGX_LEPUBKEYHASH MSRs

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

On real hardware, on systems that supports SGX Launch Control, those
MSRs are initialized to digest of Intel's signing key; on systems that
don't support SGX Launch Control, those MSRs are not available but
hardware always uses digest of Intel's signing key in EINIT.

KVM advertises SGX LC via CPUID if and only if the MSRs are writable.
Unconditionally initialize those MSRs to digest of Intel's signing key
when CPU is realized and reset to reflect the fact. This avoids
potential bug in case kvm_arch_put_registers() is called before
kvm_arch_get_registers() is called, in which case guest's virtual
SGX_LEPUBKEYHASH MSRs will be set to 0, although KVM initializes those
to digest of Intel's signing key by default, since KVM allows those MSRs
to be updated by Qemu to support live migration.

Save/restore the SGX Launch Enclave Public Key Hash MSRs if SGX Launch
Control (LC) is exposed to the guest. Likewise, migrate the MSRs if they
are writable by the guest.

Signed-off-by: Sean Christopherson 
Signed-off-by: Kai Huang 
Signed-off-by: Yang Zhong 
---
 target/i386/cpu.c | 17 -
 target/i386/cpu.h |  1 +
 target/i386/kvm/kvm.c | 22 ++
 target/i386/machine.c | 20 
 4 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index ec12e12a33..43e6fdf162 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -6179,6 +6179,16 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, 
uint32_t count,
 }
 }
 
+#ifndef CONFIG_USER_ONLY
+static void x86_cpu_set_sgxlepubkeyhash(CPUX86State *env)
+{
+env->msr_ia32_sgxlepubkeyhash[0] = 0xa6053e051270b7acULL;
+env->msr_ia32_sgxlepubkeyhash[1] = 0x6cfbe8ba8b3b413dULL;
+env->msr_ia32_sgxlepubkeyhash[2] = 0xc4916d99f2b3735dULL;
+env->msr_ia32_sgxlepubkeyhash[3] = 0xd4f8c05909f9bb3bULL;
+}
+#endif
+
 static void x86_cpu_reset(DeviceState *dev)
 {
 CPUState *s = CPU(dev);
@@ -6310,6 +6320,8 @@ static void x86_cpu_reset(DeviceState *dev)
 if (kvm_enabled()) {
 kvm_arch_reset_vcpu(cpu);
 }
+
+x86_cpu_set_sgxlepubkeyhash(env);
 #endif
 }
 
@@ -6922,6 +6934,10 @@ static void x86_cpu_realizefn(DeviceState *dev, Error 
**errp)
 /* Process Hyper-V enlightenments */
 x86_cpu_hyperv_realize(cpu);
 
+#ifndef CONFIG_USER_ONLY
+x86_cpu_set_sgxlepubkeyhash(env);
+#endif
+
 cpu_exec_realizefn(cs, &local_err);
 if (local_err != NULL) {
 error_propagate(errp, local_err);
@@ -7559,7 +7575,6 @@ static const TypeInfo x86_cpu_type_info = {
 .class_init = x86_cpu_common_class_init,
 };
 
-
 /* "base" CPU model, used by query-cpu-model-expansion */
 static void x86_cpu_base_class_init(ObjectClass *oc, void *data)
 {
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 9df748119f..28e0183ce3 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1500,6 +1500,7 @@ typedef struct CPUX86State {
 uint64_t mcg_status;
 uint64_t msr_ia32_misc_enable;
 uint64_t msr_ia32_feature_control;
+uint64_t msr_ia32_sgxlepubkeyhash[4];
 
 uint64_t msr_fixed_ctr_ctrl;
 uint64_t msr_global_ctrl;
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 7fe9f52710..4463d638c4 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -3030,6 +3030,17 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
 }
 }
 
+if (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_SGX_LC) {
+kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH0,
+  env->msr_ia32_sgxlepubkeyhash[0]);
+kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH1,
+  env->msr_ia32_sgxlepubkeyhash[1]);
+kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH2,
+  env->msr_ia32_sgxlepubkeyhash[2]);
+kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH3,
+  env->msr_ia32_sgxlepubkeyhash[3]);
+}
+
 /* Note: MSR_IA32_FEATURE_CONTROL is written separately, see
  *   kvm_put_msr_feature_control. */
 }
@@ -3369,6 +3380,13 @@ static int kvm_get_msrs(X86CPU *cpu)
 }
 }
 
+if (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_SGX_LC) {
+kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH0, 0);
+kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH1, 0);
+kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH2, 0);
+kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH3, 0);
+}
+
 ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, cpu->kvm_msr_buf);
 if (ret < 0) {
 return ret;
@@ -3658,6 +3676,10 @@ static int kvm_get_msrs(X86CPU *cpu)
 case MSR_IA32_RTIT_ADDR0_A ... MSR_IA32_RTIT_ADDR3_B:
 env->msr_rtit_addrs[index - MSR_IA32_RTIT_ADDR0_A] = msrs[i].data;
 break;
+case MSR_IA32_SGXLEPUBKEYHASH0 ... MSR_IA32_SGXLEPUBKEYHASH3:
+env->msr_ia32_sgxlepubkeyhash[

[RESEND PATCH 22/32] i440fx: Add support for SGX EPC

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

Enable SGX EPC virtualization, which is currently only support by KVM.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 hw/i386/pc_piix.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 46cc951073..7ced457146 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -156,6 +156,10 @@ static void pc_init1(MachineState *machine,
 }
 }
 
+if (sgx_epc_enabled) {
+pc_machine_init_sgx_epc(pcms);
+}
+
 x86_cpus_init(x86ms, pcmc->default_cpu_version);
 
 if (pcmc->kvmclock_enabled) {
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 11/32] i386: Add feature control MSR dependency when SGX is enabled

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

SGX adds multiple flags to FEATURE_CONTROL to enable SGX and Flexible
Launch Control.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 target/i386/kvm/kvm.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 4463d638c4..fa495a6f9e 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -1789,6 +1789,11 @@ int kvm_arch_init_vcpu(CPUState *cs)
   !!(c->ecx & CPUID_EXT_SMX);
 }
 
+c = cpuid_find_entry(&cpuid_data.cpuid, 7, 0);
+if (c && (c->ebx & CPUID_7_0_EBX_SGX)) {
+has_msr_feature_control = true;
+}
+
 if (env->mcg_cap & MCG_LMCE_P) {
 has_msr_mcg_ext_ctl = has_msr_feature_control = true;
 }
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 05/32] vl: Add "sgx-epc" option to expose SGX EPC sections to guest

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

Because SGX EPC is enumerated through CPUID, EPC "devices" need to be
realized prior to realizing the vCPUs themselves, i.e. long before
generic devices are parsed and realized.  From a virtualization
perspective, the CPUID aspect also means that EPC sections cannot be
hotplugged without paravirtualizing the guest kernel (hardware does
not support hotplugging as EPC sections must be locked down during
pre-boot to provide EPC's security properties).

So even though EPC sections could be realized through the generic
-devices command, they need to be created much earlier for them to
actually be usable by the guest.  Place all EPC sections in a
contiguous block, somewhat arbitrarily starting after RAM above 4g.
Ensuring EPC is in a contiguous region simplifies calculations, e.g.
device memory base, PCI hole, etc..., allows dynamic calculation of the
total EPC size, e.g. exposing EPC to guests does not require -maxmem,
and last but not least allows all of EPC to be enumerated in a single
ACPI entry, which is expected by some kernels, e.g. Windows 7 and 8.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 hw/i386/sgx-epc.c | 104 +-
 include/hw/i386/pc.h  |   6 +++
 include/hw/i386/sgx-epc.h |  16 ++
 qemu-options.hx   |   8 +++
 softmmu/globals.c |   1 +
 softmmu/vl.c  |   9 
 6 files changed, 143 insertions(+), 1 deletion(-)

diff --git a/hw/i386/sgx-epc.c b/hw/i386/sgx-epc.c
index aa487dea79..0858819a71 100644
--- a/hw/i386/sgx-epc.c
+++ b/hw/i386/sgx-epc.c
@@ -56,6 +56,8 @@ static void sgx_epc_realize(DeviceState *dev, Error **errp)
 {
 PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
 X86MachineState *x86ms = X86_MACHINE(pcms);
+MemoryDeviceState *md = MEMORY_DEVICE(dev);
+SGXEPCState *sgx_epc = pcms->sgx_epc;
 SGXEPCDevice *epc = SGX_EPC(dev);
 const char *path;
 
@@ -74,7 +76,18 @@ static void sgx_epc_realize(DeviceState *dev, Error **errp)
 return;
 }
 
-error_setg(errp, "'" TYPE_SGX_EPC "' not supported");
+epc->addr = sgx_epc->base + sgx_epc->size;
+
+memory_region_add_subregion(&sgx_epc->mr, epc->addr - sgx_epc->base,
+host_memory_backend_get_memory(epc->hostmem));
+
+host_memory_backend_set_mapped(epc->hostmem, true);
+
+sgx_epc->sections = g_renew(SGXEPCDevice *, sgx_epc->sections,
+sgx_epc->nr_sections + 1);
+sgx_epc->sections[sgx_epc->nr_sections++] = epc;
+
+sgx_epc->size += memory_device_get_region_size(md, errp);
 }
 
 static void sgx_epc_unrealize(DeviceState *dev)
@@ -159,3 +172,92 @@ static void sgx_epc_register_types(void)
 }
 
 type_init(sgx_epc_register_types)
+
+
+static int sgx_epc_set_property(void *opaque, const char *name,
+const char *value, Error **errp)
+{
+Object *obj = opaque;
+Error *err = NULL;
+
+object_property_parse(obj, name, value, &err);
+if (err != NULL) {
+error_propagate(errp, err);
+return -1;
+}
+return 0;
+}
+
+static int sgx_epc_init_func(void *opaque, QemuOpts *opts, Error **errp)
+{
+Error *err = NULL;
+Object *obj;
+
+obj = object_new("sgx-epc");
+
+qdev_set_id(DEVICE(obj), qemu_opts_id(opts));
+
+if (qemu_opt_foreach(opts, sgx_epc_set_property, obj, &err)) {
+goto out;
+}
+
+object_property_set_bool(obj, "realized", true, &err);
+
+out:
+if (err != NULL) {
+error_propagate(errp, err);
+}
+object_unref(obj);
+return err != NULL ? -1 : 0;
+}
+
+void pc_machine_init_sgx_epc(PCMachineState *pcms)
+{
+SGXEPCState *sgx_epc;
+X86MachineState *x86ms = X86_MACHINE(pcms);
+
+sgx_epc = g_malloc0(sizeof(*sgx_epc));
+pcms->sgx_epc = sgx_epc;
+
+sgx_epc->base = 0x1ULL + x86ms->above_4g_mem_size;
+
+memory_region_init(&sgx_epc->mr, OBJECT(pcms), "sgx-epc", UINT64_MAX);
+memory_region_add_subregion(get_system_memory(), sgx_epc->base,
+&sgx_epc->mr);
+
+qemu_opts_foreach(qemu_find_opts("sgx-epc"), sgx_epc_init_func, NULL,
+  &error_fatal);
+
+if ((sgx_epc->base + sgx_epc->size) < sgx_epc->base) {
+error_report("Size of all 'sgx-epc' =0x%"PRIu64" causes EPC to wrap",
+ sgx_epc->size);
+exit(EXIT_FAILURE);
+}
+
+memory_region_set_size(&sgx_epc->mr, sgx_epc->size);
+}
+
+static QemuOptsList sgx_epc_opts = {
+.name = "sgx-epc",
+.implied_opt_name = "id",
+.head = QTAILQ_HEAD_INITIALIZER(sgx_epc_opts.head),
+.desc = {
+{
+.name = "id",
+.type = QEMU_OPT_STRING,
+.help = "SGX EPC section ID",
+},{
+.name = "memdev",
+.type = QEMU_OPT_STRING,
+.help = "memory object backend",
+},
+{ /* end of list */ }
+},
+};
+
+static void sgx_epc_reg

[RESEND PATCH 03/32] qom: Add memory-backend-epc ObjectOptions support

2021-04-29 Thread Yang Zhong
Add the new 'memory-backend-epc' user creatable QOM object in
the ObjectOptions to support SGX, or the sgx backend object
cannot bootup.

Signed-off-by: Yang Zhong 
---
 qapi/qom.json | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/qapi/qom.json b/qapi/qom.json
index cd0e76d564..fd6fbee597 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -767,6 +767,7 @@
 { 'name': 'memory-backend-memfd',
   'if': 'defined(CONFIG_LINUX)' },
 'memory-backend-ram',
+'memory-backend-epc',
 'pef-guest',
 'pr-manager-helper',
 'rng-builtin',
@@ -824,6 +825,7 @@
   'memory-backend-memfd':   { 'type': 'MemoryBackendMemfdProperties',
   'if': 'defined(CONFIG_LINUX)' },
   'memory-backend-ram': 'MemoryBackendProperties',
+  'memory-backend-epc': 'MemoryBackendProperties',
   'pr-manager-helper':  'PrManagerHelperProperties',
   'rng-builtin':'RngProperties',
   'rng-egd':'RngEgdProperties',
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 07/32] i386: Add SGX CPUID leaf FEAT_SGX_12_0_EAX

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

CPUID leaf 12_0_EAX is an Intel-defined feature bits leaf enumerating
the CPU's SGX capabilities, e.g. supported SGX instruction sets.
Currently there are four enumerated capabilities:

  - SGX1 instruction set, i.e. "base" SGX
  - SGX2 instruction set for dynamic EPC management
  - ENCLV instruction set for VMM oversubscription of EPC
  - ENCLS-C instruction set for thread safe variants of ENCLS

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 target/i386/cpu.c | 20 
 target/i386/cpu.h |  1 +
 2 files changed, 21 insertions(+)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 544d7be43c..5443f69fa5 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -676,6 +676,7 @@ static void x86_cpu_vendor_words2str(char *dst, uint32_t 
vendor1,
   /* missing:
   CPUID_XSAVE_XSAVEC, CPUID_XSAVE_XSAVES */
 #define TCG_14_0_ECX_FEATURES 0
+#define TCG_SGX_12_0_EAX_FEATURES 0
 
 typedef enum FeatureWordType {
CPUID_FEATURE_WORD,
@@ -1325,6 +1326,25 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] 
= {
 .tcg_features = TCG_14_0_ECX_FEATURES,
  },
 
+[FEAT_SGX_12_0_EAX] = {
+.type = CPUID_FEATURE_WORD,
+.feat_names = {
+"sgx1", "sgx2", NULL, NULL,
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL,
+},
+.cpuid = {
+.eax = 0x12,
+.needs_ecx = true, .ecx = 0,
+.reg = R_EAX,
+},
+.tcg_features = TCG_SGX_12_0_EAX_FEATURES,
+},
 };
 
 typedef struct FeatureMask {
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index f6afea22ca..7aba71a982 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -549,6 +549,7 @@ typedef enum FeatureWord {
 FEAT_VMX_BASIC,
 FEAT_VMX_VMFUNC,
 FEAT_14_0_ECX,
+FEAT_SGX_12_0_EAX,  /* CPUID[EAX=0x12,ECX=0].EAX (SGX) */
 FEATURE_WORDS,
 } FeatureWord;
 
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 19/32] i386/pc: Add e820 entry for SGX EPC section(s)

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

Note that SGX EPC is currently guaranteed to reside in a single
contiguous chunk of memory regardless of the number of EPC sections.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 hw/i386/pc.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 90585a2471..3f5aedd756 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -895,6 +895,10 @@ void pc_memory_init(PCMachineState *pcms,
 e820_add_entry(0x1ULL, x86ms->above_4g_mem_size, E820_RAM);
 }
 
+if (pcms->sgx_epc != NULL) {
+e820_add_entry(pcms->sgx_epc->base, pcms->sgx_epc->size, 
E820_RESERVED);
+}
+
 if (!pcmc->has_reserved_memory &&
 (machine->ram_slots ||
  (machine->maxram_size > machine->ram_size))) {
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 06/32] i386: Add primary SGX CPUID and MSR defines

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

Add CPUID defines for SGX and SGX Launch Control (LC), as well as
defines for their associated FEATURE_CONTROL MSR bits.  Define the
Launch Enclave Public Key Hash MSRs (LE Hash MSRs), which exist
when SGX LC is present (in CPUID), and are writable when SGX LC is
enabled (in FEATURE_CONTROL).

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

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index ad99cad0e7..544d7be43c 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -938,7 +938,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
 [FEAT_7_0_EBX] = {
 .type = CPUID_FEATURE_WORD,
 .feat_names = {
-"fsgsbase", "tsc-adjust", NULL, "bmi1",
+"fsgsbase", "tsc-adjust", "sgx", "bmi1",
 "hle", "avx2", NULL, "smep",
 "bmi2", "erms", "invpcid", "rtm",
 NULL, NULL, "mpx", NULL,
@@ -964,7 +964,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
 "la57", NULL, NULL, NULL,
 NULL, NULL, "rdpid", NULL,
 "bus-lock-detect", "cldemote", NULL, "movdiri",
-"movdir64b", NULL, NULL, "pks",
+"movdir64b", NULL, "sgxlc", "pks",
 },
 .cpuid = {
 .eax = 7,
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 570f916878..f6afea22ca 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -360,9 +360,17 @@ typedef enum X86Seg {
 #define MSR_IA32_PKRS   0x6e1
 
 #define FEATURE_CONTROL_LOCKED(1<<0)
+#define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX  (1ULL << 1)
 #define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX (1<<2)
+#define FEATURE_CONTROL_SGX_LC(1ULL << 17)
+#define FEATURE_CONTROL_SGX   (1ULL << 18)
 #define FEATURE_CONTROL_LMCE  (1<<20)
 
+#define MSR_IA32_SGXLEPUBKEYHASH0   0x8c
+#define MSR_IA32_SGXLEPUBKEYHASH1   0x8d
+#define MSR_IA32_SGXLEPUBKEYHASH2   0x8e
+#define MSR_IA32_SGXLEPUBKEYHASH3   0x8f
+
 #define MSR_P6_PERFCTR0 0xc1
 
 #define MSR_IA32_SMBASE 0x9e
@@ -689,6 +697,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS];
 
 /* Support RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE */
 #define CPUID_7_0_EBX_FSGSBASE  (1U << 0)
+/* Support SGX */
+#define CPUID_7_0_EBX_SGX   (1U << 2)
 /* 1st Group of Advanced Bit Manipulation Extensions */
 #define CPUID_7_0_EBX_BMI1  (1U << 3)
 /* Hardware Lock Elision */
@@ -776,6 +786,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS];
 #define CPUID_7_0_ECX_MOVDIRI   (1U << 27)
 /* Move 64 Bytes as Direct Store Instruction */
 #define CPUID_7_0_ECX_MOVDIR64B (1U << 28)
+/* Support SGX Launch Control */
+#define CPUID_7_0_ECX_SGX_LC(1U << 30)
 /* Protection Keys for Supervisor-mode Pages */
 #define CPUID_7_0_ECX_PKS   (1U << 31)
 
-- 
2.29.2.334.gfaefdd61ec




[RESEND PATCH 01/32] memory: Add RAM_PROTECTED flag to skip IOMMU mappings

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

Add a new RAMBlock flag to denote "protected" memory, i.e. memory that
looks and acts like RAM but is inaccessible via normal mechanisms,
including DMA.  Use the flag to skip protected memory regions when
mapping RAM for DMA in VFIO.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 backends/hostmem-memfd.c |  2 +-
 hw/misc/ivshmem.c|  2 +-
 hw/remote/memory.c   |  2 +-
 hw/vfio/common.c |  1 +
 include/exec/memory.h| 15 +++
 softmmu/memory.c | 12 ++--
 softmmu/physmem.c|  2 +-
 7 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c
index 69b0ae30bb..d4267cc35c 100644
--- a/backends/hostmem-memfd.c
+++ b/backends/hostmem-memfd.c
@@ -55,7 +55,7 @@ memfd_backend_memory_alloc(HostMemoryBackend *backend, Error 
**errp)
 name = host_memory_backend_get_name(backend);
 memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
name, backend->size,
-   backend->share, fd, 0, errp);
+   backend->share, false, fd, 0, errp);
 g_free(name);
 }
 
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index a1fa4878be..aa3fa80774 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -494,7 +494,7 @@ static void process_msg_shmem(IVShmemState *s, int fd, 
Error **errp)
 
 /* mmap the region and map into the BAR2 */
 memory_region_init_ram_from_fd(&s->server_bar2, OBJECT(s),
-   "ivshmem.bar2", size, true, fd, 0,
+   "ivshmem.bar2", size, true, false, fd, 0,
&local_err);
 if (local_err) {
 error_propagate(errp, local_err);
diff --git a/hw/remote/memory.c b/hw/remote/memory.c
index 32085b1e05..5d0a213030 100644
--- a/hw/remote/memory.c
+++ b/hw/remote/memory.c
@@ -48,7 +48,7 @@ void remote_sysmem_reconfig(MPQemuMsg *msg, Error **errp)
 name = g_strdup_printf("remote-mem-%u", suffix++);
 memory_region_init_ram_from_fd(subregion, NULL,
name, sysmem_info->sizes[region],
-   true, msg->fds[region],
+   true, false, msg->fds[region],
sysmem_info->offsets[region],
errp);
 
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index ae5654fcdb..5bc5d29358 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -538,6 +538,7 @@ static bool 
vfio_listener_skipped_section(MemoryRegionSection *section)
 {
 return (!memory_region_is_ram(section->mr) &&
 !memory_region_is_iommu(section->mr)) ||
+   memory_region_is_protected(section->mr) ||
/*
 * Sizing an enabled 64-bit BAR can cause spurious mappings to
 * addresses in the upper part of the 64-bit address space.  These
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 5728a681b2..2816e52be3 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -155,6 +155,9 @@ typedef struct IOMMUTLBEvent {
  */
 #define RAM_UF_WRITEPROTECT (1 << 6)
 
+/* RAM that isn't accessible through normal means. */
+#define RAM_PROTECTED (1 << 7)
+
 static inline void iommu_notifier_init(IOMMUNotifier *n, IOMMUNotify fn,
IOMMUNotifierFlag flags,
hwaddr start, hwaddr end,
@@ -1021,6 +1024,7 @@ void memory_region_init_ram_from_file(MemoryRegion *mr,
  * @name: the name of the region.
  * @size: size of the region.
  * @share: %true if memory must be mmaped with the MAP_SHARED flag
+ * @protected: %true if memory is protected and isn't treated like normal RAM
  * @fd: the fd to mmap.
  * @offset: offset within the file referenced by fd
  * @errp: pointer to Error*, to store an error if it happens.
@@ -1033,6 +1037,7 @@ void memory_region_init_ram_from_fd(MemoryRegion *mr,
 const char *name,
 uint64_t size,
 bool share,
+bool protected,
 int fd,
 ram_addr_t offset,
 Error **errp);
@@ -1321,6 +1326,16 @@ static inline bool memory_region_is_romd(MemoryRegion 
*mr)
 return mr->rom_device && mr->romd_mode;
 }
 
+/**
+ * memory_region_is_protected: check whether a memory region is protected
+ *
+ * Returns %true if a memory region is protected RAM and cannot be accessed
+ * via standard mechanisms, e.g. DMA.
+ *
+ * @mr: the memory region being queried
+ */
+bool memory_region_is_protected(MemoryRegion *mr);
+
 /**
  * memory_region_get_iommu: check whether a memory region is an iommu
  *
diff --git a/softmmu/

[RESEND PATCH 04/32] i386: Add 'sgx-epc' device to expose EPC sections to guest

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

SGX EPC is enumerated through CPUID, i.e. EPC "devices" need to be
realized prior to realizing the vCPUs themselves, which occurs long
before generic devices are parsed and realized.  Because of this,
do not allow 'sgx-epc' devices to be instantiated after vCPUS have
been created.

The 'sgx-epc' device is essentially a placholder at this time, it will
be fully implemented in a future patch along with a dedicated command
to create 'sgx-epc' devices.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 hw/i386/meson.build   |   1 +
 hw/i386/sgx-epc.c | 161 ++
 include/hw/i386/sgx-epc.h |  44 +++
 3 files changed, 206 insertions(+)
 create mode 100644 hw/i386/sgx-epc.c
 create mode 100644 include/hw/i386/sgx-epc.h

diff --git a/hw/i386/meson.build b/hw/i386/meson.build
index e5d109f5c6..087426c75c 100644
--- a/hw/i386/meson.build
+++ b/hw/i386/meson.build
@@ -5,6 +5,7 @@ i386_ss.add(files(
   'e820_memory_layout.c',
   'multiboot.c',
   'x86.c',
+  'sgx-epc.c',
 ))
 
 i386_ss.add(when: 'CONFIG_X86_IOMMU', if_true: files('x86-iommu.c'),
diff --git a/hw/i386/sgx-epc.c b/hw/i386/sgx-epc.c
new file mode 100644
index 00..aa487dea79
--- /dev/null
+++ b/hw/i386/sgx-epc.c
@@ -0,0 +1,161 @@
+/*
+ * SGX EPC device
+ *
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * Authors:
+ *   Sean Christopherson 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "hw/i386/pc.h"
+#include "hw/i386/sgx-epc.h"
+#include "hw/mem/memory-device.h"
+#include "hw/qdev-properties.h"
+#include "monitor/qdev.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
+#include "qemu/config-file.h"
+#include "qemu/error-report.h"
+#include "qemu/option.h"
+#include "qemu/units.h"
+#include "target/i386/cpu.h"
+#include "exec/address-spaces.h"
+
+static Property sgx_epc_properties[] = {
+DEFINE_PROP_UINT64(SGX_EPC_ADDR_PROP, SGXEPCDevice, addr, 0),
+DEFINE_PROP_LINK(SGX_EPC_MEMDEV_PROP, SGXEPCDevice, hostmem,
+ TYPE_MEMORY_BACKEND, HostMemoryBackend *),
+DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sgx_epc_get_size(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+Error *local_err = NULL;
+uint64_t value;
+
+value = memory_device_get_region_size(MEMORY_DEVICE(obj), &local_err);
+if (local_err) {
+error_propagate(errp, local_err);
+return;
+}
+
+visit_type_uint64(v, name, &value, errp);
+}
+
+static void sgx_epc_init(Object *obj)
+{
+object_property_add(obj, SGX_EPC_SIZE_PROP, "uint64", sgx_epc_get_size,
+NULL, NULL, NULL);
+}
+
+static void sgx_epc_realize(DeviceState *dev, Error **errp)
+{
+PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
+X86MachineState *x86ms = X86_MACHINE(pcms);
+SGXEPCDevice *epc = SGX_EPC(dev);
+const char *path;
+
+if (x86ms->boot_cpus != 0) {
+error_setg(errp, "'" TYPE_SGX_EPC "' can't be created after vCPUs,"
+ "e.g. via -device");
+return;
+}
+
+if (!epc->hostmem) {
+error_setg(errp, "'" SGX_EPC_MEMDEV_PROP "' property is not set");
+return;
+} else if (host_memory_backend_is_mapped(epc->hostmem)) {
+path = object_get_canonical_path_component(OBJECT(epc->hostmem));
+error_setg(errp, "can't use already busy memdev: %s", path);
+return;
+}
+
+error_setg(errp, "'" TYPE_SGX_EPC "' not supported");
+}
+
+static void sgx_epc_unrealize(DeviceState *dev)
+{
+SGXEPCDevice *epc = SGX_EPC(dev);
+
+host_memory_backend_set_mapped(epc->hostmem, false);
+}
+
+static uint64_t sgx_epc_md_get_addr(const MemoryDeviceState *md)
+{
+const SGXEPCDevice *epc = SGX_EPC(md);
+
+return epc->addr;
+}
+
+static void sgx_epc_md_set_addr(MemoryDeviceState *md, uint64_t addr,
+Error **errp)
+{
+object_property_set_uint(OBJECT(md), SGX_EPC_ADDR_PROP, addr, errp);
+}
+
+static uint64_t sgx_epc_md_get_plugged_size(const MemoryDeviceState *md,
+Error **errp)
+{
+return 0;
+}
+
+static MemoryRegion *sgx_epc_md_get_memory_region(MemoryDeviceState *md,
+  Error **errp)
+{
+SGXEPCDevice *epc = SGX_EPC(md);
+
+if (!epc->hostmem) {
+error_setg(errp, "'" SGX_EPC_MEMDEV_PROP "' property must be set");
+return NULL;
+}
+
+return host_memory_backend_get_memory(epc->hostmem);
+}
+
+static void sgx_epc_md_fill_device_info(const MemoryDeviceState *md,
+MemoryDeviceInfo *info)
+{
+/* TODO */
+}
+
+static void sgx_epc_class_init(ObjectClass *oc, void *data)
+{
+DeviceClass *dc = DEVICE_CLASS(oc);
+MemoryDeviceClass *mdc = MEMORY_DEVICE_CL

[RESEND PATCH 00/32] Qemu SGX virtualization

2021-04-29 Thread Yang Zhong
Since Sean Christopherson has left Intel and i am responsible for Qemu SGX
upstream work. His @intel.com address will be bouncing and his new email(
sea...@google.com) is also in CC lists.

This series is Qemu SGX virtualization implementation rebased on latest
Qemu release.

You can find Qemu repo here:

 https://github.com/intel/qemu-sgx.git upstream

If you want to try sgx, you can also get the kernel/kvm code from upstream
branch of kvm-sgx repo on github:

 https://github.com/intel/kvm-sgx.git upstream

Notice: The kvm SGX patch series has been queued by Paolo in 4/17. This Qemu
series still depend on above kvm-sgx upstream branch, so the 
KVM_CAP_SGX_ATTRIBUTE
will be changed to 196 once the linux release merge all kvm SGX series.

To simplify, you'd better install kvm-sgx on host and guest, which can support
SGX on host and guest kernel. And to me, use below reference command to boot
SGX guest:

 #qemu-system-x86_64 \
 .. \
 -cpu host,+sgx_provisionkey \
 -sgx-epc id=epc1,memdev=mem1 \
 -object memory-backend-epc,id=mem1,size=64M,prealloc=on

Overview


Intel Software Guard eXtensions (SGX) is a set of instructions and mechanisms
for memory accesses in order to provide security accesses for sensitive
applications and data. SGX allows an application to use it's pariticular
address space as an *enclave*, which is a protected area provides 
confidentiality
and integrity even in the presence of privileged malware. Accesses to the
enclave memory area from any software not resident in the enclave are prevented,
including those from privileged software.

SGX virtaulization
==

The KVM SGX creates one new misc device, sgx_vepc, and Qemu will open 
'/dev/sgx_vepc'
device node to mmap() host EPC memory to guest. The Qemu also adds 'sgx-epc' 
device
to expose EPC sections to guest through CPUID and ACPI table.  The Qemu SGX also
supports multiple virtual EPC sections to guest, we just put them together 
physically
contiguous for the sake of simplicity. The kernel SGX NUMA has been merged into 
Linux
tip tree, we will support this function in the next phase.

Although the current host SGX subsystem can not support SGX2 feature, the 
KVM/Qemu
implementation still expose this feature to guest. Guest SGX2 support doesn't 
have
interaction with host kernel SGX driver, the SGX guest can normally use those 
new
instructions.

As for SGX virtualization detailed infomation, please reference 
docs/intel-sgx.txt
docuement(patch 32).

Sean Christopherson (22):
  memory: Add RAM_PROTECTED flag to skip IOMMU mappings
  hostmem: Add hostmem-epc as a backend for SGX EPC
  i386: Add 'sgx-epc' device to expose EPC sections to guest
  vl: Add "sgx-epc" option to expose SGX EPC sections to guest
  i386: Add primary SGX CPUID and MSR defines
  i386: Add SGX CPUID leaf FEAT_SGX_12_0_EAX
  i386: Add SGX CPUID leaf FEAT_SGX_12_0_EBX
  i386: Add SGX CPUID leaf FEAT_SGX_12_1_EAX
  i386: Add get/set/migrate support for SGX_LEPUBKEYHASH MSRs
  i386: Add feature control MSR dependency when SGX is enabled
  i386: Update SGX CPUID info according to hardware/KVM/user input
  linux-headers: Add placeholder for KVM_CAP_SGX_ATTRIBUTE
  i386: kvm: Add support for exposing PROVISIONKEY to guest
  i386: Propagate SGX CPUID sub-leafs to KVM
  Adjust min CPUID level to 0x12 when SGX is enabled
  hw/i386/fw_cfg: Set SGX bits in feature control fw_cfg accordingly
  hw/i386/pc: Account for SGX EPC sections when calculating device
memory
  i386/pc: Add e820 entry for SGX EPC section(s)
  i386: acpi: Add SGX EPC entry to ACPI tables
  q35: Add support for SGX EPC
  i440fx: Add support for SGX EPC
  doc: Add the SGX doc

Yang Zhong (10):
  qom: Add memory-backend-epc ObjectOptions support
  hostmem: Add the reset interface for EPC backend reset
  sgx-epc: Add the reset interface for sgx-epc virt device
  qmp: Add query-sgx command
  hmp: Add 'info sgx' command
  i386: Add sgx_get_info() interface
  bitops: Support 32 and 64 bit mask macro
  qmp: Add the qmp_query_sgx_capabilities()
  Kconfig: Add CONFIG_SGX support
  sgx-epc: Add the fill_device_info() callback support

 backends/hostmem-epc.c   | 106 ++
 backends/hostmem-memfd.c |   2 +-
 backends/meson.build |   1 +
 default-configs/devices/i386-softmmu.mak |   1 +
 docs/intel-sgx.txt   | 173 +
 hmp-commands-info.hx |  15 +
 hw/i386/Kconfig  |   5 +
 hw/i386/acpi-build.c |  22 ++
 hw/i386/fw_cfg.c |  10 +-
 hw/i386/meson.build  |   1 +
 hw/i386/pc.c |  15 +-
 hw/i386/pc_piix.c|   4 +
 hw/i386/pc_q35.c |   3 +
 hw/i386/sgx-epc.c| 451 +++
 hw/i386/sgx-stub.c   |  13 +
 hw/misc/ivshmem.c   

[RESEND PATCH 02/32] hostmem: Add hostmem-epc as a backend for SGX EPC

2021-04-29 Thread Yang Zhong
From: Sean Christopherson 

EPC (Enclave Page Cahe) is a specialized type of memory used by Intel
SGX (Software Guard Extensions).  The SDM desribes EPC as:

The Enclave Page Cache (EPC) is the secure storage used to store
enclave pages when they are a part of an executing enclave. For an
EPC page, hardware performs additional access control checks to
restrict access to the page. After the current page access checks
and translations are performed, the hardware checks that the EPC
page is accessible to the program currently executing. Generally an
EPC page is only accessed by the owner of the executing enclave or
an instruction which is setting up an EPC page.

Because of its unique requirements, Linux manages EPC separately from
normal memory.  Similar to memfd, the device /dev/sgx_vepc can be
opened to obtain a file descriptor which can in turn be used to mmap()
EPC memory.

Signed-off-by: Sean Christopherson 
Signed-off-by: Yang Zhong 
---
 backends/hostmem-epc.c | 90 ++
 backends/meson.build   |  1 +
 2 files changed, 91 insertions(+)
 create mode 100644 backends/hostmem-epc.c

diff --git a/backends/hostmem-epc.c b/backends/hostmem-epc.c
new file mode 100644
index 00..f267cf9f91
--- /dev/null
+++ b/backends/hostmem-epc.c
@@ -0,0 +1,90 @@
+/*
+ * QEMU host SGX EPC memory backend
+ *
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * Authors:
+ *   Sean Christopherson 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include 
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qom/object_interfaces.h"
+#include "qapi/error.h"
+#include "sysemu/hostmem.h"
+
+#define TYPE_MEMORY_BACKEND_EPC "memory-backend-epc"
+
+#define MEMORY_BACKEND_EPC(obj)\
+OBJECT_CHECK(HostMemoryBackendEpc, (obj), TYPE_MEMORY_BACKEND_EPC)
+
+typedef struct HostMemoryBackendEpc HostMemoryBackendEpc;
+
+struct HostMemoryBackendEpc {
+HostMemoryBackend parent_obj;
+};
+
+static void
+sgx_epc_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
+{
+char *name;
+int fd;
+
+if (!backend->size) {
+error_setg(errp, "can't create backend with size 0");
+return;
+}
+
+fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
+if (fd < 0) {
+error_setg_errno(errp, errno,
+ "failed to open /dev/sgx_vepc to alloc SGX EPC");
+return;
+}
+
+name = object_get_canonical_path(OBJECT(backend));
+memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
+   name, backend->size, backend->share, true,
+   fd, 0, errp);
+g_free(name);
+}
+
+static void sgx_epc_backend_instance_init(Object *obj)
+{
+HostMemoryBackend *m = MEMORY_BACKEND(obj);
+
+m->share = true;
+m->merge = false;
+m->dump = false;
+}
+
+static void sgx_epc_backend_class_init(ObjectClass *oc, void *data)
+{
+HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
+
+bc->alloc = sgx_epc_backend_memory_alloc;
+}
+
+static const TypeInfo sgx_epc_backed_info = {
+.name = TYPE_MEMORY_BACKEND_EPC,
+.parent = TYPE_MEMORY_BACKEND,
+.instance_init = sgx_epc_backend_instance_init,
+.class_init = sgx_epc_backend_class_init,
+.instance_size = sizeof(HostMemoryBackendEpc),
+};
+
+static void register_types(void)
+{
+int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
+if (fd >= 0) {
+close(fd);
+
+type_register_static(&sgx_epc_backed_info);
+}
+}
+
+type_init(register_types);
diff --git a/backends/meson.build b/backends/meson.build
index d4221831fc..46fd16b269 100644
--- a/backends/meson.build
+++ b/backends/meson.build
@@ -16,5 +16,6 @@ softmmu_ss.add(when: ['CONFIG_VHOST_USER', 'CONFIG_VIRTIO'], 
if_true: files('vho
 softmmu_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: 
files('cryptodev-vhost.c'))
 softmmu_ss.add(when: ['CONFIG_VIRTIO_CRYPTO', 'CONFIG_VHOST_CRYPTO'], if_true: 
files('cryptodev-vhost-user.c'))
 softmmu_ss.add(when: 'CONFIG_GIO', if_true: [files('dbus-vmstate.c'), gio])
+softmmu_ss.add(when: 'CONFIG_LINUX', if_true: files('hostmem-epc.c'))
 
 subdir('tpm')
-- 
2.29.2.334.gfaefdd61ec




Re: [PATCH v4 10/12] qtest/qmp-cmd-test: Make test build-independent from accelerator

2021-04-29 Thread Markus Armbruster
Philippe Mathieu-Daudé  writes:

> On 4/29/21 3:22 PM, Markus Armbruster wrote:
>> Philippe Mathieu-Daudé  writes:
> Now than we can probe if the TCG accelerator is available
> at runtime with a QMP command, do it once at the beginning
> and only register the tests we can run.
> We can then replace the #ifdef'ry by a runtime check.
>
> Suggested-by: Paolo Bonzini 
> Signed-off-by: Philippe Mathieu-Daudé 

 Please read the last remark first.  The other ones are detail; feel free
 to skip them until we're done with the last one.

> ---
>  tests/qtest/qmp-cmd-test.c | 18 ++
>  1 file changed, 14 insertions(+), 4 deletions(-)
>>>
> +tcg_accel_available = qtest_has_accel("tcg");
> +

 When does tcg_accel_available differ from defined(CONFIG_TCG)?
>>>
>>> qtest_has_accel("tcg") is a runtime check, while defined(CONFIG_TCG)
>>> is build-time.
>> 
>> Let me rephrase my question: under what conditions can the values of
>> qtest_has_accel("tcg") and defined(CONFIG_TCG) differ?
>
> They are currently the same, so this patch is a no-op. *But* it
> allows us to remove the global dependence on CONFIG_TCG in the
> Meson machinery (see the last commit in this series).
>
> Is that missing part of the commit description?
>
> "This will allow us to remove the global CONFIG_TCG dependency
> in our Meson machinery in a pair of commits."?

Do you mean "in the next two commits"?

Please also note that the probing at run-time always gives the same
result as the compile-time check it replaces.

I don't understand what exactly the conversion to probing enables and
how, but I believe I don't have to.

[...]




Re: [PATCH] virtio-blk: drop deprecated scsi=on|off property

2021-04-29 Thread Michal PrĂ­voznĂ­k
On 4/29/21 5:52 PM, Stefan Hajnoczi wrote:
> The scsi=on|off property was deprecated in QEMU 5.0 and can be removed
> completely at this point.
> 
> Drop the scsi=on|off option. It was only available on Legacy virtio-blk
> devices. Linux v5.6 already dropped support for it.
> 
> Remove the hw_compat_2_4[] property assignment since scsi=on|off no
> longer exists. Old guests with Legacy virtio-blk devices no longer see
> the SCSI host features bit.
> 
> Live migrating old guests from an old QEMU with the SCSI feature bit
> enabled will fail with "Features 0x... unsupported. Allowed features:
> 0x...". We've followed the QEMU deprecation policy so users have been
> warned...
> 
> I have tested that libvirt still works when the property is absent. It
> no longer adds scsi=on|off to the command-line.
> 
> Cc: Markus Armbruster 
> Cc: Christoph Hellwig 
> Cc: Peter Krempa 
> Cc: Dr. David Alan Gilbert 
> Signed-off-by: Stefan Hajnoczi 
> ---
>  docs/specs/tpm.rst   |   2 +-
>  docs/system/deprecated.rst   |  13 ---
>  docs/pci_expander_bridge.txt |   2 +-
>  hw/block/virtio-blk.c| 192 +--
>  hw/core/machine.c|   2 -
>  5 files changed, 3 insertions(+), 208 deletions(-)

Reviewed-by: Michal Privoznik 

Michal




Re: [RFC PATCH v2 2/4] hw/arm/virt: Parse -smp cluster parameter in virt_smp_parse

2021-04-29 Thread wangyanan (Y)

Hi Drew,

On 2021/4/29 19:02, Andrew Jones wrote:

On Thu, Apr 29, 2021 at 04:56:06PM +0800, wangyanan (Y) wrote:

On 2021/4/29 15:16, Andrew Jones wrote:

On Thu, Apr 29, 2021 at 10:14:37AM +0800, wangyanan (Y) wrote:

On 2021/4/28 18:31, Andrew Jones wrote:

On Tue, Apr 13, 2021 at 04:31:45PM +0800, Yanan Wang wrote:

} else if (sockets == 0) {
threads = threads > 0 ? threads : 1;
-sockets = cpus / (cores * threads);
+sockets = cpus / (clusters * cores * threads);
sockets = sockets > 0 ? sockets : 1;

If we initialize clusters to zero instead of one and add lines in
'cpus == 0 || cores == 0' and 'sockets == 0' like
'clusters = clusters > 0 ? clusters : 1' as needed, then I think we can
add

} else if (clusters == 0) {
threads = threads > 0 ? threads : 1;
clusters = cpus / (sockets * cores * thread);
clusters = clusters > 0 ? clusters : 1;
}

here.

I have thought about this kind of format before, but there is a little bit
difference between these two ways. Let's chose the better and more
reasonable one of the two.

Way A currently in this patch:
If value of clusters is not explicitly specified in -smp command line, we
assume
that users don't want to support clusters, for compatibility we initialized
the
value to 1. So that with cmdline "-smp cpus=24, sockets=2, cores=6", we will
parse out the topology description like below:
cpus=24, sockets=2, clusters=1, cores=6, threads=2

Way B that you suggested for this patch:
Whether value of clusters is explicitly specified in -smp command line or
not,
we assume that clusters are supported and calculate the value. So that with
cmdline "-smp cpus=24, sockets=2, cores=6", we will parse out the topology
description like below:
cpus =24, sockets=2, clusters=2, cores=6, threads=1

But I think maybe we should not assume too much about what users think
through the -smp command line. We should just assume that all levels of
cpu topology are supported and calculate them, and users should be more
careful if they want to get the expected results with not so complete
cmdline.
If I'm right, then Way B should be better. :)


Hi Yanan,

We're already assuming the user wants to describe clusters to the guest
because we require at least one per socket. If we want the user to have a
choice between using clusters or not, then I guess we need to change the
logic in the PPTT and the cpu-map to only generate the cluster level when
the number of clusters is not zero. And then change this parser to not
require clusters at all.

Hi Drew,

I think this kind of change will introduce more complexity and actually is
not necessary.
Not generating cluster level at all and generating cluster level (one per
socket) are same
to kernel. Without cluster description provided, kernel will initialize all
cores in the same
cluster which also means one cluster per socket.

Which kernel? All kernels? One without the cluster support patches [1]?

[1] 
https://lore.kernel.org/lkml/20210420001844.9116-1-song.bao@hisilicon.com/#t

I'm sorry, I didn't make it clear. :)
I actually mean the ARM64 kernel, with or without [1].

Without [1]: Kernel doesn't care about cluster. When populating cpu 
topology, it directly
finds the hierarchy node with "physical package flag" as package when 
parsing ACPI, and
finds the core node's parent as package when parsing DT. So even we 
provide cluster level
description (one per socket), the parsing results will be the same as 
not providing at all.


With [1]: Kernel finds the core hierarchy node's parent as cluster when 
parsing ACPI. So if
we don't provide cluster level description, package will be taken as 
cluster. And if we provide

the description (one per socket), the parsing result will also be the same.

That's why I said that we just need to provide description of cluster 
(one per socket) if we

don't want to make use of it in VMs.

[1] 
https://lore.kernel.org/lkml/20210420001844.9116-1-song.bao@hisilicon.com/#t

So we should only ensure value of clusters per socket is one if we don't
want to use clusters,
and don't need to care about whether or not to generate description in PPTT
and cpu-map.
Is this right?

Depends on your answer to my 'which kernel' questions.


I'm not a big fan of these auto-calculated values either, but the
documentation says that it'll do that, and it's been done that way
forever, so I think we're stuck with it for the -smp option. Hmm, I was
just about to say that x86 computes all its values, but I see the most
recently added one, 'dies', is implemented the way you're proposing we
implement 'clusters', i.e. default to one and don't calculate it when it's
missing. I actually consider that either a documentation bug or an smp
parsing bug, though.

My propose originally came from implementation of x86.

Another possible option, for Arm, because only the cpus and maxcpus
parameters of -smp have ever worked, is to document, for Arm, that 

Re: [PATCH RFC v5 07/12] hw/riscv: PLIC update external interrupt by KVM when kvm enabled

2021-04-29 Thread Anup Patel
On Mon, Apr 12, 2021 at 12:24 PM Yifei Jiang  wrote:
>
> Only support supervisor external interrupt currently.
>
> Signed-off-by: Yifei Jiang 
> Signed-off-by: Yipeng Yin 
> ---
>  hw/intc/sifive_plic.c| 29 -
>  target/riscv/kvm-stub.c  |  5 +
>  target/riscv/kvm.c   | 20 
>  target/riscv/kvm_riscv.h |  1 +
>  4 files changed, 46 insertions(+), 9 deletions(-)
>
> diff --git a/hw/intc/sifive_plic.c b/hw/intc/sifive_plic.c
> index 97a1a27a9a..2746eb7a05 100644
> --- a/hw/intc/sifive_plic.c
> +++ b/hw/intc/sifive_plic.c
> @@ -31,6 +31,8 @@
>  #include "target/riscv/cpu.h"
>  #include "sysemu/sysemu.h"
>  #include "migration/vmstate.h"
> +#include "sysemu/kvm.h"
> +#include "kvm_riscv.h"
>
>  #define RISCV_DEBUG_PLIC 0
>
> @@ -147,15 +149,24 @@ static void sifive_plic_update(SiFivePLICState *plic)
>  continue;
>  }
>  int level = sifive_plic_irqs_pending(plic, addrid);
> -switch (mode) {
> -case PLICMode_M:
> -riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MEIP, 
> BOOL_TO_MASK(level));
> -break;
> -case PLICMode_S:
> -riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_SEIP, 
> BOOL_TO_MASK(level));
> -break;
> -default:
> -break;
> +if (kvm_enabled()) {
> +if (mode == PLICMode_M) {
> +continue;
> +}
> +kvm_riscv_set_irq(RISCV_CPU(cpu), IRQ_S_EXT, level);
> +} else {
> +switch (mode) {
> +case PLICMode_M:
> +riscv_cpu_update_mip(RISCV_CPU(cpu),
> + MIP_MEIP, BOOL_TO_MASK(level));
> +break;
> +case PLICMode_S:
> +riscv_cpu_update_mip(RISCV_CPU(cpu),
> + MIP_SEIP, BOOL_TO_MASK(level));
> +break;
> +default:
> +break;
> +}

I am not comfortable with this patch.

This way we will endup calling kvm_riscv_set_irq() from various
places in hw/intc and hw/riscv.

I suggest to extend riscv_cpu_update_mip() such that when kvm is
enabled riscv_cpu_update_mip() will:
1) Consider only MIP_SEIP bit in "mask" parameter and all other
bits in "mask" parameter will be ignored probably with warning
2) When the MIP_SEIP bit is set in "mask" call kvm_riscv_set_irq()
to change the IRQ state in the KVM module.

Regards,
Anup

>  }
>  }
>
> diff --git a/target/riscv/kvm-stub.c b/target/riscv/kvm-stub.c
> index 39b96fe3f4..4e8fc31a21 100644
> --- a/target/riscv/kvm-stub.c
> +++ b/target/riscv/kvm-stub.c
> @@ -23,3 +23,8 @@ void kvm_riscv_reset_vcpu(RISCVCPU *cpu)
>  {
>  abort();
>  }
> +
> +void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level)
> +{
> +abort();
> +}
> diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c
> index 79c931acb4..da63535812 100644
> --- a/target/riscv/kvm.c
> +++ b/target/riscv/kvm.c
> @@ -453,6 +453,26 @@ void kvm_riscv_reset_vcpu(RISCVCPU *cpu)
>  env->gpr[11] = cpu->env.fdt_addr;  /* a1 */
>  }
>
> +void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level)
> +{
> +int ret;
> +unsigned virq = level ? KVM_INTERRUPT_SET : KVM_INTERRUPT_UNSET;
> +
> +if (irq != IRQ_S_EXT) {
> +return;
> +}
> +
> +if (!kvm_enabled()) {
> +return;
> +}
> +
> +ret = kvm_vcpu_ioctl(CPU(cpu), KVM_INTERRUPT, &virq);
> +if (ret < 0) {
> +perror("Set irq failed");
> +abort();
> +}
> +}
> +
>  bool kvm_arch_cpu_check_are_resettable(void)
>  {
>  return true;
> diff --git a/target/riscv/kvm_riscv.h b/target/riscv/kvm_riscv.h
> index f38c82bf59..ed281bdce0 100644
> --- a/target/riscv/kvm_riscv.h
> +++ b/target/riscv/kvm_riscv.h
> @@ -20,5 +20,6 @@
>  #define QEMU_KVM_RISCV_H
>
>  void kvm_riscv_reset_vcpu(RISCVCPU *cpu);
> +void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level);
>
>  #endif
> --
> 2.19.1
>
>
> --
> kvm-riscv mailing list
> kvm-ri...@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kvm-riscv



Re: [PATCH v2 4/7] target/ppc: turned SPR R/W callbacks not static

2021-04-29 Thread Richard Henderson

On 4/29/21 9:21 AM, Bruno Larsen (billionai) wrote:

To be able to compile translate_init.c.inc as a standalone file,
we have to make the callbacks accessible outside of translate.c;
This patch does that, making the callbacks not static and creating
a new .h file

Signed-off-by: Bruno Larsen (billionai)
---
  target/ppc/spr_tcg.c.inc | 203 ---
  target/ppc/spr_tcg.h | 121 +++
  2 files changed, 223 insertions(+), 101 deletions(-)
  create mode 100644 target/ppc/spr_tcg.h


FWIW, a good follow-up would be to separately compile this.


r~



Re: [PATCH v2 7/7] target/ppc: isolated cpu init from translation logic

2021-04-29 Thread Richard Henderson

On 4/29/21 9:21 AM, Bruno Larsen (billionai) wrote:

@@ -49,7 +54,12 @@ static inline void vscr_init(CPUPPCState *env, uint32_t val)
  {
  /* Altivec always uses round-to-nearest */
  set_float_rounding_mode(float_round_nearest_even, &env->vec_status);
-helper_mtvscr(env, val);
+/*
+ * This comment is here just so the project will build.
+ * The current solution is in another patch and will be
+ * added when we figure out an internal fork of qemu
+ */
+/* helper_mtvscr(env, val); */
  }


(1) this is a separate change to splitting out cpu_init.c.
(2) you can't even do this without introducing a regression.


r~



Re: [PATCH v2 6/7] target/ttc: renamed SPR registration functions

2021-04-29 Thread Richard Henderson

On 4/29/21 9:21 AM, Bruno Larsen (billionai) wrote:

Renamed all gen_spr_* and gen_* functions specifically related to
registering SPRs to register_*_sprs and register_*, to avoid future
confusion with other TCG related code.

Signed-off-by: Bruno Larsen (billionai)
---
  target/ppc/translate_init.c.inc | 860 
  1 file changed, 430 insertions(+), 430 deletions(-)


Reviewed-by: Richard Henderson 

r~



Re: [PATCH v2 4/7] target/ppc: turned SPR R/W callbacks not static

2021-04-29 Thread Richard Henderson

On 4/29/21 9:21 AM, Bruno Larsen (billionai) wrote:

@@ -234,19 +235,19 @@ static void spr_read_tbu(DisasContext *ctx, int gprn, int 
sprn)
  }
  
  ATTRIBUTE_UNUSED

-static void spr_read_atbl(DisasContext *ctx, int gprn, int sprn)
+void spr_read_atbl(DisasContext *ctx, int gprn, int sprn)
  {


You can drop the ATTRIBUTE_UNUSED at the same time.

It was only there to stop the static symbol from being signaled as unused; for 
a non-static symbol, the compiler obviously can't tell.



diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
new file mode 100644
index 00..b573a23e7b
--- /dev/null
+++ b/target/ppc/spr_tcg.h
@@ -0,0 +1,121 @@
+#ifndef SPR_TCG_H
+#define SPR_TCG_H
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/translator.h"
+#include "tcg/tcg.h"


All new files get copyright headers.  No headers include osdep.h.  It doesn't 
appear that you need any headers for this file; just add


typedef struct DisasContext DisasContext;

to the top of the file.


r~



Re: [PATCH v2 3/7] target/ppc: Isolated SPR read/write callbacks

2021-04-29 Thread Richard Henderson

On 4/29/21 9:21 AM, Bruno Larsen (billionai) wrote:

diff --git a/target/ppc/spr_tcg.c.inc b/target/ppc/spr_tcg.c.inc
new file mode 100644
index 00..48274dd52b
--- /dev/null
+++ b/target/ppc/spr_tcg.c.inc
@@ -0,0 +1,1033 @@
+#include "exec/translator.h"


All new files must have copyright header.


+/* I really see no reason to keep these gen_*_xer */
+/* instead of just leaving the code in the spr_*_xer */


Then just do that, as a separate patch, before or after.


@@ -8515,3 +8471,4 @@ void restore_state_to_opc(CPUPPCState *env, 
TranslationBlock *tb,
  {
  env->nip = data[0];
  }
+


Watch the extra whitespace at end of file.


r~



Re: Let's remove some deprecated stuff

2021-04-29 Thread Robert Hoo
On Thu, 2021-04-29 at 11:59 +0200, Markus Armbruster wrote:
> If you're cc'ed, you added a section to docs/system/deprecated.rst
> that
> is old enough to permit removal.  This is *not* a demand to remove,
> it's
> a polite request to consider whether the time for removal has come.
> Extra points for telling us in a reply.  "We should remove, but I
> can't
> do it myself right now" is a valid answer.  Let's review the file:
> 
> System emulator command line arguments
> --
> 
[...]
> 
> Robert Hoo:
> 
> ``Icelake-Client`` CPU Model (since 5.2.0)
> ''
> 
> ``Icelake-Client`` CPU Models are deprecated. Use ``Icelake-
> Server`` CPU
> Models instead.
> 
Yeah, please drop this entry.
Actually I've sent patches for this.
https://lore.kernel.org/qemu-devel/1619660147-136679-1-git-send-email-robert...@linux.intel.com/




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

2021-04-29 Thread Like Xu

Hi Eduardo,

Thanks for your detailed comments.

On 2021/4/29 5:19, Eduardo Habkost wrote:

On Tue, Apr 27, 2021 at 04:09:48PM +0800, 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".


I don't understand why "migratable" matters here.  "migratable"
is just a convenience property to get better defaults when using
"-cpu host".  I don't know why it would change the lbr-fmt
validation rules.


Your comments bevlow help me understand why we introduced "migratable"
and I'll fllow it.





Signed-off-by: Like Xu 
---


A changelog explaining what you changed since v1 would have been
useful here.


Sorry for inconvenience.




  target/i386/cpu.c | 34 ++
  target/i386/cpu.h | 10 ++
  target/i386/kvm/kvm.c | 10 --
  3 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index ad99cad0e7..9c8e54aa6f 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -6623,6 +6623,10 @@ static void x86_cpu_filter_features(X86CPU *cpu, bool 
verbose)
  }
  
  for (w = 0; w < FEATURE_WORDS; w++) {

+if (w == FEAT_PERF_CAPABILITIES) {
+continue;
+}
+


Why exactly is this necessary?  I expected to be completely OK to
call mark_unavailable_features() multiple times for the same
FeatureWord.



OK.


If there's a reason why this is necessary, I suggest adding a
comment explaining why.


  uint64_t host_feat =
  x86_cpu_get_supported_feature_word(w, false);
  uint64_t requested_features = env->features[w];
@@ -6630,6 +6634,27 @@ static void x86_cpu_filter_features(X86CPU *cpu, bool 
verbose)
  mark_unavailable_features(cpu, w, unavailable_features, prefix);
  }
  
+uint64_t host_perf_cap =

+x86_cpu_get_supported_feature_word(FEAT_PERF_CAPABILITIES, false);
+if (!cpu->lbr_fmt && !cpu->migratable) {
+cpu->lbr_fmt = host_perf_cap & PERF_CAP_LBR_FMT;


"migratable=no" is not a request to override explicit user
settings.  This is why we have the ~env->user_features masking
inside x86_cpu_expand_features() when initializing
env->features[].

In either case, I don't understand why you need the lines above.
"migratable=no" should already trigger the x86_cpu_get_supported_feature_word()
loop inside x86_cpu_expand_features(), and it should initialize
env->features[FEAT_PERF_CAPABILITIES] with the host value.  Isn't
that code working for you?



+if (cpu->lbr_fmt) {
+info_report("vPMU: The value of lbr-fmt has been adjusted "
+"to 0x%lx and guest LBR is enabled.",
+host_perf_cap & PERF_CAP_LBR_FMT);




From your other message:


(I'm assuming your examples are for a lbr-fmt=5 host)


"-cpu host,migratable=no" --> "Enable guest LBR and show warning"


Enabling guest LBR in this case is 100% OK, isn't it?  I don't
think you need to show a warning.



"-cpu host,migratable=no,lbr-fmt=0" --> "Enable guest LBR and show warning"


Why?  In this case, we should do what the user asked for whenever
possible, and the user is explicitly asking lbr-fmt to be 0.


"-cpu host,migratable=no,lbr-fmt=5" --> "Enable guest LBR"


Looks OK.


"-cpu host,migratable=no,lbr-fmt=6" --> "Disable guest LBR and show warning"


Makes sense to me[1].



+}
+} else {
+uint64_t requested_lbr_fmt = cpu->lbr_fmt & PERF_CAP_LBR_FMT;
+if (requested_lbr_fmt && kvm_enabled()) {




From your other message:



"-cpu host,lbr-fmt=0" --> "Disable guest LBR"


Makes sense to me.  I understand this as a confirmation that it's
OK to have a guest/host mismatch if guest LBR=0.


"-cpu host,lbr-fmt=5" --> "Enable guest LBR"


Makes sense to me.


"-cpu host,lbr-fmt=6" --> "Disable guest LBR and show warning"


Makes sense to me[1].


[1] As long as "show warning" becomes "fatal error" if enforce=1.
 mark_unavailable_features() should make sure this happens.

 Or maybe we should make this an error?  It would be even
 better.  The example code below makes it an error.



+if (requested_lbr_fmt != (host_perf_cap & PERF_CAP_LBR_FMT)) {
+cpu->lbr_fmt = 0;
+warn_report("vPMU: The supported lbr-fmt value on the host "
+"is 0x%lx and guest LBR is disa

Re: [PATCH v2 1/7] target/ppc: move opcode table logic to translate.c

2021-04-29 Thread Richard Henderson

On 4/29/21 9:21 AM, Bruno Larsen (billionai) wrote:

code motion to remove opcode callback table from
translate_init.c.inc to translate.c in preparation to remove
the #include  from translate.c. Also created
destroy_ppc_opcodes and removed that logic from ppc_cpu_unrealize

Signed-off-by: Bruno Larsen (billionai)
---
  target/ppc/internal.h   |   8 +
  target/ppc/translate.c  | 394 
  target/ppc/translate_init.c.inc | 391 +--
  3 files changed, 403 insertions(+), 390 deletions(-)


Reviewed-by: Richard Henderson 

r~



Re: [PATCH v2 0/7] target/ppc: untangle cpu init from translation

2021-04-29 Thread Richard Henderson

On 4/29/21 9:21 AM, Bruno Larsen (billionai) wrote:

This series requires the patch proposed in
<20210426184706.48040-1-bruno.lar...@eldorado.org.br>


FYI, for the benefit of tooling, use "Based-on: message-id" which will allow 
patchew to construct a patch repository.


As is,

https://patchew.org/QEMU/20210429162130.2412-1-bruno.lar...@eldorado.org.br/

reports "Failed in applying to current master". Compare that to

https://patchew.org/QEMU/20210416210240.1591291-1-richard.hender...@linaro.org/

(which, no coincidence, is the first one I could think of that uses Based-on).


r~



[PATCH v2] Set the correct env->fpip for x86 float instructions

2021-04-29 Thread Ziqiao Kong
Thanks the review for v1 from Richard Henderson!

Changes since v1:
  - Don't update FCS, FIP, FDS and FDP for x87 control instruction.
  - Also write FCS, FDS and FDP for FSTENV.
  - Clear FCS, FIP, FDS and FDP for FXSAVE as intel manual says.

Note:
  During my test, I find that the implementation between some intel cpus
  differs on updating FDS and FDP while the AMD Ryzen always update the 
  two registers correctly. Not sure wthether it's a bug or not.

Ziqiao

Signed-off-by: Ziqiao Kong 
---
 target/i386/cpu.h|  4 +++
 target/i386/tcg/fpu_helper.c | 50 ++--
 target/i386/tcg/translate.c  | 45 +++-
 3 files changed, 79 insertions(+), 20 deletions(-)

diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 570f916878..ba43ceb4ad 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -705,6 +705,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS];
 #define CPUID_7_0_EBX_INVPCID   (1U << 10)
 /* Restricted Transactional Memory */
 #define CPUID_7_0_EBX_RTM   (1U << 11)
+/* Deprecates FPU CS and FPU DS values */
+#define CPUID_7_0_EBX_FCS_FDS   (1U << 13)
 /* Memory Protection Extension */
 #define CPUID_7_0_EBX_MPX   (1U << 14)
 /* AVX-512 Foundation */
@@ -1440,7 +1442,9 @@ typedef struct CPUX86State {
 FPReg fpregs[8];
 /* KVM-only so far */
 uint16_t fpop;
+uint16_t fpcs;
 uint64_t fpip;
+uint16_t fpds;
 uint64_t fpdp;
 
 /* emulator internal variables */
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
index 60ed93520a..97cf68542b 100644
--- a/target/i386/tcg/fpu_helper.c
+++ b/target/i386/tcg/fpu_helper.c
@@ -766,6 +766,10 @@ void helper_fninit(CPUX86State *env)
 {
 env->fpus = 0;
 env->fpstt = 0;
+env->fpcs = 0;
+env->fpip = 0;
+env->fpds = 0;
+env->fpdp = 0;
 cpu_set_fpuc(env, 0x37f);
 env->fptags[0] = 1;
 env->fptags[1] = 1;
@@ -2368,6 +2372,7 @@ static void do_fstenv(CPUX86State *env, target_ulong ptr, 
int data32,
 {
 int fpus, fptag, exp, i;
 uint64_t mant;
+uint16_t fpcs, fpds;
 CPU_LDoubleU tmp;
 
 fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
@@ -2390,24 +2395,41 @@ static void do_fstenv(CPUX86State *env, target_ulong 
ptr, int data32,
 }
 }
 }
+
+/*
+ * If CR0.PE = 1, each instruction saves FCS and FDS into memory. If
+ * CPUID.(EAX=07H,ECX=0H):EBX[bit 13] = 1, the processor deprecates
+ * FCS and FDS; it saves each as H.
+ */
+if (!(env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_FCS_FDS)
+&& (env->cr[0] & CR0_PE_MASK)) {
+fpcs = env->fpcs;
+fpds = env->fpds;
+} else {
+fpcs = 0;
+fpds = 0;
+}
+
 if (data32) {
 /* 32 bit */
 cpu_stl_data_ra(env, ptr, env->fpuc, retaddr);
 cpu_stl_data_ra(env, ptr + 4, fpus, retaddr);
 cpu_stl_data_ra(env, ptr + 8, fptag, retaddr);
-cpu_stl_data_ra(env, ptr + 12, 0, retaddr); /* fpip */
-cpu_stl_data_ra(env, ptr + 16, 0, retaddr); /* fpcs */
-cpu_stl_data_ra(env, ptr + 20, 0, retaddr); /* fpoo */
-cpu_stl_data_ra(env, ptr + 24, 0, retaddr); /* fpos */
+cpu_stl_data_ra(env, ptr + 12, env->fpip, retaddr); /* fpip */
+cpu_stw_data_ra(env, ptr + 16, fpcs, retaddr); /* fpcs */
+cpu_stw_data_ra(env, ptr + 18, 0, retaddr);
+cpu_stl_data_ra(env, ptr + 20, env->fpdp, retaddr); /* fpdp */
+cpu_stw_data_ra(env, ptr + 24, fpds, retaddr); /* fpds */
+cpu_stw_data_ra(env, ptr + 26, 0, retaddr);
 } else {
 /* 16 bit */
 cpu_stw_data_ra(env, ptr, env->fpuc, retaddr);
 cpu_stw_data_ra(env, ptr + 2, fpus, retaddr);
 cpu_stw_data_ra(env, ptr + 4, fptag, retaddr);
-cpu_stw_data_ra(env, ptr + 6, 0, retaddr);
-cpu_stw_data_ra(env, ptr + 8, 0, retaddr);
-cpu_stw_data_ra(env, ptr + 10, 0, retaddr);
-cpu_stw_data_ra(env, ptr + 12, 0, retaddr);
+cpu_stw_data_ra(env, ptr + 6, env->fpip, retaddr);
+cpu_stw_data_ra(env, ptr + 8, fpcs, retaddr);
+cpu_stw_data_ra(env, ptr + 10, env->fpdp, retaddr);
+cpu_stw_data_ra(env, ptr + 12, fpds, retaddr);
 }
 }
 
@@ -2473,17 +2495,7 @@ void helper_fsave(CPUX86State *env, target_ulong ptr, 
int data32)
 }
 
 /* fninit */
-env->fpus = 0;
-env->fpstt = 0;
-cpu_set_fpuc(env, 0x37f);
-env->fptags[0] = 1;
-env->fptags[1] = 1;
-env->fptags[2] = 1;
-env->fptags[3] = 1;
-env->fptags[4] = 1;
-env->fptags[5] = 1;
-env->fptags[6] = 1;
-env->fptags[7] = 1;
+helper_fninit(env);
 }
 
 void helper_frstor(CPUX86State *env, target_ulong ptr, int data32)
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 880bc45561..c26d343ab8 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -4486,6 +4486,11 @@ static target_ul

Re: [PATCH] spapr: Modify ibm, get-config-addr-info2 to set DEVNUM in PE config address.

2021-04-29 Thread Oliver O'Halloran
On Thu, Apr 29, 2021 at 7:02 PM Mahesh J Salgaonkar
 wrote:
>
> On 2021-04-28 22:33:45 Wed, Oliver O'Halloran wrote:
> > On Tue, Apr 27, 2021 at 9:56 PM Mahesh Salgaonkar  
> > wrote:
> > >
> > > With upstream kernel, especially after commit 98ba956f6a389
> > > ("powerpc/pseries/eeh: Rework device EEH PE determination") we see that 
> > > KVM
> > > guest isn't able to enable EEH option for PCI pass-through devices 
> > > anymore.
> >
> > How are you passing the devices through to the guest?
>
> I am using libvirt with below xml section to add pass-through:
>
> 
>   
>   
> 
>   
>function='0x0' multifunction='on'/>
> 
> 
>   
>   
> 
>   
>function='0x1' multifunction='on'/>
> 
>
> Looks like libvirt does not allow pass through device in slot zero, and
> throws following error.
>
> error: XML error: Invalid PCI address :01:00.0. slot must be >= 1
> Failed. Try again? [y,n,i,f,?]:

That's pretty odd and I have no idea why that's happening. I seem to
remember being able to use slot 0 for vfio devices when doing the
passthru manually with the qemu command line so this might be a
libvirt quirk.

> *snip*
>
> Agree. I realize my fix is not correctly handling this. The current code
> under ibm,set-eeh-option is checking for individual PCI device presence.
> Better fix should be to check if there is any PCI device (vfio-pci)
> present under specified bus and enable the EEH if found. And no change
> in return value of get-config-addr-info2. What do you say ?

That sounds reasonable. You would however need to verify that all the
devices on that bus are within the same PE on the hypervisor side.



Re: [PATCH v3 00/30] Base for adding PowerPC 64-bit instructions

2021-04-29 Thread no-reply
Patchew URL: 
https://patchew.org/QEMU/20210430011543.1017113-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: 20210430011543.1017113-1-richard.hender...@linaro.org
Subject: [PATCH v3 00/30] Base for adding PowerPC 64-bit instructions

=== 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/20210430011543.1017113-1-richard.hender...@linaro.org -> 
patchew/20210430011543.1017113-1-richard.hender...@linaro.org
Switched to a new branch 'test'
94d954b target/ppc: Implement prefixed integer store instructions
d2b6c00 target/ppc: Move D/DS/X-form integer stores to decodetree
3b6ae7e target/ppc: Implement prefixed integer load instructions
7785d8b target/ppc: Move D/DS/X-form integer loads to decodetree
60fd320 target/ppc: Implement PNOP
6d3431c target/ppc: Move ADDI, ADDIS to decodetree, implement PADDI
9cbf606 target/ppc: Move page crossing check to ppc_tr_translate_insn
f04f977 target/ppc: Add infrastructure for prefixed insns
efe0f1b target/ppc: Introduce macros to check isa extensions
69d9dd3 target/ppc: Use translator_loop_temp_check
2aba16a target/ppc: Mark helper_raise_exception* as noreturn
3b0336d target/ppc: Tidy exception vs exit_tb
d9e4ef4 target/ppc: Move single-step check to ppc_tr_tb_stop
27cd7b1 target/ppc: Remove DisasContext.exception
1241c8b target/ppc: Replace POWERPC_EXCP_BRANCH with DISAS_NORETURN
79906ac target/ppc: Replace POWERPC_EXCP_STOP with DISAS_EXIT_UPDATE
cf2d292 target/ppc: Introduce gen_icount_io_start
434992b target/ppc: Remove unnecessary gen_io_end calls
4c7c9fe target/ppc: Replace POWERPC_EXCP_SYNC with DISAS_EXIT
e4f28a4 target/ppc: Introduce DISAS_{EXIT,CHAIN}{,_UPDATE}
59c8dec target/ppc: Simplify gen_debug_exception
33ef476 target/ppc: Remove special case for POWERPC_EXCP_TRAP
a899437 target/ppc: Remove special case for POWERPC_SYSCALL
65217f2 target/ppc: Move DISAS_NORETURN setting into gen_exception*
68b60d8 target/ppc: Split out decode_legacy
91d5d66 target/ppc: Add cia field to DisasContext
8b45cf3 decodetree: Extend argument set syntax to allow types
2797541 decodetree: Add support for 64-bit instructions
1b1c946 decodetree: More use of f-strings
fd4892f decodetree: Introduce whex and whexC helpers

=== OUTPUT BEGIN ===
1/30 Checking commit fd4892f09eff (decodetree: Introduce whex and whexC helpers)
ERROR: line over 90 characters
#51: FILE: scripts/decodetree.py:495:
+output(ind, f'if ((insn & {whexC(innermask)}) == 
{whexC(innerbits)}) {{\n')

WARNING: line over 80 characters
#52: FILE: scripts/decodetree.py:496:
+output(ind, f'/* {str_match_bits(p.fixedbits, 
p.fixedmask)} */\n')

total: 1 errors, 1 warnings, 136 lines checked

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

2/30 Checking commit 1b1c946ade32 (decodetree: More use of f-strings)
3/30 Checking commit 279754143f3b (decodetree: Add support for 64-bit 
instructions)
WARNING: line over 80 characters
#74: FILE: scripts/decodetree.py:236:
+ret = f'deposit{bitop_width}({ret}, {pos}, {bitop_width - 
pos}, {ext})'

total: 0 errors, 1 warnings, 63 lines checked

Patch 3/30 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
4/30 Checking commit 8b45cf3a2c2d (decodetree: Extend argument set syntax to 
allow types)
Use of uninitialized value $acpi_testexpected in string eq at 
./scripts/checkpatch.pl line 1529.
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#155: 
new file mode 100644

total: 0 errors, 1 warnings, 121 lines checked

Patch 4/30 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
5/30 Checking commit 91d5d66281c8 (target/ppc: Add cia field to DisasContext)
6/30 Checking commit 68b60d843565 (target/ppc: Split out decode_legacy)
7/30 Checking commit 65217f275156 (target/ppc: Move DISAS_NORETURN setting into 
gen_exception*)
8/30 Checking commit a899437b0743 (target/ppc: Remove special case for 
POWERPC_SYSCALL)
9/30 Checking commit 33ef476619c9 (target/ppc: Remove special case for 
POWERPC_EXCP_TRAP)
10/30 Checking commit 59c8dec6fc93 (target/ppc: Simplify gen_debug_exception)
11/30 Checking commit e4f28a4f9529 (target/ppc: Introduce 
DISAS_{EXIT,CHAIN}{,_UPDATE})
12/30 Checking commit 4c7c9fedf741 (target/ppc: Replace POWERPC_EXCP_SYNC with 
DISAS_EXIT)
13/30 Checking commit 434992beb095 (target/ppc: Remove 

[PATCH v3 29/30] target/ppc: Move D/DS/X-form integer stores to decodetree

2021-04-29 Thread Richard Henderson
These are all connected by macros in the legacy decoding.

Signed-off-by: Richard Henderson 
---
 target/ppc/insn32.decode   | 22 ++
 target/ppc/translate.c | 83 +-
 target/ppc/translate/fixedpoint-impl.c.inc | 24 +++
 3 files changed, 48 insertions(+), 81 deletions(-)

diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index 1c1b4620fc..7d35f61e45 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -63,6 +63,28 @@ LDU 111010 . . ..01 
@PLS_DS
 LDX 01 . . . 010101 -   @X
 LDUX01 . . . 110101 -   @X
 
+### Fixed-Point Store Instructions
+
+STB 100110 . .  @PLS_D
+STBU100111 . .  @PLS_D
+STBX01 . . . 0011010111 -   @X
+STBUX   01 . . . 000111 -   @X
+
+STH 101100 . .  @PLS_D
+STHU101101 . .  @PLS_D
+STHX01 . . . 0110010111 -   @X
+STHUX   01 . . . 0110110111 -   @X
+
+STW 100100 . .  @PLS_D
+STWU100101 . .  @PLS_D
+STWX01 . . . 0010010111 -   @X
+STWUX   01 . . . 0010110111 -   @X
+
+STD 10 . . ..00 @PLS_DS
+STDU10 . . ..01 @PLS_DS
+STDX01 . . . 0010010101 -   @X
+STDUX   01 . . . 0010110101 -   @X
+
 ### Fixed-Point Arithmetic Instructions
 
 ADDI001110 . .  @PLS_D
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 1fdb501ee9..ad32fcc740 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -2463,7 +2463,9 @@ static void glue(gen_qemu_, stop)(DisasContext *ctx,  
  \
 tcg_gen_qemu_st_tl(val, addr, ctx->mem_idx, op);\
 }
 
+#if defined(TARGET_PPC64) || !defined(CONFIG_USER_ONLY)
 GEN_QEMU_STORE_TL(st8,  DEF_MEMOP(MO_UB))
+#endif
 GEN_QEMU_STORE_TL(st16, DEF_MEMOP(MO_UW))
 GEN_QEMU_STORE_TL(st32, DEF_MEMOP(MO_UL))
 
@@ -2596,52 +2598,6 @@ static void gen_lq(DisasContext *ctx)
 #endif
 
 /***  Integer store***/
-#define GEN_ST(name, stop, opc, type) \
-static void glue(gen_, name)(DisasContext *ctx)   \
-{ \
-TCGv EA;  \
-gen_set_access_type(ctx, ACCESS_INT); \
-EA = tcg_temp_new();  \
-gen_addr_imm_index(ctx, EA, 0);   \
-gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA);   \
-tcg_temp_free(EA);\
-}
-
-#define GEN_STU(name, stop, opc, type)\
-static void glue(gen_, stop##u)(DisasContext *ctx)\
-{ \
-TCGv EA;  \
-if (unlikely(rA(ctx->opcode) == 0)) { \
-gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);   \
-return;   \
-} \
-gen_set_access_type(ctx, ACCESS_INT); \
-EA = tcg_temp_new();  \
-if (type == PPC_64B)  \
-gen_addr_imm_index(ctx, EA, 0x03);\
-else  \
-gen_addr_imm_index(ctx, EA, 0);   \
-gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA);   \
-tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \
-tcg_temp_free(EA);\
-}
-
-#define GEN_STUX(name, stop, opc2, opc3, type)\
-static void glue(gen_, name##ux)(DisasContext *ctx)   \
-{ \
-TCGv EA;  \
-if (unlikely(rA(ctx->op

Re: [PATCH v3 24/30] target/ppc: Move page crossing check to ppc_tr_translate_insn

2021-04-29 Thread Richard Henderson

On 4/29/21 6:15 PM, Richard Henderson wrote:

With prefixed instructions, the number of instructions
remaining until the page crossing is no longer constant.

Signed-off-by: Richard Henderson
---
  target/ppc/translate.c | 8 +---
  1 file changed, 5 insertions(+), 3 deletions(-)


Oops, this was supposed to be ordered before the previous patch.


r~



[PATCH v3 25/30] target/ppc: Move ADDI, ADDIS to decodetree, implement PADDI

2021-04-29 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/ppc/insn32.decode   | 12 +++
 target/ppc/insn64.decode   | 15 +
 target/ppc/translate.c | 29 
 target/ppc/translate/fixedpoint-impl.c.inc | 39 ++
 4 files changed, 66 insertions(+), 29 deletions(-)

diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index b175441209..52d9b355d4 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -16,3 +16,15 @@
 # You should have received a copy of the GNU Lesser General Public
 # License along with this library; if not, see .
 #
+
+&D  rt ra si
+@D  .. rt:5 ra:5 si:s16 &D
+
+# If a prefix is allowed, decode with default values.
+&PLS_D  rt ra si:int64_t r:bool
+@PLS_D  .. rt:5 ra:5 si:s16 &PLS_D r=0
+
+### Fixed-Point Arithmetic Instructions
+
+ADDI001110 . .  @PLS_D
+ADDIS   00 . .  @D
diff --git a/target/ppc/insn64.decode b/target/ppc/insn64.decode
index 9fc45d0614..f4272df724 100644
--- a/target/ppc/insn64.decode
+++ b/target/ppc/insn64.decode
@@ -16,3 +16,18 @@
 # You should have received a copy of the GNU Lesser General Public
 # License along with this library; if not, see .
 #
+
+# Many all of these instruction names would be prefixed by "P",
+# but we share code with the non-prefixed instruction.
+
+# Format MLS:D and 8LS:D
+&PLS_D  rt ra si:int64_t r:bool  !extern
+%pls_si 32:s18 0:16
+@PLS_D  .. .. ... r:1 .. .. \
+.. rt:5 ra:5    \
+&PLS_D si=%pls_si
+
+### Fixed-Point Arithmetic Instructions
+
+ADDI01 10 0--.-- .. \
+001110 . .  @PLS_D
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index d782a13d27..5a8a3c39c3 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -924,19 +924,6 @@ GEN_INT_ARITH_ADD(addex, 0x05, cpu_ov, 1, 1, 0);
 /* addze  addze.  addzeo  addzeo.*/
 GEN_INT_ARITH_ADD_CONST(addze, 0x06, 0, cpu_ca, 1, 1, 0)
 GEN_INT_ARITH_ADD_CONST(addzeo, 0x16, 0, cpu_ca, 1, 1, 1)
-/* addi */
-static void gen_addi(DisasContext *ctx)
-{
-target_long simm = SIMM(ctx->opcode);
-
-if (rA(ctx->opcode) == 0) {
-/* li case */
-tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], simm);
-} else {
-tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)],
-cpu_gpr[rA(ctx->opcode)], simm);
-}
-}
 /* addic  addic.*/
 static inline void gen_op_addic(DisasContext *ctx, bool compute_rc0)
 {
@@ -956,20 +943,6 @@ static void gen_addic_(DisasContext *ctx)
 gen_op_addic(ctx, 1);
 }
 
-/* addis */
-static void gen_addis(DisasContext *ctx)
-{
-target_long simm = SIMM(ctx->opcode);
-
-if (rA(ctx->opcode) == 0) {
-/* lis case */
-tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], simm << 16);
-} else {
-tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)],
-cpu_gpr[rA(ctx->opcode)], simm << 16);
-}
-}
-
 /* addpcis */
 static void gen_addpcis(DisasContext *ctx)
 {
@@ -7029,10 +7002,8 @@ GEN_HANDLER_E(cmpeqb, 0x1F, 0x00, 0x07, 0x0060, 
PPC_NONE, PPC2_ISA300),
 GEN_HANDLER_E(cmpb, 0x1F, 0x1C, 0x0F, 0x0001, PPC_NONE, PPC2_ISA205),
 GEN_HANDLER_E(cmprb, 0x1F, 0x00, 0x06, 0x0041, PPC_NONE, PPC2_ISA300),
 GEN_HANDLER(isel, 0x1F, 0x0F, 0xFF, 0x0001, PPC_ISEL),
-GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x, PPC_INTEGER),
 GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x, PPC_INTEGER),
 GEN_HANDLER2(addic_, "addic.", 0x0D, 0xFF, 0xFF, 0x, PPC_INTEGER),
-GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x, PPC_INTEGER),
 GEN_HANDLER_E(addpcis, 0x13, 0x2, 0xFF, 0x, PPC_NONE, PPC2_ISA300),
 GEN_HANDLER(mulhw, 0x1F, 0x0B, 0x02, 0x0400, PPC_INTEGER),
 GEN_HANDLER(mulhwu, 0x1F, 0x0B, 0x00, 0x0400, PPC_INTEGER),
diff --git a/target/ppc/translate/fixedpoint-impl.c.inc 
b/target/ppc/translate/fixedpoint-impl.c.inc
index b740083605..7af1b3bcf5 100644
--- a/target/ppc/translate/fixedpoint-impl.c.inc
+++ b/target/ppc/translate/fixedpoint-impl.c.inc
@@ -16,3 +16,42 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, see .
  */
+
+/*
+ * Incorporate CIA into the constant when R=1.
+ * Validate that when R=1, RA=0.
+ */
+static bool resolve_PLS_D(DisasContext *ctx, arg_PLS_D *a)
+{
+if (a->r) {
+if (unlikely(a->ra != 0)) {
+gen_invalid(ctx);
+return false;
+}
+a->si += ctx->cia;
+}
+return true;
+}
+
+static bool trans_ADDI(DisasContext *ctx, arg_PLS_D *a)
+{
+if (resolve_PLS_D(ctx, a)) {
+if (a->ra) {
+tcg_gen_addi

[PATCH v3 28/30] target/ppc: Implement prefixed integer load instructions

2021-04-29 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/ppc/insn64.decode | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/target/ppc/insn64.decode b/target/ppc/insn64.decode
index 5a82ce375e..4198e5c8f3 100644
--- a/target/ppc/insn64.decode
+++ b/target/ppc/insn64.decode
@@ -29,6 +29,21 @@
 .. rt:5 ra:5    \
 &PLS_D si=%pls_si
 
+### Fixed-Point Load Instructions
+
+LBZ 01 10 0--.-- .. \
+100010 . .  @PLS_D
+LHZ 01 10 0--.-- .. \
+101000 . .  @PLS_D
+LHA 01 10 0--.-- .. \
+101010 . .  @PLS_D
+LWZ 01 10 0--.-- .. \
+10 . .  @PLS_D
+LWA 01 00 0--.-- .. \
+101001 . .  @PLS_D
+LD  01 00 0--.-- .. \
+111001 . .  @PLS_D
+
 ### Fixed-Point Arithmetic Instructions
 
 ADDI01 10 0--.-- .. \
-- 
2.25.1




[PATCH v3 27/30] target/ppc: Move D/DS/X-form integer loads to decodetree

2021-04-29 Thread Richard Henderson
These are all connected by macros in the legacy decoding.
Decode the D and DS forms into the PLS_D argument set so
that prefixed insns can share code.

Signed-off-by: Richard Henderson 
---
 target/ppc/insn32.decode   |  37 ++
 target/ppc/translate.c | 145 -
 target/ppc/translate/fixedpoint-impl.c.inc | 114 
 3 files changed, 174 insertions(+), 122 deletions(-)

diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index 2ed25c7e67..1c1b4620fc 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -26,6 +26,43 @@
 &PLS_D  rt ra si:int64_t r:bool
 @PLS_D  .. rt:5 ra:5 si:s16 &PLS_D r=0
 
+%ds_si  2:s14  !function=times_4
+@PLS_DS .. rt:5 ra:5 .. ..  &PLS_D si=%ds_si r=0
+
+&X  rt ra rb
+@X  .. rt:5 ra:5 rb:5 .. .  &X
+
+### Fixed-Point Load Instructions
+
+LBZ 100010 . .  @PLS_D
+LBZU100011 . .  @PLS_D
+LBZX01 . . . 0001010111 -   @X
+LBZUX   01 . . . 0001110111 -   @X
+
+LHZ 101000 . .  @PLS_D
+LHZU101001 . .  @PLS_D
+LHZX01 . . . 0100010111 -   @X
+LHZUX   01 . . . 0100110111 -   @X
+
+LHA 101010 . .  @PLS_D
+LHAU101011 . .  @PLS_D
+LHAX01 . . . 0101010111 -   @X
+LHAXU   01 . . . 0101110111 -   @X
+
+LWZ 10 . .  @PLS_D
+LWZU11 . .  @PLS_D
+LWZX01 . . . 010111 -   @X
+LWZUX   01 . . . 110111 -   @X
+
+LWA 111010 . . ..10 @PLS_DS
+LWAX01 . . . 0101010101 -   @X
+LWAUX   01 . . . 0101110101 -   @X
+
+LD  111010 . . ..00 @PLS_DS
+LDU 111010 . . ..01 @PLS_DS
+LDX 01 . . . 010101 -   @X
+LDUX01 . . . 110101 -   @X
+
 ### Fixed-Point Arithmetic Instructions
 
 ADDI001110 . .  @PLS_D
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 5a8a3c39c3..1fdb501ee9 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -2487,54 +2487,6 @@ GEN_QEMU_STORE_64(st64, DEF_MEMOP(MO_Q))
 GEN_QEMU_STORE_64(st64r, BSWAP_MEMOP(MO_Q))
 #endif
 
-#define GEN_LD(name, ldop, opc, type) \
-static void glue(gen_, name)(DisasContext *ctx)   \
-{ \
-TCGv EA;  \
-gen_set_access_type(ctx, ACCESS_INT); \
-EA = tcg_temp_new();  \
-gen_addr_imm_index(ctx, EA, 0);   \
-gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA);   \
-tcg_temp_free(EA);\
-}
-
-#define GEN_LDU(name, ldop, opc, type)\
-static void glue(gen_, name##u)(DisasContext *ctx)\
-{ \
-TCGv EA;  \
-if (unlikely(rA(ctx->opcode) == 0 ||  \
- rA(ctx->opcode) == rD(ctx->opcode))) {   \
-gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);   \
-return;   \
-} \
-gen_set_access_type(ctx, ACCESS_INT); \
-EA = tcg_temp_new();  \
-if (type == PPC_64B)  \
-gen_addr_imm_index(ctx, EA, 0x03);\
-else  \
-gen_addr_imm_index(ctx, EA, 0);   \
-gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA);   \
-tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \
-tcg_temp_free(EA);\
-}
-
-

[PATCH v3 21/30] target/ppc: Use translator_loop_temp_check

2021-04-29 Thread Richard Henderson
The special logging is unnecessary.  It will have been done
immediately before in the log file.

Signed-off-by: Richard Henderson 
---
 target/ppc/translate.c | 6 +-
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index fe3982e289..112afd02d5 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -8046,11 +8046,7 @@ static void ppc_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cs)
 handler->count++;
 #endif
 
-if (tcg_check_temp_count()) {
-qemu_log("Opcode %02x %02x %02x %02x (%08x) leaked "
- "temporaries\n", opc1(ctx->opcode), opc2(ctx->opcode),
- opc3(ctx->opcode), opc4(ctx->opcode), ctx->opcode);
-}
+translator_loop_temp_check(&ctx->base);
 }
 
 static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
-- 
2.25.1




[PATCH v3 24/30] target/ppc: Move page crossing check to ppc_tr_translate_insn

2021-04-29 Thread Richard Henderson
With prefixed instructions, the number of instructions
remaining until the page crossing is no longer constant.

Signed-off-by: Richard Henderson 
---
 target/ppc/translate.c | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 65848463ea..d782a13d27 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -8019,9 +8019,6 @@ static void ppc_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cs)
 
 if (ctx->singlestep_enabled & (CPU_SINGLE_STEP | GDBSTUB_SINGLE_STEP)) {
 ctx->base.max_insns = 1;
-} else {
-int bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
-ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
 }
 }
 
@@ -8098,6 +8095,11 @@ static void ppc_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cs)
 handler->count++;
 #endif
 
+/* End the TB when crossing a page boundary. */
+if (ctx->base.is_jmp == DISAS_NEXT && !(pc & ~TARGET_PAGE_MASK)) {
+ctx->base.is_jmp = DISAS_TOO_MANY;
+}
+
 translator_loop_temp_check(&ctx->base);
 }
 
-- 
2.25.1




[PATCH v3 23/30] target/ppc: Add infrastructure for prefixed insns

2021-04-29 Thread Richard Henderson
Signed-off-by: Luis Pires 
Signed-off-by: Richard Henderson 
---
v3: Move page crossing check to its own patch,
fold in ISA310 check to is_prefix_insn
---
 target/ppc/cpu.h   |  1 +
 target/ppc/insn32.decode   | 18 
 target/ppc/insn64.decode   | 18 
 target/ppc/translate.c | 34 +++---
 target/ppc/translate/fixedpoint-impl.c.inc | 18 
 target/ppc/meson.build |  9 ++
 6 files changed, 94 insertions(+), 4 deletions(-)
 create mode 100644 target/ppc/insn32.decode
 create mode 100644 target/ppc/insn64.decode
 create mode 100644 target/ppc/translate/fixedpoint-impl.c.inc

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 5b22eb64dc..82a2bf1e58 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -144,6 +144,7 @@ enum {
 POWERPC_EXCP_ALIGN_PROT= 0x04,  /* Access cross protection boundary  */
 POWERPC_EXCP_ALIGN_BAT = 0x05,  /* Access cross a BAT/seg boundary   */
 POWERPC_EXCP_ALIGN_CACHE   = 0x06,  /* Impossible dcbz access*/
+POWERPC_EXCP_ALIGN_INSN= 0x07,  /* Pref. insn x-ing 64-byte boundary */
 /* Exception subtypes for POWERPC_EXCP_PROGRAM   */
 /* FP exceptions */
 POWERPC_EXCP_FP= 0x10,
diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
new file mode 100644
index 00..b175441209
--- /dev/null
+++ b/target/ppc/insn32.decode
@@ -0,0 +1,18 @@
+#
+# Power ISA decode for 32-bit insns (opcode space 0)
+#
+# Copyright (c) 2021 Luis Pires 
+#
+# 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 .
+#
diff --git a/target/ppc/insn64.decode b/target/ppc/insn64.decode
new file mode 100644
index 00..9fc45d0614
--- /dev/null
+++ b/target/ppc/insn64.decode
@@ -0,0 +1,18 @@
+#
+# Power ISA decode for 64-bit prefixed insns (opcode space 0 and 1)
+#
+# Copyright (c) 2021 Luis Pires 
+#
+# 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 .
+#
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index cde12e9d38..65848463ea 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -6902,6 +6902,10 @@ static inline void set_avr64(int regno, TCGv_i64 src, 
bool high)
 # define REQUIRE_64BIT(CTX)  REQUIRE_INSNS_FLAGS(CTX, 64B)
 #endif
 
+#include "decode-insn32.c.inc"
+#include "decode-insn64.c.inc"
+#include "translate/fixedpoint-impl.c.inc"
+
 #include "translate/fp-impl.c.inc"
 
 #include "translate/vmx-impl.c.inc"
@@ -8047,11 +8051,18 @@ static bool ppc_tr_breakpoint_check(DisasContextBase 
*dcbase, CPUState *cs,
 return true;
 }
 
+static bool is_prefix_insn(DisasContext *ctx, uint32_t insn)
+{
+REQUIRE_INSNS_FLAGS2(ctx, ISA310);
+return opc1(insn) == 1;
+}
+
 static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
 {
 DisasContext *ctx = container_of(dcbase, DisasContext, base);
 PowerPCCPU *cpu = POWERPC_CPU(cs);
 CPUPPCState *env = cs->env_ptr;
+target_ulong pc;
 uint32_t insn;
 bool ok;
 
@@ -8059,11 +8070,26 @@ static void ppc_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cs)
 LOG_DISAS("nip=" TARGET_FMT_lx " super=%d ir=%d\n",
   ctx->base.pc_next, ctx->mem_idx, (int)msr_ir);
 
-ctx->cia = ctx->base.pc_next;
-insn = translator_ldl_swap(env, ctx->base.pc_next, need_byteswap(ctx));
-ctx->base.pc_next += 4;
+ctx->cia = pc = ctx->base.pc_next;
+insn = translator_ldl_swap(env, pc, need_byteswap(ctx));
+ctx->base.pc_next = pc += 4;
 
-ok = decode_legacy(cpu, ctx, insn);
+if (!is_prefix_insn(ctx, insn)) {
+ok = (decode_insn32(ctx, insn) ||
+  de

[PATCH v3 20/30] target/ppc: Mark helper_raise_exception* as noreturn

2021-04-29 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/ppc/helper.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 6a4dccf70c..af5b3586d1 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -1,5 +1,5 @@
-DEF_HELPER_FLAGS_3(raise_exception_err, TCG_CALL_NO_WG, void, env, i32, i32)
-DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, void, env, i32)
+DEF_HELPER_FLAGS_3(raise_exception_err, TCG_CALL_NO_WG, noreturn, env, i32, 
i32)
+DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32)
 DEF_HELPER_FLAGS_4(tw, TCG_CALL_NO_WG, void, env, tl, tl, i32)
 #if defined(TARGET_PPC64)
 DEF_HELPER_FLAGS_4(td, TCG_CALL_NO_WG, void, env, tl, tl, i32)
-- 
2.25.1




[PATCH v3 30/30] target/ppc: Implement prefixed integer store instructions

2021-04-29 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/ppc/insn64.decode | 12 
 1 file changed, 12 insertions(+)

diff --git a/target/ppc/insn64.decode b/target/ppc/insn64.decode
index 4198e5c8f3..7a71a7a3bb 100644
--- a/target/ppc/insn64.decode
+++ b/target/ppc/insn64.decode
@@ -44,6 +44,18 @@ LWA 01 00 0--.-- .. \
 LD  01 00 0--.-- .. \
 111001 . .  @PLS_D
 
+### Fixed-Point Store Instructions
+
+STW 01 10 0--.-- .. \
+100100 . .  @PLS_D
+STB 01 10 0--.-- .. \
+100110 . .  @PLS_D
+STH 01 10 0--.-- .. \
+101100 . .  @PLS_D
+
+STD 01 00 0--.-- .. \
+01 . .  @PLS_D
+
 ### Fixed-Point Arithmetic Instructions
 
 ADDI01 10 0--.-- .. \
-- 
2.25.1




[PATCH v3 15/30] target/ppc: Replace POWERPC_EXCP_STOP with DISAS_EXIT_UPDATE

2021-04-29 Thread Richard Henderson
Remove the synthetic "exception" after no more uses.

Signed-off-by: Richard Henderson 
---
 target/ppc/cpu.h|  1 -
 linux-user/ppc/cpu_loop.c   |  3 ---
 target/ppc/translate.c  | 20 +---
 target/ppc/translate_init.c.inc |  4 ++--
 4 files changed, 7 insertions(+), 21 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index cf10117065..9bb370abba 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -132,7 +132,6 @@ enum {
 /* EOL   */
 POWERPC_EXCP_NB   = 103,
 /* QEMU exceptions: used internally during code translation  */
-POWERPC_EXCP_STOP = 0x200, /* stop translation   */
 POWERPC_EXCP_BRANCH   = 0x201, /* branch instruction */
 /* QEMU exceptions: special cases we want to stop translation*/
 POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only  */
diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c
index df71e15a25..4c308835bd 100644
--- a/linux-user/ppc/cpu_loop.c
+++ b/linux-user/ppc/cpu_loop.c
@@ -423,9 +423,6 @@ void cpu_loop(CPUPPCState *env)
 cpu_abort(cs, "Maintenance exception while in user mode. "
   "Aborting\n");
 break;
-case POWERPC_EXCP_STOP: /* stop translation  */
-/* We did invalidate the instruction cache. Go on */
-break;
 case POWERPC_EXCP_BRANCH:   /* branch instruction:   */
 /* We just stopped because of a branch. Go on */
 break;
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 45cd3189c0..82fdf0bb77 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -367,13 +367,6 @@ static inline void gen_hvpriv_exception(DisasContext *ctx, 
uint32_t error)
 gen_exception_err(ctx, POWERPC_EXCP_HV_EMU, POWERPC_EXCP_PRIV | error);
 }
 
-/* Stop translation */
-static inline void gen_stop_exception(DisasContext *ctx)
-{
-gen_update_nip(ctx, ctx->base.pc_next);
-ctx->exception = POWERPC_EXCP_STOP;
-}
-
 #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type)  \
 GEN_OPCODE(name, opc1, opc2, opc3, inval, type, PPC_NONE)
 
@@ -3157,7 +3150,7 @@ static void gen_isync(DisasContext *ctx)
 gen_check_tlb_flush(ctx, false);
 }
 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
-gen_stop_exception(ctx);
+ctx->base.is_jmp = DISAS_EXIT_UPDATE;
 }
 
 #define MEMOP_GET_SIZE(x)  (1 << ((x) & MO_SIZE))
@@ -4434,7 +4427,7 @@ static void gen_mtmsrd(DisasContext *ctx)
 gen_helper_store_msr(cpu_env, cpu_gpr[rS(ctx->opcode)]);
 }
 /* Must stop the translation as machine state (may have) changed */
-gen_stop_exception(ctx);
+ctx->base.is_jmp = DISAS_EXIT_UPDATE;
 #endif /* !defined(CONFIG_USER_ONLY) */
 }
 #endif /* defined(TARGET_PPC64) */
@@ -4477,7 +4470,7 @@ static void gen_mtmsr(DisasContext *ctx)
 tcg_temp_free(msr);
 }
 /* Must stop the translation as machine state (may have) changed */
-gen_stop_exception(ctx);
+ctx->base.is_jmp = DISAS_EXIT_UPDATE;
 #endif
 }
 
@@ -6614,7 +6607,7 @@ static void gen_wrtee(DisasContext *ctx)
  * Stop translation to have a chance to raise an exception if we
  * just set msr_ee to 1
  */
-gen_stop_exception(ctx);
+ctx->base.is_jmp = DISAS_EXIT_UPDATE;
 #endif /* defined(CONFIG_USER_ONLY) */
 }
 
@@ -6628,7 +6621,7 @@ static void gen_wrteei(DisasContext *ctx)
 if (ctx->opcode & 0x8000) {
 tcg_gen_ori_tl(cpu_msr, cpu_msr, (1 << MSR_EE));
 /* Stop translation to have a chance to raise an exception */
-gen_stop_exception(ctx);
+ctx->base.is_jmp = DISAS_EXIT_UPDATE;
 } else {
 tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE));
 }
@@ -8083,9 +8076,6 @@ static void ppc_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cs)
 case POWERPC_EXCP_BRANCH:
 ctx->base.is_jmp = DISAS_NORETURN;
 break;
-case POWERPC_EXCP_STOP:
-ctx->base.is_jmp = DISAS_EXIT;
-break;
 default:
 /* Every other ctx->exception should have set NORETURN. */
 g_assert_not_reached();
diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc
index 9af3fb2066..f3e79b8685 100644
--- a/target/ppc/translate_init.c.inc
+++ b/target/ppc/translate_init.c.inc
@@ -463,7 +463,7 @@ static void spr_write_hid0_601(DisasContext *ctx, int sprn, 
int gprn)
 {
 gen_helper_store_hid0_601(cpu_env, cpu_gpr[gprn]);
 /* Must stop the translation as endianness may have changed */
-gen_stop_exception(ctx);
+ctx->base.is_jmp = DISAS_EXIT_UPDATE;
 }
 #endif
 
@@ -511,7 +511,7 @@ static void spr_write_40x_dbcr0(DisasContext *ctx, int 
sprn, int gprn)
 gen_store_spr(sprn, cpu_gpr[gprn]);
 gen_helper_store_40x

[PATCH v3 17/30] target/ppc: Remove DisasContext.exception

2021-04-29 Thread Richard Henderson
Now that we have removed all of the fake exceptions, and all real
exceptions exit via DISAS_NORETURN, we can remove this field.

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

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 276a4a2a79..d78071a4a4 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -259,15 +259,12 @@ static void gen_exception_err(DisasContext *ctx, uint32_t 
excp, uint32_t error)
  * These are all synchronous exceptions, we set the PC back to the
  * faulting instruction
  */
-if (ctx->exception == POWERPC_EXCP_NONE) {
-gen_update_nip(ctx, ctx->cia);
-}
+gen_update_nip(ctx, ctx->cia);
 t0 = tcg_const_i32(excp);
 t1 = tcg_const_i32(error);
 gen_helper_raise_exception_err(cpu_env, t0, t1);
 tcg_temp_free_i32(t0);
 tcg_temp_free_i32(t1);
-ctx->exception = excp;
 ctx->base.is_jmp = DISAS_NORETURN;
 }
 
@@ -279,13 +276,10 @@ static void gen_exception(DisasContext *ctx, uint32_t 
excp)
  * These are all synchronous exceptions, we set the PC back to the
  * faulting instruction
  */
-if (ctx->exception == POWERPC_EXCP_NONE) {
-gen_update_nip(ctx, ctx->cia);
-}
+gen_update_nip(ctx, ctx->cia);
 t0 = tcg_const_i32(excp);
 gen_helper_raise_exception(cpu_env, t0);
 tcg_temp_free_i32(t0);
-ctx->exception = excp;
 ctx->base.is_jmp = DISAS_NORETURN;
 }
 
@@ -298,7 +292,6 @@ static void gen_exception_nip(DisasContext *ctx, uint32_t 
excp,
 t0 = tcg_const_i32(excp);
 gen_helper_raise_exception(cpu_env, t0);
 tcg_temp_free_i32(t0);
-ctx->exception = excp;
 ctx->base.is_jmp = DISAS_NORETURN;
 }
 
@@ -7919,7 +7912,6 @@ static void ppc_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cs)
 CPUPPCState *env = cs->env_ptr;
 int bound;
 
-ctx->exception = POWERPC_EXCP_NONE;
 ctx->spr_cb = env->spr_cb;
 ctx->pr = msr_pr;
 ctx->mem_idx = env->dmmu_idx;
@@ -8067,16 +8059,6 @@ static void ppc_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cs)
  "temporaries\n", opc1(ctx->opcode), opc2(ctx->opcode),
  opc3(ctx->opcode), opc4(ctx->opcode), ctx->opcode);
 }
-
-if (ctx->base.is_jmp == DISAS_NEXT) {
-switch (ctx->exception) {
-case POWERPC_EXCP_NONE:
-break;
-default:
-/* Every other ctx->exception should have set NORETURN. */
-g_assert_not_reached();
-}
-}
 }
 
 static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
-- 
2.25.1




[PATCH v3 19/30] target/ppc: Tidy exception vs exit_tb

2021-04-29 Thread Richard Henderson
We do not need to emit an exit_tb after an exception,
as the latter will exit via longjmp.

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

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index c018960ce9..fe3982e289 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -3726,8 +3726,9 @@ static void gen_lookup_and_goto_ptr(DisasContext *ctx)
 } else if (sse & (CPU_SINGLE_STEP | CPU_BRANCH_STEP)) {
 uint32_t excp = gen_prep_dbgex(ctx);
 gen_exception(ctx, excp);
+} else {
+tcg_gen_exit_tb(NULL, 0);
 }
-tcg_gen_exit_tb(NULL, 0);
 } else {
 tcg_gen_lookup_and_goto_ptr();
 }
-- 
2.25.1




[PATCH v3 26/30] target/ppc: Implement PNOP

2021-04-29 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/ppc/insn32.decode   |  2 ++
 target/ppc/insn64.decode   | 11 +++
 target/ppc/translate/fixedpoint-impl.c.inc |  5 +
 3 files changed, 18 insertions(+)

diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index 52d9b355d4..2ed25c7e67 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -17,6 +17,8 @@
 # License along with this library; if not, see .
 #
 
+&empty
+
 &D  rt ra si
 @D  .. rt:5 ra:5 si:s16 &D
 
diff --git a/target/ppc/insn64.decode b/target/ppc/insn64.decode
index f4272df724..5a82ce375e 100644
--- a/target/ppc/insn64.decode
+++ b/target/ppc/insn64.decode
@@ -20,6 +20,8 @@
 # Many all of these instruction names would be prefixed by "P",
 # but we share code with the non-prefixed instruction.
 
+&empty  !extern
+
 # Format MLS:D and 8LS:D
 &PLS_D  rt ra si:int64_t r:bool  !extern
 %pls_si 32:s18 0:16
@@ -31,3 +33,12 @@
 
 ADDI01 10 0--.-- .. \
 001110 . .  @PLS_D
+
+### Prefixed No-operation Instruction
+
+# TODO: diagnose the set of patterns that are illegal:
+# branches, rfebb, sync other than isync, or a service processor attention.
+# The Engineering Note allows us to either diagnose these as illegal,
+# or treat them all as no-op.
+NOP 01 11 -- 00 \
+
diff --git a/target/ppc/translate/fixedpoint-impl.c.inc 
b/target/ppc/translate/fixedpoint-impl.c.inc
index 7af1b3bcf5..96b8c38f60 100644
--- a/target/ppc/translate/fixedpoint-impl.c.inc
+++ b/target/ppc/translate/fixedpoint-impl.c.inc
@@ -55,3 +55,8 @@ static bool trans_ADDIS(DisasContext *ctx, arg_D *a)
 }
 return true;
 }
+
+static bool trans_NOP(DisasContext *ctx, arg_NOP *a)
+{
+return true;
+}
-- 
2.25.1




[PATCH v3 16/30] target/ppc: Replace POWERPC_EXCP_BRANCH with DISAS_NORETURN

2021-04-29 Thread Richard Henderson
The translation of branch instructions always results in exit from
the TB.  Remove the synthetic "exception" after no more uses.

Signed-off-by: Richard Henderson 
---
 target/ppc/cpu.h  | 2 --
 linux-user/ppc/cpu_loop.c | 3 ---
 target/ppc/translate.c| 8 ++--
 3 files changed, 2 insertions(+), 11 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 9bb370abba..5b22eb64dc 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -131,8 +131,6 @@ enum {
 POWERPC_EXCP_SYSCALL_VECTORED = 102, /* scv exception 
*/
 /* EOL   */
 POWERPC_EXCP_NB   = 103,
-/* QEMU exceptions: used internally during code translation  */
-POWERPC_EXCP_BRANCH   = 0x201, /* branch instruction */
 /* QEMU exceptions: special cases we want to stop translation*/
 POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only  */
 };
diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c
index 4c308835bd..adf5a8a4e6 100644
--- a/linux-user/ppc/cpu_loop.c
+++ b/linux-user/ppc/cpu_loop.c
@@ -423,9 +423,6 @@ void cpu_loop(CPUPPCState *env)
 cpu_abort(cs, "Maintenance exception while in user mode. "
   "Aborting\n");
 break;
-case POWERPC_EXCP_BRANCH:   /* branch instruction:   */
-/* We just stopped because of a branch. Go on */
-break;
 case POWERPC_EXCP_SYSCALL_USER:
 /* system call in user-mode emulation */
 /* WARNING:
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 82fdf0bb77..276a4a2a79 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -3769,7 +3769,6 @@ static void gen_b(DisasContext *ctx)
 {
 target_ulong li, target;
 
-ctx->exception = POWERPC_EXCP_BRANCH;
 /* sign extend LI */
 li = LI(ctx->opcode);
 li = (li ^ 0x0200) - 0x0200;
@@ -3783,6 +3782,7 @@ static void gen_b(DisasContext *ctx)
 }
 gen_update_cfar(ctx, ctx->cia);
 gen_goto_tb(ctx, 0, target);
+ctx->base.is_jmp = DISAS_NORETURN;
 }
 
 #define BCOND_IM  0
@@ -3795,7 +3795,6 @@ static void gen_bcond(DisasContext *ctx, int type)
 uint32_t bo = BO(ctx->opcode);
 TCGLabel *l1;
 TCGv target;
-ctx->exception = POWERPC_EXCP_BRANCH;
 
 if (type == BCOND_LR || type == BCOND_CTR || type == BCOND_TAR) {
 target = tcg_temp_local_new();
@@ -3902,6 +3901,7 @@ static void gen_bcond(DisasContext *ctx, int type)
 gen_set_label(l1);
 gen_goto_tb(ctx, 1, ctx->base.pc_next);
 }
+ctx->base.is_jmp = DISAS_NORETURN;
 }
 
 static void gen_bc(DisasContext *ctx)
@@ -8057,7 +8057,6 @@ static void ppc_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cs)
 /* Check trace mode exceptions */
 if (unlikely(ctx->singlestep_enabled & CPU_SINGLE_STEP &&
  (ctx->base.pc_next <= 0x100 || ctx->base.pc_next > 0xF00) &&
- ctx->exception != POWERPC_EXCP_BRANCH &&
  ctx->base.is_jmp != DISAS_NORETURN)) {
 uint32_t excp = gen_prep_dbgex(ctx);
 gen_exception_nip(ctx, excp, ctx->base.pc_next);
@@ -8073,9 +8072,6 @@ static void ppc_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cs)
 switch (ctx->exception) {
 case POWERPC_EXCP_NONE:
 break;
-case POWERPC_EXCP_BRANCH:
-ctx->base.is_jmp = DISAS_NORETURN;
-break;
 default:
 /* Every other ctx->exception should have set NORETURN. */
 g_assert_not_reached();
-- 
2.25.1




[PATCH v3 14/30] target/ppc: Introduce gen_icount_io_start

2021-04-29 Thread Richard Henderson
Create a function to handle the details for interacting with icount.

Force the exit from the tb via DISAS_TOO_MANY, which allows chaining
to the next tb, where the code emitted for gen_tb_start() will
determine if we must exit.  We can thus remove any matching
conditional call to gen_stop_exception.

Signed-off-by: Richard Henderson 
---
 target/ppc/translate.c  |  41 +-
 target/ppc/translate_init.c.inc | 133 +---
 2 files changed, 39 insertions(+), 135 deletions(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index d22d6e5b85..45cd3189c0 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -302,6 +302,20 @@ static void gen_exception_nip(DisasContext *ctx, uint32_t 
excp,
 ctx->base.is_jmp = DISAS_NORETURN;
 }
 
+static void gen_icount_io_start(DisasContext *ctx)
+{
+if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+gen_io_start();
+/*
+ * An I/O instruction must be last in the TB.
+ * Chain to the next TB, and let the code from gen_tb_start
+ * decide if we need to return to the main loop.
+ * Doing this first also allows this value to be overridden.
+ */
+ctx->base.is_jmp = DISAS_TOO_MANY;
+}
+}
+
 /*
  * Tells the caller what is the appropriate exception to generate and prepares
  * SPR registers for this exception.
@@ -1842,18 +1856,13 @@ static void gen_darn(DisasContext *ctx)
 if (l > 2) {
 tcg_gen_movi_i64(cpu_gpr[rD(ctx->opcode)], -1);
 } else {
-if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_io_start();
-}
+gen_icount_io_start(ctx);
 if (l == 0) {
 gen_helper_darn32(cpu_gpr[rD(ctx->opcode)]);
 } else {
 /* Return 64-bit random for both CRN and RRN */
 gen_helper_darn64(cpu_gpr[rD(ctx->opcode)]);
 }
-if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_stop_exception(ctx);
-}
 }
 }
 #endif
@@ -3995,9 +4004,7 @@ static void gen_rfi(DisasContext *ctx)
 }
 /* Restore CPU state */
 CHK_SV;
-if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_io_start();
-}
+gen_icount_io_start(ctx);
 gen_update_cfar(ctx, ctx->cia);
 gen_helper_rfi(cpu_env);
 ctx->base.is_jmp = DISAS_EXIT;
@@ -4012,9 +4019,7 @@ static void gen_rfid(DisasContext *ctx)
 #else
 /* Restore CPU state */
 CHK_SV;
-if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_io_start();
-}
+gen_icount_io_start(ctx);
 gen_update_cfar(ctx, ctx->cia);
 gen_helper_rfid(cpu_env);
 ctx->base.is_jmp = DISAS_EXIT;
@@ -4029,9 +4034,7 @@ static void gen_rfscv(DisasContext *ctx)
 #else
 /* Restore CPU state */
 CHK_SV;
-if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_io_start();
-}
+gen_icount_io_start(ctx);
 gen_update_cfar(ctx, ctx->cia);
 gen_helper_rfscv(cpu_env);
 ctx->base.is_jmp = DISAS_EXIT;
@@ -4406,9 +4409,7 @@ static void gen_mtmsrd(DisasContext *ctx)
 CHK_SV;
 
 #if !defined(CONFIG_USER_ONLY)
-if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_io_start();
-}
+gen_icount_io_start(ctx);
 if (ctx->opcode & 0x0001) {
 /* L=1 form only updates EE and RI */
 TCGv t0 = tcg_temp_new();
@@ -4443,9 +,7 @@ static void gen_mtmsr(DisasContext *ctx)
 CHK_SV;
 
 #if !defined(CONFIG_USER_ONLY)
-if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_io_start();
-}
+gen_icount_io_start(ctx);
 if (ctx->opcode & 0x0001) {
 /* L=1 form only updates EE and RI */
 TCGv t0 = tcg_temp_new();
diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc
index 99e5f52925..9af3fb2066 100644
--- a/target/ppc/translate_init.c.inc
+++ b/target/ppc/translate_init.c.inc
@@ -183,24 +183,14 @@ static void spr_write_ureg(DisasContext *ctx, int sprn, 
int gprn)
 #if !defined(CONFIG_USER_ONLY)
 static void spr_read_decr(DisasContext *ctx, int gprn, int sprn)
 {
-if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_io_start();
-}
+gen_icount_io_start(ctx);
 gen_helper_load_decr(cpu_gpr[gprn], cpu_env);
-if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_stop_exception(ctx);
-}
 }
 
 static void spr_write_decr(DisasContext *ctx, int sprn, int gprn)
 {
-if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_io_start();
-}
+gen_icount_io_start(ctx);
 gen_helper_store_decr(cpu_env, cpu_gpr[gprn]);
-if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_stop_exception(ctx);
-}
 }
 #endif
 
@@ -208,24 +198,14 @@ static void spr_write_decr(DisasContext *ctx, int sprn, 
int gprn)
 /* Time base */
 static void spr_read_tbl(DisasContext *ctx, int gprn, int sprn)
 {
-if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_io_start();
-}
+gen_icount_io_start(ctx);
 gen_helper_l

[PATCH v3 18/30] target/ppc: Move single-step check to ppc_tr_tb_stop

2021-04-29 Thread Richard Henderson
When single-stepping, force max_insns to 1 in init_disas
so that we exit the translation loop immediately.

Combine the single-step checks in tb_stop, and give the
gdb exception priority over the cpu exception, just as
we already do in gen_lookup_and_goto_ptr.

Signed-off-by: Richard Henderson 
---
 target/ppc/translate.c | 37 +++--
 1 file changed, 19 insertions(+), 18 deletions(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index d78071a4a4..c018960ce9 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -7910,7 +7910,6 @@ static void ppc_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cs)
 {
 DisasContext *ctx = container_of(dcbase, DisasContext, base);
 CPUPPCState *env = cs->env_ptr;
-int bound;
 
 ctx->spr_cb = env->spr_cb;
 ctx->pr = msr_pr;
@@ -7986,13 +7985,13 @@ static void ppc_tr_init_disas_context(DisasContextBase 
*dcbase, CPUState *cs)
 if (unlikely(ctx->base.singlestep_enabled)) {
 ctx->singlestep_enabled |= GDBSTUB_SINGLE_STEP;
 }
-#if defined(DO_SINGLE_STEP) && 0
-/* Single step trace mode */
-msr_se = 1;
-#endif
 
-bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
-ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
+if (ctx->singlestep_enabled & (CPU_SINGLE_STEP | GDBSTUB_SINGLE_STEP)) {
+ctx->base.max_insns = 1;
+} else {
+int bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
+ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
+}
 }
 
 static void ppc_tr_tb_start(DisasContextBase *db, CPUState *cs)
@@ -8046,14 +8045,6 @@ static void ppc_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cs)
 handler->count++;
 #endif
 
-/* Check trace mode exceptions */
-if (unlikely(ctx->singlestep_enabled & CPU_SINGLE_STEP &&
- (ctx->base.pc_next <= 0x100 || ctx->base.pc_next > 0xF00) &&
- ctx->base.is_jmp != DISAS_NORETURN)) {
-uint32_t excp = gen_prep_dbgex(ctx);
-gen_exception_nip(ctx, excp, ctx->base.pc_next);
-}
-
 if (tcg_check_temp_count()) {
 qemu_log("Opcode %02x %02x %02x %02x (%08x) leaked "
  "temporaries\n", opc1(ctx->opcode), opc2(ctx->opcode),
@@ -8066,6 +8057,7 @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, 
CPUState *cs)
 DisasContext *ctx = container_of(dcbase, DisasContext, base);
 DisasJumpType is_jmp = ctx->base.is_jmp;
 target_ulong nip = ctx->base.pc_next;
+int sse;
 
 if (is_jmp == DISAS_NORETURN) {
 /* We have already exited the TB. */
@@ -8073,7 +8065,8 @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, 
CPUState *cs)
 }
 
 /* Honor single stepping. */
-if (unlikely(ctx->base.singlestep_enabled)) {
+sse = ctx->singlestep_enabled & (CPU_SINGLE_STEP | GDBSTUB_SINGLE_STEP);
+if (unlikely(sse)) {
 switch (is_jmp) {
 case DISAS_TOO_MANY:
 case DISAS_EXIT_UPDATE:
@@ -8086,8 +8079,16 @@ static void ppc_tr_tb_stop(DisasContextBase *dcbase, 
CPUState *cs)
 default:
 g_assert_not_reached();
 }
-gen_debug_exception(ctx);
-return;
+
+if (sse & GDBSTUB_SINGLE_STEP) {
+gen_debug_exception(ctx);
+return;
+}
+/* else CPU_SINGLE_STEP... */
+if (nip <= 0x100 || nip > 0xf00) {
+gen_exception(ctx, gen_prep_dbgex(ctx));
+return;
+}
 }
 
 switch (is_jmp) {
-- 
2.25.1




[PATCH v3 22/30] target/ppc: Introduce macros to check isa extensions

2021-04-29 Thread Richard Henderson
These will be used by the decodetree trans_* functions
to early-exit when the instruction set is not enabled.

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

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 112afd02d5..cde12e9d38 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -6876,6 +6876,32 @@ static inline void set_avr64(int regno, TCGv_i64 src, 
bool high)
 tcg_gen_st_i64(src, cpu_env, avr64_offset(regno, high));
 }
 
+/*
+ * Helpers for trans_* functions to check for specific insns flags.
+ * Use token pasting to ensure that we use the proper flag with the
+ * proper variable.
+ */
+#define REQUIRE_INSNS_FLAGS(CTX, NAME) \
+do {\
+if (((CTX)->insns_flags & PPC_##NAME) == 0) {   \
+return false;   \
+}   \
+} while (0)
+
+#define REQUIRE_INSNS_FLAGS2(CTX, NAME) \
+do {\
+if (((CTX)->insns_flags2 & PPC2_##NAME) == 0) { \
+return false;   \
+}   \
+} while (0)
+
+/* Then special-case the check for 64-bit so that we elide code for ppc32. */
+#if TARGET_LONG_BITS == 32
+# define REQUIRE_64BIT(CTX)  return false
+#else
+# define REQUIRE_64BIT(CTX)  REQUIRE_INSNS_FLAGS(CTX, 64B)
+#endif
+
 #include "translate/fp-impl.c.inc"
 
 #include "translate/vmx-impl.c.inc"
-- 
2.25.1




[PATCH v3 07/30] target/ppc: Move DISAS_NORETURN setting into gen_exception*

2021-04-29 Thread Richard Henderson
There are other valid settings for is_jmp besides
DISAS_NEXT and DISAS_NORETURN, so eliminating that
dichotomy from ppc_tr_translate_insn is helpful.

Signed-off-by: Richard Henderson 
---
v3: Retain an exit from translator loop for ctx->exception.
Do not emit code for single-step or ppc_tr_tb_stop for NORETURN.
---
 target/ppc/translate.c | 26 ++
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index ebe5afe7ae..3607cc12f3 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -262,7 +262,8 @@ static void gen_exception_err(DisasContext *ctx, uint32_t 
excp, uint32_t error)
 gen_helper_raise_exception_err(cpu_env, t0, t1);
 tcg_temp_free_i32(t0);
 tcg_temp_free_i32(t1);
-ctx->exception = (excp);
+ctx->exception = excp;
+ctx->base.is_jmp = DISAS_NORETURN;
 }
 
 static void gen_exception(DisasContext *ctx, uint32_t excp)
@@ -279,7 +280,8 @@ static void gen_exception(DisasContext *ctx, uint32_t excp)
 t0 = tcg_const_i32(excp);
 gen_helper_raise_exception(cpu_env, t0);
 tcg_temp_free_i32(t0);
-ctx->exception = (excp);
+ctx->exception = excp;
+ctx->base.is_jmp = DISAS_NORETURN;
 }
 
 static void gen_exception_nip(DisasContext *ctx, uint32_t excp,
@@ -291,7 +293,8 @@ static void gen_exception_nip(DisasContext *ctx, uint32_t 
excp,
 t0 = tcg_const_i32(excp);
 gen_helper_raise_exception(cpu_env, t0);
 tcg_temp_free_i32(t0);
-ctx->exception = (excp);
+ctx->exception = excp;
+ctx->base.is_jmp = DISAS_NORETURN;
 }
 
 /*
@@ -337,6 +340,7 @@ static void gen_debug_exception(DisasContext *ctx)
 t0 = tcg_const_i32(EXCP_DEBUG);
 gen_helper_raise_exception(cpu_env, t0);
 tcg_temp_free_i32(t0);
+ctx->base.is_jmp = DISAS_NORETURN;
 }
 
 static inline void gen_inval_exception(DisasContext *ctx, uint32_t error)
@@ -8037,7 +8041,6 @@ static bool ppc_tr_breakpoint_check(DisasContextBase 
*dcbase, CPUState *cs,
 DisasContext *ctx = container_of(dcbase, DisasContext, base);
 
 gen_debug_exception(ctx);
-dcbase->is_jmp = DISAS_NORETURN;
 /*
  * The address covered by the breakpoint must be included in
  * [tb->pc, tb->pc + tb->size) in order to for it to be properly
@@ -8067,18 +8070,19 @@ static void ppc_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cs)
 ok = decode_legacy(cpu, ctx, insn);
 if (!ok) {
 gen_invalid(ctx);
-ctx->base.is_jmp = DISAS_NORETURN;
 }
 
 #if defined(DO_PPC_STATISTICS)
 handler->count++;
 #endif
+
 /* Check trace mode exceptions */
 if (unlikely(ctx->singlestep_enabled & CPU_SINGLE_STEP &&
  (ctx->base.pc_next <= 0x100 || ctx->base.pc_next > 0xF00) &&
  ctx->exception != POWERPC_SYSCALL &&
  ctx->exception != POWERPC_EXCP_TRAP &&
- ctx->exception != POWERPC_EXCP_BRANCH)) {
+ ctx->exception != POWERPC_EXCP_BRANCH &&
+ ctx->base.is_jmp != DISAS_NORETURN)) {
 uint32_t excp = gen_prep_dbgex(ctx);
 gen_exception_nip(ctx, excp, ctx->base.pc_next);
 }
@@ -8089,14 +8093,20 @@ static void ppc_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cs)
  opc3(ctx->opcode), opc4(ctx->opcode), ctx->opcode);
 }
 
-ctx->base.is_jmp = ctx->exception == POWERPC_EXCP_NONE ?
-DISAS_NEXT : DISAS_NORETURN;
+if (ctx->base.is_jmp == DISAS_NEXT
+&& ctx->exception != POWERPC_EXCP_NONE) {
+ctx->base.is_jmp = DISAS_TOO_MANY;
+}
 }
 
 static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
 {
 DisasContext *ctx = container_of(dcbase, DisasContext, base);
 
+if (ctx->base.is_jmp == DISAS_NORETURN) {
+return;
+}
+
 if (ctx->exception == POWERPC_EXCP_NONE) {
 gen_goto_tb(ctx, 0, ctx->base.pc_next);
 } else if (ctx->exception != POWERPC_EXCP_BRANCH) {
-- 
2.25.1




[PATCH v3 09/30] target/ppc: Remove special case for POWERPC_EXCP_TRAP

2021-04-29 Thread Richard Henderson
Since POWERPC_EXCP_TRAP is raised by gen_exception_err,
we will have also set DISAS_NORETURN.

Signed-off-by: Richard Henderson 
---
 target/ppc/translate.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index b26b6964a7..5efa4d6566 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -8079,7 +8079,6 @@ static void ppc_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cs)
 /* Check trace mode exceptions */
 if (unlikely(ctx->singlestep_enabled & CPU_SINGLE_STEP &&
  (ctx->base.pc_next <= 0x100 || ctx->base.pc_next > 0xF00) &&
- ctx->exception != POWERPC_EXCP_TRAP &&
  ctx->exception != POWERPC_EXCP_BRANCH &&
  ctx->base.is_jmp != DISAS_NORETURN)) {
 uint32_t excp = gen_prep_dbgex(ctx);
-- 
2.25.1




[PATCH v3 02/30] decodetree: More use of f-strings

2021-04-29 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 scripts/decodetree.py | 50 ---
 1 file changed, 23 insertions(+), 27 deletions(-)

diff --git a/scripts/decodetree.py b/scripts/decodetree.py
index 0861e5d503..d5da101167 100644
--- a/scripts/decodetree.py
+++ b/scripts/decodetree.py
@@ -59,9 +59,9 @@ def error_with_file(file, lineno, *args):
 
 prefix = ''
 if file:
-prefix += '{0}:'.format(file)
+prefix += f'{file}:'
 if lineno:
-prefix += '{0}:'.format(lineno)
+prefix += f'{lineno}:'
 if prefix:
 prefix += ' '
 print(prefix, end='error: ', file=sys.stderr)
@@ -203,7 +203,7 @@ def str_extract(self):
 extr = 'sextract32'
 else:
 extr = 'extract32'
-return '{0}(insn, {1}, {2})'.format(extr, self.pos, self.len)
+return f'{extr}(insn, {self.pos}, {self.len})'
 
 def __eq__(self, other):
 return self.sign == other.sign and self.mask == other.mask
@@ -227,11 +227,11 @@ def str_extract(self):
 ret = '0'
 pos = 0
 for f in reversed(self.subs):
+ext = f.str_extract()
 if pos == 0:
-ret = f.str_extract()
+ret = ext
 else:
-ret = 'deposit32({0}, {1}, {2}, {3})' \
-  .format(ret, pos, 32 - pos, f.str_extract())
+ret = f'deposit32({ret}, {pos}, {32 - pos}, {ext})'
 pos += f.len
 return ret
 
@@ -675,11 +675,11 @@ def parse_field(lineno, name, toks):
 subtoks = t.split(':')
 sign = False
 else:
-error(lineno, 'invalid field token "{0}"'.format(t))
+error(lineno, f'invalid field token "{t}"')
 po = int(subtoks[0])
 le = int(subtoks[1])
 if po + le > insnwidth:
-error(lineno, 'field {0} too large'.format(t))
+error(lineno, f'field {t} too large')
 f = Field(sign, po, le)
 subs.append(f)
 width += le
@@ -724,9 +724,9 @@ def parse_arguments(lineno, name, toks):
 anyextern = True
 continue
 if not re.fullmatch(re_C_ident, t):
-error(lineno, 'invalid argument set token "{0}"'.format(t))
+error(lineno, f'invalid argument set token "{t}"')
 if t in flds:
-error(lineno, 'duplicate argument "{0}"'.format(t))
+error(lineno, f'duplicate argument "{t}"')
 flds.append(t)
 
 if name in arguments:
@@ -895,14 +895,14 @@ def parse_generic(lineno, parent_pat, name, toks):
 flen = flen[1:]
 shift = int(flen, 10)
 if shift + width > insnwidth:
-error(lineno, 'field {0} exceeds insnwidth'.format(fname))
+error(lineno, f'field {fname} exceeds insnwidth')
 f = Field(sign, insnwidth - width - shift, shift)
 flds = add_field(lineno, flds, fname, f)
 fixedbits <<= shift
 fixedmask <<= shift
 undefmask <<= shift
 else:
-error(lineno, 'invalid token "{0}"'.format(t))
+error(lineno, f'invalid token "{t}"')
 width += shift
 
 if variablewidth and width < insnwidth and width % 8 == 0:
@@ -914,7 +914,7 @@ def parse_generic(lineno, parent_pat, name, toks):
 
 # We should have filled in all of the bits of the instruction.
 elif not (is_format and width == 0) and width != insnwidth:
-error(lineno, 'definition has {0} bits'.format(width))
+error(lineno, f'definition has {width} bits')
 
 # Do not check for fields overlapping fields; one valid usage
 # is to be able to duplicate fields via import.
@@ -932,8 +932,7 @@ def parse_generic(lineno, parent_pat, name, toks):
 if arg:
 for f in flds.keys():
 if f not in arg.fields:
-error(lineno, 'field {0} not in argument set {1}'
-  .format(f, arg.name))
+error(lineno, f'field {f} not in argument set {arg.name}')
 else:
 arg = infer_argument_set(flds)
 if name in formats:
@@ -960,13 +959,12 @@ def parse_generic(lineno, parent_pat, name, toks):
 arg = fmt.base
 for f in flds.keys():
 if f not in arg.fields:
-error(lineno, 'field {0} not in argument set {1}'
-  .format(f, arg.name))
+error(lineno, f'field {f} not in argument set {arg.name}')
 if f in fmt.fields.keys():
-error(lineno, 'field {0} set by format and pattern'.format(f))
+error(lineno, f'field {f} set by format and pattern')
 for f in arg.fields:
 if f not in flds.keys() and f not in fmt.fields.keys():
-error(lineno, 'field {0} not initialized'.format(f))
+error(lineno, f'field {f} not initialized')
  

[PATCH v3 13/30] target/ppc: Remove unnecessary gen_io_end calls

2021-04-29 Thread Richard Henderson
Since ba3e7926691ed33, we switched the implementation of icount
to always reset can_do_io at the start of the following TB.
Most of them were removed in 9e9b10c64911, but some were missed.

Signed-off-by: Richard Henderson 
---
 target/ppc/translate_init.c.inc | 6 --
 1 file changed, 6 deletions(-)

diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc
index c03a7c4f52..99e5f52925 100644
--- a/target/ppc/translate_init.c.inc
+++ b/target/ppc/translate_init.c.inc
@@ -213,7 +213,6 @@ static void spr_read_tbl(DisasContext *ctx, int gprn, int 
sprn)
 }
 gen_helper_load_tbl(cpu_gpr[gprn], cpu_env);
 if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_io_end();
 gen_stop_exception(ctx);
 }
 }
@@ -225,7 +224,6 @@ static void spr_read_tbu(DisasContext *ctx, int gprn, int 
sprn)
 }
 gen_helper_load_tbu(cpu_gpr[gprn], cpu_env);
 if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_io_end();
 gen_stop_exception(ctx);
 }
 }
@@ -250,7 +248,6 @@ static void spr_write_tbl(DisasContext *ctx, int sprn, int 
gprn)
 }
 gen_helper_store_tbl(cpu_env, cpu_gpr[gprn]);
 if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_io_end();
 gen_stop_exception(ctx);
 }
 }
@@ -262,7 +259,6 @@ static void spr_write_tbu(DisasContext *ctx, int sprn, int 
gprn)
 }
 gen_helper_store_tbu(cpu_env, cpu_gpr[gprn]);
 if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_io_end();
 gen_stop_exception(ctx);
 }
 }
@@ -311,7 +307,6 @@ static void spr_read_hdecr(DisasContext *ctx, int gprn, int 
sprn)
 }
 gen_helper_load_hdecr(cpu_gpr[gprn], cpu_env);
 if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_io_end();
 gen_stop_exception(ctx);
 }
 }
@@ -323,7 +318,6 @@ static void spr_write_hdecr(DisasContext *ctx, int sprn, 
int gprn)
 }
 gen_helper_store_hdecr(cpu_env, cpu_gpr[gprn]);
 if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
-gen_io_end();
 gen_stop_exception(ctx);
 }
 }
-- 
2.25.1




[PATCH v3 06/30] target/ppc: Split out decode_legacy

2021-04-29 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/ppc/translate.c | 115 +++--
 1 file changed, 64 insertions(+), 51 deletions(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index ee25badba2..ebe5afe7ae 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -7876,6 +7876,62 @@ void ppc_cpu_dump_statistics(CPUState *cs, int flags)
 #endif
 }
 
+static bool decode_legacy(PowerPCCPU *cpu, DisasContext *ctx, uint32_t insn)
+{
+opc_handler_t **table, *handler;
+uint32_t inval;
+
+ctx->opcode = insn;
+
+LOG_DISAS("translate opcode %08x (%02x %02x %02x %02x) (%s)\n",
+  insn, opc1(insn), opc2(insn), opc3(insn), opc4(insn),
+  ctx->le_mode ? "little" : "big");
+
+table = cpu->opcodes;
+handler = table[opc1(insn)];
+if (is_indirect_opcode(handler)) {
+table = ind_table(handler);
+handler = table[opc2(insn)];
+if (is_indirect_opcode(handler)) {
+table = ind_table(handler);
+handler = table[opc3(insn)];
+if (is_indirect_opcode(handler)) {
+table = ind_table(handler);
+handler = table[opc4(insn)];
+}
+}
+}
+
+/* Is opcode *REALLY* valid ? */
+if (unlikely(handler->handler == &gen_invalid)) {
+qemu_log_mask(LOG_GUEST_ERROR, "invalid/unsupported opcode: "
+  "%02x - %02x - %02x - %02x (%08x) "
+  TARGET_FMT_lx "\n",
+  opc1(insn), opc2(insn), opc3(insn), opc4(insn),
+  insn, ctx->cia);
+return false;
+}
+
+if (unlikely(handler->type & (PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE)
+ && Rc(insn))) {
+inval = handler->inval2;
+} else {
+inval = handler->inval1;
+}
+
+if (unlikely((insn & inval) != 0)) {
+qemu_log_mask(LOG_GUEST_ERROR, "invalid bits: %08x for opcode: "
+  "%02x - %02x - %02x - %02x (%08x) "
+  TARGET_FMT_lx "\n", insn & inval,
+  opc1(insn), opc2(insn), opc3(insn), opc4(insn),
+  insn, ctx->cia);
+return false;
+}
+
+handler->handler(ctx);
+return true;
+}
+
 static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
 {
 DisasContext *ctx = container_of(dcbase, DisasContext, base);
@@ -7997,66 +8053,23 @@ static void ppc_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cs)
 DisasContext *ctx = container_of(dcbase, DisasContext, base);
 PowerPCCPU *cpu = POWERPC_CPU(cs);
 CPUPPCState *env = cs->env_ptr;
-opc_handler_t **table, *handler;
+uint32_t insn;
+bool ok;
 
 LOG_DISAS("\n");
 LOG_DISAS("nip=" TARGET_FMT_lx " super=%d ir=%d\n",
   ctx->base.pc_next, ctx->mem_idx, (int)msr_ir);
 
 ctx->cia = ctx->base.pc_next;
-ctx->opcode = translator_ldl_swap(env, ctx->base.pc_next,
-  need_byteswap(ctx));
-
-LOG_DISAS("translate opcode %08x (%02x %02x %02x %02x) (%s)\n",
-  ctx->opcode, opc1(ctx->opcode), opc2(ctx->opcode),
-  opc3(ctx->opcode), opc4(ctx->opcode),
-  ctx->le_mode ? "little" : "big");
+insn = translator_ldl_swap(env, ctx->base.pc_next, need_byteswap(ctx));
 ctx->base.pc_next += 4;
-table = cpu->opcodes;
-handler = table[opc1(ctx->opcode)];
-if (is_indirect_opcode(handler)) {
-table = ind_table(handler);
-handler = table[opc2(ctx->opcode)];
-if (is_indirect_opcode(handler)) {
-table = ind_table(handler);
-handler = table[opc3(ctx->opcode)];
-if (is_indirect_opcode(handler)) {
-table = ind_table(handler);
-handler = table[opc4(ctx->opcode)];
-}
-}
-}
-/* Is opcode *REALLY* valid ? */
-if (unlikely(handler->handler == &gen_invalid)) {
-qemu_log_mask(LOG_GUEST_ERROR, "invalid/unsupported opcode: "
-  "%02x - %02x - %02x - %02x (%08x) "
-  TARGET_FMT_lx " %d\n",
-  opc1(ctx->opcode), opc2(ctx->opcode),
-  opc3(ctx->opcode), opc4(ctx->opcode),
-  ctx->opcode, ctx->cia, (int)msr_ir);
-} else {
-uint32_t inval;
 
-if (unlikely(handler->type & (PPC_SPE | PPC_SPE_SINGLE | 
PPC_SPE_DOUBLE)
- && Rc(ctx->opcode))) {
-inval = handler->inval2;
-} else {
-inval = handler->inval1;
-}
-
-if (unlikely((ctx->opcode & inval) != 0)) {
-qemu_log_mask(LOG_GUEST_ERROR, "invalid bits: %08x for opcode: "
-  "%02x - %02x - %02x - %02x (%08x) "
-  TARGET_FMT_lx "\n", ctx->opcode & inval,
-  opc1(ctx->opcode), opc2(ctx->opcode),
-  opc3(ct

[PATCH v3 08/30] target/ppc: Remove special case for POWERPC_SYSCALL

2021-04-29 Thread Richard Henderson
Since POWERPC_SYSCALL is raised by gen_exception_err,
we will have also set DISAS_NORETURN.

Signed-off-by: Richard Henderson 
---
 target/ppc/translate.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 3607cc12f3..b26b6964a7 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -8079,7 +8079,6 @@ static void ppc_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cs)
 /* Check trace mode exceptions */
 if (unlikely(ctx->singlestep_enabled & CPU_SINGLE_STEP &&
  (ctx->base.pc_next <= 0x100 || ctx->base.pc_next > 0xF00) &&
- ctx->exception != POWERPC_SYSCALL &&
  ctx->exception != POWERPC_EXCP_TRAP &&
  ctx->exception != POWERPC_EXCP_BRANCH &&
  ctx->base.is_jmp != DISAS_NORETURN)) {
-- 
2.25.1




[PATCH v3 11/30] target/ppc: Introduce DISAS_{EXIT,CHAIN}{,_UPDATE}

2021-04-29 Thread Richard Henderson
Rewrite ppc_tr_tb_stop to handle these new codes.

Convert ctx->exception into these new codes at the end of
ppc_tr_translate_insn, prior to pushing the change back
throughout translate.c.

Signed-off-by: Richard Henderson 
---
 target/ppc/translate.c | 75 --
 1 file changed, 65 insertions(+), 10 deletions(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index b58e2ac8dc..7dbdf3d047 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -183,6 +183,11 @@ struct DisasContext {
 uint64_t insns_flags2;
 };
 
+#define DISAS_EXIT DISAS_TARGET_0  /* exit to main loop, pc updated */
+#define DISAS_EXIT_UPDATE  DISAS_TARGET_1  /* exit to main loop, pc stale */
+#define DISAS_CHAINDISAS_TARGET_2  /* lookup next tb, pc updated */
+#define DISAS_CHAIN_UPDATE DISAS_TARGET_3  /* lookup next tb, pc stale */
+
 /* Return true iff byteswap is needed in a scalar memop */
 static inline bool need_byteswap(const DisasContext *ctx)
 {
@@ -8080,28 +8085,78 @@ static void ppc_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cs)
  opc3(ctx->opcode), opc4(ctx->opcode), ctx->opcode);
 }
 
-if (ctx->base.is_jmp == DISAS_NEXT
-&& ctx->exception != POWERPC_EXCP_NONE) {
-ctx->base.is_jmp = DISAS_TOO_MANY;
+if (ctx->base.is_jmp == DISAS_NEXT) {
+switch (ctx->exception) {
+case POWERPC_EXCP_NONE:
+break;
+case POWERPC_EXCP_BRANCH:
+ctx->base.is_jmp = DISAS_NORETURN;
+break;
+case POWERPC_EXCP_SYNC:
+case POWERPC_EXCP_STOP:
+ctx->base.is_jmp = DISAS_EXIT;
+break;
+default:
+/* Every other ctx->exception should have set NORETURN. */
+g_assert_not_reached();
+}
 }
 }
 
 static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
 {
 DisasContext *ctx = container_of(dcbase, DisasContext, base);
+DisasJumpType is_jmp = ctx->base.is_jmp;
+target_ulong nip = ctx->base.pc_next;
 
-if (ctx->base.is_jmp == DISAS_NORETURN) {
+if (is_jmp == DISAS_NORETURN) {
+/* We have already exited the TB. */
 return;
 }
 
-if (ctx->exception == POWERPC_EXCP_NONE) {
-gen_goto_tb(ctx, 0, ctx->base.pc_next);
-} else if (ctx->exception != POWERPC_EXCP_BRANCH) {
-if (unlikely(ctx->base.singlestep_enabled)) {
-gen_debug_exception(ctx);
+/* Honor single stepping. */
+if (unlikely(ctx->base.singlestep_enabled)) {
+switch (is_jmp) {
+case DISAS_TOO_MANY:
+case DISAS_EXIT_UPDATE:
+case DISAS_CHAIN_UPDATE:
+gen_update_nip(ctx, nip);
+break;
+case DISAS_EXIT:
+case DISAS_CHAIN:
+break;
+default:
+g_assert_not_reached();
 }
-/* Generate the return instruction */
+gen_debug_exception(ctx);
+return;
+}
+
+switch (is_jmp) {
+case DISAS_TOO_MANY:
+if (use_goto_tb(ctx, nip)) {
+tcg_gen_goto_tb(0);
+gen_update_nip(ctx, nip);
+tcg_gen_exit_tb(ctx->base.tb, 0);
+break;
+}
+/* fall through */
+case DISAS_CHAIN_UPDATE:
+gen_update_nip(ctx, nip);
+/* fall through */
+case DISAS_CHAIN:
+tcg_gen_lookup_and_goto_ptr();
+break;
+
+case DISAS_EXIT_UPDATE:
+gen_update_nip(ctx, nip);
+/* fall through */
+case DISAS_EXIT:
 tcg_gen_exit_tb(NULL, 0);
+break;
+
+default:
+g_assert_not_reached();
 }
 }
 
-- 
2.25.1




[PATCH v3 10/30] target/ppc: Simplify gen_debug_exception

2021-04-29 Thread Richard Henderson
Two of the call sites that use gen_debug_exception have already
updated NIP.  Only ppc_tr_breakpoint_check requires the update.

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

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 5efa4d6566..b58e2ac8dc 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -327,19 +327,7 @@ static uint32_t gen_prep_dbgex(DisasContext *ctx)
 
 static void gen_debug_exception(DisasContext *ctx)
 {
-TCGv_i32 t0;
-
-/*
- * These are all synchronous exceptions, we set the PC back to the
- * faulting instruction
- */
-if ((ctx->exception != POWERPC_EXCP_BRANCH) &&
-(ctx->exception != POWERPC_EXCP_SYNC)) {
-gen_update_nip(ctx, ctx->base.pc_next);
-}
-t0 = tcg_const_i32(EXCP_DEBUG);
-gen_helper_raise_exception(cpu_env, t0);
-tcg_temp_free_i32(t0);
+gen_helper_raise_exception(cpu_env, tcg_constant_i32(EXCP_DEBUG));
 ctx->base.is_jmp = DISAS_NORETURN;
 }
 
@@ -8040,6 +8028,7 @@ static bool ppc_tr_breakpoint_check(DisasContextBase 
*dcbase, CPUState *cs,
 {
 DisasContext *ctx = container_of(dcbase, DisasContext, base);
 
+gen_update_nip(ctx, ctx->base.pc_next);
 gen_debug_exception(ctx);
 /*
  * The address covered by the breakpoint must be included in
-- 
2.25.1




[PATCH v3 03/30] decodetree: Add support for 64-bit instructions

2021-04-29 Thread Richard Henderson
From: Luis Fernando Fujita Pires 

Allow '64' to be specified for the instruction width command line params
and use the appropriate extract and deposit functions in that case.

This will be used to implement the new 64-bit Power ISA 3.1 instructions.

Reviewed-by: Philippe Mathieu-Daudé 
Signed-off-by: Luis Pires 
Message-Id: 

[rth: Drop the change to the field type; use bitop_width instead of separate
variables for extract/deposit; use "ull" for 64-bit constants.]
Signed-off-by: Richard Henderson 
---
 scripts/decodetree.py | 21 ++---
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/scripts/decodetree.py b/scripts/decodetree.py
index d5da101167..f85da45ee3 100644
--- a/scripts/decodetree.py
+++ b/scripts/decodetree.py
@@ -27,6 +27,7 @@
 import getopt
 
 insnwidth = 32
+bitop_width = 32
 insnmask = 0x
 variablewidth = False
 fields = {}
@@ -112,7 +113,9 @@ def whexC(val):
 """Return a hex string for val padded for insnwidth,
and with the proper suffix for a C constant."""
 suffix = ''
-if val >= 0x8000:
+if val >= 0x1:
+suffix = 'ull'
+elif val >= 0x8000:
 suffix = 'u'
 return whex(val) + suffix
 
@@ -199,11 +202,9 @@ def __str__(self):
 return str(self.pos) + ':' + s + str(self.len)
 
 def str_extract(self):
-if self.sign:
-extr = 'sextract32'
-else:
-extr = 'extract32'
-return f'{extr}(insn, {self.pos}, {self.len})'
+global bitop_width
+s = 's' if self.sign else ''
+return f'{s}extract{bitop_width}(insn, {self.pos}, {self.len})'
 
 def __eq__(self, other):
 return self.sign == other.sign and self.mask == other.mask
@@ -224,6 +225,7 @@ def __str__(self):
 return str(self.subs)
 
 def str_extract(self):
+global bitop_width
 ret = '0'
 pos = 0
 for f in reversed(self.subs):
@@ -231,7 +233,7 @@ def str_extract(self):
 if pos == 0:
 ret = ext
 else:
-ret = f'deposit32({ret}, {pos}, {32 - pos}, {ext})'
+ret = f'deposit{bitop_width}({ret}, {pos}, {bitop_width - 
pos}, {ext})'
 pos += f.len
 return ret
 
@@ -1270,6 +1272,7 @@ def main():
 global insntype
 global insnmask
 global decode_function
+global bitop_width
 global variablewidth
 global anyextern
 
@@ -1299,6 +1302,10 @@ def main():
 if insnwidth == 16:
 insntype = 'uint16_t'
 insnmask = 0x
+elif insnwidth == 64:
+insntype = 'uint64_t'
+insnmask = 0x
+bitop_width = 64
 elif insnwidth != 32:
 error(0, 'cannot handle insns of width', insnwidth)
 else:
-- 
2.25.1




[PATCH v3 04/30] decodetree: Extend argument set syntax to allow types

2021-04-29 Thread Richard Henderson
Rather than force all structure members to be 'int',
allow the type of the member to be specified.

Signed-off-by: Richard Henderson 
---
 docs/devel/decodetree.rst | 11 ---
 tests/decode/succ_argset_type1.decode |  1 +
 scripts/decodetree.py | 45 +--
 3 files changed, 36 insertions(+), 21 deletions(-)
 create mode 100644 tests/decode/succ_argset_type1.decode

diff --git a/docs/devel/decodetree.rst b/docs/devel/decodetree.rst
index 74f66bf46e..49ea50c2a7 100644
--- a/docs/devel/decodetree.rst
+++ b/docs/devel/decodetree.rst
@@ -40,9 +40,6 @@ and returns an integral value extracted from there.
 
 A field with no ``unnamed_fields`` and no ``!function`` is in error.
 
-FIXME: the fields of the structure into which this result will be stored
-is restricted to ``int``.  Which means that we cannot expand 64-bit items.
-
 Field examples:
 
 +---+-+
@@ -66,9 +63,14 @@ Argument Sets
 Syntax::
 
   args_def:= '&' identifier ( args_elt )+ ( !extern )?
-  args_elt:= identifier
+  args_elt:= identifier (':' identifier)?
 
 Each *args_elt* defines an argument within the argument set.
+If the form of the *args_elt* contains a colon, the first
+identifier is the argument name and the second identifier is
+the argument type.  If the colon is missing, the argument
+type will be ``int``.
+
 Each argument set will be rendered as a C structure "arg_$name"
 with each of the fields being one of the member arguments.
 
@@ -86,6 +88,7 @@ Argument set examples::
 
   ®3   ra rb rc
   &loadstore  reg base offset
+  &longldst   reg base offset:int64_t
 
 
 Formats
diff --git a/tests/decode/succ_argset_type1.decode 
b/tests/decode/succ_argset_type1.decode
new file mode 100644
index 00..ed946b420d
--- /dev/null
+++ b/tests/decode/succ_argset_type1.decode
@@ -0,0 +1 @@
+&asdf b:bool c:uint64_t a
diff --git a/scripts/decodetree.py b/scripts/decodetree.py
index f85da45ee3..a03dc6b5e3 100644
--- a/scripts/decodetree.py
+++ b/scripts/decodetree.py
@@ -165,11 +165,15 @@ def is_contiguous(bits):
 return -1
 
 
-def eq_fields_for_args(flds_a, flds_b):
-if len(flds_a) != len(flds_b):
+def eq_fields_for_args(flds_a, arg):
+if len(flds_a) != len(arg.fields):
 return False
+# Only allow inference on default types
+for t in arg.types:
+if t != 'int':
+return False
 for k, a in flds_a.items():
-if k not in flds_b:
+if k not in arg.fields:
 return False
 return True
 
@@ -313,10 +317,11 @@ def __ne__(self, other):
 
 class Arguments:
 """Class representing the extracted fields of a format"""
-def __init__(self, nm, flds, extern):
+def __init__(self, nm, flds, types, extern):
 self.name = nm
 self.extern = extern
-self.fields = sorted(flds)
+self.fields = flds
+self.types = types
 
 def __str__(self):
 return self.name + ' ' + str(self.fields)
@@ -327,8 +332,8 @@ def struct_name(self):
 def output_def(self):
 if not self.extern:
 output('typedef struct {\n')
-for n in self.fields:
-output('int ', n, ';\n')
+for (n, t) in zip(self.fields, self.types):
+output(f'{t} {n};\n')
 output('} ', self.struct_name(), ';\n\n')
 # end Arguments
 
@@ -719,21 +724,27 @@ def parse_arguments(lineno, name, toks):
 global anyextern
 
 flds = []
+types = []
 extern = False
-for t in toks:
-if re.fullmatch('!extern', t):
+for n in toks:
+if re.fullmatch('!extern', n):
 extern = True
 anyextern = True
 continue
-if not re.fullmatch(re_C_ident, t):
-error(lineno, f'invalid argument set token "{t}"')
-if t in flds:
-error(lineno, f'duplicate argument "{t}"')
-flds.append(t)
+if re.fullmatch(re_C_ident + ':' + re_C_ident, n):
+(n, t) = n.split(':')
+elif re.fullmatch(re_C_ident, n):
+t = 'int'
+else:
+error(lineno, f'invalid argument set token "{n}"')
+if n in flds:
+error(lineno, f'duplicate argument "{n}"')
+flds.append(n)
+types.append(t)
 
 if name in arguments:
 error(lineno, 'duplicate argument set', name)
-arguments[name] = Arguments(name, flds, extern)
+arguments[name] = Arguments(name, flds, types, extern)
 # end parse_arguments
 
 
@@ -760,11 +771,11 @@ def infer_argument_set(flds):
 global decode_function
 
 for arg in arguments.values():
-if eq_fields_for_args(flds, arg.fields):
+if eq_fields_for_args(flds, arg):
 return arg
 
 name = decode_function + str(len(arguments))
-arg = Arguments(name, flds.keys(), False)
+arg = Arguments(name, flds.keys(), ['int'] * len(flds), False)
 argumen

[PATCH v3 12/30] target/ppc: Replace POWERPC_EXCP_SYNC with DISAS_EXIT

2021-04-29 Thread Richard Henderson
Remove the synthetic "exception" after no more uses.

Signed-off-by: Richard Henderson 
---
 target/ppc/cpu.h   |  1 -
 target/ppc/translate.c | 27 +--
 2 files changed, 9 insertions(+), 19 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index e73416da68..cf10117065 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -135,7 +135,6 @@ enum {
 POWERPC_EXCP_STOP = 0x200, /* stop translation   */
 POWERPC_EXCP_BRANCH   = 0x201, /* branch instruction */
 /* QEMU exceptions: special cases we want to stop translation*/
-POWERPC_EXCP_SYNC = 0x202, /* context synchronizing instruction  */
 POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only  */
 };
 
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 7dbdf3d047..d22d6e5b85 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -360,14 +360,6 @@ static inline void gen_stop_exception(DisasContext *ctx)
 ctx->exception = POWERPC_EXCP_STOP;
 }
 
-#ifndef CONFIG_USER_ONLY
-/* No need to update nip here, as execution flow will change */
-static inline void gen_sync_exception(DisasContext *ctx)
-{
-ctx->exception = POWERPC_EXCP_SYNC;
-}
-#endif
-
 #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type)  \
 GEN_OPCODE(name, opc1, opc2, opc3, inval, type, PPC_NONE)
 
@@ -4008,7 +4000,7 @@ static void gen_rfi(DisasContext *ctx)
 }
 gen_update_cfar(ctx, ctx->cia);
 gen_helper_rfi(cpu_env);
-gen_sync_exception(ctx);
+ctx->base.is_jmp = DISAS_EXIT;
 #endif
 }
 
@@ -4025,7 +4017,7 @@ static void gen_rfid(DisasContext *ctx)
 }
 gen_update_cfar(ctx, ctx->cia);
 gen_helper_rfid(cpu_env);
-gen_sync_exception(ctx);
+ctx->base.is_jmp = DISAS_EXIT;
 #endif
 }
 
@@ -4042,7 +4034,7 @@ static void gen_rfscv(DisasContext *ctx)
 }
 gen_update_cfar(ctx, ctx->cia);
 gen_helper_rfscv(cpu_env);
-gen_sync_exception(ctx);
+ctx->base.is_jmp = DISAS_EXIT;
 #endif
 }
 #endif
@@ -4055,7 +4047,7 @@ static void gen_hrfid(DisasContext *ctx)
 /* Restore CPU state */
 CHK_HV;
 gen_helper_hrfid(cpu_env);
-gen_sync_exception(ctx);
+ctx->base.is_jmp = DISAS_EXIT;
 #endif
 }
 #endif
@@ -5941,7 +5933,7 @@ static void gen_rfsvc(DisasContext *ctx)
 CHK_SV;
 
 gen_helper_rfsvc(cpu_env);
-gen_sync_exception(ctx);
+ctx->base.is_jmp = DISAS_EXIT;
 #endif /* defined(CONFIG_USER_ONLY) */
 }
 
@@ -6321,7 +6313,7 @@ static void gen_rfci_40x(DisasContext *ctx)
 CHK_SV;
 /* Restore CPU state */
 gen_helper_40x_rfci(cpu_env);
-gen_sync_exception(ctx);
+ctx->base.is_jmp = DISAS_EXIT;
 #endif /* defined(CONFIG_USER_ONLY) */
 }
 
@@ -6333,7 +6325,7 @@ static void gen_rfci(DisasContext *ctx)
 CHK_SV;
 /* Restore CPU state */
 gen_helper_rfci(cpu_env);
-gen_sync_exception(ctx);
+ctx->base.is_jmp = DISAS_EXIT;
 #endif /* defined(CONFIG_USER_ONLY) */
 }
 
@@ -6348,7 +6340,7 @@ static void gen_rfdi(DisasContext *ctx)
 CHK_SV;
 /* Restore CPU state */
 gen_helper_rfdi(cpu_env);
-gen_sync_exception(ctx);
+ctx->base.is_jmp = DISAS_EXIT;
 #endif /* defined(CONFIG_USER_ONLY) */
 }
 
@@ -6361,7 +6353,7 @@ static void gen_rfmci(DisasContext *ctx)
 CHK_SV;
 /* Restore CPU state */
 gen_helper_rfmci(cpu_env);
-gen_sync_exception(ctx);
+ctx->base.is_jmp = DISAS_EXIT;
 #endif /* defined(CONFIG_USER_ONLY) */
 }
 
@@ -8092,7 +8084,6 @@ static void ppc_tr_translate_insn(DisasContextBase 
*dcbase, CPUState *cs)
 case POWERPC_EXCP_BRANCH:
 ctx->base.is_jmp = DISAS_NORETURN;
 break;
-case POWERPC_EXCP_SYNC:
 case POWERPC_EXCP_STOP:
 ctx->base.is_jmp = DISAS_EXIT;
 break;
-- 
2.25.1




[PATCH v3 05/30] target/ppc: Add cia field to DisasContext

2021-04-29 Thread Richard Henderson
Signed-off-by: Richard Henderson 
---
 target/ppc/translate.c | 34 ++
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 0984ce637b..ee25badba2 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -154,6 +154,7 @@ void ppc_translate_init(void)
 /* internal defines */
 struct DisasContext {
 DisasContextBase base;
+target_ulong cia;  /* current instruction address */
 uint32_t opcode;
 uint32_t exception;
 /* Routine used to access memory */
@@ -254,7 +255,7 @@ static void gen_exception_err(DisasContext *ctx, uint32_t 
excp, uint32_t error)
  * faulting instruction
  */
 if (ctx->exception == POWERPC_EXCP_NONE) {
-gen_update_nip(ctx, ctx->base.pc_next - 4);
+gen_update_nip(ctx, ctx->cia);
 }
 t0 = tcg_const_i32(excp);
 t1 = tcg_const_i32(error);
@@ -273,7 +274,7 @@ static void gen_exception(DisasContext *ctx, uint32_t excp)
  * faulting instruction
  */
 if (ctx->exception == POWERPC_EXCP_NONE) {
-gen_update_nip(ctx, ctx->base.pc_next - 4);
+gen_update_nip(ctx, ctx->cia);
 }
 t0 = tcg_const_i32(excp);
 gen_helper_raise_exception(cpu_env, t0);
@@ -3113,7 +3114,7 @@ static void gen_eieio(DisasContext *ctx)
  */
 if (!(ctx->insns_flags2 & PPC2_ISA300)) {
 qemu_log_mask(LOG_GUEST_ERROR, "invalid eieio using bit 6 at @"
-  TARGET_FMT_lx "\n", ctx->base.pc_next - 4);
+  TARGET_FMT_lx "\n", ctx->cia);
 } else {
 bar = TCG_MO_ST_LD;
 }
@@ -3782,14 +3783,14 @@ static void gen_b(DisasContext *ctx)
 li = LI(ctx->opcode);
 li = (li ^ 0x0200) - 0x0200;
 if (likely(AA(ctx->opcode) == 0)) {
-target = ctx->base.pc_next + li - 4;
+target = ctx->cia + li;
 } else {
 target = li;
 }
 if (LK(ctx->opcode)) {
 gen_setlr(ctx, ctx->base.pc_next);
 }
-gen_update_cfar(ctx, ctx->base.pc_next - 4);
+gen_update_cfar(ctx, ctx->cia);
 gen_goto_tb(ctx, 0, target);
 }
 
@@ -3888,11 +3889,11 @@ static void gen_bcond(DisasContext *ctx, int type)
 }
 tcg_temp_free_i32(temp);
 }
-gen_update_cfar(ctx, ctx->base.pc_next - 4);
+gen_update_cfar(ctx, ctx->cia);
 if (type == BCOND_IM) {
 target_ulong li = (target_long)((int16_t)(BD(ctx->opcode)));
 if (likely(AA(ctx->opcode) == 0)) {
-gen_goto_tb(ctx, 0, ctx->base.pc_next + li - 4);
+gen_goto_tb(ctx, 0, ctx->cia + li);
 } else {
 gen_goto_tb(ctx, 0, li);
 }
@@ -4008,7 +4009,7 @@ static void gen_rfi(DisasContext *ctx)
 if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
 }
-gen_update_cfar(ctx, ctx->base.pc_next - 4);
+gen_update_cfar(ctx, ctx->cia);
 gen_helper_rfi(cpu_env);
 gen_sync_exception(ctx);
 #endif
@@ -4025,7 +4026,7 @@ static void gen_rfid(DisasContext *ctx)
 if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
 }
-gen_update_cfar(ctx, ctx->base.pc_next - 4);
+gen_update_cfar(ctx, ctx->cia);
 gen_helper_rfid(cpu_env);
 gen_sync_exception(ctx);
 #endif
@@ -4042,7 +4043,7 @@ static void gen_rfscv(DisasContext *ctx)
 if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
 gen_io_start();
 }
-gen_update_cfar(ctx, ctx->base.pc_next - 4);
+gen_update_cfar(ctx, ctx->cia);
 gen_helper_rfscv(cpu_env);
 gen_sync_exception(ctx);
 #endif
@@ -4338,7 +4339,7 @@ static inline void gen_op_mfspr(DisasContext *ctx)
 if (sprn != SPR_PVR) {
 qemu_log_mask(LOG_GUEST_ERROR, "Trying to read privileged spr "
   "%d (0x%03x) at " TARGET_FMT_lx "\n", sprn, sprn,
-  ctx->base.pc_next - 4);
+  ctx->cia);
 }
 gen_priv_exception(ctx, POWERPC_EXCP_PRIV_REG);
 }
@@ -4352,7 +4353,7 @@ static inline void gen_op_mfspr(DisasContext *ctx)
 /* Not defined */
 qemu_log_mask(LOG_GUEST_ERROR,
   "Trying to read invalid spr %d (0x%03x) at "
-  TARGET_FMT_lx "\n", sprn, sprn, ctx->base.pc_next - 4);
+  TARGET_FMT_lx "\n", sprn, sprn, ctx->cia);
 
 /*
  * The behaviour depends on MSR:PR and SPR# bit 0x10, it can
@@ -4516,7 +4517,7 @@ static void gen_mtspr(DisasContext *ctx)
 /* Privilege exception */
 qemu_log_mask(LOG_GUEST_ERROR, "Trying to write privileged spr "
   "%d (0x%03x) at " TARGET_FMT_lx "\n", sprn, sprn,
-  ctx->base.pc_next - 4);
+  ctx->cia);
 gen_priv_exception(ctx, POWERPC_EXCP_PRIV_REG);
 }
 } else {
@@ -4530,7 +4531,7 @@ static void gen_mtspr(DisasContext *ctx)

[PATCH v3 01/30] decodetree: Introduce whex and whexC helpers

2021-04-29 Thread Richard Henderson
Form a hex constant of the appropriate insnwidth.
Begin using f-strings on changed lines.

Signed-off-by: Richard Henderson 
---
 scripts/decodetree.py | 66 +--
 1 file changed, 38 insertions(+), 28 deletions(-)

diff --git a/scripts/decodetree.py b/scripts/decodetree.py
index 4637b633e7..0861e5d503 100644
--- a/scripts/decodetree.py
+++ b/scripts/decodetree.py
@@ -102,6 +102,21 @@ def str_fields(fields):
 return r[1:]
 
 
+def whex(val):
+"""Return a hex string for val padded for insnwidth"""
+global insnwidth
+return f'0x{val:0{insnwidth // 4}x}'
+
+
+def whexC(val):
+"""Return a hex string for val padded for insnwidth,
+   and with the proper suffix for a C constant."""
+suffix = ''
+if val >= 0x8000:
+suffix = 'u'
+return whex(val) + suffix
+
+
 def str_match_bits(bits, mask):
 """Return a string pretty-printing BITS/MASK"""
 global insnwidth
@@ -477,11 +492,8 @@ def output_code(self, i, extracted, outerbits, outermask):
 if outermask != p.fixedmask:
 innermask = p.fixedmask & ~outermask
 innerbits = p.fixedbits & ~outermask
-output(ind, 'if ((insn & ',
-   '0x{0:08x}) == 0x{1:08x}'.format(innermask, innerbits),
-   ') {\n')
-output(ind, '/* ',
-   str_match_bits(p.fixedbits, p.fixedmask), ' */\n')
+output(ind, f'if ((insn & {whexC(innermask)}) == 
{whexC(innerbits)}) {{\n')
+output(ind, f'/* {str_match_bits(p.fixedbits, 
p.fixedmask)} */\n')
 p.output_code(i + 4, extracted, p.fixedbits, p.fixedmask)
 output(ind, '}\n')
 else:
@@ -500,12 +512,12 @@ def __init__(self, fm, tm):
 
 def str1(self, i):
 ind = str_indent(i)
-r = '{0}{1:08x}'.format(ind, self.fixedmask)
+r = ind + whex(self.fixedmask)
 if self.format:
 r += ' ' + self.format.name
 r += ' [\n'
 for (b, s) in self.subs:
-r += '{0}  {1:08x}:\n'.format(ind, b)
+r += ind + f'  {whex(b)}:\n'
 r += s.str1(i + 4) + '\n'
 r += ind + ']'
 return r
@@ -529,16 +541,16 @@ def output_code(self, i, extracted, outerbits, outermask):
 if sh > 0:
 # Propagate SH down into the local functions.
 def str_switch(b, sh=sh):
-return '(insn >> {0}) & 0x{1:x}'.format(sh, b >> sh)
+return f'(insn >> {sh}) & {b >> sh:#x}'
 
 def str_case(b, sh=sh):
-return '0x{0:x}'.format(b >> sh)
+return hex(b >> sh)
 else:
 def str_switch(b):
-return 'insn & 0x{0:08x}'.format(b)
+return f'insn & {whexC(b)}'
 
 def str_case(b):
-return '0x{0:08x}'.format(b)
+return whexC(b)
 
 output(ind, 'switch (', str_switch(self.thismask), ') {\n')
 for b, s in sorted(self.subs):
@@ -962,19 +974,19 @@ def parse_generic(lineno, parent_pat, name, toks):
 
 # Validate the masks that we have assembled.
 if fieldmask & fixedmask:
-error(lineno, 'fieldmask overlaps fixedmask (0x{0:08x} & 0x{1:08x})'
-  .format(fieldmask, fixedmask))
+error(lineno, 'fieldmask overlaps fixedmask ',
+  f'({whex(fieldmask)} & {whex(fixedmask)})')
 if fieldmask & undefmask:
-error(lineno, 'fieldmask overlaps undefmask (0x{0:08x} & 0x{1:08x})'
-  .format(fieldmask, undefmask))
+error(lineno, 'fieldmask overlaps undefmask ',
+  f'({whex(fieldmask)} & {whex(undefmask)})')
 if fixedmask & undefmask:
-error(lineno, 'fixedmask overlaps undefmask (0x{0:08x} & 0x{1:08x})'
-  .format(fixedmask, undefmask))
+error(lineno, 'fixedmask overlaps undefmask ',
+  f'({whex(fixedmask)} & {whex(undefmask)})')
 if not is_format:
 allbits = fieldmask | fixedmask | undefmask
 if allbits != insnmask:
-error(lineno, 'bits left unspecified (0x{0:08x})'
-  .format(allbits ^ insnmask))
+error(lineno, 'bits left unspecified ',
+  f'({whex(allbits ^ insnmask)})')
 # end parse_general
 
 
@@ -1104,10 +1116,9 @@ def __init__(self, m, w):
 
 def str1(self, i):
 ind = str_indent(i)
-r = '{0}{1:08x}'.format(ind, self.mask)
-r += ' [\n'
+r = ind + whex(self.mask) + ' [\n'
 for (b, s) in self.subs:
-r += '{0}  {1:08x}:\n'.format(ind, b)
+r += ind + f'  {whex(b)}:\n'
 r += s.str1(i + 4) + '\n'
 r += ind + ']'
 return r
@@ -1131,16 +1142,16 @@ def output_code(self, i, extracted, outerbits, 
outermask):
 if sh > 0:
 # Propagate SH down into the local functions.
 

[PATCH v3 00/30] Base for adding PowerPC 64-bit instructions

2021-04-29 Thread Richard Henderson
Changes for v3:
  * More changes for decodetree.
  * Cleanup exception/is_jmp logic to the point exception is removed.
  * Fold in Luis' isa check for prefixed insn support.
  * Share trans_* between prefixed and non-prefixed instructions.
  * Use macros to minimize the trans_* boilerplate.
  * Fix decode mistake for STHX/STHXU.


r~


Luis Fernando Fujita Pires (1):
  decodetree: Add support for 64-bit instructions

Richard Henderson (29):
  decodetree: Introduce whex and whexC helpers
  decodetree: More use of f-strings
  decodetree: Extend argument set syntax to allow types
  target/ppc: Add cia field to DisasContext
  target/ppc: Split out decode_legacy
  target/ppc: Move DISAS_NORETURN setting into gen_exception*
  target/ppc: Remove special case for POWERPC_SYSCALL
  target/ppc: Remove special case for POWERPC_EXCP_TRAP
  target/ppc: Simplify gen_debug_exception
  target/ppc: Introduce DISAS_{EXIT,CHAIN}{,_UPDATE}
  target/ppc: Replace POWERPC_EXCP_SYNC with DISAS_EXIT
  target/ppc: Remove unnecessary gen_io_end calls
  target/ppc: Introduce gen_icount_io_start
  target/ppc: Replace POWERPC_EXCP_STOP with DISAS_EXIT_UPDATE
  target/ppc: Replace POWERPC_EXCP_BRANCH with DISAS_NORETURN
  target/ppc: Remove DisasContext.exception
  target/ppc: Move single-step check to ppc_tr_tb_stop
  target/ppc: Tidy exception vs exit_tb
  target/ppc: Mark helper_raise_exception* as noreturn
  target/ppc: Use translator_loop_temp_check
  target/ppc: Introduce macros to check isa extensions
  target/ppc: Add infrastructure for prefixed insns
  target/ppc: Move page crossing check to ppc_tr_translate_insn
  target/ppc: Move ADDI, ADDIS to decodetree, implement PADDI
  target/ppc: Implement PNOP
  target/ppc: Move D/DS/X-form integer loads to decodetree
  target/ppc: Implement prefixed integer load instructions
  target/ppc: Move D/DS/X-form integer stores to decodetree
  target/ppc: Implement prefixed integer store instructions

 docs/devel/decodetree.rst  |  11 +-
 target/ppc/cpu.h   |   5 +-
 target/ppc/helper.h|   4 +-
 target/ppc/insn32.decode   |  91 +++
 target/ppc/insn64.decode   |  71 +++
 tests/decode/succ_argset_type1.decode  |   1 +
 linux-user/ppc/cpu_loop.c  |   6 -
 target/ppc/translate.c | 672 +
 target/ppc/translate/fixedpoint-impl.c.inc | 200 ++
 target/ppc/translate_init.c.inc| 143 +
 scripts/decodetree.py  | 172 +++---
 target/ppc/meson.build |   9 +
 12 files changed, 772 insertions(+), 613 deletions(-)
 create mode 100644 target/ppc/insn32.decode
 create mode 100644 target/ppc/insn64.decode
 create mode 100644 tests/decode/succ_argset_type1.decode
 create mode 100644 target/ppc/translate/fixedpoint-impl.c.inc

-- 
2.25.1




[PATCH 0/2] cocoa: keyboard quality of life

2021-04-29 Thread gustavo
From: Gustavo Noronha Silva 

This series adds two new options to the cocoa display:

 - full-grab causes it to use a global tap to steal system combos
   away from Mac OS X, so they can be handled by the VM

 - swap-option-command does what it says on the tin; while that is
   something you can do at the Mac OS X level or even supported by
   some keyboards, it is much more convenient to have qemu put
   Meta/Super and Alt where they belong if you are running a
   non-Mac VM

I propose to enable swap-option-command by default and leave full-grab
off because unfortunately it needs accessibility permissions for input
grabbing, so it requires more deliberate action by the user anyway.

Gustavo Noronha Silva (2):
  ui/cocoa: capture all keys and combos when mouse is grabbed
  ui/cocoa: add option to swap Option and Command, enable by default

 qapi/ui.json|  20 +++
 qemu-options.hx |   4 ++
 ui/cocoa.m  | 139 +++-
 3 files changed, 151 insertions(+), 12 deletions(-)

-- 
2.24.3 (Apple Git-128)




[PATCH 1/2] ui/cocoa: capture all keys and combos when mouse is grabbed

2021-04-29 Thread gustavo
From: Gustavo Noronha Silva 

Applications such as Gnome may use Alt-Tab and Super-Tab for different
purposes, some use Ctrl-arrows so we want to allow qemu to handle
everything when it captures the mouse/keyboard.

However, Mac OS handles some combos like Command-Tab and Ctrl-arrows
at an earlier part of the event handling chain, not letting qemu see it.

We add a global Event Tap that allows qemu to see all events when the
mouse is grabbed. Note that this requires additional permissions.

See:

https://developer.apple.com/documentation/coregraphics/1454426-cgeventtapcreate?language=objc#discussion
https://support.apple.com/en-in/guide/mac-help/mh32356/mac

Signed-off-by: Gustavo Noronha Silva 
---
 qapi/ui.json| 15 ++
 qemu-options.hx |  3 ++
 ui/cocoa.m  | 73 +++--
 3 files changed, 89 insertions(+), 2 deletions(-)

diff --git a/qapi/ui.json b/qapi/ui.json
index 1052ca9c38..77bc00fd0d 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -1088,6 +1088,20 @@
 { 'struct'  : 'DisplayCurses',
   'data': { '*charset'   : 'str' } }
 
+##
+# @DisplayCocoa:
+#
+# Cocoa display options.
+#
+# @full-grab:   Capture all key presses, including system combos. This
+#   requires accessibility permissions, since it performs
+#   a global grab on key events. (default: off)
+#   See 
https://support.apple.com/en-in/guide/mac-help/mh32356/mac
+#
+##
+{ 'struct'  : 'DisplayCocoa',
+  'data': { '*full-grab' : 'bool' } }
+
 ##
 # @DisplayType:
 #
@@ -1153,6 +1167,7 @@
 '*gl': 'DisplayGLMode' },
   'discriminator' : 'type',
   'data': { 'gtk': 'DisplayGTK',
+'cocoa'  : 'DisplayCocoa',
 'curses' : 'DisplayCurses',
 'egl-headless'   : 'DisplayEGLHeadless'} }
 
diff --git a/qemu-options.hx b/qemu-options.hx
index fd21002bd6..a77505241f 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1783,6 +1783,9 @@ DEF("display", HAS_ARG, QEMU_OPTION_display,
 #if defined(CONFIG_CURSES)
 "-display curses[,charset=]\n"
 #endif
+#if defined(CONFIG_COCOA)
+"-display cocoa[,full_grab=on|off]\n"
+#endif
 #if defined(CONFIG_OPENGL)
 "-display egl-headless[,rendernode=]\n"
 #endif
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 37e1fb52eb..f1e4449082 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -72,6 +72,7 @@
 typedef struct {
 int width;
 int height;
+bool full_grab;
 } QEMUScreen;
 
 static void cocoa_update(DisplayChangeListener *dcl,
@@ -304,11 +305,13 @@ @interface QemuCocoaView : NSView
 BOOL isMouseGrabbed;
 BOOL isFullscreen;
 BOOL isAbsoluteEnabled;
+CFMachPortRef eventsTap;
 }
 - (void) switchSurface:(pixman_image_t *)image;
 - (void) grabMouse;
 - (void) ungrabMouse;
 - (void) toggleFullScreen:(id)sender;
+- (void) setFullGrab:(id)sender to:(BOOL)value;
 - (void) handleMonitorInput:(NSEvent *)event;
 - (bool) handleEvent:(NSEvent *)event;
 - (bool) handleEventLocked:(NSEvent *)event;
@@ -323,6 +326,7 @@ - (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled;
  */
 - (BOOL) isMouseGrabbed;
 - (BOOL) isAbsoluteEnabled;
+- (BOOL) isFullGrabEnabled;
 - (float) cdx;
 - (float) cdy;
 - (QEMUScreen) gscreen;
@@ -331,6 +335,19 @@ - (void) raiseAllKeys;
 
 QemuCocoaView *cocoaView;
 
+static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, 
CGEventRef cgEvent, void *userInfo)
+{
+QemuCocoaView *cocoaView = (QemuCocoaView*) userInfo;
+NSEvent* event = [NSEvent eventWithCGEvent:cgEvent];
+if ([cocoaView isFullGrabEnabled] && [cocoaView isMouseGrabbed] && 
[cocoaView handleEvent:event]) {
+COCOA_DEBUG("Global events tap: qemu handled the event, capturing!\n");
+return NULL;
+}
+COCOA_DEBUG("Global events tap: qemu did not handle the event, letting it 
through...\n");
+
+return cgEvent;
+}
+
 @implementation QemuCocoaView
 - (id)initWithFrame:(NSRect)frameRect
 {
@@ -344,6 +361,32 @@ - (id)initWithFrame:(NSRect)frameRect
 kbd = qkbd_state_init(dcl.con);
 
 }
+
+CGEventMask mask = CGEventMaskBit(kCGEventKeyDown) | 
CGEventMaskBit(kCGEventKeyUp) | CGEventMaskBit(kCGEventFlagsChanged);
+eventsTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, 
kCGEventTapOptionDefault,
+ mask, handleTapEvent, self);
+if (!eventsTap) {
+warn_report("Could not create event tap, system key combos will not be 
captured.\n");
+return self;
+} else {
+COCOA_DEBUG("Global events tap created! Will capture system key 
combos.\n");
+}
+
+CFRunLoopRef runLoop = CFRunLoopGetCurrent();
+if (!runLoop) {
+warn_report("Could not obtain current CF RunLoop, system key combos 
will not be captured.\n");
+return self;
+}
+
+CFRunLoopSourceRef tapEventsSrc = 
CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventsTap, 0);
+if (!tapEvent

[PATCH 2/2] ui/cocoa: add option to swap Option and Command, enable by default

2021-04-29 Thread gustavo
From: Gustavo Noronha Silva 

On Mac OS X the Option key maps to Alt and Command to Super/Meta. This change
swaps them around so that Alt is the key closer to the space bar and Meta/Super
is between Control and Alt, like on non-Mac keyboards.

It is a cocoa display option, enabled by default.

Signed-off-by: Gustavo Noronha Silva 
---
 qapi/ui.json|  7 +-
 qemu-options.hx |  1 +
 ui/cocoa.m  | 66 +
 3 files changed, 63 insertions(+), 11 deletions(-)

diff --git a/qapi/ui.json b/qapi/ui.json
index 77bc00fd0d..02db684251 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -1098,9 +1098,14 @@
 #   a global grab on key events. (default: off)
 #   See 
https://support.apple.com/en-in/guide/mac-help/mh32356/mac
 #
+# @swap-option-command: Swaps the Option and Command keys so that their key 
codes
+#   match their position on non-Mac keyboards and you can 
use
+#   Meta/Super and Alt where you expect them. (default: on)
+#
 ##
 { 'struct'  : 'DisplayCocoa',
-  'data': { '*full-grab' : 'bool' } }
+  'data': { '*full-grab'   : 'bool',
+'*swap-option-command' : 'bool' } }
 
 ##
 # @DisplayType:
diff --git a/qemu-options.hx b/qemu-options.hx
index a77505241f..d6137eedac 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1785,6 +1785,7 @@ DEF("display", HAS_ARG, QEMU_OPTION_display,
 #endif
 #if defined(CONFIG_COCOA)
 "-display cocoa[,full_grab=on|off]\n"
+"  [,swap_option_command=on|off]\n"
 #endif
 #if defined(CONFIG_OPENGL)
 "-display egl-headless[,rendernode=]\n"
diff --git a/ui/cocoa.m b/ui/cocoa.m
index f1e4449082..879e568a9d 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -73,6 +73,7 @@
 int width;
 int height;
 bool full_grab;
+bool swap_option_command;
 } QEMUScreen;
 
 static void cocoa_update(DisplayChangeListener *dcl,
@@ -327,6 +328,7 @@ - (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled;
 - (BOOL) isMouseGrabbed;
 - (BOOL) isAbsoluteEnabled;
 - (BOOL) isFullGrabEnabled;
+- (BOOL) isSwapOptionCommandEnabled;
 - (float) cdx;
 - (float) cdy;
 - (QEMUScreen) gscreen;
@@ -648,6 +650,13 @@ - (void) setFullGrab:(id)sender to:(BOOL)value
 screen.full_grab = value;
 }
 
+- (void) setSwapOptionCommand:(id)sender
+{
+COCOA_DEBUG("QemuCocoaView: setSwapOptionCommand\n");
+
+screen.swap_option_command = true;
+}
+
 - (void) toggleKey: (int)keycode {
 qkbd_state_key_event(kbd, keycode, !qkbd_state_key_get(kbd, keycode));
 }
@@ -797,12 +806,22 @@ - (bool) handleEventLocked:(NSEvent *)event
 qkbd_state_key_event(kbd, Q_KEY_CODE_CTRL_R, false);
 }
 if (!(modifiers & NSEventModifierFlagOption)) {
-qkbd_state_key_event(kbd, Q_KEY_CODE_ALT, false);
-qkbd_state_key_event(kbd, Q_KEY_CODE_ALT_R, false);
+if ([self isSwapOptionCommandEnabled]) {
+qkbd_state_key_event(kbd, Q_KEY_CODE_META_L, false);
+qkbd_state_key_event(kbd, Q_KEY_CODE_META_R, false);
+} else {
+qkbd_state_key_event(kbd, Q_KEY_CODE_ALT, false);
+qkbd_state_key_event(kbd, Q_KEY_CODE_ALT_R, false);
+}
 }
 if (!(modifiers & NSEventModifierFlagCommand)) {
-qkbd_state_key_event(kbd, Q_KEY_CODE_META_L, false);
-qkbd_state_key_event(kbd, Q_KEY_CODE_META_R, false);
+if ([self isSwapOptionCommandEnabled]) {
+qkbd_state_key_event(kbd, Q_KEY_CODE_ALT, false);
+qkbd_state_key_event(kbd, Q_KEY_CODE_ALT_R, false);
+} else {
+qkbd_state_key_event(kbd, Q_KEY_CODE_META_L, false);
+qkbd_state_key_event(kbd, Q_KEY_CODE_META_R, false);
+}
 }
 
 switch ([event type]) {
@@ -834,13 +853,21 @@ - (bool) handleEventLocked:(NSEvent *)event
 
 case kVK_Option:
 if (!!(modifiers & NSEventModifierFlagOption)) {
-[self toggleKey:Q_KEY_CODE_ALT];
+if ([self isSwapOptionCommandEnabled]) {
+[self toggleKey:Q_KEY_CODE_META_L];
+} else {
+[self toggleKey:Q_KEY_CODE_ALT];
+}
 }
 break;
 
 case kVK_RightOption:
 if (!!(modifiers & NSEventModifierFlagOption)) {
-[self toggleKey:Q_KEY_CODE_ALT_R];
+if ([self isSwapOptionCommandEnabled]) {
+[self toggleKey:Q_KEY_CODE_META_R];
+} else {
+[self toggleKey:Q_KEY_CODE_ALT_R];
+}
 }
 break;
 
@@ -848,15 +875,21 @@ - (bool) handleEventLocked:(NSEvent *)event
 case kVK_Command:
 if (isMouseGrabbed &&
 !!(modifiers & NSEventModifier

[PATCH v3 7/8] hw/arm/sbsa-ref: add ITS support in SBSA GIC

2021-04-29 Thread Shashi Mallela
Included creation of ITS as part of SBSA platform GIC
initialization.

Signed-off-by: Shashi Mallela 
---
 hw/arm/sbsa-ref.c | 26 +++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
index 88dfb2284c..d05cbcae48 100644
--- a/hw/arm/sbsa-ref.c
+++ b/hw/arm/sbsa-ref.c
@@ -35,7 +35,7 @@
 #include "hw/boards.h"
 #include "hw/ide/internal.h"
 #include "hw/ide/ahci_internal.h"
-#include "hw/intc/arm_gicv3_common.h"
+#include "hw/intc/arm_gicv3_its_common.h"
 #include "hw/loader.h"
 #include "hw/pci-host/gpex.h"
 #include "hw/qdev-properties.h"
@@ -65,6 +65,7 @@ enum {
 SBSA_CPUPERIPHS,
 SBSA_GIC_DIST,
 SBSA_GIC_REDIST,
+SBSA_GIC_ITS,
 SBSA_SECURE_EC,
 SBSA_GWDT,
 SBSA_GWDT_REFRESH,
@@ -108,6 +109,7 @@ static const MemMapEntry sbsa_ref_memmap[] = {
 [SBSA_CPUPERIPHS] = { 0x4000, 0x0004 },
 [SBSA_GIC_DIST] =   { 0x4006, 0x0001 },
 [SBSA_GIC_REDIST] = { 0x4008, 0x0400 },
+[SBSA_GIC_ITS] ={ 0x4409, 0x0002 },
 [SBSA_SECURE_EC] =  { 0x5000, 0x1000 },
 [SBSA_GWDT_REFRESH] =   { 0x5001, 0x1000 },
 [SBSA_GWDT_CONTROL] =   { 0x50011000, 0x1000 },
@@ -378,7 +380,20 @@ static void create_secure_ram(SBSAMachineState *sms,
 memory_region_add_subregion(secure_sysmem, base, secram);
 }
 
-static void create_gic(SBSAMachineState *sms)
+static void create_its(SBSAMachineState *sms)
+{
+DeviceState *dev;
+
+dev = qdev_new(TYPE_ARM_GICV3_ITS);
+SysBusDevice *s = SYS_BUS_DEVICE(dev);
+
+object_property_set_link(OBJECT(dev), "parent-gicv3", OBJECT(sms->gic),
+ &error_abort);
+sysbus_realize_and_unref(s, &error_fatal);
+sysbus_mmio_map(s, 0, sbsa_ref_memmap[SBSA_GIC_ITS].base);
+}
+
+static void create_gic(SBSAMachineState *sms, MemoryRegion *mem)
 {
 unsigned int smp_cpus = MACHINE(sms)->smp.cpus;
 SysBusDevice *gicbusdev;
@@ -405,6 +420,10 @@ static void create_gic(SBSAMachineState *sms)
 qdev_prop_set_uint32(sms->gic, "len-redist-region-count", 1);
 qdev_prop_set_uint32(sms->gic, "redist-region-count[0]", redist0_count);
 
+object_property_set_link(OBJECT(sms->gic), "sysmem", OBJECT(mem),
+ &error_fatal);
+qdev_prop_set_bit(sms->gic, "has-lpi", true);
+
 gicbusdev = SYS_BUS_DEVICE(sms->gic);
 sysbus_realize_and_unref(gicbusdev, &error_fatal);
 sysbus_mmio_map(gicbusdev, 0, sbsa_ref_memmap[SBSA_GIC_DIST].base);
@@ -451,6 +470,7 @@ static void create_gic(SBSAMachineState *sms)
 sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
 }
+create_its(sms);
 }
 
 static void create_uart(const SBSAMachineState *sms, int uart,
@@ -763,7 +783,7 @@ static void sbsa_ref_init(MachineState *machine)
 
 create_secure_ram(sms, secure_sysmem);
 
-create_gic(sms);
+create_gic(sms, sysmem);
 
 create_uart(sms, SBSA_UART, sysmem, serial_hd(0));
 create_uart(sms, SBSA_SECURE_UART, secure_sysmem, serial_hd(1));
-- 
2.27.0




[PATCH v3 0/8] GICv3 LPI and ITS feature implementation

2021-04-29 Thread Shashi Mallela
This patchset implements qemu device model for enabling physical
LPI support and ITS functionality in GIC as per GICv3 specification.
Both flat table and 2 level tables are implemented.The ITS commands
for adding/deleting ITS table entries,trigerring LPI interrupts are
implemented.Translated LPI interrupt ids are processed by redistributor
to determine priority and set pending state appropriately before
forwarding the same to cpu interface.
The ITS feature support has been added to sbsa-ref platform as well as
virt platform,wherein the emulated functionality co-exists with kvm
kernel functionality.

Changes in v3:
 - review comments addressed

Shashi Mallela (8):
  hw/intc: GICv3 ITS initial framework
  hw/intc: GICv3 ITS register definitions added
  hw/intc: GICv3 ITS command queue framework
  hw/intc: GICv3 ITS Command processing
  hw/intc: GICv3 ITS Feature enablement
  hw/intc: GICv3 redistributor ITS processing
  hw/arm/sbsa-ref: add ITS support in SBSA GIC
  hw/arm/virt: add ITS support in virt GIC

 hw/arm/sbsa-ref.c  |   26 +-
 hw/arm/virt.c  |   27 +-
 hw/intc/arm_gicv3.c|6 +
 hw/intc/arm_gicv3_common.c |   13 +
 hw/intc/arm_gicv3_cpuif.c  |   20 +-
 hw/intc/arm_gicv3_dist.c   |   21 +-
 hw/intc/arm_gicv3_its.c| 1247 
 hw/intc/arm_gicv3_its_common.c |   11 +-
 hw/intc/arm_gicv3_its_kvm.c|2 +-
 hw/intc/arm_gicv3_redist.c |  163 +++-
 hw/intc/gicv3_internal.h   |  186 +++-
 hw/intc/meson.build|1 +
 include/hw/arm/virt.h  |2 +
 include/hw/intc/arm_gicv3_common.h |6 +
 include/hw/intc/arm_gicv3_its_common.h |   40 +-
 target/arm/kvm_arm.h   |4 +-
 16 files changed, 1738 insertions(+), 37 deletions(-)
 create mode 100644 hw/intc/arm_gicv3_its.c

--
2.27.0



[PATCH v3 2/8] hw/intc: GICv3 ITS register definitions added

2021-04-29 Thread Shashi Mallela
Defined descriptors for ITS device table,collection table and ITS
command queue entities.Implemented register read/write functions,
extract ITS table parameters and command queue parameters,extended
gicv3 common to capture qemu address space(which host the ITS table
platform memories required for subsequent ITS processing) and
initialize the same in ITS device.

Signed-off-by: Shashi Mallela 
---
 hw/intc/arm_gicv3_its.c| 333 +
 hw/intc/gicv3_internal.h   |  23 ++
 include/hw/intc/arm_gicv3_common.h |   3 +
 include/hw/intc/arm_gicv3_its_common.h |  30 +++
 4 files changed, 389 insertions(+)

diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
index 7b11330e01..a7ccb38a89 100644
--- a/hw/intc/arm_gicv3_its.c
+++ b/hw/intc/arm_gicv3_its.c
@@ -28,6 +28,162 @@ struct GICv3ITSClass {
 void (*parent_reset)(DeviceState *dev);
 };
 
+static bool extract_table_params(GICv3ITSState *s)
+{
+bool result = true;
+uint16_t num_pages = 0;
+uint8_t  page_sz_type;
+uint8_t type;
+uint32_t page_sz = 0;
+uint64_t value;
+
+for (int i = 0; i < 8; i++) {
+value = s->baser[i];
+
+if (!value) {
+continue;
+}
+
+page_sz_type = FIELD_EX64(value, GITS_BASER, PAGESIZE);
+
+switch (page_sz_type) {
+case 0:
+page_sz = GITS_ITT_PAGE_SIZE_0;
+break;
+
+case 1:
+page_sz = GITS_ITT_PAGE_SIZE_1;
+break;
+
+case 2:
+case 3:
+page_sz = GITS_ITT_PAGE_SIZE_2;
+break;
+
+default:
+result = false;
+break;
+}
+
+if (result) {
+num_pages = FIELD_EX64(value, GITS_BASER, SIZE);
+
+type = FIELD_EX64(value, GITS_BASER, TYPE);
+
+switch (type) {
+
+case GITS_ITT_TYPE_DEVICE:
+memset(&s->dt, 0 , sizeof(s->dt));
+s->dt.valid = FIELD_EX64(value, GITS_BASER, VALID);
+
+if (s->dt.valid) {
+s->dt.page_sz = page_sz;
+s->dt.indirect = FIELD_EX64(value, GITS_BASER, INDIRECT);
+s->dt.entry_sz = FIELD_EX64(value, GITS_BASER, ENTRYSIZE);
+
+if (!s->dt.indirect) {
+s->dt.max_entries = ((num_pages + 1) * page_sz) /
+   s->dt.entry_sz;
+} else {
+s->dt.max_entries = num_pages + 1) * page_sz) /
+L1TABLE_ENTRY_SIZE) *
+(page_sz / s->dt.entry_sz));
+}
+
+s->dt.max_devids = (1UL << (FIELD_EX64(s->typer, 
GITS_TYPER,
+DEVBITS) + 1));
+
+if ((page_sz == GITS_ITT_PAGE_SIZE_0) ||
+(page_sz == GITS_ITT_PAGE_SIZE_1)) {
+s->dt.base_addr = FIELD_EX64(value, GITS_BASER,
+  PHYADDR);
+s->dt.base_addr <<= R_GITS_BASER_PHYADDR_SHIFT;
+} else if (page_sz == GITS_ITT_PAGE_SIZE_2) {
+s->dt.base_addr = FIELD_EX64(value, GITS_BASER,
+   PHYADDRL_64K) <<
+   R_GITS_BASER_PHYADDRL_64K_SHIFT;
+s->dt.base_addr |= ((value >>
+ R_GITS_BASER_PHYADDR_SHIFT) &
+ R_GITS_BASER_PHYADDRH_64K_MASK) <<
+ R_GITS_BASER_PHYADDRH_64K_SHIFT;
+}
+}
+break;
+
+case GITS_ITT_TYPE_COLLECTION:
+memset(&s->ct, 0 , sizeof(s->ct));
+s->ct.valid = FIELD_EX64(value, GITS_BASER, VALID);
+
+/*
+ * GITS_TYPER.HCC is 0 for this implementation
+ * hence writes are discarded if ct.valid is 0
+ */
+if (s->ct.valid) {
+s->ct.page_sz = page_sz;
+s->ct.indirect = FIELD_EX64(value, GITS_BASER, INDIRECT);
+s->ct.entry_sz = FIELD_EX64(value, GITS_BASER, ENTRYSIZE);
+
+if (!s->ct.indirect) {
+s->ct.max_entries = ((num_pages + 1) * page_sz) /
+  s->ct.entry_sz;
+} else {
+s->ct.max_entries = num_pages + 1) * page_sz) /
+  L1TABLE_ENTRY_SIZE) *
+  (page_sz / s->ct.entry_sz));
+}
+
+if (FIELD_EX64(s->typer, GITS_TYPER, CIL)) {
+s->ct.max_collids =

[PATCH v3 4/8] hw/intc: GICv3 ITS Command processing

2021-04-29 Thread Shashi Mallela
Added ITS command queue handling for MAPTI,MAPI commands,handled ITS
translation which triggers an LPI via INT command as well as write
to GITS_TRANSLATER register,defined enum to differentiate between ITS
command interrupt trigger and GITS_TRANSLATER based interrupt trigger.
Each of these commands make use of other functionalities implemented to
get device table entry,collection table entry or interrupt translation
table entry required for their processing.

Signed-off-by: Shashi Mallela 
---
 hw/intc/arm_gicv3_its.c| 346 -
 hw/intc/gicv3_internal.h   |  12 +
 include/hw/intc/arm_gicv3_common.h |   2 +
 3 files changed, 359 insertions(+), 1 deletion(-)

diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
index 7cb465813a..98c984dd22 100644
--- a/hw/intc/arm_gicv3_its.c
+++ b/hw/intc/arm_gicv3_its.c
@@ -28,6 +28,156 @@ struct GICv3ITSClass {
 void (*parent_reset)(DeviceState *dev);
 };
 
+typedef enum ItsCmdType {
+NONE = 0, /* internal indication for GITS_TRANSLATER write */
+CLEAR = 1,
+DISCARD = 2,
+INT = 3,
+} ItsCmdType;
+
+static bool get_cte(GICv3ITSState *s, uint16_t icid, uint64_t *cte,
+MemTxResult *res)
+{
+AddressSpace *as = &s->gicv3->dma_as;
+uint64_t l2t_addr;
+uint64_t value;
+bool valid_l2t;
+uint32_t l2t_id;
+uint32_t max_l2_entries;
+bool status = false;
+
+if (s->ct.indirect) {
+l2t_id = icid / (s->ct.page_sz / L1TABLE_ENTRY_SIZE);
+
+value = address_space_ldq_le(as,
+ s->ct.base_addr +
+ (l2t_id * L1TABLE_ENTRY_SIZE),
+ MEMTXATTRS_UNSPECIFIED, res);
+
+if (*res == MEMTX_OK) {
+valid_l2t = (value >> VALID_SHIFT) & VALID_MASK;
+
+if (valid_l2t) {
+max_l2_entries = s->ct.page_sz / s->ct.entry_sz;
+
+l2t_addr = value & ((1ULL << 51) - 1);
+
+*cte =  address_space_ldq_le(as, l2t_addr +
+((icid % max_l2_entries) * GITS_CTE_SIZE),
+MEMTXATTRS_UNSPECIFIED, res);
+   }
+   }
+} else {
+/* Flat level table */
+*cte =  address_space_ldq_le(as, s->ct.base_addr +
+ (icid * GITS_CTE_SIZE),
+  MEMTXATTRS_UNSPECIFIED, res);
+}
+
+if (*cte & VALID_MASK) {
+status = true;
+}
+
+return status;
+}
+
+static MemTxResult update_ite(GICv3ITSState *s, uint32_t eventid, uint64_t dte,
+uint64_t itel, uint32_t iteh)
+{
+AddressSpace *as = &s->gicv3->dma_as;
+uint64_t itt_addr;
+MemTxResult res = MEMTX_OK;
+
+itt_addr = (dte >> 6ULL) & ITTADDR_MASK;
+itt_addr <<= ITTADDR_SHIFT; /* 256 byte aligned */
+
+address_space_stq_le(as, itt_addr + (eventid * sizeof(uint64_t)),
+ itel, MEMTXATTRS_UNSPECIFIED, &res);
+
+if (res == MEMTX_OK) {
+address_space_stl_le(as, itt_addr + ((eventid + sizeof(uint64_t)) *
+ sizeof(uint32_t)), iteh, MEMTXATTRS_UNSPECIFIED,
+ &res);
+}
+   return res;
+}
+
+static bool get_ite(GICv3ITSState *s, uint32_t eventid, uint64_t dte,
+  uint16_t *icid, uint32_t *pIntid, MemTxResult *res)
+{
+AddressSpace *as = &s->gicv3->dma_as;
+uint64_t itt_addr;
+bool status = false;
+uint64_t itel = 0;
+uint32_t iteh = 0;
+
+itt_addr = (dte >> 6ULL) & ITTADDR_MASK;
+itt_addr <<= ITTADDR_SHIFT; /* 256 byte aligned */
+
+itel = address_space_ldq_le(as, itt_addr + (eventid * sizeof(uint64_t)),
+MEMTXATTRS_UNSPECIFIED, res);
+
+if (*res == MEMTX_OK) {
+iteh = address_space_ldl_le(as, itt_addr + ((eventid +
+sizeof(uint64_t)) * sizeof(uint32_t)),
+MEMTXATTRS_UNSPECIFIED, res);
+
+if (*res == MEMTX_OK) {
+if (itel & VALID_MASK) {
+if ((itel >> ITE_ENTRY_INTTYPE_SHIFT) & GITS_TYPE_PHYSICAL) {
+*pIntid = (itel >> ITE_ENTRY_INTID_SHIFT) &
+  ITE_ENTRY_INTID_MASK;
+*icid = iteh & ITE_ENTRY_ICID_MASK;
+status = true;
+}
+}
+}
+}
+return status;
+}
+
+static uint64_t get_dte(GICv3ITSState *s, uint32_t devid, MemTxResult *res)
+{
+AddressSpace *as = &s->gicv3->dma_as;
+uint64_t l2t_addr;
+uint64_t value;
+bool valid_l2t;
+uint32_t l2t_id;
+uint32_t max_l2_entries;
+
+if (s->dt.indirect) {
+l2t_id = devid / (s->dt.page_sz / L1TABLE_ENTRY_SIZE);
+
+value = address_space_ldq_le(as,
+ s->dt.base_addr +
+ (l2t_id * L1TABLE_ENTRY_SIZE),
+   

Re: [PATCH v2 8/8] hw/arm/virt: add ITS support in virt GIC

2021-04-29 Thread shashi . mallela
On Mon, 2021-04-19 at 13:46 +0100, Peter Maydell wrote:
> On Thu, 1 Apr 2021 at 03:42, Shashi Mallela <
> shashi.mall...@linaro.org> wrote:
> > Included creation of ITS as part of virt platform GIC
> > initialization.This Emulated ITS model now co-exists with kvm
> > ITS and is enabled in absence of kvm irq kernel support in a
> > platform.
> > 
> > Signed-off-by: Shashi Mallela 
> > ---
> >  hw/arm/virt.c| 10 --
> >  target/arm/kvm_arm.h |  4 ++--
> >  2 files changed, 10 insertions(+), 4 deletions(-)
> > 
> > diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> > index aa2bbd14e0..77cf2db90f 100644
> > --- a/hw/arm/virt.c
> > +++ b/hw/arm/virt.c
> > @@ -622,7 +622,7 @@ static void create_v2m(VirtMachineState *vms)
> >  vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
> >  }
> > 
> > -static void create_gic(VirtMachineState *vms)
> > +static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
> >  {
> >  MachineState *ms = MACHINE(vms);
> >  /* We create a standalone GIC */
> > @@ -656,6 +656,12 @@ static void create_gic(VirtMachineState *vms)
> >   nb_redist_regions);
> >  qdev_prop_set_uint32(vms->gic, "redist-region-count[0]",
> > redist0_count);
> > 
> > +if (!kvm_irqchip_in_kernel()) {
> > +object_property_set_link(OBJECT(vms->gic), "sysmem",
> > OBJECT(mem),
> > + &error_fatal);
> > +qdev_prop_set_bit(vms->gic, "has-lpi", true);
> > +}
> > +
> >  if (nb_redist_regions == 2) {
> >  uint32_t redist1_capacity =
> >  vms->memmap[VIRT_HIGH_GIC_REDIST2].size /
> > GICV3_REDIST_SIZE;
> > @@ -2039,7 +2045,7 @@ static void machvirt_init(MachineState
> > *machine)
> > 
> >  virt_flash_fdt(vms, sysmem, secure_sysmem ?: sysmem);
> > 
> > -create_gic(vms);
> > +create_gic(vms, sysmem);
> > 
> >  virt_cpu_post_init(vms, sysmem);
> > 
> > diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
> > index 34f8daa377..0613454975 100644
> > --- a/target/arm/kvm_arm.h
> > +++ b/target/arm/kvm_arm.h
> > @@ -525,8 +525,8 @@ static inline const char *its_class_name(void)
> >  /* KVM implementation requires this capability */
> >  return kvm_direct_msi_enabled() ? "arm-its-kvm" : NULL;
> >  } else {
> > -/* Software emulation is not implemented yet */
> > -return NULL;
> > +/* Software emulation based model */
> > +return "arm-gicv3-its";
> >  }
> >  }
> 
> This is OK as far as it goes, but I think we need to add the
> versioned-machine support so that only "virt-6.1" and later get the
> new ITS, and "virt-6.0" behave the same way (ie no ITS) as they did
> in older QEMU versions.
> 
> Have added versioned machine support to enable new ITS only for
> versions 6.1 and above
> thanks
> -- PMM




[PATCH v3 6/8] hw/intc: GICv3 redistributor ITS processing

2021-04-29 Thread Shashi Mallela
Implemented lpi processing at redistributor to get lpi config info
from lpi configuration table,determine priority,set pending state in
lpi pending table and forward the lpi to cpuif.Added logic to invoke
redistributor lpi processing with translated LPI which set/clear LPI
from ITS device as part of ITS INT,CLEAR,DISCARD command and
GITS_TRANSLATER processing.

Signed-off-by: Shashi Mallela 
---
 hw/intc/arm_gicv3.c|   6 ++
 hw/intc/arm_gicv3_cpuif.c  |  20 --
 hw/intc/arm_gicv3_its.c|  12 ++--
 hw/intc/arm_gicv3_redist.c | 133 +
 hw/intc/gicv3_internal.h   |   9 +++
 5 files changed, 171 insertions(+), 9 deletions(-)

diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index 66eaa97198..618fa1af95 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -166,6 +166,12 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
 cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq);
 }
 
+if (cs->gic->lpi_enable) {
+if (gicv3_redist_update_lpi(cs)) {
+seenbetter = true;
+}
+}
+
 /* If the best interrupt we just found would preempt whatever
  * was the previous best interrupt before this update, then
  * we know it's definitely the best one now.
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index 43ef1d7a84..11b1df5b6b 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -899,9 +899,14 @@ static void icc_activate_irq(GICv3CPUState *cs, int irq)
 cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 0);
 gicv3_redist_update(cs);
 } else {
-gicv3_gicd_active_set(cs->gic, irq);
-gicv3_gicd_pending_clear(cs->gic, irq);
-gicv3_update(cs->gic, irq, 1);
+if (irq >= GICV3_LPI_INTID_START) {
+gicv3_redist_lpi_pending(cs, irq, 0);
+gicv3_redist_update(cs);
+} else {
+gicv3_gicd_active_set(cs->gic, irq);
+gicv3_gicd_pending_clear(cs->gic, irq);
+gicv3_update(cs->gic, irq, 1);
+}
 }
 }
 
@@ -1328,7 +1333,8 @@ static void icc_eoir_write(CPUARMState *env, const 
ARMCPRegInfo *ri,
 }
 }
 
-if (irq >= cs->gic->num_irq) {
+if ((irq >= cs->gic->num_irq) && (!(cs->gic->lpi_enable &&
+(irq >= GICV3_LPI_INTID_START {
 /* This handles two cases:
  * 1. If software writes the ID of a spurious interrupt [ie 1020-1023]
  * to the GICC_EOIR, the GIC ignores that write.
@@ -1348,7 +1354,11 @@ static void icc_eoir_write(CPUARMState *env, const 
ARMCPRegInfo *ri,
 
 if (!icc_eoi_split(env, cs)) {
 /* Priority drop and deactivate not split: deactivate irq now */
-icc_deactivate_irq(cs, irq);
+if (irq >= GICV3_LPI_INTID_START) {
+gicv3_update(cs->gic, irq, 1);
+} else {
+icc_deactivate_irq(cs, irq);
+}
 }
 }
 
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
index 98c984dd22..28da2d1d77 100644
--- a/hw/intc/arm_gicv3_its.c
+++ b/hw/intc/arm_gicv3_its.c
@@ -219,6 +219,7 @@ static MemTxResult process_int(GICv3ITSState *s, uint64_t 
value,
 bool ite_valid = false;
 uint64_t cte = 0;
 bool cte_valid = false;
+uint64_t rdbase;
 uint64_t itel = 0;
 uint32_t iteh = 0;
 
@@ -275,10 +276,13 @@ static MemTxResult process_int(GICv3ITSState *s, uint64_t 
value,
  * command in the queue
  */
 } else {
-/*
- * Current implementation only supports rdbase == procnum
- * Hence rdbase physical address is ignored
- */
+rdbase = (cte >> 1U) & RDBASE_PROCNUM_MASK;
+if ((cmd == CLEAR) || (cmd == DISCARD)) {
+gicv3_redist_process_lpi(&s->gicv3->cpu[rdbase], pIntid, 0);
+} else {
+gicv3_redist_process_lpi(&s->gicv3->cpu[rdbase], pIntid, 1);
+}
+
 if (cmd == DISCARD) {
 /* remove mapping from interrupt translation table */
 res = update_ite(s, eventid, dte, itel, iteh);
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index 7604ccdc83..82ca9d71e5 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -256,6 +256,8 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr 
offset,
 if (cs->gicr_typer & GICR_TYPER_PLPIS) {
 if (value & GICR_CTLR_ENABLE_LPIS) {
 cs->gicr_ctlr |= GICR_CTLR_ENABLE_LPIS;
+/* Check for any pending interr in pending table */
+gicv3_redist_update(cs);
 } else {
 cs->gicr_ctlr &= ~GICR_CTLR_ENABLE_LPIS;
 }
@@ -546,6 +548,137 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr 
offset, uint64_t data,
 return r;
 }
 
+bool gicv3_redist_update_lpi(GICv3CPUState *cs)
+{
+/*
+ * This function scans the LPI pending table and for each pending
+ * LPI, reads the corresponding entry f

[PATCH v3 3/8] hw/intc: GICv3 ITS command queue framework

2021-04-29 Thread Shashi Mallela
Added functionality to trigger ITS command queue processing on
write to CWRITE register and process each command queue entry to
identify the command type and handle commands like MAPD,MAPC,SYNC.

Signed-off-by: Shashi Mallela 
---
 hw/intc/arm_gicv3_its.c  | 327 +++
 hw/intc/gicv3_internal.h |  41 +
 2 files changed, 368 insertions(+)

diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
index a7ccb38a89..7cb465813a 100644
--- a/hw/intc/arm_gicv3_its.c
+++ b/hw/intc/arm_gicv3_its.c
@@ -28,6 +28,327 @@ struct GICv3ITSClass {
 void (*parent_reset)(DeviceState *dev);
 };
 
+static MemTxResult process_sync(GICv3ITSState *s, uint32_t offset)
+{
+AddressSpace *as = &s->gicv3->dma_as;
+uint64_t rdbase;
+uint64_t value;
+MemTxResult res = MEMTX_OK;
+
+offset += NUM_BYTES_IN_DW;
+offset += NUM_BYTES_IN_DW;
+
+value = address_space_ldq_le(as, s->cq.base_addr + offset,
+ MEMTXATTRS_UNSPECIFIED, &res);
+
+rdbase = (value >> RDBASE_SHIFT) & RDBASE_PROCNUM_MASK;
+
+if (rdbase < (s->gicv3->num_cpu)) {
+/*
+ * Current implementation makes a blocking synchronous call
+ * for every command issued earlier,hence the internal state
+ * is already consistent by the time SYNC command is executed.
+ */
+}
+
+offset += NUM_BYTES_IN_DW;
+return res;
+}
+
+static MemTxResult update_cte(GICv3ITSState *s, uint16_t icid, bool valid,
+uint64_t rdbase)
+{
+AddressSpace *as = &s->gicv3->dma_as;
+uint64_t value;
+uint64_t l2t_addr;
+bool valid_l2t;
+uint32_t l2t_id;
+uint32_t max_l2_entries;
+uint64_t cte = 0;
+MemTxResult res = MEMTX_OK;
+
+if (s->ct.valid) {
+if (valid) {
+/* add mapping entry to collection table */
+cte = (valid & VALID_MASK) |
+  ((rdbase & RDBASE_PROCNUM_MASK) << 1ULL);
+}
+} else {
+return res;
+}
+
+/*
+ * The specification defines the format of level 1 entries of a
+ * 2-level table, but the format of level 2 entries and the format
+ * of flat-mapped tables is IMPDEF.
+ */
+if (s->ct.indirect) {
+l2t_id = icid / (s->ct.page_sz / L1TABLE_ENTRY_SIZE);
+
+value = address_space_ldq_le(as,
+ s->ct.base_addr +
+ (l2t_id * L1TABLE_ENTRY_SIZE),
+ MEMTXATTRS_UNSPECIFIED, &res);
+
+if (res != MEMTX_OK) {
+return res;
+}
+
+valid_l2t = (value >> VALID_SHIFT) & VALID_MASK;
+
+if (valid_l2t) {
+max_l2_entries = s->ct.page_sz / s->ct.entry_sz;
+
+l2t_addr = value & ((1ULL << 51) - 1);
+
+address_space_stq_le(as, l2t_addr +
+ ((icid % max_l2_entries) * GITS_CTE_SIZE),
+ cte, MEMTXATTRS_UNSPECIFIED, &res);
+}
+} else {
+/* Flat level table */
+address_space_stq_le(as, s->ct.base_addr + (icid * GITS_CTE_SIZE),
+ cte, MEMTXATTRS_UNSPECIFIED, &res);
+}
+return res;
+}
+
+static MemTxResult process_mapc(GICv3ITSState *s, uint32_t offset)
+{
+AddressSpace *as = &s->gicv3->dma_as;
+uint16_t icid;
+uint64_t rdbase;
+bool valid;
+MemTxResult res = MEMTX_OK;
+uint64_t value;
+
+offset += NUM_BYTES_IN_DW;
+offset += NUM_BYTES_IN_DW;
+
+value = address_space_ldq_le(as, s->cq.base_addr + offset,
+ MEMTXATTRS_UNSPECIFIED, &res);
+
+if (res != MEMTX_OK) {
+return res;
+}
+
+icid = value & ICID_MASK;
+
+rdbase = (value >> RDBASE_SHIFT) & RDBASE_PROCNUM_MASK;
+
+valid = (value >> VALID_SHIFT) & VALID_MASK;
+
+if ((icid > s->ct.max_collids) || (rdbase > s->gicv3->num_cpu)) {
+qemu_log_mask(LOG_GUEST_ERROR,
+"ITS MAPC: invalid collection table attributes "
+"icid %d rdbase %lu\n",  icid, rdbase);
+/*
+ * in this implementation,in case of error
+ * we ignore this command and move onto the next
+ * command in the queue
+ */
+} else {
+res = update_cte(s, icid, valid, rdbase);
+}
+
+offset += NUM_BYTES_IN_DW;
+offset += NUM_BYTES_IN_DW;
+
+return res;
+}
+
+static MemTxResult update_dte(GICv3ITSState *s, uint32_t devid, bool valid,
+uint8_t size, uint64_t itt_addr)
+{
+AddressSpace *as = &s->gicv3->dma_as;
+uint64_t value;
+uint64_t l2t_addr;
+bool valid_l2t;
+uint32_t l2t_id;
+uint32_t max_l2_entries;
+uint64_t dte = 0;
+MemTxResult res = MEMTX_OK;
+
+if (s->dt.valid) {
+if (valid) {
+/* add mapping entry to device table */
+dte = (valid & VALID_MASK) |
+  ((size & SIZE_MASK) << 1U) |
+  ((itt_addr & ITTADDR_MASK) << 6

Re: [PATCH v2 3/8] hw/intc: GICv3 ITS command queue framework

2021-04-29 Thread shashi . mallela
On Mon, 2021-04-19 at 11:30 +0100, Peter Maydell wrote:
> On Thu, 1 Apr 2021 at 03:41, Shashi Mallela <
> shashi.mall...@linaro.org> wrote:
> > Added functionality to trigger ITS command queue processing on
> > write to CWRITE register and process each command queue entry to
> > identify the command type and handle commands like MAPD,MAPC,SYNC.
> > 
> > Signed-off-by: Shashi Mallela 
> > ---
> >  hw/intc/arm_gicv3_its.c  | 347
> > +++
> >  hw/intc/gicv3_internal.h |  41 +
> >  2 files changed, 388 insertions(+)
> > 
> > diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
> > index 81373f049d..fcac33c836 100644
> > --- a/hw/intc/arm_gicv3_its.c
> > +++ b/hw/intc/arm_gicv3_its.c
> > @@ -28,6 +28,347 @@ struct GICv3ITSClass {
> >  void (*parent_reset)(DeviceState *dev);
> >  };
> > 
> > +static MemTxResult process_sync(GICv3ITSState *s, uint32_t offset)
> > +{
> > +AddressSpace *as = &s->gicv3->sysmem_as;
> > +uint64_t rdbase;
> > +uint64_t value;
> > +bool pta = false;
> > +MemTxResult res = MEMTX_OK;
> > +
> > +offset += NUM_BYTES_IN_DW;
> > +offset += NUM_BYTES_IN_DW;
> > +
> > +value = address_space_ldq_le(as, s->cq.base_addr + offset,
> > + MEMTXATTRS_UNSPECIFIED,
> > &res);
> 
> If the ITS fails to read or write DMA, it does not report that
> by provoking a bus error for the CPU's write to GITS_CWRITER,
> which is what will happen if you just propagate up the MemTxResult
> from this DMA operation back through the register write function
> to its caller. The spec doesn't seem to define a particular behaviour
> for "I couldn't read the command out of the command queue", but
> it would seem sensible to pick one of the options from the "Command
> errors"
> section: ignore the command, or stall the command queue ("treat as
> valid" is the other option there but doesn't seem relevant here).
> 
> "Stall" is probably best as otherwise we might loop forever through
> a region of unreadable addresses.
>
> have implemented "stall" indication for all failing dma read/write
calls(based on the return value of each call) 
> 
> > +if (FIELD_EX64(s->typer, GITS_TYPER, PTA)) {
> > +/*
> > + * only bits[47:16] are considered instead of bits [51:16]
> > + * since with a physical address the target address must
> > be
> > + * 64KB aligned
> > + */
> > +rdbase = (value >> RDBASE_OFFSET) & RDBASE_MASK;
> > +pta = true;
> > +} else {
> > +rdbase = (value >> RDBASE_OFFSET) & RDBASE_PROCNUM_MASK;
> > +}
> > +
> > +if (!pta && (rdbase < (s->gicv3->num_cpu))) {
> > +/*
> > + * Current implementation makes a blocking synchronous
> > call
> > + * for every command issued earlier,hence the internal
> > state
> > + * is already consistent by the time SYNC command is
> > executed.
> > + */
> > +}
> > +
> > +offset += NUM_BYTES_IN_DW;
> > +return res;
> > +}
> 
> TODO: review process_mapd and process_mapc
> 
> > +
> > +static void update_cte(GICv3ITSState *s, uint16_t icid, uint64_t
> > cte)
> > +{
> > +AddressSpace *as = &s->gicv3->sysmem_as;
> > +uint64_t value;
> > +uint8_t  page_sz_type;
> > +uint64_t l2t_addr;
> > +bool valid_l2t;
> > +uint32_t l2t_id;
> > +uint32_t page_sz = 0;
> > +uint32_t max_l2_entries;
> 
> I think it's worth having a comment here:
> 
> /*
>  * The specification defines the format of level 1 entries of a
>  * 2-level table, but the format of level 2 entries and the format
>  * of flat-mapped tables is IMPDEF.
>  */
> 
> Q: why have you chosen to make the level-2 and flatmap entries
> 64 bits here ? They only need to contain the valid bit plus a
> 16 bit processor number. (We know the processor number fits in 16
> bits because the GICR_TYPER.Processor_Number field in the
> redistributor
> is that large.) Is there something I'm missing in the spec that makes
> 64-bit entries a good choice anyway ?
> 
> I chose 64 bits to be able to have the data structure ready for both
the processor number and RD_base address possibilities, in case we add
RD_Base address support in the future
> > +
> > +if (s->ct.indirect) {
> > +/* 2 level table */
> > +page_sz_type = FIELD_EX64(s->baser[1], GITS_BASER,
> > PAGESIZE);
> > +
> > +if (page_sz_type == 0) {
> > +page_sz = GITS_ITT_PAGE_SIZE_0;
> > +} else if (page_sz_type == 1) {
> > +page_sz = GITS_ITT_PAGE_SIZE_1;
> > +} else if (page_sz_type == 2) {
> > +page_sz = GITS_ITT_PAGE_SIZE_2;
> > +}
> 
> page_sz_type == 3 has a defined meaning: must be treated like 2.
> 
> If we're caching stuff in s->ct, maybe we should cache page_sz too ?
> 
> > +
> > +l2t_id = icid / (page_sz / L1TABLE_ENTRY_SIZE);
> > +
> > +value = address_space_ldq_le(as,
> > + s->ct.base_add

[PATCH v3 5/8] hw/intc: GICv3 ITS Feature enablement

2021-04-29 Thread Shashi Mallela
Added properties to enable ITS feature and define qemu system
address space memory in gicv3 common,setup distributor and
redistributor registers to indicate LPI support.

Signed-off-by: Shashi Mallela 
---
 hw/intc/arm_gicv3_common.c | 13 +
 hw/intc/arm_gicv3_dist.c   | 21 +++--
 hw/intc/arm_gicv3_redist.c | 30 +-
 hw/intc/gicv3_internal.h   | 17 +
 include/hw/intc/arm_gicv3_common.h |  1 +
 5 files changed, 75 insertions(+), 7 deletions(-)

diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 58ef65f589..a55e91071a 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -381,6 +381,16 @@ static void arm_gicv3_common_realize(DeviceState *dev, 
Error **errp)
 (1 << 24) |
 (i << 8) |
 (last << 4);
+
+if (s->lpi_enable) {
+s->cpu[i].gicr_typer |= GICR_TYPER_PLPIS;
+
+if (!s->dma) {
+error_setg(errp,
+"Redist-ITS: Guest 'sysmem' reference link not set");
+return;
+}
+}
 }
 }
 
@@ -494,9 +504,12 @@ static Property arm_gicv3_common_properties[] = {
 DEFINE_PROP_UINT32("num-cpu", GICv3State, num_cpu, 1),
 DEFINE_PROP_UINT32("num-irq", GICv3State, num_irq, 32),
 DEFINE_PROP_UINT32("revision", GICv3State, revision, 3),
+DEFINE_PROP_BOOL("has-lpi", GICv3State, lpi_enable, 0),
 DEFINE_PROP_BOOL("has-security-extensions", GICv3State, security_extn, 0),
 DEFINE_PROP_ARRAY("redist-region-count", GICv3State, nb_redist_regions,
   redist_region_count, qdev_prop_uint32, uint32_t),
+DEFINE_PROP_LINK("sysmem", GICv3State, dma, TYPE_MEMORY_REGION,
+ MemoryRegion *),
 DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c
index b65f56f903..43e0ea4367 100644
--- a/hw/intc/arm_gicv3_dist.c
+++ b/hw/intc/arm_gicv3_dist.c
@@ -366,12 +366,15 @@ static MemTxResult gicd_readl(GICv3State *s, hwaddr 
offset,
 return MEMTX_OK;
 case GICD_TYPER:
 {
+bool lpi_supported = false;
 /* For this implementation:
  * No1N == 1 (1-of-N SPI interrupts not supported)
  * A3V == 1 (non-zero values of Affinity level 3 supported)
  * IDbits == 0xf (we support 16-bit interrupt identifiers)
  * DVIS == 0 (Direct virtual LPI injection not supported)
- * LPIS == 0 (LPIs not supported)
+ * LPIS == 1 (LPIs are supported if affinity routing is enabled)
+ * num_LPIs == 0b0 (bits [15:11],Number of LPIs as indicated
+ *  by GICD_TYPER.IDbits)
  * MBIS == 0 (message-based SPIs not supported)
  * SecurityExtn == 1 if security extns supported
  * CPUNumber == 0 since for us ARE is always 1
@@ -385,8 +388,22 @@ static MemTxResult gicd_readl(GICv3State *s, hwaddr offset,
  */
 bool sec_extn = !(s->gicd_ctlr & GICD_CTLR_DS);
 
+/*
+ * With securityextn on, LPIs are supported when affinity routing
+ * is enabled for non-secure state and if off LPIs are supported
+ * when affinity routing is enabled.
+ */
+if (s->lpi_enable) {
+if (sec_extn) {
+lpi_supported = (s->gicd_ctlr & GICD_CTLR_ARE_NS);
+} else {
+lpi_supported = (s->gicd_ctlr & GICD_CTLR_ARE);
+}
+}
+
 *data = (1 << 25) | (1 << 24) | (sec_extn << 10) |
-(0xf << 19) | itlinesnumber;
+(lpi_supported << GICD_TYPER_LPIS_OFFSET) | (GICD_TYPER_IDBITS <<
+GICD_TYPER_IDBITS_OFFSET) | itlinesnumber;
 return MEMTX_OK;
 }
 case GICD_IIDR:
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index 8645220d61..7604ccdc83 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -244,14 +244,22 @@ static MemTxResult gicr_readl(GICv3CPUState *cs, hwaddr 
offset,
 static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset,
uint64_t value, MemTxAttrs attrs)
 {
+uint64_t data;
+
 switch (offset) {
 case GICR_CTLR:
 /* For our implementation, GICR_TYPER.DPGS is 0 and so all
  * the DPG bits are RAZ/WI. We don't do anything asynchronously,
- * so UWP and RWP are RAZ/WI. And GICR_TYPER.LPIS is 0 (we don't
- * implement LPIs) so Enable_LPIs is RES0. So there are no writable
- * bits for us.
+ * so UWP and RWP are RAZ/WI. GICR_TYPER.LPIS is 1 (we
+ * implement LPIs) so Enable_LPIs is programmable.
  */
+if (cs->gicr_typer & GICR_TYPER_PLPIS) {
+if (value & GICR_CTLR_ENABLE_LPIS) {
+cs->gicr_ctlr |= GICR_CTLR_ENABLE_LPIS;
+} else {
+cs->gicr_ctlr &= ~GICR_CTLR_ENABLE_LPIS;
+}
+   

Re: [PATCH v2 6/8] hw/intc: GICv3 redistributor ITS processing

2021-04-29 Thread shashi . mallela
On Thu, 2021-04-29 at 18:16 -0400, shashi.mall...@linaro.org wrote:
On Mon, 2021-04-19 at 13:44 +0100, Peter Maydell wrote:
> On Thu, 1 Apr 2021 at 03:41, Shashi Mallela <
> shashi.mall...@linaro.org> wrote:
> > Implemented lpi processing at redistributor to get lpi config info
> > from lpi configuration table,determine priority,set pending state
> > in
> > lpi pending table and forward the lpi to cpuif.Added logic to
> > invoke
> > redistributor lpi processing with translated LPI which set/clear
> > LPI
> > from ITS device as part of ITS INT,CLEAR,DISCARD command and
> > GITS_TRANSLATER processing.
> 
> Nit: commas should all have a space following.
> 
> > Signed-off-by: Shashi Mallela 
> > ---
> >  hw/intc/arm_gicv3.c|   6 ++
> >  hw/intc/arm_gicv3_cpuif.c  |  15 +++--
> >  hw/intc/arm_gicv3_its.c|   9 ++-
> >  hw/intc/arm_gicv3_redist.c | 124
> > +
> >  hw/intc/gicv3_internal.h   |   9 +++
> >  5 files changed, 158 insertions(+), 5 deletions(-)
> > 
> > diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
> > index 66eaa97198..618fa1af95 100644
> > --- a/hw/intc/arm_gicv3.c
> > +++ b/hw/intc/arm_gicv3.c
> > @@ -166,6 +166,12 @@ static void
> > gicv3_redist_update_noirqset(GICv3CPUState *cs)
> >  cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq);
> >  }
> > 
> > +if (cs->gic->lpi_enable) {
> > +if (gicv3_redist_update_lpi(cs)) {
> > +seenbetter = true;
> > +}
> > +}
> > +
> >  /* If the best interrupt we just found would preempt whatever
> >   * was the previous best interrupt before this update, then
> >   * we know it's definitely the best one now.
> > diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
> > index 43ef1d7a84..c225b80f66 100644
> > --- a/hw/intc/arm_gicv3_cpuif.c
> > +++ b/hw/intc/arm_gicv3_cpuif.c
> > @@ -899,9 +899,14 @@ static void icc_activate_irq(GICv3CPUState
> > *cs, int irq)
> >  cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 0);
> >  gicv3_redist_update(cs);
> >  } else {
> > -gicv3_gicd_active_set(cs->gic, irq);
> > -gicv3_gicd_pending_clear(cs->gic, irq);
> > -gicv3_update(cs->gic, irq, 1);
> > +if (irq >= GICV3_LPI_INTID_START) {
> > +gicv3_redist_lpi_pending(cs, irq, 0);
> > +gicv3_redist_update(cs);
> > +} else {
> > +gicv3_gicd_active_set(cs->gic, irq);
> > +gicv3_gicd_pending_clear(cs->gic, irq);
> > +gicv3_update(cs->gic, irq, 1);
> > +}
> >  }
> >  }
> > 
> > @@ -1337,7 +1342,9 @@ static void icc_eoir_write(CPUARMState *env,
> > const ARMCPRegInfo *ri,
> >   * valid interrupt value read from the Interrupt
> > Acknowledge
> >   * register" and so this is UNPREDICTABLE. We choose to
> > ignore it.
> >   */
> > -return;
> > +if (!(cs->gic->lpi_enable && (irq >=
> > GICV3_LPI_INTID_START))) {
> > +return;
> > +}
> 
> This condition is in the wrong place. I think what you are trying to
> do is modify "what is the set of numbers we consider to be valid IRQ
> numbers", in which case you want to be changing the outer
> "if (irq >= cs->gic->num_irq)" condition, not adding an extra one
> inside it.
> 
> More importantly, the thing this condition is guarding is that
> the code below it assumes that IRQ numbers are in range for the
> GIC's own internal non-LPI interrupts. If you allow numbers
> > = cs->gic->num_irq through, then you will get array overruns
> when icc_deactivate_irq() tries to clear its Active bit.
> 
> >  }
> > 
> >  if (icc_highest_active_group(cs) != grp) {
> > diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
> > index 0e3f176809..41e1e8b2a8 100644
> > --- a/hw/intc/arm_gicv3_its.c
> > +++ b/hw/intc/arm_gicv3_its.c
> > @@ -226,6 +226,7 @@ static MemTxResult process_int(GICv3ITSState
> > *s, uint64_t value,
> >  bool ite_valid = false;
> >  uint64_t cte = 0;
> >  bool cte_valid = false;
> > +uint64_t rdbase;
> >  uint8_t buff[ITS_ITT_ENTRY_SIZE];
> >  uint64_t itt_addr;
> > 
> > @@ -278,12 +279,18 @@ static MemTxResult process_int(GICv3ITSState
> > *s, uint64_t value,
> >   * since with a physical address the target address
> > must be
> >   * 64KB aligned
> >   */
> > -
> > +rdbase = (cte >> 1U) & RDBASE_MASK;
> 
> What's going on here? Shouldn't this be in a previous patch ?
> > 
> No,this part relates to the ITS processing wherein the rdbase is
extracted and used for subsequent redistributor trigger
> > >  /*
> >   * Current implementation only supports rdbase ==
> > procnum
> >   * Hence rdbase physical address is ignored
> >   */
> >  } else {
> > +rdbase = (cte >> 1U) & RDBASE_PROCNUM_MASK;
> > +if ((cmd == CLEAR) || (cmd == DISCARD)) {
> > +gic

[PATCH v3 8/8] hw/arm/virt: add ITS support in virt GIC

2021-04-29 Thread Shashi Mallela
Included creation of ITS as part of virt platform GIC
initialization.This Emulated ITS model now co-exists with kvm
ITS and is enabled in absence of kvm irq kernel support in a
platform.

Signed-off-by: Shashi Mallela 
---
 hw/arm/virt.c | 27 +--
 include/hw/arm/virt.h |  2 ++
 target/arm/kvm_arm.h  |  4 ++--
 3 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 9f01d9041b..8f581747bc 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -585,6 +585,12 @@ static void create_its(VirtMachineState *vms)
 const char *itsclass = its_class_name();
 DeviceState *dev;
 
+if (!strcmp(itsclass, "arm-gicv3-its")) {
+if (!vms->tcg_its) {
+itsclass = NULL;
+}
+}
+
 if (!itsclass) {
 /* Do nothing if not supported */
 return;
@@ -622,7 +628,7 @@ static void create_v2m(VirtMachineState *vms)
 vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
 }
 
-static void create_gic(VirtMachineState *vms)
+static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
 {
 MachineState *ms = MACHINE(vms);
 /* We create a standalone GIC */
@@ -656,6 +662,14 @@ static void create_gic(VirtMachineState *vms)
  nb_redist_regions);
 qdev_prop_set_uint32(vms->gic, "redist-region-count[0]", 
redist0_count);
 
+if (!kvm_irqchip_in_kernel()) {
+if (vms->tcg_its) {
+object_property_set_link(OBJECT(vms->gic), "sysmem",
+ OBJECT(mem), &error_fatal);
+qdev_prop_set_bit(vms->gic, "has-lpi", true);
+}
+}
+
 if (nb_redist_regions == 2) {
 uint32_t redist1_capacity =
 vms->memmap[VIRT_HIGH_GIC_REDIST2].size / 
GICV3_REDIST_SIZE;
@@ -2039,7 +2053,7 @@ static void machvirt_init(MachineState *machine)
 
 virt_flash_fdt(vms, sysmem, secure_sysmem ?: sysmem);
 
-create_gic(vms);
+create_gic(vms, sysmem);
 
 virt_cpu_post_init(vms, sysmem);
 
@@ -2718,6 +2732,12 @@ static void virt_instance_init(Object *obj)
 } else {
 /* Default allows ITS instantiation */
 vms->its = true;
+
+if (vmc->no_tcg_its) {
+vms->tcg_its = false;
+} else {
+vms->tcg_its = true;
+}
 }
 
 /* Default disallows iommu instantiation */
@@ -2759,6 +2779,9 @@ type_init(machvirt_machine_init);
 
 static void virt_machine_6_0_options(MachineClass *mc)
 {
+VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
+/* qemu ITS was introduced with 6.1 */
+vmc->no_tcg_its = true;
 }
 DEFINE_VIRT_MACHINE_AS_LATEST(6, 0)
 
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 921416f918..f873ab9068 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -120,6 +120,7 @@ struct VirtMachineClass {
 MachineClass parent;
 bool disallow_affinity_adjustment;
 bool no_its;
+bool no_tcg_its;
 bool no_pmu;
 bool claim_edge_triggered_timers;
 bool smbios_old_sys_ver;
@@ -141,6 +142,7 @@ struct VirtMachineState {
 bool highmem;
 bool highmem_ecam;
 bool its;
+bool tcg_its;
 bool virt;
 bool ras;
 bool mte;
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 34f8daa377..0613454975 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -525,8 +525,8 @@ static inline const char *its_class_name(void)
 /* KVM implementation requires this capability */
 return kvm_direct_msi_enabled() ? "arm-its-kvm" : NULL;
 } else {
-/* Software emulation is not implemented yet */
-return NULL;
+/* Software emulation based model */
+return "arm-gicv3-its";
 }
 }
 
-- 
2.27.0




[PATCH v3 1/8] hw/intc: GICv3 ITS initial framework

2021-04-29 Thread Shashi Mallela
Added register definitions relevant to ITS,implemented overall
ITS device framework with stubs for ITS control and translater
regions read/write,extended ITS common to handle mmio init between
existing kvm device and newer qemu device.

Signed-off-by: Shashi Mallela 
---
 hw/intc/arm_gicv3_its.c| 239 +
 hw/intc/arm_gicv3_its_common.c |  11 +-
 hw/intc/arm_gicv3_its_kvm.c|   2 +-
 hw/intc/gicv3_internal.h   |  88 +++--
 hw/intc/meson.build|   1 +
 include/hw/intc/arm_gicv3_its_common.h |  10 +-
 6 files changed, 331 insertions(+), 20 deletions(-)
 create mode 100644 hw/intc/arm_gicv3_its.c

diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
new file mode 100644
index 00..7b11330e01
--- /dev/null
+++ b/hw/intc/arm_gicv3_its.c
@@ -0,0 +1,239 @@
+/*
+ * ITS emulation for a GICv3-based system
+ *
+ * Copyright Linaro.org 2021
+ *
+ * Authors:
+ *  Shashi Mallela 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version.  See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/qdev-properties.h"
+#include "hw/intc/arm_gicv3_its_common.h"
+#include "gicv3_internal.h"
+#include "qom/object.h"
+
+typedef struct GICv3ITSClass GICv3ITSClass;
+/* This is reusing the GICv3ITSState typedef from ARM_GICV3_ITS_COMMON */
+DECLARE_OBJ_CHECKERS(GICv3ITSState, GICv3ITSClass,
+ ARM_GICV3_ITS, TYPE_ARM_GICV3_ITS)
+
+struct GICv3ITSClass {
+GICv3ITSCommonClass parent_class;
+void (*parent_reset)(DeviceState *dev);
+};
+
+static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset,
+   uint64_t data, unsigned size, MemTxAttrs attrs)
+{
+MemTxResult result = MEMTX_OK;
+
+return result;
+}
+
+static MemTxResult its_writel(GICv3ITSState *s, hwaddr offset,
+   uint64_t value, MemTxAttrs attrs)
+{
+MemTxResult result = MEMTX_OK;
+
+return result;
+}
+
+static MemTxResult its_readl(GICv3ITSState *s, hwaddr offset,
+   uint64_t *data, MemTxAttrs attrs)
+{
+MemTxResult result = MEMTX_OK;
+
+return result;
+}
+
+static MemTxResult its_writell(GICv3ITSState *s, hwaddr offset,
+   uint64_t value, MemTxAttrs attrs)
+{
+MemTxResult result = MEMTX_OK;
+
+return result;
+}
+
+static MemTxResult its_readll(GICv3ITSState *s, hwaddr offset,
+   uint64_t *data, MemTxAttrs attrs)
+{
+MemTxResult result = MEMTX_OK;
+
+return result;
+}
+
+static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data,
+  unsigned size, MemTxAttrs attrs)
+{
+GICv3ITSState *s = (GICv3ITSState *)opaque;
+MemTxResult result;
+
+switch (size) {
+case 4:
+result = its_readl(s, offset, data, attrs);
+break;
+case 8:
+result = its_readll(s, offset, data, attrs);
+break;
+default:
+result = MEMTX_ERROR;
+break;
+}
+
+if (result == MEMTX_ERROR) {
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: invalid guest read at offset " TARGET_FMT_plx
+  "size %u\n", __func__, offset, size);
+/*
+ * The spec requires that reserved registers are RAZ/WI;
+ * so use MEMTX_ERROR returns from leaf functions as a way to
+ * trigger the guest-error logging but don't return it to
+ * the caller, or we'll cause a spurious guest data abort.
+ */
+result = MEMTX_OK;
+*data = 0;
+}
+return result;
+}
+
+static MemTxResult gicv3_its_write(void *opaque, hwaddr offset, uint64_t data,
+   unsigned size, MemTxAttrs attrs)
+{
+GICv3ITSState *s = (GICv3ITSState *)opaque;
+MemTxResult result;
+
+switch (size) {
+case 4:
+result = its_writel(s, offset, data, attrs);
+break;
+case 8:
+result = its_writell(s, offset, data, attrs);
+break;
+default:
+result = MEMTX_ERROR;
+break;
+}
+
+if (result == MEMTX_ERROR) {
+qemu_log_mask(LOG_GUEST_ERROR,
+  "%s: invalid guest write at offset " TARGET_FMT_plx
+  "size %u\n", __func__, offset, size);
+/*
+ * The spec requires that reserved registers are RAZ/WI;
+ * so use MEMTX_ERROR returns from leaf functions as a way to
+ * trigger the guest-error logging but don't return it to
+ * the caller, or we'll cause a spurious guest data abort.
+ */
+result = MEMTX_OK;
+}
+return result;
+}
+
+static const MemoryRegionOps gicv3_its_control_ops = {
+.read_with_attrs = gicv3_its_read,
+.write_with_attrs = gicv3_its_write,
+.valid.min_access_size = 4,
+.valid.max_acc

Re: [PATCH v2 2/8] hw/intc: GICv3 ITS register definitions added

2021-04-29 Thread shashi . mallela
On Thu, 2021-04-29 at 17:46 -0400, shashi.mall...@linaro.org wrote:
On Fri, 2021-04-16 at 19:54 +0100, Peter Maydell wrote:
> On Thu, 1 Apr 2021 at 03:41, Shashi Mallela <
> shashi.mall...@linaro.org> wrote:
> > Defined descriptors for ITS device table,collection table and ITS
> > command queue entities.Implemented register read/write functions,
> > extract ITS table parameters and command queue parameters,extended
> > gicv3 common to capture qemu address space(which host the ITS table
> > platform memories required for subsequent ITS processing) and
> > initialize the same in its device.
> > 
> > Signed-off-by: Shashi Mallela 
> > ---
> >  hw/intc/arm_gicv3_its.c| 313
> > +
> >  hw/intc/arm_gicv3_its_common.c |  42 
> >  hw/intc/gicv3_internal.h   |  33 ++-
> >  include/hw/intc/arm_gicv3_common.h |   4 +
> >  include/hw/intc/arm_gicv3_its_common.h |  28 +++
> >  5 files changed, 414 insertions(+), 6 deletions(-)
> > 
> > diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
> > index 209120d102..81373f049d 100644
> > --- a/hw/intc/arm_gicv3_its.c
> > +++ b/hw/intc/arm_gicv3_its.c
> > @@ -28,6 +28,131 @@ struct GICv3ITSClass {
> >  void (*parent_reset)(DeviceState *dev);
> >  };
> > 
> > +static bool extract_table_params(GICv3ITSState *s, int index)
> > +{
> > +uint16_t num_pages = 0;
> > +uint8_t  page_sz_type;
> > +uint8_t type;
> > +uint32_t page_sz = 0;
> > +uint64_t value = s->baser[index];
> > +
> > +num_pages = FIELD_EX64(value, GITS_BASER, SIZE);
> > +page_sz_type = FIELD_EX64(value, GITS_BASER, PAGESIZE);
> > +
> > +if (page_sz_type == 0) {
> > +page_sz = GITS_ITT_PAGE_SIZE_0;
> > +} else if (page_sz_type == 0) {
> > +page_sz = GITS_ITT_PAGE_SIZE_1;
> > +} else if (page_sz_type == 2) {
> > +page_sz = GITS_ITT_PAGE_SIZE_2;
> > +} else {
> > +return false;
> 
> The spec says that page_sz+type = 0b11 should be treated as 0b10.
> So we could log this as a guest error if you like but otherwise
> should handle it the same way we do 0b10.
> 
> > +}
> 
> if (x == CONST1) {
> } else if (x == CONST2) {
> } else {
> }
> 
> is usually clearer written with switch(). (There are other instances
> of this pattern below.)
> 
> > +
> > +type = FIELD_EX64(value, GITS_BASER, TYPE);
> > +
> > +if (type == GITS_ITT_TYPE_DEVICE) {
> > +s->dt.valid = FIELD_EX64(value, GITS_BASER, VALID);
> > +
> > +if (s->dt.valid) {
> > +s->dt.indirect = FIELD_EX64(value, GITS_BASER,
> > INDIRECT);
> > +s->dt.entry_sz = FIELD_EX64(value, GITS_BASER,
> > ENTRYSIZE);
> > +
> > +if (!s->dt.indirect) {
> > +s->dt.max_entries = ((num_pages + 1) * page_sz) /
> > +   s-
> > >dt.entry_sz;
> > +} else {
> > +s->dt.max_entries = num_pages + 1) * page_sz)
> > /
> > +L1TABLE_ENTRY_SIZE) *
> > +(page_sz / s->dt.entry_sz));
> > +}
> > +
> > +s->dt.max_devids = (1UL << (FIELD_EX64(s->typer,
> > GITS_TYPER,
> > +DEVBITS) +
> > 1));
> > +
> > +if ((page_sz == GITS_ITT_PAGE_SIZE_0) ||
> > +(page_sz == GITS_ITT_PAGE_SIZE_1)) {
> > +s->dt.base_addr = FIELD_EX64(value, GITS_BASER,
> > PHYADDR);
> > +s->dt.base_addr <<= R_GITS_BASER_PHYADDR_SHIFT;
> > +} else if (page_sz == GITS_ITT_PAGE_SIZE_2) {
> > +s->dt.base_addr = FIELD_EX64(value, GITS_BASER,
> > PHYADDRL_64K) <<
> > +  R_GITS_BASER_PHYADDRL_64K_SHIFT;
> > +  s->dt.base_addr |= ((value >>
> > R_GITS_BASER_PHYADDR_SHIFT) &
> > +   R_GITS_BASER_PHYADDRH_64K_M
> > ASK) <<
> > +   R_GITS_BASER_PHYADDRH_64K_S
> > HIFT;
> > +}
> > +}
> > +} else if (type == GITS_ITT_TYPE_COLLECTION) {
> > +s->ct.valid = FIELD_EX64(value, GITS_BASER, VALID);
> > +
> > +/*
> > + * GITS_TYPER.HCC is 0 for this implementation
> > + * hence writes are discarded if ct.valid is 0
> > + */
> > +if (s->ct.valid) {
> > +s->ct.indirect = FIELD_EX64(value, GITS_BASER,
> > INDIRECT);
> > +s->ct.entry_sz = FIELD_EX64(value, GITS_BASER,
> > ENTRYSIZE);
> > +
> > +if (!s->ct.indirect) {
> > +s->ct.max_entries = ((num_pages + 1) * page_sz) /
> > +  s->ct.entry_sz;
> > +} else {
> > +s->ct.max_entries = num_pages + 1) * page_sz)
> > /
> > +  L1TABLE_ENTRY_SIZE) *
> > +  (page_sz / s->ct.entry_sz));
> > +   

Re: [PATCH v2 5/8] hw/intc: GICv3 ITS Feature enablement

2021-04-29 Thread shashi . mallela
On Mon, 2021-04-19 at 11:51 +0100, Peter Maydell wrote:
> On Thu, 1 Apr 2021 at 03:41, Shashi Mallela <
> shashi.mall...@linaro.org> wrote:
> > Added properties to enable ITS feature and define qemu system
> > address space memory in gicv3 common,setup distributor and
> > redistributor registers to indicate LPI support.
> > 
> > Signed-off-by: Shashi Mallela 
> > ---
> >  hw/intc/arm_gicv3_common.c | 16 
> >  hw/intc/arm_gicv3_dist.c   | 22 --
> >  hw/intc/arm_gicv3_redist.c | 28 +-
> > --
> >  hw/intc/gicv3_internal.h   | 17 +
> >  include/hw/intc/arm_gicv3_common.h |  8 
> >  5 files changed, 86 insertions(+), 5 deletions(-)
> > 
> > diff --git a/hw/intc/arm_gicv3_common.c
> > b/hw/intc/arm_gicv3_common.c
> > index 58ef65f589..3bfc52f7fa 100644
> > --- a/hw/intc/arm_gicv3_common.c
> > +++ b/hw/intc/arm_gicv3_common.c
> > @@ -156,6 +156,7 @@ static const VMStateDescription
> > vmstate_gicv3_cpu = {
> >  VMSTATE_UINT32(gicr_waker, GICv3CPUState),
> >  VMSTATE_UINT64(gicr_propbaser, GICv3CPUState),
> >  VMSTATE_UINT64(gicr_pendbaser, GICv3CPUState),
> > +VMSTATE_BOOL(lpi_outofrange, GICv3CPUState),
> >  VMSTATE_UINT32(gicr_igroupr0, GICv3CPUState),
> >  VMSTATE_UINT32(gicr_ienabler0, GICv3CPUState),
> >  VMSTATE_UINT32(gicr_ipendr0, GICv3CPUState),
> > @@ -227,6 +228,7 @@ static const VMStateDescription vmstate_gicv3 =
> > {
> >  .priority = MIG_PRI_GICV3,
> >  .fields = (VMStateField[]) {
> >  VMSTATE_UINT32(gicd_ctlr, GICv3State),
> > +VMSTATE_UINT32(gicd_typer, GICv3State),
> >  VMSTATE_UINT32_ARRAY(gicd_statusr, GICv3State, 2),
> >  VMSTATE_UINT32_ARRAY(group, GICv3State, GICV3_BMP_SIZE),
> >  VMSTATE_UINT32_ARRAY(grpmod, GICv3State, GICV3_BMP_SIZE),
> 
> You can't add fields to an existing VMStateDescription like this
> without extra effort to handle migration compatibility.
> What are we trying to achieve with the extra fields?
> GICD_TYPER is read-only, I think.
> I don't think we need an lpi_outofrange flag: we should just
> naturally
> handle this as part of working with the GITR_PROPBASER.IDbits field.
> 
> Removed all fields to VMStateDescription,handled as part of working 
> with GITR_PROPBASER.IDbits field
>
> > @@ -381,6 +383,16 @@ static void
> > arm_gicv3_common_realize(DeviceState *dev, Error **errp)
> >  (1 << 24) |
> >  (i << 8) |
> >  (last << 4);
> > +
> > +if (s->lpi_enable) {
> > +s->cpu[i].gicr_typer |= GICR_TYPER_PLPIS;
> > +
> > +if (!s->sysmem) {
> > +error_setg(errp,
> > +"Redist-ITS: Guest 'sysmem' reference link not
> > set");
> > +return;
> > +}
> > +}
> >  }
> >  }
> > 
> > @@ -406,6 +418,7 @@ static void arm_gicv3_common_reset(DeviceState
> > *dev)
> >  cs->gicr_waker = GICR_WAKER_ProcessorSleep |
> > GICR_WAKER_ChildrenAsleep;
> >  cs->gicr_propbaser = 0;
> >  cs->gicr_pendbaser = 0;
> > +cs->lpi_outofrange = false;
> >  /* If we're resetting a TZ-aware GIC as if secure firmware
> >   * had set it up ready to start a kernel in non-secure, we
> >   * need to set interrupts to group 1 so the kernel can use
> > them.
> > @@ -494,9 +507,12 @@ static Property arm_gicv3_common_properties[]
> > = {
> >  DEFINE_PROP_UINT32("num-cpu", GICv3State, num_cpu, 1),
> >  DEFINE_PROP_UINT32("num-irq", GICv3State, num_irq, 32),
> >  DEFINE_PROP_UINT32("revision", GICv3State, revision, 3),
> > +DEFINE_PROP_BOOL("has-lpi", GICv3State, lpi_enable, 0),
> >  DEFINE_PROP_BOOL("has-security-extensions", GICv3State,
> > security_extn, 0),
> >  DEFINE_PROP_ARRAY("redist-region-count", GICv3State,
> > nb_redist_regions,
> >redist_region_count, qdev_prop_uint32,
> > uint32_t),
> > +DEFINE_PROP_LINK("sysmem", GICv3State, sysmem,
> > TYPE_MEMORY_REGION,
> > + MemoryRegion *),
> >  DEFINE_PROP_END_OF_LIST(),
> >  };
> > 
> > diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c
> > index b65f56f903..96a317a8ef 100644
> > --- a/hw/intc/arm_gicv3_dist.c
> > +++ b/hw/intc/arm_gicv3_dist.c
> > @@ -366,12 +366,15 @@ static MemTxResult gicd_readl(GICv3State *s,
> > hwaddr offset,
> >  return MEMTX_OK;
> >  case GICD_TYPER:
> >  {
> > +bool lpi_supported = false;
> >  /* For this implementation:
> >   * No1N == 1 (1-of-N SPI interrupts not supported)
> >   * A3V == 1 (non-zero values of Affinity level 3
> > supported)
> >   * IDbits == 0xf (we support 16-bit interrupt identifiers)
> >   * DVIS == 0 (Direct virtual LPI injection not supported)
> > - * LPIS == 0 (LPIs not supported)
> > + * LPIS == 1 (LPIs are supported if affinity routin

  1   2   3   4   >