[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v2 5/5] xen/arm: Support ARM standard PV time for domains created via toolstack


  • To: xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Koichiro Den <den@xxxxxxxxxxxxx>
  • Date: Sat, 5 Jul 2025 23:27:03 +0900
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=valinux.co.jp; dmarc=pass action=none header.from=valinux.co.jp; dkim=pass header.d=valinux.co.jp; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Nnrprq8cKz+z61aN0ctsSnuccFtU6U8bKDUu7U3f/8M=; b=Z8xwkc6rTSD2/xS5HwJCL7jjZNG6zR980hFIdCclrCk4nZ9YNppg5fZAVW03Q0lxxQiNbad5Th7+tXFUSy4nX+iuks5iPyIvGJw/HwaN1qnNZv52NRLrNhbNxcCDGnHIOONuQQ6nQz/xbp21cahi7hmKTf6dqZW9kSw3FWSpQzBkgwUDe8gnhegmY0+rNrRm2k/2oj+sWse6BQzrqIHQP9gQAM17c5pvrMcyn+W8OyYMPG9gg+l7b0XTM+FICfSJcJQuyE6IdPcq8HVHahNgjzqoUKuW2uyvhp6tjtQYFC3W0LhKU50nX99EX/QM0pLEW201/AekVF4M9WRnXFM/+Q==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Ys7ouQXjJukv5QFgSsrYD8Rh9azgdrgel6H+KjBChBdstfXDahAUKhthz3az5kTaS8ZfvGJvnX6AR1zhybreIiytN/YAx1yW/UbQwaacDwThjHb0wSjaqYx5LdeeDf8bl/Wq5PPi+PlLM1LnuZ+Zh33/o5y75vPA16kfuc42hnSbuH0H+zYCbzW8YgjA3dO/5FI347MgvKSSJzBmo3DBReJpEx0+okfUGwzHxbpIrVDtduZfzRK1HC1KG9XqhvrVgQtC79ctriVyGL6n/0DKZMkPyr2CabfHu9kcBooO2hUh6RhxO55LQ30ySHxpgSzdnnIon8VNgGxtltkHCP8MMg==
  • Authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=valinux.co.jp;
  • Cc: Koichiro Den <den@xxxxxxxxxxxxx>, Anthony PERARD <anthony.perard@xxxxxxxxxx>, Juergen Gross <jgross@xxxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Jan Beulich <jbeulich@xxxxxxxx>, Julien Grall <julien@xxxxxxx>, Roger Pau Monné <roger.pau@xxxxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>
  • Delivery-date: Sat, 05 Jul 2025 14:27:44 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

Implement ARM DEN 0057A PV time support for domains created via the
toolstack, utilizing the newly introduced XENMAPSPACE_pv_time.

Signed-off-by: Koichiro Den <den@xxxxxxxxxxxxx>
---
 tools/libs/light/libxl_arm.c | 185 ++++++++++++++++++++++++++++-------
 xen/arch/arm/mm.c            |  14 +++
 xen/include/public/memory.h  |   1 +
 3 files changed, 167 insertions(+), 33 deletions(-)

diff --git a/tools/libs/light/libxl_arm.c b/tools/libs/light/libxl_arm.c
index 4a19a8d22bdf..33251520c07a 100644
--- a/tools/libs/light/libxl_arm.c
+++ b/tools/libs/light/libxl_arm.c
@@ -684,6 +684,40 @@ static int make_memory_nodes(libxl__gc *gc, void *fdt,
     return 0;
 }
 
+static int make_resv_memory_node(libxl__gc *gc, void *fdt,
+                                 const struct xc_dom_image *dom)
+{
+    int res;
+
+    if (strcmp(dom->guest_type, "xen-3.0-aarch64"))
+        /*
+         * The stolen time shared memory region for ARM DEN 0057A is currently
+         * the only user of /reserved-memory node when a domain is created via
+         * the toolstack, and it requires both the hypervisor and the domain to
+         * be AArch64.
+         */
+        return 0;
+
+    res = fdt_begin_node(fdt, "reserved-memory");
+    if (res) return res;
+
+    res = fdt_property_cell(fdt, "#address-cells", GUEST_ROOT_ADDRESS_CELLS);
+    if (res) return res;
+
+    res = fdt_property_cell(fdt, "#size-cells", GUEST_ROOT_SIZE_CELLS);
+    if (res) return res;
+
+    /* reg 0 is a placeholder for PV time region */
+    res = fdt_property_reg_placeholder(gc, fdt, GUEST_ROOT_ADDRESS_CELLS,
+                                       GUEST_ROOT_SIZE_CELLS, 1);
+    if (res) return res;
+
+    res = fdt_end_node(fdt);
+    if (res) return res;
+
+    return 0;
+}
+
 static int make_gicv2_node(libxl__gc *gc, void *fdt,
                            uint64_t gicd_base, uint64_t gicd_size,
                            uint64_t gicc_base, uint64_t gicc_size)
@@ -1352,6 +1386,7 @@ next_resize:
         FDT( make_psci_node(gc, fdt) );
 
         FDT( make_memory_nodes(gc, fdt, dom) );
+        FDT( make_resv_memory_node(gc, fdt, dom) );
 
         switch (info->arch_arm.gic_version) {
         case LIBXL_GIC_VERSION_V2:
@@ -1519,6 +1554,9 @@ static void finalise_one_node(libxl__gc *gc, void *fdt, 
const char *uname,
 
 #define EXT_REGION_MIN_SIZE   xen_mk_ullong(0x0004000000) /* 64MB */
 
+/* As per ARM DEN 0057A, stolen time memory regions are 64-byte aligned */
+#define PV_REGIONS_PER_PAGE  (XC_PAGE_SIZE / 64)
+
 static int compare_iomem(const void *a, const void *b)
 {
     const libxl_iomem_range *x = a, *y = b;
@@ -1530,24 +1568,92 @@ static int compare_iomem(const void *a, const void *b)
     return 0;
 }
 
-static int finalize_hypervisor_node(libxl__gc *gc,
-                                    libxl_domain_build_info *b_info,
-                                    struct xc_dom_image *dom)
+static int get_pv_region(libxl_domain_build_info *b_info,
+                         struct xc_dom_image *dom,
+                         uint64_t *start, uint64_t end,
+                         uint64_t *region_base, uint64_t *region_size)
+{
+    unsigned int npages = DIV_ROUNDUP(b_info->max_vcpus, PV_REGIONS_PER_PAGE);
+    unsigned int len = npages * XC_PAGE_SIZE;
+    uint32_t domid = dom->guest_domid;
+    xc_interface *xch = dom->xch;
+    unsigned long idx = 0;
+    uint64_t size;
+    int rc;
+
+    if (*start >= end)
+        return -1;
+    size = end - *start;
+    if (size < len)
+        return -1;
+
+    for (; npages; npages--, idx++) {
+        rc = xc_domain_add_to_physmap(xch, domid, XENMAPSPACE_pv_time, idx,
+                                      (*start >> XC_PAGE_SHIFT) + idx);
+        if (rc)
+            return rc;
+    }
+
+    region_base[0] = *start;
+    region_size[0] = len;
+    *start += len;
+    return 0;
+}
+
+static void get_ext_region(uint64_t start, uint64_t end, uint64_t *region_base,
+                           uint64_t *region_size, unsigned int *nr_regions)
+{
+    uint64_t size;
+
+    start = ALIGN_UP_TO_2MB(start);
+    if (start >= end)
+        return;
+
+    size = end - start;
+    if (size < EXT_REGION_MIN_SIZE)
+        return;
+
+    region_base[*nr_regions] = start;
+    region_size[*nr_regions] = size;
+    (*nr_regions)++;
+}
+
+static int finalize_extra_regions(libxl__gc *gc,
+                                  libxl_domain_build_info *b_info,
+                                  struct xc_dom_image *dom)
 {
     void *fdt = dom->devicetree_blob;
-    uint64_t region_base[MAX_NR_EXT_REGIONS], region_size[MAX_NR_EXT_REGIONS];
-    uint32_t regs[(GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) *
+
+    /* For extended regions */
+    uint64_t ext_region_base[MAX_NR_EXT_REGIONS], 
ext_region_size[MAX_NR_EXT_REGIONS];
+    uint32_t ext_regs[(GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) *
                   (MAX_NR_EXT_REGIONS + 1)];
-    be32 *cells = &regs[0];
+    be32 *ext_cells = &ext_regs[0];
+    int hyp_offset;
+
+    /* For pv regions */
+    uint64_t pv_region_base[1], pv_region_size[1];
+    uint32_t pv_regs[GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS];
+    be32 *pv_cells = &pv_regs[0];
+    int resv_offset;
+
     const uint64_t bankbase[] = GUEST_RAM_BANK_BASES;
     const uint64_t banksize[] = GUEST_RAM_BANK_SIZES;
     unsigned int i, j, len, nr_regions = 0;
+    bool pv_region_pending = true;
     libxl_dominfo info;
-    int offset, rc;
+    int rc;
 
-    offset = fdt_path_offset(fdt, "/hypervisor");
-    if (offset < 0)
-        return offset;
+    resv_offset = fdt_path_offset(fdt, "/reserved-memory");
+    if (!strcmp(dom->guest_type, "xen-3.0-aarch64")) {
+        if (resv_offset < 0)
+            return resv_offset;
+    } else
+        pv_region_pending = false;
+
+    hyp_offset = fdt_path_offset(fdt, "/hypervisor");
+    if (hyp_offset < 0)
+        return hyp_offset;
 
     rc = libxl_domain_info(CTX, &info, dom->guest_domid);
     if (rc)
@@ -1572,8 +1678,7 @@ static int finalize_hypervisor_node(libxl__gc *gc,
         } unallocated;
         uint64_t unallocated_size = 0;
 
-        unallocated.start = bankbase[i] +
-            ALIGN_UP_TO_2MB((uint64_t)dom->rambank_size[i] << XC_PAGE_SHIFT);
+        unallocated.start = bankbase[i] + ((uint64_t)dom->rambank_size[i] << 
XC_PAGE_SHIFT);
 
         unallocated.end = ~0ULL >> (64 - info.gpaddr_bits);
         unallocated.end = min(unallocated.end, bankbase[i] + banksize[i] - 1);
@@ -1581,7 +1686,7 @@ static int finalize_hypervisor_node(libxl__gc *gc,
         if (unallocated.end >= unallocated.start)
             unallocated_size = unallocated.end - unallocated.start + 1;
 
-        if (unallocated_size < EXT_REGION_MIN_SIZE)
+        if (unallocated_size <= 0)
             continue;
 
         /* Exclude iomem */
@@ -1605,14 +1710,14 @@ static int finalize_hypervisor_node(libxl__gc *gc,
                     if (unallocated.start > unallocated.end)
                         break;
                 } else {
-                    uint64_t size = iomem.start - unallocated.start;
-
-                    if (size >= EXT_REGION_MIN_SIZE) {
-                        region_base[nr_regions] = unallocated.start;
-                        region_size[nr_regions] = size;
-                        nr_regions++;
+                    if (pv_region_pending) {
+                        rc = get_pv_region(b_info, dom, &unallocated.start, 
iomem.start,
+                                           pv_region_base, pv_region_size);
+                        if (!rc)
+                            pv_region_pending = false;
                     }
-
+                    get_ext_region(unallocated.start, iomem.start, 
ext_region_base,
+                                   ext_region_size, &nr_regions);
                     unallocated.start = iomem.end + 1;
 
                     if (unallocated.start > unallocated.end)
@@ -1624,38 +1729,52 @@ static int finalize_hypervisor_node(libxl__gc *gc,
         if (unallocated.end >= unallocated.start
             && nr_regions < MAX_NR_EXT_REGIONS)
         {
-            uint64_t size = unallocated.end - unallocated.start + 1;
-
-            if (size >= EXT_REGION_MIN_SIZE) {
-                region_base[nr_regions] = unallocated.start;
-                region_size[nr_regions] = size;
-                nr_regions++;
+            if (pv_region_pending) {
+                rc = get_pv_region(b_info, dom, &unallocated.start, 
unallocated.end,
+                                   pv_region_base, pv_region_size);
+                if (!rc)
+                    pv_region_pending = false;
             }
+            get_ext_region(unallocated.start, unallocated.end, ext_region_base,
+                           ext_region_size, &nr_regions);
         }
     }
 
+    if (!strcmp(dom->guest_type, "xen-3.0-aarch64")) {
+        if (pv_region_pending) {
+            LOG(ERROR, "The PV time region cannot be allocated, not enough 
space");
+            return ERROR_FAIL;
+        }
+        set_range(&pv_cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
+                  pv_region_base[0], pv_region_size[0]);
+        len = sizeof(pv_regs[0]) * (GUEST_ROOT_ADDRESS_CELLS + 
GUEST_ROOT_SIZE_CELLS);
+        rc = fdt_setprop(fdt, resv_offset, "reg", pv_regs, len);
+        if (rc)
+            return rc;
+    }
+
     /*
      * The region 0 for grant table space must be always present. If we managed
      * to allocate the extended regions then insert them as regions 1...N.
      */
-    set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
+    set_range(&ext_cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
               GUEST_GNTTAB_BASE, GUEST_GNTTAB_SIZE);
 
     for (i = 0; i < nr_regions; i++) {
         LOG(DEBUG, "Extended region %u: %#"PRIx64"->%#"PRIx64"",
-            i, region_base[i], region_base[i] + region_size[i] - 1);
+            i, ext_region_base[i], ext_region_base[i] + ext_region_size[i] - 
1);
 
-        set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
-                  region_base[i], region_size[i]);
+        set_range(&ext_cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
+                  ext_region_base[i], ext_region_size[i]);
     }
 
     if (!nr_regions)
         LOG(WARN, "The extended regions cannot be allocated, not enough 
space");
 
-    len = sizeof(regs[0]) * (GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) 
*
+    len = sizeof(ext_regs[0]) * (GUEST_ROOT_ADDRESS_CELLS + 
GUEST_ROOT_SIZE_CELLS) *
         (nr_regions + 1);
 
-    return fdt_setprop(fdt, offset, "reg", regs, len);
+    return fdt_setprop(fdt, hyp_offset, "reg", ext_regs, len);
 }
 
 int libxl__arch_domain_finalise_hw_description(libxl__gc *gc,
@@ -1698,7 +1817,7 @@ int libxl__arch_domain_finalise_hw_description(libxl__gc 
*gc,
 
     }
 
-    res = finalize_hypervisor_node(gc, &d_config->b_info, dom);
+    res = finalize_extra_regions(gc, &d_config->b_info, dom);
     if (res)
         return res;
 
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 0613c1916936..4741472ea1a0 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -180,7 +180,21 @@ int xenmem_add_to_physmap_one(
     case XENMAPSPACE_dev_mmio:
         rc = map_dev_mmio_page(d, gfn, _mfn(idx));
         return rc;
+    case XENMAPSPACE_pv_time:
+#ifdef CONFIG_ARM_64
+        ASSERT(IS_POWER_OF_TWO(sizeof(struct pv_time_region)));
+        if ( idx >= DIV_ROUND_UP(d->max_vcpus * sizeof(struct pv_time_region),
+                                 PAGE_SIZE) )
+            return -EINVAL;
+
+        if ( idx == 0 )
+            d->arch.pv_time_regions_gfn = gfn;
 
+        mfn = virt_to_mfn(d->arch.pv_time_regions[idx]);
+        t = p2m_ram_ro;
+
+        break;
+#endif
     default:
         return -ENOSYS;
     }
diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h
index bd9fc37b5297..4daa703e882e 100644
--- a/xen/include/public/memory.h
+++ b/xen/include/public/memory.h
@@ -217,6 +217,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_machphys_mapping_t);
                                       Stage-2 using the Normal Memory
                                       Inner/Outer Write-Back Cacheable
                                       memory attribute. */
+#define XENMAPSPACE_pv_time      6 /* PV time shared region (ARM64 only) */
 /* ` } */
 
 /*
-- 
2.48.1




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.