procfs_mem.c revision 16308
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 * @(#)procfs_mem.c 8.4 (Berkeley) 1/21/94 39 * 40 * $Id: procfs_mem.c,v 1.17 1996/01/25 06:05:38 peter Exp $ 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_param.h> 57#include <vm/vm_prot.h> 58#include <vm/lock.h> 59#include <vm/pmap.h> 60#include <vm/vm_map.h> 61#include <vm/vm_kern.h> 62#include <vm/vm_object.h> 63#include <vm/vm_page.h> 64#include <vm/vm_extern.h> 65#include <sys/user.h> 66 67static int procfs_rwmem __P((struct proc *p, struct uio *uio)); 68 69static int 70procfs_rwmem(p, uio) 71 struct proc *p; 72 struct uio *uio; 73{ 74 int error; 75 int writing; 76 struct vmspace *vm; 77 78 /* 79 * if the vmspace is in the midst of being deallocated or the 80 * process is exiting, don't try to grab anything. The page table 81 * usage in that process can be messed up. 82 */ 83 vm = p->p_vmspace; 84 if ((p->p_flag & P_WEXIT) || (vm->vm_refcnt < 1)) 85 return EFAULT; 86 ++vm->vm_refcnt; 87 88 writing = uio->uio_rw == UIO_WRITE; 89 90 /* 91 * Only map in one page at a time. We don't have to, but it 92 * makes things easier. This way is trivial - right? 93 */ 94 do { 95 vm_map_t map, tmap; 96 vm_object_t object; 97 vm_offset_t kva = 0; 98 vm_offset_t uva; 99 int page_offset; /* offset into page */ 100 vm_offset_t pageno; /* page number */ 101 vm_map_entry_t out_entry; 102 vm_prot_t out_prot; 103 vm_page_t m; 104 boolean_t wired, single_use; 105 vm_pindex_t pindex; 106 u_int len; 107 int fix_prot; 108 109 uva = (vm_offset_t) uio->uio_offset; 110 111 /* 112 * Get the page number of this segment. 113 */ 114 pageno = trunc_page(uva); 115 page_offset = uva - pageno; 116 117 /* 118 * How many bytes to copy 119 */ 120 len = min(PAGE_SIZE - page_offset, uio->uio_resid); 121 122 if (uva >= VM_MAXUSER_ADDRESS) { 123 if (writing || (uva >= (VM_MAXUSER_ADDRESS + UPAGES * PAGE_SIZE))) { 124 error = 0; 125 break; 126 } 127 128 /* we are reading the "U area", force it into core */ 129 PHOLD(p); 130 131 /* sanity check */ 132 if (!(p->p_flag & P_INMEM)) { 133 /* aiee! */ 134 error = EFAULT; 135 break; 136 } 137 138 /* populate the ptrace/procfs area */ 139 p->p_addr->u_kproc.kp_proc = *p; 140 fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); 141 142 /* locate the in-core address */ 143 kva = (u_int)p->p_addr + uva - VM_MAXUSER_ADDRESS; 144 145 /* transfer it */ 146 error = uiomove((caddr_t)kva, len, uio); 147 148 /* let the pages go */ 149 PRELE(p); 150 151 continue; 152 } 153 154 155 /* 156 * The map we want... 157 */ 158 map = &vm->vm_map; 159 160 /* 161 * Check the permissions for the area we're interested 162 * in. 163 */ 164 fix_prot = 0; 165 if (writing) 166 fix_prot = !vm_map_check_protection(map, pageno, 167 pageno + PAGE_SIZE, VM_PROT_WRITE); 168 169 if (fix_prot) { 170 /* 171 * If the page is not writable, we make it so. 172 * XXX It is possible that a page may *not* be 173 * read/executable, if a process changes that! 174 * We will assume, for now, that a page is either 175 * VM_PROT_ALL, or VM_PROT_READ|VM_PROT_EXECUTE. 176 */ 177 error = vm_map_protect(map, pageno, 178 pageno + PAGE_SIZE, VM_PROT_ALL, 0); 179 if (error) 180 break; 181 } 182 183 /* 184 * Now we need to get the page. out_entry, out_prot, wired, 185 * and single_use aren't used. One would think the vm code 186 * would be a *bit* nicer... We use tmap because 187 * vm_map_lookup() can change the map argument. 188 */ 189 tmap = map; 190 error = vm_map_lookup(&tmap, pageno, 191 writing ? VM_PROT_WRITE : VM_PROT_READ, 192 &out_entry, &object, &pindex, &out_prot, 193 &wired, &single_use); 194 /* 195 * We're done with tmap now. 196 */ 197 if (!error) 198 vm_map_lookup_done(tmap, out_entry); 199 200 /* 201 * Fault the page in... 202 */ 203 if (!error && writing && object->backing_object) { 204 m = vm_page_lookup(object, pindex); 205 if (m == 0) 206 error = vm_fault(map, pageno, 207 VM_PROT_WRITE, FALSE); 208 } 209 210 /* Find space in kernel_map for the page we're interested in */ 211 if (!error) 212 error = vm_map_find(kernel_map, object, 213 IDX_TO_OFF(pindex), &kva, PAGE_SIZE, 1, 214 VM_PROT_ALL, VM_PROT_ALL, 0); 215 216 if (!error) { 217 /* 218 * Neither vm_map_lookup() nor vm_map_find() appear 219 * to add a reference count to the object, so we do 220 * that here and now. 221 */ 222 vm_object_reference(object); 223 224 /* 225 * Mark the page we just found as pageable. 226 */ 227 error = vm_map_pageable(kernel_map, kva, 228 kva + PAGE_SIZE, 0); 229 230 /* 231 * Now do the i/o move. 232 */ 233 if (!error) 234 error = uiomove((caddr_t)(kva + page_offset), 235 len, uio); 236 237 vm_map_remove(kernel_map, kva, kva + PAGE_SIZE); 238 } 239 if (fix_prot) 240 vm_map_protect(map, pageno, pageno + PAGE_SIZE, 241 VM_PROT_READ|VM_PROT_EXECUTE, 0); 242 } while (error == 0 && uio->uio_resid > 0); 243 244 vmspace_free(vm); 245 return (error); 246} 247 248/* 249 * Copy data in and out of the target process. 250 * We do this by mapping the process's page into 251 * the kernel and then doing a uiomove direct 252 * from the kernel address space. 253 */ 254int 255procfs_domem(curp, p, pfs, uio) 256 struct proc *curp; 257 struct proc *p; 258 struct pfsnode *pfs; 259 struct uio *uio; 260{ 261 int error; 262 263 if (uio->uio_resid == 0) 264 return (0); 265 266 error = procfs_rwmem(p, uio); 267 268 return (error); 269} 270 271/* 272 * Given process (p), find the vnode from which 273 * it's text segment is being executed. 274 * 275 * It would be nice to grab this information from 276 * the VM system, however, there is no sure-fire 277 * way of doing that. Instead, fork(), exec() and 278 * wait() all maintain the p_textvp field in the 279 * process proc structure which contains a held 280 * reference to the exec'ed vnode. 281 */ 282struct vnode * 283procfs_findtextvp(p) 284 struct proc *p; 285{ 286 return (p->p_textvp); 287} 288