Implement p2m_set_allocation() to construct p2m pages pool for guests
based on required number of pages.
This is implemented by:
- Adding a `struct paging_domain` which contains a freelist, a
counter variable and a spinlock to `struct arch_domain` to
indicate the free p2m pages and the number of p2m total pages in
the p2m pages pool.
- Adding a helper `p2m_set_allocation` to set the p2m pages pool
size. This helper should be called before allocating memory for
a guest and is called from domain_p2m_set_allocation(), the latter
is a part of common dom0less code.
- Adding implementation of paging_freelist_adjust() and
paging_domain_init().
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
---
Changes in V5:
- Nothing changed. Only rebase.
---
Changes in V4:
- s/paging_freelist_init/paging_freelist_adjust.
- Add empty line between definiton of paging_freelist_adjust()
and paging_domain_init().
- Update commit message.
- Add Acked-by: Jan Beulich <jbeulich@suse.com>.
---
Changes in v3:
- Drop usage of p2m_ prefix inside struct paging_domain().
- Introduce paging_domain_init() to init paging struct.
---
Changes in v2:
- Drop the comment above inclusion of <xen/event.h> in riscv/p2m.c.
- Use ACCESS_ONCE() for lhs and rhs for the expressions in
p2m_set_allocation().
---
xen/arch/riscv/Makefile | 1 +
xen/arch/riscv/include/asm/Makefile | 1 -
xen/arch/riscv/include/asm/domain.h | 12 ++++++
xen/arch/riscv/include/asm/paging.h | 13 ++++++
xen/arch/riscv/p2m.c | 18 ++++++++
xen/arch/riscv/paging.c | 65 +++++++++++++++++++++++++++++
6 files changed, 109 insertions(+), 1 deletion(-)
create mode 100644 xen/arch/riscv/include/asm/paging.h
create mode 100644 xen/arch/riscv/paging.c
diff --git a/xen/arch/riscv/Makefile b/xen/arch/riscv/Makefile
index e2499210c8..6b912465b9 100644
--- a/xen/arch/riscv/Makefile
+++ b/xen/arch/riscv/Makefile
@@ -6,6 +6,7 @@ obj-y += imsic.o
obj-y += intc.o
obj-y += irq.o
obj-y += mm.o
+obj-y += paging.o
obj-y += pt.o
obj-y += p2m.o
obj-$(CONFIG_RISCV_64) += riscv64/
diff --git a/xen/arch/riscv/include/asm/Makefile b/xen/arch/riscv/include/asm/Makefile
index bfdf186c68..3824f31c39 100644
--- a/xen/arch/riscv/include/asm/Makefile
+++ b/xen/arch/riscv/include/asm/Makefile
@@ -6,7 +6,6 @@ generic-y += hardirq.h
generic-y += hypercall.h
generic-y += iocap.h
generic-y += irq-dt.h
-generic-y += paging.h
generic-y += percpu.h
generic-y += perfc_defn.h
generic-y += random.h
diff --git a/xen/arch/riscv/include/asm/domain.h b/xen/arch/riscv/include/asm/domain.h
index e688980efa..316e7c6c84 100644
--- a/xen/arch/riscv/include/asm/domain.h
+++ b/xen/arch/riscv/include/asm/domain.h
@@ -2,6 +2,8 @@
#ifndef ASM__RISCV__DOMAIN_H
#define ASM__RISCV__DOMAIN_H
+#include <xen/mm.h>
+#include <xen/spinlock.h>
#include <xen/xmalloc.h>
#include <public/hvm/params.h>
@@ -24,11 +26,21 @@ struct arch_vcpu {
struct vcpu_vmid vmid;
};
+struct paging_domain {
+ spinlock_t lock;
+ /* Free pages from the pre-allocated pool */
+ struct page_list_head freelist;
+ /* Number of pages from the pre-allocated pool */
+ unsigned long total_pages;
+};
+
struct arch_domain {
struct hvm_domain hvm;
/* Virtual MMU */
struct p2m_domain p2m;
+
+ struct paging_domain paging;
};
#include <xen/sched.h>
diff --git a/xen/arch/riscv/include/asm/paging.h b/xen/arch/riscv/include/asm/paging.h
new file mode 100644
index 0000000000..98d8b06d45
--- /dev/null
+++ b/xen/arch/riscv/include/asm/paging.h
@@ -0,0 +1,13 @@
+#ifndef ASM_RISCV_PAGING_H
+#define ASM_RISCV_PAGING_H
+
+#include <asm-generic/paging.h>
+
+struct domain;
+
+int paging_domain_init(struct domain *d);
+
+int paging_freelist_adjust(struct domain *d, unsigned long pages,
+ bool *preempted);
+
+#endif /* ASM_RISCV_PAGING_H */
diff --git a/xen/arch/riscv/p2m.c b/xen/arch/riscv/p2m.c
index 1b5fc7ffff..d670e7612a 100644
--- a/xen/arch/riscv/p2m.c
+++ b/xen/arch/riscv/p2m.c
@@ -11,6 +11,7 @@
#include <asm/csr.h>
#include <asm/flushtlb.h>
+#include <asm/paging.h>
#include <asm/riscv_encoding.h>
#include <asm/vmid.h>
@@ -112,8 +113,25 @@ int p2m_init(struct domain *d)
*/
p2m->domain = d;
+ paging_domain_init(d);
+
rwlock_init(&p2m->lock);
INIT_PAGE_LIST_HEAD(&p2m->pages);
return 0;
}
+
+/*
+ * Set the pool of pages to the required number of pages.
+ * Returns 0 for success, non-zero for failure.
+ * Call with d->arch.paging.lock held.
+ */
+int p2m_set_allocation(struct domain *d, unsigned long pages, bool *preempted)
+{
+ int rc;
+
+ if ( (rc = paging_freelist_adjust(d, pages, preempted)) )
+ return rc;
+
+ return 0;
+}
diff --git a/xen/arch/riscv/paging.c b/xen/arch/riscv/paging.c
new file mode 100644
index 0000000000..2df8de033b
--- /dev/null
+++ b/xen/arch/riscv/paging.c
@@ -0,0 +1,65 @@
+#include <xen/event.h>
+#include <xen/lib.h>
+#include <xen/mm.h>
+#include <xen/sched.h>
+#include <xen/spinlock.h>
+
+int paging_freelist_adjust(struct domain *d, unsigned long pages,
+ bool *preempted)
+{
+ struct page_info *pg;
+
+ ASSERT(spin_is_locked(&d->arch.paging.lock));
+
+ for ( ; ; )
+ {
+ if ( d->arch.paging.total_pages < pages )
+ {
+ /* Need to allocate more memory from domheap */
+ pg = alloc_domheap_page(d, MEMF_no_owner);
+ if ( pg == NULL )
+ {
+ printk(XENLOG_ERR "Failed to allocate pages.\n");
+ return -ENOMEM;
+ }
+ ACCESS_ONCE(d->arch.paging.total_pages)++;
+ page_list_add_tail(pg, &d->arch.paging.freelist);
+ }
+ else if ( d->arch.paging.total_pages > pages )
+ {
+ /* Need to return memory to domheap */
+ pg = page_list_remove_head(&d->arch.paging.freelist);
+ if ( pg )
+ {
+ ACCESS_ONCE(d->arch.paging.total_pages)--;
+ free_domheap_page(pg);
+ }
+ else
+ {
+ printk(XENLOG_ERR
+ "Failed to free pages, freelist is empty.\n");
+ return -ENOMEM;
+ }
+ }
+ else
+ break;
+
+ /* Check to see if we need to yield and try again */
+ if ( preempted && general_preempt_check() )
+ {
+ *preempted = true;
+ return -ERESTART;
+ }
+ }
+
+ return 0;
+}
+
+/* Domain paging struct initialization. */
+int paging_domain_init(struct domain *d)
+{
+ spin_lock_init(&d->arch.paging.lock);
+ INIT_PAGE_LIST_HEAD(&d->arch.paging.freelist);
+
+ return 0;
+}
--
2.51.0