procfs_mem.c revision 1.11 1 /* $NetBSD: procfs_mem.c,v 1.11 1996/10/13 02:21:38 christos Exp $ */
2
3 /*
4 * Copyright (c) 1993 Jan-Simon Pendry
5 * Copyright (c) 1993 Sean Eric Fagan
6 * Copyright (c) 1993
7 * The Regents of the University of California. All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Jan-Simon Pendry and Sean Eric Fagan.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * @(#)procfs_mem.c 8.5 (Berkeley) 6/15/94
41 */
42
43 /*
44 * This is a lightly hacked and merged version
45 * of sef's pread/pwrite functions
46 */
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/time.h>
51 #include <sys/kernel.h>
52 #include <sys/proc.h>
53 #include <sys/vnode.h>
54 #include <miscfs/procfs/procfs.h>
55 #include <vm/vm.h>
56 #include <vm/vm_kern.h>
57 #include <vm/vm_page.h>
58
59 static int procfs_rwmem __P((struct proc *, struct uio *));
60
61 static int
62 procfs_rwmem(p, uio)
63 struct proc *p;
64 struct uio *uio;
65 {
66 int error;
67 int writing;
68
69 writing = uio->uio_rw == UIO_WRITE;
70
71 /*
72 * Only map in one page at a time. We don't have to, but it
73 * makes things easier. This way is trivial - right?
74 */
75 do {
76 vm_map_t map, tmap;
77 vm_object_t object;
78 vm_offset_t kva;
79 vm_offset_t uva;
80 int page_offset; /* offset into page */
81 vm_offset_t pageno; /* page number */
82 vm_map_entry_t out_entry;
83 vm_prot_t out_prot;
84 vm_page_t m;
85 boolean_t wired, single_use;
86 vm_offset_t off;
87 u_int len;
88 int fix_prot;
89
90 uva = (vm_offset_t) uio->uio_offset;
91 if (uva > VM_MAXUSER_ADDRESS) {
92 error = 0;
93 break;
94 }
95
96 /*
97 * Get the page number of this segment.
98 */
99 pageno = trunc_page(uva);
100 page_offset = uva - pageno;
101
102 /*
103 * How many bytes to copy
104 */
105 len = min(PAGE_SIZE - page_offset, uio->uio_resid);
106
107 /*
108 * The map we want...
109 */
110 map = &p->p_vmspace->vm_map;
111
112 /*
113 * Check the permissions for the area we're interested
114 * in.
115 */
116 fix_prot = 0;
117 if (writing)
118 fix_prot = !vm_map_check_protection(map, pageno,
119 pageno + PAGE_SIZE, VM_PROT_WRITE);
120
121 if (fix_prot) {
122 /*
123 * If the page is not writable, we make it so.
124 * XXX It is possible that a page may *not* be
125 * read/executable, if a process changes that!
126 * We will assume, for now, that a page is either
127 * VM_PROT_ALL, or VM_PROT_READ|VM_PROT_EXECUTE.
128 */
129 error = vm_map_protect(map, pageno,
130 pageno + PAGE_SIZE, VM_PROT_ALL, 0);
131 if (error)
132 break;
133 }
134
135 /*
136 * Now we need to get the page. out_entry, out_prot, wired,
137 * and single_use aren't used. One would think the vm code
138 * would be a *bit* nicer... We use tmap because
139 * vm_map_lookup() can change the map argument.
140 */
141 tmap = map;
142 error = vm_map_lookup(&tmap, pageno,
143 writing ? VM_PROT_WRITE : VM_PROT_READ,
144 &out_entry, &object, &off, &out_prot,
145 &wired, &single_use);
146 /*
147 * We're done with tmap now.
148 */
149 if (!error)
150 vm_map_lookup_done(tmap, out_entry);
151
152 /*
153 * Fault the page in...
154 */
155 if (!error && writing && object->shadow) {
156 m = vm_page_lookup(object, off);
157 if (m == 0 || (m->flags & PG_COPYONWRITE))
158 error = vm_fault(map, pageno,
159 VM_PROT_WRITE, FALSE);
160 }
161
162 /* Find space in kernel_map for the page we're interested in */
163 if (!error) {
164 kva = VM_MIN_KERNEL_ADDRESS;
165 error = vm_map_find(kernel_map, object, off, &kva,
166 PAGE_SIZE, 1);
167 }
168
169 if (!error) {
170 /*
171 * Neither vm_map_lookup() nor vm_map_find() appear
172 * to add a reference count to the object, so we do
173 * that here and now.
174 */
175 vm_object_reference(object);
176
177 /*
178 * Mark the page we just found as pageable.
179 */
180 error = vm_map_pageable(kernel_map, kva,
181 kva + PAGE_SIZE, 0);
182
183 /*
184 * Now do the i/o move.
185 */
186 if (!error)
187 error = uiomove((caddr_t) (kva + page_offset),
188 len, uio);
189
190 vm_map_remove(kernel_map, kva, kva + PAGE_SIZE);
191 }
192 if (fix_prot)
193 vm_map_protect(map, pageno, pageno + PAGE_SIZE,
194 VM_PROT_READ|VM_PROT_EXECUTE, 0);
195 } while (error == 0 && uio->uio_resid > 0);
196
197 return (error);
198 }
199
200 /*
201 * Copy data in and out of the target process.
202 * We do this by mapping the process's page into
203 * the kernel and then doing a uiomove direct
204 * from the kernel address space.
205 */
206 int
207 procfs_domem(curp, p, pfs, uio)
208 struct proc *curp;
209 struct proc *p;
210 struct pfsnode *pfs;
211 struct uio *uio;
212 {
213 int error;
214
215 if (uio->uio_resid == 0)
216 return (0);
217
218 PHOLD(p);
219 error = procfs_rwmem(p, uio);
220 PRELE(p);
221 return (error);
222 }
223
224 /*
225 * Given process (p), find the vnode from which
226 * it's text segment is being executed.
227 *
228 * It would be nice to grab this information from
229 * the VM system, however, there is no sure-fire
230 * way of doing that. Instead, fork(), exec() and
231 * wait() all maintain the p_textvp field in the
232 * process proc structure which contains a held
233 * reference to the exec'ed vnode.
234 */
235 struct vnode *
236 procfs_findtextvp(p)
237 struct proc *p;
238 {
239
240 return (p->p_textvp);
241 }
242
243
244 #ifdef probably_never
245 /*
246 * Given process (p), find the vnode from which
247 * it's text segment is being mapped.
248 *
249 * (This is here, rather than in procfs_subr in order
250 * to keep all the VM related code in one place.)
251 */
252 struct vnode *
253 procfs_findtextvp(p)
254 struct proc *p;
255 {
256 int error;
257 vm_object_t object;
258 vm_offset_t pageno; /* page number */
259
260 /* find a vnode pager for the user address space */
261
262 for (pageno = VM_MIN_ADDRESS;
263 pageno < VM_MAXUSER_ADDRESS;
264 pageno += PAGE_SIZE) {
265 vm_map_t map;
266 vm_map_entry_t out_entry;
267 vm_prot_t out_prot;
268 boolean_t wired, single_use;
269 vm_offset_t off;
270
271 map = &p->p_vmspace->vm_map;
272 error = vm_map_lookup(&map, pageno,
273 VM_PROT_READ,
274 &out_entry, &object, &off, &out_prot,
275 &wired, &single_use);
276
277 if (!error) {
278 vm_pager_t pager;
279
280 printf("procfs: found vm object\n");
281 vm_map_lookup_done(map, out_entry);
282 printf("procfs: vm object = %x\n", object);
283
284 /*
285 * At this point, assuming no errors, object
286 * is the VM object mapping UVA (pageno).
287 * Ensure it has a vnode pager, then grab
288 * the vnode from that pager's handle.
289 */
290
291 pager = object->pager;
292 printf("procfs: pager = %x\n", pager);
293 if (pager)
294 printf("procfs: found pager, type = %d\n",
295 pager->pg_type);
296 if (pager && pager->pg_type == PG_VNODE) {
297 struct vnode *vp;
298
299 vp = (struct vnode *) pager->pg_handle;
300 printf("procfs: vp = 0x%x\n", vp);
301 return (vp);
302 }
303 }
304 }
305
306 printf("procfs: text object not found\n");
307 return (0);
308 }
309 #endif /* probably_never */
310