[kvm-unit-tests PATCH 20/24] riscv: Enable vmalloc

Andrew Jones
2024-01-24T07:19:10Z

Implement the functions that vmalloc depends on and let it enable the
MMU through setup_vm(). We can now also run the sieve test, so we
add it as well.

Signed-off-by: Andrew Jones <andrew.jones@linux.dev>
---
lib/riscv/asm/io.h | 6 +++++
lib/riscv/asm/mmu.h | 2 --
lib/riscv/mmu.c | 57 ++++++++++++++++++++++++++++++++++++++++++++-
lib/riscv/setup.c | 16 ++++++++++---
riscv/Makefile | 3 ++-
riscv/sieve.c | 1 +
6 files changed, 78 insertions(+), 7 deletions(-)
create mode 120000 riscv/sieve.c

diff --git a/lib/riscv/asm/io.h b/lib/riscv/asm/io.h
index 6fe111289102..37a130e533c9 100644
--- a/lib/riscv/asm/io.h
+++ b/lib/riscv/asm/io.h
@@ -76,6 +76,12 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
#define ioremap ioremap
void __iomem *ioremap(phys_addr_t phys_addr, size_t size);

+#define virt_to_phys virt_to_phys
+unsigned long virt_to_phys(volatile void *address);
+
+#define phys_to_virt phys_to_virt
+void *phys_to_virt(unsigned long address);
+
#include <asm-generic/io.h>

#endif /* _ASMRISCV_IO_H_ */
diff --git a/lib/riscv/asm/mmu.h b/lib/riscv/asm/mmu.h
index 02703f607511..66e993800b45 100644
--- a/lib/riscv/asm/mmu.h
+++ b/lib/riscv/asm/mmu.h
@@ -18,8 +18,6 @@ void __mmu_enable(unsigned long satp);
void mmu_enable(unsigned long mode, pgd_t *pgtable);
void mmu_disable(void);

-void setup_mmu(void);
-
static inline void local_flush_tlb_page(unsigned long addr)
{
asm volatile("sfence.vma %0" : : "r" (addr) : "memory");
diff --git a/lib/riscv/mmu.c b/lib/riscv/mmu.c
index 6b1af518ddd8..e2fb15359773 100644
--- a/lib/riscv/mmu.c
+++ b/lib/riscv/mmu.c
@@ -5,6 +5,7 @@
#include <libcflat.h>
#include <alloc_page.h>
#include <memregions.h>
+#include <vmalloc.h>
#include <asm/csr.h>
#include <asm/io.h>
#include <asm/mmu.h>
@@ -54,6 +55,15 @@ static pteval_t *__install_page(pgd_t *pgtable, phys_addr_t paddr,
return (pteval_t *)ptep;
}

+pteval_t *install_page(pgd_t *pgtable, phys_addr_t phys, void *virt)
+{
+ phys_addr_t paddr = phys & PAGE_MASK;
+ uintptr_t vaddr = (uintptr_t)virt & PAGE_MASK;
+
+ return __install_page(pgtable, paddr, vaddr,
+ __pgprot(_PAGE_READ | _PAGE_WRITE), true);
+}
+
void mmu_set_range_ptes(pgd_t *pgtable, uintptr_t virt_offset,
phys_addr_t phys_start, phys_addr_t phys_end,
pgprot_t prot, bool flush)
@@ -93,7 +103,7 @@ void mmu_enable(unsigned long mode, pgd_t *pgtable)
__mmu_enable(satp);
}

-void setup_mmu(void)
+void *setup_mmu(phys_addr_t top, void *opaque)
{
struct mem_region *r;
pgd_t *pgtable;
@@ -115,6 +125,8 @@ void setup_mmu(void)
}

mmu_enable(SATP_MODE_DEFAULT, pgtable);
+
+ return pgtable;
}

void __iomem *ioremap(phys_addr_t phys_addr, size_t size)
@@ -138,3 +150,46 @@ void __iomem *ioremap(phys_addr_t phys_addr, size_t size)

return (void __iomem *)(unsigned long)phys_addr;
}
+
+phys_addr_t virt_to_pte_phys(pgd_t *pgtable, void *virt)
+{
+ uintptr_t vaddr = (uintptr_t)virt;
+ pte_t *ptep = pgtable;
+
+ assert(pgtable && !((uintptr_t)pgtable & ~PAGE_MASK));
+
+ for (int level = NR_LEVELS - 1; level > 0; --level) {
+ pte_t *next = &ptep[pte_index(vaddr, level)];
+ if (!(*next & _PAGE_PRESENT))
+ return 0;
+ ptep = pte_to_ptep(*next);
+ }
+ ptep = &ptep[pte_index(vaddr, 0)];
+
+ if (!(*ptep & _PAGE_PRESENT))
+ return 0;
+
+ return (((phys_addr_t)*ptep & PTE_PPN) >> PPN_SHIFT) << PAGE_SHIFT;
+}
+
+unsigned long virt_to_phys(volatile void *address)
+{
+ unsigned long satp = csr_read(CSR_SATP);
+ pgd_t *pgtable = (pgd_t *)((satp & SATP_PPN) << PAGE_SHIFT);
+ phys_addr_t paddr;
+
+ if ((satp >> SATP_MODE_SHIFT) == 0)
+ return __pa(address);
+
+ paddr = virt_to_pte_phys(pgtable, (void *)address);
+ assert(sizeof(long) == 8 || !(paddr >> 32));
+
+ return (unsigned long)paddr;
+}
+
+void *phys_to_virt(unsigned long address)
+{
+ /* @address must have an identity mapping for this to work. */
+ assert(virt_to_phys(__va(address)) == address);
+ return __va(address);
+}
diff --git a/lib/riscv/setup.c b/lib/riscv/setup.c
index c4c1bd58b337..40ff26a24cfc 100644
--- a/lib/riscv/setup.c
+++ b/lib/riscv/setup.c
@@ -9,10 +9,12 @@
#include <alloc_page.h>
#include <alloc_phys.h>
#include <argv.h>
+#include <auxinfo.h>
#include <cpumask.h>
#include <devicetree.h>
#include <memregions.h>
#include <on-cpus.h>
+#include <vmalloc.h>
#include <asm/csr.h>
#include <asm/mmu.h>
#include <asm/page.h>
@@ -20,6 +22,11 @@
#include <asm/setup.h>

#define VA_BASE ((phys_addr_t)3 * SZ_1G)
+#if __riscv_xlen == 64
+#define VA_TOP ((phys_addr_t)4 * SZ_1G)
+#else
+#define VA_TOP ((phys_addr_t)0)
+#endif

#define MAX_DT_MEM_REGIONS 16
#define NR_MEM_REGIONS (MAX_DT_MEM_REGIONS + 16)
@@ -106,6 +113,8 @@ static void mem_init(phys_addr_t freemem_start)
freemem_end = VA_BASE;
assert(freemem_end - freemem_start >= SZ_1M * 16);

+ init_alloc_vpage(__va(VA_TOP));
+
/*
* TODO: Remove the need for this phys allocator dance, since, as we
* can see with the assert, we could have gone straight to the page
@@ -137,7 +146,7 @@ void setup(const void *fdt, phys_addr_t freemem_start)
int ret;

assert(sizeof(long) == 8 || freemem_start < VA_BASE);
- freemem = (void *)(unsigned long)freemem_start;
+ freemem = __va(freemem_start);

/* Move the FDT to the base of free memory */
fdt_size = fdt_totalsize(fdt);
@@ -156,7 +165,7 @@ void setup(const void *fdt, phys_addr_t freemem_start)
freemem += initrd_size;
}

- mem_init(PAGE_ALIGN((unsigned long)freemem));
+ mem_init(PAGE_ALIGN(__pa(freemem)));
cpu_init();
thread_info_init();
io_init();
@@ -172,7 +181,8 @@ void setup(const void *fdt, phys_addr_t freemem_start)
setup_env(env, initrd_size);
}

- setup_mmu();
+ if (!(auxinfo.flags & AUXINFO_MMU_OFF))
+ setup_vm();

banner();
}
diff --git a/riscv/Makefile b/riscv/Makefile
index 821891b719e7..61a1ff88d8ec 100644
--- a/riscv/Makefile
+++ b/riscv/Makefile
@@ -13,7 +13,7 @@ endif
tests =
tests += $(TEST_DIR)/sbi.$(exe)
tests += $(TEST_DIR)/selftest.$(exe)
-#tests += $(TEST_DIR)/sieve.$(exe)
+tests += $(TEST_DIR)/sieve.$(exe)

all: $(tests)

@@ -27,6 +27,7 @@ cflatobjs += lib/alloc_phys.o
cflatobjs += lib/devicetree.o
cflatobjs += lib/memregions.o
cflatobjs += lib/on-cpus.o
+cflatobjs += lib/vmalloc.o
cflatobjs += lib/riscv/bitops.o
cflatobjs += lib/riscv/io.o
cflatobjs += lib/riscv/mmu.o
diff --git a/riscv/sieve.c b/riscv/sieve.c
new file mode 120000
index 000000000000..8f14a5c3d4aa
--- /dev/null
+++ b/riscv/sieve.c
@@ -0,0 +1 @@
+../x86/sieve.c
\ No newline at end of file
--
2.43.0