procfs_mem.c revision 8876
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 *
408876Srgrimes *	$Id: procfs_mem.c,v 1.6 1995/01/05 03:59:38 davidg 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>
561541Srgrimes#include <vm/vm_kern.h>
571541Srgrimes#include <vm/vm_page.h>
581541Srgrimes
591541Srgrimesstatic int
601541Srgrimesprocfs_rwmem(p, uio)
611541Srgrimes	struct proc *p;
621541Srgrimes	struct uio *uio;
631541Srgrimes{
641541Srgrimes	int error;
651541Srgrimes	int writing;
661541Srgrimes
671541Srgrimes	writing = uio->uio_rw == UIO_WRITE;
681541Srgrimes
691541Srgrimes	/*
701541Srgrimes	 * Only map in one page at a time.  We don't have to, but it
711541Srgrimes	 * makes things easier.  This way is trivial - right?
721541Srgrimes	 */
731541Srgrimes	do {
741541Srgrimes		vm_map_t map, tmap;
751541Srgrimes		vm_object_t object;
765403Sdg		vm_offset_t kva = 0;
771541Srgrimes		vm_offset_t uva;
781541Srgrimes		int page_offset;		/* offset into page */
791541Srgrimes		vm_offset_t pageno;		/* page number */
801541Srgrimes		vm_map_entry_t out_entry;
811541Srgrimes		vm_prot_t out_prot;
821541Srgrimes		vm_page_t m;
831541Srgrimes		boolean_t wired, single_use;
841541Srgrimes		vm_offset_t off;
851541Srgrimes		u_int len;
861541Srgrimes		int fix_prot;
871541Srgrimes
881541Srgrimes		uva = (vm_offset_t) uio->uio_offset;
893687Sdg		if (uva >= VM_MAXUSER_ADDRESS) {
903687Sdg			if (writing || (uva >= (VM_MAXUSER_ADDRESS + UPAGES * PAGE_SIZE))) {
913687Sdg				error = 0;
923687Sdg				break;
933687Sdg			}
941541Srgrimes		}
951541Srgrimes
961541Srgrimes		/*
971541Srgrimes		 * Get the page number of this segment.
981541Srgrimes		 */
991541Srgrimes		pageno = trunc_page(uva);
1001541Srgrimes		page_offset = uva - pageno;
1011541Srgrimes
1021541Srgrimes		/*
1031541Srgrimes		 * How many bytes to copy
1041541Srgrimes		 */
1051541Srgrimes		len = min(PAGE_SIZE - page_offset, uio->uio_resid);
1061541Srgrimes
1071541Srgrimes		/*
1081541Srgrimes		 * The map we want...
1091541Srgrimes		 */
1101541Srgrimes		map = &p->p_vmspace->vm_map;
1118876Srgrimes
1121541Srgrimes		/*
1131541Srgrimes		 * Check the permissions for the area we're interested
1141541Srgrimes		 * in.
1151541Srgrimes		 */
1161541Srgrimes		fix_prot = 0;
1171541Srgrimes		if (writing)
1181541Srgrimes			fix_prot = !vm_map_check_protection(map, pageno,
1191541Srgrimes					pageno + PAGE_SIZE, VM_PROT_WRITE);
1201541Srgrimes
1211541Srgrimes		if (fix_prot) {
1221541Srgrimes			/*
1231541Srgrimes			 * If the page is not writable, we make it so.
1241541Srgrimes			 * XXX It is possible that a page may *not* be
1251541Srgrimes			 * read/executable, if a process changes that!
1261541Srgrimes			 * We will assume, for now, that a page is either
1271541Srgrimes			 * VM_PROT_ALL, or VM_PROT_READ|VM_PROT_EXECUTE.
1281541Srgrimes			 */
1291541Srgrimes			error = vm_map_protect(map, pageno,
1301541Srgrimes					pageno + PAGE_SIZE, VM_PROT_ALL, 0);
1311541Srgrimes			if (error)
1321541Srgrimes				break;
1331541Srgrimes		}
1341541Srgrimes
1351541Srgrimes		/*
1361541Srgrimes		 * Now we need to get the page.  out_entry, out_prot, wired,
1371541Srgrimes		 * and single_use aren't used.  One would think the vm code
1381541Srgrimes		 * would be a *bit* nicer...  We use tmap because
1391541Srgrimes		 * vm_map_lookup() can change the map argument.
1401541Srgrimes		 */
1411541Srgrimes		tmap = map;
1421541Srgrimes		error = vm_map_lookup(&tmap, pageno,
1431541Srgrimes				      writing ? VM_PROT_WRITE : VM_PROT_READ,
1441541Srgrimes				      &out_entry, &object, &off, &out_prot,
1451541Srgrimes				      &wired, &single_use);
1461541Srgrimes		/*
1471541Srgrimes		 * We're done with tmap now.
1481541Srgrimes		 */
1491541Srgrimes		if (!error)
1501541Srgrimes			vm_map_lookup_done(tmap, out_entry);
1518876Srgrimes
1521541Srgrimes		/*
1531541Srgrimes		 * Fault the page in...
1541541Srgrimes		 */
1551541Srgrimes		if (!error && writing && object->shadow) {
1561541Srgrimes			m = vm_page_lookup(object, off);
1571541Srgrimes			if (m == 0 || (m->flags & PG_COPYONWRITE))
1581541Srgrimes				error = vm_fault(map, pageno,
1591541Srgrimes							VM_PROT_WRITE, FALSE);
1601541Srgrimes		}
1611541Srgrimes
1621541Srgrimes		/* Find space in kernel_map for the page we're interested in */
1631541Srgrimes		if (!error)
1641541Srgrimes			error = vm_map_find(kernel_map, object, off, &kva,
1651541Srgrimes					PAGE_SIZE, 1);
1661541Srgrimes
1671541Srgrimes		if (!error) {
1681541Srgrimes			/*
1691541Srgrimes			 * Neither vm_map_lookup() nor vm_map_find() appear
1701541Srgrimes			 * to add a reference count to the object, so we do
1711541Srgrimes			 * that here and now.
1721541Srgrimes			 */
1731541Srgrimes			vm_object_reference(object);
1741541Srgrimes
1751541Srgrimes			/*
1761541Srgrimes			 * Mark the page we just found as pageable.
1771541Srgrimes			 */
1781541Srgrimes			error = vm_map_pageable(kernel_map, kva,
1791541Srgrimes				kva + PAGE_SIZE, 0);
1801541Srgrimes
1811541Srgrimes			/*
1821541Srgrimes			 * Now do the i/o move.
1831541Srgrimes			 */
1841541Srgrimes			if (!error)
1852807Sbde				error = uiomove((caddr_t)(kva + page_offset),
1862807Sbde						len, uio);
1871541Srgrimes
1881541Srgrimes			vm_map_remove(kernel_map, kva, kva + PAGE_SIZE);
1891541Srgrimes		}
1901541Srgrimes		if (fix_prot)
1911541Srgrimes			vm_map_protect(map, pageno, pageno + PAGE_SIZE,
1921541Srgrimes					VM_PROT_READ|VM_PROT_EXECUTE, 0);
1931541Srgrimes	} while (error == 0 && uio->uio_resid > 0);
1941541Srgrimes
1951541Srgrimes	return (error);
1961541Srgrimes}
1971541Srgrimes
1981541Srgrimes/*
1991541Srgrimes * Copy data in and out of the target process.
2001541Srgrimes * We do this by mapping the process's page into
2011541Srgrimes * the kernel and then doing a uiomove direct
2021541Srgrimes * from the kernel address space.
2031541Srgrimes */
2041541Srgrimesint
2051541Srgrimesprocfs_domem(curp, p, pfs, uio)
2061541Srgrimes	struct proc *curp;
2071541Srgrimes	struct proc *p;
2081541Srgrimes	struct pfsnode *pfs;
2091541Srgrimes	struct uio *uio;
2101541Srgrimes{
2111541Srgrimes	int error;
2121541Srgrimes
2131541Srgrimes	if (uio->uio_resid == 0)
2141541Srgrimes		return (0);
2151541Srgrimes
2161541Srgrimes	error = procfs_rwmem(p, uio);
2171541Srgrimes
2181541Srgrimes	return (error);
2191541Srgrimes}
2201541Srgrimes
2211541Srgrimes/*
2221541Srgrimes * Given process (p), find the vnode from which
2231541Srgrimes * it's text segment is being executed.
2241541Srgrimes *
2251541Srgrimes * It would be nice to grab this information from
2261541Srgrimes * the VM system, however, there is no sure-fire
2271541Srgrimes * way of doing that.  Instead, fork(), exec() and
2281541Srgrimes * wait() all maintain the p_textvp field in the
2291541Srgrimes * process proc structure which contains a held
2301541Srgrimes * reference to the exec'ed vnode.
2311541Srgrimes */
2321541Srgrimesstruct vnode *
2331541Srgrimesprocfs_findtextvp(p)
2341541Srgrimes	struct proc *p;
2351541Srgrimes{
2361541Srgrimes	return (p->p_textvp);
2371541Srgrimes}
2381541Srgrimes
2391541Srgrimes
2401541Srgrimes#ifdef probably_never
2411541Srgrimes/*
2421541Srgrimes * Given process (p), find the vnode from which
2431541Srgrimes * it's text segment is being mapped.
2441541Srgrimes *
2451541Srgrimes * (This is here, rather than in procfs_subr in order
2461541Srgrimes * to keep all the VM related code in one place.)
2471541Srgrimes */
2481541Srgrimesstruct vnode *
2491541Srgrimesprocfs_findtextvp(p)
2501541Srgrimes	struct proc *p;
2511541Srgrimes{
2521541Srgrimes	int error;
2531541Srgrimes	vm_object_t object;
2541541Srgrimes	vm_offset_t pageno;		/* page number */
2551541Srgrimes
2561541Srgrimes	/* find a vnode pager for the user address space */
2571541Srgrimes
2581541Srgrimes	for (pageno = VM_MIN_ADDRESS;
2591541Srgrimes			pageno < VM_MAXUSER_ADDRESS;
2601541Srgrimes			pageno += PAGE_SIZE) {
2611541Srgrimes		vm_map_t map;
2621541Srgrimes		vm_map_entry_t out_entry;
2631541Srgrimes		vm_prot_t out_prot;
2641541Srgrimes		boolean_t wired, single_use;
2651541Srgrimes		vm_offset_t off;
2661541Srgrimes
2671541Srgrimes		map = &p->p_vmspace->vm_map;
2681541Srgrimes		error = vm_map_lookup(&map, pageno,
2691541Srgrimes			      VM_PROT_READ,
2701541Srgrimes			      &out_entry, &object, &off, &out_prot,
2711541Srgrimes			      &wired, &single_use);
2721541Srgrimes
2731541Srgrimes		if (!error) {
2741541Srgrimes			vm_pager_t pager;
2751541Srgrimes
2761541Srgrimes			printf("procfs: found vm object\n");
2771541Srgrimes			vm_map_lookup_done(map, out_entry);
2781541Srgrimes			printf("procfs: vm object = %x\n", object);
2791541Srgrimes
2801541Srgrimes			/*
2811541Srgrimes			 * At this point, assuming no errors, object
2821541Srgrimes			 * is the VM object mapping UVA (pageno).
2831541Srgrimes			 * Ensure it has a vnode pager, then grab
2841541Srgrimes			 * the vnode from that pager's handle.
2851541Srgrimes			 */
2861541Srgrimes
2871541Srgrimes			pager = object->pager;
2881541Srgrimes			printf("procfs: pager = %x\n", pager);
2891541Srgrimes			if (pager)
2901541Srgrimes				printf("procfs: found pager, type = %d\n", pager->pg_type);
2911541Srgrimes			if (pager && pager->pg_type == PG_VNODE) {
2921541Srgrimes				struct vnode *vp;
2931541Srgrimes
2941541Srgrimes				vp = (struct vnode *) pager->pg_handle;
2951541Srgrimes				printf("procfs: vp = 0x%x\n", vp);
2961541Srgrimes				return (vp);
2971541Srgrimes			}
2981541Srgrimes		}
2991541Srgrimes	}
3001541Srgrimes
3011541Srgrimes	printf("procfs: text object not found\n");
3021541Srgrimes	return (0);
3031541Srgrimes}
3041541Srgrimes#endif /* probably_never */
305