[PATCH v3 06/19] range: Introduce range_get_last_bit()

2024-04-28 Thread Zhenzhong Duan
This helper get the highest 1 bit position of the upper bound.

If the range is empty or upper bound is zero, -1 is returned.

Suggested-by: Cédric Le Goater 
Signed-off-by: Zhenzhong Duan 
---
 include/qemu/range.h | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/include/qemu/range.h b/include/qemu/range.h
index 205e1da76d..8e05bc1d9f 100644
--- a/include/qemu/range.h
+++ b/include/qemu/range.h
@@ -20,6 +20,8 @@
 #ifndef QEMU_RANGE_H
 #define QEMU_RANGE_H
 
+#include "qemu/bitops.h"
+
 /*
  * Operations on 64 bit address ranges.
  * Notes:
@@ -217,6 +219,15 @@ static inline int ranges_overlap(uint64_t first1, uint64_t 
len1,
 return !(last2 < first1 || last1 < first2);
 }
 
+/* Get highest non-zero bit position of a range */
+static inline int range_get_last_bit(Range *range)
+{
+if (range_is_empty(range) || !range->upb) {
+return -1;
+}
+return find_last_bit(&range->upb, sizeof(range->upb));
+}
+
 /*
  * Return -1 if @a < @b, 1 @a > @b, and 0 if they touch or overlap.
  * Both @a and @b must not be empty.
-- 
2.34.1




[PATCH v3 03/19] backends/iommufd: Introduce abstract HostIOMMUDeviceIOMMUFD device

2024-04-28 Thread Zhenzhong Duan
HostIOMMUDeviceIOMMUFD represents a host IOMMU device under iommufd
backend.

Currently it contains public iommufd handle and device id which
will be passed to vIOMMU to allocate/free ioas, hwpt, etc.

When nested translation is supported in future, vIOMMU will
request iommufd related operations like attaching/detaching hwpt.
VFIO and VDPA device have different way of attaching/detaching hwpt.
So HostIOMMUDeviceIOMMUFD is still an abstract class which will be
inherited by VFIO and VDPA device sub-classes.

Opportunistically, add missed header to include/sysemu/iommufd.h.

Suggested-by: Cédric Le Goater 
Signed-off-by: Yi Liu 
Signed-off-by: Zhenzhong Duan 
---
 include/sysemu/iommufd.h | 30 ++
 backends/iommufd.c   | 37 -
 2 files changed, 50 insertions(+), 17 deletions(-)

diff --git a/include/sysemu/iommufd.h b/include/sysemu/iommufd.h
index 9af27ebd6c..6a9fb0007a 100644
--- a/include/sysemu/iommufd.h
+++ b/include/sysemu/iommufd.h
@@ -1,9 +1,23 @@
+/*
+ * iommufd container backend declaration
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ * Copyright Red Hat, Inc. 2024
+ *
+ * Authors: Yi Liu 
+ *  Eric Auger 
+ *  Zhenzhong Duan 
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
 #ifndef SYSEMU_IOMMUFD_H
 #define SYSEMU_IOMMUFD_H
 
 #include "qom/object.h"
 #include "exec/hwaddr.h"
 #include "exec/cpu-common.h"
+#include "sysemu/host_iommu_device.h"
 
 #define TYPE_IOMMUFD_BACKEND "iommufd"
 OBJECT_DECLARE_TYPE(IOMMUFDBackend, IOMMUFDBackendClass, IOMMUFD_BACKEND)
@@ -33,4 +47,20 @@ int iommufd_backend_map_dma(IOMMUFDBackend *be, uint32_t 
ioas_id, hwaddr iova,
 ram_addr_t size, void *vaddr, bool readonly);
 int iommufd_backend_unmap_dma(IOMMUFDBackend *be, uint32_t ioas_id,
   hwaddr iova, ram_addr_t size);
+
+#define TYPE_HOST_IOMMU_DEVICE_IOMMUFD TYPE_HOST_IOMMU_DEVICE "-iommufd"
+OBJECT_DECLARE_TYPE(HostIOMMUDeviceIOMMUFD, HostIOMMUDeviceIOMMUFDClass,
+HOST_IOMMU_DEVICE_IOMMUFD)
+
+/* Abstract of host IOMMU device with iommufd backend */
+struct HostIOMMUDeviceIOMMUFD {
+HostIOMMUDevice parent_obj;
+
+IOMMUFDBackend *iommufd;
+uint32_t devid;
+};
+
+struct HostIOMMUDeviceIOMMUFDClass {
+HostIOMMUDeviceClass parent_class;
+};
 #endif
diff --git a/backends/iommufd.c b/backends/iommufd.c
index 76a0204852..19e46194a2 100644
--- a/backends/iommufd.c
+++ b/backends/iommufd.c
@@ -211,23 +211,26 @@ int iommufd_backend_unmap_dma(IOMMUFDBackend *be, 
uint32_t ioas_id,
 return ret;
 }
 
-static const TypeInfo iommufd_backend_info = {
-.name = TYPE_IOMMUFD_BACKEND,
-.parent = TYPE_OBJECT,
-.instance_size = sizeof(IOMMUFDBackend),
-.instance_init = iommufd_backend_init,
-.instance_finalize = iommufd_backend_finalize,
-.class_size = sizeof(IOMMUFDBackendClass),
-.class_init = iommufd_backend_class_init,
-.interfaces = (InterfaceInfo[]) {
-{ TYPE_USER_CREATABLE },
-{ }
+static const TypeInfo types[] = {
+{
+.name = TYPE_IOMMUFD_BACKEND,
+.parent = TYPE_OBJECT,
+.instance_size = sizeof(IOMMUFDBackend),
+.instance_init = iommufd_backend_init,
+.instance_finalize = iommufd_backend_finalize,
+.class_size = sizeof(IOMMUFDBackendClass),
+.class_init = iommufd_backend_class_init,
+.interfaces = (InterfaceInfo[]) {
+{ TYPE_USER_CREATABLE },
+{ }
+}
+}, {
+.name = TYPE_HOST_IOMMU_DEVICE_IOMMUFD,
+.parent = TYPE_HOST_IOMMU_DEVICE,
+.instance_size = sizeof(HostIOMMUDeviceIOMMUFD),
+.class_size = sizeof(HostIOMMUDeviceIOMMUFDClass),
+.abstract = true,
 }
 };
 
-static void register_types(void)
-{
-type_register_static(&iommufd_backend_info);
-}
-
-type_init(register_types);
+DEFINE_TYPES(types)
-- 
2.34.1




[PATCH v3 17/19] intel_iommu: Extract out vtd_cap_init() to initialize cap/ecap

2024-04-28 Thread Zhenzhong Duan
Extract cap/ecap initialization in vtd_cap_init() to make code
cleaner.

No functional change intended.

Reviewed-by: Eric Auger 
Signed-off-by: Zhenzhong Duan 
---
 hw/i386/intel_iommu.c | 93 ---
 1 file changed, 51 insertions(+), 42 deletions(-)

diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index cc8e59674e..519063c8f8 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -3934,30 +3934,10 @@ static void vtd_iommu_replay(IOMMUMemoryRegion 
*iommu_mr, IOMMUNotifier *n)
 return;
 }
 
-/* Do the initialization. It will also be called when reset, so pay
- * attention when adding new initialization stuff.
- */
-static void vtd_init(IntelIOMMUState *s)
+static void vtd_cap_init(IntelIOMMUState *s)
 {
 X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s);
 
-memset(s->csr, 0, DMAR_REG_SIZE);
-memset(s->wmask, 0, DMAR_REG_SIZE);
-memset(s->w1cmask, 0, DMAR_REG_SIZE);
-memset(s->womask, 0, DMAR_REG_SIZE);
-
-s->root = 0;
-s->root_scalable = false;
-s->dmar_enabled = false;
-s->intr_enabled = false;
-s->iq_head = 0;
-s->iq_tail = 0;
-s->iq = 0;
-s->iq_size = 0;
-s->qi_enabled = false;
-s->iq_last_desc_type = VTD_INV_DESC_NONE;
-s->iq_dw = false;
-s->next_frcd_reg = 0;
 s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND |
  VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS |
  VTD_CAP_MGAW(s->aw_bits);
@@ -3974,27 +3954,6 @@ static void vtd_init(IntelIOMMUState *s)
 }
 s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO;
 
-/*
- * Rsvd field masks for spte
- */
-vtd_spte_rsvd[0] = ~0ULL;
-vtd_spte_rsvd[1] = VTD_SPTE_PAGE_L1_RSVD_MASK(s->aw_bits,
-  x86_iommu->dt_supported);
-vtd_spte_rsvd[2] = VTD_SPTE_PAGE_L2_RSVD_MASK(s->aw_bits);
-vtd_spte_rsvd[3] = VTD_SPTE_PAGE_L3_RSVD_MASK(s->aw_bits);
-vtd_spte_rsvd[4] = VTD_SPTE_PAGE_L4_RSVD_MASK(s->aw_bits);
-
-vtd_spte_rsvd_large[2] = VTD_SPTE_LPAGE_L2_RSVD_MASK(s->aw_bits,
- 
x86_iommu->dt_supported);
-vtd_spte_rsvd_large[3] = VTD_SPTE_LPAGE_L3_RSVD_MASK(s->aw_bits,
- 
x86_iommu->dt_supported);
-
-if (s->scalable_mode || s->snoop_control) {
-vtd_spte_rsvd[1] &= ~VTD_SPTE_SNP;
-vtd_spte_rsvd_large[2] &= ~VTD_SPTE_SNP;
-vtd_spte_rsvd_large[3] &= ~VTD_SPTE_SNP;
-}
-
 if (x86_iommu_ir_supported(x86_iommu)) {
 s->ecap |= VTD_ECAP_IR | VTD_ECAP_MHMV;
 if (s->intr_eim == ON_OFF_AUTO_ON) {
@@ -4027,6 +3986,56 @@ static void vtd_init(IntelIOMMUState *s)
 if (s->pasid) {
 s->ecap |= VTD_ECAP_PASID;
 }
+}
+
+/*
+ * Do the initialization. It will also be called when reset, so pay
+ * attention when adding new initialization stuff.
+ */
+static void vtd_init(IntelIOMMUState *s)
+{
+X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s);
+
+memset(s->csr, 0, DMAR_REG_SIZE);
+memset(s->wmask, 0, DMAR_REG_SIZE);
+memset(s->w1cmask, 0, DMAR_REG_SIZE);
+memset(s->womask, 0, DMAR_REG_SIZE);
+
+s->root = 0;
+s->root_scalable = false;
+s->dmar_enabled = false;
+s->intr_enabled = false;
+s->iq_head = 0;
+s->iq_tail = 0;
+s->iq = 0;
+s->iq_size = 0;
+s->qi_enabled = false;
+s->iq_last_desc_type = VTD_INV_DESC_NONE;
+s->iq_dw = false;
+s->next_frcd_reg = 0;
+
+vtd_cap_init(s);
+
+/*
+ * Rsvd field masks for spte
+ */
+vtd_spte_rsvd[0] = ~0ULL;
+vtd_spte_rsvd[1] = VTD_SPTE_PAGE_L1_RSVD_MASK(s->aw_bits,
+  x86_iommu->dt_supported);
+vtd_spte_rsvd[2] = VTD_SPTE_PAGE_L2_RSVD_MASK(s->aw_bits);
+vtd_spte_rsvd[3] = VTD_SPTE_PAGE_L3_RSVD_MASK(s->aw_bits);
+vtd_spte_rsvd[4] = VTD_SPTE_PAGE_L4_RSVD_MASK(s->aw_bits);
+
+vtd_spte_rsvd_large[2] = VTD_SPTE_LPAGE_L2_RSVD_MASK(s->aw_bits,
+x86_iommu->dt_supported);
+vtd_spte_rsvd_large[3] = VTD_SPTE_LPAGE_L3_RSVD_MASK(s->aw_bits,
+x86_iommu->dt_supported);
+
+if (s->scalable_mode || s->snoop_control) {
+vtd_spte_rsvd[1] &= ~VTD_SPTE_SNP;
+vtd_spte_rsvd_large[2] &= ~VTD_SPTE_SNP;
+vtd_spte_rsvd_large[3] &= ~VTD_SPTE_SNP;
+}
 
 vtd_reset_caches(s);
 
-- 
2.34.1




[PATCH v3 12/19] vfio: Introduce VFIOIOMMUClass::hiod_typename attribute

2024-04-28 Thread Zhenzhong Duan
Initialize attribute VFIOIOMMUClass::hiod_typename based on
VFIO backend type.

This attribute will facilitate HostIOMMUDevice creation in
vfio_attach_device().

Suggested-by: Cédric Le Goater 
Signed-off-by: Zhenzhong Duan 
---
 include/hw/vfio/vfio-container-base.h | 3 +++
 hw/vfio/container.c   | 2 ++
 hw/vfio/iommufd.c | 2 ++
 3 files changed, 7 insertions(+)

diff --git a/include/hw/vfio/vfio-container-base.h 
b/include/hw/vfio/vfio-container-base.h
index 3582d5f97a..c387f0d8a4 100644
--- a/include/hw/vfio/vfio-container-base.h
+++ b/include/hw/vfio/vfio-container-base.h
@@ -110,6 +110,9 @@ DECLARE_CLASS_CHECKERS(VFIOIOMMUClass, VFIO_IOMMU, 
TYPE_VFIO_IOMMU)
 struct VFIOIOMMUClass {
 InterfaceClass parent_class;
 
+/* Properties */
+const char *hiod_typename;
+
 /* basic feature */
 int (*setup)(VFIOContainerBase *bcontainer, Error **errp);
 int (*dma_map)(const VFIOContainerBase *bcontainer,
diff --git a/hw/vfio/container.c b/hw/vfio/container.c
index 3683487605..57c814fcd5 100644
--- a/hw/vfio/container.c
+++ b/hw/vfio/container.c
@@ -1133,6 +1133,8 @@ static void vfio_iommu_legacy_class_init(ObjectClass 
*klass, void *data)
 {
 VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass);
 
+vioc->hiod_typename = TYPE_HOST_IOMMU_DEVICE_LEGACY_VFIO;
+
 vioc->setup = vfio_legacy_setup;
 vioc->dma_map = vfio_legacy_dma_map;
 vioc->dma_unmap = vfio_legacy_dma_unmap;
diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
index 6bc2dc68f6..1ac7dea789 100644
--- a/hw/vfio/iommufd.c
+++ b/hw/vfio/iommufd.c
@@ -628,6 +628,8 @@ static void vfio_iommu_iommufd_class_init(ObjectClass 
*klass, void *data)
 {
 VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass);
 
+vioc->hiod_typename = TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO;
+
 vioc->dma_map = iommufd_cdev_map;
 vioc->dma_unmap = iommufd_cdev_unmap;
 vioc->attach_device = iommufd_cdev_attach;
-- 
2.34.1




[PATCH v3 08/19] backends/iommufd: Introduce helper function iommufd_backend_get_device_info()

2024-04-28 Thread Zhenzhong Duan
Introduce a helper function iommufd_backend_get_device_info() to get
host IOMMU related information through iommufd uAPI.

Signed-off-by: Yi Liu 
Signed-off-by: Yi Sun 
Signed-off-by: Zhenzhong Duan 
---
 include/sysemu/iommufd.h |  4 
 backends/iommufd.c   | 24 +++-
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/include/sysemu/iommufd.h b/include/sysemu/iommufd.h
index 6a9fb0007a..e9593637a3 100644
--- a/include/sysemu/iommufd.h
+++ b/include/sysemu/iommufd.h
@@ -17,6 +17,7 @@
 #include "qom/object.h"
 #include "exec/hwaddr.h"
 #include "exec/cpu-common.h"
+#include 
 #include "sysemu/host_iommu_device.h"
 
 #define TYPE_IOMMUFD_BACKEND "iommufd"
@@ -47,6 +48,9 @@ int iommufd_backend_map_dma(IOMMUFDBackend *be, uint32_t 
ioas_id, hwaddr iova,
 ram_addr_t size, void *vaddr, bool readonly);
 int iommufd_backend_unmap_dma(IOMMUFDBackend *be, uint32_t ioas_id,
   hwaddr iova, ram_addr_t size);
+int iommufd_backend_get_device_info(IOMMUFDBackend *be, uint32_t devid,
+enum iommu_hw_info_type *type,
+void *data, uint32_t len, Error **errp);
 
 #define TYPE_HOST_IOMMU_DEVICE_IOMMUFD TYPE_HOST_IOMMU_DEVICE "-iommufd"
 OBJECT_DECLARE_TYPE(HostIOMMUDeviceIOMMUFD, HostIOMMUDeviceIOMMUFDClass,
diff --git a/backends/iommufd.c b/backends/iommufd.c
index 19e46194a2..d61209788a 100644
--- a/backends/iommufd.c
+++ b/backends/iommufd.c
@@ -19,7 +19,6 @@
 #include "monitor/monitor.h"
 #include "trace.h"
 #include 
-#include 
 
 static void iommufd_backend_init(Object *obj)
 {
@@ -211,6 +210,29 @@ int iommufd_backend_unmap_dma(IOMMUFDBackend *be, uint32_t 
ioas_id,
 return ret;
 }
 
+int iommufd_backend_get_device_info(IOMMUFDBackend *be, uint32_t devid,
+enum iommu_hw_info_type *type,
+void *data, uint32_t len, Error **errp)
+{
+struct iommu_hw_info info = {
+.size = sizeof(info),
+.dev_id = devid,
+.data_len = len,
+.data_uptr = (uintptr_t)data,
+};
+int ret;
+
+ret = ioctl(be->fd, IOMMU_GET_HW_INFO, &info);
+if (ret) {
+error_setg_errno(errp, errno, "Failed to get hardware info");
+} else {
+g_assert(type);
+*type = info.out_data_type;
+}
+
+return ret;
+}
+
 static const TypeInfo types[] = {
 {
 .name = TYPE_IOMMUFD_BACKEND,
-- 
2.34.1




[PATCH v3 14/19] hw/pci: Introduce helper function pci_device_get_iommu_bus_devfn()

2024-04-28 Thread Zhenzhong Duan
Extract out pci_device_get_iommu_bus_devfn() from
pci_device_iommu_address_space() to facilitate
implementation of pci_device_[set|unset]_iommu_device()
in following patch.

No functional change intended.

Signed-off-by: Yi Liu 
Signed-off-by: Yi Sun 
Signed-off-by: Nicolin Chen 
Signed-off-by: Zhenzhong Duan 
---
 hw/pci/pci.c | 48 +---
 1 file changed, 45 insertions(+), 3 deletions(-)

diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 324c1302d2..02a4bb2af6 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -2648,11 +2648,27 @@ static void pci_device_class_base_init(ObjectClass 
*klass, void *data)
 }
 }
 
-AddressSpace *pci_device_iommu_address_space(PCIDevice *dev)
+/*
+ * Get IOMMU root bus, aliased bus and devfn of a PCI device
+ *
+ * IOMMU root bus is needed by all call sites to call into iommu_ops.
+ * For call sites which don't need aliased BDF, passing NULL to
+ * aliased_[bus|devfn] is allowed.
+ *
+ * @piommu_bus: return root #PCIBus backed by an IOMMU for the PCI device.
+ *
+ * @aliased_bus: return aliased #PCIBus of the PCI device, optional.
+ *
+ * @aliased_devfn: return aliased devfn of the PCI device, optional.
+ */
+static void pci_device_get_iommu_bus_devfn(PCIDevice *dev,
+   PCIBus **piommu_bus,
+   PCIBus **aliased_bus,
+   int *aliased_devfn)
 {
 PCIBus *bus = pci_get_bus(dev);
 PCIBus *iommu_bus = bus;
-uint8_t devfn = dev->devfn;
+int devfn = dev->devfn;
 
 while (iommu_bus && !iommu_bus->iommu_ops && iommu_bus->parent_dev) {
 PCIBus *parent_bus = pci_get_bus(iommu_bus->parent_dev);
@@ -2693,7 +2709,33 @@ AddressSpace *pci_device_iommu_address_space(PCIDevice 
*dev)
 
 iommu_bus = parent_bus;
 }
-if (!pci_bus_bypass_iommu(bus) && iommu_bus->iommu_ops) {
+
+assert(0 <= devfn && devfn < PCI_DEVFN_MAX);
+assert(iommu_bus);
+
+if (pci_bus_bypass_iommu(bus) || !iommu_bus->iommu_ops) {
+iommu_bus = NULL;
+}
+
+*piommu_bus = iommu_bus;
+
+if (aliased_bus) {
+*aliased_bus = bus;
+}
+
+if (aliased_devfn) {
+*aliased_devfn = devfn;
+}
+}
+
+AddressSpace *pci_device_iommu_address_space(PCIDevice *dev)
+{
+PCIBus *bus;
+PCIBus *iommu_bus;
+int devfn;
+
+pci_device_get_iommu_bus_devfn(dev, &iommu_bus, &bus, &devfn);
+if (iommu_bus) {
 return iommu_bus->iommu_ops->get_address_space(bus,
  iommu_bus->iommu_opaque, devfn);
 }
-- 
2.34.1




[PATCH v3 05/19] backends/host_iommu_device: Introduce HostIOMMUDeviceCaps

2024-04-28 Thread Zhenzhong Duan
HostIOMMUDeviceCaps's elements map to the host IOMMU's capabilities.
Different platform IOMMU can support different elements.

Currently only two elements, type and aw_bits, type hints the host
platform IOMMU type, i.e., INTEL vtd, ARM smmu, etc; aw_bits hints
host IOMMU address width.

Introduce .check_cap() handler to check if HOST_IOMMU_DEVICE_CAP_XXX
is supported.

Introduce a HostIOMMUDevice API host_iommu_device_check_cap() which
is a wrapper of .check_cap().

Introduce a HostIOMMUDevice API host_iommu_device_check_cap_common()
to check common capabalities of different host platform IOMMUs.

Suggested-by: Cédric Le Goater 
Signed-off-by: Zhenzhong Duan 
---
 include/sysemu/host_iommu_device.h | 44 ++
 backends/host_iommu_device.c   | 29 
 2 files changed, 73 insertions(+)

diff --git a/include/sysemu/host_iommu_device.h 
b/include/sysemu/host_iommu_device.h
index 2b58a94d62..12b6afb463 100644
--- a/include/sysemu/host_iommu_device.h
+++ b/include/sysemu/host_iommu_device.h
@@ -14,12 +14,27 @@
 
 #include "qom/object.h"
 #include "qapi/error.h"
+#include "linux/iommufd.h"
+
+/**
+ * struct HostIOMMUDeviceCaps - Define host IOMMU device capabilities.
+ *
+ * @type: host platform IOMMU type.
+ *
+ * @aw_bits: host IOMMU address width. 0xff if no limitation.
+ */
+typedef struct HostIOMMUDeviceCaps {
+enum iommu_hw_info_type type;
+uint8_t aw_bits;
+} HostIOMMUDeviceCaps;
 
 #define TYPE_HOST_IOMMU_DEVICE "host-iommu-device"
 OBJECT_DECLARE_TYPE(HostIOMMUDevice, HostIOMMUDeviceClass, HOST_IOMMU_DEVICE)
 
 struct HostIOMMUDevice {
 Object parent_obj;
+
+HostIOMMUDeviceCaps caps;
 };
 
 /**
@@ -47,5 +62,34 @@ struct HostIOMMUDeviceClass {
  * Returns: true on success, false on failure.
  */
 bool (*realize)(HostIOMMUDevice *hiod, void *opaque, Error **errp);
+/**
+ * @check_cap: check if a host IOMMU device capability is supported.
+ *
+ * Optional callback, if not implemented, hint not supporting query
+ * of @cap.
+ *
+ * @hiod: pointer to a host IOMMU device instance.
+ *
+ * @cap: capability to check.
+ *
+ * @errp: pass an Error out when fails to query capability.
+ *
+ * Returns: <0 on failure, 0 if a @cap is unsupported, or else
+ * 1 or some positive value for some special @cap,
+ * i.e., HOST_IOMMU_DEVICE_CAP_AW_BITS.
+ */
+int (*check_cap)(HostIOMMUDevice *hiod, int cap, Error **errp);
 };
+
+/*
+ * Host IOMMU device capability list.
+ */
+#define HOST_IOMMU_DEVICE_CAP_IOMMUFD   0
+#define HOST_IOMMU_DEVICE_CAP_IOMMU_TYPE1
+#define HOST_IOMMU_DEVICE_CAP_AW_BITS   2
+
+
+int host_iommu_device_check_cap(HostIOMMUDevice *hiod, int cap, Error **errp);
+int host_iommu_device_check_cap_common(HostIOMMUDevice *hiod, int cap,
+   Error **errp);
 #endif
diff --git a/backends/host_iommu_device.c b/backends/host_iommu_device.c
index 41f2fdce20..b97d008cc7 100644
--- a/backends/host_iommu_device.c
+++ b/backends/host_iommu_device.c
@@ -28,3 +28,32 @@ static void host_iommu_device_init(Object *obj)
 static void host_iommu_device_finalize(Object *obj)
 {
 }
+
+/* Wrapper of HostIOMMUDeviceClass:check_cap */
+int host_iommu_device_check_cap(HostIOMMUDevice *hiod, int cap, Error **errp)
+{
+HostIOMMUDeviceClass *hiodc = HOST_IOMMU_DEVICE_GET_CLASS(hiod);
+if (!hiodc->check_cap) {
+error_setg(errp, ".check_cap() not implemented");
+return -EINVAL;
+}
+
+return hiodc->check_cap(hiod, cap, errp);
+}
+
+/* Implement check on common IOMMU capabilities */
+int host_iommu_device_check_cap_common(HostIOMMUDevice *hiod, int cap,
+   Error **errp)
+{
+HostIOMMUDeviceCaps *caps = &hiod->caps;
+
+switch (cap) {
+case HOST_IOMMU_DEVICE_CAP_IOMMU_TYPE:
+return caps->type;
+case HOST_IOMMU_DEVICE_CAP_AW_BITS:
+return caps->aw_bits;
+default:
+error_setg(errp, "Not support query cap %x", cap);
+return -EINVAL;
+}
+}
-- 
2.34.1




[PATCH v3 19/19] intel_iommu: Check compatibility with host IOMMU capabilities

2024-04-28 Thread Zhenzhong Duan
If check fails, host device (either VFIO or VDPA device) is not
compatible with current vIOMMU config and should not be passed to
guest.

Only aw_bits is checked for now, we don't care other capabilities
before scalable modern mode is introduced.

Signed-off-by: Yi Liu 
Signed-off-by: Zhenzhong Duan 
---
 hw/i386/intel_iommu.c | 28 
 1 file changed, 28 insertions(+)

diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 4f84e2e801..4a295c41cc 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -3819,6 +3819,26 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, 
PCIBus *bus,
 return vtd_dev_as;
 }
 
+static int vtd_check_hdev(IntelIOMMUState *s, VTDHostIOMMUDevice *vtd_hdev,
+  Error **errp)
+{
+HostIOMMUDevice *hiod = vtd_hdev->dev;
+int ret;
+
+/* Common checks */
+ret = host_iommu_device_check_cap(hiod, HOST_IOMMU_DEVICE_CAP_AW_BITS,
+  errp);
+if (ret < 0) {
+return ret;
+}
+if (s->aw_bits > ret) {
+error_setg(errp, "aw-bits %d > host aw-bits %d", s->aw_bits, ret);
+return -EINVAL;
+}
+
+return 0;
+}
+
 static int vtd_dev_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
 HostIOMMUDevice *hiod, Error **errp)
 {
@@ -3829,6 +3849,7 @@ static int vtd_dev_set_iommu_device(PCIBus *bus, void 
*opaque, int devfn,
 .devfn = devfn,
 };
 struct vtd_as_key *new_key;
+int ret;
 
 assert(hiod);
 
@@ -3848,6 +3869,13 @@ static int vtd_dev_set_iommu_device(PCIBus *bus, void 
*opaque, int devfn,
 vtd_hdev->iommu_state = s;
 vtd_hdev->dev = hiod;
 
+ret = vtd_check_hdev(s, vtd_hdev, errp);
+if (ret) {
+g_free(vtd_hdev);
+vtd_iommu_unlock(s);
+return ret;
+}
+
 new_key = g_malloc(sizeof(*new_key));
 new_key->bus = bus;
 new_key->devfn = devfn;
-- 
2.34.1




[PATCH v3 18/19] intel_iommu: Implement [set|unset]_iommu_device() callbacks

2024-04-28 Thread Zhenzhong Duan
From: Yi Liu 

Implement [set|unset]_iommu_device() callbacks in Intel vIOMMU.
In set call, a new structure VTDHostIOMMUDevice which holds
a reference to HostIOMMUDevice is stored in hash table
indexed by PCI BDF.

Signed-off-by: Yi Liu 
Signed-off-by: Yi Sun 
Signed-off-by: Zhenzhong Duan 
---
 hw/i386/intel_iommu_internal.h |  8 
 include/hw/i386/intel_iommu.h  |  2 +
 hw/i386/intel_iommu.c  | 76 ++
 3 files changed, 86 insertions(+)

diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h
index f8cf99bddf..becafd03c1 100644
--- a/hw/i386/intel_iommu_internal.h
+++ b/hw/i386/intel_iommu_internal.h
@@ -537,4 +537,12 @@ typedef struct VTDRootEntry VTDRootEntry;
 #define VTD_SL_IGN_COM  0xbff0ULL
 #define VTD_SL_TM   (1ULL << 62)
 
+
+typedef struct VTDHostIOMMUDevice {
+IntelIOMMUState *iommu_state;
+PCIBus *bus;
+uint8_t devfn;
+HostIOMMUDevice *dev;
+QLIST_ENTRY(VTDHostIOMMUDevice) next;
+} VTDHostIOMMUDevice;
 #endif
diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h
index 7d694b0813..2bbde41e45 100644
--- a/include/hw/i386/intel_iommu.h
+++ b/include/hw/i386/intel_iommu.h
@@ -293,6 +293,8 @@ struct IntelIOMMUState {
 /* list of registered notifiers */
 QLIST_HEAD(, VTDAddressSpace) vtd_as_with_notifiers;
 
+GHashTable *vtd_host_iommu_dev; /* VTDHostIOMMUDevice */
+
 /* interrupt remapping */
 bool intr_enabled;  /* Whether guest enabled IR */
 dma_addr_t intr_root;   /* Interrupt remapping table pointer */
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 519063c8f8..4f84e2e801 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -237,6 +237,13 @@ static gboolean vtd_as_equal(gconstpointer v1, 
gconstpointer v2)
(key1->pasid == key2->pasid);
 }
 
+static gboolean vtd_as_idev_equal(gconstpointer v1, gconstpointer v2)
+{
+const struct vtd_as_key *key1 = v1;
+const struct vtd_as_key *key2 = v2;
+
+return (key1->bus == key2->bus) && (key1->devfn == key2->devfn);
+}
 /*
  * Note that we use pointer to PCIBus as the key, so hashing/shifting
  * based on the pointer value is intended. Note that we deal with
@@ -3812,6 +3819,70 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, 
PCIBus *bus,
 return vtd_dev_as;
 }
 
+static int vtd_dev_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
+HostIOMMUDevice *hiod, Error **errp)
+{
+IntelIOMMUState *s = opaque;
+VTDHostIOMMUDevice *vtd_hdev;
+struct vtd_as_key key = {
+.bus = bus,
+.devfn = devfn,
+};
+struct vtd_as_key *new_key;
+
+assert(hiod);
+
+vtd_iommu_lock(s);
+
+vtd_hdev = g_hash_table_lookup(s->vtd_host_iommu_dev, &key);
+
+if (vtd_hdev) {
+error_setg(errp, "IOMMUFD device already exist");
+vtd_iommu_unlock(s);
+return -EEXIST;
+}
+
+vtd_hdev = g_malloc0(sizeof(VTDHostIOMMUDevice));
+vtd_hdev->bus = bus;
+vtd_hdev->devfn = (uint8_t)devfn;
+vtd_hdev->iommu_state = s;
+vtd_hdev->dev = hiod;
+
+new_key = g_malloc(sizeof(*new_key));
+new_key->bus = bus;
+new_key->devfn = devfn;
+
+object_ref(hiod);
+g_hash_table_insert(s->vtd_host_iommu_dev, new_key, vtd_hdev);
+
+vtd_iommu_unlock(s);
+
+return 0;
+}
+
+static void vtd_dev_unset_iommu_device(PCIBus *bus, void *opaque, int devfn)
+{
+IntelIOMMUState *s = opaque;
+VTDHostIOMMUDevice *vtd_hdev;
+struct vtd_as_key key = {
+.bus = bus,
+.devfn = devfn,
+};
+
+vtd_iommu_lock(s);
+
+vtd_hdev = g_hash_table_lookup(s->vtd_host_iommu_dev, &key);
+if (!vtd_hdev) {
+vtd_iommu_unlock(s);
+return;
+}
+
+g_hash_table_remove(s->vtd_host_iommu_dev, &key);
+object_unref(vtd_hdev->dev);
+
+vtd_iommu_unlock(s);
+}
+
 /* Unmap the whole range in the notifier's scope. */
 static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n)
 {
@@ -4116,6 +4187,8 @@ static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void 
*opaque, int devfn)
 
 static PCIIOMMUOps vtd_iommu_ops = {
 .get_address_space = vtd_host_dma_iommu,
+.set_iommu_device = vtd_dev_set_iommu_device,
+.unset_iommu_device = vtd_dev_unset_iommu_device,
 };
 
 static bool vtd_decide_config(IntelIOMMUState *s, Error **errp)
@@ -4235,6 +4308,9 @@ static void vtd_realize(DeviceState *dev, Error **errp)
  g_free, g_free);
 s->vtd_address_spaces = g_hash_table_new_full(vtd_as_hash, vtd_as_equal,
   g_free, g_free);
+s->vtd_host_iommu_dev = g_hash_table_new_full(vtd_as_hash,
+  vtd_as_idev_equal,
+  g_free, g_free);
 vtd_init(s);
 pci_setup_iommu(bus, &vtd_iommu_ops, dev);
 

[PATCH v3 13/19] vfio: Create host IOMMU device instance

2024-04-28 Thread Zhenzhong Duan
Create host IOMMU device instance in vfio_attach_device() and call
.realize() to initialize it further.

Suggested-by: Cédric Le Goater 
Signed-off-by: Zhenzhong Duan 
---
 include/hw/vfio/vfio-common.h |  1 +
 hw/vfio/common.c  | 18 +-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
index 0943add3bc..b204b93a55 100644
--- a/include/hw/vfio/vfio-common.h
+++ b/include/hw/vfio/vfio-common.h
@@ -126,6 +126,7 @@ typedef struct VFIODevice {
 OnOffAuto pre_copy_dirty_page_tracking;
 bool dirty_pages_supported;
 bool dirty_tracking;
+HostIOMMUDevice *hiod;
 int devid;
 IOMMUFDBackend *iommufd;
 } VFIODevice;
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 8f9cbdc026..0be8b70ebd 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -1497,6 +1497,8 @@ int vfio_attach_device(char *name, VFIODevice *vbasedev,
 {
 const VFIOIOMMUClass *ops =
 VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_LEGACY));
+HostIOMMUDevice *hiod;
+int ret;
 
 if (vbasedev->iommufd) {
 ops = VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_IOMMUFD));
@@ -1504,7 +1506,20 @@ int vfio_attach_device(char *name, VFIODevice *vbasedev,
 
 assert(ops);
 
-return ops->attach_device(name, vbasedev, as, errp);
+ret = ops->attach_device(name, vbasedev, as, errp);
+if (ret < 0) {
+return ret;
+}
+
+hiod = HOST_IOMMU_DEVICE(object_new(ops->hiod_typename));
+if (!HOST_IOMMU_DEVICE_GET_CLASS(hiod)->realize(hiod, vbasedev, errp)) {
+object_unref(hiod);
+ops->detach_device(vbasedev);
+return -EINVAL;
+}
+vbasedev->hiod = hiod;
+
+return 0;
 }
 
 void vfio_detach_device(VFIODevice *vbasedev)
@@ -1512,5 +1527,6 @@ void vfio_detach_device(VFIODevice *vbasedev)
 if (!vbasedev->bcontainer) {
 return;
 }
+object_unref(vbasedev->hiod);
 vbasedev->bcontainer->ops->detach_device(vbasedev);
 }
-- 
2.34.1




[PATCH v3 07/19] vfio/container: Implement HostIOMMUDeviceClass::realize() handler

2024-04-28 Thread Zhenzhong Duan
Utilize range_get_last_bit() to get host IOMMU address width and
package it in HostIOMMUDeviceCaps for query with .check_cap().

Signed-off-by: Zhenzhong Duan 
---
 hw/vfio/container.c | 29 +
 1 file changed, 29 insertions(+)

diff --git a/hw/vfio/container.c b/hw/vfio/container.c
index 3b6826996a..863eec3943 100644
--- a/hw/vfio/container.c
+++ b/hw/vfio/container.c
@@ -1143,6 +1143,34 @@ static void vfio_iommu_legacy_class_init(ObjectClass 
*klass, void *data)
 vioc->pci_hot_reset = vfio_legacy_pci_hot_reset;
 };
 
+static bool hiod_legacy_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
+ Error **errp)
+{
+VFIODevice *vdev = opaque;
+/* iova_ranges is a sorted list */
+GList *l = g_list_last(vdev->bcontainer->iova_ranges);
+
+/* There is no VFIO uAPI to query host platform IOMMU type */
+hiod->caps.type = IOMMU_HW_INFO_TYPE_NONE;
+HOST_IOMMU_DEVICE_IOMMUFD_VFIO(hiod)->vdev = vdev;
+
+if (l) {
+Range *range = l->data;
+hiod->caps.aw_bits = range_get_last_bit(range) + 1;
+} else {
+hiod->caps.aw_bits = 0xff;
+}
+
+return true;
+}
+
+static void hiod_legacy_vfio_class_init(ObjectClass *oc, void *data)
+{
+HostIOMMUDeviceClass *hioc = HOST_IOMMU_DEVICE_CLASS(oc);
+
+hioc->realize = hiod_legacy_vfio_realize;
+};
+
 static const TypeInfo types[] = {
 {
 .name = TYPE_VFIO_IOMMU_LEGACY,
@@ -1152,6 +1180,7 @@ static const TypeInfo types[] = {
 .name = TYPE_HOST_IOMMU_DEVICE_LEGACY_VFIO,
 .parent = TYPE_HOST_IOMMU_DEVICE,
 .instance_size = sizeof(HostIOMMUDeviceLegacyVFIO),
+.class_init = hiod_legacy_vfio_class_init,
 }
 };
 
-- 
2.34.1




[PATCH v3 15/19] hw/pci: Introduce pci_device_[set|unset]_iommu_device()

2024-04-28 Thread Zhenzhong Duan
From: Yi Liu 

pci_device_[set|unset]_iommu_device() call pci_device_get_iommu_bus_devfn()
to get iommu_bus->iommu_ops and call [set|unset]_iommu_device callback to
set/unset HostIOMMUDevice for a given PCI device.

Signed-off-by: Yi Liu 
Signed-off-by: Yi Sun 
Signed-off-by: Nicolin Chen 
Signed-off-by: Zhenzhong Duan 
---
 include/hw/pci/pci.h | 38 +-
 hw/pci/pci.c | 27 +++
 2 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index eaa3fc99d8..849e391813 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -3,6 +3,7 @@
 
 #include "exec/memory.h"
 #include "sysemu/dma.h"
+#include "sysemu/host_iommu_device.h"
 
 /* PCI includes legacy ISA access.  */
 #include "hw/isa/isa.h"
@@ -383,10 +384,45 @@ typedef struct PCIIOMMUOps {
  *
  * @devfn: device and function number
  */
-   AddressSpace * (*get_address_space)(PCIBus *bus, void *opaque, int devfn);
+AddressSpace * (*get_address_space)(PCIBus *bus, void *opaque, int devfn);
+/**
+ * @set_iommu_device: attach a HostIOMMUDevice to a vIOMMU
+ *
+ * Optional callback, if not implemented in vIOMMU, then vIOMMU can't
+ * retrieve host information from the associated HostIOMMUDevice.
+ *
+ * @bus: the #PCIBus of the PCI device.
+ *
+ * @opaque: the data passed to pci_setup_iommu().
+ *
+ * @devfn: device and function number of the PCI device.
+ *
+ * @dev: the data structure representing host IOMMU device.
+ *
+ * @errp: pass an Error out only when return false
+ *
+ * Returns: 0 if HostIOMMUDevice is attached, or else <0 with errp set.
+ */
+int (*set_iommu_device)(PCIBus *bus, void *opaque, int devfn,
+HostIOMMUDevice *dev, Error **errp);
+/**
+ * @unset_iommu_device: detach a HostIOMMUDevice from a vIOMMU
+ *
+ * Optional callback.
+ *
+ * @bus: the #PCIBus of the PCI device.
+ *
+ * @opaque: the data passed to pci_setup_iommu().
+ *
+ * @devfn: device and function number of the PCI device.
+ */
+void (*unset_iommu_device)(PCIBus *bus, void *opaque, int devfn);
 } PCIIOMMUOps;
 
 AddressSpace *pci_device_iommu_address_space(PCIDevice *dev);
+int pci_device_set_iommu_device(PCIDevice *dev, HostIOMMUDevice *hiod,
+Error **errp);
+void pci_device_unset_iommu_device(PCIDevice *dev);
 
 /**
  * pci_setup_iommu: Initialize specific IOMMU handlers for a PCIBus
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 02a4bb2af6..c3293e9357 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -2742,6 +2742,33 @@ AddressSpace *pci_device_iommu_address_space(PCIDevice 
*dev)
 return &address_space_memory;
 }
 
+int pci_device_set_iommu_device(PCIDevice *dev, HostIOMMUDevice *hiod,
+Error **errp)
+{
+PCIBus *iommu_bus;
+
+/* set_iommu_device requires device's direct BDF instead of aliased BDF */
+pci_device_get_iommu_bus_devfn(dev, &iommu_bus, NULL, NULL);
+if (iommu_bus && iommu_bus->iommu_ops->set_iommu_device) {
+return iommu_bus->iommu_ops->set_iommu_device(pci_get_bus(dev),
+  iommu_bus->iommu_opaque,
+  dev->devfn, hiod, errp);
+}
+return 0;
+}
+
+void pci_device_unset_iommu_device(PCIDevice *dev)
+{
+PCIBus *iommu_bus;
+
+pci_device_get_iommu_bus_devfn(dev, &iommu_bus, NULL, NULL);
+if (iommu_bus && iommu_bus->iommu_ops->unset_iommu_device) {
+return iommu_bus->iommu_ops->unset_iommu_device(pci_get_bus(dev),
+
iommu_bus->iommu_opaque,
+dev->devfn);
+}
+}
+
 void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque)
 {
 /*
-- 
2.34.1




[PATCH v3 16/19] vfio/pci: Pass HostIOMMUDevice to vIOMMU

2024-04-28 Thread Zhenzhong Duan
With HostIOMMUDevice passed, vIOMMU can check compatibility with host
IOMMU, call into IOMMUFD specific methods, etc.

Originally-by: Yi Liu 
Signed-off-by: Nicolin Chen 
Signed-off-by: Yi Sun 
Signed-off-by: Zhenzhong Duan 
---
 hw/vfio/pci.c | 20 +++-
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 64780d1b79..224501a86e 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -3111,11 +3111,17 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
 
 vfio_bars_register(vdev);
 
-ret = vfio_add_capabilities(vdev, errp);
+ret = pci_device_set_iommu_device(pdev, vbasedev->hiod, errp);
 if (ret) {
+error_prepend(errp, "Failed to set iommu_device: ");
 goto out_teardown;
 }
 
+ret = vfio_add_capabilities(vdev, errp);
+if (ret) {
+goto out_unset_idev;
+}
+
 if (vdev->vga) {
 vfio_vga_quirk_setup(vdev);
 }
@@ -3132,7 +3138,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
 error_setg(errp,
"cannot support IGD OpRegion feature on hotplugged "
"device");
-goto out_teardown;
+goto out_unset_idev;
 }
 
 ret = vfio_get_dev_region_info(vbasedev,
@@ -3141,13 +3147,13 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
 if (ret) {
 error_setg_errno(errp, -ret,
  "does not support requested IGD OpRegion 
feature");
-goto out_teardown;
+goto out_unset_idev;
 }
 
 ret = vfio_pci_igd_opregion_init(vdev, opregion, errp);
 g_free(opregion);
 if (ret) {
-goto out_teardown;
+goto out_unset_idev;
 }
 }
 
@@ -3233,6 +3239,8 @@ out_deregister:
 if (vdev->intx.mmap_timer) {
 timer_free(vdev->intx.mmap_timer);
 }
+out_unset_idev:
+pci_device_unset_iommu_device(pdev);
 out_teardown:
 vfio_teardown_msi(vdev);
 vfio_bars_exit(vdev);
@@ -3261,6 +3269,7 @@ static void vfio_instance_finalize(Object *obj)
 static void vfio_exitfn(PCIDevice *pdev)
 {
 VFIOPCIDevice *vdev = VFIO_PCI(pdev);
+VFIODevice *vbasedev = &vdev->vbasedev;
 
 vfio_unregister_req_notifier(vdev);
 vfio_unregister_err_notifier(vdev);
@@ -3275,7 +3284,8 @@ static void vfio_exitfn(PCIDevice *pdev)
 vfio_teardown_msi(vdev);
 vfio_pci_disable_rp_atomics(vdev);
 vfio_bars_exit(vdev);
-vfio_migration_exit(&vdev->vbasedev);
+vfio_migration_exit(vbasedev);
+pci_device_unset_iommu_device(pdev);
 }
 
 static void vfio_pci_reset(DeviceState *dev)
-- 
2.34.1




[PATCH v3 09/19] vfio/iommufd: Implement HostIOMMUDeviceClass::realize() handler

2024-04-28 Thread Zhenzhong Duan
It calls iommufd_backend_get_device_info() to get host IOMMU
related information and translate it into HostIOMMUDeviceCaps
for query with .check_cap().

Introduce macro VTD_MGAW_FROM_CAP to get MGAW which equals to
(aw_bits - 1).

Signed-off-by: Zhenzhong Duan 
---
 include/hw/i386/intel_iommu.h |  1 +
 hw/vfio/iommufd.c | 44 +++
 2 files changed, 45 insertions(+)

diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h
index 7fa0a695c8..7d694b0813 100644
--- a/include/hw/i386/intel_iommu.h
+++ b/include/hw/i386/intel_iommu.h
@@ -47,6 +47,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(IntelIOMMUState, 
INTEL_IOMMU_DEVICE)
 #define VTD_HOST_AW_48BIT   48
 #define VTD_HOST_ADDRESS_WIDTH  VTD_HOST_AW_39BIT
 #define VTD_HAW_MASK(aw)((1ULL << (aw)) - 1)
+#define VTD_MGAW_FROM_CAP(cap)  ((cap >> 16) & 0x3fULL)
 
 #define DMAR_REPORT_F_INTR  (1)
 
diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
index 997f4ac43e..6bc2dc68f6 100644
--- a/hw/vfio/iommufd.c
+++ b/hw/vfio/iommufd.c
@@ -25,6 +25,7 @@
 #include "qemu/cutils.h"
 #include "qemu/chardev_open.h"
 #include "pci.h"
+#include "hw/i386/intel_iommu_internal.h"
 
 static int iommufd_cdev_map(const VFIOContainerBase *bcontainer, hwaddr iova,
 ram_addr_t size, void *vaddr, bool readonly)
@@ -634,6 +635,48 @@ static void vfio_iommu_iommufd_class_init(ObjectClass 
*klass, void *data)
 vioc->pci_hot_reset = iommufd_cdev_pci_hot_reset;
 };
 
+static bool hiod_iommufd_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
+  Error **errp)
+{
+VFIODevice *vdev = opaque;
+HostIOMMUDeviceIOMMUFD *idev = HOST_IOMMU_DEVICE_IOMMUFD(hiod);
+HostIOMMUDeviceCaps *caps = &hiod->caps;
+enum iommu_hw_info_type type;
+union {
+struct iommu_hw_info_vtd vtd;
+} data;
+int ret;
+
+HOST_IOMMU_DEVICE_IOMMUFD_VFIO(hiod)->vdev = vdev;
+idev->iommufd = vdev->iommufd;
+idev->devid = vdev->devid;
+
+ret = iommufd_backend_get_device_info(idev->iommufd, idev->devid,
+  &type, &data, sizeof(data), errp);
+if (ret) {
+return false;
+}
+
+caps->type = type;
+
+switch (type) {
+case IOMMU_HW_INFO_TYPE_INTEL_VTD:
+caps->aw_bits = VTD_MGAW_FROM_CAP(data.vtd.cap_reg) + 1;
+break;
+case IOMMU_HW_INFO_TYPE_NONE:
+break;
+}
+
+return true;
+}
+
+static void hiod_iommufd_vfio_class_init(ObjectClass *oc, void *data)
+{
+HostIOMMUDeviceClass *hiodc = HOST_IOMMU_DEVICE_CLASS(oc);
+
+hiodc->realize = hiod_iommufd_vfio_realize;
+};
+
 static const TypeInfo types[] = {
 {
 .name = TYPE_VFIO_IOMMU_IOMMUFD,
@@ -643,6 +686,7 @@ static const TypeInfo types[] = {
 .name = TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO,
 .parent = TYPE_HOST_IOMMU_DEVICE_IOMMUFD,
 .instance_size = sizeof(HostIOMMUDeviceIOMMUFDVFIO),
+.class_init = hiod_iommufd_vfio_class_init,
 }
 };
 
-- 
2.34.1




[PATCH v3 10/19] vfio/container: Implement HostIOMMUDeviceClass::check_cap() handler

2024-04-28 Thread Zhenzhong Duan
Suggested-by: Cédric Le Goater 
Signed-off-by: Zhenzhong Duan 
---
 hw/vfio/container.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/hw/vfio/container.c b/hw/vfio/container.c
index 863eec3943..3683487605 100644
--- a/hw/vfio/container.c
+++ b/hw/vfio/container.c
@@ -1164,11 +1164,23 @@ static bool hiod_legacy_vfio_realize(HostIOMMUDevice 
*hiod, void *opaque,
 return true;
 }
 
+static int hiod_legacy_vfio_check_cap(HostIOMMUDevice *hiod, int cap,
+  Error **errp)
+{
+switch (cap) {
+case HOST_IOMMU_DEVICE_CAP_IOMMUFD:
+return 0;
+default:
+return host_iommu_device_check_cap_common(hiod, cap, errp);
+}
+}
+
 static void hiod_legacy_vfio_class_init(ObjectClass *oc, void *data)
 {
 HostIOMMUDeviceClass *hioc = HOST_IOMMU_DEVICE_CLASS(oc);
 
 hioc->realize = hiod_legacy_vfio_realize;
+hioc->check_cap = hiod_legacy_vfio_check_cap;
 };
 
 static const TypeInfo types[] = {
-- 
2.34.1




[PATCH v3 11/19] backends/iommufd: Implement HostIOMMUDeviceClass::check_cap() handler

2024-04-28 Thread Zhenzhong Duan
Suggested-by: Cédric Le Goater 
Signed-off-by: Zhenzhong Duan 
---
 backends/iommufd.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/backends/iommufd.c b/backends/iommufd.c
index d61209788a..28faec528e 100644
--- a/backends/iommufd.c
+++ b/backends/iommufd.c
@@ -233,6 +233,23 @@ int iommufd_backend_get_device_info(IOMMUFDBackend *be, 
uint32_t devid,
 return ret;
 }
 
+static int hiod_iommufd_check_cap(HostIOMMUDevice *hiod, int cap, Error **errp)
+{
+switch (cap) {
+case HOST_IOMMU_DEVICE_CAP_IOMMUFD:
+return 1;
+default:
+return host_iommu_device_check_cap_common(hiod, cap, errp);
+}
+}
+
+static void hiod_iommufd_class_init(ObjectClass *oc, void *data)
+{
+HostIOMMUDeviceClass *hioc = HOST_IOMMU_DEVICE_CLASS(oc);
+
+hioc->check_cap = hiod_iommufd_check_cap;
+};
+
 static const TypeInfo types[] = {
 {
 .name = TYPE_IOMMUFD_BACKEND,
@@ -251,6 +268,7 @@ static const TypeInfo types[] = {
 .parent = TYPE_HOST_IOMMU_DEVICE,
 .instance_size = sizeof(HostIOMMUDeviceIOMMUFD),
 .class_size = sizeof(HostIOMMUDeviceIOMMUFDClass),
+.class_init = hiod_iommufd_class_init,
 .abstract = true,
 }
 };
-- 
2.34.1




[PATCH v3 04/19] vfio/iommufd: Introduce HostIOMMUDeviceIOMMUFDVFIO device

2024-04-28 Thread Zhenzhong Duan
HostIOMMUDeviceIOMMUFDVFIO represents a host IOMMU device under VFIO
iommufd backend. It will be created during VFIO device attaching and
passed to vIOMMU.

It includes a link to VFIODevice so that we can do VFIO device
specific operations, i.e., [at/de]taching hwpt, etc.

Signed-off-by: Zhenzhong Duan 
---
 include/hw/vfio/vfio-common.h | 13 +
 hw/vfio/iommufd.c |  6 +-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
index aa3abe0a18..0943add3bc 100644
--- a/include/hw/vfio/vfio-common.h
+++ b/include/hw/vfio/vfio-common.h
@@ -32,6 +32,7 @@
 #include "sysemu/sysemu.h"
 #include "hw/vfio/vfio-container-base.h"
 #include "sysemu/host_iommu_device.h"
+#include "sysemu/iommufd.h"
 
 #define VFIO_MSG_PREFIX "vfio %s: "
 
@@ -159,6 +160,18 @@ struct HostIOMMUDeviceLegacyVFIO {
 VFIODevice *vdev;
 };
 
+#define TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO \
+TYPE_HOST_IOMMU_DEVICE_IOMMUFD "-vfio"
+OBJECT_DECLARE_SIMPLE_TYPE(HostIOMMUDeviceIOMMUFDVFIO,
+   HOST_IOMMU_DEVICE_IOMMUFD_VFIO)
+
+/* Abstraction of host IOMMU device with VFIO IOMMUFD backend */
+struct HostIOMMUDeviceIOMMUFDVFIO {
+HostIOMMUDeviceIOMMUFD parent;
+
+VFIODevice *vdev;
+};
+
 typedef struct VFIODMABuf {
 QemuDmaBuf buf;
 uint32_t pos_x, pos_y, pos_updates;
diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
index 8827ffe636..997f4ac43e 100644
--- a/hw/vfio/iommufd.c
+++ b/hw/vfio/iommufd.c
@@ -639,7 +639,11 @@ static const TypeInfo types[] = {
 .name = TYPE_VFIO_IOMMU_IOMMUFD,
 .parent = TYPE_VFIO_IOMMU,
 .class_init = vfio_iommu_iommufd_class_init,
-},
+}, {
+.name = TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO,
+.parent = TYPE_HOST_IOMMU_DEVICE_IOMMUFD,
+.instance_size = sizeof(HostIOMMUDeviceIOMMUFDVFIO),
+}
 };
 
 DEFINE_TYPES(types)
-- 
2.34.1




[PATCH v3 00/19] Add a host IOMMU device abstraction to check with vIOMMU

2024-04-28 Thread Zhenzhong Duan
Hi,

The most important change in this version is instroducing a common
HostIOMMUDeviceCaps structure in HostIOMMUDevice and a new interface
between vIOMMU and HostIOMMUDevice.

HostIOMMUDeviceClass::realize() is introduced to initialize
HostIOMMUDeviceCaps and other fields of HostIOMMUDevice variants.

HostIOMMUDeviceClass::check_cap() is introduced to query host IOMMU
device capabilities.

After the change, part2 is only 3 patches, so merge it with part1 to be
a single prerequisite series, same for changelog. If anyone doesn't like
that, I can split again.

The class tree is as below:

  HostIOMMUDevice
 | .caps
 | .realize()
 | .check_cap()
 |
.---.
||  |
HostIOMMUDeviceLegacyVFIO  {HostIOMMUDeviceLegacyVDPA}  HostIOMMUDeviceIOMMUFD
| .vdev  | {.vdev}  | .iommufd
| .devid
| [.ioas_id]
| [.attach_hwpt()]
| [.detach_hwpt()]
|
  .--.
  |  |
   HostIOMMUDeviceIOMMUFDVFIO  {HostIOMMUDeviceIOMMUFDVDPA}
  | .vdev| {.vdev}

* The attributes in [] will be implemented in nesting series.
* The classes in {} will be implemented in future.
* .vdev in different class points to different agent device,
* i.e., for VFIO it points to VFIODevice.

PATCH1-4: Introduce HostIOMMUDevice and its sub classes
PATCH5-11: Introduce HostIOMMUDeviceCaps, implement .realize() and .check_cap() 
handler
PATCH12-16: Create HostIOMMUDevice instance and pass to vIOMMU
PATCH17-19: Implement compatibility check between host IOMMU and 
vIOMMU(intel_iommu)

Qemu code can be found at:
https://github.com/yiliu1765/qemu/tree/zhenzhong/iommufd_nesting_preq_v3

Besides the compatibility check in this series, in nesting series, this
host IOMMU device is extended for much wider usage. For anyone interested
on the nesting series, here is the link:
https://github.com/yiliu1765/qemu/tree/zhenzhong/iommufd_nesting_rfcv2

Thanks
Zhenzhong

Changelog:
v3:
- refine declaration and doc for HostIOMMUDevice (Cédric, Philippe)
- introduce HostIOMMUDeviceCaps, .realize() and .check_cap() (Cédric)
- introduce helper range_get_last_bit() for range operation (Cédric)
- separate pci_device_get_iommu_bus_devfn() in a prereq patch (Cédric)
- replace HIOD_ abbreviation with HOST_IOMMU_DEVICE_ (Cédric)
- add header in include/sysemu/iommufd.h (Cédric)

v2:
- use QOM to abstract host IOMMU device and its sub-classes (Cédric)
- move host IOMMU device creation in attach_device() (Cédric)
- refine pci_device_set/unset_iommu_device doc further (Eric)
- define host IOMMU info format of different backend
- implement get_host_iommu_info() for different backend (Cédric)
- drop cap/ecap update logic (MST)
- check aw-bits from get_host_iommu_info() in legacy mode

v1:
- use HostIOMMUDevice handle instead of union in VFIODevice (Eric)
- change host_iommu_device_init to host_iommu_device_create
- allocate HostIOMMUDevice in host_iommu_device_create callback
  and set the VFIODevice base_hdev handle (Eric)
- refine pci_device_set/unset_iommu_device doc (Eric)
- use HostIOMMUDevice handle instead of union in VTDHostIOMMUDevice (Eric)
- convert HostIOMMUDevice to sub object pointer in vtd_check_hdev

rfcv2:
- introduce common abstract HostIOMMUDevice and sub struct for different BEs 
(Eric, Cédric)
- remove iommufd_device.[ch] (Cédric)
- remove duplicate iommufd/devid define from VFIODevice (Eric)
- drop the p in aliased_pbus and aliased_pdevfn (Eric)
- assert devfn and iommu_bus in pci_device_get_iommu_bus_devfn (Cédric, Eric)
- use errp in iommufd_device_get_info (Eric)
- split and simplify cap/ecap check/sync code in intel_iommu.c (Cédric)
- move VTDHostIOMMUDevice declaration to intel_iommu_internal.h (Cédric)
- make '(vtd->cap_reg >> 16) & 0x3fULL' a MACRO and add missed '+1' (Cédric)
- block migration if vIOMMU cap/ecap updated based on host IOMMU cap/ecap
- add R-B

Yi Liu (2):
  hw/pci: Introduce pci_device_[set|unset]_iommu_device()
  intel_iommu: Implement [set|unset]_iommu_device() callbacks

Zhenzhong Duan (17):
  backends: Introduce HostIOMMUDevice abstract
  vfio/container: Introduce HostIOMMUDeviceLegacyVFIO device
  backends/iommufd: Introduce abstract HostIOMMUDeviceIOMMUFD device
  vfio/iommufd: Introduce HostIOMMUDeviceIOMMUFDVFIO device
  backends/host_iommu_de

[PATCH v3 02/19] vfio/container: Introduce HostIOMMUDeviceLegacyVFIO device

2024-04-28 Thread Zhenzhong Duan
HostIOMMUDeviceLegacyVFIO represents a host IOMMU device under VFIO
legacy container backend.

It includes a link to VFIODevice.

Suggested-by: Eric Auger 
Suggested-by: Cédric Le Goater 
Signed-off-by: Zhenzhong Duan 
---
 include/hw/vfio/vfio-common.h | 12 
 hw/vfio/container.c   |  6 +-
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
index b9da6c08ef..aa3abe0a18 100644
--- a/include/hw/vfio/vfio-common.h
+++ b/include/hw/vfio/vfio-common.h
@@ -31,6 +31,7 @@
 #endif
 #include "sysemu/sysemu.h"
 #include "hw/vfio/vfio-container-base.h"
+#include "sysemu/host_iommu_device.h"
 
 #define VFIO_MSG_PREFIX "vfio %s: "
 
@@ -147,6 +148,17 @@ typedef struct VFIOGroup {
 bool ram_block_discard_allowed;
 } VFIOGroup;
 
+#define TYPE_HOST_IOMMU_DEVICE_LEGACY_VFIO TYPE_HOST_IOMMU_DEVICE 
"-legacy-vfio"
+OBJECT_DECLARE_SIMPLE_TYPE(HostIOMMUDeviceLegacyVFIO,
+   HOST_IOMMU_DEVICE_LEGACY_VFIO)
+
+/* Abstract of host IOMMU device with VFIO legacy container backend */
+struct HostIOMMUDeviceLegacyVFIO {
+HostIOMMUDevice parent_obj;
+
+VFIODevice *vdev;
+};
+
 typedef struct VFIODMABuf {
 QemuDmaBuf buf;
 uint32_t pos_x, pos_y, pos_updates;
diff --git a/hw/vfio/container.c b/hw/vfio/container.c
index 77bdec276e..3b6826996a 100644
--- a/hw/vfio/container.c
+++ b/hw/vfio/container.c
@@ -1148,7 +1148,11 @@ static const TypeInfo types[] = {
 .name = TYPE_VFIO_IOMMU_LEGACY,
 .parent = TYPE_VFIO_IOMMU,
 .class_init = vfio_iommu_legacy_class_init,
-},
+}, {
+.name = TYPE_HOST_IOMMU_DEVICE_LEGACY_VFIO,
+.parent = TYPE_HOST_IOMMU_DEVICE,
+.instance_size = sizeof(HostIOMMUDeviceLegacyVFIO),
+}
 };
 
 DEFINE_TYPES(types)
-- 
2.34.1




[PATCH v3 01/19] backends: Introduce HostIOMMUDevice abstract

2024-04-28 Thread Zhenzhong Duan
Introduce HostIOMMUDevice as an abstraction of host IOMMU device.

Introduce .realize() to initialize HostIOMMUDevice further after
instance init.

Introduce a macro CONFIG_HOST_IOMMU_DEVICE to define the usage
for VFIO, and VDPA in the future.

Suggested-by: Cédric Le Goater 
Signed-off-by: Zhenzhong Duan 
---
 MAINTAINERS|  2 ++
 include/sysemu/host_iommu_device.h | 51 ++
 backends/host_iommu_device.c   | 30 ++
 backends/Kconfig   |  5 +++
 backends/meson.build   |  1 +
 5 files changed, 89 insertions(+)
 create mode 100644 include/sysemu/host_iommu_device.h
 create mode 100644 backends/host_iommu_device.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 302b6fd00c..f67cd36b34 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2190,6 +2190,8 @@ M: Zhenzhong Duan 
 S: Supported
 F: backends/iommufd.c
 F: include/sysemu/iommufd.h
+F: backends/host_iommu_device.c
+F: include/sysemu/host_iommu_device.h
 F: include/qemu/chardev_open.h
 F: util/chardev_open.c
 F: docs/devel/vfio-iommufd.rst
diff --git a/include/sysemu/host_iommu_device.h 
b/include/sysemu/host_iommu_device.h
new file mode 100644
index 00..2b58a94d62
--- /dev/null
+++ b/include/sysemu/host_iommu_device.h
@@ -0,0 +1,51 @@
+/*
+ * Host IOMMU device abstract declaration
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ *
+ * Authors: Zhenzhong Duan 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef HOST_IOMMU_DEVICE_H
+#define HOST_IOMMU_DEVICE_H
+
+#include "qom/object.h"
+#include "qapi/error.h"
+
+#define TYPE_HOST_IOMMU_DEVICE "host-iommu-device"
+OBJECT_DECLARE_TYPE(HostIOMMUDevice, HostIOMMUDeviceClass, HOST_IOMMU_DEVICE)
+
+struct HostIOMMUDevice {
+Object parent_obj;
+};
+
+/**
+ * struct HostIOMMUDeviceClass - The base class for all host IOMMU devices.
+ *
+ * Different type of host devices (e.g., VFIO or VDPA device) or devices
+ * with different backend (e.g., VFIO legacy container or IOMMUFD backend)
+ * can have different sub-classes.
+ */
+struct HostIOMMUDeviceClass {
+ObjectClass parent_class;
+
+/**
+ * @realize: initialize host IOMMU device instance further.
+ *
+ * Mandatory callback.
+ *
+ * @hiod: pointer to a host IOMMU device instance.
+ *
+ * @opaque: pointer to agent device of this host IOMMU device,
+ *  i.e., for VFIO, pointer to VFIODevice
+ *
+ * @errp: pass an Error out when realize fails.
+ *
+ * Returns: true on success, false on failure.
+ */
+bool (*realize)(HostIOMMUDevice *hiod, void *opaque, Error **errp);
+};
+#endif
diff --git a/backends/host_iommu_device.c b/backends/host_iommu_device.c
new file mode 100644
index 00..41f2fdce20
--- /dev/null
+++ b/backends/host_iommu_device.c
@@ -0,0 +1,30 @@
+/*
+ * Host IOMMU device abstract
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ *
+ * Authors: Zhenzhong Duan 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "sysemu/host_iommu_device.h"
+
+OBJECT_DEFINE_ABSTRACT_TYPE(HostIOMMUDevice,
+host_iommu_device,
+HOST_IOMMU_DEVICE,
+OBJECT)
+
+static void host_iommu_device_class_init(ObjectClass *oc, void *data)
+{
+}
+
+static void host_iommu_device_init(Object *obj)
+{
+}
+
+static void host_iommu_device_finalize(Object *obj)
+{
+}
diff --git a/backends/Kconfig b/backends/Kconfig
index 2cb23f62fa..34ab29e994 100644
--- a/backends/Kconfig
+++ b/backends/Kconfig
@@ -3,3 +3,8 @@ source tpm/Kconfig
 config IOMMUFD
 bool
 depends on VFIO
+
+config HOST_IOMMU_DEVICE
+bool
+default y
+depends on VFIO
diff --git a/backends/meson.build b/backends/meson.build
index 8b2b111497..2e975d641e 100644
--- a/backends/meson.build
+++ b/backends/meson.build
@@ -25,6 +25,7 @@ if have_vhost_user
 endif
 system_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: 
files('cryptodev-vhost.c'))
 system_ss.add(when: 'CONFIG_IOMMUFD', if_true: files('iommufd.c'))
+system_ss.add(when: 'CONFIG_HOST_IOMMU_DEVICE', if_true: 
files('host_iommu_device.c'))
 if have_vhost_user_crypto
   system_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: 
files('cryptodev-vhost-user.c'))
 endif
-- 
2.34.1




[PULL 6/9] backends/cryptodev-builtin: Fix local_error leaks

2024-04-28 Thread Michael Tokarev
From: Li Zhijian via 

It seems that this error does not need to be propagated to the upper,
directly output the error to avoid the leaks

Closes: https://gitlab.com/qemu-project/qemu/-/issues/2283
Fixes: 2fda101de07 ("virtio-crypto: Support asynchronous mode")
Signed-off-by: Li Zhijian 
Reviewed-by: Philippe Mathieu-Daudé 
Reviewed-by: zhenwei pi 
Reviewed-by: Michael Tokarev 
Signed-off-by: Michael Tokarev 
---
 backends/cryptodev-builtin.c | 9 +
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c
index a514bbb310..940104ee55 100644
--- a/backends/cryptodev-builtin.c
+++ b/backends/cryptodev-builtin.c
@@ -23,6 +23,7 @@
 
 #include "qemu/osdep.h"
 #include "sysemu/cryptodev.h"
+#include "qemu/error-report.h"
 #include "qapi/error.h"
 #include "standard-headers/linux/virtio_crypto.h"
 #include "crypto/cipher.h"
@@ -396,8 +397,8 @@ static int cryptodev_builtin_create_session(
 case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
 case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
 default:
-error_setg(&local_error, "Unsupported opcode :%" PRIu32 "",
-   sess_info->op_code);
+error_report("Unsupported opcode :%" PRIu32 "",
+ sess_info->op_code);
 return -VIRTIO_CRYPTO_NOTSUPP;
 }
 
@@ -554,8 +555,8 @@ static int cryptodev_builtin_operation(
 
 if (op_info->session_id >= MAX_NUM_SESSIONS ||
   builtin->sessions[op_info->session_id] == NULL) {
-error_setg(&local_error, "Cannot find a valid session id: %" PRIu64 "",
-   op_info->session_id);
+error_report("Cannot find a valid session id: %" PRIu64 "",
+ op_info->session_id);
 return -VIRTIO_CRYPTO_INVSESS;
 }
 
-- 
2.39.2




[PULL 4/9] scripts/checkpatch: Avoid author email mangled by qemu-*@nongnu.org

2024-04-28 Thread Michael Tokarev
From: Philippe Mathieu-Daudé 

Commit f5177798d8 ("scripts: report on author emails
that are mangled by the mailing list") added a check
for qemu-devel@ list, extend the regexp to cover more
such qemu-trivial@, qemu-block@ and qemu-ppc@.

Signed-off-by: Philippe Mathieu-Daudé 
Reviewed-by: Michael Tokarev 
Signed-off-by: Michael Tokarev 
---
 scripts/checkpatch.pl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 7026895074..12e9028b10 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1573,7 +1573,7 @@ sub process {
$is_patch = 1;
}
 
-   if ($line =~ /^(Author|From): .* via 
.*/) {
+   if ($line =~ /^(Author|From): .* via 
.*/) {
ERROR("Author email address is mangled by the mailing 
list\n" . $herecurr);
}
 
-- 
2.39.2




[PULL 0/9] Trivial patches for 2024-04-29

2024-04-28 Thread Michael Tokarev
The following changes since commit fd87be1dada5672f877e03c2ca8504458292c479:

  Merge tag 'accel-20240426' of https://github.com/philmd/qemu into staging 
(2024-04-26 15:28:13 -0700)

are available in the Git repository at:

  https://gitlab.com/mjt0k/qemu.git tags/pull-trivial-patches

for you to fetch changes up to d2f20c25281908a07bcb8c3dea8292abf68e5c8b:

  checkpatch.pl: forbid strerrorname_np() (2024-04-29 09:37:26 +0300)


trivial patches for 2024-04-29


Daniel Henrique Barboza (2):
  target/riscv/kvm: remove sneaky strerrorname_np() instance
  checkpatch.pl: forbid strerrorname_np()

Li Zhijian via (1):
  backends/cryptodev-builtin: Fix local_error leaks

Michael Tokarev (1):
  target/loongarch/cpu.c: typo fix: expection

Philippe Mathieu-Daudé (2):
  scripts/checkpatch: Avoid author email mangled by qemu-*@nongnu.org
  scripts/checkpatch: Do not use mailmap

Thomas Huth (3):
  target/i386/cpu: Remove "x86" prefix from the CPU list
  target/s390x/cpu_models: Rework the output of "-cpu help"
  target/ppc/cpu_init: Remove "PowerPC" prefix from the CPU list

 backends/cryptodev-builtin.c |  9 +
 scripts/checkpatch.pl| 11 +++
 target/i386/cpu.c|  2 +-
 target/loongarch/cpu.c   |  2 +-
 target/ppc/cpu_init.c|  9 +
 target/riscv/kvm/kvm-cpu.c   |  4 ++--
 target/s390x/cpu_models.c|  9 +
 7 files changed, 26 insertions(+), 20 deletions(-)



[PULL 2/9] target/s390x/cpu_models: Rework the output of "-cpu help"

2024-04-28 Thread Michael Tokarev
From: Thomas Huth 

Printing an "s390x" in front of each CPU name is not helpful at all:
It is confusing for the users since they don't know whether they
have to specify these letters for the "-cpu" parameter, too, and
it also takes some precious space in the dense output of the CPU
entries. Let's simply remove this now!

While we're at it, use two spaces at the beginning of the lines for
the indentation of the entries, and add a "Available CPUs" in the
very first line, like most other target architectures are doing it
for their "-cpu help" output already.

Signed-off-by: Thomas Huth 
Reviewed-by: Richard Henderson 
Reviewed-by: Michael Tokarev 
Signed-off-by: Michael Tokarev 
---
 target/s390x/cpu_models.c | 9 +
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index 8ed3bb6a27..58c58f05a0 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -355,9 +355,9 @@ static void s390_print_cpu_model_list_entry(gpointer data, 
gpointer user_data)
 /* strip off the -s390x-cpu */
 g_strrstr(name, "-" TYPE_S390_CPU)[0] = 0;
 if (details->len) {
-qemu_printf("s390 %-15s %-35s (%s)\n", name, scc->desc, details->str);
+qemu_printf("  %-15s %-35s (%s)\n", name, scc->desc, details->str);
 } else {
-qemu_printf("s390 %-15s %-35s\n", name, scc->desc);
+qemu_printf("  %-15s %-35s\n", name, scc->desc);
 }
 g_free(name);
 }
@@ -402,6 +402,7 @@ void s390_cpu_list(void)
 S390Feat feat;
 GSList *list;
 
+qemu_printf("Available CPUs:\n");
 list = object_class_get_list(TYPE_S390_CPU, false);
 list = g_slist_sort(list, s390_cpu_list_compare);
 g_slist_foreach(list, s390_print_cpu_model_list_entry, NULL);
@@ -411,14 +412,14 @@ void s390_cpu_list(void)
 for (feat = 0; feat < S390_FEAT_MAX; feat++) {
 const S390FeatDef *def = s390_feat_def(feat);
 
-qemu_printf("%-20s %s\n", def->name, def->desc);
+qemu_printf("  %-20s %s\n", def->name, def->desc);
 }
 
 qemu_printf("\nRecognized feature groups:\n");
 for (group = 0; group < S390_FEAT_GROUP_MAX; group++) {
 const S390FeatGroupDef *def = s390_feat_group_def(group);
 
-qemu_printf("%-20s %s\n", def->name, def->desc);
+qemu_printf("  %-20s %s\n", def->name, def->desc);
 }
 }
 
-- 
2.39.2




[PULL 9/9] checkpatch.pl: forbid strerrorname_np()

2024-04-28 Thread Michael Tokarev
From: Daniel Henrique Barboza 

Commit d424db2354 removed an instance of strerrorname_np() because it
was breaking building with musl libc. A recent RISC-V patch ended up
re-introducing it again by accident.

Put this function in the baddies list in checkpatch.pl to avoid this
situation again. This is what it will look like next time:

 $ ./scripts/checkpatch.pl 0001-temp-test.patch
 ERROR: use strerror() instead of strerrorname_np()
 #22: FILE: target/riscv/kvm/kvm-cpu.c:1058:
 + strerrorname_np(errno));

 total: 1 errors, 0 warnings, 10 lines checked

Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Thomas Huth 
Reviewed-by: Philippe Mathieu-Daudé 
Reviewed-by: Alistair Francis 
Reviewed-by: Michael Tokarev 
Signed-off-by: Michael Tokarev 
---
 scripts/checkpatch.pl | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 76a0b79266..ff373a7083 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -3078,6 +3078,9 @@ sub process {
if ($line =~ /\b(g_)?assert\(0\)/) {
ERROR("use g_assert_not_reached() instead of 
assert(0)\n" . $herecurr);
}
+   if ($line =~ /\bstrerrorname_np\(/) {
+   ERROR("use strerror() instead of strerrorname_np()\n" . 
$herecurr);
+   }
my $non_exit_glib_asserts = qr{g_assert_cmpstr|
g_assert_cmpint|
g_assert_cmpuint|
-- 
2.39.2




[PULL 5/9] scripts/checkpatch: Do not use mailmap

2024-04-28 Thread Michael Tokarev
From: Philippe Mathieu-Daudé 

The .mailmap file fixes mistake we already did.
Do not use it when running checkpatch.pl, otherwise
we might commit the very same mistakes.

Reported-by: Peter Maydell 
Signed-off-by: Philippe Mathieu-Daudé 
Reviewed-by: Michael Tokarev 
Signed-off-by: Michael Tokarev 
---
 scripts/checkpatch.pl | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 12e9028b10..76a0b79266 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -435,8 +435,8 @@ if ($chk_branch) {
my @patches;
my %git_commits = ();
my $HASH;
-   open($HASH, "-|", "git", "log", "--reverse", "--no-merges", 
"--format=%H %s", $ARGV[0]) ||
-   die "$P: git log --reverse --no-merges --format='%H %s' 
$ARGV[0] failed - $!\n";
+   open($HASH, "-|", "git", "log", "--reverse", "--no-merges", 
"--no-mailmap", "--format=%H %s", $ARGV[0]) ||
+   die "$P: git log --reverse --no-merges --no-mailmap 
--format='%H %s' $ARGV[0] failed - $!\n";
 
for my $line (<$HASH>) {
$line =~ /^([0-9a-fA-F]{40,40}) (.*)$/;
@@ -460,7 +460,7 @@ if ($chk_branch) {
  "-c", "diff.renamelimit=0",
  "-c", "diff.renames=True",
  "-c", "diff.algorithm=histogram",
- "show",
+ "show", "--no-mailmap",
  "--patch-with-stat", $hash) ||
die "$P: git show $hash - $!\n";
while (<$FILE>) {
-- 
2.39.2




[PULL 1/9] target/i386/cpu: Remove "x86" prefix from the CPU list

2024-04-28 Thread Michael Tokarev
From: Thomas Huth 

Printing an "x86" in front of each CPU name is not helpful at all:
It is confusing for the users since they don't know whether they
have to specify these letters for the "-cpu" parameter, too, and
it also takes some precious space in the dense output of the CPU
entries. Let's simply remove this now and use two spaces at the
beginning of the lines for the indentation of the entries instead,
like most other target architectures are doing it for their CPU help
output already.

Signed-off-by: Thomas Huth 
Reviewed-by: Richard Henderson 
Reviewed-by: Michael Tokarev 
Signed-off-by: Michael Tokarev 
---
 target/i386/cpu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index fa1ea3735d..aa3b2d8391 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -5708,7 +5708,7 @@ static void x86_cpu_list_entry(gpointer data, gpointer 
user_data)
 desc = g_strdup_printf("%s (deprecated)", olddesc);
 }
 
-qemu_printf("x86 %-20s  %s\n", name, desc);
+qemu_printf("  %-20s  %s\n", name, desc);
 }
 
 /* list available CPU models and flags */
-- 
2.39.2




[PULL 8/9] target/riscv/kvm: remove sneaky strerrorname_np() instance

2024-04-28 Thread Michael Tokarev
From: Daniel Henrique Barboza 

Commit d424db2354 excluded some strerrorname_np() instances because they
break musl libc builds. Another instance happened to slip by via commit
d4ff3da8f4.

Remove it before it causes trouble again.

Fixes: d4ff3da8f4 (target/riscv/kvm: initialize 'vlenb' via get-reg-list)
Signed-off-by: Daniel Henrique Barboza 
Reviewed-by: Thomas Huth 
Reviewed-by: Philippe Mathieu-Daudé 
Reviewed-by: Alistair Francis 
Reviewed-by: Michael Tokarev 
Signed-off-by: Michael Tokarev 
---
 target/riscv/kvm/kvm-cpu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 49d2f3ad58..eaa36121c7 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -1054,8 +1054,8 @@ static void kvm_riscv_read_vlenb(RISCVCPU *cpu, 
KVMScratchCPU *kvmcpu,
 
 ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®);
 if (ret != 0) {
-error_report("Unable to read vlenb register, error code: %s",
- strerrorname_np(errno));
+error_report("Unable to read vlenb register, error code: %d",
+ errno);
 exit(EXIT_FAILURE);
 }
 
-- 
2.39.2




[PULL 3/9] target/ppc/cpu_init: Remove "PowerPC" prefix from the CPU list

2024-04-28 Thread Michael Tokarev
From: Thomas Huth 

Printing a "PowerPC" in front of each CPU name is not helpful at all:
It is confusing for the users since they don't know whether they
have to specify these letters for the "-cpu" parameter, too, and
it also takes some precious space in the dense output of the CPU
entries. Let's simply remove this now and use two spaces at the
beginning of the lines for the indentation of the entries instead,
and add a "Available CPUs" in the very first line, like most other
target architectures are doing it for their CPU help output already.

Signed-off-by: Thomas Huth 
Reviewed-by: Richard Henderson 
Reviewed-by: Michael Tokarev 
Signed-off-by: Michael Tokarev 
---
 target/ppc/cpu_init.c | 9 +
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 6d82f24c87..c11a69fd90 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -7063,7 +7063,7 @@ static void ppc_cpu_list_entry(gpointer data, gpointer 
user_data)
 }
 
 name = cpu_model_from_type(typename);
-qemu_printf("PowerPC %-16s PVR %08x\n", name, pcc->pvr);
+qemu_printf("  %-16s PVR %08x\n", name, pcc->pvr);
 for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) {
 PowerPCCPUAlias *alias = &ppc_cpu_aliases[i];
 ObjectClass *alias_oc = ppc_cpu_class_by_name(alias->model);
@@ -7076,10 +7076,10 @@ static void ppc_cpu_list_entry(gpointer data, gpointer 
user_data)
  * avoid printing the wrong alias here and use "preferred" instead
  */
 if (strcmp(alias->alias, family->desc) == 0) {
-qemu_printf("PowerPC %-16s (alias for preferred %s CPU)\n",
+qemu_printf("  %-16s (alias for preferred %s CPU)\n",
 alias->alias, family->desc);
 } else {
-qemu_printf("PowerPC %-16s (alias for %s)\n",
+qemu_printf("  %-16s (alias for %s)\n",
 alias->alias, name);
 }
 }
@@ -7090,6 +7090,7 @@ void ppc_cpu_list(void)
 {
 GSList *list;
 
+qemu_printf("Available CPUs:\n");
 list = object_class_get_list(TYPE_POWERPC_CPU, false);
 list = g_slist_sort(list, ppc_cpu_list_compare);
 g_slist_foreach(list, ppc_cpu_list_entry, NULL);
@@ -7097,7 +7098,7 @@ void ppc_cpu_list(void)
 
 #ifdef CONFIG_KVM
 qemu_printf("\n");
-qemu_printf("PowerPC %s\n", "host");
+qemu_printf("  %s\n", "host");
 #endif
 }
 
-- 
2.39.2




[PULL 7/9] target/loongarch/cpu.c: typo fix: expection

2024-04-28 Thread Michael Tokarev
Fixes: 1590154ee437 ("target/loongarch: Fix qemu-system-loongarch64 assert 
failed with the option '-d int'")
Signed-off-by: Michael Tokarev 
Reviewed-by: Richard Henderson 
---
 target/loongarch/cpu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index bac84dca7a..1ebba043f4 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -92,7 +92,7 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env,
 {
 CPUState *cs = env_cpu(env);
 
-qemu_log_mask(CPU_LOG_INT, "%s: expection: %d (%s)\n",
+qemu_log_mask(CPU_LOG_INT, "%s: exception: %d (%s)\n",
   __func__,
   exception,
   loongarch_exception_name(exception));
-- 
2.39.2




Re: [PATCH v2 2/4] hw/arm/sbsa-ref: Force CPU generic timer to 62.5MHz

2024-04-28 Thread Marcin Juszkiewicz

W dniu 26.04.2024 o 14:29, Peter Maydell pisze:

The default frequency used by the 'max' CPU is about to change, so
make the sbsa-ref board force the CPU frequency to the value which
the firmware expects.

Newer versions of TF-A will read the frequency from the CPU's
CNTFRQ_EL0 register:
  
https://github.com/ARM-software/arm-trusted-firmware/commit/4c77fac98dac0bebc63798aae9101ac865b87148
so in the longer term we could make this board use the 1GHz
frequency. We will need to make sure we update the binaries used
by our avocado test
  Aarch64SbsarefMachine.test_sbsaref_alpine_linux_max_pauth_impdef
before we can do that.

Signed-off-by: Peter Maydell
---
I leave it up to the sbsa-ref maintainers exactly when they
want to shift to 1GHz (probably after a TF-A release with the fix?)


Reviewed-by: Marcin Juszkiewicz 

TF-A 2.11 will be released in June. It will have several other 
improvements so I prefer to wait for it.


We will have EDK2 202405 stable release then too which allow us to 
collect all changes we did during last half year (and maybe even those 
in progress).


In meantime we go with 62.5 MHz frequency as it was before so no one 
will get "too fast wall clock" issue. Then, in a middle of June, new 
firmware will be built for QEMU CI and we will be able to move to 1 GHz 
by default and maybe add some other changes on top.




Re: [PATCH v4 1/1] hw/arm/sbsa-ref: Enable CPU cluster on ARM sbsa machine

2024-04-28 Thread Marcin Juszkiewicz

W dniu 26.04.2024 o 18:06, Richard Henderson pisze:


Isn't this basically what MPIDR_EL1 is supposed to indicate?
We do not yet implement all of that in QEMU, but should.


QEMU has socket/cluster/core/thread model which could map to
aff3/aff2/aff1/aff0 (or aff0/1/2/3) of MPIDR_EL1 register, right? But it 
does not.


Nevermind which combination of socket/cluster/core/thread I use all I 
have is this:


cpu 0x000 mpidr  
cpu 0x001 mpidr  0001
cpu 0x002 mpidr  0010
cpu 0x003 mpidr  0011
cpu 0x004 mpidr  0100
cpu 0x005 mpidr  0101
cpu 0x006 mpidr  0110
cpu 0x007 mpidr  0111

cpu 0x008 mpidr 0001 
cpu 0x009 mpidr 0001 0001
cpu 0x00a mpidr 0001 0010
cpu 0x00b mpidr 0001 0011
cpu 0x00c mpidr 0001 0100
cpu 0x00d mpidr 0001 0101
cpu 0x00e mpidr 0001 0110
cpu 0x00f mpidr 0001 0111

Eight cpu cores per unit. Probably leftover from GICv2 times where there 
was 8 cores per GIC limit.


So looks like adding mapping of topology to MPIDR_EL1 into QEMU would be 
a better option. May require checking for more than 256 of one kind then.



Why does the same info need to be replicated in devicetree?


One of things we had on todolist: export cpu topology in PPTT table. 
With MPIDR being 2 level while topology can be 4 level.




Re: [PATCH v7 3/4] target/riscv: Expose sdtrig ISA extension

2024-04-28 Thread Alistair Francis
On Fri, Mar 15, 2024 at 5:02 AM Himanshu Chauhan
 wrote:
>
> This patch adds "sdtrig" in the ISA string when sdtrig extension is enabled.
> The sdtrig extension may or may not be implemented in a system. Therefore, the
>-cpu rv64,sdtrig=
> option can be used to dynamically turn sdtrig extension on or off.
>
> By default, the sdtrig extension is disabled and debug property enabled as 
> usual.
>
> Signed-off-by: Himanshu Chauhan 

Acked-by: Alistair Francis 

Alistair

> ---
>  target/riscv/cpu.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index ab631500ac..4231f36c1b 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -175,6 +175,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
>  ISA_EXT_DATA_ENTRY(zvkt, PRIV_VERSION_1_12_0, ext_zvkt),
>  ISA_EXT_DATA_ENTRY(zhinx, PRIV_VERSION_1_12_0, ext_zhinx),
>  ISA_EXT_DATA_ENTRY(zhinxmin, PRIV_VERSION_1_12_0, ext_zhinxmin),
> +ISA_EXT_DATA_ENTRY(sdtrig, PRIV_VERSION_1_12_0, ext_sdtrig),
>  ISA_EXT_DATA_ENTRY(smaia, PRIV_VERSION_1_12_0, ext_smaia),
>  ISA_EXT_DATA_ENTRY(smepmp, PRIV_VERSION_1_12_0, ext_smepmp),
>  ISA_EXT_DATA_ENTRY(smstateen, PRIV_VERSION_1_12_0, ext_smstateen),
> @@ -1485,6 +1486,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = {
>  MULTI_EXT_CFG_BOOL("zvfhmin", ext_zvfhmin, false),
>  MULTI_EXT_CFG_BOOL("sstc", ext_sstc, true),
>
> +MULTI_EXT_CFG_BOOL("sdtrig", ext_sdtrig, false),
>  MULTI_EXT_CFG_BOOL("smaia", ext_smaia, false),
>  MULTI_EXT_CFG_BOOL("smepmp", ext_smepmp, false),
>  MULTI_EXT_CFG_BOOL("smstateen", ext_smstateen, false),
> --
> 2.34.1
>
>



[PATCH 2/3] target/ppc: Move VMX integer logical instructions to decodetree.

2024-04-28 Thread Chinmay Rath
Moving the following instructions to decodetree specification:

v{and, andc, nand, or, orc, nor, xor, eqv}  : VX-form

The changes were verified by validating that the tcp ops generated by those
instructions remain the same, which were captured with the '-d in_asm,op' flag.

Signed-off-by: Chinmay Rath 
---
 target/ppc/insn32.decode| 11 +++
 target/ppc/translate/vmx-impl.c.inc | 22 ++
 target/ppc/translate/vmx-ops.c.inc  | 15 ---
 3 files changed, 21 insertions(+), 27 deletions(-)

diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index 27655f0d9e..e00bc05381 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -574,6 +574,17 @@ VCMPNEZW000100 . . . . 011111   @VC
 VCMPSQ  000100 ... -- . . 0010101   @VX_bf
 VCMPUQ  000100 ... -- . . 0010001   @VX_bf
 
+## Vector Integer Logical Instructions
+
+VAND000100 . . . 1000100@VX
+VANDC   000100 . . . 10001000100@VX
+VNAND   000100 . . . 1011100@VX
+VOR 000100 . . . 1001100@VX
+VORC000100 . . . 10101000100@VX
+VNOR000100 . . . 1010100@VX
+VXOR000100 . . . 10011000100@VX
+VEQV000100 . . . 1101100@VX
+
 ## Vector Integer Average Instructions
 
 VAVGSB  000100 . . . 1010010@VX
diff --git a/target/ppc/translate/vmx-impl.c.inc 
b/target/ppc/translate/vmx-impl.c.inc
index 4d5e743cfe..cefe04127c 100644
--- a/target/ppc/translate/vmx-impl.c.inc
+++ b/target/ppc/translate/vmx-impl.c.inc
@@ -205,16 +205,6 @@ static void glue(gen_, name)(DisasContext *ctx)
 \
16, 16); \
 }
 
-/* Logical operations */
-GEN_VXFORM_V(vand, MO_64, tcg_gen_gvec_and, 2, 16);
-GEN_VXFORM_V(vandc, MO_64, tcg_gen_gvec_andc, 2, 17);
-GEN_VXFORM_V(vor, MO_64, tcg_gen_gvec_or, 2, 18);
-GEN_VXFORM_V(vxor, MO_64, tcg_gen_gvec_xor, 2, 19);
-GEN_VXFORM_V(vnor, MO_64, tcg_gen_gvec_nor, 2, 20);
-GEN_VXFORM_V(veqv, MO_64, tcg_gen_gvec_eqv, 2, 26);
-GEN_VXFORM_V(vnand, MO_64, tcg_gen_gvec_nand, 2, 22);
-GEN_VXFORM_V(vorc, MO_64, tcg_gen_gvec_orc, 2, 21);
-
 #define GEN_VXFORM(name, opc2, opc3)\
 static void glue(gen_, name)(DisasContext *ctx) \
 {   \
@@ -727,6 +717,16 @@ TRANS_FLAGS(ALTIVEC, VRLH, do_vector_gvec3_VX, MO_16, 
tcg_gen_gvec_rotlv)
 TRANS_FLAGS(ALTIVEC, VRLW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_rotlv)
 TRANS_FLAGS2(ALTIVEC_207, VRLD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_rotlv)
 
+/* Logical operations */
+TRANS_FLAGS(ALTIVEC, VAND, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_and);
+TRANS_FLAGS(ALTIVEC, VANDC, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_andc);
+TRANS_FLAGS(ALTIVEC, VOR, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_or);
+TRANS_FLAGS(ALTIVEC, VXOR, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_xor);
+TRANS_FLAGS(ALTIVEC, VNOR, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_nor);
+TRANS_FLAGS2(ALTIVEC_207, VEQV, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_eqv);
+TRANS_FLAGS2(ALTIVEC_207, VNAND, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_nand);
+TRANS_FLAGS2(ALTIVEC_207, VORC, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_orc);
+
 static TCGv_vec do_vrl_mask_vec(unsigned vece, TCGv_vec vrb)
 {
 TCGv_vec t0 = tcg_temp_new_vec_matching(vrb),
@@ -3331,8 +3331,6 @@ TRANS_FLAGS2(ISA310, VMODUQ, do_vx_helper, 
gen_helper_VMODUQ)
 #undef DIVS64
 #undef DIVU64
 
-#undef GEN_VX_LOGICAL
-#undef GEN_VX_LOGICAL_207
 #undef GEN_VXFORM
 #undef GEN_VXFORM_207
 #undef GEN_VXFORM_DUAL
diff --git a/target/ppc/translate/vmx-ops.c.inc 
b/target/ppc/translate/vmx-ops.c.inc
index 672fba3796..80c5217749 100644
--- a/target/ppc/translate/vmx-ops.c.inc
+++ b/target/ppc/translate/vmx-ops.c.inc
@@ -1,18 +1,3 @@
-#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3)\
-GEN_HANDLER(name, 0x04, opc2, opc3, 0x, PPC_ALTIVEC)
-
-#define GEN_VX_LOGICAL_207(name, tcg_op, opc2, opc3) \
-GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x, PPC_NONE, PPC2_ALTIVEC_207)
-
-GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16),
-GEN_VX_LOGICAL(vandc, tcg_gen_andc_i64, 2, 17),
-GEN_VX_LOGICAL(vor, tcg_gen_or_i64, 2, 18),
-GEN_VX_LOGICAL(vxor, tcg_gen_xor_i64, 2, 19),
-GEN_VX_LOGICAL(vnor, tcg_gen_nor_i64, 2, 20),
-GEN_VX_LOGICAL_207(veqv, tcg_gen_eqv_i64, 2, 26),
-GEN_VX_LOGICAL_207(vnand, tcg_gen_nand_i64, 2, 22),
-GEN_VX_LOGICAL_207(vorc, tcg_gen_orc_i64, 2, 21),
-
 #define GEN_VXFORM(name, opc2, opc3)\
 GEN_HANDLER(name, 0x04, opc2, opc3, 0x, PPC_ALTIVEC)
 
-- 
2.39.3




[PATCH 1/3] target/ppc: Move VMX storage access instructions to decodetree

2024-04-28 Thread Chinmay Rath
Moving the following instructions to decodetree specification :

{l,st}ve{b,h,w}x,
{l,st}v{x,xl},
lvs{l,r}: X-form

The changes were verified by validating that the tcg ops generated by those
instructions remain the same, which were captured using the '-d in_asm,op' flag.

Signed-off-by: Chinmay Rath 
---
 target/ppc/helper.h |  12 +-
 target/ppc/insn32.decode|  17 +++
 target/ppc/mem_helper.c |  12 +-
 target/ppc/translate.c  |   2 -
 target/ppc/translate/vmx-impl.c.inc | 221 
 target/ppc/translate/vmx-ops.c.inc  |  19 ---
 6 files changed, 120 insertions(+), 163 deletions(-)

diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 86f97ee1e7..f397ef459a 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -267,12 +267,12 @@ DEF_HELPER_5(VMSUMSHS, void, env, avr, avr, avr, avr)
 DEF_HELPER_FLAGS_5(VMLADDUHM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
 DEF_HELPER_FLAGS_2(mtvscr, TCG_CALL_NO_RWG, void, env, i32)
 DEF_HELPER_FLAGS_1(mfvscr, TCG_CALL_NO_RWG, i32, env)
-DEF_HELPER_3(lvebx, void, env, avr, tl)
-DEF_HELPER_3(lvehx, void, env, avr, tl)
-DEF_HELPER_3(lvewx, void, env, avr, tl)
-DEF_HELPER_3(stvebx, void, env, avr, tl)
-DEF_HELPER_3(stvehx, void, env, avr, tl)
-DEF_HELPER_3(stvewx, void, env, avr, tl)
+DEF_HELPER_3(LVEBX, void, env, avr, tl)
+DEF_HELPER_3(LVEHX, void, env, avr, tl)
+DEF_HELPER_3(LVEWX, void, env, avr, tl)
+DEF_HELPER_3(STVEBX, void, env, avr, tl)
+DEF_HELPER_3(STVEHX, void, env, avr, tl)
+DEF_HELPER_3(STVEWX, void, env, avr, tl)
 #if defined(TARGET_PPC64)
 DEF_HELPER_4(lxvl, void, env, tl, vsr, tl)
 DEF_HELPER_4(lxvll, void, env, tl, vsr, tl)
diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index eada59f59f..27655f0d9e 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -526,6 +526,23 @@ DSCRIQ  11 . . .. 001100010 .   
@Z22_tap_sh_rc
 
 VPMSUMD 000100 . . . 10011001000@VX
 
+## Vector Load/Store Instructions
+
+LVEBX   01 . . . 000111 -   @X
+LVEHX   01 . . . 100111 -   @X
+LVEWX   01 . . . 0001000111 -   @X
+LVX 01 . . . 0001100111 -   @X
+LVXL01 . . . 0101100111 -   @X
+
+STVEBX  01 . . . 001111 -   @X
+STVEHX  01 . . . 0010100111 -   @X
+STVEWX  01 . . . 0011000111 -   @X
+STVX01 . . . 0011100111 -   @X
+STVXL   01 . . . 000111 -   @X
+
+LVSL01 . . . 000110 -   @X
+LVSR01 . . . 100110 -   @X
+
 ## Vector Integer Instructions
 
 VCMPEQUB000100 . . . . 000110   @VC
diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c
index ea7e8443a8..f88155ad45 100644
--- a/target/ppc/mem_helper.c
+++ b/target/ppc/mem_helper.c
@@ -404,9 +404,9 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong 
addr, uint32_t reg,
 }   \
 }
 #define I(x) (x)
-LVE(lvebx, cpu_ldub_data_ra, I, u8)
-LVE(lvehx, cpu_lduw_data_ra, bswap16, u16)
-LVE(lvewx, cpu_ldl_data_ra, bswap32, u32)
+LVE(LVEBX, cpu_ldub_data_ra, I, u8)
+LVE(LVEHX, cpu_lduw_data_ra, bswap16, u16)
+LVE(LVEWX, cpu_ldl_data_ra, bswap32, u32)
 #undef I
 #undef LVE
 
@@ -432,9 +432,9 @@ LVE(lvewx, cpu_ldl_data_ra, bswap32, u32)
 }   \
 }
 #define I(x) (x)
-STVE(stvebx, cpu_stb_data_ra, I, u8)
-STVE(stvehx, cpu_stw_data_ra, bswap16, u16)
-STVE(stvewx, cpu_stl_data_ra, bswap32, u32)
+STVE(STVEBX, cpu_stb_data_ra, I, u8)
+STVE(STVEHX, cpu_stw_data_ra, bswap16, u16)
+STVE(STVEWX, cpu_stl_data_ra, bswap32, u32)
 #undef I
 #undef LVE
 
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 93ffec787c..cde3b88b98 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -6640,8 +6640,6 @@ GEN_HANDLER2_E(icbt_440, "icbt", 0x1F, 0x16, 0x00, 
0x03E1,
PPC_BOOKE, PPC2_BOOKE206),
 GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x06, 0x08, 0x03E1,
  PPC_440_SPEC),
-GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x0001, PPC_ALTIVEC),
-GEN_HANDLER(lvsr, 0x1f, 0x06, 0x01, 0x0001, PPC_ALTIVEC),
 GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC),
 GEN_HANDLER(mtvscr, 0x04, 0x2, 0x19, 0x03ff, PPC_ALTIVEC),
 #if defined(TARGET_PPC64)
diff --git a/target/ppc/translate/vmx-impl.c.inc 
b/target/ppc/translate/vmx-impl.c.inc
index b56e615c24..4d5e743cfe 100644
--- a/target/ppc/translate/vmx-impl.c.inc
+++ b/target/ppc/translate/vmx-impl.c.inc
@@ -14,125 +14,88 @@ static inline TCGv_ptr gen_avr_ptr(int reg)
 return r;
 }
 
-#define GEN_VR_LDX(name, opc2, opc3)  

[PATCH 0/3] target/ppc: Moving VMX insns to decodetree

2024-04-28 Thread Chinmay Rath
Moving VMX instructions of the following types to decodetree
specification : storage access, integer logical & integer max/min.

Chinmay Rath (3):
  target/ppc: Move VMX storage access instructions to decodetree
  target/ppc: Move VMX integer logical instructions to decodetree
  target/ppc: Move VMX integer max/min instructions to decodetree.

 target/ppc/helper.h |  12 +-
 target/ppc/insn32.decode|  50 +
 target/ppc/mem_helper.c |  12 +-
 target/ppc/translate.c  |   2 -
 target/ppc/translate/vmx-impl.c.inc | 280 
 target/ppc/translate/vmx-ops.c.inc  |  50 -
 6 files changed, 184 insertions(+), 222 deletions(-)

-- 
2.39.3




[PATCH 3/3] target/ppc: Move VMX integer max/min instructions to decodetree.

2024-04-28 Thread Chinmay Rath
Moving the following instructions to decodetree specification :

v{max, min}{u, s}{b, h, w, d}   : VX-form

The changes were verified by validating that the tcg ops generated by those
instructions remain the same, which were captured with the '-d in_asm,op' flag.

Signed-off-by: Chinmay Rath 
---
 target/ppc/insn32.decode| 22 +
 target/ppc/translate/vmx-impl.c.inc | 37 -
 target/ppc/translate/vmx-ops.c.inc  | 16 -
 3 files changed, 43 insertions(+), 32 deletions(-)

diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index e00bc05381..847a2f4356 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -717,6 +717,28 @@ VEXTSD2Q000100 . 11011 . 1100010
@VX_tb
 VNEGD   000100 . 00111 . 1100010@VX_tb
 VNEGW   000100 . 00110 . 1100010@VX_tb
 
+## Vector Integer Maximum/Minimum Instructions
+
+VMAXUB  000100 . . . 010@VX
+VMAXUH  000100 . . . 110@VX
+VMAXUW  000100 . . . 0001010@VX
+VMAXUD  000100 . . . 0001110@VX
+
+VMAXSB  000100 . . . 0010010@VX
+VMAXSH  000100 . . . 0010110@VX
+VMAXSW  000100 . . . 0011010@VX
+VMAXSD  000100 . . . 0011110@VX
+
+VMINUB  000100 . . . 0100010@VX
+VMINUH  000100 . . . 0100110@VX
+VMINUW  000100 . . . 0101010@VX
+VMINUD  000100 . . . 0101110@VX
+
+VMINSB  000100 . . . 0110010@VX
+VMINSH  000100 . . . 0110110@VX
+VMINSW  000100 . . . 0111010@VX
+VMINSD  000100 . . . 010@VX
+
 ## Vector Mask Manipulation Instructions
 
 MTVSRBM 000100 . 1 . 1100110@VX_tb
diff --git a/target/ppc/translate/vmx-impl.c.inc 
b/target/ppc/translate/vmx-impl.c.inc
index cefe04127c..8084af75cc 100644
--- a/target/ppc/translate/vmx-impl.c.inc
+++ b/target/ppc/translate/vmx-impl.c.inc
@@ -342,22 +342,6 @@ GEN_VXFORM_V(vsububm, MO_8, tcg_gen_gvec_sub, 0, 16);
 GEN_VXFORM_V(vsubuhm, MO_16, tcg_gen_gvec_sub, 0, 17);
 GEN_VXFORM_V(vsubuwm, MO_32, tcg_gen_gvec_sub, 0, 18);
 GEN_VXFORM_V(vsubudm, MO_64, tcg_gen_gvec_sub, 0, 19);
-GEN_VXFORM_V(vmaxub, MO_8, tcg_gen_gvec_umax, 1, 0);
-GEN_VXFORM_V(vmaxuh, MO_16, tcg_gen_gvec_umax, 1, 1);
-GEN_VXFORM_V(vmaxuw, MO_32, tcg_gen_gvec_umax, 1, 2);
-GEN_VXFORM_V(vmaxud, MO_64, tcg_gen_gvec_umax, 1, 3);
-GEN_VXFORM_V(vmaxsb, MO_8, tcg_gen_gvec_smax, 1, 4);
-GEN_VXFORM_V(vmaxsh, MO_16, tcg_gen_gvec_smax, 1, 5);
-GEN_VXFORM_V(vmaxsw, MO_32, tcg_gen_gvec_smax, 1, 6);
-GEN_VXFORM_V(vmaxsd, MO_64, tcg_gen_gvec_smax, 1, 7);
-GEN_VXFORM_V(vminub, MO_8, tcg_gen_gvec_umin, 1, 8);
-GEN_VXFORM_V(vminuh, MO_16, tcg_gen_gvec_umin, 1, 9);
-GEN_VXFORM_V(vminuw, MO_32, tcg_gen_gvec_umin, 1, 10);
-GEN_VXFORM_V(vminud, MO_64, tcg_gen_gvec_umin, 1, 11);
-GEN_VXFORM_V(vminsb, MO_8, tcg_gen_gvec_smin, 1, 12);
-GEN_VXFORM_V(vminsh, MO_16, tcg_gen_gvec_smin, 1, 13);
-GEN_VXFORM_V(vminsw, MO_32, tcg_gen_gvec_smin, 1, 14);
-GEN_VXFORM_V(vminsd, MO_64, tcg_gen_gvec_smin, 1, 15);
 GEN_VXFORM(vmrghb, 6, 0);
 GEN_VXFORM(vmrghh, 6, 1);
 GEN_VXFORM(vmrghw, 6, 2);
@@ -727,6 +711,27 @@ TRANS_FLAGS2(ALTIVEC_207, VEQV, do_vector_gvec3_VX, MO_64, 
tcg_gen_gvec_eqv);
 TRANS_FLAGS2(ALTIVEC_207, VNAND, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_nand);
 TRANS_FLAGS2(ALTIVEC_207, VORC, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_orc);
 
+/* Integer Max/Min operations */
+TRANS_FLAGS(ALTIVEC, VMAXUB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_umax);
+TRANS_FLAGS(ALTIVEC, VMAXUH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_umax);
+TRANS_FLAGS(ALTIVEC, VMAXUW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_umax);
+TRANS_FLAGS2(ALTIVEC_207, VMAXUD, do_vector_gvec3_VX, MO_64, 
tcg_gen_gvec_umax);
+
+TRANS_FLAGS(ALTIVEC, VMAXSB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_smax);
+TRANS_FLAGS(ALTIVEC, VMAXSH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_smax);
+TRANS_FLAGS(ALTIVEC, VMAXSW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_smax);
+TRANS_FLAGS2(ALTIVEC_207, VMAXSD, do_vector_gvec3_VX, MO_64, 
tcg_gen_gvec_smax);
+
+TRANS_FLAGS(ALTIVEC, VMINUB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_umin);
+TRANS_FLAGS(ALTIVEC, VMINUH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_umin);
+TRANS_FLAGS(ALTIVEC, VMINUW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_umin);
+TRANS_FLAGS2(ALTIVEC_207, VMINUD, do_vector_gvec3_VX, MO_64, 
tcg_gen_gvec_umin);
+
+TRANS_FLAGS(ALTIVEC, VMINSB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_smin);
+TRANS_FLAGS(ALTIVEC, VMINSH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_smin);
+TRANS_FLAGS(ALTIVEC, VMINSW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_smin);
+TRANS_FLAGS2(ALTIVEC_207, VMINSD, do_vector_gv

Re: [PATCH v7 2/4] target/riscv: Enable mcontrol6 triggers only when sdtrig is selected

2024-04-28 Thread Alistair Francis
On Fri, Mar 15, 2024 at 5:01 AM Himanshu Chauhan
 wrote:
>
> The mcontrol6 triggers are not defined in debug specification v0.13
> These triggers are defined in sdtrig ISA extension.
>
> This patch:
>* Adds ext_sdtrig capability which is used to select mcontrol6 triggers
>* Keeps the debug property. All triggers that are defined in v0.13 are
>  exposed.

Thanks for this!

>
> Signed-off-by: Himanshu Chauhan 
> ---
>  target/riscv/cpu.c |  5 +
>  target/riscv/cpu_cfg.h |  1 +
>  target/riscv/debug.c   | 30 +-
>  3 files changed, 31 insertions(+), 5 deletions(-)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index c160b9216b..ab631500ac 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -1008,6 +1008,11 @@ static void riscv_cpu_reset_hold(Object *obj)
>  set_default_nan_mode(1, &env->fp_status);
>
>  #ifndef CONFIG_USER_ONLY
> +if (!cpu->cfg.debug && cpu->cfg.ext_sdtrig) {
> +warn_report("Enabling 'debug' since 'sdtrig' is enabled.");

I don't think we need the warning. It isn't a problem for the user

Otherwise

Reviewed-by: Alistair Francis 

Alistair

> +cpu->cfg.debug = true;
> +}
> +
>  if (cpu->cfg.debug) {
>  riscv_trigger_reset_hold(env);
>  }
> diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
> index 2040b90da0..0c57e1acd4 100644
> --- a/target/riscv/cpu_cfg.h
> +++ b/target/riscv/cpu_cfg.h
> @@ -114,6 +114,7 @@ struct RISCVCPUConfig {
>  bool ext_zvfbfwma;
>  bool ext_zvfh;
>  bool ext_zvfhmin;
> +bool ext_sdtrig;
>  bool ext_smaia;
>  bool ext_ssaia;
>  bool ext_sscofpmf;
> diff --git a/target/riscv/debug.c b/target/riscv/debug.c
> index 5f14b39b06..c40e727e12 100644
> --- a/target/riscv/debug.c
> +++ b/target/riscv/debug.c
> @@ -100,13 +100,16 @@ static trigger_action_t 
> get_trigger_action(CPURISCVState *env,
>  target_ulong tdata1 = env->tdata1[trigger_index];
>  int trigger_type = get_trigger_type(env, trigger_index);
>  trigger_action_t action = DBG_ACTION_NONE;
> +const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
>
>  switch (trigger_type) {
>  case TRIGGER_TYPE_AD_MATCH:
>  action = (tdata1 & TYPE2_ACTION) >> 12;
>  break;
>  case TRIGGER_TYPE_AD_MATCH6:
> -action = (tdata1 & TYPE6_ACTION) >> 12;
> +if (cfg->ext_sdtrig) {
> +action = (tdata1 & TYPE6_ACTION) >> 12;
> +}
>  break;
>  case TRIGGER_TYPE_INST_CNT:
>  case TRIGGER_TYPE_INT:
> @@ -727,7 +730,12 @@ void tdata_csr_write(CPURISCVState *env, int 
> tdata_index, target_ulong val)
>  type2_reg_write(env, env->trigger_cur, tdata_index, val);
>  break;
>  case TRIGGER_TYPE_AD_MATCH6:
> -type6_reg_write(env, env->trigger_cur, tdata_index, val);
> +if (riscv_cpu_cfg(env)->ext_sdtrig) {
> +type6_reg_write(env, env->trigger_cur, tdata_index, val);
> +} else {
> +qemu_log_mask(LOG_UNIMP, "trigger type: %d is not supported\n",
> +  trigger_type);
> +}
>  break;
>  case TRIGGER_TYPE_INST_CNT:
>  itrigger_reg_write(env, env->trigger_cur, tdata_index, val);
> @@ -750,9 +758,13 @@ void tdata_csr_write(CPURISCVState *env, int 
> tdata_index, target_ulong val)
>
>  target_ulong tinfo_csr_read(CPURISCVState *env)
>  {
> -/* assume all triggers support the same types of triggers */
> -return BIT(TRIGGER_TYPE_AD_MATCH) |
> -   BIT(TRIGGER_TYPE_AD_MATCH6);
> +target_ulong ts = BIT(TRIGGER_TYPE_AD_MATCH);
> +
> +if (riscv_cpu_cfg(env)->ext_sdtrig) {
> +ts |= BIT(TRIGGER_TYPE_AD_MATCH6);
> +}
> +
> +return ts;
>  }
>
>  void riscv_cpu_debug_excp_handler(CPUState *cs)
> @@ -803,6 +815,10 @@ bool riscv_cpu_debug_check_breakpoint(CPUState *cs)
>  }
>  break;
>  case TRIGGER_TYPE_AD_MATCH6:
> +if (!cpu->cfg.ext_sdtrig) {
> +break;
> +}
> +
>  ctrl = env->tdata1[i];
>  pc = env->tdata2[i];
>
> @@ -869,6 +885,10 @@ bool riscv_cpu_debug_check_watchpoint(CPUState *cs, 
> CPUWatchpoint *wp)
>  }
>  break;
>  case TRIGGER_TYPE_AD_MATCH6:
> +if (!cpu->cfg.ext_sdtrig) {
> +break;
> +}
> +
>  ctrl = env->tdata1[i];
>  addr = env->tdata2[i];
>  flags = 0;
> --
> 2.34.1
>
>



Re: [PATCH v7 1/4] target/riscv: Check for valid itimer pointer before free

2024-04-28 Thread Alistair Francis
On Fri, Mar 15, 2024 at 5:01 AM Himanshu Chauhan
 wrote:
>
> Check if each element of array of pointers for itimer contains a non-null
> pointer before freeing.
>
> Signed-off-by: Himanshu Chauhan 

Reviewed-by: Alistair Francis 

Alistair

> ---
>  target/riscv/debug.c | 5 -
>  1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/target/riscv/debug.c b/target/riscv/debug.c
> index e30d99cc2f..5f14b39b06 100644
> --- a/target/riscv/debug.c
> +++ b/target/riscv/debug.c
> @@ -938,7 +938,10 @@ void riscv_trigger_reset_hold(CPURISCVState *env)
>  env->tdata3[i] = 0;
>  env->cpu_breakpoint[i] = NULL;
>  env->cpu_watchpoint[i] = NULL;
> -timer_del(env->itrigger_timer[i]);
> +if (env->itrigger_timer[i]) {
> +timer_del(env->itrigger_timer[i]);
> +env->itrigger_timer[i] = NULL;
> +}
>  }
>
>  env->mcontext = 0;
> --
> 2.34.1
>
>



Re: [PATCH v3] target/riscv: raise an exception when CSRRS/CSRRC writes a read-only CSR

2024-04-28 Thread Alistair Francis
On Wed, Apr 3, 2024 at 5:10 PM Yu-Ming Chang via  wrote:
>
> Both CSRRS and CSRRC always read the addressed CSR and cause any read side
> effects regardless of rs1 and rd fields. Note that if rs1 specifies a register
> holding a zero value other than x0, the instruction will still attempt to 
> write
> the unmodified value back to the CSR and will cause any attendant side 
> effects.
>
> So if CSRRS or CSRRC tries to write a read-only CSR with rs1 which specifies
> a register holding a zero value, an illegal instruction exception should be
> raised.
>
> Signed-off-by: Yu-Ming Chang 

Thanks!

Applied to riscv-to-apply.next

Alistair

> ---
> Hi maintainers,
> Do I need to make any further improvements to this patch?
>
> Best regards,
> Yuming
>
>  target/riscv/cpu.h   |  4 
>  target/riscv/csr.c   | 51 
>  target/riscv/op_helper.c |  6 ++---
>  3 files changed, 53 insertions(+), 8 deletions(-)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 3b1a02b944..99006bdb45 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -710,6 +710,8 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc,
>  void riscv_cpu_update_mask(CPURISCVState *env);
>  bool riscv_cpu_is_32bit(RISCVCPU *cpu);
>
> +RISCVException riscv_csrr(CPURISCVState *env, int csrno,
> +  target_ulong *ret_value);
>  RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
> target_ulong *ret_value,
> target_ulong new_value, target_ulong write_mask);
> @@ -742,6 +744,8 @@ typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState 
> *env, int csrno,
>target_ulong new_value,
>target_ulong write_mask);
>
> +RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno,
> +   Int128 *ret_value);
>  RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno,
>  Int128 *ret_value,
>  Int128 new_value, Int128 write_mask);
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 726096444f..35662e1777 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -4312,7 +4312,7 @@ static RISCVException rmw_seed(CPURISCVState *env, int 
> csrno,
>
>  static inline RISCVException riscv_csrrw_check(CPURISCVState *env,
> int csrno,
> -   bool write_mask)
> +   bool write)
>  {
>  /* check privileges and return RISCV_EXCP_ILLEGAL_INST if check fails */
>  bool read_only = get_field(csrno, 0xC00) == 3;
> @@ -4334,7 +4334,7 @@ static inline RISCVException 
> riscv_csrrw_check(CPURISCVState *env,
>  }
>
>  /* read / write check */
> -if (write_mask && read_only) {
> +if (write && read_only) {
>  return RISCV_EXCP_ILLEGAL_INST;
>  }
>
> @@ -4421,11 +4421,22 @@ static RISCVException riscv_csrrw_do64(CPURISCVState 
> *env, int csrno,
>  return RISCV_EXCP_NONE;
>  }
>
> +RISCVException riscv_csrr(CPURISCVState *env, int csrno,
> +   target_ulong *ret_value)
> +{
> +RISCVException ret = riscv_csrrw_check(env, csrno, false);
> +if (ret != RISCV_EXCP_NONE) {
> +return ret;
> +}
> +
> +return riscv_csrrw_do64(env, csrno, ret_value, 0, 0);
> +}
> +
>  RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
> target_ulong *ret_value,
> target_ulong new_value, target_ulong write_mask)
>  {
> -RISCVException ret = riscv_csrrw_check(env, csrno, write_mask);
> +RISCVException ret = riscv_csrrw_check(env, csrno, true);
>  if (ret != RISCV_EXCP_NONE) {
>  return ret;
>  }
> @@ -4473,13 +4484,45 @@ static RISCVException riscv_csrrw_do128(CPURISCVState 
> *env, int csrno,
>  return RISCV_EXCP_NONE;
>  }
>
> +RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno,
> +   Int128 *ret_value)
> +{
> +RISCVException ret;
> +
> +ret = riscv_csrrw_check(env, csrno, false);
> +if (ret != RISCV_EXCP_NONE) {
> +return ret;
> +}
> +
> +if (csr_ops[csrno].read128) {
> +return riscv_csrrw_do128(env, csrno, ret_value,
> + int128_zero(), int128_zero());
> +}
> +
> +/*
> + * Fall back to 64-bit version for now, if the 128-bit alternative isn't
> + * at all defined.
> + * Note, some CSRs don't need to extend to MXLEN (64 upper bits non
> + * significant), for those, this fallback is correctly handling the
> + * accesses
> + */
> +target_ulong old_value;
> +ret = riscv_csrrw_do64(env, csrno, &old_value,
> +   (target_ulong)0,
> +   (target_ulong)0);
> +if (

Re: [PATCH v3] target/riscv: raise an exception when CSRRS/CSRRC writes a read-only CSR

2024-04-28 Thread Alistair Francis
On Wed, Apr 3, 2024 at 5:10 PM Yu-Ming Chang via  wrote:
>
> Both CSRRS and CSRRC always read the addressed CSR and cause any read side
> effects regardless of rs1 and rd fields. Note that if rs1 specifies a register
> holding a zero value other than x0, the instruction will still attempt to 
> write
> the unmodified value back to the CSR and will cause any attendant side 
> effects.
>
> So if CSRRS or CSRRC tries to write a read-only CSR with rs1 which specifies
> a register holding a zero value, an illegal instruction exception should be
> raised.
>
> Signed-off-by: Yu-Ming Chang 

Reviewed-by: Alistair Francis 

Alistair

> ---
> Hi maintainers,
> Do I need to make any further improvements to this patch?
>
> Best regards,
> Yuming
>
>  target/riscv/cpu.h   |  4 
>  target/riscv/csr.c   | 51 
>  target/riscv/op_helper.c |  6 ++---
>  3 files changed, 53 insertions(+), 8 deletions(-)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 3b1a02b944..99006bdb45 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -710,6 +710,8 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc,
>  void riscv_cpu_update_mask(CPURISCVState *env);
>  bool riscv_cpu_is_32bit(RISCVCPU *cpu);
>
> +RISCVException riscv_csrr(CPURISCVState *env, int csrno,
> +  target_ulong *ret_value);
>  RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
> target_ulong *ret_value,
> target_ulong new_value, target_ulong write_mask);
> @@ -742,6 +744,8 @@ typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState 
> *env, int csrno,
>target_ulong new_value,
>target_ulong write_mask);
>
> +RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno,
> +   Int128 *ret_value);
>  RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno,
>  Int128 *ret_value,
>  Int128 new_value, Int128 write_mask);
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 726096444f..35662e1777 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -4312,7 +4312,7 @@ static RISCVException rmw_seed(CPURISCVState *env, int 
> csrno,
>
>  static inline RISCVException riscv_csrrw_check(CPURISCVState *env,
> int csrno,
> -   bool write_mask)
> +   bool write)
>  {
>  /* check privileges and return RISCV_EXCP_ILLEGAL_INST if check fails */
>  bool read_only = get_field(csrno, 0xC00) == 3;
> @@ -4334,7 +4334,7 @@ static inline RISCVException 
> riscv_csrrw_check(CPURISCVState *env,
>  }
>
>  /* read / write check */
> -if (write_mask && read_only) {
> +if (write && read_only) {
>  return RISCV_EXCP_ILLEGAL_INST;
>  }
>
> @@ -4421,11 +4421,22 @@ static RISCVException riscv_csrrw_do64(CPURISCVState 
> *env, int csrno,
>  return RISCV_EXCP_NONE;
>  }
>
> +RISCVException riscv_csrr(CPURISCVState *env, int csrno,
> +   target_ulong *ret_value)
> +{
> +RISCVException ret = riscv_csrrw_check(env, csrno, false);
> +if (ret != RISCV_EXCP_NONE) {
> +return ret;
> +}
> +
> +return riscv_csrrw_do64(env, csrno, ret_value, 0, 0);
> +}
> +
>  RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
> target_ulong *ret_value,
> target_ulong new_value, target_ulong write_mask)
>  {
> -RISCVException ret = riscv_csrrw_check(env, csrno, write_mask);
> +RISCVException ret = riscv_csrrw_check(env, csrno, true);
>  if (ret != RISCV_EXCP_NONE) {
>  return ret;
>  }
> @@ -4473,13 +4484,45 @@ static RISCVException riscv_csrrw_do128(CPURISCVState 
> *env, int csrno,
>  return RISCV_EXCP_NONE;
>  }
>
> +RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno,
> +   Int128 *ret_value)
> +{
> +RISCVException ret;
> +
> +ret = riscv_csrrw_check(env, csrno, false);
> +if (ret != RISCV_EXCP_NONE) {
> +return ret;
> +}
> +
> +if (csr_ops[csrno].read128) {
> +return riscv_csrrw_do128(env, csrno, ret_value,
> + int128_zero(), int128_zero());
> +}
> +
> +/*
> + * Fall back to 64-bit version for now, if the 128-bit alternative isn't
> + * at all defined.
> + * Note, some CSRs don't need to extend to MXLEN (64 upper bits non
> + * significant), for those, this fallback is correctly handling the
> + * accesses
> + */
> +target_ulong old_value;
> +ret = riscv_csrrw_do64(env, csrno, &old_value,
> +   (target_ulong)0,
> +   (target_ulong)0);
> +if (ret == RI

Re: [PATCH 12/12] tests/qtest/bios-tables-test.c: Enable basic testing for RISC-V

2024-04-28 Thread Alistair Francis
On Fri, Mar 15, 2024 at 11:10 PM Sunil V L  wrote:
>
> Add basic ACPI table testing for RISC-V.
>
> Signed-off-by: Sunil V L 

Reviewed-by: Alistair Francis 

Alistair

> ---
>  tests/qtest/bios-tables-test.c | 28 
>  1 file changed, 28 insertions(+)
>
> diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
> index c492438ced..033acc8958 100644
> --- a/tests/qtest/bios-tables-test.c
> +++ b/tests/qtest/bios-tables-test.c
> @@ -1923,6 +1923,30 @@ static void test_acpi_microvm_acpi_erst(void)
>  }
>  #endif /* CONFIG_POSIX */
>
> +static void test_acpi_riscv64_virt_tcg(void)
> +{
> +test_data data = {
> +.machine = "virt",
> +.arch = "riscv64",
> +.tcg_only = true,
> +.uefi_fl1 = "pc-bios/edk2-riscv-code.fd",
> +.uefi_fl2 = "pc-bios/edk2-riscv-vars.fd",
> +.ram_start = 0x8000ULL,
> +.scan_len = 128ULL * 1024 * 1024,
> +};
> +
> +/*
> + * RHCT will have ISA string encoded. To reduce the effort
> + * of updating expected AML file for any new default ISA extension,
> + * use the profile rva22s64. Once profile is ratified, there may
> + * not be new extension possible.
> + */
> +test_acpi_one("-cpu rva22s64 -device virtio-blk-device,drive=hd0 "
> +  "-drive 
> file=tests/data/uefi-boot-images/bios-tables-test.riscv64.iso.qcow2,id=hd0",
> +  &data);
> +free_test_data(&data);
> +}
> +
>  static void test_acpi_aarch64_virt_tcg(void)
>  {
>  test_data data = {
> @@ -2342,6 +2366,10 @@ int main(int argc, char *argv[])
>  qtest_add_func("acpi/virt/viot", 
> test_acpi_aarch64_virt_viot);
>  }
>  }
> +} else if (strcmp(arch, "riscv64") == 0) {
> +if (has_tcg && qtest_has_device("virtio-blk-pci")) {
> +qtest_add_func("acpi/virt", test_acpi_riscv64_virt_tcg);
> +}
>  }
>  ret = g_test_run();
>  boot_sector_cleanup(disk);
> --
> 2.40.1
>



Re: [PATCH 11/12] tests/data/acpi/virt/riscv64: Add expected ACPI tables for RISC-V

2024-04-28 Thread Alistair Francis
On Fri, Mar 15, 2024 at 11:10 PM Sunil V L  wrote:
>
> Add expected ACPI tables for RISC-V so that bios-table-test can be
> enabled for RISC-V.

Can you detail where and how these files are generated/built?

Alistair

>
> Signed-off-by: Sunil V L 
> ---
>  tests/data/acpi/virt/riscv64/APIC | Bin 0 -> 116 bytes
>  tests/data/acpi/virt/riscv64/BGRT | Bin 0 -> 56 bytes
>  tests/data/acpi/virt/riscv64/DSDT | Bin 0 -> 3518 bytes
>  tests/data/acpi/virt/riscv64/FACP | Bin 0 -> 276 bytes
>  tests/data/acpi/virt/riscv64/MCFG | Bin 0 -> 60 bytes
>  tests/data/acpi/virt/riscv64/RHCT | Bin 0 -> 314 bytes
>  tests/data/acpi/virt/riscv64/RSDP | Bin 0 -> 36 bytes
>  tests/data/acpi/virt/riscv64/SPCR | Bin 0 -> 80 bytes
>  tests/data/acpi/virt/riscv64/XSDT | Bin 0 -> 84 bytes
>  9 files changed, 0 insertions(+), 0 deletions(-)
>  create mode 100755 tests/data/acpi/virt/riscv64/APIC
>  create mode 100755 tests/data/acpi/virt/riscv64/BGRT
>  create mode 100755 tests/data/acpi/virt/riscv64/DSDT
>  create mode 100755 tests/data/acpi/virt/riscv64/FACP
>  create mode 100755 tests/data/acpi/virt/riscv64/MCFG
>  create mode 100755 tests/data/acpi/virt/riscv64/RHCT
>  create mode 100755 tests/data/acpi/virt/riscv64/RSDP
>  create mode 100755 tests/data/acpi/virt/riscv64/SPCR
>  create mode 100755 tests/data/acpi/virt/riscv64/XSDT
>
> diff --git a/tests/data/acpi/virt/riscv64/APIC 
> b/tests/data/acpi/virt/riscv64/APIC
> new file mode 100755
> index 
> ..66a25dfd2d6ea2b607c024722b2eab95873a01e9
> GIT binary patch
> literal 116
> zcmZ<^@N_O=U|?X|;^gn_5v<@85#X!<1dKp25F13pfP@Mo12P{Zj?R|`s)2!c7=s}J
> I#NvT*0o0BN0RR91
>
> literal 0
> HcmV?d1
>
> diff --git a/tests/data/acpi/virt/riscv64/BGRT 
> b/tests/data/acpi/virt/riscv64/BGRT
> new file mode 100755
> index 
> ..dccf14cce4063dbfe18cd8a459aaa8b206d3b3f0
> GIT binary patch
> literal 56
> zcmZ>A4+^nhU|?XZ_Vf#J^-*wj@itNb0w$msh!zG)F#_2V3gY!3S{^7-3}gTR|5yhB
>
> literal 0
> HcmV?d1
>
> diff --git a/tests/data/acpi/virt/riscv64/DSDT 
> b/tests/data/acpi/virt/riscv64/DSDT
> new file mode 100755
> index 
> ..0fb2d5e0e389541209b765d5092d0706f40298f6
> GIT binary patch
> literal 3518
> zcmZvf%WvaU6vnR;w@IBxlQexl(t(j!ppl%0(ryq zgcxeCJ*}oI`D?w!iChKA+$9t$orAn%(bn
> zN+n)t?0eh6a^of6TgGN7rRbcFh1Tyc_k%{iceZVNuIr}z+pT7 z>)qm0&dr&dmZB`a{a^Ra*0&D5Eo1b;X8Qm}E3gQ zVE91w&KfCiza7@#@A>YkTOF1_DRa)WNl^t#{A^TNmZNji{btZCtt5&QPNDqU;E!+b
> zecnEQ^xc;~?0jvN=B?69B6sx0n@1-LMCh z|GVk1+UV8=+`16nn$W3iZBaGE(t=R0Su8V)L_|(iti)M3i8v3Jc_g_ zZ0_+)tcM-v;WLjB?y(x{F%swTD)SiS9?!;ljK+DKGLIDZSc~;Y#d$nr9_i3y=NsQ^
> zu@zZ&*ReP}{EyK3th+T@*_*eqZ#4FX%O>b{iWO(USDtFAW3{YY{55g*p1P}!a8zWX
> z7lz;IPVBzpJS=7G%wV8y2Q62ba|`EHRm#%1lYm%>L=vK=N;x|_7+?*WxKL3R0`umY
> z&O>MhKe$y(1g;N2-TU8l! zP=$;-)Haz>@sOMoiwl`i1tW@cj+o4-cu3BPCB-VhD+4MD9hIDroD&Pl#Oi8OIy2%-
> zNlr-4iRFXLXr|LTGn$gLp$V}cX!M^n3=p)tt`$vN>NG_kr`M{qil6Owag1ZPHY
> zW+W#h=gbPutl-Q_PDsv)?-Htwo@Y*Q<|HR1=gbSvyx`1BPDsup=eXpA zv*(GAkEvZhm4f7i zLUPVY!8s{7CnYB&=bRFpQ-X6!azb*>X~8)yIHx5iB zS;+~>Ip+lDoZy_3oRFMzUU1F}&UwiR$vGDU=Yrr|kera5b5U?E3eH8z3CTH^1m}|A
> zT#}rSoU5@qiM`L8Qmx@>rXnqyVu6bqy3;0
> zSfN$e$O$X-aop-gjFlN1TJ2C(VM8aZsGs9rPsDhcG3gaHcG3%d9rt=N#> zYt+>h-rEXOMpLn!a_)bcQwbVUYCt>d6Z~go(OKwiV=x$e6rJOWm8FJLZ)jL(gSOQ9
> z(=101Q%{N90rg{iGreXyIPiUy_PU*2Ro)uw?+2cJexkhQVfAu5b@3W?^1b$-wSOuL
> z8($pWumAYmuXoN*92)^EIHqx|osu9QI;oM>2efl4w7)DozPM|Bh$~ecUA>%od=bT&
> z;R0PerC=JrI{7MZ#_1;2tCR9A{Hkc%mp4o`zpVZISFrki`_c5@?b)Ba_T|{c>*}hQ
> pv@F`;cR<_jYzAT_(hnb+|8pBtRxTSGr9{slF`>K_0A
>
> literal 0
> HcmV?d1
>
> diff --git a/tests/data/acpi/virt/riscv64/FACP 
> b/tests/data/acpi/virt/riscv64/FACP
> new file mode 100755
> index 
> ..a5276b65ea8ce46cc9b40d96d98f0669c9089ed4
> GIT binary patch
> literal 276
> zcmZ>BbPf< A0RR91
>
> literal 0
> HcmV?d1
>
> diff --git a/tests/data/acpi/virt/riscv64/MCFG 
> b/tests/data/acpi/virt/riscv64/MCFG
> new file mode 100755
> index 
> ..37eb923a9320f5573c0c2cdb90bd98409cc7eb6f
> GIT binary patch
> literal 60
> rcmeZuc5}C3U|?Y6aq@Te2v%^42yj*a0!E-1hz+8VfB}^KA4CHH3`GY4
>
> literal 0
> HcmV?d1
>
> diff --git a/tests/data/acpi/virt/riscv64/RHCT 
> b/tests/data/acpi/virt/riscv64/RHCT
> new file mode 100755
> index 
> ..beaa961bbf0f0486c0dee25f543377c928354f84
> GIT binary patch
> literal 314
> zcmXAlu}%Xq42FGxD#XNyI`tt=C&buWx`A2-wkXNvbP-K1O46&8iKjrk6)SI3ey5h~
> z@3-SPa`wCa{iPvl)b_RC9X8vKw|)adiC8n)zP^7d?+~A>`lE(^DK1@Wog4=(iq&1K
> z7;1J`gewX|OE=3Z>{xM3wM)ljIQKa+635YaZ7jrOeGc+eJEnks*|jl=GEUBVQ8WhX
> zK@ Pp1|9>GjINg;u`)Bd);9H
>
> literal 0
> HcmV?d1
>
> diff --git a/tests/data/acpi/virt/riscv64/RSDP 
> b/tests/data/acpi/virt/riscv64/RSDP
> new file mode 100755
> index 
> ..55054f8730c389d0d7eba90c24a1dae6d1283b90
> GIT binary patch
> literal 36
> ncmWFvc2Nij2~zmy
> literal 0
> HcmV?d1
>
> diff 

Re: [PATCH 10/12] tests/data/acpi/rebuild-expected-aml.sh: Add RISC-V

2024-04-28 Thread Alistair Francis
On Fri, Mar 15, 2024 at 11:10 PM Sunil V L  wrote:
>
> Update the list of supported architectures to include RISC-V.
>
> Signed-off-by: Sunil V L 

Reviewed-by: Alistair Francis 

Alistair

> ---
>  tests/data/acpi/rebuild-expected-aml.sh | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/tests/data/acpi/rebuild-expected-aml.sh 
> b/tests/data/acpi/rebuild-expected-aml.sh
> index dcf2e2f221..c1092fb8ba 100755
> --- a/tests/data/acpi/rebuild-expected-aml.sh
> +++ b/tests/data/acpi/rebuild-expected-aml.sh
> @@ -12,7 +12,7 @@
>  # This work is licensed under the terms of the GNU GPLv2.
>  # See the COPYING.LIB file in the top-level directory.
>
> -qemu_arches="x86_64 aarch64"
> +qemu_arches="x86_64 aarch64 riscv64"
>
>  if [ ! -e "tests/qtest/bios-tables-test" ]; then
>  echo "Test: bios-tables-test is required! Run make check before this 
> script."
> @@ -36,7 +36,8 @@ fi
>  if [ -z "$qemu_bins" ]; then
>  echo "Only the following architectures are currently supported: 
> $qemu_arches"
>  echo "None of these configured!"
> -echo "To fix, run configure --target-list=x86_64-softmmu,aarch64-softmmu"
> +echo "To fix, run configure \
> + --target-list=x86_64-softmmu,aarch64-softmmu,riscv64-softmmu"
>  exit 1;
>  fi
>
> --
> 2.40.1
>



Re: [PATCH v4] target/riscv: Implement dynamic establishment of custom decoder

2024-04-28 Thread Alistair Francis
On Thu, Mar 14, 2024 at 7:23 PM Huang Tao  wrote:
>
> In this patch, we modify the decoder to be a freely composable data
> structure instead of a hardcoded one. It can be dynamically builded up
> according to the extensions.
> This approach has several benefits:
> 1. Provides support for heterogeneous cpu architectures. As we add decoder in
>RISCVCPU, each cpu can have their own decoder, and the decoders can be
>different due to cpu's features.
> 2. Improve the decoding efficiency. We run the guard_func to see if the 
> decoder
>can be added to the dynamic_decoder when building up the decoder. 
> Therefore,
>there is no need to run the guard_func when decoding each instruction. It 
> can
>improve the decoding efficiency
> 3. For vendor or dynamic cpus, it allows them to customize their own decoder
>functions to improve decoding efficiency, especially when vendor-defined
>instruction sets increase. Because of dynamic building up, it can skip the 
> other
>decoder guard functions when decoding.
> 4. Pre patch for allowing adding a vendor decoder before decode_insn32() with 
> minimal
>overhead for users that don't need this particular vendor decoder.
>
> Signed-off-by: Huang Tao 
> Suggested-by: Christoph Muellner 
> Co-authored-by: LIU Zhiwei 
> Reviewed-by: Richard Henderson 

Do you mind rebasing this on
https://github.com/alistair23/qemu/tree/riscv-to-apply.next?

Alistair

> ---
> Changes in v4:
> - fix typo
> - rename function
> - add 'if tcg_enable()'
> - move function to tcg-cpu.c and declarations to tcg-cpu.h
>
> Changes in v3:
> - use GPtrArray to save decode function poionter list.
> ---
>  target/riscv/cpu.c |  1 +
>  target/riscv/cpu.h |  1 +
>  target/riscv/tcg/tcg-cpu.c | 15 +++
>  target/riscv/tcg/tcg-cpu.h | 15 +++
>  target/riscv/translate.c   | 31 +++
>  5 files changed, 47 insertions(+), 16 deletions(-)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index c160b9216b..17070b82a7 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -1132,6 +1132,7 @@ void riscv_cpu_finalize_features(RISCVCPU *cpu, Error 
> **errp)
>  error_propagate(errp, local_err);
>  return;
>  }
> +riscv_tcg_cpu_finalize_dynamic_decoder(cpu);
>  } else if (kvm_enabled()) {
>  riscv_kvm_cpu_finalize_features(cpu, &local_err);
>  if (local_err != NULL) {
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 3b1a02b944..48e67410e1 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -457,6 +457,7 @@ struct ArchCPU {
>  uint32_t pmu_avail_ctrs;
>  /* Mapping of events to counters */
>  GHashTable *pmu_event_ctr_map;
> +const GPtrArray *decoders;
>  };
>
>  /**
> diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
> index ab6db817db..c9ab92ea2f 100644
> --- a/target/riscv/tcg/tcg-cpu.c
> +++ b/target/riscv/tcg/tcg-cpu.c
> @@ -853,6 +853,21 @@ void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, 
> Error **errp)
>  }
>  }
>
> +void riscv_tcg_cpu_finalize_dynamic_decoder(RISCVCPU *cpu)
> +{
> +GPtrArray *dynamic_decoders;
> +dynamic_decoders = g_ptr_array_sized_new(decoder_table_size);
> +for (size_t i = 0; i < decoder_table_size; ++i) {
> +if (decoder_table[i].guard_func &&
> +decoder_table[i].guard_func(&cpu->cfg)) {
> +g_ptr_array_add(dynamic_decoders,
> +(gpointer)decoder_table[i].riscv_cpu_decode_fn);
> +}
> +}
> +
> +cpu->decoders = dynamic_decoders;
> +}
> +
>  bool riscv_cpu_tcg_compatible(RISCVCPU *cpu)
>  {
>  return object_dynamic_cast(OBJECT(cpu), TYPE_RISCV_CPU_HOST) == NULL;
> diff --git a/target/riscv/tcg/tcg-cpu.h b/target/riscv/tcg/tcg-cpu.h
> index f7b32417f8..ce94253fe4 100644
> --- a/target/riscv/tcg/tcg-cpu.h
> +++ b/target/riscv/tcg/tcg-cpu.h
> @@ -26,4 +26,19 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, 
> Error **errp);
>  void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error **errp);
>  bool riscv_cpu_tcg_compatible(RISCVCPU *cpu);
>
> +struct DisasContext;
> +struct RISCVCPUConfig;
> +typedef struct RISCVDecoder {
> +bool (*guard_func)(const struct RISCVCPUConfig *);
> +bool (*riscv_cpu_decode_fn)(struct DisasContext *, uint32_t);
> +} RISCVDecoder;
> +
> +typedef bool (*riscv_cpu_decode_fn)(struct DisasContext *, uint32_t);
> +
> +extern const size_t decoder_table_size;
> +
> +extern const RISCVDecoder decoder_table[];
> +
> +void riscv_tcg_cpu_finalize_dynamic_decoder(RISCVCPU *cpu);
> +
>  #endif
> diff --git a/target/riscv/translate.c b/target/riscv/translate.c
> index ea5d52b2ef..bce16d5054 100644
> --- a/target/riscv/translate.c
> +++ b/target/riscv/translate.c
> @@ -37,6 +37,8 @@
>  #include "exec/helper-info.c.inc"
>  #undef  HELPER_H
>
> +#include "tcg/tcg-cpu.h"
> +
>  /* global register indices */
>  static TCGv cpu_gpr[32], cpu_gprh

Re: [PATCH 09/12] pc-bios/meson.build: Add support for RISC-V in unpack_edk2_blobs

2024-04-28 Thread Alistair Francis
On Fri, Mar 15, 2024 at 11:10 PM Sunil V L  wrote:
>
> Update list of images supported in unpack_edk2_blobs to enable RISC-V
> ACPI table testing.
>
> Signed-off-by: Sunil V L 

Reviewed-by: Alistair Francis 

Alistair

> ---
>  pc-bios/meson.build | 2 ++
>  tests/qtest/meson.build | 3 +++
>  2 files changed, 5 insertions(+)
>
> diff --git a/pc-bios/meson.build b/pc-bios/meson.build
> index 0760612bea..8602b45b9b 100644
> --- a/pc-bios/meson.build
> +++ b/pc-bios/meson.build
> @@ -4,6 +4,8 @@ if unpack_edk2_blobs
>  'edk2-aarch64-code.fd',
>  'edk2-arm-code.fd',
>  'edk2-arm-vars.fd',
> +'edk2-riscv-code.fd',
> +'edk2-riscv-vars.fd',
>  'edk2-i386-code.fd',
>  'edk2-i386-secure-code.fd',
>  'edk2-i386-vars.fd',
> diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
> index 36c5c13a7b..dd19711d9f 100644
> --- a/tests/qtest/meson.build
> +++ b/tests/qtest/meson.build
> @@ -252,6 +252,9 @@ qtests_s390x = \
>  qtests_riscv32 = \
>(config_all_devices.has_key('CONFIG_SIFIVE_E_AON') ? 
> ['sifive-e-aon-watchdog-test'] : [])
>
> +qtests_riscv64 = \
> +  (unpack_edk2_blobs ? ['bios-tables-test'] : [])
> +
>  qos_test_ss = ss.source_set()
>  qos_test_ss.add(
>'ac97-test.c',
> --
> 2.40.1
>



Re: [PATCH 08/12] meson.build: Add RISC-V to the edk2-target list

2024-04-28 Thread Alistair Francis
On Fri, Mar 15, 2024 at 11:09 PM Sunil V L  wrote:
>
> so that ACPI table test can be supported.
>
> Signed-off-by: Sunil V L 

Reviewed-by: Alistair Francis 

Alistair

> ---
>  meson.build | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/meson.build b/meson.build
> index b8ded80cbe..bf50688593 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -93,7 +93,7 @@ else
>iasl = find_program(get_option('iasl'), required: true)
>  endif
>
> -edk2_targets = [ 'arm-softmmu', 'aarch64-softmmu', 'i386-softmmu', 
> 'x86_64-softmmu' ]
> +edk2_targets = [ 'arm-softmmu', 'aarch64-softmmu', 'i386-softmmu', 
> 'x86_64-softmmu', 'riscv64-softmmu' ]
>  unpack_edk2_blobs = false
>  foreach target : edk2_targets
>if target in target_dirs
> --
> 2.40.1
>



Re: [PATCH 07/12] tests/data/acpi/virt: Move ACPI tables under aarch64

2024-04-28 Thread Alistair Francis
On Fri, Mar 15, 2024 at 11:09 PM Sunil V L  wrote:
>
> Since virt is a common machine name across architectures like ARM64 and
> RISC-V, move existing ARM64 ACPI tables under aarch64 folder so that
> RISC-V tables can be added under riscv64 folder in future.
>
> Signed-off-by: Sunil V L 

Reviewed-by: Alistair Francis 

Alistair

> ---
>  tests/data/acpi/virt/{ => aarch64}/APIC | Bin
>  .../data/acpi/virt/{ => aarch64}/APIC.acpihmatvirt  | Bin
>  tests/data/acpi/virt/{ => aarch64}/APIC.topology| Bin
>  tests/data/acpi/virt/{ => aarch64}/DBG2 | Bin
>  tests/data/acpi/virt/{ => aarch64}/DSDT | Bin
>  .../data/acpi/virt/{ => aarch64}/DSDT.acpihmatvirt  | Bin
>  tests/data/acpi/virt/{ => aarch64}/DSDT.memhp   | Bin
>  tests/data/acpi/virt/{ => aarch64}/DSDT.pxb | Bin
>  tests/data/acpi/virt/{ => aarch64}/DSDT.topology| Bin
>  tests/data/acpi/virt/{ => aarch64}/FACP | Bin
>  tests/data/acpi/virt/{ => aarch64}/GTDT | Bin
>  .../data/acpi/virt/{ => aarch64}/HMAT.acpihmatvirt  | Bin
>  tests/data/acpi/virt/{ => aarch64}/IORT | Bin
>  tests/data/acpi/virt/{ => aarch64}/MCFG | Bin
>  tests/data/acpi/virt/{ => aarch64}/NFIT.memhp   | Bin
>  tests/data/acpi/virt/{ => aarch64}/PPTT | Bin
>  .../data/acpi/virt/{ => aarch64}/PPTT.acpihmatvirt  | Bin
>  tests/data/acpi/virt/{ => aarch64}/PPTT.topology| Bin
>  tests/data/acpi/virt/{ => aarch64}/SLIT.memhp   | Bin
>  tests/data/acpi/virt/{ => aarch64}/SPCR | Bin
>  .../data/acpi/virt/{ => aarch64}/SRAT.acpihmatvirt  | Bin
>  tests/data/acpi/virt/{ => aarch64}/SRAT.memhp   | Bin
>  tests/data/acpi/virt/{ => aarch64}/SRAT.numamem | Bin
>  tests/data/acpi/virt/{ => aarch64}/SSDT.memhp   | Bin
>  tests/data/acpi/virt/{ => aarch64}/VIOT | Bin
>  25 files changed, 0 insertions(+), 0 deletions(-)
>  rename tests/data/acpi/virt/{ => aarch64}/APIC (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/APIC.acpihmatvirt (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/APIC.topology (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/DBG2 (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/DSDT (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/DSDT.acpihmatvirt (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/DSDT.memhp (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/DSDT.pxb (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/DSDT.topology (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/FACP (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/GTDT (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/HMAT.acpihmatvirt (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/IORT (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/MCFG (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/NFIT.memhp (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/PPTT (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/PPTT.acpihmatvirt (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/PPTT.topology (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/SLIT.memhp (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/SPCR (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/SRAT.acpihmatvirt (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/SRAT.memhp (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/SRAT.numamem (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/SSDT.memhp (100%)
>  rename tests/data/acpi/virt/{ => aarch64}/VIOT (100%)
>
> diff --git a/tests/data/acpi/virt/APIC b/tests/data/acpi/virt/aarch64/APIC
> similarity index 100%
> rename from tests/data/acpi/virt/APIC
> rename to tests/data/acpi/virt/aarch64/APIC
> diff --git a/tests/data/acpi/virt/APIC.acpihmatvirt 
> b/tests/data/acpi/virt/aarch64/APIC.acpihmatvirt
> similarity index 100%
> rename from tests/data/acpi/virt/APIC.acpihmatvirt
> rename to tests/data/acpi/virt/aarch64/APIC.acpihmatvirt
> diff --git a/tests/data/acpi/virt/APIC.topology 
> b/tests/data/acpi/virt/aarch64/APIC.topology
> similarity index 100%
> rename from tests/data/acpi/virt/APIC.topology
> rename to tests/data/acpi/virt/aarch64/APIC.topology
> diff --git a/tests/data/acpi/virt/DBG2 b/tests/data/acpi/virt/aarch64/DBG2
> similarity index 100%
> rename from tests/data/acpi/virt/DBG2
> rename to tests/data/acpi/virt/aarch64/DBG2
> diff --git a/tests/data/acpi/virt/DSDT b/tests/data/acpi/virt/aarch64/DSDT
> similarity index 100%
> rename from tests/data/acpi/virt/DSDT
> rename to tests/data/acpi/virt/aarch64/DSDT
> diff --git a/tests/data/acpi/virt/DSDT.acpihmatvirt 
> b/tests/data/acpi/virt/aarch64/DSDT.acpihmatvirt
> similarity index 100%
> rename from tests/data/acpi/virt/DSDT.acpihmatvirt
> rename to tests/data/acpi/virt/aarch64/DSDT.acpihmatvirt
> diff --git a/tests/data/acpi/virt/DSDT.memhp 
> b/tests/data/acpi/virt/aarch64/DSDT.memhp
> similarity index 100%
> rename from tests/data/acpi/virt/DSDT.memhp
> rename to tests/data/acpi/virt/aarch64/DSDT.memhp
> diff --git a/tests/data/acpi/virt/D

Re: [PATCH 06/12] tests/qtest/bios-tables-test.c: Add support for arch in path

2024-04-28 Thread Alistair Francis
On Fri, Mar 15, 2024 at 11:09 PM Sunil V L  wrote:
>
> Since virt machine is common for multiple architectures, add "arch" in
> the path to search expected AML files. Since the AML files are still
> under old path, support both by searching with and without arch in the
> path.
>
> Signed-off-by: Sunil V L 

Reviewed-by: Alistair Francis 

Alistair

> ---
>  tests/qtest/bios-tables-test.c | 32 +---
>  1 file changed, 29 insertions(+), 3 deletions(-)
>
> diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
> index ea3ba1992b..c492438ced 100644
> --- a/tests/qtest/bios-tables-test.c
> +++ b/tests/qtest/bios-tables-test.c
> @@ -78,6 +78,7 @@
>  typedef struct {
>  bool tcg_only;
>  const char *machine;
> +const char *arch;
>  const char *machine_param;
>  const char *variant;
>  const char *uefi_fl1;
> @@ -262,8 +263,20 @@ static void dump_aml_files(test_data *data, bool rebuild)
>  g_assert(exp_sdt->aml);
>
>  if (rebuild) {
> -aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, 
> data->machine,
> +aml_file = g_strdup_printf("%s/%s/%s/%.4s%s", data_dir,
> +   data->machine, data->arch,
> sdt->aml, ext);
> +
> +/*
> + * To keep test cases not failing when the DATA files are moved 
> to
> + * ARCH under virt folder, add this check which can be removed 
> once
> + * the DATA files are moved.
> + */
> +if (!g_file_test(aml_file, G_FILE_TEST_EXISTS)) {
> +aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, 
> data->machine,
> +   sdt->aml, ext);
> +}
> +
>  if (!g_file_test(aml_file, G_FILE_TEST_EXISTS) &&
>  sdt->aml_len == exp_sdt->aml_len &&
>  !memcmp(sdt->aml, exp_sdt->aml, sdt->aml_len)) {
> @@ -398,8 +411,13 @@ static GArray *load_expected_aml(test_data *data)
>  memset(&exp_sdt, 0, sizeof(exp_sdt));
>
>  try_again:
> -aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
> -   sdt->aml, ext);
> +aml_file = g_strdup_printf("%s/%s/%s/%.4s%s", data_dir, 
> data->machine,
> +   data->arch, sdt->aml, ext);
> +if (!g_file_test(aml_file, G_FILE_TEST_EXISTS)) {
> +aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, 
> data->machine,
> +   sdt->aml, ext);
> +}
> +exp_sdt.aml_file = aml_file;
>  if (verbosity_level >= 2) {
>  fprintf(stderr, "Looking for expected file '%s'\n", aml_file);
>  }
> @@ -1561,6 +1579,7 @@ static void test_acpi_aarch64_virt_tcg_memhp(void)
>  {
>  test_data data = {
>  .machine = "virt",
> +.arch = "aarch64",
>  .tcg_only = true,
>  .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
>  .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
> @@ -1654,6 +1673,7 @@ static void test_acpi_aarch64_virt_tcg_numamem(void)
>  {
>  test_data data = {
>  .machine = "virt",
> +.arch = "aarch64",
>  .tcg_only = true,
>  .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
>  .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
> @@ -1676,6 +1696,7 @@ static void test_acpi_aarch64_virt_tcg_pxb(void)
>  {
>  test_data data = {
>  .machine = "virt",
> +.arch = "aarch64",
>  .tcg_only = true,
>  .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
>  .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
> @@ -1749,6 +1770,7 @@ static void test_acpi_aarch64_virt_tcg_acpi_hmat(void)
>  {
>  test_data data = {
>  .machine = "virt",
> +.arch = "aarch64",
>  .tcg_only = true,
>  .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
>  .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
> @@ -1905,6 +1927,7 @@ static void test_acpi_aarch64_virt_tcg(void)
>  {
>  test_data data = {
>  .machine = "virt",
> +.arch = "aarch64",
>  .tcg_only = true,
>  .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
>  .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
> @@ -1924,6 +1947,7 @@ static void test_acpi_aarch64_virt_tcg_topology(void)
>  {
>  test_data data = {
>  .machine = "virt",
> +.arch = "aarch64",
>  .variant = ".topology",
>  .tcg_only = true,
>  .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
> @@ -2007,6 +2031,7 @@ static void test_acpi_aarch64_virt_viot(void)
>  {
>  test_data data = {
>  .machine = "virt",
> +.arch = "aarch64",
>  .tcg_only = true,
>  .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
>  .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
> @@ -2139,6 +2164,7 @@ static void test_acpi_aarch64_virt_oem_fields(void)
>  {
>  test_data data =

Re: [PATCH 05/12] qtest: bios-tables-test: Rename aarch64 tests with aarch64 in them

2024-04-28 Thread Alistair Francis
On Fri, Mar 15, 2024 at 11:09 PM Sunil V L  wrote:
>
> Existing AARCH64 virt test functions do not have AARCH64 in their name.
> To add RISC-V virt related test cases, better to rename existing
> functions to indicate they are ARM only.
>
> Signed-off-by: Sunil V L 

Reviewed-by: Alistair Francis 

Alistair

> ---
>  tests/qtest/bios-tables-test.c | 35 ++
>  1 file changed, 19 insertions(+), 16 deletions(-)
>
> diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
> index 21811a1ab5..ea3ba1992b 100644
> --- a/tests/qtest/bios-tables-test.c
> +++ b/tests/qtest/bios-tables-test.c
> @@ -1557,7 +1557,7 @@ static void test_acpi_piix4_tcg_dimm_pxm(void)
>  test_acpi_tcg_dimm_pxm(MACHINE_PC);
>  }
>
> -static void test_acpi_virt_tcg_memhp(void)
> +static void test_acpi_aarch64_virt_tcg_memhp(void)
>  {
>  test_data data = {
>  .machine = "virt",
> @@ -1650,7 +1650,7 @@ static void test_acpi_microvm_ioapic2_tcg(void)
>  free_test_data(&data);
>  }
>
> -static void test_acpi_virt_tcg_numamem(void)
> +static void test_acpi_aarch64_virt_tcg_numamem(void)
>  {
>  test_data data = {
>  .machine = "virt",
> @@ -1672,7 +1672,7 @@ static void test_acpi_virt_tcg_numamem(void)
>
>  }
>
> -static void test_acpi_virt_tcg_pxb(void)
> +static void test_acpi_aarch64_virt_tcg_pxb(void)
>  {
>  test_data data = {
>  .machine = "virt",
> @@ -1745,7 +1745,7 @@ static void test_acpi_piix4_tcg_acpi_hmat(void)
>  test_acpi_tcg_acpi_hmat(MACHINE_PC);
>  }
>
> -static void test_acpi_virt_tcg_acpi_hmat(void)
> +static void test_acpi_aarch64_virt_tcg_acpi_hmat(void)
>  {
>  test_data data = {
>  .machine = "virt",
> @@ -1901,7 +1901,7 @@ static void test_acpi_microvm_acpi_erst(void)
>  }
>  #endif /* CONFIG_POSIX */
>
> -static void test_acpi_virt_tcg(void)
> +static void test_acpi_aarch64_virt_tcg(void)
>  {
>  test_data data = {
>  .machine = "virt",
> @@ -1920,7 +1920,7 @@ static void test_acpi_virt_tcg(void)
>  free_test_data(&data);
>  }
>
> -static void test_acpi_virt_tcg_topology(void)
> +static void test_acpi_aarch64_virt_tcg_topology(void)
>  {
>  test_data data = {
>  .machine = "virt",
> @@ -2003,7 +2003,7 @@ static void test_acpi_q35_cxl(void)
>  }
>  #endif /* CONFIG_POSIX */
>
> -static void test_acpi_virt_viot(void)
> +static void test_acpi_aarch64_virt_viot(void)
>  {
>  test_data data = {
>  .machine = "virt",
> @@ -2135,7 +2135,7 @@ static void test_acpi_microvm_oem_fields(void)
>  g_free(args);
>  }
>
> -static void test_acpi_virt_oem_fields(void)
> +static void test_acpi_aarch64_virt_oem_fields(void)
>  {
>  test_data data = {
>  .machine = "virt",
> @@ -2301,16 +2301,19 @@ int main(int argc, char *argv[])
>  }
>  } else if (strcmp(arch, "aarch64") == 0) {
>  if (has_tcg && qtest_has_device("virtio-blk-pci")) {
> -qtest_add_func("acpi/virt", test_acpi_virt_tcg);
> +qtest_add_func("acpi/virt", test_acpi_aarch64_virt_tcg);
>  qtest_add_func("acpi/virt/acpihmatvirt",
> -test_acpi_virt_tcg_acpi_hmat);
> -qtest_add_func("acpi/virt/topology", 
> test_acpi_virt_tcg_topology);
> -qtest_add_func("acpi/virt/numamem", test_acpi_virt_tcg_numamem);
> -qtest_add_func("acpi/virt/memhp", test_acpi_virt_tcg_memhp);
> -qtest_add_func("acpi/virt/pxb", test_acpi_virt_tcg_pxb);
> -qtest_add_func("acpi/virt/oem-fields", 
> test_acpi_virt_oem_fields);
> +   test_acpi_aarch64_virt_tcg_acpi_hmat);
> +qtest_add_func("acpi/virt/topology",
> +   test_acpi_aarch64_virt_tcg_topology);
> +qtest_add_func("acpi/virt/numamem",
> +   test_acpi_aarch64_virt_tcg_numamem);
> +qtest_add_func("acpi/virt/memhp", 
> test_acpi_aarch64_virt_tcg_memhp);
> +qtest_add_func("acpi/virt/pxb", test_acpi_aarch64_virt_tcg_pxb);
> +qtest_add_func("acpi/virt/oem-fields",
> +   test_acpi_aarch64_virt_oem_fields);
>  if (qtest_has_device("virtio-iommu-pci")) {
> -qtest_add_func("acpi/virt/viot", test_acpi_virt_viot);
> +qtest_add_func("acpi/virt/viot", 
> test_acpi_aarch64_virt_viot);
>  }
>  }
>  }
> --
> 2.40.1
>



Re: [PATCH 04/12] tests/data/uefi-boot-images: Add RISC-V ISO image

2024-04-28 Thread Alistair Francis
On Fri, Mar 15, 2024 at 11:09 PM Sunil V L  wrote:
>
> To test ACPI tables, edk2 needs to be booted with a disk image having
> EFI partition. This image is created using UefiTestToolsPkg.

Can we document exactly how this is generated?

Alistair

>
> Signed-off-by: Sunil V L 
> ---
>  .../bios-tables-test.riscv64.iso.qcow2  | Bin 0 -> 16896 bytes
>  1 file changed, 0 insertions(+), 0 deletions(-)
>  create mode 100644 
> tests/data/uefi-boot-images/bios-tables-test.riscv64.iso.qcow2
>
> diff --git a/tests/data/uefi-boot-images/bios-tables-test.riscv64.iso.qcow2 
> b/tests/data/uefi-boot-images/bios-tables-test.riscv64.iso.qcow2
> new file mode 100644
> index 
> ..c720bf99a45fab6d1e21963cca563ee0ea059b82
> GIT binary patch
> literal 16896
> zcmeIZbyQp5w=Wvpf_t$*DNx*s76?*Gkpjhw1#fW*1ef3~T4-^K6sNdLaVJ>O;85J1
> zQtYN*dfvO^_r|&BjPd@sc6P{~`K&p2_F8kzHD!gZF8|^R005vN-~auA^AEuE|F<^$
> z`wy6ZG3p z_xx|@-`fAs`xiQr{%5_w|CP%9-)GSN|8x}_a8C*T_v!e5_4NOj2EhMZjSKiomH*QD
> zf0~h}zj*WC@W0Y~J|4-xw*P1G-|IpDS^0mJ`+Gh2zqbEp@!#vk|2_G?{Fr}_5BZ0I
> zmv=7*eEpX~|I*lh*#8Tk%v_*+yu9Y-hexM)k!r2@sfGd9K1aO*;5H00Tww@06OrZ8
> z5@aa=+vz ze&FE@Q?{7~eU9$yACs`VJL0a+XCzoJo{kNEx2gkp@vhq8LSKa}QGwPn*YYNLL{
> z@~dP#ETCmdJ*7_kgqm;AKA-YZ)H7i(_@NMQyg)%>KxsGsR-2gBcMs8>CNZu}?giTr
> zW$PK&8%mMm2N;bN$uC%lqEk?%*o3+>e_ic4JOyZ|QDL}X0t1oRteN9K<8(Pw$37xF
> z1|I2P6F9n_yPUW{fk&qoW*`a$lHzw{Kz0D&>R{It0_pAL#g%74US}QyK_2E*7!OJR
> zAOI>3rhJGxFB1wt!!!m0K*PZ#AnIyU>wpil!a2G-TU)W^B7llPn!FEq6{Iy4q~)j}
> z>{K9cNmkXnrC&tPStW#fh-_pr=`de}dA<-N&D^d}y}pq>O>MJ&j$(%bF!LVvC;g^~
> zXE=dk`Gi+tSz8D zE!HV_; zO))_I13c;qnhO2HJTH{{UuY@xaSlytsA2cMP~m*3)eGl%$tCkqb)b)jEniasuC% z&Zfx4jmghJUZKH3u6RtY_`#ol>wS_3uBWFbZj%A zkpZ&g(|VYmZbB9TMC$l|z*Fjn^GtHR;Nn(STY^9oIQpY|qy0yKkfrVQ0ssbT{;@Lf
> zD`XQ5Fs9*;hJqPVm319 zz%Sr!DWXGx#Ovp%MAGuCn0_Fj3AQPq--{nzKtv#jFOe_NA8zSr;dp#Oh;#f+z{T}M
> z6Z|ASco~e{!Ir@X0Gvdcf@lO|O34XO4XCMJp(d(#O7d> zqI?)_gAoOZaWl<>zyV%_=l~oF%n-a=AdsJV^C9}F;wuhCstjLCnUP*F48|zU^QfHp
> zBMJ#O{w?+cY7szMfzGGoxOAWs2Ye9nKr0PthyUvz;D5RZZ20$j`j@}-Kj!00+{+OG
> zApZywo!w&+yn9UQdymNi?=d<2o>EHQw^NnfV`{`brO~{nv}N~vdis0JU~x}DfBiTU
> z_#QueeNUO^!GJ#p3peB+${KJ_*~Y>DV0OiO%z=B4IqmK-*N1z`!*k!xn|6=+obNIJ
> z-|rFdzsG_R_xvXb_gE z;9m|iNCr@oqQXc0cPl8=9YrM4Ci?)1f@8Iihn0CWpe5WAz@Sgkk!
> z`gPpBm$H~L9JTE~PC!(x9k^sr57SWaemy2t{-hFrElVz*fv{aT9xicJN6~n1W2%AH
> zFz7ge3Yn;tW&tB8wW|-F68=c@4o$;g>UMmqbv5_1c)wkvML zMn<^4q13|xeoj(hGYFBT(iMNw8Cr{oS} z=Zi}}TF|Xa?;4$3@)rdFI`_xj)J|%%X7)0I%4U~Ax%2p;YI~RfuZ6> zZ&idXAc=FHr%pwUhvNqkV;EFaUxWpf@9*k$Zq9Gx@BinnJ3p+5L_@0wb2 zCfM0hI4`j*4h$xmPrNHV23l6dcR7j5(Hga@hb5wH8`|kL8}$xA1N57L)5TCXejBv$
> z{k)5eb)IL{`fW5O7qG}gsDQ0}t+)wZ;e3fsj0N=!BQ(!24c>raUAyg?f9Xt3O+n84
> zxsFBX$^U1H-jvM19JShUm36pu-|w@BOyrj!y)XL!K-(D4iF`Jx?;EZRkq(^%-V;CE
> zcCCm2TZd0Zyx9J>IzrROgqwwaV4a)5#CQHST8)M~U(xf(CglJ&*7=;~S6QbpX;V)T
> zw2syD4S@~j;erLP2kkcLLaZLfMRkwS0(o~v2kvzw!X~{MrJ5esl&4GEOJV7d&hn8{
> zeXmzCDRM1cZ?;5Rdn$LUpGE2RNlNXtlH|}3`e>#khWUA_OBnq{A4nn&@%q-@rrO#r
> zxunkjqcl+%<=?T&QPlY8on}hQAT0X`EyB5^YASJg%Nk_nMh*dNzwzGuKByng+~1e4
> z(>xQDn?MQP0zxSLe$(8ldOyAz4en>*y!(XjKOM3bU4b#c5Vo*p2u|1JNb!apiEl7F
> z6oe$t^09h6zbrWyIyW4 zX0m0099ygS39lB`T#P2Q_hl_{AE#DbAvz_qmXPsnFH?coYZQ&HrK&<7Cgsmv2~wa*
> zS!j$Dcv z&k6E`v6FJ-oY)=Jb%Lm!G$R7SQ$X=1RNTd6XXzmoHI<3w_QO*QAajh+ zoVP^BQ6bN~{IY0aOq7^|<(^m8&iWE-GgCjyF#kUBTPd32-(SXhmEv@A8$;@ezZ4Cn
> zH7>@vXsP?ApYD`Ds;wbvlic;r&SvoW5h{zAnIo~U0XGI;nY+E^rWKx**=fVr<=(@I
> zO5qv}aXk5CR8{LkI<~~9xK4fKH@V}TA6(DfZG-1LPdWF)-~zu^aB6Q!#@P^;GI@u;
> z4tpm`m-41mquxn8e1f?;V%ABiZlX3YrJ~3ltEae`Zce;$8)|WdW*6O}gvLkKGd3_9
> zK`!RvNGvcn)8@&>_L<;My9Y^gH$Wy9eAsc
> z*l+dtwVGq!z*W<*a1;Eh1G*bV8qoDlueCBHZfEf7Q`bwwGQ{VxZ8~GZq<3WpzWh?k
> zT^6RC1loy@L<6#`Y~N7#q0j_Ql`njd2(+Sh@_)AET3l<&=RUtU`}k1AHlY=2AWFiR
> zovd$E!^p++iW zn|V@0A%f6x&Ob<(^}*dE_@{V7pA%jFdZwdu{0WWs52L0_UL@Hwz0D^&&rDIYv}AgL
> zd;Un{&J$5A3n#38v3a%RllkhG_=D zOr|MI>WXf$oR@TjbdO6BO>4t4(8kFvAP_iAL-p&EUHtW1AuDMT@z$@l<*S619(Zb8
> z11;tS2SD(-G3d&nqSq}%+pP^FazC!cZ==@6M{`LtD{*?fm96(&ehVYezoIYJk4S))
> zQ@i?t9&_f*Va3bo2_~kAP|b(*l9fU*#m*RR{`>>b<@(Mp5FAI6`bxJvxvJG&>q@ii
> zg+L}t4!No&{*r%U&TG_aRqAZhC;`bhs?$*wv3TL6Y8Z{_D;vpiNzt+web{los3i}D
> zk=~Bo$0P=jR8wMzSnp-9$l=K-yPkD#7M)*XV5<^J@Ux1wx3U7f9})pl;@=IKPZese
> z;0ivjh}nz&5sitdmdK%Rd-?DXy!yTqFG;u`lM~+0!UT^)NS`K1Wr!rt4c$`qVj_-)
> zONtSn)_5x44j6~gkfT#mgH6(L1vL^s9+gzQ&xoy%{z?)E9PzpMgkLj<)^HeA(e+t;
> zZ2nJZY*Z3rKz0D&^~+lf4XxuO1hZaiPlHf6rE)Ii(#RkZCY?CQ<;uT zKT8qj&;Ur3{9gE7-Oyc3ob>0a z;LSH8Z|hK*dIA{p9DN(akscZ9+9ujptOjjpO zdGON=+}IUs7psh6Q1bE%(g?EirSP)j2=KH2QR~0O`HI!_ine&aexc{Lf(?8r)z@}H
> z7MDG?GslE0=~xc`Z`c92E@%l6Yreuv?gXKYdl2TI(5r3Gh0)9*lA|jHQhf-PC9INS
> zk?MVyj>uZ$W*bk0WdiVP6=D`al1d^tu2Ltds|9(CyFZmdEpQ3olTc!W)ow(-WJ(Ev
> zwi!l6z4{Hr?d$K(pG0wVla<{5y%qX0=B$2JR@RyaLH#_5k@PH40g9?rA|TJG6q(a1
> zC>p>j>_f`2cPTO`1%Z0{y)kBl@U`3s2ou*@iRwJrR=)?3|!
> zzb=BOYGq}bI)_Y74y>ePd|u(&FjaV31ajTwHU^%S`I)=w*t-w4_5w6I{@8s(;o3pc
> zpx*7E`y7z@g6yD=0_y{AC4=AWCd&|}c{$yc>xfpO7C7^*=huINDC<+poR;LcId^*N
> zS5G>b&k{)bw2M18?fr&;r?U|~W7K~V3y~(Hi3KlOrjzTf)YYVet_kqIdSw#a)BlA5
> zd9S5Pb#T629fsBg)e2=;e!FuJ&VDozOO@zLOD#x9;*vFvdWs|d>NZ`Mn)7}

Re: [PATCH v4] target/riscv: Implement dynamic establishment of custom decoder

2024-04-28 Thread Alistair Francis
On Thu, Mar 14, 2024 at 7:23 PM Huang Tao  wrote:
>
> In this patch, we modify the decoder to be a freely composable data
> structure instead of a hardcoded one. It can be dynamically builded up
> according to the extensions.
> This approach has several benefits:
> 1. Provides support for heterogeneous cpu architectures. As we add decoder in
>RISCVCPU, each cpu can have their own decoder, and the decoders can be
>different due to cpu's features.
> 2. Improve the decoding efficiency. We run the guard_func to see if the 
> decoder
>can be added to the dynamic_decoder when building up the decoder. 
> Therefore,
>there is no need to run the guard_func when decoding each instruction. It 
> can
>improve the decoding efficiency
> 3. For vendor or dynamic cpus, it allows them to customize their own decoder
>functions to improve decoding efficiency, especially when vendor-defined
>instruction sets increase. Because of dynamic building up, it can skip the 
> other
>decoder guard functions when decoding.
> 4. Pre patch for allowing adding a vendor decoder before decode_insn32() with 
> minimal
>overhead for users that don't need this particular vendor decoder.
>
> Signed-off-by: Huang Tao 
> Suggested-by: Christoph Muellner 
> Co-authored-by: LIU Zhiwei 
> Reviewed-by: Richard Henderson 

Reviewed-by: Alistair Francis 

Alistair

> ---
> Changes in v4:
> - fix typo
> - rename function
> - add 'if tcg_enable()'
> - move function to tcg-cpu.c and declarations to tcg-cpu.h
>
> Changes in v3:
> - use GPtrArray to save decode function poionter list.
> ---
>  target/riscv/cpu.c |  1 +
>  target/riscv/cpu.h |  1 +
>  target/riscv/tcg/tcg-cpu.c | 15 +++
>  target/riscv/tcg/tcg-cpu.h | 15 +++
>  target/riscv/translate.c   | 31 +++
>  5 files changed, 47 insertions(+), 16 deletions(-)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index c160b9216b..17070b82a7 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -1132,6 +1132,7 @@ void riscv_cpu_finalize_features(RISCVCPU *cpu, Error 
> **errp)
>  error_propagate(errp, local_err);
>  return;
>  }
> +riscv_tcg_cpu_finalize_dynamic_decoder(cpu);
>  } else if (kvm_enabled()) {
>  riscv_kvm_cpu_finalize_features(cpu, &local_err);
>  if (local_err != NULL) {
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 3b1a02b944..48e67410e1 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -457,6 +457,7 @@ struct ArchCPU {
>  uint32_t pmu_avail_ctrs;
>  /* Mapping of events to counters */
>  GHashTable *pmu_event_ctr_map;
> +const GPtrArray *decoders;
>  };
>
>  /**
> diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
> index ab6db817db..c9ab92ea2f 100644
> --- a/target/riscv/tcg/tcg-cpu.c
> +++ b/target/riscv/tcg/tcg-cpu.c
> @@ -853,6 +853,21 @@ void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, 
> Error **errp)
>  }
>  }
>
> +void riscv_tcg_cpu_finalize_dynamic_decoder(RISCVCPU *cpu)
> +{
> +GPtrArray *dynamic_decoders;
> +dynamic_decoders = g_ptr_array_sized_new(decoder_table_size);
> +for (size_t i = 0; i < decoder_table_size; ++i) {
> +if (decoder_table[i].guard_func &&
> +decoder_table[i].guard_func(&cpu->cfg)) {
> +g_ptr_array_add(dynamic_decoders,
> +(gpointer)decoder_table[i].riscv_cpu_decode_fn);
> +}
> +}
> +
> +cpu->decoders = dynamic_decoders;
> +}
> +
>  bool riscv_cpu_tcg_compatible(RISCVCPU *cpu)
>  {
>  return object_dynamic_cast(OBJECT(cpu), TYPE_RISCV_CPU_HOST) == NULL;
> diff --git a/target/riscv/tcg/tcg-cpu.h b/target/riscv/tcg/tcg-cpu.h
> index f7b32417f8..ce94253fe4 100644
> --- a/target/riscv/tcg/tcg-cpu.h
> +++ b/target/riscv/tcg/tcg-cpu.h
> @@ -26,4 +26,19 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, 
> Error **errp);
>  void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error **errp);
>  bool riscv_cpu_tcg_compatible(RISCVCPU *cpu);
>
> +struct DisasContext;
> +struct RISCVCPUConfig;
> +typedef struct RISCVDecoder {
> +bool (*guard_func)(const struct RISCVCPUConfig *);
> +bool (*riscv_cpu_decode_fn)(struct DisasContext *, uint32_t);
> +} RISCVDecoder;
> +
> +typedef bool (*riscv_cpu_decode_fn)(struct DisasContext *, uint32_t);
> +
> +extern const size_t decoder_table_size;
> +
> +extern const RISCVDecoder decoder_table[];
> +
> +void riscv_tcg_cpu_finalize_dynamic_decoder(RISCVCPU *cpu);
> +
>  #endif
> diff --git a/target/riscv/translate.c b/target/riscv/translate.c
> index ea5d52b2ef..bce16d5054 100644
> --- a/target/riscv/translate.c
> +++ b/target/riscv/translate.c
> @@ -37,6 +37,8 @@
>  #include "exec/helper-info.c.inc"
>  #undef  HELPER_H
>
> +#include "tcg/tcg-cpu.h"
> +
>  /* global register indices */
>  static TCGv cpu_gpr[32], cpu_gprh[32], cpu_pc, cpu_vl, cpu_vstart;
>  static TCGv_i64 cpu_fp

Re: [PATCH v3] target/riscv: Fix the element agnostic function problem

2024-04-28 Thread Alistair Francis
On Mon, Mar 25, 2024 at 12:18 PM Huang Tao  wrote:
>
> In RVV and vcrypto instructions, the masked and tail elements are set to 1s
> using vext_set_elems_1s function if the vma/vta bit is set. It is the element
> agnostic policy.
>
> However, this function can't deal the big endian situation. This patch fixes
> the problem by adding handling of such case.
>
> Signed-off-by: Huang Tao 
> Suggested-by: Richard Henderson 
> Reviewed-by: LIU Zhiwei 

Thanks!

Applied to riscv-to-apply.next

Alistair

> ---
> Changes in v3:
> - use "if (HOST_BIG_ENDIAN)" instead of "#if HOST_BIG_ENDIAN"
>
> Changes in v2:
> - Keep the api of vext_set_elems_1s
> - Reduce the number of patches.
> ---
>  target/riscv/vector_internals.c | 22 ++
>  1 file changed, 22 insertions(+)
>
> diff --git a/target/riscv/vector_internals.c b/target/riscv/vector_internals.c
> index 12f5964fbb..36635a1138 100644
> --- a/target/riscv/vector_internals.c
> +++ b/target/riscv/vector_internals.c
> @@ -30,6 +30,28 @@ void vext_set_elems_1s(void *base, uint32_t is_agnostic, 
> uint32_t cnt,
>  if (tot - cnt == 0) {
>  return ;
>  }
> +
> +if (HOST_BIG_ENDIAN) {
> +/*
> + * Deal the situation when the elements are insdie
> + * only one uint64 block including setting the
> + * masked-off element.
> + */
> +if (((tot - 1) ^ cnt) < 8) {
> +memset(base + H1(tot - 1), -1, tot - cnt);
> +return;
> +}
> +/*
> + * Otherwise, at least cross two uint64_t blocks.
> + * Set first unaligned block.
> + */
> +if (cnt % 8 != 0) {
> +uint32_t j = ROUND_UP(cnt, 8);
> +memset(base + H1(j - 1), -1, j - cnt);
> +cnt = j;
> +}
> +/* Set other 64bit aligend blocks */
> +}
>  memset(base + cnt, -1, tot - cnt);
>  }
>
> --
> 2.41.0
>
>



Re: [PATCH v3 0/3] target/riscv: Support Zve32x and Zve64x extensions

2024-04-28 Thread Alistair Francis
On Thu, Mar 28, 2024 at 12:25 PM Jason Chien  wrote:
>
> This patch series adds the support for Zve32x and Zvx64x and makes vector
> registers visible in GDB if any of the V/Zve*/Zvk* extensions is enabled.
>
> v2:
> Rebase onto riscv-to-apply.next (commit 385e575).
> v3:
> Spuash patch 2 into patch 1.
> Spuash patch 4 into patch 3.
>
> Jason Chien (3):
>   target/riscv: Add support for Zve32x extension
>   target/riscv: Add support for Zve64x extension
>   target/riscv: Relax vector register check in RISCV gdbstub

Thanks!

Applied to riscv-to-apply.next

Alistair

>
>  target/riscv/cpu.c  |  4 +++
>  target/riscv/cpu_cfg.h  |  2 ++
>  target/riscv/cpu_helper.c   |  2 +-
>  target/riscv/csr.c  |  2 +-
>  target/riscv/gdbstub.c  |  2 +-
>  target/riscv/insn_trans/trans_rvv.c.inc |  4 +--
>  target/riscv/tcg/tcg-cpu.c  | 33 ++---
>  7 files changed, 30 insertions(+), 19 deletions(-)
>
> --
> 2.43.2
>
>



Re: [PATCH v4] riscv: thead: Add th.sxstatus CSR emulation

2024-04-28 Thread Alistair Francis
On Mon, Apr 22, 2024 at 4:53 PM Christoph Müllner
 wrote:
>
> The th.sxstatus CSR can be used to identify available custom extension
> on T-Head CPUs. The CSR is documented here:
>   
> https://github.com/T-head-Semi/thead-extension-spec/blob/master/xtheadsxstatus.adoc
>
> An important property of this patch is, that the th.sxstatus MAEE field
> is not set (indicating that XTheadMae is not available).
> XTheadMae is a memory attribute extension (similar to Svpbmt) which is
> implemented in many T-Head CPUs (C906, C910, etc.) and utilizes bits
> in PTEs that are marked as reserved. QEMU maintainers prefer to not
> implement XTheadMae, so we need give kernels a mechanism to identify
> if XTheadMae is available in a system or not. And this patch introduces
> this mechanism in QEMU in a way that's compatible with real HW
> (i.e., probing the th.sxstatus.MAEE bit).
>
> Further context can be found on the list:
> https://lists.gnu.org/archive/html/qemu-devel/2024-02/msg00775.html
>
> Reviewed-by: LIU Zhiwei 
> Signed-off-by: Christoph Müllner 
> ---
>  target/riscv/cpu.c   |  1 +
>  target/riscv/cpu.h   |  3 ++
>  target/riscv/meson.build |  1 +
>  target/riscv/th_csr.c| 77 
>  4 files changed, 82 insertions(+)
>  create mode 100644 target/riscv/th_csr.c
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 36e3e5fdaf..b82ba95ae6 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -545,6 +545,7 @@ static void rv64_thead_c906_cpu_init(Object *obj)
>  cpu->cfg.mvendorid = THEAD_VENDOR_ID;
>  #ifndef CONFIG_USER_ONLY
>  set_satp_mode_max_supported(cpu, VM_1_10_SV39);
> +th_register_custom_csrs(cpu);
>  #endif
>
>  /* inherited from parent obj via riscv_cpu_init() */
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 3b1a02b944..c9f8f06751 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -824,4 +824,7 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState 
> *cs);
>  uint8_t satp_mode_max_from_map(uint32_t map);
>  const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit);
>
> +/* Implemented in th_csr.c */
> +void th_register_custom_csrs(RISCVCPU *cpu);
> +
>  #endif /* RISCV_CPU_H */
> diff --git a/target/riscv/meson.build b/target/riscv/meson.build
> index a5e0734e7f..a4bd61e52a 100644
> --- a/target/riscv/meson.build
> +++ b/target/riscv/meson.build
> @@ -33,6 +33,7 @@ riscv_system_ss.add(files(
>'monitor.c',
>'machine.c',
>'pmu.c',
> +  'th_csr.c',
>'time_helper.c',
>'riscv-qmp-cmds.c',
>  ))
> diff --git a/target/riscv/th_csr.c b/target/riscv/th_csr.c
> new file mode 100644
> index 00..0eb3ad64f1
> --- /dev/null
> +++ b/target/riscv/th_csr.c
> @@ -0,0 +1,77 @@
> +/*
> + * T-Head-specific CSRs.
> + *
> + * Copyright (c) 2024 VRULL GmbH
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along 
> with
> + * this program.  If not, see .
> + */
> +
> +#include "qemu/osdep.h"
> +#include "cpu.h"
> +#include "cpu_vendorid.h"
> +
> +#define CSR_TH_SXSTATUS 0x5c0
> +
> +/* TH_SXSTATUS bits */
> +#define TH_SXSTATUS_UCMEBIT(16)
> +#define TH_SXSTATUS_MAEEBIT(21)
> +#define TH_SXSTATUS_THEADISAEE  BIT(22)
> +
> +typedef struct {
> +int csrno;
> +int (*insertion_test)(RISCVCPU *cpu);
> +riscv_csr_operations csr_ops;
> +} riscv_csr;
> +
> +static RISCVException smode(CPURISCVState *env, int csrno)
> +{
> +if (riscv_has_ext(env, RVS)) {
> +return RISCV_EXCP_NONE;
> +}
> +
> +return RISCV_EXCP_ILLEGAL_INST;
> +}
> +
> +static int test_thead_mvendorid(RISCVCPU *cpu)
> +{
> +if (cpu->cfg.mvendorid != THEAD_VENDOR_ID)
> +return -1;
> +
> +return 0;
> +}
> +
> +static RISCVException read_th_sxstatus(CPURISCVState *env, int csrno,
> +   target_ulong *val)
> +{
> +/* We don't set MAEE here, because QEMU does not implement MAEE. */
> +*val = TH_SXSTATUS_UCME | TH_SXSTATUS_THEADISAEE;
> +return RISCV_EXCP_NONE;
> +}
> +
> +static riscv_csr th_csr_list[] = {
> +{
> +.csrno = CSR_TH_SXSTATUS,
> +.insertion_test = test_thead_mvendorid,
> +.csr_ops = { "th.sxstatus", smode, read_th_sxstatus }
> +}
> +};
> +
> +void th_register_custom_csrs(RISCVCPU *cpu)
> +{
> +for (size_t i = 0; i < ARRAY_SIZE(th_csr_list); i++) {
> +int csrno = th_csr_list[i].csrno;
> +riscv_csr_operations *csr_ops = &th

[RFC PATCH v3 07/18] hw/arm/smmuv3: Translate CD and TT using stage-2 table

2024-04-28 Thread Mostafa Saleh
According to ARM SMMU architecture specification (ARM IHI 0070 F.b),
In "5.2 Stream Table Entry":
 [51:6] S1ContextPtr
 If Config[1] == 1 (stage 2 enabled), this pointer is an IPA translated by
 stage 2 and the programmed value must be within the range of the IAS.

In "5.4.1 CD notes":
 The translation table walks performed from TTB0 or TTB1 are always performed
 in IPA space if stage 2 translations are enabled.

This patch implements translation of the S1 context descriptor pointer and
TTBx base addresses through the S2 stage (IPA -> PA)

smmuv3_do_translate() is updated to have one arg which is translation
class, this is useful for:
 - Decide wether a translation is stage-2 only or use the STE config.
 - Populate the class in case of faults, WALK_EABT is lefat as it as
   it is always triggered from TT access so no need to use the input
   class.

In case for stage-2 only translation, which only used in nesting, the
stage and asid are saved and restored before and after calling
smmu_translate().

Translating CD or TTBx can fail for the following reasons:
1) Large address size: This is described in
   (3.4.3 Address sizes of SMMU-originated accesses)
   - For CD ptr larger than IAS, for SMMUv3.1, it can trigger either
 C_BAD_STE or Translation fault, we implement the latter as it
 requires no extra code.
   - For TTBx, if larger than the effective stage 1 output address size, it
 triggers C_BAD_CD.

2) Faults from PTWs (7.3 Event records)
   - F_ADDR_SIZE: large address size after first level causes stage 2 Address
 Size fault (Also in 3.4.3 Address sizes of SMMU-originated accesses)
   - F_PERMISSION: Same as an address translation. However, when
 CLASS == CD, the access is implicitly Data and a read.
   - F_ACCESS: Same as an address translation.
   - F_TRANSLATION: Same as an address translation.
   - F_WALK_EABT: Same as an address translation.
  These are already implemented in the PTW logic, so no extra handling
  required.

As, there is multiple locations where the address is calculated from
cached entry, a new macro is introduced CACHED_ENTRY_TO_ADDR.

Signed-off-by: Mostafa Saleh 
---
 hw/arm/smmuv3.c  | 76 ++--
 include/hw/arm/smmu-common.h |  3 ++
 2 files changed, 66 insertions(+), 13 deletions(-)

diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index cc61708160..cc61c82321 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -337,14 +337,33 @@ static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, 
STE *buf,
 
 }
 
+static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
+ SMMUTransCfg *cfg,
+ SMMUEventInfo *event,
+ IOMMUAccessFlags flag,
+ SMMUTLBEntry **out_entry,
+ SMMUTranslationClass class);
 /* @ssid > 0 not supported yet */
-static int smmu_get_cd(SMMUv3State *s, STE *ste, uint32_t ssid,
-   CD *buf, SMMUEventInfo *event)
+static int smmu_get_cd(SMMUv3State *s, STE *ste, SMMUTransCfg *cfg,
+   uint32_t ssid, CD *buf, SMMUEventInfo *event)
 {
 dma_addr_t addr = STE_CTXPTR(ste);
 int ret, i;
+SMMUTranslationStatus status;
+SMMUTLBEntry *entry;
 
 trace_smmuv3_get_cd(addr);
+
+if (cfg->stage == SMMU_NESTED) {
+status = smmuv3_do_translate(s, addr, cfg, event,
+ IOMMU_RO, &entry, SMMU_CLASS_CD);
+if (status != SMMU_TRANS_SUCCESS) {
+return -EINVAL;
+}
+
+addr = CACHED_ENTRY_TO_ADDR(entry, addr);
+}
+
 /* TODO: guarantee 64-bit single-copy atomicity */
 ret = dma_memory_read(&address_space_memory, addr, buf, sizeof(*buf),
   MEMTXATTRS_UNSPECIFIED);
@@ -659,10 +678,13 @@ static int smmu_find_ste(SMMUv3State *s, uint32_t sid, 
STE *ste,
 return 0;
 }
 
-static int decode_cd(SMMUTransCfg *cfg, CD *cd, SMMUEventInfo *event)
+static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
+ CD *cd, SMMUEventInfo *event)
 {
 int ret = -EINVAL;
 int i;
+SMMUTranslationStatus status;
+SMMUTLBEntry *entry;
 
 if (!CD_VALID(cd) || !CD_AARCH64(cd)) {
 goto bad_cd;
@@ -713,9 +735,21 @@ static int decode_cd(SMMUTransCfg *cfg, CD *cd, 
SMMUEventInfo *event)
 
 tt->tsz = tsz;
 tt->ttb = CD_TTB(cd, i);
+
 if (tt->ttb & ~(MAKE_64BIT_MASK(0, cfg->oas))) {
 goto bad_cd;
 }
+
+/* Translate the TTBx, from IPA to PA if nesting is enabled. */
+if (cfg->stage == SMMU_NESTED) {
+status = smmuv3_do_translate(s, tt->ttb, cfg, event, IOMMU_RO,
+ &entry, SMMU_CLASS_TT);
+if (status != SMMU_TRANS_SUCCESS) {
+return -EINVAL;
+}

[RFC PATCH v3 01/18] hw/arm/smmu-common: Add missing size check for stage-1

2024-04-28 Thread Mostafa Saleh
According to the SMMU architecture specification (ARM IHI 0070 F.b),
in “3.4 Address sizes”
The address output from the translation causes a stage 1 Address Size
fault if it exceeds the range of the effective IPA size for the given CD.

However, this check was missing.

There is already a similar check for stage-2 against effective PA.

Signed-off-by: Mostafa Saleh 
---
 hw/arm/smmu-common.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 1ce706bf94..eb2356bc35 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -381,6 +381,16 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
 goto error;
 }
 
+/*
+ * The address output from the translation causes a stage 1 Address
+ * Size fault if it exceeds the range of the effective IPA size for
+ * the given CD.
+ */
+if (gpa >= (1ULL << cfg->oas)) {
+info->type = SMMU_PTW_ERR_ADDR_SIZE;
+goto error;
+}
+
 tlbe->entry.translated_addr = gpa;
 tlbe->entry.iova = iova & ~mask;
 tlbe->entry.addr_mask = mask;
-- 
2.44.0.769.g3c40516874-goog




[RFC PATCH v3 06/18] hw/arm/smmu: Consolidate ASID and VMID types

2024-04-28 Thread Mostafa Saleh
ASID and VMID used to be uint16_t in the translation config, however,
in other contexts they can be int as -1 in case of TLB invalidation,
to represent all(don’t care).
When stage-2 was added asid was set to -1 in stage-2 and vmid to -1
in stage-1 configs. However, that meant they were set as (65536),
this was not an issue as nesting was not supported and no
commands/lookup targets both.

With nesting, it’s critical to get this right as translation must be
tagged correctly with ASID/VMID, and with ASID=-1 meaning stage-2.
Represent ASID/VMID everywhere as int.

Signed-off-by: Mostafa Saleh 
---
 hw/arm/smmu-common.c | 10 +-
 hw/arm/smmuv3.c  |  4 ++--
 hw/arm/trace-events  | 18 +-
 include/hw/arm/smmu-common.h | 14 +++---
 4 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index d94db6b34f..21982621c0 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -57,7 +57,7 @@ static gboolean smmu_iotlb_key_equal(gconstpointer v1, 
gconstpointer v2)
(k1->vmid == k2->vmid);
 }
 
-SMMUIOTLBKey smmu_get_iotlb_key(uint16_t asid, uint16_t vmid, uint64_t iova,
+SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
 uint8_t tg, uint8_t level)
 {
 SMMUIOTLBKey key = {.asid = asid, .vmid = vmid, .iova = iova,
@@ -130,7 +130,7 @@ void smmu_iotlb_inv_all(SMMUState *s)
 static gboolean smmu_hash_remove_by_asid(gpointer key, gpointer value,
  gpointer user_data)
 {
-uint16_t asid = *(uint16_t *)user_data;
+int asid = *(int *)user_data;
 SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
 
 return SMMU_IOTLB_ASID(*iotlb_key) == asid;
@@ -139,7 +139,7 @@ static gboolean smmu_hash_remove_by_asid(gpointer key, 
gpointer value,
 static gboolean smmu_hash_remove_by_vmid(gpointer key, gpointer value,
  gpointer user_data)
 {
-uint16_t vmid = *(uint16_t *)user_data;
+int vmid = *(int *)user_data;
 SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
 
 return SMMU_IOTLB_VMID(*iotlb_key) == vmid;
@@ -191,13 +191,13 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int 
vmid, dma_addr_t iova,
 &info);
 }
 
-void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid)
+void smmu_iotlb_inv_asid(SMMUState *s, int asid)
 {
 trace_smmu_iotlb_inv_asid(asid);
 g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid, &asid);
 }
 
-void smmu_iotlb_inv_vmid(SMMUState *s, uint16_t vmid)
+void smmu_iotlb_inv_vmid(SMMUState *s, int vmid)
 {
 trace_smmu_iotlb_inv_vmid(vmid);
 g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid, &vmid);
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index f98c157221..cc61708160 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1243,7 +1243,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
 }
 case SMMU_CMD_TLBI_NH_ASID:
 {
-uint16_t asid = CMD_ASID(&cmd);
+int asid = CMD_ASID(&cmd);
 
 if (!STAGE1_SUPPORTED(s)) {
 cmd_error = SMMU_CERROR_ILL;
@@ -1276,7 +1276,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
 break;
 case SMMU_CMD_TLBI_S12_VMALL:
 {
-uint16_t vmid = CMD_VMID(&cmd);
+int vmid = CMD_VMID(&cmd);
 
 if (!STAGE2_SUPPORTED(s)) {
 cmd_error = SMMU_CERROR_ILL;
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index cc12924a84..09ccd39548 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -11,13 +11,13 @@ smmu_ptw_page_pte(int stage, int level,  uint64_t iova, 
uint64_t baseaddr, uint6
 smmu_ptw_block_pte(int stage, int level, uint64_t baseaddr, uint64_t pteaddr, 
uint64_t pte, uint64_t iova, uint64_t gpa, int bsize_mb) "stage=%d level=%d 
base@=0x%"PRIx64" pte@=0x%"PRIx64" pte=0x%"PRIx64" iova=0x%"PRIx64" block 
address = 0x%"PRIx64" block size = %d MiB"
 smmu_get_pte(uint64_t baseaddr, int index, uint64_t pteaddr, uint64_t pte) 
"baseaddr=0x%"PRIx64" index=0x%x, pteaddr=0x%"PRIx64", pte=0x%"PRIx64
 smmu_iotlb_inv_all(void) "IOTLB invalidate all"
-smmu_iotlb_inv_asid(uint16_t asid) "IOTLB invalidate asid=%d"
-smmu_iotlb_inv_vmid(uint16_t vmid) "IOTLB invalidate vmid=%d"
-smmu_iotlb_inv_iova(uint16_t asid, uint64_t addr) "IOTLB invalidate asid=%d 
addr=0x%"PRIx64
+smmu_iotlb_inv_asid(int asid) "IOTLB invalidate asid=%d"
+smmu_iotlb_inv_vmid(int vmid) "IOTLB invalidate vmid=%d"
+smmu_iotlb_inv_iova(int asid, uint64_t addr) "IOTLB invalidate asid=%d 
addr=0x%"PRIx64
 smmu_inv_notifiers_mr(const char *name) "iommu mr=%s"
-smmu_iotlb_lookup_hit(uint16_t asid, uint16_t vmid, uint64_t addr, uint32_t 
hit, uint32_t miss, uint32_t p) "IOTLB cache HIT asid=%d vmid=%d 
addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
-smmu_iotlb_lookup_miss(uint16_t asid, uint16_t vmid, uint64_t addr, uint32_t 
hit, u

[RFC PATCH v3 12/18] hw/arm/smmu: Support nesting in the rest of commands

2024-04-28 Thread Mostafa Saleh
Some commands need rework for nesting, as they used to assume S1
and S2 are mutually exclusive:

- CMD_TLBI_NH_ASID: Consider VMID if stage-2 is supported
- CMD_TLBI_NH_ALL: Consider VMID if stage-2 is supported, otherwise
  invalidate everything, this required a new vmid invalidation
  function for stage-1 only (ASID >= 0)

Also, rework trace events to reflect the new implementation.

Signed-off-by: Mostafa Saleh 
---
 hw/arm/smmu-common.c | 36 +---
 hw/arm/smmuv3.c  | 31 +--
 hw/arm/trace-events  |  6 --
 include/hw/arm/smmu-common.h |  3 ++-
 4 files changed, 64 insertions(+), 12 deletions(-)

diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index fa2460cf64..3ed0be05ef 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -147,13 +147,14 @@ void smmu_iotlb_inv_all(SMMUState *s)
 g_hash_table_remove_all(s->iotlb);
 }
 
-static gboolean smmu_hash_remove_by_asid(gpointer key, gpointer value,
- gpointer user_data)
+static gboolean smmu_hash_remove_by_asid_vmid(gpointer key, gpointer value,
+  gpointer user_data)
 {
-int asid = *(int *)user_data;
+SMMUIOTLBPageInvInfo *info = (SMMUIOTLBPageInvInfo *)user_data;
 SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
 
-return SMMU_IOTLB_ASID(*iotlb_key) == asid;
+return (SMMU_IOTLB_ASID(*iotlb_key) == info->asid) &&
+   (SMMU_IOTLB_VMID(*iotlb_key) == info->vmid);
 }
 
 static gboolean smmu_hash_remove_by_vmid(gpointer key, gpointer value,
@@ -165,6 +166,16 @@ static gboolean smmu_hash_remove_by_vmid(gpointer key, 
gpointer value,
 return SMMU_IOTLB_VMID(*iotlb_key) == vmid;
 }
 
+static gboolean smmu_hash_remove_by_vmid_s1(gpointer key, gpointer value,
+gpointer user_data)
+{
+int vmid = *(int *)user_data;
+SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
+
+return (SMMU_IOTLB_VMID(*iotlb_key) == vmid) &&
+   (SMMU_IOTLB_ASID(*iotlb_key) >= 0);
+}
+
 static gboolean smmu_hash_remove_by_asid_vmid_iova(gpointer key, gpointer 
value,
   gpointer user_data)
 {
@@ -258,10 +269,15 @@ void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, 
dma_addr_t ipa, uint8_t tg,
 &info);
 }
 
-void smmu_iotlb_inv_asid(SMMUState *s, int asid)
+void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid)
 {
-trace_smmu_iotlb_inv_asid(asid);
-g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid, &asid);
+SMMUIOTLBPageInvInfo info = {
+.asid = asid,
+.vmid = vmid,
+};
+
+trace_smmu_iotlb_inv_asid_vmid(asid, vmid);
+g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid_vmid, 
&info);
 }
 
 void smmu_iotlb_inv_vmid(SMMUState *s, int vmid)
@@ -270,6 +286,12 @@ void smmu_iotlb_inv_vmid(SMMUState *s, int vmid)
 g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid, &vmid);
 }
 
+inline void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid)
+{
+trace_smmu_iotlb_inv_vmid_s1(vmid);
+g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid_s1, &vmid);
+}
+
 /* VMSAv8-64 Translation */
 
 /**
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 82d918d9b5..e0fd494646 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1303,25 +1303,52 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
 case SMMU_CMD_TLBI_NH_ASID:
 {
 int asid = CMD_ASID(&cmd);
+int vmid = -1;
 
 if (!STAGE1_SUPPORTED(s)) {
 cmd_error = SMMU_CERROR_ILL;
 break;
 }
 
+/*
+ * VMID is only matched when stage 2 is supported for the Security
+ * state corresponding to the command queue that the command was
+ * issued in.
+ * QEMU ignores the field by setting to -1, similarly to what STE
+ * decoding does. And invalidation commands ignore VMID < 0.
+ */
+if (STAGE2_SUPPORTED(s)) {
+vmid = CMD_VMID(&cmd);
+}
+
 trace_smmuv3_cmdq_tlbi_nh_asid(asid);
 smmu_inv_notifiers_all(&s->smmu_state);
-smmu_iotlb_inv_asid(bs, asid);
+smmu_iotlb_inv_asid_vmid(bs, asid, vmid);
 break;
 }
 case SMMU_CMD_TLBI_NH_ALL:
+{
+int vmid = -1;
+
 if (!STAGE1_SUPPORTED(s)) {
 cmd_error = SMMU_CERROR_ILL;
 break;
 }
+
+/*
+ * If stage-2 is supported, invalidate for this VMID only, 
otherwise
+ * invalidate the whole thing, see SMMU_CMD_TLBI_NH_ASID()
+ */
+if (STAGE2_SUPPORTED(s)) {
+vmid = CMD_VMID(&cmd);
+trace_smmuv3_cmdq_tlbi_nh(vmid);
+smmu_iotlb_in

[PULL 0/1] ufs queue

2024-04-28 Thread Jeuk Kim
From: Jeuk Kim 

The following changes since commit fd87be1dada5672f877e03c2ca8504458292c479:

  Merge tag 'accel-20240426' of https://github.com/philmd/qemu into staging 
(2024-04-26 15:28:13 -0700)

are available in the Git repository at:

  https://gitlab.com/jeuk20.kim/qemu.git tags/pull-ufs-20240429

for you to fetch changes up to f2c8aeb1afefcda92054c448b21fc59cdd99db30:

  hw/ufs: Fix buffer overflow bug (2024-04-29 12:13:35 +0900)


ufs queue

- Fix ufs sanitizer vulnerability


Jeuk Kim (1):
  hw/ufs: Fix buffer overflow bug

 hw/ufs/ufs.c | 8 
 1 file changed, 8 insertions(+)



[PULL 1/1] hw/ufs: Fix buffer overflow bug

2024-04-28 Thread Jeuk Kim
From: Jeuk Kim 

It fixes the buffer overflow vulnerability in the ufs device.
The bug was detected by sanitizers.

You can reproduce it by:

cat << EOF |\
qemu-system-x86_64 \
-display none -machine accel=qtest -m 512M -M q35 -nodefaults -drive \
file=null-co://,if=none,id=disk0 -device ufs,id=ufs_bus -device \
ufs-lu,drive=disk0,bus=ufs_bus -qtest stdio
outl 0xcf8 0x8810
outl 0xcfc 0xe000
outl 0xcf8 0x8804
outw 0xcfc 0x06
write 0xe058 0x1 0xa7
write 0xa 0x1 0x50
EOF

Resolves: #2299
Fixes: 329f16624499 ("hw/ufs: Support for Query Transfer Requests")
Reported-by: Zheyu Ma 
Signed-off-by: Jeuk Kim 
---
 hw/ufs/ufs.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
index eccdb852a0..bac78a32bb 100644
--- a/hw/ufs/ufs.c
+++ b/hw/ufs/ufs.c
@@ -126,6 +126,10 @@ static MemTxResult ufs_dma_read_req_upiu(UfsRequest *req)
 copy_size = sizeof(UtpUpiuHeader) + UFS_TRANSACTION_SPECIFIC_FIELD_SIZE +
 data_segment_length;
 
+if (copy_size > sizeof(req->req_upiu)) {
+copy_size = sizeof(req->req_upiu);
+}
+
 ret = ufs_addr_read(u, req_upiu_base_addr, &req->req_upiu, copy_size);
 if (ret) {
 trace_ufs_err_dma_read_req_upiu(req->slot, req_upiu_base_addr);
@@ -225,6 +229,10 @@ static MemTxResult ufs_dma_write_rsp_upiu(UfsRequest *req)
 copy_size = rsp_upiu_byte_len;
 }
 
+if (copy_size > sizeof(req->rsp_upiu)) {
+copy_size = sizeof(req->rsp_upiu);
+}
+
 ret = ufs_addr_write(u, rsp_upiu_base_addr, &req->rsp_upiu, copy_size);
 if (ret) {
 trace_ufs_err_dma_write_rsp_upiu(req->slot, rsp_upiu_base_addr);
-- 
2.34.1




[RFC PATCH v3 16/18] hw/arm/smmu: Refactor SMMU OAS

2024-04-28 Thread Mostafa Saleh
SMMUv3 OAS is hardcoded to 44 bits, for nested configurations that
can be a problem as stage-2 might be shared with the CPU which might
have different PARANGE, and according to SMMU manual ARM IHI 0070F.b:
6.3.6 SMMU_IDR5, OAS must match the system physical address size.

This patch doesn't change the SMMU OAS, but refactors the code to
make it easier to do that:
- Rely everywhere on IDR5 for reading OAS instead of using the macro so
  it is easier just change IDR5 and it propagages correctly.
- Remove unused functions/macros: pa_range/MAX_PA

Signed-off-by: Mostafa Saleh 
---
 hw/arm/smmu-common.c |  7 ---
 hw/arm/smmuv3-internal.h | 13 -
 hw/arm/smmuv3.c  | 35 ---
 3 files changed, 32 insertions(+), 23 deletions(-)

diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 3ed0be05ef..b559878aef 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -434,7 +434,8 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
 inputsize = 64 - tt->tsz;
 level = 4 - (inputsize - 4) / stride;
 indexmask = VMSA_IDXMSK(inputsize, stride, level);
-baseaddr = extract64(tt->ttb, 0, 48);
+
+baseaddr = extract64(tt->ttb, 0, cfg->oas);
 baseaddr &= ~indexmask;
 
 while (level < VMSA_LEVELS) {
@@ -557,8 +558,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
  * Get the ttb from concatenated structure.
  * The offset is the idx * size of each ttb(number of ptes * (sizeof(pte))
  */
-uint64_t baseaddr = extract64(cfg->s2cfg.vttb, 0, 48) + (1 << stride) *
-  idx * sizeof(uint64_t);
+uint64_t baseaddr = extract64(cfg->s2cfg.vttb, 0, cfg->s2cfg.eff_ps) +
+  (1 << stride) * idx * sizeof(uint64_t);
 dma_addr_t indexmask = VMSA_IDXMSK(inputsize, stride, level);
 
 baseaddr &= ~indexmask;
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index 0f3ecec804..0ebf2eebcf 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -602,19 +602,6 @@ static inline int oas2bits(int oas_field)
 return -1;
 }
 
-static inline int pa_range(STE *ste)
-{
-int oas_field = MIN(STE_S2PS(ste), SMMU_IDR5_OAS);
-
-if (!STE_S2AA64(ste)) {
-return 40;
-}
-
-return oas2bits(oas_field);
-}
-
-#define MAX_PA(ste) ((1 << pa_range(ste)) - 1)
-
 /* CD fields */
 
 #define CD_VALID(x)   extract32((x)->word[0], 31, 1)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 8a11e41144..4ac818cf7a 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -408,10 +408,10 @@ static bool s2t0sz_valid(SMMUTransCfg *cfg)
 }
 
 if (cfg->s2cfg.granule_sz == 16) {
-return (cfg->s2cfg.tsz >= 64 - oas2bits(SMMU_IDR5_OAS));
+return (cfg->s2cfg.tsz >= 64 - cfg->s2cfg.eff_ps);
 }
 
-return (cfg->s2cfg.tsz >= MAX(64 - oas2bits(SMMU_IDR5_OAS), 16));
+return (cfg->s2cfg.tsz >= MAX(64 - cfg->s2cfg.eff_ps, 16));
 }
 
 /*
@@ -432,8 +432,11 @@ static bool s2_pgtable_config_valid(uint8_t sl0, uint8_t 
t0sz, uint8_t gran)
 return nr_concat <= VMSA_MAX_S2_CONCAT;
 }
 
-static int decode_ste_s2_cfg(SMMUTransCfg *cfg, STE *ste)
+static int decode_ste_s2_cfg(SMMUv3State *s, SMMUTransCfg *cfg,
+ STE *ste)
 {
+uint8_t oas = FIELD_EX32(s->idr[5], IDR5, OAS);
+
 if (STE_S2AA64(ste) == 0x0) {
 qemu_log_mask(LOG_UNIMP,
   "SMMUv3 AArch32 tables not supported\n");
@@ -466,7 +469,15 @@ static int decode_ste_s2_cfg(SMMUTransCfg *cfg, STE *ste)
 }
 
 /* For AA64, The effective S2PS size is capped to the OAS. */
-cfg->s2cfg.eff_ps = oas2bits(MIN(STE_S2PS(ste), SMMU_IDR5_OAS));
+cfg->s2cfg.eff_ps = oas2bits(MIN(STE_S2PS(ste), oas));
+/*
+ * For SMMUv3.1 and later, when OAS == IAS == 52, the stage 2 input
+ * range is further limited to 48 bits unless STE.S2TG indicates a
+ * 64KB granule.
+ */
+if (cfg->s2cfg.granule_sz != 16) {
+cfg->s2cfg.eff_ps = MIN(cfg->s2cfg.eff_ps, 48);
+}
 /*
  * It is ILLEGAL for the address in S2TTB to be outside the range
  * described by the effective S2PS value.
@@ -542,6 +553,7 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
   STE *ste, SMMUEventInfo *event)
 {
 uint32_t config;
+uint8_t oas = FIELD_EX32(s->idr[5], IDR5, OAS);
 int ret;
 
 if (!STE_VALID(ste)) {
@@ -585,8 +597,8 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
  * Stage-1 OAS defaults to OAS even if not enabled as it would be used
  * in input address check for stage-2.
  */
-cfg->oas = oas2bits(SMMU_IDR5_OAS);
-ret = decode_ste_s2_cfg(cfg, ste);
+cfg->oas = oas2bits(oas);
+ret = decode_ste_s2_cfg(s, cfg, ste);
 if (ret) {
 goto bad_ste;
 }
@@ -712,6 +724,7 @@ static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
 int i;
 SMMUTranslationStatus status;
  

[RFC PATCH v3 17/18] hw/arm/smmuv3: Add property for OAS

2024-04-28 Thread Mostafa Saleh
Add property that sets the OAS of the SMMU, this in not used in this
patch.

Signed-off-by: Mostafa Saleh 
---
 hw/arm/smmuv3-internal.h |  3 ++-
 hw/arm/smmuv3.c  | 29 -
 include/hw/arm/smmuv3.h  |  1 +
 3 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index 0ebf2eebcf..dd91807624 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -111,7 +111,8 @@ REG32(IDR5,0x14)
  FIELD(IDR5, VAX,10, 2);
  FIELD(IDR5, STALL_MAX,  16, 16);
 
-#define SMMU_IDR5_OAS 4
+#define SMMU_IDR5_OAS_DEF 4 /* 44 bits. */
+#define SMMU_IDR5_OAS_MAX 5 /* 48 bits. */
 
 REG32(IIDR,0x18)
 REG32(AIDR,0x1c)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 4ac818cf7a..39d03e7e24 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -299,7 +299,9 @@ static void smmuv3_init_regs(SMMUv3State *s)
 s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1);
 s->idr[3] = FIELD_DP32(s->idr[3], IDR3, BBML, 2);
 
-s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS); /* 44 bits */
+/* PTW doesn't support 52 bits. */
+s->oas = MIN(s->oas, SMMU_IDR5_OAS_MAX);
+s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, s->oas);
 /* 4K, 16K and 64K granule support */
 s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN4K, 1);
 s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN16K, 1);
@@ -1901,11 +1903,34 @@ static const VMStateDescription vmstate_gbpa = {
 }
 };
 
+static const VMStateDescription vmstate_oas = {
+.name = "smmuv3/oas",
+.version_id = 1,
+.minimum_version_id = 1,
+.fields = (const VMStateField[]) {
+VMSTATE_INT32(oas, SMMUv3State),
+VMSTATE_END_OF_LIST()
+}
+};
+
+static int smmuv3_preload(void *opaque)
+{
+SMMUv3State *s = opaque;
+
+/*
+ * In case it wasn't migrated, use the value used
+ * by older QEMU.
+ */
+s->oas = SMMU_IDR5_OAS_DEF;
+return 0;
+}
+
 static const VMStateDescription vmstate_smmuv3 = {
 .name = "smmuv3",
 .version_id = 1,
 .minimum_version_id = 1,
 .priority = MIG_PRI_IOMMU,
+.pre_load = smmuv3_preload,
 .fields = (const VMStateField[]) {
 VMSTATE_UINT32(features, SMMUv3State),
 VMSTATE_UINT8(sid_size, SMMUv3State),
@@ -1933,6 +1958,7 @@ static const VMStateDescription vmstate_smmuv3 = {
 },
 .subsections = (const VMStateDescription * const []) {
 &vmstate_gbpa,
+&vmstate_oas,
 NULL
 }
 };
@@ -1945,6 +1971,7 @@ static Property smmuv3_properties[] = {
  * Defaults to stage 1
  */
 DEFINE_PROP_STRING("stage", SMMUv3State, stage),
+DEFINE_PROP_INT32("oas", SMMUv3State, oas, SMMU_IDR5_OAS_DEF),
 DEFINE_PROP_END_OF_LIST()
 };
 
diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h
index d183a62766..00a9eb4467 100644
--- a/include/hw/arm/smmuv3.h
+++ b/include/hw/arm/smmuv3.h
@@ -63,6 +63,7 @@ struct SMMUv3State {
 qemu_irq irq[4];
 QemuMutex mutex;
 char *stage;
+int32_t oas;
 };
 
 typedef enum {
-- 
2.44.0.769.g3c40516874-goog




[RFC PATCH v3 04/18] hw/arm/smmu: Use enum for SMMU stage

2024-04-28 Thread Mostafa Saleh
Currently, translation stage is represented as an int, where 1 is stage-1 and
2 is stage-2, when nested is added, 3 would be confusing to represent nesting,
so we use an enum instead.

While keeping the same values, this is useful for:
 - Doing tricks with bit masks, where BIT(0) is stage-1 and BIT(1) is
   stage-2 and both is nested.
 - Tracing, as stage is printed as int.

Signed-off-by: Mostafa Saleh 
Reviewed-by: Eric Auger 
---
 hw/arm/smmu-common.c | 14 +++---
 hw/arm/smmuv3.c  | 15 ---
 include/hw/arm/smmu-common.h | 11 +--
 3 files changed, 24 insertions(+), 16 deletions(-)

diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 8a8c718e6b..8a5858f69f 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -304,7 +304,7 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
   SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
 {
 dma_addr_t baseaddr, indexmask;
-int stage = cfg->stage;
+SMMUStage stage = cfg->stage;
 SMMUTransTableInfo *tt = select_tt(cfg, iova);
 uint8_t level, granule_sz, inputsize, stride;
 
@@ -402,7 +402,7 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
 info->type = SMMU_PTW_ERR_TRANSLATION;
 
 error:
-info->stage = 1;
+info->stage = SMMU_STAGE_1;
 tlbe->entry.perm = IOMMU_NONE;
 return -EINVAL;
 }
@@ -425,7 +425,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
   dma_addr_t ipa, IOMMUAccessFlags perm,
   SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
 {
-const int stage = 2;
+const SMMUStage stage = SMMU_STAGE_2;
 int granule_sz = cfg->s2cfg.granule_sz;
 /* ARM DDI0487I.a: Table D8-7. */
 int inputsize = 64 - cfg->s2cfg.tsz;
@@ -525,7 +525,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
 error_ipa:
 info->addr = ipa;
 error:
-info->stage = 2;
+info->stage = SMMU_STAGE_2;
 tlbe->entry.perm = IOMMU_NONE;
 return -EINVAL;
 }
@@ -544,9 +544,9 @@ error:
 int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
  SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
 {
-if (cfg->stage == 1) {
+if (cfg->stage == SMMU_STAGE_1) {
 return smmu_ptw_64_s1(cfg, iova, perm, tlbe, info);
-} else if (cfg->stage == 2) {
+} else if (cfg->stage == SMMU_STAGE_2) {
 /*
  * If bypassing stage 1(or unimplemented), the input address is passed
  * directly to stage 2 as IPA. If the input address of a transaction
@@ -555,7 +555,7 @@ int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, 
IOMMUAccessFlags perm,
  */
 if (iova >= (1ULL << cfg->oas)) {
 info->type = SMMU_PTW_ERR_ADDR_SIZE;
-info->stage = 1;
+info->stage = SMMU_STAGE_1;
 tlbe->entry.perm = IOMMU_NONE;
 return -EINVAL;
 }
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 1eb5b160d2..dab3ad2db9 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -34,7 +34,8 @@
 #include "smmuv3-internal.h"
 #include "smmu-internal.h"
 
-#define PTW_RECORD_FAULT(cfg)   (((cfg)->stage == 1) ? (cfg)->record_faults : \
+#define PTW_RECORD_FAULT(cfg)   (((cfg)->stage == SMMU_STAGE_1) ? \
+ (cfg)->record_faults : \
  (cfg)->s2cfg.record_faults)
 
 /**
@@ -402,7 +403,7 @@ static bool s2_pgtable_config_valid(uint8_t sl0, uint8_t 
t0sz, uint8_t gran)
 
 static int decode_ste_s2_cfg(SMMUTransCfg *cfg, STE *ste)
 {
-cfg->stage = 2;
+cfg->stage = SMMU_STAGE_2;
 
 if (STE_S2AA64(ste) == 0x0) {
 qemu_log_mask(LOG_UNIMP,
@@ -678,7 +679,7 @@ static int decode_cd(SMMUTransCfg *cfg, CD *cd, 
SMMUEventInfo *event)
 
 /* we support only those at the moment */
 cfg->aa64 = true;
-cfg->stage = 1;
+cfg->stage = SMMU_STAGE_1;
 
 cfg->oas = oas2bits(CD_IPS(cd));
 cfg->oas = MIN(oas2bits(SMMU_IDR5_OAS), cfg->oas);
@@ -762,7 +763,7 @@ static int smmuv3_decode_config(IOMMUMemoryRegion *mr, 
SMMUTransCfg *cfg,
 return ret;
 }
 
-if (cfg->aborted || cfg->bypassed || (cfg->stage == 2)) {
+if (cfg->aborted || cfg->bypassed || (cfg->stage == SMMU_STAGE_2)) {
 return 0;
 }
 
@@ -882,7 +883,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion 
*mr, hwaddr addr,
 goto epilogue;
 }
 
-if (cfg->stage == 1) {
+if (cfg->stage == SMMU_STAGE_1) {
 /* Select stage1 translation table. */
 tt = select_tt(cfg, addr);
 if (!tt) {
@@ -919,7 +920,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion 
*mr, hwaddr addr,
  * nesting is not supported. So it is sufficient to check the
  * translation stage to know the TLB stage for now.
  */
-event.u.f_walk_eabt.s2 = (cfg->stage == 2);
+event.u.f_walk_eabt.s2 = (cfg->stage == SMMU_STAGE_2);
 if (PTW_RECORD_FAULT(cfg)) {
 event.type =

[RFC PATCH v3 14/18] hw/arm/smmuv3: Support and advertise nesting

2024-04-28 Thread Mostafa Saleh
Everything is in place, add the last missing bits:
- Handle fault checking according to the actual PTW event and not the
  the translation stage.
- Consolidate parsing of STE cfg and setting translation stage.

Advertise nesting if stage requested is "nested".

Signed-off-by: Mostafa Saleh 
---
 hw/arm/smmuv3.c | 50 +
 1 file changed, 34 insertions(+), 16 deletions(-)

diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 96d07234fe..88f6473d33 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -34,9 +34,10 @@
 #include "smmuv3-internal.h"
 #include "smmu-internal.h"
 
-#define PTW_RECORD_FAULT(cfg)   (((cfg)->stage == SMMU_STAGE_1) ? \
- (cfg)->record_faults : \
- (cfg)->s2cfg.record_faults)
+#define PTW_RECORD_FAULT(ptw_info, cfg) (((ptw_info).stage == SMMU_STAGE_1 && \
+(cfg)->record_faults) || \
+((ptw_info).stage == SMMU_STAGE_2 && \
+(cfg)->s2cfg.record_faults))
 
 /**
  * smmuv3_trigger_irq - pulse @irq if enabled and update
@@ -260,6 +261,9 @@ static void smmuv3_init_regs(SMMUv3State *s)
 /* Based on sys property, the stages supported in smmu will be 
advertised.*/
 if (s->stage && !strcmp("2", s->stage)) {
 s->idr[0] = FIELD_DP32(s->idr[0], IDR0, S2P, 1);
+} else if (s->stage && !strcmp("nested", s->stage)) {
+s->idr[0] = FIELD_DP32(s->idr[0], IDR0, S1P, 1);
+s->idr[0] = FIELD_DP32(s->idr[0], IDR0, S2P, 1);
 } else {
 s->idr[0] = FIELD_DP32(s->idr[0], IDR0, S1P, 1);
 }
@@ -422,8 +426,6 @@ static bool s2_pgtable_config_valid(uint8_t sl0, uint8_t 
t0sz, uint8_t gran)
 
 static int decode_ste_s2_cfg(SMMUTransCfg *cfg, STE *ste)
 {
-cfg->stage = SMMU_STAGE_2;
-
 if (STE_S2AA64(ste) == 0x0) {
 qemu_log_mask(LOG_UNIMP,
   "SMMUv3 AArch32 tables not supported\n");
@@ -506,6 +508,27 @@ bad_ste:
 return -EINVAL;
 }
 
+static void decode_ste_config(SMMUTransCfg *cfg, uint32_t config)
+{
+
+if (STE_CFG_ABORT(config)) {
+cfg->aborted = true;
+return;
+}
+if (STE_CFG_BYPASS(config)) {
+cfg->bypassed = true;
+return;
+}
+
+if (STE_CFG_S1_ENABLED(config)) {
+cfg->stage = SMMU_STAGE_1;
+}
+
+if (STE_CFG_S2_ENABLED(config)) {
+cfg->stage |= SMMU_STAGE_2;
+}
+}
+
 /* Returns < 0 in case of invalid STE, 0 otherwise */
 static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
   STE *ste, SMMUEventInfo *event)
@@ -522,13 +545,9 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
 
 config = STE_CONFIG(ste);
 
-if (STE_CFG_ABORT(config)) {
-cfg->aborted = true;
-return 0;
-}
+decode_ste_config(cfg, config);
 
-if (STE_CFG_BYPASS(config)) {
-cfg->bypassed = true;
+if (cfg->aborted || cfg->bypassed) {
 return 0;
 }
 
@@ -701,7 +720,6 @@ static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
 
 /* we support only those at the moment */
 cfg->aa64 = true;
-cfg->stage = SMMU_STAGE_1;
 
 cfg->oas = oas2bits(CD_IPS(cd));
 cfg->oas = MIN(oas2bits(SMMU_IDR5_OAS), cfg->oas);
@@ -901,7 +919,7 @@ static SMMUTranslationStatus 
smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
 event->u.f_walk_eabt.addr2 = ptw_info.addr;
 break;
 case SMMU_PTW_ERR_TRANSLATION:
-if (PTW_RECORD_FAULT(cfg)) {
+if (PTW_RECORD_FAULT(ptw_info, cfg)) {
 event->type = SMMU_EVT_F_TRANSLATION;
 event->u.f_translation.addr = addr;
 event->u.f_translation.addr2 = ptw_info.addr;
@@ -910,7 +928,7 @@ static SMMUTranslationStatus 
smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
 }
 break;
 case SMMU_PTW_ERR_ADDR_SIZE:
-if (PTW_RECORD_FAULT(cfg)) {
+if (PTW_RECORD_FAULT(ptw_info, cfg)) {
 event->type = SMMU_EVT_F_ADDR_SIZE;
 event->u.f_addr_size.addr = addr;
 event->u.f_addr_size.addr2 = ptw_info.addr;
@@ -919,7 +937,7 @@ static SMMUTranslationStatus 
smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
 }
 break;
 case SMMU_PTW_ERR_ACCESS:
-if (PTW_RECORD_FAULT(cfg)) {
+if (PTW_RECORD_FAULT(ptw_info, cfg)) {
 event->type = SMMU_EVT_F_ACCESS;
 event->u.f_access.addr = addr;
 event->u.f_access.addr2 = ptw_info.addr;
@@ -928,7 +946,7 @@ static SMMUTranslationStatus 
smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
 }
 break;
 case SMMU_PTW_ERR_PERMISSION:
-if (PTW_RECORD_FAULT(cfg)) {
+if (PTW_RECORD_FAULT(ptw_info, cfg)) {
 event->type = SMMU_EVT_F_PERMISSION;
 event->u.f_

[RFC PATCH v3 11/18] hw/arm/smmu: Support nesting in smmuv3_range_inval()

2024-04-28 Thread Mostafa Saleh
With nesting, we would need to invalidate IPAs without
over-invalidating stage-1 IOVAs. This can be done by
distinguishing IPAs in the TLBs by having ASID=-1.
To achieve that, rework the invalidation for IPAs to have a
separate function, while for IOVA invalidation ASID=-1 means
invalidate for all ASIDs.

Signed-off-by: Mostafa Saleh 
Reviewed-by: Eric Auger 
---
 hw/arm/smmu-common.c | 47 
 hw/arm/smmuv3.c  | 23 --
 hw/arm/trace-events  |  2 +-
 include/hw/arm/smmu-common.h |  3 ++-
 4 files changed, 66 insertions(+), 9 deletions(-)

diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index d48ec08947..fa2460cf64 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -183,6 +183,25 @@ static gboolean 
smmu_hash_remove_by_asid_vmid_iova(gpointer key, gpointer value,
((entry->iova & ~info->mask) == info->iova);
 }
 
+static gboolean smmu_hash_remove_by_vmid_ipa(gpointer key, gpointer value,
+ gpointer user_data)
+{
+SMMUTLBEntry *iter = (SMMUTLBEntry *)value;
+IOMMUTLBEntry *entry = &iter->entry;
+SMMUIOTLBPageInvInfo *info = (SMMUIOTLBPageInvInfo *)user_data;
+SMMUIOTLBKey iotlb_key = *(SMMUIOTLBKey *)key;
+
+if (info->asid >= 0) {
+/* This is a stage-1 address. */
+return false;
+}
+if (info->vmid != SMMU_IOTLB_VMID(iotlb_key)) {
+return false;
+}
+return ((info->iova & ~entry->addr_mask) == entry->iova) ||
+   ((entry->iova & ~info->mask) == info->iova);
+}
+
 void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
  uint8_t tg, uint64_t num_pages, uint8_t ttl)
 {
@@ -211,6 +230,34 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, 
dma_addr_t iova,
 &info);
 }
 
+/*
+ * Similar to smmu_iotlb_inv_iova(), but for Stage-2, ASID is always -1,
+ * in Stage-1 invalidation ASID = -1, means don't care.
+ */
+void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
+uint64_t num_pages, uint8_t ttl)
+{
+uint8_t granule = tg ? tg * 2 + 10 : 12;
+int asid = -1;
+
+   if (ttl && (num_pages == 1)) {
+SMMUIOTLBKey key = smmu_get_iotlb_key(asid, vmid, ipa, tg, ttl);
+
+if (g_hash_table_remove(s->iotlb, &key)) {
+return;
+}
+}
+
+SMMUIOTLBPageInvInfo info = {
+.iova = ipa,
+.vmid = vmid,
+.mask = (num_pages * 1 << granule) - 1};
+
+g_hash_table_foreach_remove(s->iotlb,
+smmu_hash_remove_by_vmid_ipa,
+&info);
+}
+
 void smmu_iotlb_inv_asid(SMMUState *s, int asid)
 {
 trace_smmu_iotlb_inv_asid(asid);
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index cc61c82321..82d918d9b5 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1118,7 +1118,7 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int 
asid, int vmid,
 }
 }
 
-static void smmuv3_range_inval(SMMUState *s, Cmd *cmd)
+static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage)
 {
 dma_addr_t end, addr = CMD_ADDR(cmd);
 uint8_t type = CMD_TYPE(cmd);
@@ -1143,9 +1143,13 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd)
 }
 
 if (!tg) {
-trace_smmuv3_range_inval(vmid, asid, addr, tg, 1, ttl, leaf);
+trace_smmuv3_range_inval(vmid, asid, addr, tg, 1, ttl, leaf, stage);
 smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1);
-smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl);
+if (stage == SMMU_STAGE_1) {
+smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl);
+} else {
+smmu_iotlb_inv_ipa(s, vmid, addr, tg, 1, ttl);
+}
 return;
 }
 
@@ -1161,9 +1165,14 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd)
 uint64_t mask = dma_aligned_pow2_mask(addr, end, 64);
 
 num_pages = (mask + 1) >> granule;
-trace_smmuv3_range_inval(vmid, asid, addr, tg, num_pages, ttl, leaf);
+trace_smmuv3_range_inval(vmid, asid, addr, tg, num_pages,
+ ttl, leaf, stage);
 smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, num_pages);
-smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, num_pages, ttl);
+if (stage == SMMU_STAGE_1) {
+smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, num_pages, ttl);
+} else {
+smmu_iotlb_inv_ipa(s, vmid, addr, tg, num_pages, ttl);
+}
 addr += mask + 1;
 }
 }
@@ -1322,7 +1331,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
 cmd_error = SMMU_CERROR_ILL;
 break;
 }
-smmuv3_range_inval(bs, &cmd);
+smmuv3_range_inval(bs, &cmd, SMMU_STAGE_1);
 break;
 case SMMU_CMD_TLBI_S12_VMALL:
 {
@@ -1347,7 +1356,7 @@ static int s

[RFC PATCH v3 10/18] hw/arm/smmu-common: Support nested translation

2024-04-28 Thread Mostafa Saleh
When nested translation is requested, do the following:

- Translate stage-1 IPA using stage-2 to a physical address.
- Translate stage-1 table walks using stage-2.
- Combine both to create a single TLB entry using the logic
  introduced before.

For stage-1 table translation, the spec (ARM IHI 0070 F.b) says in:
7.3.12 F_WALK_EABT:
Translation of an IPA for Stage 1 descriptor fetch:
S2 == 1 (stage 2), CLASS == T
So, F_WALK_EABT is used which propagtes to CLASS == TT.

smmu_ptw() has a new argument SMMUState which include the TLB as
stage-1 table address can be cached in there.

Also in smmu_ptw() a separate path used for nesting to simplify the
code, although some logic can be combined.

Signed-off-by: Mostafa Saleh 
---
 hw/arm/smmu-common.c | 67 ++--
 include/hw/arm/smmu-common.h |  2 +-
 2 files changed, 58 insertions(+), 11 deletions(-)

diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index c67af3bc6d..d48ec08947 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -306,6 +306,32 @@ SMMUTransTableInfo *select_tt(SMMUTransCfg *cfg, 
dma_addr_t iova)
 return NULL;
 }
 
+/* Translate stage-1 table address using stage-2 page table. */
+static inline int translate_table_s1(dma_addr_t *table_addr, SMMUTransCfg *cfg,
+ SMMUPTWEventInfo *info, SMMUState *bs)
+{
+dma_addr_t addr = *table_addr;
+SMMUTLBEntry *cached_entry;
+int asid;
+
+asid = cfg->asid;
+cfg->stage = SMMU_STAGE_2;
+cfg->asid = -1;
+cached_entry = smmu_translate(bs, cfg, addr, IOMMU_RO, info);
+cfg->asid = asid;
+cfg->stage = SMMU_NESTED;
+
+if (cached_entry) {
+*table_addr = CACHED_ENTRY_TO_ADDR(cached_entry, addr);
+return 0;
+}
+
+info->stage = SMMU_STAGE_2;
+info->type = SMMU_PTW_ERR_WALK_EABT;
+info->addr = addr;
+return -EINVAL;
+}
+
 /**
  * smmu_ptw_64_s1 - VMSAv8-64 Walk of the page tables for a given IOVA
  * @cfg: translation config
@@ -321,7 +347,8 @@ SMMUTransTableInfo *select_tt(SMMUTransCfg *cfg, dma_addr_t 
iova)
  */
 static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
   dma_addr_t iova, IOMMUAccessFlags perm,
-  SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
+  SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info,
+  SMMUState *bs)
 {
 dma_addr_t baseaddr, indexmask;
 SMMUStage stage = cfg->stage;
@@ -369,6 +396,11 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
 goto error;
 }
 baseaddr = get_table_pte_address(pte, granule_sz);
+if (cfg->stage == SMMU_NESTED) {
+if (translate_table_s1(&baseaddr, cfg, info, bs)) {
+goto error;
+}
+}
 level++;
 continue;
 } else if (is_page_pte(pte, level)) {
@@ -551,10 +583,8 @@ error:
 }
 
 /* combine 2 TLB entries and return in tlbe in nested config. */
-static void __attribute__((unused)) combine_tlb(SMMUTLBEntry *tlbe,
-SMMUTLBEntry *tlbe_s2,
-dma_addr_t iova,
-SMMUTransCfg *cfg)
+static void combine_tlb(SMMUTLBEntry *tlbe, SMMUTLBEntry *tlbe_s2,
+dma_addr_t iova, SMMUTransCfg *cfg)
 {
 if (tlbe_s2->entry.addr_mask < tlbe->entry.addr_mask) {
 tlbe->entry.addr_mask = tlbe_s2->entry.addr_mask;
@@ -579,14 +609,19 @@ static void __attribute__((unused)) 
combine_tlb(SMMUTLBEntry *tlbe,
  * @perm: tentative access type
  * @tlbe: returned entry
  * @info: ptw event handle
+ * @bs: smmu state which includes TLB instance
  *
  * return 0 on success
  */
 int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
- SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
+ SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info, SMMUState *bs)
 {
+int ret;
+SMMUTLBEntry tlbe_s2;
+dma_addr_t ipa;
+
 if (cfg->stage == SMMU_STAGE_1) {
-return smmu_ptw_64_s1(cfg, iova, perm, tlbe, info);
+return smmu_ptw_64_s1(cfg, iova, perm, tlbe, info, bs);
 } else if (cfg->stage == SMMU_STAGE_2) {
 /*
  * If bypassing stage 1(or unimplemented), the input address is passed
@@ -600,11 +635,23 @@ int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, 
IOMMUAccessFlags perm,
 tlbe->entry.perm = IOMMU_NONE;
 return -EINVAL;
 }
-
 return smmu_ptw_64_s2(cfg, iova, perm, tlbe, info);
 }
 
-g_assert_not_reached();
+/* SMMU_NESTED. */
+ret = smmu_ptw_64_s1(cfg, iova, perm, tlbe, info, bs);
+if (ret) {
+return ret;
+}
+
+ipa = CACHED_ENTRY_TO_ADDR(tlbe, iova);
+ret = smmu_ptw_64_s2(cfg, ipa, perm, &tlbe_s2, info);
+if (ret) {
+return ret;
+}
+
+combine_tlb(tlbe, &tlbe_s2, io

[RFC PATCH v3 13/18] hw/arm/smmuv3: Support nested SMMUs in smmuv3_notify_iova()

2024-04-28 Thread Mostafa Saleh
IOMMUTLBEvent only understands IOVA, for stage-2 only SMMUs keep
the implementation, while only notify for stage-1 invalidation
in case of nesting.

Signed-off-by: Mostafa Saleh 
---
 hw/arm/smmuv3.c | 23 +++
 hw/arm/trace-events |  2 +-
 2 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index e0fd494646..96d07234fe 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1051,7 +1051,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
IOMMUNotifier *n,
int asid, int vmid,
dma_addr_t iova, uint8_t tg,
-   uint64_t num_pages)
+   uint64_t num_pages, int stage)
 {
 SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
 IOMMUTLBEvent event;
@@ -1075,14 +1075,21 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
 return;
 }
 
-if (STAGE1_SUPPORTED(s)) {
+/*
+ * IOMMUTLBEvent only understands IOVA, for stage-2 only SMMUs
+ * keep the implementation, while only notify for stage-1
+ * invalidation in case of nesting.
+ */
+if (stage == SMMU_STAGE_1) {
 tt = select_tt(cfg, iova);
 if (!tt) {
 return;
 }
 granule = tt->granule_sz;
-} else {
+} else if (!STAGE1_SUPPORTED(s)) {
 granule = cfg->s2cfg.granule_sz;
+} else {
+return;
 }
 
 } else {
@@ -1101,7 +1108,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
 /* invalidate an asid/vmid/iova range tuple in all mr's */
 static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
   dma_addr_t iova, uint8_t tg,
-  uint64_t num_pages)
+  uint64_t num_pages, int stage)
 {
 SMMUDevice *sdev;
 
@@ -1110,10 +1117,10 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int 
asid, int vmid,
 IOMMUNotifier *n;
 
 trace_smmuv3_inv_notifiers_iova(mr->parent_obj.name, asid, vmid,
-iova, tg, num_pages);
+iova, tg, num_pages, stage);
 
 IOMMU_NOTIFIER_FOREACH(n, mr) {
-smmuv3_notify_iova(mr, n, asid, vmid, iova, tg, num_pages);
+smmuv3_notify_iova(mr, n, asid, vmid, iova, tg, num_pages, stage);
 }
 }
 }
@@ -1144,7 +1151,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, 
SMMUStage stage)
 
 if (!tg) {
 trace_smmuv3_range_inval(vmid, asid, addr, tg, 1, ttl, leaf, stage);
-smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1);
+smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1, stage);
 if (stage == SMMU_STAGE_1) {
 smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl);
 } else {
@@ -1167,7 +1174,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, 
SMMUStage stage)
 num_pages = (mask + 1) >> granule;
 trace_smmuv3_range_inval(vmid, asid, addr, tg, num_pages,
  ttl, leaf, stage);
-smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, num_pages);
+smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, num_pages, stage);
 if (stage == SMMU_STAGE_1) {
 smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, num_pages, ttl);
 } else {
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index 593cc571da..be6c8f720b 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -55,7 +55,7 @@ smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
 smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
 smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu 
mr=%s"
 smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu 
mr=%s"
-smmuv3_inv_notifiers_iova(const char *name, int asid, int vmid, uint64_t iova, 
uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" 
tg=%d num_pages=0x%"PRIx64
+smmuv3_inv_notifiers_iova(const char *name, int asid, int vmid, uint64_t iova, 
uint8_t tg, uint64_t num_pages, int stage) "iommu mr=%s asid=%d vmid=%d 
iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" stage=%d"
 
 # strongarm.c
 strongarm_uart_update_parameters(const char *label, int speed, char parity, 
int data_bits, int stop_bits) "%s speed=%d parity=%c data=%d stop=%d"
-- 
2.44.0.769.g3c40516874-goog




[RFC PATCH v3 09/18] hw/arm/smmu-common: Rework TLB lookup for nesting

2024-04-28 Thread Mostafa Saleh
In the previous patch, comine_tlb() was added which combines 2 TLB
entries into one, which chooses the granule and level from the
smallest entry.

This means that a nested translation, an entry can be cached with the
granule of stage-2 and not stage-1.

However, the lookup for an IOVA in nested configuration is done with
stage-1 granule, this patch reworks lookup in that case, so it falls
back to stage-2 granule if no entry is found using stage-1 granule.

Signed-off-by: Mostafa Saleh 
---
 hw/arm/smmu-common.c | 24 ++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 0d6945fa54..c67af3bc6d 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -66,8 +66,10 @@ SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t 
iova,
 return key;
 }
 
-SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
-SMMUTransTableInfo *tt, hwaddr iova)
+static SMMUTLBEntry *smmu_iotlb_lookup_all_levels(SMMUState *bs,
+  SMMUTransCfg *cfg,
+  SMMUTransTableInfo *tt,
+  hwaddr iova)
 {
 uint8_t tg = (tt->granule_sz - 10) / 2;
 uint8_t inputsize = 64 - tt->tsz;
@@ -88,6 +90,24 @@ SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg 
*cfg,
 }
 level++;
 }
+return entry;
+}
+
+SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
+SMMUTransTableInfo *tt, hwaddr iova)
+{
+SMMUTLBEntry *entry = NULL;
+
+entry = smmu_iotlb_lookup_all_levels(bs, cfg, tt, iova);
+/*
+ * For nested translation also try the s2 granule, as the TLB will insert
+ * it if the size of s2 tlb entry was smaller.
+ */
+if (!entry && (cfg->stage == SMMU_NESTED) &&
+(cfg->s2cfg.granule_sz != tt->granule_sz)) {
+tt->granule_sz = cfg->s2cfg.granule_sz;
+entry = smmu_iotlb_lookup_all_levels(bs, cfg, tt, iova);
+}
 
 if (entry) {
 cfg->iotlb_hits++;
-- 
2.44.0.769.g3c40516874-goog




[RFC PATCH v3 15/18] hw/arm/smmuv3: Advertise S2FWB

2024-04-28 Thread Mostafa Saleh
QEMU doesn's support memory attributes, so FWB is NOP, this
might change in the future if memory attributre would be supported.

Signed-off-by: Mostafa Saleh 
---
 hw/arm/smmuv3.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 88f6473d33..8a11e41144 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -287,6 +287,14 @@ static void smmuv3_init_regs(SMMUv3State *s)
 if (FIELD_EX32(s->idr[0], IDR0, S2P)) {
 /* XNX is a stage-2-specific feature */
 s->idr[3] = FIELD_DP32(s->idr[3], IDR3, XNX, 1);
+if (FIELD_EX32(s->idr[0], IDR0, S1P)) {
+/*
+ * QEMU doesn's support memory attributes, so FWB is NOP, this
+ * might change in the future if memory attributre would be
+ * supported.
+ */
+   s->idr[3] = FIELD_DP32(s->idr[3], IDR3, FWB, 1);
+}
 }
 s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1);
 s->idr[3] = FIELD_DP32(s->idr[3], IDR3, BBML, 2);
-- 
2.44.0.769.g3c40516874-goog




Re: [PATCH 1/1] target/riscv/kvm.c: Fix the hart bit setting of AIA

2024-04-28 Thread Alistair Francis
On Mon, Apr 15, 2024 at 4:53 PM Yong-Xuan Wang  wrote:
>
> The hart bit setting is different with Linux AIA driver[1] when the number
> of hart is power of 2. For example, when the guest has 4 harts, the
> estimated result of AIA driver is 2, whereas we pass 3 to RISC-V/KVM. Since
> only 2 bits are needed to represent 4 harts, update the formula to get the
> accurate result.

I don't really follow this.

Do you mind re-wording it to talk about what the specification says?
Not what Linux does.

>
> [1] 
> https://lore.kernel.org/all/20240307140307.646078-1-apa...@ventanamicro.com/
>
> Signed-off-by: Yong-Xuan Wang 
> ---
>  target/riscv/kvm/kvm-cpu.c | 9 -
>  1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
> index 6a6c6cae80f1..388c4ddaa145 100644
> --- a/target/riscv/kvm/kvm-cpu.c
> +++ b/target/riscv/kvm/kvm-cpu.c
> @@ -1642,7 +1642,14 @@ void kvm_riscv_aia_create(MachineState *machine, 
> uint64_t group_shift,
>  }
>  }
>
> -hart_bits = find_last_bit(&max_hart_per_socket, BITS_PER_LONG) + 1;
> +
> +if (max_hart_per_socket > 1) {
> +max_hart_per_socket--;

Assuming there are an even number of cores (which there usually are)
won't this always result in a

> +hart_bits = find_last_bit(&max_hart_per_socket, BITS_PER_LONG) + 1;

1 being returned by find_last_bit()?

Alistair

> +} else {
> +hart_bits = 0;
> +}
> +
>  ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG,
>  KVM_DEV_RISCV_AIA_CONFIG_HART_BITS,
>  &hart_bits, true, NULL);
> --
> 2.17.1
>
>



[RFC PATCH v3 03/18] hw/arm/smmuv3: Fix encoding of CLASS in events

2024-04-28 Thread Mostafa Saleh
The SMMUv3 spec (ARM IHI 0070 F.b - 7.3 Event records) defines the
class of events faults as:

CLASS: The class of the operation that caused the fault:
- 0b00: CD, CD fetch.
- 0b01: TTD, Stage 1 translation table fetch.
- 0b10: IN, Input address

However, this value was not set and left as 0 which means CD and not
IN (0b10).
While at it, add an enum for class as it would be used for nesting.

Signed-off-by: Mostafa Saleh 
---
 hw/arm/smmuv3-internal.h | 6 ++
 hw/arm/smmuv3.c  | 6 +-
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index e4dd11e1e6..0f3ecec804 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -32,6 +32,12 @@ typedef enum SMMUTranslationStatus {
 SMMU_TRANS_SUCCESS,
 } SMMUTranslationStatus;
 
+typedef enum SMMUTranslationClass {
+SMMU_CLASS_CD,
+SMMU_CLASS_TT,
+SMMU_CLASS_IN,
+} SMMUTranslationClass;
+
 /* MMIO Registers */
 
 REG32(IDR0,0x0)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 9dd3ea48e4..1eb5b160d2 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -942,7 +942,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion 
*mr, hwaddr addr,
 event.type = SMMU_EVT_F_WALK_EABT;
 event.u.f_walk_eabt.addr = addr;
 event.u.f_walk_eabt.rnw = flag & 0x1;
-event.u.f_walk_eabt.class = 0x1;
+event.u.f_walk_eabt.class = SMMU_CLASS_TT;
 event.u.f_walk_eabt.addr2 = ptw_info.addr;
 break;
 case SMMU_PTW_ERR_TRANSLATION:
@@ -950,6 +950,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion 
*mr, hwaddr addr,
 event.type = SMMU_EVT_F_TRANSLATION;
 event.u.f_translation.addr = addr;
 event.u.f_translation.addr2 = ptw_info.addr;
+event.u.f_translation.class = SMMU_CLASS_IN;
 event.u.f_translation.rnw = flag & 0x1;
 }
 break;
@@ -958,6 +959,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion 
*mr, hwaddr addr,
 event.type = SMMU_EVT_F_ADDR_SIZE;
 event.u.f_addr_size.addr = addr;
 event.u.f_addr_size.addr2 = ptw_info.addr;
+event.u.f_translation.class = SMMU_CLASS_IN;
 event.u.f_addr_size.rnw = flag & 0x1;
 }
 break;
@@ -966,6 +968,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion 
*mr, hwaddr addr,
 event.type = SMMU_EVT_F_ACCESS;
 event.u.f_access.addr = addr;
 event.u.f_access.addr2 = ptw_info.addr;
+event.u.f_translation.class = SMMU_CLASS_IN;
 event.u.f_access.rnw = flag & 0x1;
 }
 break;
@@ -974,6 +977,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion 
*mr, hwaddr addr,
 event.type = SMMU_EVT_F_PERMISSION;
 event.u.f_permission.addr = addr;
 event.u.f_permission.addr2 = ptw_info.addr;
+event.u.f_translation.class = SMMU_CLASS_IN;
 event.u.f_permission.rnw = flag & 0x1;
 }
 break;
-- 
2.44.0.769.g3c40516874-goog




[RFC PATCH v3 05/18] hw/arm/smmu: Split smmuv3_translate()

2024-04-28 Thread Mostafa Saleh
smmuv3_translate() does everything from STE/CD parsing to TLB lookup
and PTW.

Soon, when nesting is supported, stage-1 data (tt, CD) needs to be
translated using stage-2.

Split smmuv3_translate() to 3 functions:

- smmu_translate(): in smmu-common.c, which does the TLB lookup, PTW,
  TLB insertion, all the functions are already there, this just puts
  them together.
  This also simplifies the code as it consolidates event generation
  in case of TLB lookup permission failure or in TT selection.

- smmuv3_do_translate(): in smmuv3.c, Calls smmu_translate() and does
  the event population in case of errors.

 - smmuv3_translate(), now calls smmuv3_do_translate() for
   translation while the rest is the same.

Also, add stage in trace_smmuv3_translate_success()

Signed-off-by: Mostafa Saleh 
Reviewed-by: Eric Auger 
---
 hw/arm/smmu-common.c |  59 +++
 hw/arm/smmuv3.c  | 191 +--
 hw/arm/trace-events  |   2 +-
 include/hw/arm/smmu-common.h |   8 ++
 4 files changed, 141 insertions(+), 119 deletions(-)

diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 8a5858f69f..d94db6b34f 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -566,6 +566,65 @@ int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, 
IOMMUAccessFlags perm,
 g_assert_not_reached();
 }
 
+SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg *cfg, dma_addr_t addr,
+ IOMMUAccessFlags flag, SMMUPTWEventInfo *info)
+{
+uint64_t page_mask, aligned_addr;
+SMMUTLBEntry *cached_entry = NULL;
+SMMUTransTableInfo *tt;
+int status;
+
+/*
+ * Combined attributes used for TLB lookup, as only one stage is supported,
+ * it will hold attributes based on the enabled stage.
+ */
+SMMUTransTableInfo tt_combined;
+
+if (cfg->stage == SMMU_STAGE_1) {
+/* Select stage1 translation table. */
+tt = select_tt(cfg, addr);
+if (!tt) {
+info->type = SMMU_PTW_ERR_TRANSLATION;
+info->stage = SMMU_STAGE_1;
+return NULL;
+}
+tt_combined.granule_sz = tt->granule_sz;
+tt_combined.tsz = tt->tsz;
+
+} else {
+/* Stage2. */
+tt_combined.granule_sz = cfg->s2cfg.granule_sz;
+tt_combined.tsz = cfg->s2cfg.tsz;
+}
+
+/*
+ * TLB lookup looks for granule and input size for a translation stage,
+ * as only one stage is supported right now, choose the right values
+ * from the configuration.
+ */
+page_mask = (1ULL << tt_combined.granule_sz) - 1;
+aligned_addr = addr & ~page_mask;
+
+cached_entry = smmu_iotlb_lookup(bs, cfg, &tt_combined, aligned_addr);
+if (cached_entry) {
+if ((flag & IOMMU_WO) && !(cached_entry->entry.perm & IOMMU_WO)) {
+info->type = SMMU_PTW_ERR_PERMISSION;
+info->stage = cfg->stage;
+return NULL;
+}
+return cached_entry;
+}
+
+cached_entry = g_new0(SMMUTLBEntry, 1);
+status = smmu_ptw(cfg, aligned_addr, flag, cached_entry, info);
+if (status) {
+g_free(cached_entry);
+return NULL;
+}
+smmu_iotlb_insert(bs, cfg, cached_entry);
+return cached_entry;
+}
+
 /**
  * The bus number is used for lookup when SID based invalidation occurs.
  * In that case we lazily populate the SMMUPciBus array from the bus hash
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index dab3ad2db9..f98c157221 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -827,6 +827,75 @@ static void smmuv3_flush_config(SMMUDevice *sdev)
 g_hash_table_remove(bc->configs, sdev);
 }
 
+/* Do translation with TLB lookup. */
+static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
+ SMMUTransCfg *cfg,
+ SMMUEventInfo *event,
+ IOMMUAccessFlags flag,
+ SMMUTLBEntry **out_entry)
+{
+SMMUPTWEventInfo ptw_info = {};
+SMMUState *bs = ARM_SMMU(s);
+SMMUTLBEntry *cached_entry = NULL;
+
+cached_entry = smmu_translate(bs, cfg, addr, flag, &ptw_info);
+if (!cached_entry) {
+/* All faults from PTW has S2 field. */
+event->u.f_walk_eabt.s2 = (ptw_info.stage == SMMU_STAGE_2);
+switch (ptw_info.type) {
+case SMMU_PTW_ERR_WALK_EABT:
+event->type = SMMU_EVT_F_WALK_EABT;
+event->u.f_walk_eabt.addr = addr;
+event->u.f_walk_eabt.rnw = flag & 0x1;
+event->u.f_walk_eabt.class = SMMU_CLASS_TT;
+event->u.f_walk_eabt.addr2 = ptw_info.addr;
+break;
+case SMMU_PTW_ERR_TRANSLATION:
+if (PTW_RECORD_FAULT(cfg)) {
+event->type = SMMU_EVT_F_TRANSLATION;
+event->u.f_translation.addr = addr;
+event->u.f_translation.addr2 = 

[RFC PATCH v3 18/18] hw/arm/virt: Set SMMU OAS based on CPU PARANGE

2024-04-28 Thread Mostafa Saleh
Use the new SMMU property to make the SMMU OAS match the CPU PARANGE.
That's according to SMMU manual ARM IHI 0070F.b:
6.3.6 SMMU_IDR5, OAS must match the system physical address size.

Signed-off-by: Mostafa Saleh 
---
 hw/arm/virt.c  | 14 --
 target/arm/cpu.h   |  2 ++
 target/arm/cpu64.c |  5 +
 3 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 3c93c0c0a6..f203b1f8e1 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -252,6 +252,13 @@ static bool ns_el2_virt_timer_present(void)
 arm_feature(env, ARM_FEATURE_EL2) && cpu_isar_feature(aa64_vh, cpu);
 }
 
+/* We rely on CPU to define system OAS. */
+static int32_t get_system_oas(void)
+{
+ARMCPU *cpu = ARM_CPU(qemu_get_cpu(0));
+return cpu_arm_get_oas(cpu);
+}
+
 static void create_fdt(VirtMachineState *vms)
 {
 MachineState *ms = MACHINE(vms);
@@ -1384,7 +1391,7 @@ static void create_pcie_irq_map(const MachineState *ms,
 }
 
 static void create_smmu(const VirtMachineState *vms,
-PCIBus *bus)
+PCIBus *bus, int32_t oas)
 {
 char *node;
 const char compat[] = "arm,smmu-v3";
@@ -1404,6 +1411,9 @@ static void create_smmu(const VirtMachineState *vms,
 
 object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus),
  &error_abort);
+
+qdev_prop_set_uint64(dev, "oas", oas);
+
 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
 for (i = 0; i < NUM_SMMU_IRQS; i++) {
@@ -1578,7 +1588,7 @@ static void create_pcie(VirtMachineState *vms)
 
 switch (vms->iommu) {
 case VIRT_IOMMU_SMMUV3:
-create_smmu(vms, vms->bus);
+create_smmu(vms, vms->bus, get_system_oas());
 qemu_fdt_setprop_cells(ms->fdt, nodename, "iommu-map",
0x0, vms->iommu_phandle, 0x0, 0x1);
 break;
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 17efc5d565..68261ffbf9 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3287,4 +3287,6 @@ static inline target_ulong cpu_untagged_addr(CPUState 
*cs, target_ulong x)
 }
 #endif
 
+int32_t cpu_arm_get_oas(ARMCPU *cpu);
+
 #endif
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 985b1efe16..08da83c082 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -787,6 +787,11 @@ static const gchar *aarch64_gdb_arch_name(CPUState *cs)
 return "aarch64";
 }
 
+int32_t cpu_arm_get_oas(ARMCPU *cpu)
+{
+return FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE);
+}
+
 static void aarch64_cpu_class_init(ObjectClass *oc, void *data)
 {
 CPUClass *cc = CPU_CLASS(oc);
-- 
2.44.0.769.g3c40516874-goog




[RFC PATCH v3 02/18] hw/arm/smmu: Fix IPA for stage-2 events

2024-04-28 Thread Mostafa Saleh
For the following events (ARM IHI 0070 F.b - 7.3 Event records):
- F_TRANSLATION
- F_ACCESS
- F_PERMISSION
- F_ADDR_SIZE

If fault occurs at stage 2, S2 == 1 and:
  - If translating an IPA for a transaction (whether by input to
stage 2-only configuration, or after successful stage 1 translation),
CLASS == IN, and IPA is provided.

However, this was not implemented correctly, as for stage 2, we Qemu
only sets the  S2 bit but not the IPA.

This field has the same bits as FetchAddr in F_WALK_EABT which is
populated correctly, so we don’t change that.
The population of this field should be done from the walker as the IPA address
wouldn't be known in case of nesting.

For stage 1, the spec says:
  If fault occurs at stage 1, S2 == 0 and:
  CLASS == IN, IPA is UNKNOWN.

So, no need to set it to for stage 1, as ptw_info is initialised by zero in
smmuv3_translate().

Signed-off-by: Mostafa Saleh 
---
 hw/arm/smmu-common.c | 10 ++
 hw/arm/smmuv3.c  |  4 
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index eb2356bc35..8a8c718e6b 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -448,7 +448,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
  */
 if (ipa >= (1ULL << inputsize)) {
 info->type = SMMU_PTW_ERR_TRANSLATION;
-goto error;
+goto error_ipa;
 }
 
 while (level < VMSA_LEVELS) {
@@ -494,13 +494,13 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
  */
 if (!PTE_AF(pte) && !cfg->s2cfg.affd) {
 info->type = SMMU_PTW_ERR_ACCESS;
-goto error;
+goto error_ipa;
 }
 
 s2ap = PTE_AP(pte);
 if (is_permission_fault_s2(s2ap, perm)) {
 info->type = SMMU_PTW_ERR_PERMISSION;
-goto error;
+goto error_ipa;
 }
 
 /*
@@ -509,7 +509,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
  */
 if (gpa >= (1ULL << cfg->s2cfg.eff_ps)) {
 info->type = SMMU_PTW_ERR_ADDR_SIZE;
-goto error;
+goto error_ipa;
 }
 
 tlbe->entry.translated_addr = gpa;
@@ -522,6 +522,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
 }
 info->type = SMMU_PTW_ERR_TRANSLATION;
 
+error_ipa:
+info->addr = ipa;
 error:
 info->stage = 2;
 tlbe->entry.perm = IOMMU_NONE;
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 2d1e0d55ec..9dd3ea48e4 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -949,6 +949,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion 
*mr, hwaddr addr,
 if (PTW_RECORD_FAULT(cfg)) {
 event.type = SMMU_EVT_F_TRANSLATION;
 event.u.f_translation.addr = addr;
+event.u.f_translation.addr2 = ptw_info.addr;
 event.u.f_translation.rnw = flag & 0x1;
 }
 break;
@@ -956,6 +957,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion 
*mr, hwaddr addr,
 if (PTW_RECORD_FAULT(cfg)) {
 event.type = SMMU_EVT_F_ADDR_SIZE;
 event.u.f_addr_size.addr = addr;
+event.u.f_addr_size.addr2 = ptw_info.addr;
 event.u.f_addr_size.rnw = flag & 0x1;
 }
 break;
@@ -963,6 +965,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion 
*mr, hwaddr addr,
 if (PTW_RECORD_FAULT(cfg)) {
 event.type = SMMU_EVT_F_ACCESS;
 event.u.f_access.addr = addr;
+event.u.f_access.addr2 = ptw_info.addr;
 event.u.f_access.rnw = flag & 0x1;
 }
 break;
@@ -970,6 +973,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion 
*mr, hwaddr addr,
 if (PTW_RECORD_FAULT(cfg)) {
 event.type = SMMU_EVT_F_PERMISSION;
 event.u.f_permission.addr = addr;
+event.u.f_permission.addr2 = ptw_info.addr;
 event.u.f_permission.rnw = flag & 0x1;
 }
 break;
-- 
2.44.0.769.g3c40516874-goog




[RFC PATCH v3 00/18] SMMUv3 nested translation support

2024-04-28 Thread Mostafa Saleh
Currently, QEMU supports emulating either stage-1 or stage-2 SMMUs
but not nested instances.
This patch series adds support for nested translation in SMMUv3,
this is controlled by property “arm-smmuv3.stage=nested”, and
advertised to guests as (IDR0.S1P == 1 && IDR0.S2P == 2)

Main changes(architecture):

1) CDs are considered IPA and translated with stage-2.
2) TTBx and tables for stage-1 are considered IPA and translated
   with stage-2.
3) Translate the IPA address with stage-2.

TLBs:
==
TLBs are the most tricky part.

1) General design
   Unified(Combined) design is used, where entries with ASID=-1 are
   IPAs(cached from stage-2 config)

   TLBs are also modified to cache 2 permissions, a new permission added
   "parent_perm."

   For non-nested configuration, perm == parent_perm and nothing
   changes. This is used to know which stage to use in case there is
   a permission fault from a TLB entry.

2) Caching in TLB
   Stage-1 and stage-2 are inserted in the TLB as is.
   For nested translation, both entries are combined into one TLB
   entry. The size (level and granule) are chosen from the smallest entries.
   That means that a stage-1 translation can be cached with sage-2
   granule in key, this is take into account lookup.

3) TLB Lookup
   TLB lookup already uses ASID in key, so it can distinguish between
   stage-1 and stage-2.
   And as mentioned above, the granule for stage-1 can be different,
   If stage-1 lookup failed, we try again with the stage-2 granule.

4) TLB invalidation
   - Address invalidation is split, for IOVA(CMD_TLBI_NH_VA
 /CMD_TLBI_NH_VAA) and IPA(CMD_TLBI_S2_IPA) based on ASID value
   - CMD_TLBI_NH_ASID/CMD_TLBI_NH_ALL: Consider VMID if stage-2 is
 supported, and invalidate stage-1 only by VMIDs

As far as I understand, this is compliant with the ARM architecture:
- ARM ARM DDI 0487J.a: RLGSCG, RTVTYQ, RGNJPZ
- ARM IHI 0070F.b: 16.2 Caching

An alternative approach would be to instantiate 2 TLBs, one per each
stage. I haven’t investigated that.

Others
===
- Advertise SMMUv3.2-S2FWB, it is NOP for QEMU as it doesn’t support
  attributes.

- OAS: A typical setup with nesting is to share CPU stage-2 with the
  SMMU, and according to the user manual, SMMU OAS must match the
  system physical address.

  This was discussed before in
  https://lore.kernel.org/all/20230226220650.1480786-11-smost...@google.com/
  The implementation here, follows the discussion, where migration is
  added and oas is set up from the board (virt). However, the OAS is
  chosen based on the CPU PARANGE as there is no fixed one.

- For nested configuration, IOVA notifier only notifies for stage-1
  invalidations (as far as I understand this is the intended
  behaviour as it notifies for IOVA)

- Stop ignoring VMID for stage-1 if stage-2 is also supported.


Future improvements:
=
1) One small improvement, that I don’t think it’s worth the extra
   complexity, is in case of Stage-1 TLB miss for nested translation,
   we can do stage-1 walk and lookup for stage-2 TLBs, instead of
   doing the full walk.

Testing

1) IOMMUFD + VFIO
   Kernel: https://lore.kernel.org/all/cover.1683688960.git.nicol...@nvidia.com/
   VMM: 
https://qemu-devel.nongnu.narkive.com/o815DqpI/rfc-v5-0-8-arm-smmuv3-emulation-support

   By assigning 
“virtio-net-pci,netdev=net0,disable-legacy=on,iommu_platform=on,ats=on”,
   to a guest VM (on top of QEMU guest) with VIFO and IOMMUFD.

2) Work in progress prototype I am hacking on for nesting on KVM
   (this is nowhere near complete, and misses many stuff but it
   doesn't require VMs/VFIO) also with virtio-net-pci and git
   cloning a bunch of stuff and also observing traces.
   
https://android-kvm.googlesource.com/linux/+log/refs/heads/smostafa/android15-6.6-smmu-nesting-wip

I also modified the Linux driver to test with mixed granules/levels.

hw/arm/smmuv3: Split smmuv3_translate() better viewed with --color-moved

The first 3 patches are fixes.

Changes in v3
v2: 
https://lore.kernel.org/qemu-devel/20240408140818.3799590-1-smost...@google.com/
- Collected Eric Rbs.
- Rebased on master.
- Fix an existing bug in class encoding.
- Fix an existing bug in S2 events missing IPA.
- Fix nesting event population (missing class and wrong events)
- Remove CALL_FUNC_CFG_S2.
- Rework TLB combination logic to cache the largest possible entries.
- Refactor nested translation code to be more clear.
- Split patch 05 to 4 patches.
- Convert asid/vmid in trace events to int also.
- Remove some extra traces as it was not needed.
- Improve commit messages.

Changes in v2:
v1: 
https://lore.kernel.org/qemu-devel/20240325101442.1306300-1-smost...@google.com/
- Collected Eric Rbs
- Rework TLB to rely on VMID/ASID instead of an extra key.
- Fixed TLB issue with large stage-1 reported by Julian.
- Cap the OAS to 48 bits as PTW doesn’t support 52 bits.
- Fix ASID/VMID representation in some contexts as 16 bits while
  they can be -

[RFC PATCH v3 08/18] hw/arm/smmu-common: Add support for nested TLB

2024-04-28 Thread Mostafa Saleh
This patch adds support for nested(combined) TLB entries.
The main function combine_tlb() is not used here but in the next
patches, but to simplify the patches it is introduced first.

Main changes:
1) New entry added in the TLB, parent_perm, for nested TLB, holds the
   stage-2 permission, this can be used to know the origin of a
   permission fault from a cached entry as caching the “and” of the
   permissions loses this information.

   SMMUPTWEventInfo is used to hold information about PTW faults so
   the event can be populated, the value of stage (which maps to S2
   in the event) used to be set based on the current stage for TLB
   permission faults, however with the parent_perm, it is now set
   based on which perm has the missing permission

   When nesting is not enabled it has the same value as perm which
   doesn't change the logic.

2) As combined TLB implementation is used, the combination logic
   chooses:
   - tg and level from the entry which has the smallest addr_mask.
   - Based on that the iova that would be cached is recalculated.
   - Translated_addr is chosen from stage-2.

Signed-off-by: Mostafa Saleh 
---
 hw/arm/smmu-common.c | 32 
 include/hw/arm/smmu-common.h |  1 +
 2 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 21982621c0..0d6945fa54 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -394,7 +394,7 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
 tlbe->entry.translated_addr = gpa;
 tlbe->entry.iova = iova & ~mask;
 tlbe->entry.addr_mask = mask;
-tlbe->entry.perm = PTE_AP_TO_PERM(ap);
+tlbe->parent_perm = tlbe->entry.perm = PTE_AP_TO_PERM(ap);
 tlbe->level = level;
 tlbe->granule = granule_sz;
 return 0;
@@ -515,7 +515,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
 tlbe->entry.translated_addr = gpa;
 tlbe->entry.iova = ipa & ~mask;
 tlbe->entry.addr_mask = mask;
-tlbe->entry.perm = s2ap;
+tlbe->parent_perm = tlbe->entry.perm = s2ap;
 tlbe->level = level;
 tlbe->granule = granule_sz;
 return 0;
@@ -530,6 +530,27 @@ error:
 return -EINVAL;
 }
 
+/* combine 2 TLB entries and return in tlbe in nested config. */
+static void __attribute__((unused)) combine_tlb(SMMUTLBEntry *tlbe,
+SMMUTLBEntry *tlbe_s2,
+dma_addr_t iova,
+SMMUTransCfg *cfg)
+{
+if (tlbe_s2->entry.addr_mask < tlbe->entry.addr_mask) {
+tlbe->entry.addr_mask = tlbe_s2->entry.addr_mask;
+tlbe->granule = tlbe_s2->granule;
+tlbe->level = tlbe_s2->level;
+}
+
+tlbe->entry.translated_addr = CACHED_ENTRY_TO_ADDR(tlbe_s2,
+tlbe->entry.translated_addr);
+
+tlbe->entry.iova = iova & ~tlbe->entry.addr_mask;
+/* parent_perm has s2 perm while perm has s1 perm. */
+tlbe->parent_perm = tlbe_s2->entry.perm;
+return;
+}
+
 /**
  * smmu_ptw - Walk the page tables for an IOVA, according to @cfg
  *
@@ -607,9 +628,12 @@ SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg 
*cfg, dma_addr_t addr,
 
 cached_entry = smmu_iotlb_lookup(bs, cfg, &tt_combined, aligned_addr);
 if (cached_entry) {
-if ((flag & IOMMU_WO) && !(cached_entry->entry.perm & IOMMU_WO)) {
+if ((flag & IOMMU_WO) && !(cached_entry->entry.perm &
+cached_entry->parent_perm & IOMMU_WO)) {
 info->type = SMMU_PTW_ERR_PERMISSION;
-info->stage = cfg->stage;
+info->stage = !(cached_entry->entry.perm & IOMMU_WO) ?
+  SMMU_STAGE_1 :
+  SMMU_STAGE_2;
 return NULL;
 }
 return cached_entry;
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index 09d3b9e734..1db566d451 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -77,6 +77,7 @@ typedef struct SMMUTLBEntry {
 IOMMUTLBEntry entry;
 uint8_t level;
 uint8_t granule;
+IOMMUAccessFlags parent_perm;
 } SMMUTLBEntry;
 
 /* Stage-2 configuration. */
-- 
2.44.0.769.g3c40516874-goog




Re: [PATCH for-9.1 v3 0/2] target/riscv: set tval in breakpoints

2024-04-28 Thread Alistair Francis
On Wed, Apr 17, 2024 at 9:05 AM Daniel Henrique Barboza
 wrote:
>
> Hi,
>
> This new version has a change suggested by Richard in v2. No other
> changes made.
>
> Changes from v2:
> - patch 2:
>   - use tcg_constant_tl() instead of loading a temp and doing a
> movi_tl()
> - v2 link: 
> https://lore.kernel.org/qemu-riscv/20240416194132.1843699-1-dbarb...@ventanamicro.com/
>
>
> Daniel Henrique Barboza (2):
>   target/riscv/debug: set tval=pc in breakpoint exceptions
>   trans_privileged.c.inc: set (m|s)tval on ebreak breakpoint

Thanks!

Applied to riscv-to-apply.next

Alistair

>
>  target/riscv/cpu_helper.c  | 1 +
>  target/riscv/debug.c   | 3 +++
>  target/riscv/insn_trans/trans_privileged.c.inc | 2 ++
>  3 files changed, 6 insertions(+)
>
> --
> 2.44.0
>
>



Re: [PATCH for-9.1 v3 2/2] trans_privileged.c.inc: set (m|s)tval on ebreak breakpoint

2024-04-28 Thread Alistair Francis
On Wed, Apr 17, 2024 at 9:05 AM Daniel Henrique Barboza
 wrote:
>
> Privileged spec section 4.1.9 mentions:
>
> "When a trap is taken into S-mode, stval is written with
> exception-specific information to assist software in handling the trap.
> (...)
>
> If stval is written with a nonzero value when a breakpoint,
> address-misaligned, access-fault, or page-fault exception occurs on an
> instruction fetch, load, or store, then stval will contain the faulting
> virtual address."
>
> A similar text is found for mtval in section 3.1.16.
>
> Setting mtval/stval in this scenario is optional, but some softwares read
> these regs when handling ebreaks.
>
> Write 'badaddr' in all ebreak breakpoints to write the appropriate
> 'tval' during riscv_do_cpu_interrrupt().
>
> Signed-off-by: Daniel Henrique Barboza 

Reviewed-by: Alistair Francis 

Alistair

> ---
>  target/riscv/insn_trans/trans_privileged.c.inc | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/target/riscv/insn_trans/trans_privileged.c.inc 
> b/target/riscv/insn_trans/trans_privileged.c.inc
> index 620ab54eb0..bc5263a4e0 100644
> --- a/target/riscv/insn_trans/trans_privileged.c.inc
> +++ b/target/riscv/insn_trans/trans_privileged.c.inc
> @@ -62,6 +62,8 @@ static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a)
>  if (pre == 0x01f01013 && ebreak == 0x00100073 && post == 0x40705013) {
>  generate_exception(ctx, RISCV_EXCP_SEMIHOST);
>  } else {
> +tcg_gen_st_tl(tcg_constant_tl(ebreak_addr), tcg_env,
> +  offsetof(CPURISCVState, badaddr));
>  generate_exception(ctx, RISCV_EXCP_BREAKPOINT);
>  }
>  return true;
> --
> 2.44.0
>
>



Re: [PATCH for-9.1 v3 1/2] target/riscv/debug: set tval=pc in breakpoint exceptions

2024-04-28 Thread Alistair Francis
On Wed, Apr 17, 2024 at 9:05 AM Daniel Henrique Barboza
 wrote:
>
> We're not setting (s/m)tval when triggering breakpoints of type 2
> (mcontrol) and 6 (mcontrol6). According to the debug spec section
> 5.7.12, "Match Control Type 6":
>
> "The Privileged Spec says that breakpoint exceptions that occur on
> instruction fetches, loads, or stores update the tval CSR with either
> zero or the faulting virtual address. The faulting virtual address for
> an mcontrol6 trigger with action = 0 is the address being accessed and
> which caused that trigger to fire."
>
> A similar text is also found in the Debug spec section 5.7.11 w.r.t.
> mcontrol.
>
> Note that what we're doing ATM is not violating the spec, but it's
> simple enough to set mtval/stval and it makes life easier for any
> software that relies on this info.
>
> Given that we always use action = 0, save the faulting address for the
> mcontrol and mcontrol6 trigger breakpoints into env->badaddr, which is
> used as as scratch area for traps with address information. 'tval' is
> then set during riscv_cpu_do_interrupt().
>
> Signed-off-by: Daniel Henrique Barboza 

Reviewed-by: Alistair Francis 

Alistair

> ---
>  target/riscv/cpu_helper.c | 1 +
>  target/riscv/debug.c  | 3 +++
>  2 files changed, 4 insertions(+)
>
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index fc090d729a..f9c6d7053b 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -1717,6 +1717,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>  tval = env->bins;
>  break;
>  case RISCV_EXCP_BREAKPOINT:
> +tval = env->badaddr;
>  if (cs->watchpoint_hit) {
>  tval = cs->watchpoint_hit->hitaddr;
>  cs->watchpoint_hit = NULL;
> diff --git a/target/riscv/debug.c b/target/riscv/debug.c
> index e30d99cc2f..b110370ea6 100644
> --- a/target/riscv/debug.c
> +++ b/target/riscv/debug.c
> @@ -798,6 +798,7 @@ bool riscv_cpu_debug_check_breakpoint(CPUState *cs)
>  if ((ctrl & TYPE2_EXEC) && (bp->pc == pc)) {
>  /* check U/S/M bit against current privilege level */
>  if ((ctrl >> 3) & BIT(env->priv)) {
> +env->badaddr = pc;
>  return true;
>  }
>  }
> @@ -810,11 +811,13 @@ bool riscv_cpu_debug_check_breakpoint(CPUState *cs)
>  if (env->virt_enabled) {
>  /* check VU/VS bit against current privilege level */
>  if ((ctrl >> 23) & BIT(env->priv)) {
> +env->badaddr = pc;
>  return true;
>  }
>  } else {
>  /* check U/S/M bit against current privilege level */
>  if ((ctrl >> 3) & BIT(env->priv)) {
> +env->badaddr = pc;
>  return true;
>  }
>  }
> --
> 2.44.0
>
>



Re: [PATCH v2 1/1] target/riscv/kvm: tolerate KVM disable ext errors

2024-04-28 Thread Alistair Francis
On Tue, Apr 23, 2024 at 3:15 AM Daniel Henrique Barboza
 wrote:
>
> Running a KVM guest using a 6.9-rc3 kernel, in a 6.8 host that has zkr
> enabled, will fail with a kernel oops SIGILL right at the start. The
> reason is that we can't expose zkr without implementing the SEED CSR.
> Disabling zkr in the guest would be a workaround, but if the KVM doesn't
> allow it we'll error out and never boot.
>
> In hindsight this is too strict. If we keep proceeding, despite not
> disabling the extension in the KVM vcpu, we'll not add the extension in
> the riscv,isa. The guest kernel will be unaware of the extension, i.e.
> it doesn't matter if the KVM vcpu has it enabled underneath or not. So
> it's ok to keep booting in this case.
>
> Change our current logic to not error out if we fail to disable an
> extension in kvm_set_one_reg(), but show a warning and keep booting. It
> is important to throw a warning because we must make the user aware that
> the extension is still available in the vcpu, meaning that an
> ill-behaved guest can ignore the riscv,isa settings and  use the
> extension.
>
> The case we're handling happens with an EINVAL error code. If we fail to
> disable the extension in KVM for any other reason, error out.
>
> We'll also keep erroring out when we fail to enable an extension in KVM,
> since adding the extension in riscv,isa at this point will cause a guest
> malfunction because the extension isn't enabled in the vcpu.
>
> Suggested-by: Andrew Jones 
> Signed-off-by: Daniel Henrique Barboza 

Thanks!

Applied to riscv-to-apply.next

Alistair

> ---
>  target/riscv/kvm/kvm-cpu.c | 12 
>  1 file changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
> index 6a6c6cae80..03e3fee607 100644
> --- a/target/riscv/kvm/kvm-cpu.c
> +++ b/target/riscv/kvm/kvm-cpu.c
> @@ -427,10 +427,14 @@ static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU 
> *cpu, CPUState *cs)
>  reg = kvm_cpu_cfg_get(cpu, multi_ext_cfg);
>  ret = kvm_set_one_reg(cs, id, ®);
>  if (ret != 0) {
> -error_report("Unable to %s extension %s in KVM, error %d",
> - reg ? "enable" : "disable",
> - multi_ext_cfg->name, ret);
> -exit(EXIT_FAILURE);
> +if (!reg && ret == -EINVAL) {
> +warn_report("KVM cannot disable extension %s",
> +multi_ext_cfg->name);
> +} else {
> +error_report("Unable to enable extension %s in KVM, error 
> %d",
> + multi_ext_cfg->name, ret);
> +exit(EXIT_FAILURE);
> +}
>  }
>  }
>  }
> --
> 2.44.0
>
>



Re: [PATCH] target/riscv: change RISCV_EXCP_SEMIHOST exception number to 63

2024-04-28 Thread Alistair Francis
On Mon, Apr 22, 2024 at 11:59 PM Clément Léger  wrote:
>
> The current semihost exception number (16) is a reserved number (range
> [16-17]). The upcoming double trap specification uses that number for
> the double trap exception. Since the privileged spec (Table 22) defines
> ranges for custom uses change the semihosting exception number to 63
> which belongs to the range [48-63] in order to avoid any future
> collisions with reserved exception.
>
> Signed-off-by: Clément Léger 

Thanks!

Applied to riscv-to-apply.next

Alistair

>
> ---
>  target/riscv/cpu_bits.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index fc2068ee4d..74318a925c 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -670,11 +670,11 @@ typedef enum RISCVException {
>  RISCV_EXCP_INST_PAGE_FAULT = 0xc, /* since: priv-1.10.0 */
>  RISCV_EXCP_LOAD_PAGE_FAULT = 0xd, /* since: priv-1.10.0 */
>  RISCV_EXCP_STORE_PAGE_FAULT = 0xf, /* since: priv-1.10.0 */
> -RISCV_EXCP_SEMIHOST = 0x10,
>  RISCV_EXCP_INST_GUEST_PAGE_FAULT = 0x14,
>  RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT = 0x15,
>  RISCV_EXCP_VIRT_INSTRUCTION_FAULT = 0x16,
>  RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT = 0x17,
> +RISCV_EXCP_SEMIHOST = 0x3f,
>  } RISCVException;
>
>  #define RISCV_EXCP_INT_FLAG0x8000
> --
> 2.43.0
>
>



[PULL v2 06/17] hw/loongarch: Init efi_boot_memmap table

2024-04-28 Thread Song Gao
The efi_system_table adds a efi_boot_memmap configuration table.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-7-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 40 +
 hw/loongarch/virt.c | 11 ++
 include/hw/loongarch/boot.h | 27 +
 include/hw/loongarch/virt.h | 10 ++
 4 files changed, 79 insertions(+), 9 deletions(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 59889dbc90..527fc9c0be 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -63,8 +63,41 @@ static const unsigned int slave_boot_code[] = {
 0x4c20,   /* jirl   $zero, $ra,0   */
 };
 
+static inline void *guidcpy(void *dst, const void *src)
+{
+return memcpy(dst, src, sizeof(efi_guid_t));
+}
+
+static void init_efi_boot_memmap(struct efi_system_table *systab,
+ void *p, void *start)
+{
+unsigned i;
+struct efi_boot_memmap *boot_memmap = p;
+efi_guid_t tbl_guid = LINUX_EFI_BOOT_MEMMAP_GUID;
+
+/* efi_configuration_table 1 */
+guidcpy(&systab->tables[0].guid, &tbl_guid);
+systab->tables[0].table = (struct efi_configuration_table *)(p - start);
+systab->nr_tables = 1;
+
+boot_memmap->desc_size = sizeof(efi_memory_desc_t);
+boot_memmap->desc_ver = 1;
+boot_memmap->map_size = 0;
+
+efi_memory_desc_t *map = p + sizeof(struct efi_boot_memmap);
+for (i = 0; i < memmap_entries; i++) {
+map = (void *)boot_memmap + sizeof(*map);
+map[i].type = memmap_table[i].type;
+map[i].phys_addr = ROUND_UP(memmap_table[i].address, 64 * KiB);
+map[i].num_pages = ROUND_DOWN(memmap_table[i].address +
+memmap_table[i].length - map[i].phys_addr, 64 * KiB);
+p += sizeof(efi_memory_desc_t);
+}
+}
+
 static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
 {
+void *bp_tables_start;
 struct efi_system_table *systab = p;
 
 info->a2 = p - start;
@@ -80,6 +113,13 @@ static void init_systab(struct loongarch_boot_info *info, 
void *p, void *start)
 p += ROUND_UP(sizeof(struct efi_system_table), 64 * KiB);
 
 systab->tables = p;
+bp_tables_start = p;
+
+init_efi_boot_memmap(systab, p, start);
+p += ROUND_UP(sizeof(struct efi_boot_memmap) +
+  sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB);
+
+systab->tables = (struct efi_configuration_table *)(bp_tables_start - 
start);
 }
 
 static void init_cmdline(struct loongarch_boot_info *info, void *p, void 
*start)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index bfb88aedab..708aa8bc60 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -378,15 +378,8 @@ static void virt_powerdown_req(Notifier *notifier, void 
*opaque)
 acpi_send_event(s->acpi_ged, ACPI_POWER_DOWN_STATUS);
 }
 
-struct memmap_entry {
-uint64_t address;
-uint64_t length;
-uint32_t type;
-uint32_t reserved;
-};
-
-static struct memmap_entry *memmap_table;
-static unsigned memmap_entries;
+struct memmap_entry *memmap_table;
+unsigned memmap_entries;
 
 static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type)
 {
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index cf0e4d4f91..76622af2e2 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -21,6 +21,15 @@ typedef struct {
 uint8_t b[16];
 } efi_guid_t QEMU_ALIGNED(8);
 
+#define EFI_GUID(a, b, c, d...) (efi_guid_t){ {
\
+(a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, 
\
+(b) & 0xff, ((b) >> 8) & 0xff, 
\
+(c) & 0xff, ((c) >> 8) & 0xff, d } }
+
+#define LINUX_EFI_BOOT_MEMMAP_GUID \
+EFI_GUID(0x800f683f, 0xd08b, 0x423a,  0xa2, 0x93, \
+ 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4)
+
 struct efi_config_table {
 efi_guid_t guid;
 uint64_t *ptr;
@@ -56,6 +65,24 @@ struct efi_system_table {
 struct efi_configuration_table *tables;
 };
 
+typedef struct {
+uint32_t type;
+uint32_t pad;
+uint64_t phys_addr;
+uint64_t virt_addr;
+uint64_t num_pages;
+uint64_t attribute;
+} efi_memory_desc_t;
+
+struct efi_boot_memmap {
+uint64_t map_size;
+uint64_t desc_size;
+uint32_t desc_ver;
+uint64_t map_key;
+uint64_t buff_size;
+efi_memory_desc_t map[32];
+};
+
 struct loongarch_boot_info {
 uint64_t ram_size;
 const char *kernel_filename;
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index d7a074d69f..8a9fe4053d 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -35,6 +35,16 @@
 
 #define COMMAND_LINE_SIZE   512
 
+extern struct memmap_entry *memmap_table;
+extern unsigned memmap_entries;
+
+struct memmap_entry {
+uint64_t address;
+uint64_t length;
+uint32_

[PULL v2 08/17] hw/loongarch: Init efi_fdt table

2024-04-28 Thread Song Gao
The efi_system_table adds a efi_fdt configuration table.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-9-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 11 +++
 hw/loongarch/virt.c |  6 ++
 include/hw/loongarch/boot.h |  4 
 include/hw/loongarch/virt.h |  2 ++
 4 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index c8b3e742b4..7d1630b2e7 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -113,6 +113,16 @@ static void init_efi_initrd_table(struct efi_system_table 
*systab,
 initrd_table->size = initrd_size;
 }
 
+static void init_efi_fdt_table(struct efi_system_table *systab)
+{
+efi_guid_t tbl_guid = DEVICE_TREE_GUID;
+
+/* efi_configuration_table 3 */
+guidcpy(&systab->tables[2].guid, &tbl_guid);
+systab->tables[2].table = (void *)FDT_BASE;
+systab->nr_tables = 3;
+}
+
 static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
 {
 void *bp_tables_start;
@@ -138,6 +148,7 @@ static void init_systab(struct loongarch_boot_info *info, 
void *p, void *start)
   sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB);
 init_efi_initrd_table(systab, p, start);
 p += ROUND_UP(sizeof(struct efi_initrd), 64 * KiB);
+init_efi_fdt_table(systab);
 
 systab->tables = (struct efi_configuration_table *)(bp_tables_start - 
start);
 }
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 708aa8bc60..42e5df8a24 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -727,7 +727,6 @@ static void loongarch_init(MachineState *machine)
 int nb_numa_nodes = machine->numa_state->num_nodes;
 NodeInfo *numa_info = machine->numa_state->nodes;
 int i;
-hwaddr fdt_base;
 const CPUArchIdList *possible_cpus;
 MachineClass *mc = MACHINE_GET_CLASS(machine);
 CPUState *cpu;
@@ -857,12 +856,11 @@ static void loongarch_init(MachineState *machine)
  * Put the FDT into the memory map as a ROM image: this will ensure
  * the FDT is copied again upon reset, even if addr points into RAM.
  */
-fdt_base = 1 * MiB;
 qemu_fdt_dumpdtb(machine->fdt, lams->fdt_size);
-rom_add_blob_fixed_as("fdt", machine->fdt, lams->fdt_size, fdt_base,
+rom_add_blob_fixed_as("fdt", machine->fdt, lams->fdt_size, FDT_BASE,
   &address_space_memory);
 qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds,
-rom_ptr_for_as(&address_space_memory, fdt_base, lams->fdt_size));
+rom_ptr_for_as(&address_space_memory, FDT_BASE, lams->fdt_size));
 
 lams->bootinfo.ram_size = ram_size;
 loongarch_load_kernel(machine, &lams->bootinfo);
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index 42d1ee3663..4ebcc89dcf 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -34,6 +34,10 @@ typedef struct {
 EFI_GUID(0x5568e427, 0x68fc, 0x4f3d,  0xac, 0x74, \
  0xca, 0x55, 0x52, 0x31, 0xcc, 0x68)
 
+#define DEVICE_TREE_GUID \
+EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5,  0x83, 0x0b, \
+ 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0)
+
 struct efi_config_table {
 efi_guid_t guid;
 uint64_t *ptr;
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 8a9fe4053d..4e14bf6060 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -35,6 +35,8 @@
 
 #define COMMAND_LINE_SIZE   512
 
+#define FDT_BASE0x10
+
 extern struct memmap_entry *memmap_table;
 extern unsigned memmap_entries;
 
-- 
2.25.1




[PULL v2 03/17] hw/loongarch: Add slave cpu boot_code

2024-04-28 Thread Song Gao
Load the slave CPU boot code at pflash0 and set
the slave CPU elf_address to VIRT_FLASH0_BASE.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-4-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 62 -
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index a5135fe542..fb6effbaff 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -15,6 +15,54 @@
 #include "sysemu/reset.h"
 #include "sysemu/qtest.h"
 
+static const unsigned int slave_boot_code[] = {
+  /* Configure reset ebase.*/
+0x0400302c,   /* csrwr  $t0, LOONGARCH_CSR_EENTRY  */
+
+  /* Disable interrupt.*/
+0x0380100c,   /* ori$t0, $zero,0x4 */
+0x04000180,   /* csrxchg$zero, $t0, LOONGARCH_CSR_CRMD */
+
+  /* Clear mailbox.*/
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038081ad,   /* ori$t1, $t1, CORE_BUF_20  */
+0x06481da0,   /* iocsrwr.d  $zero, $t1 */
+
+  /* Enable IPI interrupt. */
+0x142c,   /* lu12i.w$t0, 1(0x1)*/
+0x0400118c,   /* csrxchg$t0, $t0, LOONGARCH_CSR_ECFG   */
+0x02fffc0c,   /* addi.d $t0, $r0,-1(0xfff) */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038011ad,   /* ori$t1, $t1, CORE_EN_OFF  */
+0x064819ac,   /* iocsrwr.w  $t0, $t1   */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038081ad,   /* ori$t1, $t1, CORE_BUF_20  */
+
+  /* Wait for wakeup  <.L11>:  */
+0x06488000,   /* idle   0x0*/
+0x0340,   /* andi   $zero, $zero, 0x0  */
+0x064809ac,   /* iocsrrd.w  $t0, $t1   */
+0x43fff59f,   /* beqz   $t0, -12(0x74) # 48 <.L11> */
+
+  /* Read and clear IPI interrupt. */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x064809ac,   /* iocsrrd.w  $t0, $t1   */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038031ad,   /* ori$t1, $t1, CORE_CLEAR_OFF   */
+0x064819ac,   /* iocsrwr.w  $t0, $t1   */
+
+  /* Disable  IPI interrupt.   */
+0x142c,   /* lu12i.w$t0, 1(0x1)*/
+0x04001180,   /* csrxchg$zero, $t0, LOONGARCH_CSR_ECFG */
+
+  /* Read mail buf and jump to specified entry */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038081ad,   /* ori$t1, $t1, CORE_BUF_20  */
+0x06480dac,   /* iocsrrd.d  $t0, $t1   */
+0x00150181,   /* move   $ra, $t0   */
+0x4c20,   /* jirl   $zero, $ra,0   */
+};
+
 static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
 {
 return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
@@ -125,11 +173,23 @@ static void loongarch_direct_kernel_boot(struct 
loongarch_boot_info *info)
 }
 }
 
+/* Load slave boot code at pflash0 . */
+void *boot_code = g_malloc0(VIRT_FLASH0_SIZE);
+memcpy(boot_code, &slave_boot_code, sizeof(slave_boot_code));
+rom_add_blob_fixed("boot_code", boot_code, VIRT_FLASH0_SIZE, 
VIRT_FLASH0_BASE);
+
 CPU_FOREACH(cs) {
 lacpu = LOONGARCH_CPU(cs);
 lacpu->env.load_elf = true;
-lacpu->env.elf_address = kernel_addr;
+if (cs == first_cpu) {
+lacpu->env.elf_address = kernel_addr;
+} else {
+lacpu->env.elf_address = VIRT_FLASH0_BASE;
+}
+lacpu->env.boot_info = info;
 }
+
+g_free(boot_code);
 }
 
 void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
-- 
2.25.1




[PULL v2 12/17] hw/loongarch: fdt adds pch_pic Controller

2024-04-28 Thread Song Gao
fdt adds pch pic controller, we use 'loongson,pch-pic-1.0'

See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-pch-pic.c
https://lore.kernel.org/r/20200528152757.1028711-4-jiaxun.y...@flygoat.com

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-13-gaos...@loongson.cn>
---
 hw/loongarch/virt.c| 30 +-
 include/hw/pci-host/ls7a.h |  1 +
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 094b9d2e60..5bef161d11 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -148,6 +148,31 @@ static void fdt_add_eiointc_node(LoongArchMachineState 
*lams,
 g_free(nodename);
 }
 
+static void fdt_add_pch_pic_node(LoongArchMachineState *lams,
+ uint32_t *eiointc_phandle,
+ uint32_t *pch_pic_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+hwaddr pch_pic_base = VIRT_PCH_REG_BASE;
+hwaddr pch_pic_size = VIRT_PCH_REG_SIZE;
+
+*pch_pic_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/platic@%" PRIx64, pch_pic_base);
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt,  nodename, "phandle", *pch_pic_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,pch-pic-1.0");
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0,
+   pch_pic_base, 0, pch_pic_size);
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 2);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *eiointc_phandle);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,pic-base-vec", 0);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -570,7 +595,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
-uint32_t cpuintc_phandle, eiointc_phandle;
+uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle;
 
 /*
  * The connection of interrupts:
@@ -661,6 +686,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
 }
 
+/* Add PCH PIC node */
+fdt_add_pch_pic_node(lams, &eiointc_phandle, &pch_pic_phandle);
+
 pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
 start   =  num;
 num = EXTIOI_IRQS - start;
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index e753449593..fe260f0183 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -24,6 +24,7 @@
 #define VIRT_PCH_REG_BASE0x1000UL
 #define VIRT_IOAPIC_REG_BASE (VIRT_PCH_REG_BASE)
 #define VIRT_PCH_MSI_ADDR_LOW0x2FF0UL
+#define VIRT_PCH_REG_SIZE0x400
 
 /*
  * GSI_BASE is hard-coded with 64 in linux kernel, else kernel fails to boot
-- 
2.25.1




[PULL v2 07/17] hw/loongarch: Init efi_initrd table

2024-04-28 Thread Song Gao
The efi_system_table adds a efi_initrd configuration table.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-8-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 23 +--
 include/hw/loongarch/boot.h |  9 +
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 527fc9c0be..c8b3e742b4 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -15,6 +15,9 @@
 #include "sysemu/reset.h"
 #include "sysemu/qtest.h"
 
+ram_addr_t initrd_offset;
+uint64_t initrd_size;
+
 static const unsigned int slave_boot_code[] = {
   /* Configure reset ebase.*/
 0x0400302c,   /* csrwr  $t0, LOONGARCH_CSR_EENTRY  */
@@ -95,6 +98,21 @@ static void init_efi_boot_memmap(struct efi_system_table 
*systab,
 }
 }
 
+static void init_efi_initrd_table(struct efi_system_table *systab,
+  void *p, void *start)
+{
+efi_guid_t tbl_guid = LINUX_EFI_INITRD_MEDIA_GUID;
+struct efi_initrd *initrd_table  = p;
+
+/* efi_configuration_table 2 */
+guidcpy(&systab->tables[1].guid, &tbl_guid);
+systab->tables[1].table = (struct efi_configuration_table *)(p - start);
+systab->nr_tables = 2;
+
+initrd_table->base = initrd_offset;
+initrd_table->size = initrd_size;
+}
+
 static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
 {
 void *bp_tables_start;
@@ -118,6 +136,8 @@ static void init_systab(struct loongarch_boot_info *info, 
void *p, void *start)
 init_efi_boot_memmap(systab, p, start);
 p += ROUND_UP(sizeof(struct efi_boot_memmap) +
   sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB);
+init_efi_initrd_table(systab, p, start);
+p += ROUND_UP(sizeof(struct efi_initrd), 64 * KiB);
 
 systab->tables = (struct efi_configuration_table *)(bp_tables_start - 
start);
 }
@@ -139,8 +159,7 @@ static uint64_t cpu_loongarch_virt_to_phys(void *opaque, 
uint64_t addr)
 
 static int64_t load_kernel_info(struct loongarch_boot_info *info)
 {
-uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
-ram_addr_t initrd_offset;
+uint64_t kernel_entry, kernel_low, kernel_high;
 ssize_t kernel_size;
 
 kernel_size = load_elf(info->kernel_filename, NULL,
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index 76622af2e2..42d1ee3663 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -30,6 +30,10 @@ typedef struct {
 EFI_GUID(0x800f683f, 0xd08b, 0x423a,  0xa2, 0x93, \
  0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4)
 
+#define LINUX_EFI_INITRD_MEDIA_GUID \
+EFI_GUID(0x5568e427, 0x68fc, 0x4f3d,  0xac, 0x74, \
+ 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68)
+
 struct efi_config_table {
 efi_guid_t guid;
 uint64_t *ptr;
@@ -83,6 +87,11 @@ struct efi_boot_memmap {
 efi_memory_desc_t map[32];
 };
 
+struct efi_initrd {
+uint64_t base;
+uint64_t size;
+};
+
 struct loongarch_boot_info {
 uint64_t ram_size;
 const char *kernel_filename;
-- 
2.25.1




[PULL v2 02/17] hw/loongarch: Add load initrd

2024-04-28 Thread Song Gao
we load initrd ramdisk after kernel_high address

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-3-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 28 +++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 9feed17db3..a5135fe542 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -22,7 +22,8 @@ static uint64_t cpu_loongarch_virt_to_phys(void *opaque, 
uint64_t addr)
 
 static int64_t load_kernel_info(struct loongarch_boot_info *info)
 {
-uint64_t kernel_entry, kernel_low, kernel_high;
+uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
+ram_addr_t initrd_offset;
 ssize_t kernel_size;
 
 kernel_size = load_elf(info->kernel_filename, NULL,
@@ -37,6 +38,31 @@ static int64_t load_kernel_info(struct loongarch_boot_info 
*info)
  load_elf_strerror(kernel_size));
 exit(1);
 }
+
+if (info->initrd_filename) {
+initrd_size = get_image_size(info->initrd_filename);
+if (initrd_size > 0) {
+initrd_offset = ROUND_UP(kernel_high + 4 * kernel_size, 64 * KiB);
+
+if (initrd_offset + initrd_size > info->ram_size) {
+error_report("memory too small for initial ram disk '%s'",
+ info->initrd_filename);
+exit(1);
+}
+
+initrd_size = load_image_targphys(info->initrd_filename, 
initrd_offset,
+  info->ram_size - initrd_offset);
+}
+
+if (initrd_size == (target_ulong)-1) {
+error_report("could not load initial ram disk '%s'",
+ info->initrd_filename);
+exit(1);
+}
+} else {
+initrd_size = 0;
+}
+
 return kernel_entry;
 }
 
-- 
2.25.1




[PULL v2 15/17] hw/loongarch: fdt remove unused irqchip node

2024-04-28 Thread Song Gao
This patch removes the unused fdt irqchip node.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-16-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 31 +--
 1 file changed, 1 insertion(+), 30 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 91a55a81b6..48f73edd8e 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -446,34 +446,6 @@ static void fdt_add_pcie_node(const LoongArchMachineState 
*lams,
 g_free(nodename);
 }
 
-static void fdt_add_irqchip_node(LoongArchMachineState *lams)
-{
-MachineState *ms = MACHINE(lams);
-char *nodename;
-uint32_t irqchip_phandle;
-
-irqchip_phandle = qemu_fdt_alloc_phandle(ms->fdt);
-qemu_fdt_setprop_cell(ms->fdt, "/", "interrupt-parent", irqchip_phandle);
-
-nodename = g_strdup_printf("/intc@%lx", VIRT_IOAPIC_REG_BASE);
-qemu_fdt_add_subnode(ms->fdt, nodename);
-qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 3);
-qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
-qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 0x2);
-qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 0x2);
-qemu_fdt_setprop(ms->fdt, nodename, "ranges", NULL, 0);
-
-qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
-"loongarch,ls7a");
-
-qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
- 2, VIRT_IOAPIC_REG_BASE,
- 2, PCH_PIC_ROUTE_ENTRY_OFFSET);
-
-qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", irqchip_phandle);
-g_free(nodename);
-}
-
 static void fdt_add_memory_node(MachineState *ms,
 uint64_t base, uint64_t size, int node_id)
 {
@@ -1011,8 +983,7 @@ static void loongarch_init(MachineState *machine)
 
 /* Initialize the IO interrupt subsystem */
 loongarch_irq_init(lams);
-fdt_add_irqchip_node(lams);
-platform_bus_add_all_fdt_nodes(machine->fdt, "/intc",
+platform_bus_add_all_fdt_nodes(machine->fdt, "/platic",
VIRT_PLATFORM_BUS_BASEADDRESS,
VIRT_PLATFORM_BUS_SIZE,
VIRT_PLATFORM_BUS_IRQ);
-- 
2.25.1




[PULL v2 11/17] hw/loongarch: fdt adds Extend I/O Interrupt Controller

2024-04-28 Thread Song Gao
fdt adds Extend I/O Interrupt Controller,
we use 'loongson,ls2k2000-eiointc'.

See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-eiointc.c
https://lore.kernel.org/r/764e02d924094580ac0f1d15535f4b98308705c6.1683279769.git.zhoubin...@loongson.cn

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-12-gaos...@loongson.cn>
---
 hw/loongarch/virt.c| 30 +-
 include/hw/intc/loongarch_extioi.h |  1 +
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 88cdcb6f91..094b9d2e60 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -123,6 +123,31 @@ static void fdt_add_cpuic_node(LoongArchMachineState *lams,
 g_free(nodename);
 }
 
+static void fdt_add_eiointc_node(LoongArchMachineState *lams,
+  uint32_t *cpuintc_phandle,
+  uint32_t *eiointc_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+hwaddr extioi_base = APIC_BASE;
+hwaddr extioi_size = EXTIOI_SIZE;
+
+*eiointc_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/eiointc@%" PRIx64, extioi_base);
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *eiointc_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,ls2k2000-eiointc");
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *cpuintc_phandle);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", 3);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0,
+   extioi_base, 0x0, extioi_size);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -545,7 +570,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
-uint32_t cpuintc_phandle;
+uint32_t cpuintc_phandle, eiointc_phandle;
 
 /*
  * The connection of interrupts:
@@ -614,6 +639,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 }
 }
 
+/* Add Extend I/O Interrupt Controller node */
+fdt_add_eiointc_node(lams, &cpuintc_phandle, &eiointc_phandle);
+
 pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
 num = VIRT_PCH_PIC_IRQ_NUM;
 qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num);
diff --git a/include/hw/intc/loongarch_extioi.h 
b/include/hw/intc/loongarch_extioi.h
index a0a46b888c..410c6e1121 100644
--- a/include/hw/intc/loongarch_extioi.h
+++ b/include/hw/intc/loongarch_extioi.h
@@ -39,6 +39,7 @@
 #define EXTIOI_COREISR_END   (0xB20 - APIC_OFFSET)
 #define EXTIOI_COREMAP_START (0xC00 - APIC_OFFSET)
 #define EXTIOI_COREMAP_END   (0xD00 - APIC_OFFSET)
+#define EXTIOI_SIZE  0x800
 
 typedef struct ExtIOICore {
 uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT];
-- 
2.25.1




[PULL v2 17/17] hw/loongarch: Add cells missing from rtc node

2024-04-28 Thread Song Gao
rtc node need interrupts and interrupt-parent cells.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-18-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 12 +---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index dbd7928759..c0999878df 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -231,7 +231,8 @@ static void fdt_add_flash_node(LoongArchMachineState *lams)
 g_free(nodename);
 }
 
-static void fdt_add_rtc_node(LoongArchMachineState *lams)
+static void fdt_add_rtc_node(LoongArchMachineState *lams,
+ uint32_t *pch_pic_phandle)
 {
 char *nodename;
 hwaddr base = VIRT_RTC_REG_BASE;
@@ -240,8 +241,13 @@ static void fdt_add_rtc_node(LoongArchMachineState *lams)
 
 nodename = g_strdup_printf("/rtc@%" PRIx64, base);
 qemu_fdt_add_subnode(ms->fdt, nodename);
-qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 
"loongson,ls7a-rtc");
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,ls7a-rtc");
 qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
+   VIRT_RTC_IRQ - VIRT_GSI_BASE , 0x4);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *pch_pic_phandle);
 g_free(nodename);
 }
 
@@ -648,7 +654,7 @@ static void loongarch_devices_init(DeviceState *pch_pic,
 sysbus_create_simple("ls7a_rtc", VIRT_RTC_REG_BASE,
  qdev_get_gpio_in(pch_pic,
  VIRT_RTC_IRQ - VIRT_GSI_BASE));
-fdt_add_rtc_node(lams);
+fdt_add_rtc_node(lams, pch_pic_phandle);
 
 /* acpi ged */
 lams->acpi_ged = create_acpi_ged(pch_pic, lams);
-- 
2.25.1




[PULL v2 09/17] hw/loongarch: Fix fdt memory node wrong 'reg'

2024-04-28 Thread Song Gao
The right fdt memory node like [1], not [2]

  [1]
memory@0 {
device_type = "memory";
reg = <0x00 0x00 0x00 0x1000>;
};
  [2]
memory@0 {
device_type = "memory";
reg = <0x02 0x00 0x02 0x1000>;
};

Reviewed-by: Bibo Mao 
Signed-off-by: Song Gao 
Message-Id: <20240426091551.2397867-10-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 42e5df8a24..032f5f2ddf 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -325,7 +325,7 @@ static void fdt_add_memory_node(MachineState *ms,
 char *nodename = g_strdup_printf("/memory@%" PRIx64, base);
 
 qemu_fdt_add_subnode(ms->fdt, nodename);
-qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, 0, size);
 qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory");
 
 if (ms->numa_state && ms->numa_state->num_nodes) {
-- 
2.25.1




[PULL v2 16/17] hw/loongarch: Add cells missing from uart node

2024-04-28 Thread Song Gao
uart node need interrupts and interrupt-parent cells.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-17-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 48f73edd8e..dbd7928759 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -245,7 +245,8 @@ static void fdt_add_rtc_node(LoongArchMachineState *lams)
 g_free(nodename);
 }
 
-static void fdt_add_uart_node(LoongArchMachineState *lams)
+static void fdt_add_uart_node(LoongArchMachineState *lams,
+  uint32_t *pch_pic_phandle)
 {
 char *nodename;
 hwaddr base = VIRT_UART_BASE;
@@ -258,6 +259,10 @@ static void fdt_add_uart_node(LoongArchMachineState *lams)
 qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size);
 qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 1);
 qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
+   VIRT_UART_IRQ - VIRT_GSI_BASE, 0x4);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *pch_pic_phandle);
 g_free(nodename);
 }
 
@@ -630,7 +635,7 @@ static void loongarch_devices_init(DeviceState *pch_pic,
qdev_get_gpio_in(pch_pic,
 VIRT_UART_IRQ - VIRT_GSI_BASE),
115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
-fdt_add_uart_node(lams);
+fdt_add_uart_node(lams, pch_pic_phandle);
 
 /* Network init */
 pci_init_nic_devices(pci_bus, mc->default_nic);
-- 
2.25.1




[PULL v2 04/17] hw/loongarch: Add init_cmdline

2024-04-28 Thread Song Gao
Add init_cmline and set boot_info->a0, a1

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-5-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 30 ++
 include/hw/loongarch/virt.h |  2 ++
 target/loongarch/cpu.h  |  2 ++
 3 files changed, 34 insertions(+)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index fb6effbaff..127085bcc4 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -63,6 +63,16 @@ static const unsigned int slave_boot_code[] = {
 0x4c20,   /* jirl   $zero, $ra,0   */
 };
 
+static void init_cmdline(struct loongarch_boot_info *info, void *p, void 
*start)
+{
+hwaddr cmdline_addr = p - start;
+
+info->a0 = 1;
+info->a1 = cmdline_addr;
+
+memcpy(p, info->kernel_cmdline, COMMAND_LINE_SIZE);
+}
+
 static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
 {
 return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
@@ -121,6 +131,10 @@ static void reset_load_elf(void *opaque)
 
 cpu_reset(CPU(cpu));
 if (env->load_elf) {
+   if (cpu == LOONGARCH_CPU(first_cpu)) {
+env->gpr[4] = env->boot_info->a0;
+env->gpr[5] = env->boot_info->a1;
+}
 cpu_set_pc(CPU(cpu), env->elf_address);
 }
 }
@@ -158,8 +172,17 @@ static void loongarch_firmware_boot(LoongArchMachineState 
*lams,
 fw_cfg_add_kernel_info(info, lams->fw_cfg);
 }
 
+static void init_boot_rom(struct loongarch_boot_info *info, void *p)
+{
+void *start = p;
+
+init_cmdline(info, p, start);
+p += COMMAND_LINE_SIZE;
+}
+
 static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
 {
+void *p, *bp;
 int64_t kernel_addr = 0;
 LoongArchCPU *lacpu;
 CPUState *cs;
@@ -173,6 +196,12 @@ static void loongarch_direct_kernel_boot(struct 
loongarch_boot_info *info)
 }
 }
 
+/* Load cmdline and system tables at [0 - 1 MiB] */
+p = g_malloc0(1 * MiB);
+bp = p;
+init_boot_rom(info, p);
+rom_add_blob_fixed_as("boot_info", bp, 1 * MiB, 0, &address_space_memory);
+
 /* Load slave boot code at pflash0 . */
 void *boot_code = g_malloc0(VIRT_FLASH0_SIZE);
 memcpy(boot_code, &slave_boot_code, sizeof(slave_boot_code));
@@ -190,6 +219,7 @@ static void loongarch_direct_kernel_boot(struct 
loongarch_boot_info *info)
 }
 
 g_free(boot_code);
+g_free(bp);
 }
 
 void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index cf2f2bfb19..d7a074d69f 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -33,6 +33,8 @@
 #define VIRT_GED_MEM_ADDR   (VIRT_GED_EVT_ADDR + ACPI_GED_EVT_SEL_LEN)
 #define VIRT_GED_REG_ADDR   (VIRT_GED_MEM_ADDR + MEMORY_HOTPLUG_IO_LEN)
 
+#define COMMAND_LINE_SIZE   512
+
 struct LoongArchMachineState {
 /*< private >*/
 MachineState parent_obj;
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index abb01b2cc7..c5722670f5 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -359,6 +359,8 @@ typedef struct CPUArchState {
 uint32_t mp_state;
 /* Store ipistate to access from this struct */
 DeviceState *ipistate;
+
+struct loongarch_boot_info *boot_info;
 #endif
 } CPULoongArchState;
 
-- 
2.25.1




[PULL v2 14/17] hw/loongarch: fdt adds pcie irq_map node

2024-04-28 Thread Song Gao
This patch adds pcie irq_map node for FDT.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-15-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 73 ++---
 1 file changed, 69 insertions(+), 4 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 566f86e741..91a55a81b6 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -352,7 +352,62 @@ static void fdt_add_fw_cfg_node(const 
LoongArchMachineState *lams)
 g_free(nodename);
 }
 
-static void fdt_add_pcie_node(const LoongArchMachineState *lams)
+static void fdt_add_pcie_irq_map_node(const LoongArchMachineState *lams,
+  char *nodename,
+  uint32_t *pch_pic_phandle)
+{
+int pin, dev;
+uint32_t irq_map_stride = 0;
+uint32_t full_irq_map[GPEX_NUM_IRQS *GPEX_NUM_IRQS * 10] = {};
+uint32_t *irq_map = full_irq_map;
+const MachineState *ms = MACHINE(lams);
+
+/* This code creates a standard swizzle of interrupts such that
+ * each device's first interrupt is based on it's PCI_SLOT number.
+ * (See pci_swizzle_map_irq_fn())
+ *
+ * We only need one entry per interrupt in the table (not one per
+ * possible slot) seeing the interrupt-map-mask will allow the table
+ * to wrap to any number of devices.
+ */
+
+for (dev = 0; dev < GPEX_NUM_IRQS; dev++) {
+int devfn = dev * 0x8;
+
+for (pin = 0; pin  < GPEX_NUM_IRQS; pin++) {
+int irq_nr = 16 + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
+int i = 0;
+
+/* Fill PCI address cells */
+irq_map[i] = cpu_to_be32(devfn << 8);
+i += 3;
+
+/* Fill PCI Interrupt cells */
+irq_map[i] = cpu_to_be32(pin + 1);
+i += 1;
+
+/* Fill interrupt controller phandle and cells */
+irq_map[i++] = cpu_to_be32(*pch_pic_phandle);
+irq_map[i++] = cpu_to_be32(irq_nr);
+
+if (!irq_map_stride) {
+irq_map_stride = i;
+}
+irq_map += irq_map_stride;
+}
+}
+
+
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-map", full_irq_map,
+ GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+ irq_map_stride * sizeof(uint32_t));
+qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupt-map-mask",
+ 0x1800, 0, 0, 0x7);
+}
+
+static void fdt_add_pcie_node(const LoongArchMachineState *lams,
+  uint32_t *pch_pic_phandle,
+  uint32_t *pch_msi_phandle)
 {
 char *nodename;
 hwaddr base_mmio = VIRT_PCI_MEM_BASE;
@@ -383,6 +438,11 @@ static void fdt_add_pcie_node(const LoongArchMachineState 
*lams)
  2, base_pio, 2, size_pio,
  1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
  2, base_mmio, 2, size_mmio);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "msi-map",
+   0, *pch_msi_phandle, 0, 0x1);
+
+fdt_add_pcie_irq_map_node(lams, nodename, pch_pic_phandle);
+
 g_free(nodename);
 }
 
@@ -542,7 +602,10 @@ static DeviceState *create_platform_bus(DeviceState 
*pch_pic)
 return dev;
 }
 
-static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState 
*lams)
+static void loongarch_devices_init(DeviceState *pch_pic,
+   LoongArchMachineState *lams,
+   uint32_t *pch_pic_phandle,
+   uint32_t *pch_msi_phandle)
 {
 MachineClass *mc = MACHINE_GET_CLASS(lams);
 DeviceState *gpex_dev;
@@ -588,6 +651,9 @@ static void loongarch_devices_init(DeviceState *pch_pic, 
LoongArchMachineState *
 gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i);
 }
 
+/* Add pcie node */
+fdt_add_pcie_node(lams, pch_pic_phandle, pch_msi_phandle);
+
 serial_mm_init(get_system_memory(), VIRT_UART_BASE, 0,
qdev_get_gpio_in(pch_pic,
 VIRT_UART_IRQ - VIRT_GSI_BASE),
@@ -734,7 +800,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 /* Add PCH MSI node */
 fdt_add_pch_msi_node(lams, &eiointc_phandle, &pch_msi_phandle);
 
-loongarch_devices_init(pch_pic, lams);
+loongarch_devices_init(pch_pic, lams, &pch_pic_phandle, &pch_msi_phandle);
 }
 
 static void loongarch_firmware_init(LoongArchMachineState *lams)
@@ -956,7 +1022,6 @@ static void loongarch_init(MachineState *machine)
 lams->powerdown_notifier.notify = virt_powerdown_req;
 qemu_register_powerdown_notifier(&lams->powerdown_notifier);
 
-fdt_add_pcie_node(lams);
 /*
  * Since lowmem region starts from 0 and Linux kernel legacy start address
  * at 2 MiB, FDT base address is located at 1 MiB to avoid NULL pointer
-- 
2.25.1




[PULL v2 10/17] hw/loongarch: fdt adds cpu interrupt controller node

2024-04-28 Thread Song Gao
fdt adds cpu interrupt controller node,
we use 'loongson,cpu-interrupt-controller'.

See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongarch-cpu.c
https://lore.kernel.org/r/20221114113824.1880-2-liupei...@loongson.cn

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-11-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 21 +
 1 file changed, 21 insertions(+)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 032f5f2ddf..88cdcb6f91 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -106,6 +106,23 @@ static void virt_flash_map(LoongArchMachineState *lams,
 virt_flash_map1(flash1, VIRT_FLASH1_BASE, VIRT_FLASH1_SIZE, sysmem);
 }
 
+static void fdt_add_cpuic_node(LoongArchMachineState *lams,
+   uint32_t *cpuintc_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+
+*cpuintc_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/cpuic");
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *cpuintc_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,cpu-interrupt-controller");
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -528,6 +545,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
+uint32_t cpuintc_phandle;
 
 /*
  * The connection of interrupts:
@@ -562,6 +580,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 memory_region_add_subregion(&lams->system_iocsr, MAIL_SEND_ADDR,
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
 
+/* Add cpu interrupt-controller */
+fdt_add_cpuic_node(lams, &cpuintc_phandle);
+
 for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
 cpu_state = qemu_get_cpu(cpu);
 cpudev = DEVICE(cpu_state);
-- 
2.25.1




[PULL v2 05/17] hw/loongarch: Init efi_system_table

2024-04-28 Thread Song Gao
Add init_systab and set boot_info->a2

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-6-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 22 +
 include/hw/loongarch/boot.h | 48 +
 2 files changed, 70 insertions(+)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 127085bcc4..59889dbc90 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -63,6 +63,25 @@ static const unsigned int slave_boot_code[] = {
 0x4c20,   /* jirl   $zero, $ra,0   */
 };
 
+static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
+{
+struct efi_system_table *systab = p;
+
+info->a2 = p - start;
+
+systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE;
+systab->hdr.revision = EFI_SPECIFICATION_VERSION;
+systab->hdr.revision = sizeof(struct efi_system_table),
+systab->fw_revision = FW_VERSION << 16 | FW_PATCHLEVEL << 8;
+systab->runtime = 0;
+systab->boottime = 0;
+systab->nr_tables = 0;
+
+p += ROUND_UP(sizeof(struct efi_system_table), 64 * KiB);
+
+systab->tables = p;
+}
+
 static void init_cmdline(struct loongarch_boot_info *info, void *p, void 
*start)
 {
 hwaddr cmdline_addr = p - start;
@@ -134,6 +153,7 @@ static void reset_load_elf(void *opaque)
if (cpu == LOONGARCH_CPU(first_cpu)) {
 env->gpr[4] = env->boot_info->a0;
 env->gpr[5] = env->boot_info->a1;
+env->gpr[6] = env->boot_info->a2;
 }
 cpu_set_pc(CPU(cpu), env->elf_address);
 }
@@ -178,6 +198,8 @@ static void init_boot_rom(struct loongarch_boot_info *info, 
void *p)
 
 init_cmdline(info, p, start);
 p += COMMAND_LINE_SIZE;
+
+init_systab(info, p, start);
 }
 
 static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index 3275c1e295..cf0e4d4f91 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -8,6 +8,54 @@
 #ifndef HW_LOONGARCH_BOOT_H
 #define HW_LOONGARCH_BOOT_H
 
+/* UEFI 2.10 */
+#define EFI_SYSTEM_TABLE_SIGNATURE   0x5453595320494249
+#define EFI_2_100_SYSTEM_TABLE_REVISION  ((2<<16) | (100))
+#define EFI_SPECIFICATION_VERSIONEFI_SYSTEM_TABLE_REVISION
+#define EFI_SYSTEM_TABLE_REVISIONEFI_2_100_SYSTEM_TABLE_REVISION
+
+#define FW_VERSION 0x1
+#define FW_PATCHLEVEL 0x0
+
+typedef struct {
+uint8_t b[16];
+} efi_guid_t QEMU_ALIGNED(8);
+
+struct efi_config_table {
+efi_guid_t guid;
+uint64_t *ptr;
+const char name[16];
+};
+
+typedef struct {
+uint64_t signature;
+uint32_t revision;
+uint32_t headersize;
+uint32_t crc32;
+uint32_t reserved;
+} efi_table_hdr_t;
+
+struct efi_configuration_table {
+efi_guid_t guid;
+void *table;
+};
+
+struct efi_system_table {
+efi_table_hdr_t hdr;
+uint64_t fw_vendor;/* physical addr of CHAR16 vendor string */
+uint32_t fw_revision;
+uint64_t con_in_handle;
+uint64_t *con_in;
+uint64_t con_out_handle;
+uint64_t *con_out;
+uint64_t stderr_handle;
+uint64_t stderr_placeholder;
+uint64_t *runtime;
+uint64_t *boottime;
+uint64_t nr_tables;
+struct efi_configuration_table *tables;
+};
+
 struct loongarch_boot_info {
 uint64_t ram_size;
 const char *kernel_filename;
-- 
2.25.1




[PULL v2 01/17] hw/loongarch: Move boot functions to boot.c

2024-04-28 Thread Song Gao
Move some boot functions to boot.c and struct
loongarch_boot_info into struct LoongArchMachineState.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Reviewed-by: Philippe Mathieu-Daudé 
Message-Id: <20240426091551.2397867-2-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 128 
 hw/loongarch/meson.build|   1 +
 hw/loongarch/virt.c | 121 +++---
 include/hw/loongarch/boot.h |  21 ++
 include/hw/loongarch/virt.h |   2 +
 5 files changed, 160 insertions(+), 113 deletions(-)
 create mode 100644 hw/loongarch/boot.c
 create mode 100644 include/hw/loongarch/boot.h

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
new file mode 100644
index 00..9feed17db3
--- /dev/null
+++ b/hw/loongarch/boot.c
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch boot helper functions.
+ *
+ * Copyright (c) 2023 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "target/loongarch/cpu.h"
+#include "hw/loongarch/virt.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "qemu/error-report.h"
+#include "sysemu/reset.h"
+#include "sysemu/qtest.h"
+
+static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
+{
+return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
+}
+
+static int64_t load_kernel_info(struct loongarch_boot_info *info)
+{
+uint64_t kernel_entry, kernel_low, kernel_high;
+ssize_t kernel_size;
+
+kernel_size = load_elf(info->kernel_filename, NULL,
+   cpu_loongarch_virt_to_phys, NULL,
+   &kernel_entry, &kernel_low,
+   &kernel_high, NULL, 0,
+   EM_LOONGARCH, 1, 0);
+
+if (kernel_size < 0) {
+error_report("could not load kernel '%s': %s",
+ info->kernel_filename,
+ load_elf_strerror(kernel_size));
+exit(1);
+}
+return kernel_entry;
+}
+
+static void reset_load_elf(void *opaque)
+{
+LoongArchCPU *cpu = opaque;
+CPULoongArchState *env = &cpu->env;
+
+cpu_reset(CPU(cpu));
+if (env->load_elf) {
+cpu_set_pc(CPU(cpu), env->elf_address);
+}
+}
+
+static void fw_cfg_add_kernel_info(struct loongarch_boot_info *info,
+   FWCfgState *fw_cfg)
+{
+/*
+ * Expose the kernel, the command line, and the initrd in fw_cfg.
+ * We don't process them here at all, it's all left to the
+ * firmware.
+ */
+load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
+ info->kernel_filename,
+ false);
+
+if (info->initrd_filename) {
+load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
+ info->initrd_filename, false);
+}
+
+if (info->kernel_cmdline) {
+fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+   strlen(info->kernel_cmdline) + 1);
+fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
+  info->kernel_cmdline);
+}
+}
+
+static void loongarch_firmware_boot(LoongArchMachineState *lams,
+struct loongarch_boot_info *info)
+{
+fw_cfg_add_kernel_info(info, lams->fw_cfg);
+}
+
+static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
+{
+int64_t kernel_addr = 0;
+LoongArchCPU *lacpu;
+CPUState *cs;
+
+if (info->kernel_filename) {
+kernel_addr = load_kernel_info(info);
+} else {
+if(!qtest_enabled()) {
+error_report("Need kernel filename\n");
+exit(1);
+}
+}
+
+CPU_FOREACH(cs) {
+lacpu = LOONGARCH_CPU(cs);
+lacpu->env.load_elf = true;
+lacpu->env.elf_address = kernel_addr;
+}
+}
+
+void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
+{
+LoongArchMachineState *lams = LOONGARCH_MACHINE(ms);
+int i;
+
+/* register reset function */
+for (i = 0; i < ms->smp.cpus; i++) {
+qemu_register_reset(reset_load_elf, LOONGARCH_CPU(qemu_get_cpu(i)));
+}
+
+info->kernel_filename = ms->kernel_filename;
+info->kernel_cmdline = ms->kernel_cmdline;
+info->initrd_filename = ms->initrd_filename;
+
+if (lams->bios_loaded) {
+loongarch_firmware_boot(lams, info);
+} else {
+loongarch_direct_kernel_boot(info);
+}
+}
diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build
index c0421502ab..d306d82c2e 100644
--- a/hw/loongarch/meson.build
+++ b/hw/loongarch/meson.build
@@ -1,6 +1,7 @@
 loongarch_ss = ss.source_set()
 loongarch_ss.add(files(
 'fw_cfg.c',
+'boot.c',
 ))
 loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: [files('virt.c'), 
fdt])
 loongarch_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-build.c'

[PULL v2 13/17] hw/loongarch: fdt adds pch_msi Controller

2024-04-28 Thread Song Gao
fdt adds pch msi controller, we use 'loongson,pch-msi-1.0'.

See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-pch-msi.c
https://lore.kernel.org/r/20200528152757.1028711-6-jiaxun.y...@flygoat.com

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-14-gaos...@loongson.cn>
---
 hw/loongarch/virt.c| 33 -
 include/hw/pci-host/ls7a.h |  1 +
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 5bef161d11..566f86e741 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -173,6 +173,34 @@ static void fdt_add_pch_pic_node(LoongArchMachineState 
*lams,
 g_free(nodename);
 }
 
+static void fdt_add_pch_msi_node(LoongArchMachineState *lams,
+ uint32_t *eiointc_phandle,
+ uint32_t *pch_msi_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+hwaddr pch_msi_base = VIRT_PCH_MSI_ADDR_LOW;
+hwaddr pch_msi_size = VIRT_PCH_MSI_SIZE;
+
+*pch_msi_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/msi@%" PRIx64, pch_msi_base);
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_msi_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,pch-msi-1.0");
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg",
+   0, pch_msi_base,
+   0, pch_msi_size);
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *eiointc_phandle);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-base-vec",
+  VIRT_PCH_PIC_IRQ_NUM);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-num-vecs",
+  EXTIOI_IRQS - VIRT_PCH_PIC_IRQ_NUM);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -595,7 +623,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
-uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle;
+uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle, 
pch_msi_phandle;
 
 /*
  * The connection of interrupts:
@@ -703,6 +731,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
   qdev_get_gpio_in(extioi, i + start));
 }
 
+/* Add PCH MSI node */
+fdt_add_pch_msi_node(lams, &eiointc_phandle, &pch_msi_phandle);
+
 loongarch_devices_init(pch_pic, lams);
 }
 
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index fe260f0183..cd7c9ec7bc 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -25,6 +25,7 @@
 #define VIRT_IOAPIC_REG_BASE (VIRT_PCH_REG_BASE)
 #define VIRT_PCH_MSI_ADDR_LOW0x2FF0UL
 #define VIRT_PCH_REG_SIZE0x400
+#define VIRT_PCH_MSI_SIZE0x8
 
 /*
  * GSI_BASE is hard-coded with 64 in linux kernel, else kernel fails to boot
-- 
2.25.1




[PULL v2 00/17] loongarch-to-apply queue

2024-04-28 Thread Song Gao
The following changes since commit fd87be1dada5672f877e03c2ca8504458292c479:

  Merge tag 'accel-20240426' of https://github.com/philmd/qemu into staging 
(2024-04-26 15:28:13 -0700)

are available in the Git repository at:

  https://gitlab.com/gaosong/qemu.git tags/pull-loongarch-20240429

for you to fetch changes up to 841ef2c9df5317e32de590424b0c5c36fbb4de78:

  hw/loongarch: Add cells missing from rtc node (2024-04-29 10:25:56 +0800)


Add boot LoongArch elf kernel with FDT

v2: Fix 'make check-tcg' failed.


Song Gao (17):
  hw/loongarch: Move boot functions to boot.c
  hw/loongarch: Add load initrd
  hw/loongarch: Add slave cpu boot_code
  hw/loongarch: Add init_cmdline
  hw/loongarch: Init efi_system_table
  hw/loongarch: Init efi_boot_memmap table
  hw/loongarch: Init efi_initrd table
  hw/loongarch: Init efi_fdt table
  hw/loongarch: Fix fdt memory node wrong 'reg'
  hw/loongarch: fdt adds cpu interrupt controller node
  hw/loongarch: fdt adds Extend I/O Interrupt Controller
  hw/loongarch: fdt adds pch_pic Controller
  hw/loongarch: fdt adds pch_msi Controller
  hw/loongarch: fdt adds pcie irq_map node
  hw/loongarch: fdt remove unused irqchip node
  hw/loongarch: Add cells missing from uart node
  hw/loongarch: Add cells missing from rtc node

 hw/loongarch/boot.c| 336 ++
 hw/loongarch/meson.build   |   1 +
 hw/loongarch/virt.c| 365 +
 include/hw/intc/loongarch_extioi.h |   1 +
 include/hw/loongarch/boot.h| 109 +++
 include/hw/loongarch/virt.h|  16 ++
 include/hw/pci-host/ls7a.h |   2 +
 target/loongarch/cpu.h |   2 +
 8 files changed, 670 insertions(+), 162 deletions(-)
 create mode 100644 hw/loongarch/boot.c
 create mode 100644 include/hw/loongarch/boot.h




  1   2   3   >