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