|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v1 2/6] xen/riscv: introduce things necessary for p2m initialization
On 09.05.2025 17:57, Oleksii Kurochko wrote:
> --- a/xen/arch/riscv/include/asm/domain.h
> +++ b/xen/arch/riscv/include/asm/domain.h
> @@ -5,6 +5,8 @@
> #include <xen/xmalloc.h>
> #include <public/hvm/params.h>
>
> +#include <asm/p2m.h>
> +
> struct hvm_domain
> {
> uint64_t params[HVM_NR_PARAMS];
> @@ -16,8 +18,12 @@ struct arch_vcpu_io {
> struct arch_vcpu {
> };
>
> +
Nit: As before, no double blank lines please.
> struct arch_domain {
> struct hvm_domain hvm;
> +
> + struct p2m_domain p2m;
> +
> };
Similarly, no blank lines please at the end of a struct/union/enum.
> --- a/xen/arch/riscv/include/asm/mm.h
> +++ b/xen/arch/riscv/include/asm/mm.h
> @@ -149,6 +149,10 @@ extern struct page_info *frametable_virt_start;
> #define mfn_to_page(mfn) (frametable_virt_start + mfn_x(mfn))
> #define page_to_mfn(pg) _mfn((pg) - frametable_virt_start)
>
> +/* Convert between machine addresses and page-info structures. */
> +#define maddr_to_page(ma) mfn_to_page(maddr_to_mfn(ma))
> +#define page_to_maddr(pg) (mfn_to_maddr(page_to_mfn(pg)))
Nit: The outermost parentheses aren't really needed here. Or if you really
want them, then please be consistent and also add them for the other macro
you add.
> --- /dev/null
> +++ b/xen/arch/riscv/p2m.c
> @@ -0,0 +1,168 @@
> +#include <xen/domain_page.h>
> +#include <xen/iommu.h>
> +#include <xen/lib.h>
> +#include <xen/mm.h>
> +#include <xen/pfn.h>
> +#include <xen/rwlock.h>
> +#include <xen/sched.h>
> +#include <xen/spinlock.h>
> +
> +#include <asm/page.h>
> +#include <asm/p2m.h>
> +
> +/*
> + * Force a synchronous P2M TLB flush.
> + *
> + * Must be called with the p2m lock held.
> + *
> + * TODO: add support of flushing TLB connected to VMID.
> + */
> +static void p2m_force_tlb_flush_sync(struct p2m_domain *p2m)
> +{
> + ASSERT(p2m_is_write_locked(p2m));
> +
> + /*
> + * TODO: shouldn't be this flush done for each physical CPU?
> + * If yes, then SBI call sbi_remote_hfence_gvma() could
> + * be used for that.
> + */
> +#if defined(__riscv_hh) || defined(__riscv_h)
This is a compiler capability check (which would be applicable if you
used a built-in function below).
> + asm volatile ( "hfence.gvma" ::: "memory" );
Whereas here you use a feature in the assembler, at least for the GNU
toolchain.
> +static void clear_and_clean_page(struct page_info *page)
> +{
> + void *p = __map_domain_page(page);
> +
> + clear_page(p);
> + unmap_domain_page(p);
> +}
What's the "clean" about in the function name? The "clear" is referring
to the clear_page() call afaict. Also aren't you largely open-coding
clear_domain_page() here?
> +static struct page_info *p2m_get_clean_page(struct domain *d)
> +{
> + struct page_info *page;
> +
> + /*
> + * As mentioned in the Priviliged Architecture Spec (version 20240411)
> + * As explained in Section 18.5.1, for the paged virtual-memory schemes
> + * (Sv32x4, Sv39x4, Sv48x4, and Sv57x4), the root page table is 16 KiB
> + * and must be aligned to a 16-KiB boundary.
> + */
> + page = alloc_domheap_pages(NULL, 2, 0);
Shouldn't this allocation come from the domain's P2M pool (which is yet
to be introduced)? Also hard-coding 2 here as order effectively builds
in an assumption that PAGE_SIZE will only ever be 4k. I think to wants
properly calculating instead.
> + if ( page == NULL )
> + return NULL;
> +
> + clear_and_clean_page(page);
> +
> + return page;
> +}
Contrary to the function name you obtained 4 pages here, which is suitable
for ...
> +static struct page_info *p2m_allocate_root(struct domain *d)
> +{
> + return p2m_get_clean_page(d);
> +}
... this but - I expect - no anywhere else.
> +static unsigned long hgatp_from_page_info(struct page_info *page_info)
Except for the struct name please drop _info; we don#t use such anywhere
else.
> +{
> + unsigned long ppn;
> + unsigned long hgatp_mode;
> +
> + ppn = PFN_DOWN(page_to_maddr(page_info)) & HGATP_PPN;
> +
> + /* ASID (VMID) not supported yet */
> +
> +#if RV_STAGE1_MODE == SATP_MODE_SV39
> + hgatp_mode = HGATP_MODE_SV39X4;
> +#elif RV_STAGE1_MODE == SATP_MODE_SV48
> + hgatp_mode = HGATP_MODE_SV48X4;
> +#else
> + #error "add HGATP_MODE"
As before, please have the # of pre-processor directives in the first column.
> +#endif
> +
> + return ppn | (hgatp_mode << HGATP_MODE_SHIFT);
Use MASK_INSR()?
> +}
> +
> +static int p2m_alloc_table(struct domain *d)
> +{
> + struct p2m_domain *p2m = p2m_get_hostp2m(d);
> +
> + p2m->root = p2m_allocate_root(d);
> + if ( !p2m->root )
> + return -ENOMEM;
> +
> + p2m->hgatp = hgatp_from_page_info(p2m->root);
> +
> + /*
> + * Make sure that all TLBs corresponding to the new VMID are flushed
> + * before using it.
> + */
> + p2m_write_lock(p2m);
> + p2m_force_tlb_flush_sync(p2m);
> + p2m_write_unlock(p2m);
While Andrew directed you towards a better model in general, it won't be
usable here then, as the guest didn't run on any pCPU(s) yet. Imo you
want to do a single global flush e.g. when VMIDs wrap around. That'll be
fewer global flushes than one per VM creation.
> +int p2m_init(struct domain *d)
> +{
> + struct p2m_domain *p2m = p2m_get_hostp2m(d);
> + int rc;
> +
> + rwlock_init(&p2m->lock);
> + INIT_PAGE_LIST_HEAD(&p2m->pages);
> +
> + p2m->max_mapped_gfn = _gfn(0);
> + p2m->lowest_mapped_gfn = _gfn(ULONG_MAX);
You don't ever read these two fields. Likely better to introduce them when
they're actually needed. Same possibly for further things done in this
function.
> + p2m->default_access = p2m_access_rwx;
> +
> + radix_tree_init(&p2m->p2m_type);
> +
> +#ifdef CONFIG_HAS_PASSTHROUGH
> + /*
> + * Some IOMMUs don't support coherent PT walk. When the p2m is
> + * shared with the CPU, Xen has to make sure that the PT changes have
> + * reached the memory
> + */
> + p2m->clean_pte = is_iommu_enabled(d) &&
> + !iommu_has_feature(d, IOMMU_FEAT_COHERENT_WALK);
> +#else
> + p2m->clean_pte = true;
When there's no IOMMU (in use), doesn't this want to be "false"?
> +#endif
> +
> + /*
> + * "Trivial" initialisation is now complete. Set the backpointer so
> + * p2m_teardown() and friends know to do something.
> + */
> + p2m->domain = d;
And where is that p2m_teardown(), to cross-check the comment against?
Jan
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |