@@ -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_ */
@@ -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");
@@ -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);
+}
@@ -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();
}
@@ -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
new file mode 120000
@@ -0,0 +1 @@
+../x86/sieve.c
\ No newline at end of file
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