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