[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v2 for 4.20? 1/3] xen/riscv: implement software page table walking
RISC-V doesn't have hardware feature to ask MMU to translate virtual address to physical address ( like Arm has, for example ), so software page table walking is implemented. As pte_walk() returns pte_t and it requires inclusion of <asm/page.h> in <asm/mm.h>, the following compilation started to occur after this inclusion: - implicit declaration of function 'GENMASK'. To resolve this, <xen/bitops.h> needs to be included at the top of <asm/cmpxchg.h>. - implicit declaration of map_domain_page() and unmap_domain_page(). This issue arises because, after including <asm/page.h> in <asm/mm.h>, we could have the following hierarchy if someone decides to include <xen/domain.h>: <xen/domain_page.h> <xen/mm.h> <asm/mm.h> <asm/page.h> <xen/domain_page.h> ... flush_to_ram() which uses {un}map_domain_page() <--- ... Declaration of {un}map_domain_page() happens here <--- To avoid this compilation issue, definition of flush_to_ram() is moved to mm.c. Signed-off-by: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx> --- Changes in v2: - Update the code of pt_walk() to return pte_t instead of paddr_t. - Fix typos and drop blankets inside parentheses in the comment. - Update the `ret` handling; there is no need for `mfn` calculation anymore as pt_walk() returns or pte_t of a leaf node or non-present pte_t. - Drop the comment before unmap_table(). - Drop local variable `pa` as pt_walk() is going to return pte_t instead of paddr_t. - Add the comment above pt_walk() to explain what it does and returns. - Add additional explanation about possible return values of pt_next_level() used inside while loop in pt_walk(). - Change `pa` to `table` in the comment before while loop in pt_walk() as actually this loop finds a page table where paga table entry for `va` is located. - After including <asm/page.h> in <asm/mm.h>, the following compilation error occurs: ./arch/riscv/include/asm/cmpxchg.h:56:9: error: implicit declaration of function 'GENMASK' To resolve this, <xen/bitops.h> needs to be included at the top of <asm/cmpxchg.h>. - To avoid an issue with the implicit declaration of map_domain_page() and unmap_domain_page() after including <asm/page.h> in <asm/mm.h>, the implementation of flush_page_to_ram() has been moved to mm.c. (look for more detailed explanation in the commit message) As a result drop inclusion of <xen/domain.h> in <asm/page.h>. - Update the commit message --- xen/arch/riscv/include/asm/cmpxchg.h | 1 + xen/arch/riscv/include/asm/mm.h | 4 ++ xen/arch/riscv/include/asm/page.h | 14 +------ xen/arch/riscv/mm.c | 14 +++++++ xen/arch/riscv/pt.c | 55 ++++++++++++++++++++++++++++ 5 files changed, 75 insertions(+), 13 deletions(-) diff --git a/xen/arch/riscv/include/asm/cmpxchg.h b/xen/arch/riscv/include/asm/cmpxchg.h index 662d3fd5d4..4cfe5927b7 100644 --- a/xen/arch/riscv/include/asm/cmpxchg.h +++ b/xen/arch/riscv/include/asm/cmpxchg.h @@ -4,6 +4,7 @@ #ifndef ASM__RISCV__CMPXCHG_H #define ASM__RISCV__CMPXCHG_H +#include <xen/bitops.h> #include <xen/compiler.h> #include <xen/lib.h> diff --git a/xen/arch/riscv/include/asm/mm.h b/xen/arch/riscv/include/asm/mm.h index 292aa48fc1..10a15a8b03 100644 --- a/xen/arch/riscv/include/asm/mm.h +++ b/xen/arch/riscv/include/asm/mm.h @@ -156,6 +156,10 @@ static inline struct page_info *virt_to_page(const void *v) return frametable_virt_start + PFN_DOWN(va - directmap_virt_start); } +#include <asm/page.h> + +pte_t * pt_walk(vaddr_t va, unsigned int *pte_level); + /* * Common code requires get_page_type and put_page_type. * We don't care about typecounts so we just do the minimum to make it diff --git a/xen/arch/riscv/include/asm/page.h b/xen/arch/riscv/include/asm/page.h index 7a6174a109..b9076173f4 100644 --- a/xen/arch/riscv/include/asm/page.h +++ b/xen/arch/riscv/include/asm/page.h @@ -7,7 +7,6 @@ #include <xen/bug.h> #include <xen/const.h> -#include <xen/domain_page.h> #include <xen/errno.h> #include <xen/types.h> @@ -177,18 +176,7 @@ static inline void invalidate_icache(void) #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) #define copy_page(dp, sp) memcpy(dp, sp, PAGE_SIZE) -static inline void flush_page_to_ram(unsigned long mfn, bool sync_icache) -{ - const void *v = map_domain_page(_mfn(mfn)); - - if ( clean_and_invalidate_dcache_va_range(v, PAGE_SIZE) ) - BUG(); - - unmap_domain_page(v); - - if ( sync_icache ) - invalidate_icache(); -} +void flush_page_to_ram(unsigned long mfn, bool sync_icache); /* Write a pagetable entry. */ static inline void write_pte(pte_t *p, pte_t pte) diff --git a/xen/arch/riscv/mm.c b/xen/arch/riscv/mm.c index f2bf279bac..32574c879b 100644 --- a/xen/arch/riscv/mm.c +++ b/xen/arch/riscv/mm.c @@ -3,6 +3,7 @@ #include <xen/bootfdt.h> #include <xen/bug.h> #include <xen/compiler.h> +#include <xen/domain_page.h> #include <xen/init.h> #include <xen/kernel.h> #include <xen/libfdt/libfdt.h> @@ -564,3 +565,16 @@ void *__init arch_vmap_virt_end(void) { return (void *)(VMAP_VIRT_START + VMAP_VIRT_SIZE); } + +void flush_page_to_ram(unsigned long mfn, bool sync_icache) +{ + const void *v = map_domain_page(_mfn(mfn)); + + if ( clean_and_invalidate_dcache_va_range(v, PAGE_SIZE) ) + BUG(); + + unmap_domain_page(v); + + if ( sync_icache ) + invalidate_icache(); +} diff --git a/xen/arch/riscv/pt.c b/xen/arch/riscv/pt.c index a703e0f1bd..2a5a191a70 100644 --- a/xen/arch/riscv/pt.c +++ b/xen/arch/riscv/pt.c @@ -274,6 +274,61 @@ static int pt_update_entry(mfn_t root, vaddr_t virt, return rc; } +/* + * pt_walk() performs software page table walking and returns the pte_t of + * a leaf node or the leaf-most not-present pte_t if no leaf node is found + * for further analysis. + * Additionally, pt_walk() returns the level of the found pte. + */ +pte_t * pt_walk(vaddr_t va, unsigned int *pte_level) +{ + const mfn_t root = get_root_page(); + /* + * In pt_walk() only XEN_TABLE_MAP_NONE and XEN_TABLE_SUPER_PAGE are + * handled (as they are only possible for page table walking), so + * initialize `ret` with "impossible" XEN_TABLE_MAP_NOMEM. + */ + int ret = XEN_TABLE_MAP_NOMEM; + unsigned int level = HYP_PT_ROOT_LEVEL; + pte_t *table; + + DECLARE_OFFSETS(offsets, va); + + table = map_table(root); + + /* + * Find `table` of an entry which corresponds to `va` by iterating for each + * page level and checking if the entry points to a next page table or + * to a page. + * + * Two cases are possible: + * - ret == XEN_TABLE_SUPER_PAGE means that the entry was find; + * (Despite the name) XEN_TABLE_SUPER_PAGE also covers 4K mappings. If + * pt_next_level() is called for page table level 0, it results in the + * entry being a pointer to a leaf node, thereby returning + * XEN_TABLE_SUPER_PAGE, despite of the fact this leaf covers 4k mapping. + * - ret == XEN_TABLE_MAP_NONE means that requested `va` wasn't actually + * mapped. + */ + while ( (ret != XEN_TABLE_MAP_NONE) && (ret != XEN_TABLE_SUPER_PAGE) ) + { + /* + * This case shouldn't really occur as it will mean that for table + * level 0 a pointer to next page table has been written, but at + * level 0 it could be only a pointer to 4k page. + */ + ASSERT(level <= HYP_PT_ROOT_LEVEL); + + ret = pt_next_level(false, &table, offsets[level]); + level--; + } + + if ( pte_level ) + *pte_level = level + 1; + + return table + offsets[level + 1]; +} + /* Return the level where mapping should be done */ static int pt_mapping_level(unsigned long vfn, mfn_t mfn, unsigned long nr, unsigned int flags) -- 2.48.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |