xref: /csrg-svn/sys/miscfs/procfs/procfs_mem.c (revision 65756)
165522Spendry /*
265522Spendry  * Copyright (c) 1993 The Regents of the University of California.
365522Spendry  * Copyright (c) 1993 Jan-Simon Pendry
465522Spendry  * All rights reserved.
565522Spendry  *
665522Spendry  * This code is derived from software contributed to Berkeley by
7*65756Spendry  * Jan-Simon Pendry and Sean Eric Fagan.
865522Spendry  *
965522Spendry  * %sccs.include.redist.c%
1065522Spendry  *
11*65756Spendry  *	@(#)procfs_mem.c	8.2 (Berkeley) 01/17/94
1265522Spendry  *
1365522Spendry  * From:
1465522Spendry  *	$Id: procfs_mem.c,v 3.2 1993/12/15 09:40:17 jsp Exp $
1565522Spendry  */
1665522Spendry 
1765522Spendry /*
1865522Spendry  * This is a lightly hacked and merged version
1965522Spendry  * of sef's pread/pwrite functions
2065522Spendry  */
2165522Spendry 
2265522Spendry #include <sys/param.h>
2365522Spendry #include <sys/systm.h>
2465522Spendry #include <sys/time.h>
2565522Spendry #include <sys/kernel.h>
2665522Spendry #include <sys/proc.h>
2765522Spendry #include <sys/vnode.h>
2865522Spendry #include <miscfs/procfs/procfs.h>
2965522Spendry #include <vm/vm.h>
3065522Spendry #include <vm/vm_kern.h>
3165522Spendry #include <vm/vm_page.h>
3265522Spendry 
3365522Spendry static int
3465522Spendry procfs_rwmem(p, uio)
3565522Spendry 	struct proc *p;
3665522Spendry 	struct uio *uio;
3765522Spendry {
3865522Spendry 	int error;
3965522Spendry 	int writing;
4065522Spendry 
4165522Spendry 	writing = uio->uio_rw == UIO_WRITE;
4265522Spendry 
4365522Spendry 	/*
4465522Spendry 	 * Only map in one page at a time.  We don't have to, but it
4565522Spendry 	 * makes things easier.  This way is trivial - right?
4665522Spendry 	 */
4765522Spendry 	do {
4865522Spendry 		vm_map_t map, tmap;
4965522Spendry 		vm_object_t object;
5065522Spendry 		vm_offset_t kva;
5165522Spendry 		vm_offset_t uva;
5265522Spendry 		int page_offset;		/* offset into page */
5365522Spendry 		vm_offset_t pageno;		/* page number */
5465522Spendry 		vm_map_entry_t out_entry;
5565522Spendry 		vm_prot_t out_prot;
5665522Spendry 		vm_page_t m;
5765522Spendry 		boolean_t wired, single_use;
5865522Spendry 		vm_offset_t off;
5965522Spendry 		u_int len;
6065522Spendry 		int fix_prot;
6165522Spendry 
6265522Spendry 		uva = (vm_offset_t) uio->uio_offset;
6365522Spendry 		if (uva > VM_MAXUSER_ADDRESS) {
6465522Spendry 			error = 0;
6565522Spendry 			break;
6665522Spendry 		}
6765522Spendry 
6865522Spendry 		/*
6965522Spendry 		 * Get the page number of this segment.
7065522Spendry 		 */
7165522Spendry 		pageno = trunc_page(uva);
7265522Spendry 		page_offset = uva - pageno;
7365522Spendry 
7465522Spendry 		/*
7565522Spendry 		 * How many bytes to copy
7665522Spendry 		 */
7765522Spendry 		len = min(PAGE_SIZE - page_offset, uio->uio_resid);
7865522Spendry 
7965522Spendry 		/*
8065522Spendry 		 * The map we want...
8165522Spendry 		 */
8265522Spendry 		map = &p->p_vmspace->vm_map;
8365522Spendry 
8465522Spendry 		/*
8565522Spendry 		 * Check the permissions for the area we're interested
8665522Spendry 		 * in.
8765522Spendry 		 */
8865522Spendry 		fix_prot = 0;
8965522Spendry 		if (writing)
9065522Spendry 			fix_prot = !vm_map_check_protection(map, pageno,
9165522Spendry 					pageno + PAGE_SIZE, VM_PROT_WRITE);
9265522Spendry 
9365522Spendry 		if (fix_prot) {
9465522Spendry 			/*
9565522Spendry 			 * If the page is not writable, we make it so.
9665522Spendry 			 * XXX It is possible that a page may *not* be
9765522Spendry 			 * read/executable, if a process changes that!
9865522Spendry 			 * We will assume, for now, that a page is either
9965522Spendry 			 * VM_PROT_ALL, or VM_PROT_READ|VM_PROT_EXECUTE.
10065522Spendry 			 */
10165522Spendry 			error = vm_map_protect(map, pageno,
10265522Spendry 					pageno + PAGE_SIZE, VM_PROT_ALL, 0);
10365522Spendry 			if (error)
10465522Spendry 				break;
10565522Spendry 		}
10665522Spendry 
10765522Spendry 		/*
10865522Spendry 		 * Now we need to get the page.  out_entry, out_prot, wired,
10965522Spendry 		 * and single_use aren't used.  One would think the vm code
11065522Spendry 		 * would be a *bit* nicer...  We use tmap because
11165522Spendry 		 * vm_map_lookup() can change the map argument.
11265522Spendry 		 */
11365522Spendry 		tmap = map;
11465522Spendry 		error = vm_map_lookup(&tmap, pageno,
11565522Spendry 				      writing ? VM_PROT_WRITE : VM_PROT_READ,
11665522Spendry 				      &out_entry, &object, &off, &out_prot,
11765522Spendry 				      &wired, &single_use);
11865522Spendry 		/*
11965522Spendry 		 * We're done with tmap now.
12065522Spendry 		 */
12165522Spendry 		if (!error)
12265522Spendry 			vm_map_lookup_done(tmap, out_entry);
12365522Spendry 
12465522Spendry 		/*
12565522Spendry 		 * Fault the page in...
12665522Spendry 		 */
12765522Spendry 		if (!error && writing && object->shadow) {
12865522Spendry 			m = vm_page_lookup(object, off);
12965522Spendry 			if (m == 0 || (m->flags & PG_COPYONWRITE))
13065522Spendry 				error = vm_fault(map, pageno,
13165522Spendry 							VM_PROT_WRITE, FALSE);
13265522Spendry 		}
13365522Spendry 
13465522Spendry 		/* Find space in kernel_map for the page we're interested in */
13565522Spendry 		if (!error)
13665522Spendry 			error = vm_map_find(kernel_map, object, off, &kva,
13765522Spendry 					PAGE_SIZE, 1);
13865522Spendry 
13965522Spendry 		if (!error) {
14065522Spendry 			/*
14165522Spendry 			 * Neither vm_map_lookup() nor vm_map_find() appear
14265522Spendry 			 * to add a reference count to the object, so we do
14365522Spendry 			 * that here and now.
14465522Spendry 			 */
14565522Spendry 			vm_object_reference(object);
14665522Spendry 
14765522Spendry 			/*
14865522Spendry 			 * Mark the page we just found as pageable.
14965522Spendry 			 */
15065522Spendry 			error = vm_map_pageable(kernel_map, kva,
15165522Spendry 				kva + PAGE_SIZE, 0);
15265522Spendry 
15365522Spendry 			/*
15465522Spendry 			 * Now do the i/o move.
15565522Spendry 			 */
15665522Spendry 			if (!error)
15765522Spendry 				error = uiomove(kva + page_offset, len, uio);
15865522Spendry 
15965522Spendry 			vm_map_remove(kernel_map, kva, kva + PAGE_SIZE);
16065522Spendry 		}
16165522Spendry 		if (fix_prot)
16265522Spendry 			vm_map_protect(map, pageno, pageno + PAGE_SIZE,
16365522Spendry 					VM_PROT_READ|VM_PROT_EXECUTE, 0);
16465522Spendry 	} while (error == 0 && uio->uio_resid > 0);
16565522Spendry 
16665522Spendry 	return (error);
16765522Spendry }
16865522Spendry 
16965522Spendry /*
17065522Spendry  * Copy data in and out of the target process.
17165522Spendry  * We do this by mapping the process's page into
17265522Spendry  * the kernel and then doing a uiomove direct
17365522Spendry  * from the kernel address space.
17465522Spendry  */
17565522Spendry int
17665522Spendry procfs_domem(curp, p, pfs, uio)
17765522Spendry 	struct proc *curp;
17865522Spendry 	struct proc *p;
17965522Spendry 	struct pfsnode *pfs;
18065522Spendry 	struct uio *uio;
18165522Spendry {
18265522Spendry 	int error;
18365522Spendry 
18465522Spendry 	if (uio->uio_resid == 0)
18565522Spendry 		return (0);
18665522Spendry 
18765522Spendry 	error = procfs_rwmem(p, uio);
18865522Spendry 
18965522Spendry 	return (error);
19065522Spendry }
19165522Spendry 
19265522Spendry /*
19365522Spendry  * Given process (p), find the vnode from which
19465522Spendry  * it's text segment is being executed.
19565522Spendry  *
19665522Spendry  * It would be nice to grab this information from
19765522Spendry  * the VM system, however, there is no sure-fire
19865522Spendry  * way of doing that.  Instead, fork(), exec() and
19965522Spendry  * wait() all maintain the p_textvp field in the
20065522Spendry  * process proc structure which contains a held
20165522Spendry  * reference to the exec'ed vnode.
20265522Spendry  */
20365522Spendry struct vnode *
20465522Spendry procfs_findtextvp(p)
20565522Spendry 	struct proc *p;
20665522Spendry {
20765522Spendry 	return (p->p_textvp);
20865522Spendry }
20965522Spendry 
21065522Spendry 
21165522Spendry #ifdef probably_never
21265522Spendry /*
21365522Spendry  * Given process (p), find the vnode from which
21465522Spendry  * it's text segment is being mapped.
21565522Spendry  *
21665522Spendry  * (This is here, rather than in procfs_subr in order
21765522Spendry  * to keep all the VM related code in one place.)
21865522Spendry  */
21965522Spendry struct vnode *
22065522Spendry procfs_findtextvp(p)
22165522Spendry 	struct proc *p;
22265522Spendry {
22365522Spendry 	int error;
22465522Spendry 	vm_object_t object;
22565522Spendry 	vm_offset_t pageno;		/* page number */
22665522Spendry 
22765522Spendry 	/* find a vnode pager for the user address space */
22865522Spendry 
22965522Spendry 	for (pageno = VM_MIN_ADDRESS;
23065522Spendry 			pageno < VM_MAXUSER_ADDRESS;
23165522Spendry 			pageno += PAGE_SIZE) {
23265522Spendry 		vm_map_t map;
23365522Spendry 		vm_map_entry_t out_entry;
23465522Spendry 		vm_prot_t out_prot;
23565522Spendry 		boolean_t wired, single_use;
23665522Spendry 		vm_offset_t off;
23765522Spendry 
23865522Spendry 		map = &p->p_vmspace->vm_map;
23965522Spendry 		error = vm_map_lookup(&map, pageno,
24065522Spendry 			      VM_PROT_READ,
24165522Spendry 			      &out_entry, &object, &off, &out_prot,
24265522Spendry 			      &wired, &single_use);
24365522Spendry 
24465522Spendry 		if (!error) {
24565522Spendry 			vm_pager_t pager;
24665522Spendry 
24765522Spendry 			printf("procfs: found vm object\n");
24865522Spendry 			vm_map_lookup_done(map, out_entry);
24965522Spendry 			printf("procfs: vm object = %x\n", object);
25065522Spendry 
25165522Spendry 			/*
25265522Spendry 			 * At this point, assuming no errors, object
25365522Spendry 			 * is the VM object mapping UVA (pageno).
25465522Spendry 			 * Ensure it has a vnode pager, then grab
25565522Spendry 			 * the vnode from that pager's handle.
25665522Spendry 			 */
25765522Spendry 
25865522Spendry 			pager = object->pager;
25965522Spendry 			printf("procfs: pager = %x\n", pager);
26065522Spendry 			if (pager)
26165522Spendry 				printf("procfs: found pager, type = %d\n", pager->pg_type);
26265522Spendry 			if (pager && pager->pg_type == PG_VNODE) {
26365522Spendry 				struct vnode *vp;
26465522Spendry 
26565522Spendry 				vp = (struct vnode *) pager->pg_handle;
26665522Spendry 				printf("procfs: vp = 0x%x\n", vp);
26765522Spendry 				return (vp);
26865522Spendry 			}
26965522Spendry 		}
27065522Spendry 	}
27165522Spendry 
27265522Spendry 	printf("procfs: text object not found\n");
27365522Spendry 	return (0);
27465522Spendry }
27565522Spendry #endif /* probably_never */
276