procfs_mem.c revision 24666
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 *
3822521Sdyson *	@(#)procfs_mem.c	8.5 (Berkeley) 6/15/94
391541Srgrimes *
4024666Sdyson *	$Id: procfs_mem.c,v 1.23 1997/02/22 09:40:28 peter 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>
5822521Sdyson#include <sys/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>
6513608Speter#include <sys/user.h>
661541Srgrimes
6712595Sbdestatic int	procfs_rwmem __P((struct proc *p, struct uio *uio));
6812595Sbde
691541Srgrimesstatic int
701541Srgrimesprocfs_rwmem(p, uio)
711541Srgrimes	struct proc *p;
721541Srgrimes	struct uio *uio;
731541Srgrimes{
741541Srgrimes	int error;
751541Srgrimes	int writing;
7616308Sdyson	struct vmspace *vm;
7716889Sdyson	vm_map_t map;
7816889Sdyson	vm_object_t object = NULL;
7916889Sdyson	vm_offset_t pageno = 0;		/* page number */
8024666Sdyson	vm_prot_t reqprot;
8124666Sdyson	vm_offset_t kva;
821541Srgrimes
8316308Sdyson	/*
8416308Sdyson	 * if the vmspace is in the midst of being deallocated or the
8516308Sdyson	 * process is exiting, don't try to grab anything.  The page table
8616308Sdyson	 * usage in that process can be messed up.
8716308Sdyson	 */
8816308Sdyson	vm = p->p_vmspace;
8916308Sdyson	if ((p->p_flag & P_WEXIT) || (vm->vm_refcnt < 1))
9016308Sdyson		return EFAULT;
9116308Sdyson	++vm->vm_refcnt;
9216889Sdyson	/*
9316889Sdyson	 * The map we want...
9416889Sdyson	 */
9516889Sdyson	map = &vm->vm_map;
9616308Sdyson
971541Srgrimes	writing = uio->uio_rw == UIO_WRITE;
9824666Sdyson	reqprot = writing ? (VM_PROT_WRITE | VM_PROT_OVERRIDE_WRITE) : VM_PROT_READ;
991541Srgrimes
10024666Sdyson	kva = kmem_alloc_pageable(kernel_map, PAGE_SIZE);
10124666Sdyson
1021541Srgrimes	/*
1031541Srgrimes	 * Only map in one page at a time.  We don't have to, but it
1041541Srgrimes	 * makes things easier.  This way is trivial - right?
1051541Srgrimes	 */
1061541Srgrimes	do {
10716889Sdyson		vm_map_t tmap;
1081541Srgrimes		vm_offset_t uva;
1091541Srgrimes		int page_offset;		/* offset into page */
1101541Srgrimes		vm_map_entry_t out_entry;
1111541Srgrimes		vm_prot_t out_prot;
1121541Srgrimes		boolean_t wired, single_use;
11312904Sbde		vm_pindex_t pindex;
1141541Srgrimes		u_int len;
11524666Sdyson		vm_page_t m;
1161541Srgrimes
11716889Sdyson		object = NULL;
11816889Sdyson
1191541Srgrimes		uva = (vm_offset_t) uio->uio_offset;
1201541Srgrimes
1211541Srgrimes		/*
1221541Srgrimes		 * Get the page number of this segment.
1231541Srgrimes		 */
1241541Srgrimes		pageno = trunc_page(uva);
1251541Srgrimes		page_offset = uva - pageno;
1261541Srgrimes
1271541Srgrimes		/*
1281541Srgrimes		 * How many bytes to copy
1291541Srgrimes		 */
1301541Srgrimes		len = min(PAGE_SIZE - page_offset, uio->uio_resid);
1311541Srgrimes
13213627Speter		if (uva >= VM_MAXUSER_ADDRESS) {
13324666Sdyson			vm_offset_t tkva;
13424666Sdyson
13513627Speter			if (writing || (uva >= (VM_MAXUSER_ADDRESS + UPAGES * PAGE_SIZE))) {
13613627Speter				error = 0;
13713627Speter				break;
13813627Speter			}
13913627Speter
14013627Speter			/* we are reading the "U area", force it into core */
14113627Speter			PHOLD(p);
14213627Speter
14313627Speter			/* sanity check */
14413627Speter			if (!(p->p_flag & P_INMEM)) {
14513627Speter				/* aiee! */
14616889Sdyson				PRELE(p);
14713627Speter				error = EFAULT;
14813627Speter				break;
14913627Speter			}
15013627Speter
15113627Speter			/* populate the ptrace/procfs area */
15213627Speter			p->p_addr->u_kproc.kp_proc = *p;
15313627Speter			fill_eproc (p, &p->p_addr->u_kproc.kp_eproc);
15413627Speter
15513627Speter			/* locate the in-core address */
15624666Sdyson			tkva = (u_int)p->p_addr + uva - VM_MAXUSER_ADDRESS;
15713627Speter
15813627Speter			/* transfer it */
15924666Sdyson			error = uiomove((caddr_t)tkva, len, uio);
16013627Speter
16113627Speter			/* let the pages go */
16213627Speter			PRELE(p);
16313627Speter
16413627Speter			continue;
16513627Speter		}
16613627Speter
1671541Srgrimes		/*
16824666Sdyson		 * Fault the page on behalf of the process
1691541Srgrimes		 */
17024666Sdyson		error = vm_fault(map, pageno, reqprot, FALSE);
17124666Sdyson		if (error) {
17224666Sdyson			error = EFAULT;
17324666Sdyson			break;
1741541Srgrimes		}
1751541Srgrimes
1761541Srgrimes		/*
1771541Srgrimes		 * Now we need to get the page.  out_entry, out_prot, wired,
1781541Srgrimes		 * and single_use aren't used.  One would think the vm code
1791541Srgrimes		 * would be a *bit* nicer...  We use tmap because
1801541Srgrimes		 * vm_map_lookup() can change the map argument.
1811541Srgrimes		 */
1821541Srgrimes		tmap = map;
18324666Sdyson		error = vm_map_lookup(&tmap, pageno, reqprot,
18416889Sdyson			      &out_entry, &object, &pindex, &out_prot,
18516889Sdyson			      &wired, &single_use);
18616889Sdyson
18716889Sdyson		if (error) {
18824666Sdyson			error = EFAULT;
18924666Sdyson
19016889Sdyson			/*
19116889Sdyson			 * Make sure that there is no residue in 'object' from
19216889Sdyson			 * an error return on vm_map_lookup.
19316889Sdyson			 */
19416889Sdyson			object = NULL;
19524666Sdyson
19616889Sdyson			break;
19716889Sdyson		}
19816889Sdyson
19924666Sdyson		m = vm_page_lookup(object, pindex);
20024666Sdyson		if (m == NULL) {
20124666Sdyson			error = EFAULT;
20224666Sdyson
20324666Sdyson			/*
20424666Sdyson			 * Make sure that there is no residue in 'object' from
20524666Sdyson			 * an error return on vm_map_lookup.
20624666Sdyson			 */
20724666Sdyson			object = NULL;
20824666Sdyson
20924666Sdyson			break;
21024666Sdyson		}
21124666Sdyson
2121541Srgrimes		/*
21324666Sdyson		 * Wire the page into memory
21424666Sdyson		 */
21524666Sdyson		vm_page_wire(m);
21624666Sdyson
21724666Sdyson		/*
2181541Srgrimes		 * We're done with tmap now.
21916889Sdyson		 * But reference the object first, so that we won't loose
22016889Sdyson		 * it.
2211541Srgrimes		 */
22216889Sdyson		vm_object_reference(object);
22316889Sdyson		vm_map_lookup_done(tmap, out_entry);
2248876Srgrimes
22524666Sdyson		pmap_kenter(kva, VM_PAGE_TO_PHYS(m));
22624666Sdyson
2271541Srgrimes		/*
22824666Sdyson		 * Now do the i/o move.
2291541Srgrimes		 */
23024666Sdyson		error = uiomove((caddr_t)(kva + page_offset), len, uio);
2311541Srgrimes
23224666Sdyson		pmap_kremove(kva);
2331541Srgrimes
23416889Sdyson		/*
23524666Sdyson		 * release the page and the object
23616889Sdyson		 */
23724666Sdyson		vm_page_unwire(m);
23824666Sdyson		vm_object_deallocate(object);
2391541Srgrimes
24016889Sdyson		object = NULL;
24116889Sdyson
2421541Srgrimes	} while (error == 0 && uio->uio_resid > 0);
2431541Srgrimes
24416889Sdyson	if (object)
24516889Sdyson		vm_object_deallocate(object);
24616889Sdyson
24724666Sdyson	kmem_free(kernel_map, kva, PAGE_SIZE);
24816308Sdyson	vmspace_free(vm);
2491541Srgrimes	return (error);
2501541Srgrimes}
2511541Srgrimes
2521541Srgrimes/*
2531541Srgrimes * Copy data in and out of the target process.
2541541Srgrimes * We do this by mapping the process's page into
2551541Srgrimes * the kernel and then doing a uiomove direct
2561541Srgrimes * from the kernel address space.
2571541Srgrimes */
2581541Srgrimesint
2591541Srgrimesprocfs_domem(curp, p, pfs, uio)
2601541Srgrimes	struct proc *curp;
2611541Srgrimes	struct proc *p;
2621541Srgrimes	struct pfsnode *pfs;
2631541Srgrimes	struct uio *uio;
2641541Srgrimes{
2651541Srgrimes
2661541Srgrimes	if (uio->uio_resid == 0)
2671541Srgrimes		return (0);
2681541Srgrimes
26922521Sdyson	return (procfs_rwmem(p, uio));
2701541Srgrimes}
2711541Srgrimes
2721541Srgrimes/*
2731541Srgrimes * Given process (p), find the vnode from which
2741541Srgrimes * it's text segment is being executed.
2751541Srgrimes *
2761541Srgrimes * It would be nice to grab this information from
2771541Srgrimes * the VM system, however, there is no sure-fire
2781541Srgrimes * way of doing that.  Instead, fork(), exec() and
2791541Srgrimes * wait() all maintain the p_textvp field in the
2801541Srgrimes * process proc structure which contains a held
2811541Srgrimes * reference to the exec'ed vnode.
2821541Srgrimes */
2831541Srgrimesstruct vnode *
2841541Srgrimesprocfs_findtextvp(p)
2851541Srgrimes	struct proc *p;
2861541Srgrimes{
28722521Sdyson
2881541Srgrimes	return (p->p_textvp);
2891541Srgrimes}
290