git: 1be2e16df1d2 - main - riscv: Add a stub pmap_change_attr implementation
Jessica Clarke
jrtc27 at FreeBSD.org
Sun Oct 3 18:36:47 UTC 2021
The branch main has been updated by jrtc27:
URL: https://cgit.FreeBSD.org/src/commit/?id=1be2e16df1d29148aee83964330a71ae403c6078
commit 1be2e16df1d29148aee83964330a71ae403c6078
Author: Jessica Clarke <jrtc27 at FreeBSD.org>
AuthorDate: 2021-10-03 18:33:47 +0000
Commit: Jessica Clarke <jrtc27 at FreeBSD.org>
CommitDate: 2021-10-03 18:33:47 +0000
riscv: Add a stub pmap_change_attr implementation
pmap_change_attr is required by drm-kmod so we need the function to
exist. Since the Svpbmt extension is on the horizon we will likely end
up with a real implementation of it, so this stub implementation does
all the necessary page table walking to validate the input, ensuring
that no new errors are returned once it's implemented fully (other than
due to out of memory conditions when demoting L2 entries) and providing
a skeleton for that future implementation.
Reviewed by: markj
MFC after: 1 week
Differential Revision: https://reviews.freebsd.org/D31996
---
sys/riscv/include/pmap.h | 1 +
sys/riscv/riscv/pmap.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 95 insertions(+)
diff --git a/sys/riscv/include/pmap.h b/sys/riscv/include/pmap.h
index 599adfa4ce19..024bc3743f67 100644
--- a/sys/riscv/include/pmap.h
+++ b/sys/riscv/include/pmap.h
@@ -144,6 +144,7 @@ struct thread;
void pmap_activate_boot(pmap_t);
void pmap_activate_sw(struct thread *);
void pmap_bootstrap(vm_offset_t, vm_paddr_t, vm_size_t);
+int pmap_change_attr(vm_offset_t va, vm_size_t size, int mode);
void pmap_kenter_device(vm_offset_t, vm_size_t, vm_paddr_t);
vm_paddr_t pmap_kextract(vm_offset_t va);
void pmap_kremove(vm_offset_t);
diff --git a/sys/riscv/riscv/pmap.c b/sys/riscv/riscv/pmap.c
index 8f76881478b9..df80f07df0ca 100644
--- a/sys/riscv/riscv/pmap.c
+++ b/sys/riscv/riscv/pmap.c
@@ -310,6 +310,8 @@ static void _pmap_unwire_ptp(pmap_t pmap, vm_offset_t va, vm_page_t m,
struct spglist *free);
static int pmap_unuse_pt(pmap_t, vm_offset_t, pd_entry_t, struct spglist *);
+static int pmap_change_attr_locked(vm_offset_t va, vm_size_t size, int mode);
+
#define pmap_clear(pte) pmap_store(pte, 0)
#define pmap_clear_bits(pte, bits) atomic_clear_64(pte, bits)
#define pmap_load_store(pte, entry) atomic_swap_64(pte, entry)
@@ -4252,6 +4254,98 @@ pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma)
{
m->md.pv_memattr = ma;
+
+ /*
+ * If "m" is a normal page, update its direct mapping. This update
+ * can be relied upon to perform any cache operations that are
+ * required for data coherence.
+ */
+ if ((m->flags & PG_FICTITIOUS) == 0 &&
+ pmap_change_attr(PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m)), PAGE_SIZE,
+ m->md.pv_memattr) != 0)
+ panic("memory attribute change on the direct map failed");
+}
+
+/*
+ * Changes the specified virtual address range's memory type to that given by
+ * the parameter "mode". The specified virtual address range must be
+ * completely contained within either the direct map or the kernel map.
+ *
+ * Returns zero if the change completed successfully, and either EINVAL or
+ * ENOMEM if the change failed. Specifically, EINVAL is returned if some part
+ * of the virtual address range was not mapped, and ENOMEM is returned if
+ * there was insufficient memory available to complete the change. In the
+ * latter case, the memory type may have been changed on some part of the
+ * virtual address range.
+ */
+int
+pmap_change_attr(vm_offset_t va, vm_size_t size, int mode)
+{
+ int error;
+
+ PMAP_LOCK(kernel_pmap);
+ error = pmap_change_attr_locked(va, size, mode);
+ PMAP_UNLOCK(kernel_pmap);
+ return (error);
+}
+
+static int
+pmap_change_attr_locked(vm_offset_t va, vm_size_t size, int mode)
+{
+ vm_offset_t base, offset, tmpva;
+ pd_entry_t *l1, l1e;
+ pd_entry_t *l2, l2e;
+ pt_entry_t *l3, l3e;
+
+ PMAP_LOCK_ASSERT(kernel_pmap, MA_OWNED);
+ base = trunc_page(va);
+ offset = va & PAGE_MASK;
+ size = round_page(offset + size);
+
+ if (!VIRT_IN_DMAP(base) &&
+ !(base >= VM_MIN_KERNEL_ADDRESS && base < VM_MAX_KERNEL_ADDRESS))
+ return (EINVAL);
+
+ for (tmpva = base; tmpva < base + size; ) {
+ l1 = pmap_l1(kernel_pmap, tmpva);
+ if (l1 == NULL || ((l1e = pmap_load(l1)) & PTE_V) == 0)
+ return (EINVAL);
+ if ((l1e & PTE_RWX) != 0) {
+ /*
+ * TODO: Demote if attributes don't match and there
+ * isn't an L1 page left in the range, and update the
+ * L1 entry if the attributes don't match but there is
+ * an L1 page left in the range, once we support the
+ * upcoming Svpbmt extension.
+ */
+ tmpva = (tmpva & ~L1_OFFSET) + L1_SIZE;
+ continue;
+ }
+ l2 = pmap_l1_to_l2(l1, tmpva);
+ if (l2 == NULL || ((l2e = pmap_load(l2)) & PTE_V) == 0)
+ return (EINVAL);
+ if ((l2e & PTE_RWX) != 0) {
+ /*
+ * TODO: Demote if attributes don't match and there
+ * isn't an L2 page left in the range, and update the
+ * L2 entry if the attributes don't match but there is
+ * an L2 page left in the range, once we support the
+ * upcoming Svpbmt extension.
+ */
+ tmpva = (tmpva & ~L2_OFFSET) + L2_SIZE;
+ continue;
+ }
+ l3 = pmap_l2_to_l3(l2, tmpva);
+ if (l3 == NULL || ((l3e = pmap_load(l3)) & PTE_V) == 0)
+ return (EINVAL);
+ /*
+ * TODO: Update the L3 entry if the attributes don't match once
+ * we support the upcoming Svpbmt extension.
+ */
+ tmpva += PAGE_SIZE;
+ }
+
+ return (0);
}
/*
More information about the dev-commits-src-main
mailing list