Index: share/man/man4/mem.4 =================================================================== --- share/man/man4/mem.4 +++ share/man/man4/mem.4 @@ -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 @@ .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,45 @@ 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 */ + uint32_t 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 using a set of +flags: +.Bl -tag -width indent +.It Dv ME_STATE_VALID +The virtual address is valid. +.It Dv ME_STATE_RESIDENT +The virtual address corresponds to a resident physical page, and the returned +.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 +130,13 @@ .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 +162,11 @@ .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 +202,7 @@ .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 +211,7 @@ 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. Index: sys/amd64/amd64/mem.c =================================================================== --- sys/amd64/amd64/mem.c +++ sys/amd64/amd64/mem.c @@ -185,9 +185,8 @@ * 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; Index: sys/amd64/include/memdev.h =================================================================== --- sys/amd64/include/memdev.h +++ sys/amd64/include/memdev.h @@ -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_ */ Index: sys/arm/arm/mem.c =================================================================== --- sys/arm/arm/mem.c +++ sys/arm/arm/mem.c @@ -172,3 +172,10 @@ } 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); +} Index: sys/arm/include/memdev.h =================================================================== --- sys/arm/include/memdev.h +++ sys/arm/include/memdev.h @@ -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_ */ Index: sys/arm64/arm64/mem.c =================================================================== --- sys/arm64/arm64/mem.c +++ sys/arm64/arm64/mem.c @@ -129,3 +129,10 @@ } 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); +} Index: sys/arm64/include/memdev.h =================================================================== --- sys/arm64/include/memdev.h +++ sys/arm64/include/memdev.h @@ -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_ */ Index: sys/dev/mem/memdev.c =================================================================== --- sys/dev/mem/memdev.c +++ sys/dev/mem/memdev.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -46,12 +47,19 @@ #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, @@ -82,6 +90,41 @@ 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; + me->me_state = 0; + + 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_state |= ME_STATE_VALID; + 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_RESIDENT; + me->me_domain = _vm_phys_domain(me->me_paddr); + } + } + vm_map_unlock_read(map); + break; + default: + error = memioctl_md(dev, cmd, data, flags, td); + break; + } + return (error); +} + /* ARGSUSED */ static int mem_modevent(module_t mod __unused, int type, void *data __unused) Index: sys/i386/i386/mem.c =================================================================== --- sys/i386/i386/mem.c +++ sys/i386/i386/mem.c @@ -177,9 +177,8 @@ * 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; Index: sys/i386/include/memdev.h =================================================================== --- sys/i386/include/memdev.h +++ sys/i386/include/memdev.h @@ -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_ */ Index: sys/mips/include/memdev.h =================================================================== --- sys/mips/include/memdev.h +++ sys/mips/include/memdev.h @@ -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_ */ Index: sys/powerpc/include/memdev.h =================================================================== --- sys/powerpc/include/memdev.h +++ sys/powerpc/include/memdev.h @@ -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_ */ Index: sys/powerpc/powerpc/mem.c =================================================================== --- sys/powerpc/powerpc/mem.c +++ sys/powerpc/powerpc/mem.c @@ -278,9 +278,8 @@ * 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; Index: sys/riscv/include/memdev.h =================================================================== --- sys/riscv/include/memdev.h +++ sys/riscv/include/memdev.h @@ -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_ */ Index: sys/riscv/riscv/mem.c =================================================================== --- sys/riscv/riscv/mem.c +++ sys/riscv/riscv/mem.c @@ -122,3 +122,9 @@ 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); +} Index: sys/sys/memrange.h =================================================================== --- sys/sys/memrange.h +++ sys/sys/memrange.h @@ -45,6 +45,19 @@ #define MEMRANGE_GET _IOWR('m', 50, struct mem_range_op) #define MEMRANGE_SET _IOW('m', 51, struct mem_range_op) +#define ME_STATE_VALID 0x01 +#define ME_STATE_RESIDENT 0x02 + +struct mem_extract { + uint64_t me_vaddr; + uint64_t me_paddr; + int me_domain; + uint32_t me_state; + uint64_t pad1[5]; +}; + +#define MEM_EXTRACT_PADDR _IOWR('m', 52, struct mem_extract) + #ifdef _KERNEL MALLOC_DECLARE(M_MEMDESC);