svn commit: r327992 - in head/sys/powerpc: aim booke include powerpc

Nathan Whitehorn nwhitehorn at FreeBSD.org
Mon Jan 15 06:46:35 UTC 2018


Author: nwhitehorn
Date: Mon Jan 15 06:46:33 2018
New Revision: 327992
URL: https://svnweb.freebsd.org/changeset/base/327992

Log:
  Move the pmap-specific code in copyinout.c that gets pointers to userland
  buffers into a new pmap-module function pmap_map_user_ptr() that can
  be implemented by the respective modules. This is required to implement
  non-segment-based AIM-ish MMU systems such as the radix-tree page tables
  introduced by POWER ISA 3.0 and present on POWER9.
  
  Reviewed by:	jhibbits

Modified:
  head/sys/powerpc/aim/mmu_oea.c
  head/sys/powerpc/aim/mmu_oea64.c
  head/sys/powerpc/booke/pmap.c
  head/sys/powerpc/include/pmap.h
  head/sys/powerpc/powerpc/copyinout.c
  head/sys/powerpc/powerpc/mmu_if.m
  head/sys/powerpc/powerpc/pmap_dispatch.c

Modified: head/sys/powerpc/aim/mmu_oea.c
==============================================================================
--- head/sys/powerpc/aim/mmu_oea.c	Mon Jan 15 05:00:26 2018	(r327991)
+++ head/sys/powerpc/aim/mmu_oea.c	Mon Jan 15 06:46:33 2018	(r327992)
@@ -320,7 +320,10 @@ void moea_dumpsys_map(mmu_t mmu, vm_paddr_t pa, size_t
 void moea_scan_init(mmu_t mmu);
 vm_offset_t moea_quick_enter_page(mmu_t mmu, vm_page_t m);
 void moea_quick_remove_page(mmu_t mmu, vm_offset_t addr);
+static int moea_map_user_ptr(mmu_t mmu, pmap_t pm,
+    volatile const void *uaddr, void **kaddr, size_t ulen, size_t *klen);
 
+
 static mmu_method_t moea_methods[] = {
 	MMUMETHOD(mmu_clear_modify,	moea_clear_modify),
 	MMUMETHOD(mmu_copy_page,	moea_copy_page),
@@ -370,6 +373,7 @@ static mmu_method_t moea_methods[] = {
 	MMUMETHOD(mmu_dev_direct_mapped,moea_dev_direct_mapped),
 	MMUMETHOD(mmu_scan_init,	moea_scan_init),
 	MMUMETHOD(mmu_dumpsys_map,	moea_dumpsys_map),
+	MMUMETHOD(mmu_map_user_ptr,	moea_map_user_ptr),
 
 	{ 0, 0 }
 };
@@ -1542,6 +1546,45 @@ moea_kremove(mmu_t mmu, vm_offset_t va)
 {
 
 	moea_remove(mmu, kernel_pmap, va, va + PAGE_SIZE);
+}
+
+/*
+ * Provide a kernel pointer corresponding to a given userland pointer.
+ * The returned pointer is valid until the next time this function is
+ * called in this thread. This is used internally in copyin/copyout.
+ */
+int
+moea_map_user_ptr(mmu_t mmu, pmap_t pm, volatile const void *uaddr,
+    void **kaddr, size_t ulen, size_t *klen)
+{
+	size_t l;
+	register_t vsid;
+
+	*kaddr = (char *)USER_ADDR + ((uintptr_t)uaddr & ~SEGMENT_MASK);
+	l = ((char *)USER_ADDR + SEGMENT_LENGTH) - (char *)(*kaddr);
+	if (l > ulen)
+		l = ulen;
+	if (klen)
+		*klen = l;
+	else if (l != ulen)
+		return (EFAULT);
+
+	vsid = va_to_vsid(pm, (vm_offset_t)uaddr);
+ 
+	/* Mark segment no-execute */
+	vsid |= SR_N;
+ 
+	/* If we have already set this VSID, we can just return */
+	if (curthread->td_pcb->pcb_cpu.aim.usr_vsid == vsid)
+		return (0);
+ 
+	__asm __volatile("isync");
+	curthread->td_pcb->pcb_cpu.aim.usr_segm =
+	    (uintptr_t)uaddr >> ADDR_SR_SHFT;
+	curthread->td_pcb->pcb_cpu.aim.usr_vsid = vsid;
+	__asm __volatile("mtsr %0,%1; isync" :: "n"(USER_SR), "r"(vsid));
+
+	return (0);
 }
 
 /*

Modified: head/sys/powerpc/aim/mmu_oea64.c
==============================================================================
--- head/sys/powerpc/aim/mmu_oea64.c	Mon Jan 15 05:00:26 2018	(r327991)
+++ head/sys/powerpc/aim/mmu_oea64.c	Mon Jan 15 06:46:33 2018	(r327992)
@@ -284,7 +284,10 @@ void moea64_dumpsys_map(mmu_t mmu, vm_paddr_t pa, size
 void moea64_scan_init(mmu_t mmu);
 vm_offset_t moea64_quick_enter_page(mmu_t mmu, vm_page_t m);
 void moea64_quick_remove_page(mmu_t mmu, vm_offset_t addr);
+static int moea64_map_user_ptr(mmu_t mmu, pmap_t pm,
+    volatile const void *uaddr, void **kaddr, size_t ulen, size_t *klen);
 
+
 static mmu_method_t moea64_methods[] = {
 	MMUMETHOD(mmu_clear_modify,	moea64_clear_modify),
 	MMUMETHOD(mmu_copy_page,	moea64_copy_page),
@@ -333,6 +336,7 @@ static mmu_method_t moea64_methods[] = {
 	MMUMETHOD(mmu_dev_direct_mapped,moea64_dev_direct_mapped),
 	MMUMETHOD(mmu_scan_init,	moea64_scan_init),
 	MMUMETHOD(mmu_dumpsys_map,	moea64_dumpsys_map),
+	MMUMETHOD(mmu_map_user_ptr,	moea64_map_user_ptr),
 
 	{ 0, 0 }
 };
@@ -1831,6 +1835,70 @@ void
 moea64_kremove(mmu_t mmu, vm_offset_t va)
 {
 	moea64_remove(mmu, kernel_pmap, va, va + PAGE_SIZE);
+}
+
+/*
+ * Provide a kernel pointer corresponding to a given userland pointer.
+ * The returned pointer is valid until the next time this function is
+ * called in this thread. This is used internally in copyin/copyout.
+ */
+static int
+moea64_map_user_ptr(mmu_t mmu, pmap_t pm, volatile const void *uaddr,
+    void **kaddr, size_t ulen, size_t *klen)
+{
+	size_t l;
+#ifdef __powerpc64__
+	struct slb *slb;
+#endif
+	register_t slbv;
+
+	*kaddr = (char *)USER_ADDR + ((uintptr_t)uaddr & ~SEGMENT_MASK);
+	l = ((char *)USER_ADDR + SEGMENT_LENGTH) - (char *)(*kaddr);
+	if (l > ulen)
+		l = ulen;
+	if (klen)
+		*klen = l;
+	else if (l != ulen)
+		return (EFAULT);
+
+#ifdef __powerpc64__
+	/* Try lockless look-up first */
+	slb = user_va_to_slb_entry(pm, (vm_offset_t)uaddr);
+
+	if (slb == NULL) {
+		/* If it isn't there, we need to pre-fault the VSID */
+		PMAP_LOCK(pm);
+		slbv = va_to_vsid(pm, (vm_offset_t)uaddr) << SLBV_VSID_SHIFT;
+		PMAP_UNLOCK(pm);
+	} else {
+		slbv = slb->slbv;
+	}
+
+	/* Mark segment no-execute */
+	slbv |= SLBV_N;
+#else
+	slbv = va_to_vsid(pm, (vm_offset_t)uaddr);
+
+	/* Mark segment no-execute */
+	slbv |= SR_N;
+#endif
+
+	/* If we have already set this VSID, we can just return */
+	if (curthread->td_pcb->pcb_cpu.aim.usr_vsid == slbv)
+		return (0);
+  
+	__asm __volatile("isync");
+	curthread->td_pcb->pcb_cpu.aim.usr_segm =
+	    (uintptr_t)uaddr >> ADDR_SR_SHFT;
+	curthread->td_pcb->pcb_cpu.aim.usr_vsid = slbv;
+#ifdef __powerpc64__
+	__asm __volatile ("slbie %0; slbmte %1, %2; isync" ::
+	    "r"(USER_ADDR), "r"(slbv), "r"(USER_SLB_SLBE));
+#else
+	__asm __volatile("mtsr %0,%1; isync" :: "n"(USER_SR), "r"(slbv));
+#endif
+
+	return (0);
 }
 
 /*

Modified: head/sys/powerpc/booke/pmap.c
==============================================================================
--- head/sys/powerpc/booke/pmap.c	Mon Jan 15 05:00:26 2018	(r327991)
+++ head/sys/powerpc/booke/pmap.c	Mon Jan 15 06:46:33 2018	(r327992)
@@ -380,7 +380,10 @@ static vm_offset_t	mmu_booke_quick_enter_page(mmu_t mm
 static void		mmu_booke_quick_remove_page(mmu_t mmu, vm_offset_t addr);
 static int		mmu_booke_change_attr(mmu_t mmu, vm_offset_t addr,
     vm_size_t sz, vm_memattr_t mode);
+static int		mmu_booke_map_user_ptr(mmu_t mmu, pmap_t pm,
+    volatile const void *uaddr, void **kaddr, size_t ulen, size_t *klen);
 
+
 static mmu_method_t mmu_booke_methods[] = {
 	/* pmap dispatcher interface */
 	MMUMETHOD(mmu_clear_modify,	mmu_booke_clear_modify),
@@ -432,6 +435,7 @@ static mmu_method_t mmu_booke_methods[] = {
 	MMUMETHOD(mmu_kremove,		mmu_booke_kremove),
 	MMUMETHOD(mmu_unmapdev,		mmu_booke_unmapdev),
 	MMUMETHOD(mmu_change_attr,	mmu_booke_change_attr),
+	MMUMETHOD(mmu_map_user_ptr,	mmu_booke_map_user_ptr),
 
 	/* dumpsys() support */
 	MMUMETHOD(mmu_dumpsys_map,	mmu_booke_dumpsys_map),
@@ -2265,6 +2269,26 @@ mmu_booke_kremove(mmu_t mmu, vm_offset_t va)
 
 	tlb_miss_unlock();
 	mtx_unlock_spin(&tlbivax_mutex);
+}
+
+/*
+ * Provide a kernel pointer corresponding to a given userland pointer.
+ * The returned pointer is valid until the next time this function is
+ * called in this thread. This is used internally in copyin/copyout.
+ */
+int
+mmu_booke_map_user_ptr(mmu_t mmu, pmap_t pm, volatile const void *uaddr,
+    void **kaddr, size_t ulen, size_t *klen)
+{
+
+	if ((uintptr_t)uaddr + ulen > VM_MAXUSER_ADDRESS + PAGE_SIZE)
+		return (EFAULT);
+
+	*kaddr = (void *)(uintptr_t)uaddr;
+	if (klen)
+		*klen = ulen;
+
+	return (0);
 }
 
 /*

Modified: head/sys/powerpc/include/pmap.h
==============================================================================
--- head/sys/powerpc/include/pmap.h	Mon Jan 15 05:00:26 2018	(r327991)
+++ head/sys/powerpc/include/pmap.h	Mon Jan 15 06:46:33 2018	(r327992)
@@ -260,6 +260,8 @@ void		*pmap_mapdev_attr(vm_paddr_t, vm_size_t, vm_mema
 void		pmap_unmapdev(vm_offset_t, vm_size_t);
 void		pmap_page_set_memattr(vm_page_t, vm_memattr_t);
 int		pmap_change_attr(vm_offset_t, vm_size_t, vm_memattr_t);
+int		pmap_map_user_ptr(pmap_t pm, volatile const void *uaddr,
+		    void **kaddr, size_t ulen, size_t *klen);
 void		pmap_deactivate(struct thread *);
 vm_paddr_t	pmap_kextract(vm_offset_t);
 int		pmap_dev_direct_mapped(vm_paddr_t, vm_size_t);

Modified: head/sys/powerpc/powerpc/copyinout.c
==============================================================================
--- head/sys/powerpc/powerpc/copyinout.c	Mon Jan 15 05:00:26 2018	(r327991)
+++ head/sys/powerpc/powerpc/copyinout.c	Mon Jan 15 06:46:33 2018	(r327992)
@@ -69,108 +69,8 @@ __FBSDID("$FreeBSD$");
 #include <vm/vm_map.h>
 
 #include <machine/pcb.h>
-#include <machine/sr.h>
-#include <machine/slb.h>
 #include <machine/vmparam.h>
 
-#ifdef AIM
-/*
- * Makes sure that the right segment of userspace is mapped in.
- */
-
-#ifdef __powerpc64__
-static __inline void
-set_user_sr(pmap_t pm, volatile const void *addr)
-{
-	struct slb *slb;
-	register_t slbv;
-
-	/* Try lockless look-up first */
-	slb = user_va_to_slb_entry(pm, (vm_offset_t)addr);
-
-	if (slb == NULL) {
-		/* If it isn't there, we need to pre-fault the VSID */
-		PMAP_LOCK(pm);
-		slbv = va_to_vsid(pm, (vm_offset_t)addr) << SLBV_VSID_SHIFT;
-		PMAP_UNLOCK(pm);
-	} else {
-		slbv = slb->slbv;
-	}
-
-	/* Mark segment no-execute */
-	slbv |= SLBV_N;
-
-	/* If we have already set this VSID, we can just return */
-	if (curthread->td_pcb->pcb_cpu.aim.usr_vsid == slbv) 
-		return;
-
-	__asm __volatile("isync");
-	curthread->td_pcb->pcb_cpu.aim.usr_segm =
-	    (uintptr_t)addr >> ADDR_SR_SHFT;
-	curthread->td_pcb->pcb_cpu.aim.usr_vsid = slbv;
-	__asm __volatile ("slbie %0; slbmte %1, %2; isync" ::
-	    "r"(USER_ADDR), "r"(slbv), "r"(USER_SLB_SLBE));
-}
-#else
-static __inline void
-set_user_sr(pmap_t pm, volatile const void *addr)
-{
-	register_t vsid;
-
-	vsid = va_to_vsid(pm, (vm_offset_t)addr);
-
-	/* Mark segment no-execute */
-	vsid |= SR_N;
-
-	/* If we have already set this VSID, we can just return */
-	if (curthread->td_pcb->pcb_cpu.aim.usr_vsid == vsid)
-		return;
-
-	__asm __volatile("isync");
-	curthread->td_pcb->pcb_cpu.aim.usr_segm =
-	    (uintptr_t)addr >> ADDR_SR_SHFT;
-	curthread->td_pcb->pcb_cpu.aim.usr_vsid = vsid;
-	__asm __volatile("mtsr %0,%1; isync" :: "n"(USER_SR), "r"(vsid));
-}
-#endif
-
-static __inline int
-map_user_ptr(pmap_t pm, volatile const void *uaddr, void **kaddr, size_t ulen,
-    size_t *klen)
-{
-	size_t l;
-
-	*kaddr = (char *)USER_ADDR + ((uintptr_t)uaddr & ~SEGMENT_MASK);
-
-	l = ((char *)USER_ADDR + SEGMENT_LENGTH) - (char *)(*kaddr);
-	if (l > ulen)
-		l = ulen;
-	if (klen)
-		*klen = l;
-	else if (l != ulen)
-		return (EFAULT);
-
-	set_user_sr(pm, uaddr);
-
-	return (0);
-}
-#else /* Book-E uses a combined kernel/user mapping */
-static __inline int
-map_user_ptr(pmap_t pm, volatile const void *uaddr, void **kaddr, size_t ulen,
-    size_t *klen)
-{
-
-	if ((uintptr_t)uaddr + ulen > VM_MAXUSER_ADDRESS + PAGE_SIZE)
-		return (EFAULT);
-
-	*kaddr = (void *)(uintptr_t)uaddr;
-	if (klen)
-		*klen = ulen;
-
-	return (0);
-}
-#endif
-
 int
 copyout(const void *kaddr, void *udaddr, size_t len)
 {
@@ -194,7 +94,7 @@ copyout(const void *kaddr, void *udaddr, size_t len)
 	up = udaddr;
 
 	while (len > 0) {
-		if (map_user_ptr(pm, udaddr, (void **)&p, len, &l)) {
+		if (pmap_map_user_ptr(pm, udaddr, (void **)&p, len, &l)) {
 			td->td_pcb->pcb_onfault = NULL;
 			return (EFAULT);
 		}
@@ -233,7 +133,7 @@ copyin(const void *udaddr, void *kaddr, size_t len)
 	up = udaddr;
 
 	while (len > 0) {
-		if (map_user_ptr(pm, udaddr, (void **)&p, len, &l)) {
+		if (pmap_map_user_ptr(pm, udaddr, (void **)&p, len, &l)) {
 			td->td_pcb->pcb_onfault = NULL;
 			return (EFAULT);
 		}
@@ -299,7 +199,7 @@ subyte(volatile void *addr, int byte)
 		return (-1);
 	}
 
-	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
+	if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
 		td->td_pcb->pcb_onfault = NULL;
 		return (-1);
 	}
@@ -328,7 +228,7 @@ suword32(volatile void *addr, int word)
 		return (-1);
 	}
 
-	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
+	if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
 		td->td_pcb->pcb_onfault = NULL;
 		return (-1);
 	}
@@ -357,7 +257,7 @@ suword(volatile void *addr, long word)
 		return (-1);
 	}
 
-	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
+	if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
 		td->td_pcb->pcb_onfault = NULL;
 		return (-1);
 	}
@@ -400,7 +300,7 @@ fubyte(volatile const void *addr)
 		return (-1);
 	}
 
-	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
+	if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
 		td->td_pcb->pcb_onfault = NULL;
 		return (-1);
 	}
@@ -428,7 +328,7 @@ fuword16(volatile const void *addr)
 		return (-1);
 	}
 
-	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
+	if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
 		td->td_pcb->pcb_onfault = NULL;
 		return (-1);
 	}
@@ -456,7 +356,7 @@ fueword32(volatile const void *addr, int32_t *val)
 		return (-1);
 	}
 
-	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
+	if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
 		td->td_pcb->pcb_onfault = NULL;
 		return (-1);
 	}
@@ -485,7 +385,7 @@ fueword64(volatile const void *addr, int64_t *val)
 		return (-1);
 	}
 
-	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
+	if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
 		td->td_pcb->pcb_onfault = NULL;
 		return (-1);
 	}
@@ -514,7 +414,7 @@ fueword(volatile const void *addr, long *val)
 		return (-1);
 	}
 
-	if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
+	if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
 		td->td_pcb->pcb_onfault = NULL;
 		return (-1);
 	}
@@ -543,8 +443,8 @@ casueword32(volatile uint32_t *addr, uint32_t old, uin
 		return (-1);
 	}
 
-	if (map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p, sizeof(*p),
-	    NULL)) {
+	if (pmap_map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p,
+	    sizeof(*p), NULL)) {
 		td->td_pcb->pcb_onfault = NULL;
 		return (-1);
 	}
@@ -595,8 +495,8 @@ casueword(volatile u_long *addr, u_long old, u_long *o
 		return (-1);
 	}
 
-	if (map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p, sizeof(*p),
-	    NULL)) {
+	if (pmap_map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p,
+	    sizeof(*p), NULL)) {
 		td->td_pcb->pcb_onfault = NULL;
 		return (-1);
 	}

Modified: head/sys/powerpc/powerpc/mmu_if.m
==============================================================================
--- head/sys/powerpc/powerpc/mmu_if.m	Mon Jan 15 05:00:26 2018	(r327991)
+++ head/sys/powerpc/powerpc/mmu_if.m	Mon Jan 15 06:46:33 2018	(r327992)
@@ -817,6 +817,27 @@ METHOD void unmapdev {
 	vm_size_t	_size;
 };
 
+/**
+ * @brief Provide a kernel-space pointer that can be used to access the
+ * given userland address. The kernel accessible length returned in klen
+ * may be less than the requested length of the userland buffer (ulen). If
+ * so, retry with a higher address to get access to the later parts of the
+ * buffer. Returns EFAULT if no mapping can be made, else zero.
+ *
+ * @param _pm		PMAP for the user pointer.
+ * @param _uaddr	Userland address to map.
+ * @param _kaddr	Corresponding kernel address.
+ * @param _ulen		Length of user buffer.
+ * @param _klen		Available subset of ulen with _kaddr.
+ */
+METHOD int map_user_ptr {
+	mmu_t		_mmu;
+	pmap_t		_pm;
+	volatile const void *_uaddr;
+	void		**_kaddr;
+	size_t		_ulen;
+	size_t		*_klen;
+};
 
 /**
  * @brief Reverse-map a kernel virtual address

Modified: head/sys/powerpc/powerpc/pmap_dispatch.c
==============================================================================
--- head/sys/powerpc/powerpc/pmap_dispatch.c	Mon Jan 15 05:00:26 2018	(r327991)
+++ head/sys/powerpc/powerpc/pmap_dispatch.c	Mon Jan 15 06:46:33 2018	(r327992)
@@ -511,6 +511,15 @@ pmap_kremove(vm_offset_t va)
 	return (MMU_KREMOVE(mmu_obj, va));
 }
 
+int
+pmap_map_user_ptr(pmap_t pm, volatile const void *uaddr, void **kaddr,
+    size_t ulen, size_t *klen)
+{
+
+	CTR2(KTR_PMAP, "%s(%p)", __func__, uaddr);
+	return (MMU_MAP_USER_PTR(mmu_obj, pm, uaddr, kaddr, ulen, klen));
+}
+
 boolean_t
 pmap_dev_direct_mapped(vm_paddr_t pa, vm_size_t size)
 {


More information about the svn-src-head mailing list