|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen master] device-tree: Move Arm's static-shmem feature to common
commit 72c5fa220804520839fd431ed19cd2b6eb04015a
Author: Michal Orzel <michal.orzel@xxxxxxx>
AuthorDate: Tue Jun 3 12:03:29 2025 +0200
Commit: Michal Orzel <michal.orzel@xxxxxxx>
CommitDate: Wed Jun 4 09:04:24 2025 +0200
device-tree: Move Arm's static-shmem feature to common
This feature is arch agnostic, thus move it to common.
Signed-off-by: Michal Orzel <michal.orzel@xxxxxxx>
Acked-by: Julien Grall <jgrall@xxxxxxxxxx>
---
xen/arch/arm/Kconfig | 6 -
xen/arch/arm/Makefile | 1 -
xen/arch/arm/arm32/mmu/mm.c | 2 +-
xen/arch/arm/arm64/mmu/mm.c | 2 +-
xen/arch/arm/dom0less-build.c | 2 +-
xen/arch/arm/domain_build.c | 2 +-
xen/arch/arm/include/asm/static-shmem.h | 94 ----
xen/arch/arm/static-shmem.c | 854 --------------------------------
xen/common/Kconfig | 6 +
xen/common/device-tree/Makefile | 1 +
xen/common/device-tree/bootfdt.c | 4 +-
xen/common/device-tree/dom0less-build.c | 9 +-
xen/common/device-tree/static-shmem.c | 854 ++++++++++++++++++++++++++++++++
xen/include/xen/static-shmem.h | 94 ++++
14 files changed, 961 insertions(+), 970 deletions(-)
diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index 57919d8b3a..3f25da3ca5 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -247,12 +247,6 @@ config ARM64_BTI
source "arch/arm/tee/Kconfig"
-config STATIC_SHM
- bool "Statically shared memory on a dom0less system" if UNSUPPORTED
- depends on STATIC_MEMORY
- help
- This option enables statically shared memory on a dom0less system.
-
config PARTIAL_EMULATION
bool "Enable partial emulation of system/coprocessor registers"
default y
diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 4f08014547..ab0a0c2be6 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -51,7 +51,6 @@ obj-y += setup.o
obj-y += shutdown.o
obj-y += smp.o
obj-y += smpboot.o
-obj-$(CONFIG_STATIC_SHM) += static-shmem.init.o
obj-y += sysctl.o
obj-y += time.o
obj-y += traps.o
diff --git a/xen/arch/arm/arm32/mmu/mm.c b/xen/arch/arm/arm32/mmu/mm.c
index f3305e28e9..4d22f35618 100644
--- a/xen/arch/arm/arm32/mmu/mm.c
+++ b/xen/arch/arm/arm32/mmu/mm.c
@@ -7,9 +7,9 @@
#include <xen/param.h>
#include <xen/pfn.h>
#include <xen/static-memory.h>
+#include <xen/static-shmem.h>
#include <asm/fixmap.h>
#include <asm/setup.h>
-#include <asm/static-shmem.h>
static unsigned long opt_xenheap_megabytes __initdata;
integer_param("xenheap_megabytes", opt_xenheap_megabytes);
diff --git a/xen/arch/arm/arm64/mmu/mm.c b/xen/arch/arm/arm64/mmu/mm.c
index cded8f2787..a0a2dd8cc7 100644
--- a/xen/arch/arm/arm64/mmu/mm.c
+++ b/xen/arch/arm/arm64/mmu/mm.c
@@ -5,9 +5,9 @@
#include <xen/mm.h>
#include <xen/pfn.h>
#include <xen/static-memory.h>
+#include <xen/static-shmem.h>
#include <asm/setup.h>
-#include <asm/static-shmem.h>
/* Override macros from asm/page.h to make them work with mfn_t */
#undef virt_to_mfn
diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c
index bcfd686a8b..20aabf6be5 100644
--- a/xen/arch/arm/dom0less-build.c
+++ b/xen/arch/arm/dom0less-build.c
@@ -13,6 +13,7 @@
#include <xen/serial.h>
#include <xen/sizes.h>
#include <xen/static-memory.h>
+#include <xen/static-shmem.h>
#include <xen/vmap.h>
#include <public/bootfdt.h>
@@ -23,7 +24,6 @@
#include <asm/domain_build.h>
#include <asm/grant_table.h>
#include <asm/setup.h>
-#include <asm/static-shmem.h>
#ifdef CONFIG_VGICV2
static int __init make_gicv2_domU_node(struct kernel_info *kinfo)
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 068af31a62..590f38e520 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -21,6 +21,7 @@
#include <xen/acpi.h>
#include <xen/vmap.h>
#include <xen/warning.h>
+#include <xen/static-shmem.h>
#include <asm/device.h>
#include <asm/setup.h>
#include <asm/tee/tee.h>
@@ -32,7 +33,6 @@
#include <asm/cpufeature.h>
#include <asm/dom0less-build.h>
#include <asm/domain_build.h>
-#include <asm/static-shmem.h>
#include <xen/event.h>
#include <xen/irq.h>
diff --git a/xen/arch/arm/include/asm/static-shmem.h
b/xen/arch/arm/include/asm/static-shmem.h
deleted file mode 100644
index 6a4c33cca8..0000000000
--- a/xen/arch/arm/include/asm/static-shmem.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-
-#ifndef __ASM_STATIC_SHMEM_H_
-#define __ASM_STATIC_SHMEM_H_
-
-#include <xen/fdt-kernel.h>
-#include <xen/types.h>
-
-#ifdef CONFIG_STATIC_SHM
-
-/* Worst case /memory node reg element: (addrcells + sizecells) */
-#define DT_MEM_NODE_REG_RANGE_SIZE ((NR_MEM_BANKS + NR_SHMEM_BANKS) * 4)
-
-int make_resv_memory_node(const struct kernel_info *kinfo, int addrcells,
- int sizecells);
-
-int process_shm(struct domain *d, struct kernel_info *kinfo,
- const struct dt_device_node *node);
-
-int process_shm_node(const void *fdt, int node, uint32_t address_cells,
- uint32_t size_cells);
-
-void early_print_info_shmem(void);
-
-void init_sharedmem_pages(void);
-
-int remove_shm_from_rangeset(const struct kernel_info *kinfo,
- struct rangeset *rangeset);
-
-int make_shm_resv_memory_node(const struct kernel_info *kinfo, int addrcells,
- int sizecells);
-
-void shm_mem_node_fill_reg_range(const struct kernel_info *kinfo, __be32 *reg,
- int *nr_cells, int addrcells, int sizecells);
-
-static inline struct membanks *
-kernel_info_get_shm_mem(struct kernel_info *kinfo)
-{
- return container_of(&kinfo->shm_mem.common, struct membanks, common);
-}
-
-static inline const struct membanks *
-kernel_info_get_shm_mem_const(const struct kernel_info *kinfo)
-{
- return container_of(&kinfo->shm_mem.common, const struct membanks, common);
-}
-
-#else /* !CONFIG_STATIC_SHM */
-
-/* Worst case /memory node reg element: (addrcells + sizecells) */
-#define DT_MEM_NODE_REG_RANGE_SIZE (NR_MEM_BANKS * 4)
-
-static inline int make_resv_memory_node(const struct kernel_info *kinfo,
- int addrcells, int sizecells)
-{
- return 0;
-}
-
-static inline int process_shm(struct domain *d, struct kernel_info *kinfo,
- const struct dt_device_node *node)
-{
- return 0;
-}
-
-static inline void init_sharedmem_pages(void) {};
-
-static inline int remove_shm_from_rangeset(const struct kernel_info *kinfo,
- struct rangeset *rangeset)
-{
- return 0;
-}
-
-static inline int make_shm_resv_memory_node(const struct kernel_info *kinfo,
- int addrcells, int sizecells)
-{
- return 0;
-}
-
-static inline void shm_mem_node_fill_reg_range(const struct kernel_info *kinfo,
- __be32 *reg, int *nr_cells,
- int addrcells, int sizecells)
{};
-
-#endif /* CONFIG_STATIC_SHM */
-
-#endif /* __ASM_STATIC_SHMEM_H_ */
-
-/*
- * Local variables:
- * mode: C
- * c-file-style: "BSD"
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/xen/arch/arm/static-shmem.c b/xen/arch/arm/static-shmem.c
deleted file mode 100644
index 2055b7be0f..0000000000
--- a/xen/arch/arm/static-shmem.c
+++ /dev/null
@@ -1,854 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-
-#include <xen/device_tree.h>
-#include <xen/fdt-domain-build.h>
-#include <xen/libfdt/libfdt.h>
-#include <xen/rangeset.h>
-#include <xen/sched.h>
-#include <xen/static-memory.h>
-
-#include <asm/setup.h>
-#include <asm/static-shmem.h>
-
-typedef struct {
- struct domain *d;
- const char *role_str;
- paddr_t gbase;
- struct shmem_membank_extra *bank_extra_info;
-} alloc_heap_pages_cb_extra;
-
-static struct {
- struct membanks_hdr common;
- struct membank bank[NR_SHMEM_BANKS];
-} shm_heap_banks __initdata = {
- .common.max_banks = NR_SHMEM_BANKS,
- .common.type = STATIC_SHARED_MEMORY
-};
-
-static inline struct membanks *get_shmem_heap_banks(void)
-{
- return container_of(&shm_heap_banks.common, struct membanks, common);
-}
-
-static void __init __maybe_unused build_assertions(void)
-{
- /*
- * Check that no padding is between struct membanks "bank" flexible array
- * member and struct shared_meminfo "bank" member
- */
- BUILD_BUG_ON((offsetof(struct membanks, bank) !=
- offsetof(struct shared_meminfo, bank)));
-}
-
-static const struct membank __init *
-find_shm_bank_by_id(const struct membanks *shmem, const char *shm_id)
-{
- unsigned int bank;
-
- for ( bank = 0 ; bank < shmem->nr_banks; bank++ )
- {
- if ( strcmp(shm_id, shmem->bank[bank].shmem_extra->shm_id) == 0 )
- break;
- }
-
- if ( bank == shmem->nr_banks )
- return NULL;
-
- return &shmem->bank[bank];
-}
-
-/*
- * This function checks whether the static shared memory region is
- * already allocated to dom_io.
- */
-static bool __init is_shm_allocated_to_domio(paddr_t pbase)
-{
- struct page_info *page;
- struct domain *d;
-
- page = maddr_to_page(pbase);
- d = page_get_owner_and_reference(page);
- if ( d == NULL )
- return false;
- put_page(page);
-
- if ( d != dom_io )
- {
- printk(XENLOG_ERR
- "shm memory node has already been allocated to a specific owner
%pd, Please check your configuration\n",
- d);
- return false;
- }
-
- return true;
-}
-
-static mfn_t __init acquire_shared_memory_bank(struct domain *d,
- paddr_t pbase, paddr_t psize,
- bool bank_from_heap)
-{
- mfn_t smfn;
- unsigned long nr_pfns;
- int res;
-
- /*
- * Pages of statically shared memory shall be included
- * into domain_tot_pages().
- */
- nr_pfns = PFN_DOWN(psize);
- if ( (UINT_MAX - d->max_pages) < nr_pfns )
- {
- printk(XENLOG_ERR "%pd: Over-allocation for d->max_pages: %lu.\n",
- d, nr_pfns);
- return INVALID_MFN;
- }
- d->max_pages += nr_pfns;
-
- smfn = maddr_to_mfn(pbase);
- if ( bank_from_heap )
- /*
- * When host address is not provided, static shared memory is
- * allocated from heap and shall be assigned to owner domain.
- */
- res = assign_pages(maddr_to_page(pbase), nr_pfns, d, 0);
- else
- res = acquire_domstatic_pages(d, smfn, nr_pfns, 0);
-
- if ( res )
- {
- printk(XENLOG_ERR "%pd: failed to %s static memory: %d.\n", d,
- bank_from_heap ? "assign" : "acquire", res);
- goto fail;
- }
-
- return smfn;
-
- fail:
- d->max_pages -= nr_pfns;
- return INVALID_MFN;
-}
-
-static int __init assign_shared_memory(struct domain *d, paddr_t gbase,
- bool bank_from_heap,
- const struct membank *shm_bank)
-{
- mfn_t smfn;
- int ret = 0;
- unsigned long nr_pages, nr_borrowers, i;
- struct page_info *page;
- paddr_t pbase, psize;
-
- pbase = shm_bank->start;
- psize = shm_bank->size;
- nr_borrowers = shm_bank->shmem_extra->nr_shm_borrowers;
-
- smfn = acquire_shared_memory_bank(d, pbase, psize, bank_from_heap);
- if ( mfn_eq(smfn, INVALID_MFN) )
- return -EINVAL;
-
- /*
- * DOMID_IO is not auto-translated (i.e. it sees RAM 1:1). So we do not
need
- * to create mapping in the P2M.
- */
- nr_pages = PFN_DOWN(psize);
- if ( d != dom_io )
- {
- ret = guest_physmap_add_pages(d, gaddr_to_gfn(gbase), smfn,
- PFN_DOWN(psize));
- if ( ret )
- {
- printk(XENLOG_ERR "Failed to map shared memory to %pd.\n", d);
- return ret;
- }
- }
-
- /*
- * Instead of letting borrower domain get a page ref, we add as many
- * additional reference as the number of borrowers when the owner
- * is allocated, since there is a chance that owner is created
- * after borrower.
- * So if the borrower is created first, it will cause adding pages
- * in the P2M without reference.
- */
- page = mfn_to_page(smfn);
- for ( i = 0; i < nr_pages; i++ )
- {
- if ( !get_page_nr(page + i, d, nr_borrowers) )
- {
- printk(XENLOG_ERR
- "Failed to add %lu references to page %"PRI_mfn".\n",
- nr_borrowers, mfn_x(smfn) + i);
- goto fail;
- }
- }
-
- return 0;
-
- fail:
- while ( --i >= 0 )
- put_page_nr(page + i, nr_borrowers);
- return ret;
-}
-
-static int __init
-append_shm_bank_to_domain(struct kernel_info *kinfo, paddr_t start,
- paddr_t size, const char *shm_id)
-{
- struct membanks *shm_mem = kernel_info_get_shm_mem(kinfo);
- struct shmem_membank_extra *shm_mem_extra;
-
- if ( shm_mem->nr_banks >= shm_mem->max_banks )
- return -ENOMEM;
-
- shm_mem_extra = &kinfo->shm_mem.extra[shm_mem->nr_banks];
-
- shm_mem->bank[shm_mem->nr_banks].start = start;
- shm_mem->bank[shm_mem->nr_banks].size = size;
- safe_strcpy(shm_mem_extra->shm_id, shm_id);
- shm_mem->bank[shm_mem->nr_banks].shmem_extra = shm_mem_extra;
- shm_mem->nr_banks++;
-
- return 0;
-}
-
-static int __init handle_shared_mem_bank(struct domain *d, paddr_t gbase,
- const char *role_str,
- bool bank_from_heap,
- const struct membank *shm_bank)
-{
- bool owner_dom_io = true;
- paddr_t pbase, psize;
- int ret;
-
- pbase = shm_bank->start;
- psize = shm_bank->size;
-
- /*
- * "role" property is optional and if it is defined explicitly,
- * then the owner domain is not the default "dom_io" domain.
- */
- if ( role_str != NULL )
- owner_dom_io = false;
-
- /*
- * DOMID_IO is a fake domain and is not described in the Device-Tree.
- * Therefore when the owner of the shared region is DOMID_IO, we will
- * only find the borrowers.
- */
- if ( (owner_dom_io && !is_shm_allocated_to_domio(pbase)) ||
- (!owner_dom_io && strcmp(role_str, "owner") == 0) )
- {
- /*
- * We found the first borrower of the region, the owner was not
- * specified, so they should be assigned to dom_io.
- */
- ret = assign_shared_memory(owner_dom_io ? dom_io : d, gbase,
- bank_from_heap, shm_bank);
- if ( ret )
- return ret;
- }
-
- if ( owner_dom_io || (strcmp(role_str, "borrower") == 0) )
- {
- /* Set up P2M foreign mapping for borrower domain. */
- ret = map_regions_p2mt(d, _gfn(PFN_UP(gbase)), PFN_DOWN(psize),
- _mfn(PFN_UP(pbase)), p2m_map_foreign_rw);
- if ( ret )
- return ret;
- }
-
- return 0;
-}
-
-static bool __init save_map_heap_pages(struct domain *d, struct page_info *pg,
- unsigned int order, void *extra)
-{
- alloc_heap_pages_cb_extra *b_extra = (alloc_heap_pages_cb_extra *)extra;
- int idx = shm_heap_banks.common.nr_banks;
- int ret = -ENOSPC;
-
- BUG_ON(!b_extra);
-
- if ( idx < shm_heap_banks.common.max_banks )
- {
- shm_heap_banks.bank[idx].start = page_to_maddr(pg);
- shm_heap_banks.bank[idx].size = (1ULL << (PAGE_SHIFT + order));
- shm_heap_banks.bank[idx].shmem_extra = b_extra->bank_extra_info;
- shm_heap_banks.common.nr_banks++;
-
- ret = handle_shared_mem_bank(b_extra->d, b_extra->gbase,
- b_extra->role_str, true,
- &shm_heap_banks.bank[idx]);
- if ( !ret )
- {
- /* Increment guest physical address for next mapping */
- b_extra->gbase += shm_heap_banks.bank[idx].size;
- return true;
- }
- }
-
- printk("Failed to allocate static shared memory from Xen heap: (%d)\n",
- ret);
-
- return false;
-}
-
-int __init process_shm(struct domain *d, struct kernel_info *kinfo,
- const struct dt_device_node *node)
-{
- struct dt_device_node *shm_node;
-
- /* Hwdom case - shm node under /chosen */
- if ( !node )
- {
- node = dt_find_node_by_path("/chosen");
- BUG_ON(!node);
- }
-
- dt_for_each_child_node(node, shm_node)
- {
- const struct membank *boot_shm_bank;
- const struct dt_property *prop;
- const __be32 *cells;
- uint32_t addr_cells;
- paddr_t gbase, pbase, psize;
- int ret = 0;
- unsigned int i;
- const char *role_str;
- const char *shm_id;
-
- if ( !dt_device_is_compatible(shm_node, "xen,domain-shared-memory-v1")
)
- continue;
-
- if ( dt_property_read_string(shm_node, "xen,shm-id", &shm_id) )
- {
- printk("%pd: invalid \"xen,shm-id\" property", d);
- return -EINVAL;
- }
- BUG_ON((strlen(shm_id) <= 0) || (strlen(shm_id) >= MAX_SHM_ID_LENGTH));
-
- boot_shm_bank = find_shm_bank_by_id(bootinfo_get_shmem(), shm_id);
- if ( !boot_shm_bank )
- {
- printk("%pd: static shared memory bank not found: '%s'", d,
shm_id);
- return -ENOENT;
- }
-
- pbase = boot_shm_bank->start;
- psize = boot_shm_bank->size;
-
- /* "role" property is optional */
- if ( dt_property_read_string(shm_node, "role", &role_str) != 0 )
- role_str = NULL;
-
- /*
- * xen,shared-mem = <[pbase,] gbase, size>;
- * pbase is optional.
- */
- addr_cells = dt_n_addr_cells(shm_node);
- prop = dt_find_property(shm_node, "xen,shared-mem", NULL);
- BUG_ON(!prop);
- cells = (const __be32 *)prop->value;
-
- if ( pbase != INVALID_PADDR )
- {
- /* guest phys address is after host phys address */
- gbase = dt_read_paddr(cells + addr_cells, addr_cells);
-
- if ( is_domain_direct_mapped(d) && (pbase != gbase) )
- {
- printk("%pd: physical address 0x%"PRIpaddr" and guest address
0x%"PRIpaddr" are not direct-mapped.\n",
- d, pbase, gbase);
- return -EINVAL;
- }
-
- for ( i = 0; i < PFN_DOWN(psize); i++ )
- if ( !mfn_valid(mfn_add(maddr_to_mfn(pbase), i)) )
- {
- printk("%pd: invalid physical address 0x%"PRI_mfn"\n",
- d, mfn_x(mfn_add(maddr_to_mfn(pbase), i)));
- return -EINVAL;
- }
-
- /* The host physical address is supplied by the user */
- ret = handle_shared_mem_bank(d, gbase, role_str, false,
- boot_shm_bank);
- if ( ret )
- return ret;
- }
- else
- {
- /*
- * The host physical address is not supplied by the user, so it
- * means that the banks needs to be allocated from the Xen heap,
- * look into the already allocated banks from the heap.
- */
- const struct membank *alloc_bank =
- find_shm_bank_by_id(get_shmem_heap_banks(), shm_id);
-
- if ( is_domain_direct_mapped(d) )
- {
- printk("%pd: host and guest physical address must be supplied
for direct-mapped domains\n",
- d);
- return -EINVAL;
- }
-
- /* guest phys address is right at the beginning */
- gbase = dt_read_paddr(cells, addr_cells);
-
- if ( !alloc_bank )
- {
- alloc_heap_pages_cb_extra cb_arg = { d, role_str, gbase,
- boot_shm_bank->shmem_extra };
-
- /* shm_id identified bank is not yet allocated */
- if ( !allocate_domheap_memory(NULL, psize, save_map_heap_pages,
- &cb_arg) )
- {
- printk(XENLOG_ERR
- "Failed to allocate (%"PRIpaddr"KB) pages as static
shared memory from heap\n",
- psize >> 10);
- return -EINVAL;
- }
- }
- else
- {
- /* shm_id identified bank is already allocated */
- const struct membank *end_bank =
- &shm_heap_banks.bank[shm_heap_banks.common.nr_banks];
- paddr_t gbase_bank = gbase;
-
- /*
- * Static shared memory banks that are taken from the Xen heap
- * are allocated sequentially in shm_heap_banks, so starting
- * from the first bank found identified by shm_id, the code can
- * just advance by one bank at the time until it reaches the
end
- * of the array or it finds another bank NOT identified by
- * shm_id
- */
- for ( ; alloc_bank < end_bank; alloc_bank++ )
- {
- if ( strcmp(shm_id, alloc_bank->shmem_extra->shm_id) != 0 )
- break;
-
- ret = handle_shared_mem_bank(d, gbase_bank, role_str, true,
- alloc_bank);
- if ( ret )
- return ret;
-
- /* Increment guest physical address for next mapping */
- gbase_bank += alloc_bank->size;
- }
- }
- }
-
- /*
- * Record static shared memory region info for later setting
- * up shm-node in guest device tree.
- */
- ret = append_shm_bank_to_domain(kinfo, gbase, psize, shm_id);
- if ( ret )
- return ret;
- }
-
- return 0;
-}
-
-int __init make_shm_resv_memory_node(const struct kernel_info *kinfo,
- int addrcells, int sizecells)
-{
- const struct membanks *mem = kernel_info_get_shm_mem_const(kinfo);
- void *fdt = kinfo->fdt;
- unsigned int i = 0;
- int res = 0;
-
- if ( mem->nr_banks == 0 )
- return 0;
-
- /*
- * For each shared memory region, a range is exposed under
- * the /reserved-memory node as a child node. Each range sub-node is
- * named xen-shmem@<address>.
- */
- dt_dprintk("Create xen-shmem node\n");
-
- for ( ; i < mem->nr_banks; i++ )
- {
- uint64_t start = mem->bank[i].start;
- uint64_t size = mem->bank[i].size;
- const char compat[] = "xen,shared-memory-v1";
- /* Worst case addrcells + sizecells */
- __be32 reg[GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS];
- __be32 *cells;
- unsigned int len = (addrcells + sizecells) * sizeof(__be32);
-
- res = domain_fdt_begin_node(fdt, "xen-shmem", mem->bank[i].start);
- if ( res )
- return res;
-
- res = fdt_property(fdt, "compatible", compat, sizeof(compat));
- if ( res )
- return res;
-
- cells = reg;
- dt_child_set_range(&cells, addrcells, sizecells, start, size);
-
- res = fdt_property(fdt, "reg", reg, len);
- if ( res )
- return res;
-
- dt_dprintk("Shared memory bank %u: %#"PRIx64"->%#"PRIx64"\n",
- i, start, start + size);
-
- res = fdt_property_string(fdt, "xen,id",
- mem->bank[i].shmem_extra->shm_id);
- if ( res )
- return res;
-
- /*
- * TODO:
- * - xen,offset: (borrower VMs only)
- * 64 bit integer offset within the owner virtual machine's shared
- * memory region used for the mapping in the borrower VM
- */
- res = fdt_property_u64(fdt, "xen,offset", 0);
- if ( res )
- return res;
-
- res = fdt_end_node(fdt);
- if ( res )
- return res;
- }
-
- return res;
-}
-
-int __init process_shm_node(const void *fdt, int node, uint32_t address_cells,
- uint32_t size_cells)
-{
- const struct fdt_property *prop, *prop_id, *prop_role;
- const __be32 *cell;
- paddr_t paddr = INVALID_PADDR;
- paddr_t gaddr, size, end;
- struct membanks *mem = bootinfo_get_shmem();
- struct shmem_membank_extra *shmem_extra = bootinfo_get_shmem_extra();
- unsigned int i;
- int len;
- bool owner = false;
- const char *shm_id;
-
- if ( address_cells < 1 || size_cells < 1 )
- {
- printk("fdt: invalid #address-cells or #size-cells for static shared
memory node.\n");
- return -EINVAL;
- }
-
- /*
- * "xen,shm-id" property holds an arbitrary string with a strict limit
- * on the number of characters, MAX_SHM_ID_LENGTH
- */
- prop_id = fdt_get_property(fdt, node, "xen,shm-id", NULL);
- if ( !prop_id )
- return -ENOENT;
- shm_id = (const char *)prop_id->data;
- if ( strnlen(shm_id, MAX_SHM_ID_LENGTH) == MAX_SHM_ID_LENGTH )
- {
- printk("fdt: invalid xen,shm-id %s, it must be limited to %u
characters\n",
- shm_id, MAX_SHM_ID_LENGTH);
- return -EINVAL;
- }
-
- /*
- * "role" property is optional and if it is defined explicitly,
- * it must be either `owner` or `borrower`.
- */
- prop_role = fdt_get_property(fdt, node, "role", NULL);
- if ( prop_role )
- {
- if ( !strcmp(prop_role->data, "owner") )
- owner = true;
- else if ( strcmp(prop_role->data, "borrower") )
- {
- printk("fdt: invalid `role` property for static shared memory
node.\n");
- return -EINVAL;
- }
- }
-
- /*
- * xen,shared-mem = <paddr, gaddr, size>;
- * Memory region starting from physical address #paddr of #size shall
- * be mapped to guest physical address #gaddr as static shared memory
- * region.
- */
- prop = fdt_get_property(fdt, node, "xen,shared-mem", &len);
- if ( !prop )
- return -ENOENT;
-
- cell = (const __be32 *)prop->data;
- if ( len != dt_cells_to_size(address_cells + size_cells + address_cells) )
- {
- if ( len == dt_cells_to_size(address_cells + size_cells) )
- device_tree_get_reg(&cell, address_cells, size_cells, &gaddr,
- &size);
- else
- {
- printk("fdt: invalid `xen,shared-mem` property.\n");
- return -EINVAL;
- }
- }
- else
- {
- device_tree_get_reg(&cell, address_cells, address_cells, &paddr,
- &gaddr);
- size = dt_next_cell(size_cells, &cell);
-
- if ( !IS_ALIGNED(paddr, PAGE_SIZE) )
- {
- printk("fdt: physical address 0x%"PRIpaddr" is not suitably
aligned.\n",
- paddr);
- return -EINVAL;
- }
-
- end = paddr + size;
- if ( end <= paddr )
- {
- printk("fdt: static shared memory region %s overflow\n", shm_id);
- return -EINVAL;
- }
- }
-
- if ( !IS_ALIGNED(gaddr, PAGE_SIZE) )
- {
- printk("fdt: guest address 0x%"PRIpaddr" is not suitably aligned.\n",
- gaddr);
- return -EINVAL;
- }
-
- if ( !size )
- {
- printk("fdt: the size for static shared memory region can not be
zero\n");
- return -EINVAL;
- }
-
- if ( !IS_ALIGNED(size, PAGE_SIZE) )
- {
- printk("fdt: size 0x%"PRIpaddr" is not suitably aligned\n", size);
- return -EINVAL;
- }
-
- for ( i = 0; i < mem->nr_banks; i++ )
- {
- /*
- * Meet the following check:
- * - when host address is provided:
- * 1) The shm ID matches and the region exactly match
- * 2) The shm ID doesn't match and the region doesn't overlap
- * with an existing one
- * - when host address is not provided:
- * 1) The shm ID matches and the region size exactly match
- */
- bool paddr_assigned = (INVALID_PADDR != paddr);
-
- if ( strncmp(shm_id, shmem_extra[i].shm_id, MAX_SHM_ID_LENGTH) == 0 )
- {
- /*
- * Regions have same shm_id (cases):
- * 1) physical host address is supplied:
- * - OK: paddr is equal and size is equal (same region)
- * - Fail: paddr doesn't match or size doesn't match (there
- * cannot exists two shmem regions with same shm_id)
- * 2) physical host address is NOT supplied:
- * - OK: size is equal (same region)
- * - Fail: size is not equal (same shm_id must identify only one
- * region, there can't be two different regions with
same
- * shm_id)
- */
- bool start_match = paddr_assigned ? (paddr == mem->bank[i].start) :
- true;
-
- if ( start_match && (size == mem->bank[i].size) )
- break;
- else
- {
- printk("fdt: different shared memory region could not share
the same shm ID %s\n",
- shm_id);
- return -EINVAL;
- }
- }
-
- /*
- * Regions have different shm_id (cases):
- * 1) physical host address is supplied:
- * - OK: paddr different, or size different (case where paddr
- * is equal but psize is different are wrong, but they
- * are handled later when checking for overlapping)
- * - Fail: paddr equal and size equal (the same region can't be
- * identified with different shm_id)
- * 2) physical host address is NOT supplied:
- * - OK: Both have different shm_id so even with same size they
- * can exists
- */
- if ( !paddr_assigned || (paddr != mem->bank[i].start) ||
- (size != mem->bank[i].size) )
- continue;
- else
- {
- printk("fdt: xen,shm-id %s does not match for all the nodes using
the same region\n",
- shm_id);
- return -EINVAL;
- }
- }
-
- if ( i == mem->nr_banks )
- {
- if (i < mem->max_banks)
- {
- if ( (paddr != INVALID_PADDR) &&
- check_reserved_regions_overlap(paddr, size, false) )
- return -EINVAL;
-
- /* Static shared memory shall be reserved from any other use. */
- safe_strcpy(shmem_extra[mem->nr_banks].shm_id, shm_id);
- mem->bank[mem->nr_banks].start = paddr;
- mem->bank[mem->nr_banks].size = size;
- mem->bank[mem->nr_banks].shmem_extra = &shmem_extra[mem->nr_banks];
- mem->nr_banks++;
- }
- else
- {
- printk("Warning: Max number of supported memory regions
reached.\n");
- return -ENOSPC;
- }
- }
- /*
- * keep a count of the number of borrowers, which later may be used
- * to calculate the reference count.
- */
- if ( !owner )
- shmem_extra[i].nr_shm_borrowers++;
-
- return 0;
-}
-
-int __init make_resv_memory_node(const struct kernel_info *kinfo, int
addrcells,
- int sizecells)
-{
- const struct membanks *mem = kernel_info_get_shm_mem_const(kinfo);
- void *fdt = kinfo->fdt;
- int res = 0;
- /* Placeholder for reserved-memory\0 */
- const char resvbuf[16] = "reserved-memory";
-
- if ( mem->nr_banks == 0 )
- /* No shared memory provided. */
- return 0;
-
- dt_dprintk("Create reserved-memory node\n");
-
- res = fdt_begin_node(fdt, resvbuf);
- if ( res )
- return res;
-
- res = fdt_property(fdt, "ranges", NULL, 0);
- if ( res )
- return res;
-
- res = fdt_property_cell(fdt, "#address-cells", addrcells);
- if ( res )
- return res;
-
- res = fdt_property_cell(fdt, "#size-cells", sizecells);
- if ( res )
- return res;
-
- res = make_shm_resv_memory_node(kinfo, addrcells, sizecells);
- if ( res )
- return res;
-
- res = fdt_end_node(fdt);
-
- return res;
-}
-
-void __init early_print_info_shmem(void)
-{
- const struct membanks *shmem = bootinfo_get_shmem();
- unsigned int bank;
- unsigned int printed = 0;
-
- for ( bank = 0; bank < shmem->nr_banks; bank++, printed++ )
- if ( shmem->bank[bank].start != INVALID_PADDR )
- printk(" SHMEM[%u]: %"PRIpaddr" - %"PRIpaddr"\n", printed,
- shmem->bank[bank].start,
- shmem->bank[bank].start + shmem->bank[bank].size - 1);
-}
-
-void __init init_sharedmem_pages(void)
-{
- const struct membanks *shmem = bootinfo_get_shmem();
- unsigned int bank;
-
- for ( bank = 0 ; bank < shmem->nr_banks; bank++ )
- if ( shmem->bank[bank].start != INVALID_PADDR )
- init_staticmem_bank(&shmem->bank[bank]);
-}
-
-int __init remove_shm_from_rangeset(const struct kernel_info *kinfo,
- struct rangeset *rangeset)
-{
- const struct membanks *shm_mem = kernel_info_get_shm_mem_const(kinfo);
- unsigned int i;
-
- /* Remove static shared memory regions */
- for ( i = 0; i < shm_mem->nr_banks; i++ )
- {
- paddr_t start, end;
- int res;
-
- start = shm_mem->bank[i].start;
- end = shm_mem->bank[i].start + shm_mem->bank[i].size;
- res = rangeset_remove_range(rangeset, PFN_DOWN(start),
- PFN_DOWN(end - 1));
- if ( res )
- {
- printk(XENLOG_ERR
- "Failed to remove: %#"PRIpaddr"->%#"PRIpaddr", error: %d\n",
- start, end, res);
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-void __init shm_mem_node_fill_reg_range(const struct kernel_info *kinfo,
- __be32 *reg, int *nr_cells,
- int addrcells, int sizecells)
-{
- const struct membanks *mem = kernel_info_get_shm_mem_const(kinfo);
- unsigned int i;
- __be32 *cells;
-
- BUG_ON(!nr_cells || !reg);
-
- cells = ®[*nr_cells];
- for ( i = 0; i < mem->nr_banks; i++ )
- {
- paddr_t start = mem->bank[i].start;
- paddr_t size = mem->bank[i].size;
-
- *nr_cells += addrcells + sizecells;
- BUG_ON(*nr_cells >= DT_MEM_NODE_REG_RANGE_SIZE);
- dt_child_set_range(&cells, addrcells, sizecells, start, size);
- }
-}
-
-/*
- * Local variables:
- * mode: C
- * c-file-style: "BSD"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index 7ecf5a8031..eece1370a3 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -162,6 +162,12 @@ config STATIC_MEMORY
If unsure, say N.
+config STATIC_SHM
+ bool "Statically shared memory on a dom0less system" if UNSUPPORTED
+ depends on STATIC_MEMORY
+ help
+ This option enables statically shared memory on a dom0less system.
+
config STATIC_EVTCHN
bool "Static event channel support on a dom0less system"
depends on DOM0LESS_BOOT
diff --git a/xen/common/device-tree/Makefile b/xen/common/device-tree/Makefile
index ed11f2c3b4..13127296cb 100644
--- a/xen/common/device-tree/Makefile
+++ b/xen/common/device-tree/Makefile
@@ -8,3 +8,4 @@ obj-y += intc.o
obj-$(CONFIG_DOMAIN_BUILD_HELPERS) += kernel.o
obj-$(CONFIG_STATIC_EVTCHN) += static-evtchn.init.o
obj-$(CONFIG_STATIC_MEMORY) += static-memory.init.o
+obj-$(CONFIG_STATIC_SHM) += static-shmem.init.o
diff --git a/xen/common/device-tree/bootfdt.c b/xen/common/device-tree/bootfdt.c
index aa44f5a67c..9df80291b1 100644
--- a/xen/common/device-tree/bootfdt.c
+++ b/xen/common/device-tree/bootfdt.c
@@ -13,11 +13,9 @@
#include <xen/lib.h>
#include <xen/libfdt/libfdt-xen.h>
#include <xen/sort.h>
+#include <xen/static-shmem.h>
#include <xsm/xsm.h>
#include <asm/setup.h>
-#ifdef CONFIG_STATIC_SHM
-#include <asm/static-shmem.h>
-#endif
static void __init __maybe_unused build_assertions(void)
{
diff --git a/xen/common/device-tree/dom0less-build.c
b/xen/common/device-tree/dom0less-build.c
index c8c5a04f24..3d503c6973 100644
--- a/xen/common/device-tree/dom0less-build.c
+++ b/xen/common/device-tree/dom0less-build.c
@@ -29,10 +29,7 @@
#include <asm/setup.h>
#include <xen/static-memory.h>
-
-#if __has_include(<asm/static-shmem.h>)
-# include <asm/static-shmem.h>
-#endif
+#include <xen/static-shmem.h>
#define XENSTORE_PFN_LATE_ALLOC UINT64_MAX
@@ -505,11 +502,9 @@ static int __init prepare_dtb_domU(struct domain *d,
struct kernel_info *kinfo)
if ( ret )
goto err;
-#ifdef CONFIG_STATIC_SHM
ret = make_resv_memory_node(kinfo, addrcells, sizecells);
if ( ret )
goto err;
-#endif
/*
* domain_handle_dtb_bootmodule has to be called before the rest of
@@ -802,11 +797,9 @@ static int __init construct_domU(struct domain *d,
else
assign_static_memory_11(d, &kinfo, node);
-#ifdef CONFIG_STATIC_SHM
rc = process_shm(d, &kinfo, node);
if ( rc < 0 )
return rc;
-#endif
rc = init_vuart(d, &kinfo, node);
if ( rc < 0 )
diff --git a/xen/common/device-tree/static-shmem.c
b/xen/common/device-tree/static-shmem.c
new file mode 100644
index 0000000000..8023c0a484
--- /dev/null
+++ b/xen/common/device-tree/static-shmem.c
@@ -0,0 +1,854 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <xen/device_tree.h>
+#include <xen/fdt-domain-build.h>
+#include <xen/libfdt/libfdt.h>
+#include <xen/rangeset.h>
+#include <xen/sched.h>
+#include <xen/static-memory.h>
+#include <xen/static-shmem.h>
+
+#include <asm/setup.h>
+
+typedef struct {
+ struct domain *d;
+ const char *role_str;
+ paddr_t gbase;
+ struct shmem_membank_extra *bank_extra_info;
+} alloc_heap_pages_cb_extra;
+
+static struct {
+ struct membanks_hdr common;
+ struct membank bank[NR_SHMEM_BANKS];
+} shm_heap_banks __initdata = {
+ .common.max_banks = NR_SHMEM_BANKS,
+ .common.type = STATIC_SHARED_MEMORY
+};
+
+static inline struct membanks *get_shmem_heap_banks(void)
+{
+ return container_of(&shm_heap_banks.common, struct membanks, common);
+}
+
+static void __init __maybe_unused build_assertions(void)
+{
+ /*
+ * Check that no padding is between struct membanks "bank" flexible array
+ * member and struct shared_meminfo "bank" member
+ */
+ BUILD_BUG_ON((offsetof(struct membanks, bank) !=
+ offsetof(struct shared_meminfo, bank)));
+}
+
+static const struct membank __init *
+find_shm_bank_by_id(const struct membanks *shmem, const char *shm_id)
+{
+ unsigned int bank;
+
+ for ( bank = 0 ; bank < shmem->nr_banks; bank++ )
+ {
+ if ( strcmp(shm_id, shmem->bank[bank].shmem_extra->shm_id) == 0 )
+ break;
+ }
+
+ if ( bank == shmem->nr_banks )
+ return NULL;
+
+ return &shmem->bank[bank];
+}
+
+/*
+ * This function checks whether the static shared memory region is
+ * already allocated to dom_io.
+ */
+static bool __init is_shm_allocated_to_domio(paddr_t pbase)
+{
+ struct page_info *page;
+ struct domain *d;
+
+ page = maddr_to_page(pbase);
+ d = page_get_owner_and_reference(page);
+ if ( d == NULL )
+ return false;
+ put_page(page);
+
+ if ( d != dom_io )
+ {
+ printk(XENLOG_ERR
+ "shm memory node has already been allocated to a specific owner
%pd, Please check your configuration\n",
+ d);
+ return false;
+ }
+
+ return true;
+}
+
+static mfn_t __init acquire_shared_memory_bank(struct domain *d,
+ paddr_t pbase, paddr_t psize,
+ bool bank_from_heap)
+{
+ mfn_t smfn;
+ unsigned long nr_pfns;
+ int res;
+
+ /*
+ * Pages of statically shared memory shall be included
+ * into domain_tot_pages().
+ */
+ nr_pfns = PFN_DOWN(psize);
+ if ( (UINT_MAX - d->max_pages) < nr_pfns )
+ {
+ printk(XENLOG_ERR "%pd: Over-allocation for d->max_pages: %lu.\n",
+ d, nr_pfns);
+ return INVALID_MFN;
+ }
+ d->max_pages += nr_pfns;
+
+ smfn = maddr_to_mfn(pbase);
+ if ( bank_from_heap )
+ /*
+ * When host address is not provided, static shared memory is
+ * allocated from heap and shall be assigned to owner domain.
+ */
+ res = assign_pages(maddr_to_page(pbase), nr_pfns, d, 0);
+ else
+ res = acquire_domstatic_pages(d, smfn, nr_pfns, 0);
+
+ if ( res )
+ {
+ printk(XENLOG_ERR "%pd: failed to %s static memory: %d.\n", d,
+ bank_from_heap ? "assign" : "acquire", res);
+ goto fail;
+ }
+
+ return smfn;
+
+ fail:
+ d->max_pages -= nr_pfns;
+ return INVALID_MFN;
+}
+
+static int __init assign_shared_memory(struct domain *d, paddr_t gbase,
+ bool bank_from_heap,
+ const struct membank *shm_bank)
+{
+ mfn_t smfn;
+ int ret = 0;
+ unsigned long nr_pages, nr_borrowers, i;
+ struct page_info *page;
+ paddr_t pbase, psize;
+
+ pbase = shm_bank->start;
+ psize = shm_bank->size;
+ nr_borrowers = shm_bank->shmem_extra->nr_shm_borrowers;
+
+ smfn = acquire_shared_memory_bank(d, pbase, psize, bank_from_heap);
+ if ( mfn_eq(smfn, INVALID_MFN) )
+ return -EINVAL;
+
+ /*
+ * DOMID_IO is not auto-translated (i.e. it sees RAM 1:1). So we do not
need
+ * to create mapping in the P2M.
+ */
+ nr_pages = PFN_DOWN(psize);
+ if ( d != dom_io )
+ {
+ ret = guest_physmap_add_pages(d, gaddr_to_gfn(gbase), smfn,
+ PFN_DOWN(psize));
+ if ( ret )
+ {
+ printk(XENLOG_ERR "Failed to map shared memory to %pd.\n", d);
+ return ret;
+ }
+ }
+
+ /*
+ * Instead of letting borrower domain get a page ref, we add as many
+ * additional reference as the number of borrowers when the owner
+ * is allocated, since there is a chance that owner is created
+ * after borrower.
+ * So if the borrower is created first, it will cause adding pages
+ * in the P2M without reference.
+ */
+ page = mfn_to_page(smfn);
+ for ( i = 0; i < nr_pages; i++ )
+ {
+ if ( !get_page_nr(page + i, d, nr_borrowers) )
+ {
+ printk(XENLOG_ERR
+ "Failed to add %lu references to page %"PRI_mfn".\n",
+ nr_borrowers, mfn_x(smfn) + i);
+ goto fail;
+ }
+ }
+
+ return 0;
+
+ fail:
+ while ( --i >= 0 )
+ put_page_nr(page + i, nr_borrowers);
+ return ret;
+}
+
+static int __init
+append_shm_bank_to_domain(struct kernel_info *kinfo, paddr_t start,
+ paddr_t size, const char *shm_id)
+{
+ struct membanks *shm_mem = kernel_info_get_shm_mem(kinfo);
+ struct shmem_membank_extra *shm_mem_extra;
+
+ if ( shm_mem->nr_banks >= shm_mem->max_banks )
+ return -ENOMEM;
+
+ shm_mem_extra = &kinfo->shm_mem.extra[shm_mem->nr_banks];
+
+ shm_mem->bank[shm_mem->nr_banks].start = start;
+ shm_mem->bank[shm_mem->nr_banks].size = size;
+ safe_strcpy(shm_mem_extra->shm_id, shm_id);
+ shm_mem->bank[shm_mem->nr_banks].shmem_extra = shm_mem_extra;
+ shm_mem->nr_banks++;
+
+ return 0;
+}
+
+static int __init handle_shared_mem_bank(struct domain *d, paddr_t gbase,
+ const char *role_str,
+ bool bank_from_heap,
+ const struct membank *shm_bank)
+{
+ bool owner_dom_io = true;
+ paddr_t pbase, psize;
+ int ret;
+
+ pbase = shm_bank->start;
+ psize = shm_bank->size;
+
+ /*
+ * "role" property is optional and if it is defined explicitly,
+ * then the owner domain is not the default "dom_io" domain.
+ */
+ if ( role_str != NULL )
+ owner_dom_io = false;
+
+ /*
+ * DOMID_IO is a fake domain and is not described in the Device-Tree.
+ * Therefore when the owner of the shared region is DOMID_IO, we will
+ * only find the borrowers.
+ */
+ if ( (owner_dom_io && !is_shm_allocated_to_domio(pbase)) ||
+ (!owner_dom_io && strcmp(role_str, "owner") == 0) )
+ {
+ /*
+ * We found the first borrower of the region, the owner was not
+ * specified, so they should be assigned to dom_io.
+ */
+ ret = assign_shared_memory(owner_dom_io ? dom_io : d, gbase,
+ bank_from_heap, shm_bank);
+ if ( ret )
+ return ret;
+ }
+
+ if ( owner_dom_io || (strcmp(role_str, "borrower") == 0) )
+ {
+ /* Set up P2M foreign mapping for borrower domain. */
+ ret = map_regions_p2mt(d, _gfn(PFN_UP(gbase)), PFN_DOWN(psize),
+ _mfn(PFN_UP(pbase)), p2m_map_foreign_rw);
+ if ( ret )
+ return ret;
+ }
+
+ return 0;
+}
+
+static bool __init save_map_heap_pages(struct domain *d, struct page_info *pg,
+ unsigned int order, void *extra)
+{
+ alloc_heap_pages_cb_extra *b_extra = (alloc_heap_pages_cb_extra *)extra;
+ int idx = shm_heap_banks.common.nr_banks;
+ int ret = -ENOSPC;
+
+ BUG_ON(!b_extra);
+
+ if ( idx < shm_heap_banks.common.max_banks )
+ {
+ shm_heap_banks.bank[idx].start = page_to_maddr(pg);
+ shm_heap_banks.bank[idx].size = (1ULL << (PAGE_SHIFT + order));
+ shm_heap_banks.bank[idx].shmem_extra = b_extra->bank_extra_info;
+ shm_heap_banks.common.nr_banks++;
+
+ ret = handle_shared_mem_bank(b_extra->d, b_extra->gbase,
+ b_extra->role_str, true,
+ &shm_heap_banks.bank[idx]);
+ if ( !ret )
+ {
+ /* Increment guest physical address for next mapping */
+ b_extra->gbase += shm_heap_banks.bank[idx].size;
+ return true;
+ }
+ }
+
+ printk("Failed to allocate static shared memory from Xen heap: (%d)\n",
+ ret);
+
+ return false;
+}
+
+int __init process_shm(struct domain *d, struct kernel_info *kinfo,
+ const struct dt_device_node *node)
+{
+ struct dt_device_node *shm_node;
+
+ /* Hwdom case - shm node under /chosen */
+ if ( !node )
+ {
+ node = dt_find_node_by_path("/chosen");
+ BUG_ON(!node);
+ }
+
+ dt_for_each_child_node(node, shm_node)
+ {
+ const struct membank *boot_shm_bank;
+ const struct dt_property *prop;
+ const __be32 *cells;
+ uint32_t addr_cells;
+ paddr_t gbase, pbase, psize;
+ int ret = 0;
+ unsigned int i;
+ const char *role_str;
+ const char *shm_id;
+
+ if ( !dt_device_is_compatible(shm_node, "xen,domain-shared-memory-v1")
)
+ continue;
+
+ if ( dt_property_read_string(shm_node, "xen,shm-id", &shm_id) )
+ {
+ printk("%pd: invalid \"xen,shm-id\" property", d);
+ return -EINVAL;
+ }
+ BUG_ON((strlen(shm_id) <= 0) || (strlen(shm_id) >= MAX_SHM_ID_LENGTH));
+
+ boot_shm_bank = find_shm_bank_by_id(bootinfo_get_shmem(), shm_id);
+ if ( !boot_shm_bank )
+ {
+ printk("%pd: static shared memory bank not found: '%s'", d,
shm_id);
+ return -ENOENT;
+ }
+
+ pbase = boot_shm_bank->start;
+ psize = boot_shm_bank->size;
+
+ /* "role" property is optional */
+ if ( dt_property_read_string(shm_node, "role", &role_str) != 0 )
+ role_str = NULL;
+
+ /*
+ * xen,shared-mem = <[pbase,] gbase, size>;
+ * pbase is optional.
+ */
+ addr_cells = dt_n_addr_cells(shm_node);
+ prop = dt_find_property(shm_node, "xen,shared-mem", NULL);
+ BUG_ON(!prop);
+ cells = (const __be32 *)prop->value;
+
+ if ( pbase != INVALID_PADDR )
+ {
+ /* guest phys address is after host phys address */
+ gbase = dt_read_paddr(cells + addr_cells, addr_cells);
+
+ if ( is_domain_direct_mapped(d) && (pbase != gbase) )
+ {
+ printk("%pd: physical address 0x%"PRIpaddr" and guest address
0x%"PRIpaddr" are not direct-mapped.\n",
+ d, pbase, gbase);
+ return -EINVAL;
+ }
+
+ for ( i = 0; i < PFN_DOWN(psize); i++ )
+ if ( !mfn_valid(mfn_add(maddr_to_mfn(pbase), i)) )
+ {
+ printk("%pd: invalid physical address 0x%"PRI_mfn"\n",
+ d, mfn_x(mfn_add(maddr_to_mfn(pbase), i)));
+ return -EINVAL;
+ }
+
+ /* The host physical address is supplied by the user */
+ ret = handle_shared_mem_bank(d, gbase, role_str, false,
+ boot_shm_bank);
+ if ( ret )
+ return ret;
+ }
+ else
+ {
+ /*
+ * The host physical address is not supplied by the user, so it
+ * means that the banks needs to be allocated from the Xen heap,
+ * look into the already allocated banks from the heap.
+ */
+ const struct membank *alloc_bank =
+ find_shm_bank_by_id(get_shmem_heap_banks(), shm_id);
+
+ if ( is_domain_direct_mapped(d) )
+ {
+ printk("%pd: host and guest physical address must be supplied
for direct-mapped domains\n",
+ d);
+ return -EINVAL;
+ }
+
+ /* guest phys address is right at the beginning */
+ gbase = dt_read_paddr(cells, addr_cells);
+
+ if ( !alloc_bank )
+ {
+ alloc_heap_pages_cb_extra cb_arg = { d, role_str, gbase,
+ boot_shm_bank->shmem_extra };
+
+ /* shm_id identified bank is not yet allocated */
+ if ( !allocate_domheap_memory(NULL, psize, save_map_heap_pages,
+ &cb_arg) )
+ {
+ printk(XENLOG_ERR
+ "Failed to allocate (%"PRIpaddr"KB) pages as static
shared memory from heap\n",
+ psize >> 10);
+ return -EINVAL;
+ }
+ }
+ else
+ {
+ /* shm_id identified bank is already allocated */
+ const struct membank *end_bank =
+ &shm_heap_banks.bank[shm_heap_banks.common.nr_banks];
+ paddr_t gbase_bank = gbase;
+
+ /*
+ * Static shared memory banks that are taken from the Xen heap
+ * are allocated sequentially in shm_heap_banks, so starting
+ * from the first bank found identified by shm_id, the code can
+ * just advance by one bank at the time until it reaches the
end
+ * of the array or it finds another bank NOT identified by
+ * shm_id
+ */
+ for ( ; alloc_bank < end_bank; alloc_bank++ )
+ {
+ if ( strcmp(shm_id, alloc_bank->shmem_extra->shm_id) != 0 )
+ break;
+
+ ret = handle_shared_mem_bank(d, gbase_bank, role_str, true,
+ alloc_bank);
+ if ( ret )
+ return ret;
+
+ /* Increment guest physical address for next mapping */
+ gbase_bank += alloc_bank->size;
+ }
+ }
+ }
+
+ /*
+ * Record static shared memory region info for later setting
+ * up shm-node in guest device tree.
+ */
+ ret = append_shm_bank_to_domain(kinfo, gbase, psize, shm_id);
+ if ( ret )
+ return ret;
+ }
+
+ return 0;
+}
+
+int __init make_shm_resv_memory_node(const struct kernel_info *kinfo,
+ int addrcells, int sizecells)
+{
+ const struct membanks *mem = kernel_info_get_shm_mem_const(kinfo);
+ void *fdt = kinfo->fdt;
+ unsigned int i = 0;
+ int res = 0;
+
+ if ( mem->nr_banks == 0 )
+ return 0;
+
+ /*
+ * For each shared memory region, a range is exposed under
+ * the /reserved-memory node as a child node. Each range sub-node is
+ * named xen-shmem@<address>.
+ */
+ dt_dprintk("Create xen-shmem node\n");
+
+ for ( ; i < mem->nr_banks; i++ )
+ {
+ uint64_t start = mem->bank[i].start;
+ uint64_t size = mem->bank[i].size;
+ const char compat[] = "xen,shared-memory-v1";
+ /* Worst case addrcells + sizecells */
+ __be32 reg[GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS];
+ __be32 *cells;
+ unsigned int len = (addrcells + sizecells) * sizeof(__be32);
+
+ res = domain_fdt_begin_node(fdt, "xen-shmem", mem->bank[i].start);
+ if ( res )
+ return res;
+
+ res = fdt_property(fdt, "compatible", compat, sizeof(compat));
+ if ( res )
+ return res;
+
+ cells = reg;
+ dt_child_set_range(&cells, addrcells, sizecells, start, size);
+
+ res = fdt_property(fdt, "reg", reg, len);
+ if ( res )
+ return res;
+
+ dt_dprintk("Shared memory bank %u: %#"PRIx64"->%#"PRIx64"\n",
+ i, start, start + size);
+
+ res = fdt_property_string(fdt, "xen,id",
+ mem->bank[i].shmem_extra->shm_id);
+ if ( res )
+ return res;
+
+ /*
+ * TODO:
+ * - xen,offset: (borrower VMs only)
+ * 64 bit integer offset within the owner virtual machine's shared
+ * memory region used for the mapping in the borrower VM
+ */
+ res = fdt_property_u64(fdt, "xen,offset", 0);
+ if ( res )
+ return res;
+
+ res = fdt_end_node(fdt);
+ if ( res )
+ return res;
+ }
+
+ return res;
+}
+
+int __init process_shm_node(const void *fdt, int node, uint32_t address_cells,
+ uint32_t size_cells)
+{
+ const struct fdt_property *prop, *prop_id, *prop_role;
+ const __be32 *cell;
+ paddr_t paddr = INVALID_PADDR;
+ paddr_t gaddr, size, end;
+ struct membanks *mem = bootinfo_get_shmem();
+ struct shmem_membank_extra *shmem_extra = bootinfo_get_shmem_extra();
+ unsigned int i;
+ int len;
+ bool owner = false;
+ const char *shm_id;
+
+ if ( address_cells < 1 || size_cells < 1 )
+ {
+ printk("fdt: invalid #address-cells or #size-cells for static shared
memory node.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * "xen,shm-id" property holds an arbitrary string with a strict limit
+ * on the number of characters, MAX_SHM_ID_LENGTH
+ */
+ prop_id = fdt_get_property(fdt, node, "xen,shm-id", NULL);
+ if ( !prop_id )
+ return -ENOENT;
+ shm_id = (const char *)prop_id->data;
+ if ( strnlen(shm_id, MAX_SHM_ID_LENGTH) == MAX_SHM_ID_LENGTH )
+ {
+ printk("fdt: invalid xen,shm-id %s, it must be limited to %u
characters\n",
+ shm_id, MAX_SHM_ID_LENGTH);
+ return -EINVAL;
+ }
+
+ /*
+ * "role" property is optional and if it is defined explicitly,
+ * it must be either `owner` or `borrower`.
+ */
+ prop_role = fdt_get_property(fdt, node, "role", NULL);
+ if ( prop_role )
+ {
+ if ( !strcmp(prop_role->data, "owner") )
+ owner = true;
+ else if ( strcmp(prop_role->data, "borrower") )
+ {
+ printk("fdt: invalid `role` property for static shared memory
node.\n");
+ return -EINVAL;
+ }
+ }
+
+ /*
+ * xen,shared-mem = <paddr, gaddr, size>;
+ * Memory region starting from physical address #paddr of #size shall
+ * be mapped to guest physical address #gaddr as static shared memory
+ * region.
+ */
+ prop = fdt_get_property(fdt, node, "xen,shared-mem", &len);
+ if ( !prop )
+ return -ENOENT;
+
+ cell = (const __be32 *)prop->data;
+ if ( len != dt_cells_to_size(address_cells + size_cells + address_cells) )
+ {
+ if ( len == dt_cells_to_size(address_cells + size_cells) )
+ device_tree_get_reg(&cell, address_cells, size_cells, &gaddr,
+ &size);
+ else
+ {
+ printk("fdt: invalid `xen,shared-mem` property.\n");
+ return -EINVAL;
+ }
+ }
+ else
+ {
+ device_tree_get_reg(&cell, address_cells, address_cells, &paddr,
+ &gaddr);
+ size = dt_next_cell(size_cells, &cell);
+
+ if ( !IS_ALIGNED(paddr, PAGE_SIZE) )
+ {
+ printk("fdt: physical address 0x%"PRIpaddr" is not suitably
aligned.\n",
+ paddr);
+ return -EINVAL;
+ }
+
+ end = paddr + size;
+ if ( end <= paddr )
+ {
+ printk("fdt: static shared memory region %s overflow\n", shm_id);
+ return -EINVAL;
+ }
+ }
+
+ if ( !IS_ALIGNED(gaddr, PAGE_SIZE) )
+ {
+ printk("fdt: guest address 0x%"PRIpaddr" is not suitably aligned.\n",
+ gaddr);
+ return -EINVAL;
+ }
+
+ if ( !size )
+ {
+ printk("fdt: the size for static shared memory region can not be
zero\n");
+ return -EINVAL;
+ }
+
+ if ( !IS_ALIGNED(size, PAGE_SIZE) )
+ {
+ printk("fdt: size 0x%"PRIpaddr" is not suitably aligned\n", size);
+ return -EINVAL;
+ }
+
+ for ( i = 0; i < mem->nr_banks; i++ )
+ {
+ /*
+ * Meet the following check:
+ * - when host address is provided:
+ * 1) The shm ID matches and the region exactly match
+ * 2) The shm ID doesn't match and the region doesn't overlap
+ * with an existing one
+ * - when host address is not provided:
+ * 1) The shm ID matches and the region size exactly match
+ */
+ bool paddr_assigned = (INVALID_PADDR != paddr);
+
+ if ( strncmp(shm_id, shmem_extra[i].shm_id, MAX_SHM_ID_LENGTH) == 0 )
+ {
+ /*
+ * Regions have same shm_id (cases):
+ * 1) physical host address is supplied:
+ * - OK: paddr is equal and size is equal (same region)
+ * - Fail: paddr doesn't match or size doesn't match (there
+ * cannot exists two shmem regions with same shm_id)
+ * 2) physical host address is NOT supplied:
+ * - OK: size is equal (same region)
+ * - Fail: size is not equal (same shm_id must identify only one
+ * region, there can't be two different regions with
same
+ * shm_id)
+ */
+ bool start_match = paddr_assigned ? (paddr == mem->bank[i].start) :
+ true;
+
+ if ( start_match && (size == mem->bank[i].size) )
+ break;
+ else
+ {
+ printk("fdt: different shared memory region could not share
the same shm ID %s\n",
+ shm_id);
+ return -EINVAL;
+ }
+ }
+
+ /*
+ * Regions have different shm_id (cases):
+ * 1) physical host address is supplied:
+ * - OK: paddr different, or size different (case where paddr
+ * is equal but psize is different are wrong, but they
+ * are handled later when checking for overlapping)
+ * - Fail: paddr equal and size equal (the same region can't be
+ * identified with different shm_id)
+ * 2) physical host address is NOT supplied:
+ * - OK: Both have different shm_id so even with same size they
+ * can exists
+ */
+ if ( !paddr_assigned || (paddr != mem->bank[i].start) ||
+ (size != mem->bank[i].size) )
+ continue;
+ else
+ {
+ printk("fdt: xen,shm-id %s does not match for all the nodes using
the same region\n",
+ shm_id);
+ return -EINVAL;
+ }
+ }
+
+ if ( i == mem->nr_banks )
+ {
+ if (i < mem->max_banks)
+ {
+ if ( (paddr != INVALID_PADDR) &&
+ check_reserved_regions_overlap(paddr, size, false) )
+ return -EINVAL;
+
+ /* Static shared memory shall be reserved from any other use. */
+ safe_strcpy(shmem_extra[mem->nr_banks].shm_id, shm_id);
+ mem->bank[mem->nr_banks].start = paddr;
+ mem->bank[mem->nr_banks].size = size;
+ mem->bank[mem->nr_banks].shmem_extra = &shmem_extra[mem->nr_banks];
+ mem->nr_banks++;
+ }
+ else
+ {
+ printk("Warning: Max number of supported memory regions
reached.\n");
+ return -ENOSPC;
+ }
+ }
+ /*
+ * keep a count of the number of borrowers, which later may be used
+ * to calculate the reference count.
+ */
+ if ( !owner )
+ shmem_extra[i].nr_shm_borrowers++;
+
+ return 0;
+}
+
+int __init make_resv_memory_node(const struct kernel_info *kinfo, int
addrcells,
+ int sizecells)
+{
+ const struct membanks *mem = kernel_info_get_shm_mem_const(kinfo);
+ void *fdt = kinfo->fdt;
+ int res = 0;
+ /* Placeholder for reserved-memory\0 */
+ const char resvbuf[16] = "reserved-memory";
+
+ if ( mem->nr_banks == 0 )
+ /* No shared memory provided. */
+ return 0;
+
+ dt_dprintk("Create reserved-memory node\n");
+
+ res = fdt_begin_node(fdt, resvbuf);
+ if ( res )
+ return res;
+
+ res = fdt_property(fdt, "ranges", NULL, 0);
+ if ( res )
+ return res;
+
+ res = fdt_property_cell(fdt, "#address-cells", addrcells);
+ if ( res )
+ return res;
+
+ res = fdt_property_cell(fdt, "#size-cells", sizecells);
+ if ( res )
+ return res;
+
+ res = make_shm_resv_memory_node(kinfo, addrcells, sizecells);
+ if ( res )
+ return res;
+
+ res = fdt_end_node(fdt);
+
+ return res;
+}
+
+void __init early_print_info_shmem(void)
+{
+ const struct membanks *shmem = bootinfo_get_shmem();
+ unsigned int bank;
+ unsigned int printed = 0;
+
+ for ( bank = 0; bank < shmem->nr_banks; bank++, printed++ )
+ if ( shmem->bank[bank].start != INVALID_PADDR )
+ printk(" SHMEM[%u]: %"PRIpaddr" - %"PRIpaddr"\n", printed,
+ shmem->bank[bank].start,
+ shmem->bank[bank].start + shmem->bank[bank].size - 1);
+}
+
+void __init init_sharedmem_pages(void)
+{
+ const struct membanks *shmem = bootinfo_get_shmem();
+ unsigned int bank;
+
+ for ( bank = 0 ; bank < shmem->nr_banks; bank++ )
+ if ( shmem->bank[bank].start != INVALID_PADDR )
+ init_staticmem_bank(&shmem->bank[bank]);
+}
+
+int __init remove_shm_from_rangeset(const struct kernel_info *kinfo,
+ struct rangeset *rangeset)
+{
+ const struct membanks *shm_mem = kernel_info_get_shm_mem_const(kinfo);
+ unsigned int i;
+
+ /* Remove static shared memory regions */
+ for ( i = 0; i < shm_mem->nr_banks; i++ )
+ {
+ paddr_t start, end;
+ int res;
+
+ start = shm_mem->bank[i].start;
+ end = shm_mem->bank[i].start + shm_mem->bank[i].size;
+ res = rangeset_remove_range(rangeset, PFN_DOWN(start),
+ PFN_DOWN(end - 1));
+ if ( res )
+ {
+ printk(XENLOG_ERR
+ "Failed to remove: %#"PRIpaddr"->%#"PRIpaddr", error: %d\n",
+ start, end, res);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+void __init shm_mem_node_fill_reg_range(const struct kernel_info *kinfo,
+ __be32 *reg, int *nr_cells,
+ int addrcells, int sizecells)
+{
+ const struct membanks *mem = kernel_info_get_shm_mem_const(kinfo);
+ unsigned int i;
+ __be32 *cells;
+
+ BUG_ON(!nr_cells || !reg);
+
+ cells = ®[*nr_cells];
+ for ( i = 0; i < mem->nr_banks; i++ )
+ {
+ paddr_t start = mem->bank[i].start;
+ paddr_t size = mem->bank[i].size;
+
+ *nr_cells += addrcells + sizecells;
+ BUG_ON(*nr_cells >= DT_MEM_NODE_REG_RANGE_SIZE);
+ dt_child_set_range(&cells, addrcells, sizecells, start, size);
+ }
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/xen/static-shmem.h b/xen/include/xen/static-shmem.h
new file mode 100644
index 0000000000..76a4986912
--- /dev/null
+++ b/xen/include/xen/static-shmem.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef XEN_STATIC_SHMEM_H
+#define XEN_STATIC_SHMEM_H
+
+#include <xen/fdt-kernel.h>
+#include <xen/types.h>
+
+#ifdef CONFIG_STATIC_SHM
+
+/* Worst case /memory node reg element: (addrcells + sizecells) */
+#define DT_MEM_NODE_REG_RANGE_SIZE ((NR_MEM_BANKS + NR_SHMEM_BANKS) * 4)
+
+int make_resv_memory_node(const struct kernel_info *kinfo, int addrcells,
+ int sizecells);
+
+int process_shm(struct domain *d, struct kernel_info *kinfo,
+ const struct dt_device_node *node);
+
+int process_shm_node(const void *fdt, int node, uint32_t address_cells,
+ uint32_t size_cells);
+
+void early_print_info_shmem(void);
+
+void init_sharedmem_pages(void);
+
+int remove_shm_from_rangeset(const struct kernel_info *kinfo,
+ struct rangeset *rangeset);
+
+int make_shm_resv_memory_node(const struct kernel_info *kinfo, int addrcells,
+ int sizecells);
+
+void shm_mem_node_fill_reg_range(const struct kernel_info *kinfo, __be32 *reg,
+ int *nr_cells, int addrcells, int sizecells);
+
+static inline struct membanks *
+kernel_info_get_shm_mem(struct kernel_info *kinfo)
+{
+ return container_of(&kinfo->shm_mem.common, struct membanks, common);
+}
+
+static inline const struct membanks *
+kernel_info_get_shm_mem_const(const struct kernel_info *kinfo)
+{
+ return container_of(&kinfo->shm_mem.common, const struct membanks, common);
+}
+
+#else /* !CONFIG_STATIC_SHM */
+
+/* Worst case /memory node reg element: (addrcells + sizecells) */
+#define DT_MEM_NODE_REG_RANGE_SIZE (NR_MEM_BANKS * 4)
+
+static inline int make_resv_memory_node(const struct kernel_info *kinfo,
+ int addrcells, int sizecells)
+{
+ return 0;
+}
+
+static inline int process_shm(struct domain *d, struct kernel_info *kinfo,
+ const struct dt_device_node *node)
+{
+ return 0;
+}
+
+static inline void init_sharedmem_pages(void) {};
+
+static inline int remove_shm_from_rangeset(const struct kernel_info *kinfo,
+ struct rangeset *rangeset)
+{
+ return 0;
+}
+
+static inline int make_shm_resv_memory_node(const struct kernel_info *kinfo,
+ int addrcells, int sizecells)
+{
+ return 0;
+}
+
+static inline void shm_mem_node_fill_reg_range(const struct kernel_info *kinfo,
+ __be32 *reg, int *nr_cells,
+ int addrcells, int sizecells)
{};
+
+#endif /* CONFIG_STATIC_SHM */
+
+#endif /* XEN_STATIC_SHMEM_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--
generated by git-patchbot for /home/xen/git/xen.git#master
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |