procfs_mem.c revision 12904
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1993 Jan-Simon Pendry
31541Srgrimes * Copyright (c) 1993 Sean Eric Fagan
41541Srgrimes * Copyright (c) 1993
51541Srgrimes *	The Regents of the University of California.  All rights reserved.
61541Srgrimes *
71541Srgrimes * This code is derived from software contributed to Berkeley by
81541Srgrimes * Jan-Simon Pendry and Sean Eric Fagan.
91541Srgrimes *
101541Srgrimes * Redistribution and use in source and binary forms, with or without
111541Srgrimes * modification, are permitted provided that the following conditions
121541Srgrimes * are met:
131541Srgrimes * 1. Redistributions of source code must retain the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer.
151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161541Srgrimes *    notice, this list of conditions and the following disclaimer in the
171541Srgrimes *    documentation and/or other materials provided with the distribution.
181541Srgrimes * 3. All advertising materials mentioning features or use of this software
191541Srgrimes *    must display the following acknowledgement:
201541Srgrimes *	This product includes software developed by the University of
211541Srgrimes *	California, Berkeley and its contributors.
221541Srgrimes * 4. Neither the name of the University nor the names of its contributors
231541Srgrimes *    may be used to endorse or promote products derived from this software
241541Srgrimes *    without specific prior written permission.
251541Srgrimes *
261541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361541Srgrimes * SUCH DAMAGE.
371541Srgrimes *
381541Srgrimes *	@(#)procfs_mem.c	8.4 (Berkeley) 1/21/94
391541Srgrimes *
4012904Sbde *	$Id: procfs_mem.c,v 1.13 1995/12/11 04:56:31 dyson Exp $
411541Srgrimes */
421541Srgrimes
431541Srgrimes/*
441541Srgrimes * This is a lightly hacked and merged version
451541Srgrimes * of sef's pread/pwrite functions
461541Srgrimes */
471541Srgrimes
481541Srgrimes#include <sys/param.h>
491541Srgrimes#include <sys/systm.h>
501541Srgrimes#include <sys/time.h>
511541Srgrimes#include <sys/kernel.h>
521541Srgrimes#include <sys/proc.h>
531541Srgrimes#include <sys/vnode.h>
541541Srgrimes#include <miscfs/procfs/procfs.h>
551541Srgrimes#include <vm/vm.h>
5612662Sdg#include <vm/vm_param.h>
5712662Sdg#include <vm/vm_prot.h>
5812662Sdg#include <vm/lock.h>
5912662Sdg#include <vm/pmap.h>
6012662Sdg#include <vm/vm_map.h>
611541Srgrimes#include <vm/vm_kern.h>
6212662Sdg#include <vm/vm_object.h>
631541Srgrimes#include <vm/vm_page.h>
6412662Sdg#include <vm/vm_extern.h>
651541Srgrimes
6612595Sbdestatic int	procfs_rwmem __P((struct proc *p, struct uio *uio));
6712595Sbde
681541Srgrimesstatic int
691541Srgrimesprocfs_rwmem(p, uio)
701541Srgrimes	struct proc *p;
711541Srgrimes	struct uio *uio;
721541Srgrimes{
731541Srgrimes	int error;
741541Srgrimes	int writing;
751541Srgrimes
761541Srgrimes	writing = uio->uio_rw == UIO_WRITE;
771541Srgrimes
781541Srgrimes	/*
791541Srgrimes	 * Only map in one page at a time.  We don't have to, but it
801541Srgrimes	 * makes things easier.  This way is trivial - right?
811541Srgrimes	 */
821541Srgrimes	do {
831541Srgrimes		vm_map_t map, tmap;
841541Srgrimes		vm_object_t object;
855403Sdg		vm_offset_t kva = 0;
861541Srgrimes		vm_offset_t uva;
871541Srgrimes		int page_offset;		/* offset into page */
881541Srgrimes		vm_offset_t pageno;		/* page number */
891541Srgrimes		vm_map_entry_t out_entry;
901541Srgrimes		vm_prot_t out_prot;
911541Srgrimes		vm_page_t m;
921541Srgrimes		boolean_t wired, single_use;
9312904Sbde		vm_pindex_t pindex;
941541Srgrimes		u_int len;
951541Srgrimes		int fix_prot;
961541Srgrimes
971541Srgrimes		uva = (vm_offset_t) uio->uio_offset;
983687Sdg		if (uva >= VM_MAXUSER_ADDRESS) {
993687Sdg			if (writing || (uva >= (VM_MAXUSER_ADDRESS + UPAGES * PAGE_SIZE))) {
1003687Sdg				error = 0;
1013687Sdg				break;
1023687Sdg			}
1031541Srgrimes		}
1041541Srgrimes
1051541Srgrimes		/*
1061541Srgrimes		 * Get the page number of this segment.
1071541Srgrimes		 */
1081541Srgrimes		pageno = trunc_page(uva);
1091541Srgrimes		page_offset = uva - pageno;
1101541Srgrimes
1111541Srgrimes		/*
1121541Srgrimes		 * How many bytes to copy
1131541Srgrimes		 */
1141541Srgrimes		len = min(PAGE_SIZE - page_offset, uio->uio_resid);
1151541Srgrimes
1161541Srgrimes		/*
1171541Srgrimes		 * The map we want...
1181541Srgrimes		 */
1191541Srgrimes		map = &p->p_vmspace->vm_map;
1208876Srgrimes
1211541Srgrimes		/*
1221541Srgrimes		 * Check the permissions for the area we're interested
1231541Srgrimes		 * in.
1241541Srgrimes		 */
1251541Srgrimes		fix_prot = 0;
1261541Srgrimes		if (writing)
1271541Srgrimes			fix_prot = !vm_map_check_protection(map, pageno,
1281541Srgrimes					pageno + PAGE_SIZE, VM_PROT_WRITE);
1291541Srgrimes
1301541Srgrimes		if (fix_prot) {
1311541Srgrimes			/*
1321541Srgrimes			 * If the page is not writable, we make it so.
1331541Srgrimes			 * XXX It is possible that a page may *not* be
1341541Srgrimes			 * read/executable, if a process changes that!
1351541Srgrimes			 * We will assume, for now, that a page is either
1361541Srgrimes			 * VM_PROT_ALL, or VM_PROT_READ|VM_PROT_EXECUTE.
1371541Srgrimes			 */
1381541Srgrimes			error = vm_map_protect(map, pageno,
1391541Srgrimes					pageno + PAGE_SIZE, VM_PROT_ALL, 0);
1401541Srgrimes			if (error)
1411541Srgrimes				break;
1421541Srgrimes		}
1431541Srgrimes
1441541Srgrimes		/*
1451541Srgrimes		 * Now we need to get the page.  out_entry, out_prot, wired,
1461541Srgrimes		 * and single_use aren't used.  One would think the vm code
1471541Srgrimes		 * would be a *bit* nicer...  We use tmap because
1481541Srgrimes		 * vm_map_lookup() can change the map argument.
1491541Srgrimes		 */
1501541Srgrimes		tmap = map;
1511541Srgrimes		error = vm_map_lookup(&tmap, pageno,
1521541Srgrimes				      writing ? VM_PROT_WRITE : VM_PROT_READ,
15312904Sbde				      &out_entry, &object, &pindex, &out_prot,
1541541Srgrimes				      &wired, &single_use);
1551541Srgrimes		/*
1561541Srgrimes		 * We're done with tmap now.
1571541Srgrimes		 */
1581541Srgrimes		if (!error)
1591541Srgrimes			vm_map_lookup_done(tmap, out_entry);
1608876Srgrimes
1611541Srgrimes		/*
1621541Srgrimes		 * Fault the page in...
1631541Srgrimes		 */
1649507Sdg		if (!error && writing && object->backing_object) {
16512904Sbde			m = vm_page_lookup(object, pindex);
16611707Sdyson			if (m == 0)
1671541Srgrimes				error = vm_fault(map, pageno,
1681541Srgrimes							VM_PROT_WRITE, FALSE);
1691541Srgrimes		}
1701541Srgrimes
1711541Srgrimes		/* Find space in kernel_map for the page we're interested in */
1721541Srgrimes		if (!error)
17312767Sdyson			error = vm_map_find(kernel_map, object,
17412904Sbde				IDX_TO_OFF(pindex), &kva, PAGE_SIZE, 1);
1751541Srgrimes
1761541Srgrimes		if (!error) {
1771541Srgrimes			/*
1781541Srgrimes			 * Neither vm_map_lookup() nor vm_map_find() appear
1791541Srgrimes			 * to add a reference count to the object, so we do
1801541Srgrimes			 * that here and now.
1811541Srgrimes			 */
1821541Srgrimes			vm_object_reference(object);
1831541Srgrimes
1841541Srgrimes			/*
1851541Srgrimes			 * Mark the page we just found as pageable.
1861541Srgrimes			 */
1871541Srgrimes			error = vm_map_pageable(kernel_map, kva,
1881541Srgrimes				kva + PAGE_SIZE, 0);
1891541Srgrimes
1901541Srgrimes			/*
1911541Srgrimes			 * Now do the i/o move.
1921541Srgrimes			 */
1931541Srgrimes			if (!error)
1942807Sbde				error = uiomove((caddr_t)(kva + page_offset),
1952807Sbde						len, uio);
1961541Srgrimes
1971541Srgrimes			vm_map_remove(kernel_map, kva, kva + PAGE_SIZE);
1981541Srgrimes		}
1991541Srgrimes		if (fix_prot)
2001541Srgrimes			vm_map_protect(map, pageno, pageno + PAGE_SIZE,
2011541Srgrimes					VM_PROT_READ|VM_PROT_EXECUTE, 0);
2021541Srgrimes	} while (error == 0 && uio->uio_resid > 0);
2031541Srgrimes
2041541Srgrimes	return (error);
2051541Srgrimes}
2061541Srgrimes
2071541Srgrimes/*
2081541Srgrimes * Copy data in and out of the target process.
2091541Srgrimes * We do this by mapping the process's page into
2101541Srgrimes * the kernel and then doing a uiomove direct
2111541Srgrimes * from the kernel address space.
2121541Srgrimes */
2131541Srgrimesint
2141541Srgrimesprocfs_domem(curp, p, pfs, uio)
2151541Srgrimes	struct proc *curp;
2161541Srgrimes	struct proc *p;
2171541Srgrimes	struct pfsnode *pfs;
2181541Srgrimes	struct uio *uio;
2191541Srgrimes{
2201541Srgrimes	int error;
2211541Srgrimes
2221541Srgrimes	if (uio->uio_resid == 0)
2231541Srgrimes		return (0);
2241541Srgrimes
2251541Srgrimes	error = procfs_rwmem(p, uio);
2261541Srgrimes
2271541Srgrimes	return (error);
2281541Srgrimes}
2291541Srgrimes
2301541Srgrimes/*
2311541Srgrimes * Given process (p), find the vnode from which
2321541Srgrimes * it's text segment is being executed.
2331541Srgrimes *
2341541Srgrimes * It would be nice to grab this information from
2351541Srgrimes * the VM system, however, there is no sure-fire
2361541Srgrimes * way of doing that.  Instead, fork(), exec() and
2371541Srgrimes * wait() all maintain the p_textvp field in the
2381541Srgrimes * process proc structure which contains a held
2391541Srgrimes * reference to the exec'ed vnode.
2401541Srgrimes */
2411541Srgrimesstruct vnode *
2421541Srgrimesprocfs_findtextvp(p)
2431541Srgrimes	struct proc *p;
2441541Srgrimes{
2451541Srgrimes	return (p->p_textvp);
2461541Srgrimes}
247