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 paging_freelist_init() to struct paging_domain. Signed-off-by: Oleksii Kurochko <oleksii.kuroc...@gmail.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 | 19 +++++++++ xen/arch/riscv/paging.c | 64 +++++++++++++++++++++++++++++ 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..8fdaeeb2e4 --- /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_init(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 ae937e9bdd..214b4861d2 100644 --- a/xen/arch/riscv/p2m.c +++ b/xen/arch/riscv/p2m.c @@ -2,6 +2,8 @@ #include <xen/rwlock.h> #include <xen/sched.h> +#include <asm/paging.h> + int p2m_init(struct domain *d) { struct p2m_domain *p2m = p2m_get_hostp2m(d); @@ -12,6 +14,8 @@ int p2m_init(struct domain *d) */ p2m->domain = d; + paging_domain_init(d); + rwlock_init(&p2m->lock); INIT_PAGE_LIST_HEAD(&p2m->pages); @@ -30,3 +34,18 @@ int p2m_init(struct domain *d) 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_init(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..8882be5ac9 --- /dev/null +++ b/xen/arch/riscv/paging.c @@ -0,0 +1,64 @@ +#include <xen/event.h> +#include <xen/lib.h> +#include <xen/mm.h> +#include <xen/sched.h> +#include <xen/spinlock.h> + +int paging_freelist_init(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.50.1