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