public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: Andrew Jones <andrew.jones@linux.dev>
To: kvm@vger.kernel.org, kvm-riscv@lists.infradead.org,
	kvmarm@lists.linux.dev
Cc: ajones@ventanamicro.com, anup@brainfault.org,
	atishp@atishpatra.org, pbonzini@redhat.com, thuth@redhat.com,
	alexandru.elisei@arm.com, eric.auger@redhat.com
Subject: [kvm-unit-tests PATCH 18/24] riscv: Add MMU support
Date: Wed, 24 Jan 2024 08:18:34 +0100	[thread overview]
Message-ID: <20240124071815.6898-44-andrew.jones@linux.dev> (raw)
In-Reply-To: <20240124071815.6898-26-andrew.jones@linux.dev>

Add minimal page table defines and functions in order to build page
tables and enable the MMU.

Signed-off-by: Andrew Jones <andrew.jones@linux.dev>
---
 lib/riscv/asm/csr.h     |   1 +
 lib/riscv/asm/io.h      |   3 +
 lib/riscv/asm/mmu.h     |  28 ++++++++
 lib/riscv/asm/page.h    |  11 ++++
 lib/riscv/asm/pgtable.h |  42 ++++++++++++
 lib/riscv/mmu.c         | 140 ++++++++++++++++++++++++++++++++++++++++
 lib/riscv/setup.c       |   3 +
 riscv/Makefile          |   1 +
 8 files changed, 229 insertions(+)
 create mode 100644 lib/riscv/asm/mmu.h
 create mode 100644 lib/riscv/asm/pgtable.h
 create mode 100644 lib/riscv/mmu.c

diff --git a/lib/riscv/asm/csr.h b/lib/riscv/asm/csr.h
index eeddd1fb448a..88c816c68d09 100644
--- a/lib/riscv/asm/csr.h
+++ b/lib/riscv/asm/csr.h
@@ -9,6 +9,7 @@
 #define CSR_SEPC		0x141
 #define CSR_SCAUSE		0x142
 #define CSR_STVAL		0x143
+#define CSR_SATP		0x180
 
 /* Exception cause high bit - is an interrupt if set */
 #define CAUSE_IRQ_FLAG		(_AC(1, UL) << (__riscv_xlen - 1))
diff --git a/lib/riscv/asm/io.h b/lib/riscv/asm/io.h
index d2eb3acc9fda..6fe111289102 100644
--- a/lib/riscv/asm/io.h
+++ b/lib/riscv/asm/io.h
@@ -73,6 +73,9 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
 }
 #endif
 
+#define ioremap ioremap
+void __iomem *ioremap(phys_addr_t phys_addr, size_t size);
+
 #include <asm-generic/io.h>
 
 #endif /* _ASMRISCV_IO_H_ */
diff --git a/lib/riscv/asm/mmu.h b/lib/riscv/asm/mmu.h
new file mode 100644
index 000000000000..02703f607511
--- /dev/null
+++ b/lib/riscv/asm/mmu.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASMRISCV_MMU_H_
+#define _ASMRISCV_MMU_H_
+#include <libcflat.h>
+#include <asm/csr.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+static inline pgd_t *current_pgtable(void)
+{
+	return (pgd_t *)((csr_read(CSR_SATP) & SATP_PPN) << PAGE_SHIFT);
+}
+
+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);
+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");
+}
+
+#endif /* _ASMRISCV_MMU_H_ */
diff --git a/lib/riscv/asm/page.h b/lib/riscv/asm/page.h
index 7d7c9191605a..9801b4d1b9c1 100644
--- a/lib/riscv/asm/page.h
+++ b/lib/riscv/asm/page.h
@@ -2,6 +2,17 @@
 #ifndef _ASMRISCV_PAGE_H_
 #define _ASMRISCV_PAGE_H_
 
+#ifndef __ASSEMBLY__
+
+typedef unsigned long pgd_t;
+typedef unsigned long pte_t;
+typedef unsigned long pgprot_t;
+typedef unsigned long pteval_t;
+
+#define __pgprot(x)		((pgprot_t)(x))
+
+#endif /* !__ASSEMBLY__ */
+
 #include <asm-generic/page.h>
 
 #endif /* _ASMRISCV_PAGE_H_ */
diff --git a/lib/riscv/asm/pgtable.h b/lib/riscv/asm/pgtable.h
new file mode 100644
index 000000000000..98d41ff9f661
--- /dev/null
+++ b/lib/riscv/asm/pgtable.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASMRISCV_PGTABLE_H_
+#define _ASMRISCV_PGTABLE_H_
+#include <linux/const.h>
+
+#if __riscv_xlen == 32
+#define SATP_PPN		_AC(0x003FFFFF, UL)
+#define SATP_MODE_32		_AC(0x80000000, UL)
+#define SATP_MODE_SHIFT		31
+#define NR_LEVELS		2
+#define PGDIR_BITS		10
+#define PGDIR_MASK		_AC(0x3FF, UL)
+#define PTE_PPN			_AC(0xFFFFFC00, UL)
+
+#define SATP_MODE_DEFAULT	SATP_MODE_32
+
+#else
+#define SATP_PPN		_AC(0x00000FFFFFFFFFFF, UL)
+#define SATP_MODE_39		_AC(0x8000000000000000, UL)
+#define SATP_MODE_SHIFT		60
+#define NR_LEVELS		3
+#define PGDIR_BITS		9
+#define PGDIR_MASK		_AC(0x1FF, UL)
+#define PTE_PPN			_AC(0x3FFFFFFFFFFC00, UL)
+
+#define SATP_MODE_DEFAULT	SATP_MODE_39
+
+#endif
+
+#define PPN_SHIFT		10
+
+#define _PAGE_PRESENT		(1 << 0)
+#define _PAGE_READ		(1 << 1)
+#define _PAGE_WRITE		(1 << 2)
+#define _PAGE_EXEC		(1 << 3)
+#define _PAGE_USER		(1 << 4)
+#define _PAGE_GLOBAL		(1 << 5)
+#define _PAGE_ACCESSED		(1 << 6)
+#define _PAGE_DIRTY		(1 << 7)
+#define _PAGE_SOFT		(3 << 8)
+
+#endif /* _ASMRISCV_PGTABLE_H_ */
diff --git a/lib/riscv/mmu.c b/lib/riscv/mmu.c
new file mode 100644
index 000000000000..6b1af518ddd8
--- /dev/null
+++ b/lib/riscv/mmu.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023, Ventana Micro Systems Inc., Andrew Jones <ajones@ventanamicro.com>
+ */
+#include <libcflat.h>
+#include <alloc_page.h>
+#include <memregions.h>
+#include <asm/csr.h>
+#include <asm/io.h>
+#include <asm/mmu.h>
+#include <asm/page.h>
+
+static pgd_t *__initial_pgtable;
+
+static int pte_index(uintptr_t vaddr, int level)
+{
+	return (vaddr >> (PGDIR_BITS * level + PAGE_SHIFT)) & PGDIR_MASK;
+}
+
+static pte_t *pte_to_ptep(pte_t pte)
+{
+	return (pte_t *)(((pte & PTE_PPN) >> PPN_SHIFT) << PAGE_SHIFT);
+}
+
+static pte_t ptep_to_pte(pte_t *ptep)
+{
+	return ((pte_t)ptep >> PAGE_SHIFT) << PPN_SHIFT;
+}
+
+static pteval_t *__install_page(pgd_t *pgtable, phys_addr_t paddr,
+				uintptr_t vaddr, pgprot_t prot, bool flush)
+{
+	phys_addr_t ppn = (paddr >> PAGE_SHIFT) << PPN_SHIFT;
+	pte_t pte = (pte_t)ppn;
+	pte_t *ptep = pgtable;
+
+	assert(pgtable && !((uintptr_t)pgtable & ~PAGE_MASK));
+	assert(!(ppn & ~PTE_PPN));
+
+	for (int level = NR_LEVELS - 1; level > 0; --level) {
+		pte_t *next = &ptep[pte_index(vaddr, level)];
+		if (!*next) {
+			void *page = alloc_page();
+			*next = ptep_to_pte(page) | _PAGE_PRESENT;
+		}
+		ptep = pte_to_ptep(*next);
+	}
+	ptep = &ptep[pte_index(vaddr, 0)];
+	*ptep = pte | prot | _PAGE_PRESENT;
+
+	if (flush)
+		local_flush_tlb_page(vaddr);
+
+	return (pteval_t *)ptep;
+}
+
+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)
+{
+	phys_addr_t paddr = phys_start & PAGE_MASK;
+	uintptr_t vaddr = virt_offset & PAGE_MASK;
+	uintptr_t virt_end = phys_end - paddr + vaddr;
+
+	assert(phys_start < phys_end);
+
+	for (; vaddr < virt_end; vaddr += PAGE_SIZE, paddr += PAGE_SIZE)
+		__install_page(pgtable, paddr, vaddr, prot, flush);
+}
+
+void mmu_disable(void)
+{
+	__asm__ __volatile__ (
+	"	csrw	" xstr(CSR_SATP) ", zero\n"
+	"	sfence.vma\n"
+	: : : "memory");
+}
+
+void __mmu_enable(unsigned long satp)
+{
+	__asm__ __volatile__ (
+	"	sfence.vma\n"
+	"	csrw	" xstr(CSR_SATP) ", %0\n"
+	: : "r" (satp) : "memory");
+}
+
+void mmu_enable(unsigned long mode, pgd_t *pgtable)
+{
+	unsigned long ppn = (unsigned long)pgtable >> PAGE_SHIFT;
+	unsigned long satp = mode | ppn;
+
+	assert(!(ppn & ~SATP_PPN));
+	__mmu_enable(satp);
+}
+
+void setup_mmu(void)
+{
+	struct mem_region *r;
+	pgd_t *pgtable;
+
+	if (!__initial_pgtable)
+		__initial_pgtable = alloc_page();
+	pgtable = __initial_pgtable;
+
+	for (r = mem_regions; r->end; ++r) {
+		if (r->flags & (MR_F_IO | MR_F_RESERVED))
+			continue;
+		if (r->flags & MR_F_CODE) {
+			mmu_set_range_ptes(pgtable, r->start, r->start, r->end,
+					   __pgprot(_PAGE_READ | _PAGE_EXEC), false);
+		} else {
+			mmu_set_range_ptes(pgtable, r->start, r->start, r->end,
+					   __pgprot(_PAGE_READ | _PAGE_WRITE), false);
+		}
+	}
+
+	mmu_enable(SATP_MODE_DEFAULT, pgtable);
+}
+
+void __iomem *ioremap(phys_addr_t phys_addr, size_t size)
+{
+	phys_addr_t start = phys_addr & PAGE_MASK;
+	phys_addr_t end = PAGE_ALIGN(phys_addr + size);
+	pgd_t *pgtable = current_pgtable();
+	bool flush = true;
+
+	assert(sizeof(long) == 8 || !(phys_addr >> 32));
+
+	if (!pgtable) {
+		if (!__initial_pgtable)
+			__initial_pgtable = alloc_page();
+		pgtable = __initial_pgtable;
+		flush = false;
+	}
+
+	mmu_set_range_ptes(pgtable, start, start, end,
+			   __pgprot(_PAGE_READ | _PAGE_WRITE), flush);
+
+	return (void __iomem *)(unsigned long)phys_addr;
+}
diff --git a/lib/riscv/setup.c b/lib/riscv/setup.c
index 848ec8e83496..c4c1bd58b337 100644
--- a/lib/riscv/setup.c
+++ b/lib/riscv/setup.c
@@ -14,6 +14,7 @@
 #include <memregions.h>
 #include <on-cpus.h>
 #include <asm/csr.h>
+#include <asm/mmu.h>
 #include <asm/page.h>
 #include <asm/processor.h>
 #include <asm/setup.h>
@@ -171,5 +172,7 @@ void setup(const void *fdt, phys_addr_t freemem_start)
 		setup_env(env, initrd_size);
 	}
 
+	setup_mmu();
+
 	banner();
 }
diff --git a/riscv/Makefile b/riscv/Makefile
index ed1a14025ed2..821891b719e7 100644
--- a/riscv/Makefile
+++ b/riscv/Makefile
@@ -29,6 +29,7 @@ cflatobjs += lib/memregions.o
 cflatobjs += lib/on-cpus.o
 cflatobjs += lib/riscv/bitops.o
 cflatobjs += lib/riscv/io.o
+cflatobjs += lib/riscv/mmu.o
 cflatobjs += lib/riscv/processor.o
 cflatobjs += lib/riscv/sbi.o
 cflatobjs += lib/riscv/setup.o
-- 
2.43.0


  parent reply	other threads:[~2024-01-24  7:19 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-24  7:18 [kvm-unit-tests PATCH 00/24] Introduce RISC-V Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 01/24] configure: Add ARCH_LIBDIR Andrew Jones
2024-01-24  9:33   ` Thomas Huth
2024-01-24  7:18 ` [kvm-unit-tests PATCH 02/24] riscv: Initial port, hello world Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 03/24] arm/arm64: Move cpumask.h to common lib Andrew Jones
2024-01-24  9:52   ` Thomas Huth
2024-01-24  7:18 ` [kvm-unit-tests PATCH 04/24] arm/arm64: Share cpu online, present and idle masks Andrew Jones
2024-01-24  9:53   ` Thomas Huth
2024-01-24  7:18 ` [kvm-unit-tests PATCH 05/24] riscv: Add DT parsing Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 06/24] riscv: Add initial SBI support Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 07/24] riscv: Add run script and unittests.cfg Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 08/24] riscv: Add riscv32 support Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 09/24] riscv: Add exception handling Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 10/24] riscv: Add backtrace support Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 11/24] arm/arm64: Generalize wfe/sev names in smp.c Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 12/24] arm/arm64: Remove spinlocks from on_cpu_async Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 13/24] arm/arm64: Share on_cpus Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 14/24] riscv: Compile with march Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 15/24] riscv: Add SMP support Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 16/24] arm/arm64: Share memregions Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 17/24] riscv: Populate memregions and switch to page allocator Andrew Jones
2024-01-24  7:18 ` Andrew Jones [this message]
2024-01-24  7:18 ` [kvm-unit-tests PATCH 19/24] riscv: Enable the MMU in secondaries Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 20/24] riscv: Enable vmalloc Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 21/24] lib: Add strcasecmp and strncasecmp Andrew Jones
2024-01-24  9:41   ` Thomas Huth
2024-01-24  7:18 ` [kvm-unit-tests PATCH 22/24] riscv: Add isa string parsing Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 23/24] gitlab-ci: Add riscv64 tests Andrew Jones
2024-01-24  9:45   ` Thomas Huth
2024-01-24 10:21     ` Andrew Jones
2024-01-24  7:18 ` [kvm-unit-tests PATCH 24/24] MAINTAINERS: Add riscv Andrew Jones
2024-01-24  9:46   ` Thomas Huth
2024-01-24  9:58 ` [kvm-unit-tests PATCH 00/24] Introduce RISC-V Thomas Huth

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240124071815.6898-44-andrew.jones@linux.dev \
    --to=andrew.jones@linux.dev \
    --cc=ajones@ventanamicro.com \
    --cc=alexandru.elisei@arm.com \
    --cc=anup@brainfault.org \
    --cc=atishp@atishpatra.org \
    --cc=eric.auger@redhat.com \
    --cc=kvm-riscv@lists.infradead.org \
    --cc=kvm@vger.kernel.org \
    --cc=kvmarm@lists.linux.dev \
    --cc=pbonzini@redhat.com \
    --cc=thuth@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox