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