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@xxxxxxxxx> --- 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