From owner-svn-src-head@freebsd.org Wed Sep 2 18:12:51 2020 Return-Path: Delivered-To: svn-src-head@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id D34903C37EC; Wed, 2 Sep 2020 18:12:51 +0000 (UTC) (envelope-from markj@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4BhX9H5Ykmz40C3; Wed, 2 Sep 2020 18:12:51 +0000 (UTC) (envelope-from markj@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id A19C9E661; Wed, 2 Sep 2020 18:12:51 +0000 (UTC) (envelope-from markj@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 082ICp7e005138; Wed, 2 Sep 2020 18:12:51 GMT (envelope-from markj@FreeBSD.org) Received: (from markj@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 082ICloe005120; Wed, 2 Sep 2020 18:12:47 GMT (envelope-from markj@FreeBSD.org) Message-Id: <202009021812.082ICloe005120@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: markj set sender to markj@FreeBSD.org using -f From: Mark Johnston Date: Wed, 2 Sep 2020 18:12:47 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r365265 - in head: share/man/man4 sys/amd64/amd64 sys/amd64/include sys/arm/arm sys/arm/include sys/arm64/arm64 sys/arm64/include sys/dev/mem sys/i386/i386 sys/i386/include sys/mips/inc... X-SVN-Group: head X-SVN-Commit-Author: markj X-SVN-Commit-Paths: in head: share/man/man4 sys/amd64/amd64 sys/amd64/include sys/arm/arm sys/arm/include sys/arm64/arm64 sys/arm64/include sys/dev/mem sys/i386/i386 sys/i386/include sys/mips/include sys/mips/mips sys/po... X-SVN-Commit-Revision: 365265 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.33 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 02 Sep 2020 18:12:51 -0000 Author: markj Date: Wed Sep 2 18:12:47 2020 New Revision: 365265 URL: https://svnweb.freebsd.org/changeset/base/365265 Log: Add the MEM_EXTRACT_PADDR ioctl to /dev/mem. This allows privileged userspace processes to find information about the physical page backing a given mapping. It is useful in applications such as DPDK which perform some of their own memory management. Reviewed by: kib, jhb (previous version) MFC after: 2 weeks Sponsored by: Juniper Networks, Inc. Sponsored by: Klara Inc. Differential Revision: https://reviews.freebsd.org/D26237 Modified: head/share/man/man4/mem.4 head/sys/amd64/amd64/mem.c head/sys/amd64/include/memdev.h head/sys/arm/arm/mem.c head/sys/arm/include/memdev.h head/sys/arm64/arm64/mem.c head/sys/arm64/include/memdev.h head/sys/dev/mem/memdev.c head/sys/i386/i386/mem.c head/sys/i386/include/memdev.h head/sys/mips/include/memdev.h head/sys/mips/mips/mem.c head/sys/powerpc/include/memdev.h head/sys/powerpc/powerpc/mem.c head/sys/riscv/include/memdev.h head/sys/riscv/riscv/mem.c head/sys/sys/memrange.h Modified: head/share/man/man4/mem.4 ============================================================================== --- head/share/man/man4/mem.4 Wed Sep 2 18:04:49 2020 (r365264) +++ head/share/man/man4/mem.4 Wed Sep 2 18:12:47 2020 (r365265) @@ -28,7 +28,7 @@ .\" @(#)mem.4 5.3 (Berkeley) 5/2/91 .\" $FreeBSD$ .\" -.Dd October 3, 2004 +.Dd August 25, 2020 .Dt MEM 4 .Os .Sh NAME @@ -54,11 +54,7 @@ in the same manner as .Pa /dev/mem . Only kernel virtual addresses that are currently mapped to memory are allowed. .Pp -On -.Tn ISA -the -.Tn I/O -memory space begins at physical address 0x000a0000 +On ISA the I/O memory space begins at physical address 0x000a0000 and runs to 0x00100000. The per-process data @@ -69,6 +65,46 @@ is long, and ends at virtual address 0xf0000000. .Sh IOCTL INTERFACE +The +.Dv MEM_EXTRACT_PADDR +ioctl can be used to look up the physical address and NUMA domain of a given +virtual address in the calling process' address space. +The request is described by +.Bd -literal +struct mem_extract { + uint64_t me_vaddr; /* input */ + uint64_t me_paddr; /* output */ + int me_domain; /* output */ + int me_state; /* output */ +}; +.Ed +.Pp +The ioctl returns an error if the address is not valid. +The information returned by +.Dv MEM_EXTRACT_PADDR +may be out of date by the time that the ioctl call returns. +Specifically, concurrent system calls, page faults, or system page reclamation +activity may have unmapped the virtual page or replaced the backing physical +page before the ioctl call returns. +Wired pages, e.g., those locked by +.Xr mlock 2 , +will not be reclaimed by the system. +.Pp +The +.Fa me_state +field provides information about the state of the virtual page: +.Bl -tag -width indent +.It Dv ME_STATE_INVALID +The virtual address is invalid. +.It Dv ME_STATE_VALID +The virtual address is valid but is not mapped at the time of the ioctl call. +.It Dv ME_STATE_MAPPED +The virtual address corresponds to a physical page mapping, and the +.Fa me_paddr +and +.Fa me_domain +fields are valid. +.Pp Several architectures allow attributes to be associated with ranges of physical memory. These attributes can be manipulated via @@ -95,12 +131,13 @@ The region cannot be written to. .El .Pp Memory ranges are described by -.Vt struct mem_range_desc : -.Bd -literal -offset indent -uint64_t mr_base; /\(** physical base address \(**/ -uint64_t mr_len; /\(** physical length of region \(**/ -int mr_flags; /\(** attributes of region \(**/ -char mr_owner[8]; +.Bd -literal +struct mem_range_desc { + uint64_t mr_base; /* physical base address */ + uint64_t mr_len; /* physical length of region */ + int mr_flags; /* attributes of region */ + char mr_owner[8]; +}; .Ed .Pp In addition to the region attributes listed above, the following flags @@ -126,10 +163,11 @@ altered. .El .Pp Operations are performed using -.Fa struct mem_range_op : -.Bd -literal -offset indent -struct mem_range_desc *mo_desc; -int mo_arg[2]; +.Bd -literal +struct mem_range_op { + struct mem_range_desc *mo_desc; + int mo_arg[2]; +}; .Ed .Pp The @@ -165,7 +203,7 @@ to remove a range. .It Bq Er EOPNOTSUPP Memory range operations are not supported on this architecture. .It Bq Er ENXIO -No memory range descriptors are available (e.g.\& firmware has not enabled +No memory range descriptors are available (e.g., firmware has not enabled any). .It Bq Er EINVAL The memory range supplied as an argument is invalid or overlaps another @@ -174,7 +212,7 @@ range in a fashion not supported by this architecture. An attempt to remove or update a range failed because the range is busy. .It Bq Er ENOSPC An attempt to create a new range failed due to a shortage of hardware -resources (e.g.\& descriptor slots). +resources (e.g., descriptor slots). .It Bq Er ENOENT An attempt to remove a range failed because no range matches the descriptor base/length supplied. Modified: head/sys/amd64/amd64/mem.c ============================================================================== --- head/sys/amd64/amd64/mem.c Wed Sep 2 18:04:49 2020 (r365264) +++ head/sys/amd64/amd64/mem.c Wed Sep 2 18:12:47 2020 (r365265) @@ -185,9 +185,8 @@ memmmap(struct cdev *dev, vm_ooffset_t offset, vm_padd * This is basically just an ioctl shim for mem_range_attr_get * and mem_range_attr_set. */ -/* ARGSUSED */ int -memioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, int flags, +memioctl_md(struct cdev *dev __unused, u_long cmd, caddr_t data, int flags, struct thread *td) { int nd, error = 0; Modified: head/sys/amd64/include/memdev.h ============================================================================== --- head/sys/amd64/include/memdev.h Wed Sep 2 18:04:49 2020 (r365264) +++ head/sys/amd64/include/memdev.h Wed Sep 2 18:12:47 2020 (r365265) @@ -36,7 +36,7 @@ d_open_t memopen; d_read_t memrw; -d_ioctl_t memioctl; +d_ioctl_t memioctl_md; d_mmap_t memmmap; #endif /* _MACHINE_MEMDEV_H_ */ Modified: head/sys/arm/arm/mem.c ============================================================================== --- head/sys/arm/arm/mem.c Wed Sep 2 18:04:49 2020 (r365264) +++ head/sys/arm/arm/mem.c Wed Sep 2 18:12:47 2020 (r365265) @@ -172,3 +172,10 @@ memmmap(struct cdev *dev, vm_ooffset_t offset, vm_padd } return (-1); } + +int +memioctl_md(struct cdev *dev __unused, u_long cmd __unused, + caddr_t data __unused, int flags __unused, struct thread *td __unused) +{ + return (ENOTTY); +} Modified: head/sys/arm/include/memdev.h ============================================================================== --- head/sys/arm/include/memdev.h Wed Sep 2 18:04:49 2020 (r365264) +++ head/sys/arm/include/memdev.h Wed Sep 2 18:12:47 2020 (r365265) @@ -37,6 +37,6 @@ d_open_t memopen; d_read_t memrw; d_mmap_t memmmap; -#define memioctl (d_ioctl_t *)NULL +d_ioctl_t memioctl_md; #endif /* _MACHINE_MEMDEV_H_ */ Modified: head/sys/arm64/arm64/mem.c ============================================================================== --- head/sys/arm64/arm64/mem.c Wed Sep 2 18:04:49 2020 (r365264) +++ head/sys/arm64/arm64/mem.c Wed Sep 2 18:12:47 2020 (r365265) @@ -129,3 +129,10 @@ memmmap(struct cdev *dev, vm_ooffset_t offset, vm_padd } return (-1); } + +int +memioctl_md(struct cdev *dev __unused, u_long cmd __unused, + caddr_t data __unused, int flags __unused, struct thread *td __unused) +{ + return (ENOTTY); +} Modified: head/sys/arm64/include/memdev.h ============================================================================== --- head/sys/arm64/include/memdev.h Wed Sep 2 18:04:49 2020 (r365264) +++ head/sys/arm64/include/memdev.h Wed Sep 2 18:12:47 2020 (r365265) @@ -34,7 +34,7 @@ d_open_t memopen; d_read_t memrw; -#define memioctl (d_ioctl_t *)NULL +d_ioctl_t memioctl_md; d_mmap_t memmmap; #endif /* _MACHINE_MEMDEV_H_ */ Modified: head/sys/dev/mem/memdev.c ============================================================================== --- head/sys/dev/mem/memdev.c Wed Sep 2 18:04:49 2020 (r365264) +++ head/sys/dev/mem/memdev.c Wed Sep 2 18:12:47 2020 (r365265) @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -46,12 +47,19 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include +#include +#include +#include +#include #include static struct cdev *memdev, *kmemdev; +static d_ioctl_t memioctl; + static struct cdevsw mem_cdevsw = { .d_version = D_VERSION, .d_flags = D_MEM, @@ -79,6 +87,43 @@ memopen(struct cdev *dev __unused, int flags, int fmt error = securelevel_gt(td->td_ucred, 0); } + return (error); +} + +static int +memioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, + struct thread *td) +{ + vm_map_t map; + vm_map_entry_t entry; + struct mem_extract *me; + int error; + + error = 0; + switch (cmd) { + case MEM_EXTRACT_PADDR: + me = (struct mem_extract *)data; + + map = &td->td_proc->p_vmspace->vm_map; + vm_map_lock_read(map); + if (vm_map_lookup_entry(map, me->me_vaddr, &entry)) { + me->me_paddr = pmap_extract( + &td->td_proc->p_vmspace->vm_pmap, me->me_vaddr); + if (me->me_paddr != 0) { + me->me_state = ME_STATE_MAPPED; + me->me_domain = _vm_phys_domain(me->me_paddr); + } else { + me->me_state = ME_STATE_VALID; + } + } else { + me->me_state = ME_STATE_INVALID; + } + vm_map_unlock_read(map); + break; + default: + error = memioctl_md(dev, cmd, data, flags, td); + break; + } return (error); } Modified: head/sys/i386/i386/mem.c ============================================================================== --- head/sys/i386/i386/mem.c Wed Sep 2 18:04:49 2020 (r365264) +++ head/sys/i386/i386/mem.c Wed Sep 2 18:12:47 2020 (r365265) @@ -176,9 +176,8 @@ memmmap(struct cdev *dev, vm_ooffset_t offset, vm_padd * This is basically just an ioctl shim for mem_range_attr_get * and mem_range_attr_set. */ -/* ARGSUSED */ int -memioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, int flags, +memioctl_md(struct cdev *dev __unused, u_long cmd, caddr_t data, int flags, struct thread *td) { int nd, error = 0; Modified: head/sys/i386/include/memdev.h ============================================================================== --- head/sys/i386/include/memdev.h Wed Sep 2 18:04:49 2020 (r365264) +++ head/sys/i386/include/memdev.h Wed Sep 2 18:12:47 2020 (r365265) @@ -36,7 +36,7 @@ d_open_t memopen; d_read_t memrw; -d_ioctl_t memioctl; +d_ioctl_t memioctl_md; d_mmap_t memmmap; #endif /* _MACHINE_MEMDEV_H_ */ Modified: head/sys/mips/include/memdev.h ============================================================================== --- head/sys/mips/include/memdev.h Wed Sep 2 18:04:49 2020 (r365264) +++ head/sys/mips/include/memdev.h Wed Sep 2 18:12:47 2020 (r365265) @@ -37,7 +37,7 @@ d_open_t memopen; d_read_t memrw; -#define memioctl (d_ioctl_t *)NULL +d_ioctl_t memioctl_md; d_mmap_t memmmap; #endif /* _MACHINE_MEMDEV_H_ */ Modified: head/sys/mips/mips/mem.c ============================================================================== --- head/sys/mips/mips/mem.c Wed Sep 2 18:04:49 2020 (r365264) +++ head/sys/mips/mips/mem.c Wed Sep 2 18:12:47 2020 (r365265) @@ -160,3 +160,10 @@ memmmap(struct cdev *dev, vm_ooffset_t offset, vm_padd return (0); } + +int +memioctl_md(struct cdev *dev __unused, u_long cmd __unused, + caddr_t data __unused, int flags __unused, struct thread *td __unused) +{ + return (ENOTTY); +} Modified: head/sys/powerpc/include/memdev.h ============================================================================== --- head/sys/powerpc/include/memdev.h Wed Sep 2 18:04:49 2020 (r365264) +++ head/sys/powerpc/include/memdev.h Wed Sep 2 18:12:47 2020 (r365265) @@ -36,7 +36,7 @@ d_open_t memopen; d_read_t memrw; -d_ioctl_t memioctl; +d_ioctl_t memioctl_md; d_mmap_t memmmap; #endif /* _MACHINE_MEMDEV_H_ */ Modified: head/sys/powerpc/powerpc/mem.c ============================================================================== --- head/sys/powerpc/powerpc/mem.c Wed Sep 2 18:04:49 2020 (r365264) +++ head/sys/powerpc/powerpc/mem.c Wed Sep 2 18:12:47 2020 (r365265) @@ -278,9 +278,8 @@ ppc_mrset(struct mem_range_softc *sc, struct mem_range * This is basically just an ioctl shim for mem_range_attr_get * and mem_range_attr_set. */ -/* ARGSUSED */ int -memioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, int flags, +memioctl_md(struct cdev *dev __unused, u_long cmd, caddr_t data, int flags, struct thread *td) { int nd, error = 0; Modified: head/sys/riscv/include/memdev.h ============================================================================== --- head/sys/riscv/include/memdev.h Wed Sep 2 18:04:49 2020 (r365264) +++ head/sys/riscv/include/memdev.h Wed Sep 2 18:12:47 2020 (r365265) @@ -34,7 +34,7 @@ d_open_t memopen; d_read_t memrw; -#define memioctl (d_ioctl_t *)NULL +d_ioctl_t memioctl_md; #define memmmap (d_mmap_t *)NULL #endif /* _MACHINE_MEMDEV_H_ */ Modified: head/sys/riscv/riscv/mem.c ============================================================================== --- head/sys/riscv/riscv/mem.c Wed Sep 2 18:04:49 2020 (r365264) +++ head/sys/riscv/riscv/mem.c Wed Sep 2 18:12:47 2020 (r365265) @@ -121,3 +121,10 @@ memrw(struct cdev *dev, struct uio *uio, int flags) return (error); } + +int +memioctl_md(struct cdev *dev __unused, u_long cmd __unused, + caddr_t data __unused, int flags __unused, struct thread *td __unused) +{ + return (ENOTTY); +} Modified: head/sys/sys/memrange.h ============================================================================== --- head/sys/sys/memrange.h Wed Sep 2 18:04:49 2020 (r365264) +++ head/sys/sys/memrange.h Wed Sep 2 18:12:47 2020 (r365265) @@ -45,6 +45,20 @@ struct mem_range_op #define MEMRANGE_GET _IOWR('m', 50, struct mem_range_op) #define MEMRANGE_SET _IOW('m', 51, struct mem_range_op) +#define ME_STATE_INVALID 0 +#define ME_STATE_VALID 1 +#define ME_STATE_MAPPED 2 + +struct mem_extract { + uint64_t me_vaddr; + uint64_t me_paddr; + int me_domain; + int me_state; + uint64_t pad1[5]; +}; + +#define MEM_EXTRACT_PADDR _IOWR('m', 52, struct mem_extract) + #ifdef _KERNEL MALLOC_DECLARE(M_MEMDESC);