8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * CDDL HEADER START
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * The contents of this file are subject to the terms of the
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Common Development and Distribution License (the "License").
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * You may not use this file except in compliance with the License.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * or http://www.opensolaris.org/os/licensing.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * See the License for the specific language governing permissions
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * and limitations under the License.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * When distributing Covered Code, include this CDDL HEADER in each
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * If applicable, add the following below this CDDL HEADER, with the
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * fields enclosed by brackets "[]" replaced with your own identifying
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * information: Portions Copyright [yyyy] [name of copyright owner]
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * CDDL HEADER END
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
193974072f41a843678abf5f61979c748687e66bSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Use is subject to license terms.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/types.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/modctl.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/conf.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/ddi.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/sunddi.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/devops.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/stat.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/file.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/cred.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/policy.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/errno.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <vm/seg_dev.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <vm/seg_vn.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <vm/page.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/fs/swapnode.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/sysmacros.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/fcntl.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/vmsystm.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#include <sys/physmem.h>
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb#include <sys/vfs_opreg.h>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic dev_info_t *physmem_dip = NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Linked list element hanging off physmem_proc_hash below, which holds all
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * the information for a given segment which has been setup for this process.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * This is a simple linked list as we are assuming that for a given process
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * the setup ioctl will only be called a handful of times. If this assumption
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * changes in the future, a quicker to traverse data structure should be used.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstruct physmem_hash {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_hash *ph_next;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t ph_base_pa;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec caddr_t ph_base_va;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec size_t ph_seg_len;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct vnode *ph_vnode;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec};
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Hash of all of the processes which have setup mappings with the driver with
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * pointers to per process data.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstruct physmem_proc_hash {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct proc *pph_proc;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_hash *pph_hash;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_proc_hash *pph_next;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec};
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/* Needs to be a power of two for simple hash algorithm */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#define PPH_SIZE 8
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstruct physmem_proc_hash *pph[PPH_SIZE];
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Lock which protects the pph hash above. To add an element (either a new
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * process or a new segment) the WRITE lock must be held. To traverse the
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * list, only a READ lock is needed.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289meckrwlock_t pph_rwlock;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec#define PHYSMEM_HASH(procp) ((int)((((uintptr_t)procp) >> 8) & (PPH_SIZE - 1)))
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Need to keep a reference count of how many processes have the driver
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * open to prevent it from disappearing.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecuint64_t physmem_vnodecnt;
8b464eb836173b92f2b7a65623cd06c8c3c59289meckmutex_t physmem_mutex; /* protects phsymem_vnodecnt */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int physmem_getpage(struct vnode *vp, offset_t off, size_t len,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint_t *protp, page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw enum seg_rw rw, struct cred *cr, caller_context_t *ct);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int physmem_addmap(struct vnode *vp, offset_t off, struct as *as,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec caddr_t addr, size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw struct cred *cred, caller_context_t *ct);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int physmem_delmap(struct vnode *vp, offset_t off, struct as *as,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec caddr_t addr, size_t len, uint_t prot, uint_t maxprot, uint_t flags,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw struct cred *cred, caller_context_t *ct);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void physmem_inactive(vnode_t *vp, cred_t *crp, caller_context_t *ct);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecconst fs_operation_def_t physmem_vnodeops_template[] = {
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb VOPNAME_GETPAGE, { .vop_getpage = physmem_getpage },
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb VOPNAME_ADDMAP, { .vop_addmap = physmem_addmap },
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb VOPNAME_DELMAP, { .vop_delmap = physmem_delmap },
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb VOPNAME_INACTIVE, { .vop_inactive = physmem_inactive },
aa59c4cb15a6ac5d4e585dadf7a055b580abf579rsb NULL, NULL
8b464eb836173b92f2b7a65623cd06c8c3c59289mec};
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecvnodeops_t *physmem_vnodeops = NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Removes the current process from the hash if the process has no more
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * physmem segments active.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecvoid
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_remove_hash_proc()
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int index;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_proc_hash **walker;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_proc_hash *victim = NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec index = PHYSMEM_HASH(curproc);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_enter(&pph_rwlock, RW_WRITER);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec walker = &pph[index];
8b464eb836173b92f2b7a65623cd06c8c3c59289mec while (*walker != NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if ((*walker)->pph_proc == curproc &&
8b464eb836173b92f2b7a65623cd06c8c3c59289mec (*walker)->pph_hash == NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec victim = *walker;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *walker = victim->pph_next;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec break;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec walker = &((*walker)->pph_next);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_exit(&pph_rwlock);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (victim != NULL)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec kmem_free(victim, sizeof (struct physmem_proc_hash));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Add a new entry to the hash for the given process to cache the
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * address ranges that it is working on. If this is the first hash
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * item to be added for this process, we will create the head pointer
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * for this process.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Returns 0 on success, ERANGE when the physical address is already in the
cd64d6e9f50d70599efa5c3e990d0f88efbe4351mec * hash.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecint
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_add_hash(struct physmem_hash *php)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int index;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_proc_hash *iterator;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_proc_hash *newp = NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_hash *temp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int ret = 0;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec index = PHYSMEM_HASH(curproc);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecinsert:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_enter(&pph_rwlock, RW_WRITER);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec iterator = pph[index];
8b464eb836173b92f2b7a65623cd06c8c3c59289mec while (iterator != NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (iterator->pph_proc == curproc) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * check to make sure a single process does not try to
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * map the same region twice.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec for (temp = iterator->pph_hash; temp != NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec temp = temp->ph_next) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if ((php->ph_base_pa >= temp->ph_base_pa &&
8b464eb836173b92f2b7a65623cd06c8c3c59289mec php->ph_base_pa < temp->ph_base_pa +
8b464eb836173b92f2b7a65623cd06c8c3c59289mec temp->ph_seg_len) ||
8b464eb836173b92f2b7a65623cd06c8c3c59289mec (temp->ph_base_pa >= php->ph_base_pa &&
8b464eb836173b92f2b7a65623cd06c8c3c59289mec temp->ph_base_pa < php->ph_base_pa +
8b464eb836173b92f2b7a65623cd06c8c3c59289mec php->ph_seg_len)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ret = ERANGE;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec break;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (ret == 0) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec php->ph_next = iterator->pph_hash;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec iterator->pph_hash = php;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_exit(&pph_rwlock);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* Need to check for two threads in sync */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (newp != NULL)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec kmem_free(newp, sizeof (*newp));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (ret);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec iterator = iterator->pph_next;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (newp != NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec newp->pph_proc = curproc;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec newp->pph_next = pph[index];
8b464eb836173b92f2b7a65623cd06c8c3c59289mec newp->pph_hash = php;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec php->ph_next = NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pph[index] = newp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_exit(&pph_rwlock);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_exit(&pph_rwlock);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* Dropped the lock so we could use KM_SLEEP */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec newp = kmem_zalloc(sizeof (struct physmem_proc_hash), KM_SLEEP);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec goto insert;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Will return the pointer to the physmem_hash struct if the setup routine
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * has previously been called for this memory.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Returns NULL on failure.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstruct physmem_hash *
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_get_hash(uint64_t req_paddr, size_t len, proc_t *procp)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int index;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_proc_hash *proc_hp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_hash *php;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ASSERT(rw_lock_held(&pph_rwlock));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec index = PHYSMEM_HASH(procp);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec proc_hp = pph[index];
8b464eb836173b92f2b7a65623cd06c8c3c59289mec while (proc_hp != NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (proc_hp->pph_proc == procp) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec php = proc_hp->pph_hash;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec while (php != NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if ((req_paddr >= php->ph_base_pa) &&
8b464eb836173b92f2b7a65623cd06c8c3c59289mec (req_paddr + len <=
8b464eb836173b92f2b7a65623cd06c8c3c59289mec php->ph_base_pa + php->ph_seg_len)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (php);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec php = php->ph_next;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec proc_hp = proc_hp->pph_next;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (NULL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecint
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_validate_cookie(uint64_t p_cookie)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int index;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_proc_hash *proc_hp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_hash *php;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ASSERT(rw_lock_held(&pph_rwlock));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec index = PHYSMEM_HASH(curproc);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec proc_hp = pph[index];
8b464eb836173b92f2b7a65623cd06c8c3c59289mec while (proc_hp != NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (proc_hp->pph_proc == curproc) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec php = proc_hp->pph_hash;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec while (php != NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if ((uint64_t)(uintptr_t)php == p_cookie) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (1);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec php = php->ph_next;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec proc_hp = proc_hp->pph_next;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Remove the given vnode from the pph hash. If it exists in the hash the
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * process still has to be around as the vnode is obviously still around and
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * since it's a physmem vnode, it must be in the hash.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * If it is not in the hash that must mean that the setup ioctl failed.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Return 0 in this instance, 1 if it is in the hash.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecint
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_remove_vnode_hash(vnode_t *vp)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int index;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_proc_hash *proc_hp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_hash **phpp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_hash *victim;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec index = PHYSMEM_HASH(curproc);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* synchronize with the map routine */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_enter(&pph_rwlock, RW_WRITER);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec proc_hp = pph[index];
8b464eb836173b92f2b7a65623cd06c8c3c59289mec while (proc_hp != NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (proc_hp->pph_proc == curproc) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec phpp = &proc_hp->pph_hash;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec while (*phpp != NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if ((*phpp)->ph_vnode == vp) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec victim = *phpp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *phpp = victim->ph_next;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_exit(&pph_rwlock);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec kmem_free(victim, sizeof (*victim));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (1);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec phpp = &(*phpp)->ph_next;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec proc_hp = proc_hp->pph_next;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_exit(&pph_rwlock);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* not found */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecint
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_setup_vnops()
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int error;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec char *name = "physmem";
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (physmem_vnodeops != NULL)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cmn_err(CE_PANIC, "physmem vnodeops already set\n");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec error = vn_make_ops(name, physmem_vnodeops_template, &physmem_vnodeops);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (error != 0) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cmn_err(CE_WARN, "physmem_setup_vnops: bad vnode ops template");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (error);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * The guts of the PHYSMEM_SETUP ioctl.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Create a segment in the address space with the specified parameters.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * If pspp->user_va is NULL, as_gap will be used to find an appropriate VA.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * We do not do bounds checking on the requested physical addresses, if they
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * do not exist in the system, they will not be mappable.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Returns 0 on success with the following error codes on failure:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * ENOMEM - The VA range requested was already mapped if pspp->user_va is
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * non-NULL or the system was unable to find enough VA space for
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * the desired length if user_va was NULL>
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * EINVAL - The requested PA, VA, or length was not PAGESIZE aligned.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecint
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_setup_addrs(struct physmem_setup_param *pspp)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct as *as = curproc->p_as;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct segvn_crargs vn_a;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int ret = 0;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t base_pa;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec size_t len;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec caddr_t uvaddr;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct vnode *vp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_hash *php;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ASSERT(pspp != NULL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec base_pa = pspp->req_paddr;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec len = pspp->len;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uvaddr = (caddr_t)(uintptr_t)pspp->user_va;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* Sanity checking */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (!IS_P2ALIGNED(base_pa, PAGESIZE))
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (EINVAL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (!IS_P2ALIGNED(len, PAGESIZE))
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (EINVAL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (uvaddr != NULL && !IS_P2ALIGNED(uvaddr, PAGESIZE))
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (EINVAL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec php = kmem_zalloc(sizeof (struct physmem_hash), KM_SLEEP);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* Need to bump vnode count so that the driver can not be unloaded */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mutex_enter(&physmem_mutex);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec physmem_vnodecnt++;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mutex_exit(&physmem_mutex);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vp = vn_alloc(KM_SLEEP);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ASSERT(vp != NULL); /* SLEEP can't return NULL */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vn_setops(vp, physmem_vnodeops);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec php->ph_vnode = vp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vn_a.vp = vp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vn_a.offset = (u_offset_t)base_pa;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vn_a.type = MAP_SHARED;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vn_a.prot = PROT_ALL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vn_a.maxprot = PROT_ALL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vn_a.flags = 0;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vn_a.cred = NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vn_a.amp = NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vn_a.szc = 0;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vn_a.lgrp_mem_policy_flags = 0;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec as_rangelock(as);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (uvaddr != NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (as_gap(as, len, &uvaddr, &len, AH_LO, NULL) == -1) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ret = ENOMEM;
8b464eb836173b92f2b7a65623cd06c8c3c59289mecfail:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec as_rangeunlock(as);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vn_free(vp);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec kmem_free(php, sizeof (*php));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mutex_enter(&physmem_mutex);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec physmem_vnodecnt--;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mutex_exit(&physmem_mutex);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (ret);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec } else {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* We pick the address for the user */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec map_addr(&uvaddr, len, 0, 1, 0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (uvaddr == NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ret = ENOMEM;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec goto fail;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ret = as_map(as, uvaddr, len, segvn_create, &vn_a);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (ret == 0) {
cd64d6e9f50d70599efa5c3e990d0f88efbe4351mec as_rangeunlock(as);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec php->ph_base_pa = base_pa;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec php->ph_base_va = uvaddr;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec php->ph_seg_len = len;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pspp->user_va = (uint64_t)(uintptr_t)uvaddr;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pspp->cookie = (uint64_t)(uintptr_t)php;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ret = physmem_add_hash(php);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (ret == 0)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
cd64d6e9f50d70599efa5c3e990d0f88efbe4351mec
cd64d6e9f50d70599efa5c3e990d0f88efbe4351mec /* Note that the call to as_unmap will free the vnode */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec (void) as_unmap(as, uvaddr, len);
cd64d6e9f50d70599efa5c3e990d0f88efbe4351mec kmem_free(php, sizeof (*php));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (ret);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec goto fail;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*NOTREACHED*/
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * The guts of the PHYSMEM_MAP ioctl.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Map the given PA to the appropriate VA if PHYSMEM_SETUP ioctl has already
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * been called for this PA range.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Returns 0 on success with the following error codes on failure:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * EPERM - The requested page is long term locked, and thus repeated
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * requests to allocate this page will likely fail.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * EAGAIN - The requested page could not be allocated, but it is believed
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * that future attempts could succeed.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * ENOMEM - There was not enough free memory in the system to safely
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * map the requested page.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * EINVAL - The requested paddr was not PAGESIZE aligned or the
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * PHYSMEM_SETUP ioctl was not called for this page.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * ENOENT - The requested page was iniside the kernel cage, and the
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * PHYSMEM_CAGE flag was not set.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * EBUSY - The requested page is retired and the PHYSMEM_RETIRE flag
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * was not set.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_map_addrs(struct physmem_map_param *pmpp)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec caddr_t uvaddr;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec page_t *pp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t req_paddr;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct vnode *vp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int ret = 0;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_hash *php;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint_t flags = 0;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ASSERT(pmpp != NULL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec req_paddr = pmpp->req_paddr;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (!IS_P2ALIGNED(req_paddr, PAGESIZE))
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (EINVAL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* Find the vnode for this map request */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_enter(&pph_rwlock, RW_READER);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec php = physmem_get_hash(req_paddr, PAGESIZE, curproc);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (php == NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_exit(&pph_rwlock);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (EINVAL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vp = php->ph_vnode;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uvaddr = php->ph_base_va + (req_paddr - php->ph_base_pa);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_exit(&pph_rwlock);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pp = page_numtopp_nolock(btop((size_t)req_paddr));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (pp == NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pmpp->ret_va = NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (EPERM);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Check to see if page already mapped correctly. This can happen
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * when we failed to capture a page previously and it was captured
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * asynchronously for us. Return success in this case.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (pp->p_vnode == vp) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ASSERT(pp->p_offset == (u_offset_t)req_paddr);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pmpp->ret_va = (uint64_t)(uintptr_t)uvaddr;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * physmem should be responsible for checking for cage
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * and prom pages.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (pmpp->flags & PHYSMEM_CAGE)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec flags = CAPTURE_GET_CAGE;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (pmpp->flags & PHYSMEM_RETIRED)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec flags |= CAPTURE_GET_RETIRED;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ret = page_trycapture(pp, 0, flags | CAPTURE_PHYSMEM, curproc);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (ret != 0) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pmpp->ret_va = NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (ret);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec } else {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pmpp->ret_va = (uint64_t)(uintptr_t)uvaddr;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Map the given page into the process's address space if possible.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * We actually only hash the page in on the correct vnode as the page
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * will be mapped via segvn_pagefault.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * returns 0 on success
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * returns 1 if there is no need to map this page anymore (process exited)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * returns -1 if we failed to map the page.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecint
8b464eb836173b92f2b7a65623cd06c8c3c59289mecmap_page_proc(page_t *pp, void *arg, uint_t flags)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct vnode *vp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec proc_t *procp = (proc_t *)arg;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int ret;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec u_offset_t paddr = (u_offset_t)ptob(pp->p_pagenum);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_hash *php;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ASSERT(pp != NULL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Check against availrmem to make sure that we're not low on memory.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * We check again here as ASYNC requests do not do this check elsewhere.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * We return 1 as we don't want the page to have the PR_CAPTURE bit
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * set or be on the page capture hash.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (swapfs_minfree > availrmem + 1) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec page_free(pp, 1);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (1);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * If this is an asynchronous request for the current process,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * we can not map the page as it's possible that we are also in the
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * process of unmapping the page which could result in a deadlock
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * with the as lock.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if ((flags & CAPTURE_ASYNC) && (curproc == procp)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec page_free(pp, 1);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (-1);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* only return zeroed out pages */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pagezero(pp, 0, PAGESIZE);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_enter(&pph_rwlock, RW_READER);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec php = physmem_get_hash(paddr, PAGESIZE, procp);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (php == NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_exit(&pph_rwlock);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Free the page as there is no longer a valid outstanding
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * request for this page.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec page_free(pp, 1);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (1);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vp = php->ph_vnode;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * We need to protect against a possible deadlock here where we own
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * the vnode page hash mutex and want to acquire it again as there
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * are locations in the code, where we unlock a page while holding
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * the mutex which can lead to the page being captured and eventually
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * end up here.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (mutex_owned(page_vnode_mutex(vp))) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_exit(&pph_rwlock);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec page_free(pp, 1);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (-1);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ret = page_hashin(pp, vp, paddr, NULL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_exit(&pph_rwlock);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (ret == 0) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec page_free(pp, 1);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (-1);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec page_downgrade(pp);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mutex_enter(&freemem_lock);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec availrmem--;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mutex_exit(&freemem_lock);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * The guts of the PHYSMEM_DESTROY ioctl.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * The cookie passed in will provide all of the information needed to
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * free up the address space and physical memory associated with the
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * corresponding PHSYMEM_SETUP ioctl.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Returns 0 on success with the following error codes on failure:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * EINVAL - The cookie supplied is not valid.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mecint
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_destroy_addrs(uint64_t p_cookie)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct as *as = curproc->p_as;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec size_t len;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec caddr_t uvaddr;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_enter(&pph_rwlock, RW_READER);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (physmem_validate_cookie(p_cookie) == 0) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_exit(&pph_rwlock);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (EINVAL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec len = ((struct physmem_hash *)(uintptr_t)p_cookie)->ph_seg_len;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uvaddr = ((struct physmem_hash *)(uintptr_t)p_cookie)->ph_base_va;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rw_exit(&pph_rwlock);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec (void) as_unmap(as, uvaddr, len);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * If the page has been hashed into the physmem vnode, then just look it up
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * and return it via pl, otherwise return ENOMEM as the map ioctl has not
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * succeeded on the given page.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*ARGSUSED*/
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_getpage(struct vnode *vp, offset_t off, size_t len, uint_t *protp,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr, enum seg_rw rw,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw struct cred *cr, caller_context_t *ct)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec page_t *pp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ASSERT(len == PAGESIZE);
dc32d872cbeb56532bcea030255db9cd79bac7daJosef 'Jeff' Sipek ASSERT(AS_READ_HELD(seg->s_as));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * If the page is in the hash, then we successfully claimed this
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * page earlier, so return it to the caller.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pp = page_lookup(vp, off, SE_SHARED);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (pp != NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pl[0] = pp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pl[1] = NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *protp = PROT_ALL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (ENOMEM);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * We can not allow a process mapping /dev/physmem pages to fork as there can
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * only be a single mapping to a /dev/physmem page at a given time. Thus, the
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * return of EINVAL when we are not working on our own address space.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Otherwise we return zero as this function is required for normal operation.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*ARGSUSED*/
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_addmap(struct vnode *vp, offset_t off, struct as *as,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec caddr_t addr, size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw struct cred *cred, caller_context_t *ct)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (curproc->p_as != as) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (EINVAL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/* Will always get called for removing a whole segment. */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*ARGSUSED*/
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_delmap(struct vnode *vp, offset_t off, struct as *as,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec caddr_t addr, size_t len, uint_t prot, uint_t maxprot, uint_t flags,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw struct cred *cred, caller_context_t *ct)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Release our hold on the vnode so that the final VN_RELE will
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * call physmem_inactive to clean things up.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec VN_RELE(vp);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Clean up all the pages belonging to this vnode and then free it.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*ARGSUSED*/
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwphysmem_inactive(vnode_t *vp, cred_t *crp, caller_context_t *ct)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec page_t *pp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * Remove the vnode from the hash now, to prevent asynchronous
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * attempts to map into this vnode. This avoids a deadlock
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * where two threads try to get into this logic at the same
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * time and try to map the pages they are destroying into the
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * other's address space.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * If it's not in the hash, just free it.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (physmem_remove_vnode_hash(vp) == 0) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ASSERT(vp->v_pages == NULL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vn_free(vp);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec physmem_remove_hash_proc();
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mutex_enter(&physmem_mutex);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec physmem_vnodecnt--;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mutex_exit(&physmem_mutex);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * At this point in time, no other logic can be adding or removing
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * pages from the vnode, otherwise the v_pages list could be inaccurate.
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec while ((pp = vp->v_pages) != NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec page_t *rpp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (page_tryupgrade(pp)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /*
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * set lckcnt for page_destroy to do availrmem
8b464eb836173b92f2b7a65623cd06c8c3c59289mec * accounting
8b464eb836173b92f2b7a65623cd06c8c3c59289mec */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pp->p_lckcnt = 1;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec page_destroy(pp, 0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec } else {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* failure to lock should be transient */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec rpp = page_lookup(vp, ptob(pp->p_pagenum), SE_SHARED);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (rpp != pp) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec page_unlock(rpp);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec continue;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec page_unlock(pp);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vn_free(vp);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec physmem_remove_hash_proc();
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mutex_enter(&physmem_mutex);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec physmem_vnodecnt--;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mutex_exit(&physmem_mutex);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*ARGSUSED*/
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int *rvalp)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int ret;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec switch (cmd) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec case PHYSMEM_SETUP:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_setup_param psp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (ddi_copyin((void *)arg, &psp,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec sizeof (struct physmem_setup_param), 0))
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (EFAULT);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ret = physmem_setup_addrs(&psp);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (ddi_copyout(&psp, (void *)arg, sizeof (psp), 0))
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (EFAULT);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec break;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec case PHYSMEM_MAP:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec struct physmem_map_param pmp;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (ddi_copyin((void *)arg, &pmp,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec sizeof (struct physmem_map_param), 0))
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (EFAULT);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ret = physmem_map_addrs(&pmp);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (ddi_copyout(&pmp, (void *)arg, sizeof (pmp), 0))
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (EFAULT);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec break;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec case PHYSMEM_DESTROY:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec uint64_t cookie;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (ddi_copyin((void *)arg, &cookie,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec sizeof (uint64_t), 0))
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (EFAULT);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ret = physmem_destroy_addrs(cookie);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec break;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec default:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (ENOTSUP);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (ret);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*ARGSUSED*/
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_open(dev_t *devp, int flag, int otyp, cred_t *credp)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int ret;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec static int msg_printed = 0;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if ((flag & (FWRITE | FREAD)) != (FWRITE | FREAD)) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (EINVAL);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* need to make sure we have the right privileges */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if ((ret = secpolicy_resource(credp)) != 0)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (ret);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if ((ret = secpolicy_lock_memory(credp)) != 0)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (ret);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (msg_printed == 0) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec cmn_err(CE_NOTE, "!driver has been opened. This driver may "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "take out long term locks on pages which may impact "
8b464eb836173b92f2b7a65623cd06c8c3c59289mec "dynamic reconfiguration events");
8b464eb836173b92f2b7a65623cd06c8c3c59289mec msg_printed = 1;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*ARGSUSED*/
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_close(dev_t dev, int flag, int otyp, cred_t *credp)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (0);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec/*ARGSUSED*/
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec void *arg, void **resultp)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec switch (infocmd) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec case DDI_INFO_DEVT2DEVINFO:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *resultp = physmem_dip;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (DDI_SUCCESS);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec case DDI_INFO_DEVT2INSTANCE:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec *resultp = (void *)(ulong_t)getminor((dev_t)arg);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (DDI_SUCCESS);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec default:
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (DDI_FAILURE);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int i;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (cmd == DDI_RESUME) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (DDI_SUCCESS);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (cmd != DDI_ATTACH)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (DDI_FAILURE);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (ddi_create_minor_node(dip, ddi_get_name(dip), S_IFCHR,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ddi_get_instance(dip), DDI_PSEUDO, 0) != DDI_SUCCESS)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (DDI_FAILURE);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec physmem_dip = dip;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec /* Initialize driver specific data */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (physmem_setup_vnops()) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ddi_remove_minor_node(dip, ddi_get_name(dip));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (DDI_FAILURE);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec for (i = 0; i < PPH_SIZE; i++)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec pph[i] = NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec page_capture_register_callback(PC_PHYSMEM, 10000,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec map_page_proc);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (DDI_SUCCESS);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic int
8b464eb836173b92f2b7a65623cd06c8c3c59289mecphysmem_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec int ret = DDI_SUCCESS;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (cmd == DDI_SUSPEND) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (DDI_SUCCESS);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (cmd != DDI_DETACH)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (DDI_FAILURE);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ASSERT(physmem_dip == dip);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mutex_enter(&physmem_mutex);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (physmem_vnodecnt == 0) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (physmem_vnodeops != NULL) {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec vn_freevnodeops(physmem_vnodeops);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec physmem_vnodeops = NULL;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec page_capture_unregister_callback(PC_PHYSMEM);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec } else {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ret = EBUSY;
8b464eb836173b92f2b7a65623cd06c8c3c59289mec }
8b464eb836173b92f2b7a65623cd06c8c3c59289mec mutex_exit(&physmem_mutex);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec if (ret == DDI_SUCCESS)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ddi_remove_minor_node(dip, ddi_get_name(dip));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (ret);
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic struct cb_ops physmem_cb_ops = {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec physmem_open, /* open */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec physmem_close, /* close */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec nodev, /* strategy */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec nodev, /* print */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec nodev, /* dump */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec nodev, /* read */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec nodev, /* write */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec physmem_ioctl, /* ioctl */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec nodev, /* devmap */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec nodev, /* mmap */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec nodev, /* segmap */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec nochpoll, /* chpoll */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec ddi_prop_op, /* prop_op */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec NULL, /* cb_str */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec D_NEW | D_MP | D_DEVMAP,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec CB_REV,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec NULL,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec NULL
8b464eb836173b92f2b7a65623cd06c8c3c59289mec};
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic struct dev_ops physmem_ops = {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec DEVO_REV,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec 0,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec physmem_getinfo,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec nulldev,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec nulldev,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec physmem_attach,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec physmem_detach,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec nodev,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec &physmem_cb_ops,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec NULL,
193974072f41a843678abf5f61979c748687e66bSherry Moore NULL,
193974072f41a843678abf5f61979c748687e66bSherry Moore ddi_quiesce_not_needed, /* quiesce */
8b464eb836173b92f2b7a65623cd06c8c3c59289mec};
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic struct modldrv modldrv = {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec &mod_driverops,
193974072f41a843678abf5f61979c748687e66bSherry Moore "physmem driver",
8b464eb836173b92f2b7a65623cd06c8c3c59289mec &physmem_ops
8b464eb836173b92f2b7a65623cd06c8c3c59289mec};
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecstatic struct modlinkage modlinkage = {
8b464eb836173b92f2b7a65623cd06c8c3c59289mec MODREV_1,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec &modldrv,
8b464eb836173b92f2b7a65623cd06c8c3c59289mec NULL
8b464eb836173b92f2b7a65623cd06c8c3c59289mec};
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecint
8b464eb836173b92f2b7a65623cd06c8c3c59289mec_init(void)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mod_install(&modlinkage));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecint
8b464eb836173b92f2b7a65623cd06c8c3c59289mec_info(struct modinfo *modinfop)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mod_info(&modlinkage, modinfop));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}
8b464eb836173b92f2b7a65623cd06c8c3c59289mec
8b464eb836173b92f2b7a65623cd06c8c3c59289mecint
8b464eb836173b92f2b7a65623cd06c8c3c59289mec_fini(void)
8b464eb836173b92f2b7a65623cd06c8c3c59289mec{
8b464eb836173b92f2b7a65623cd06c8c3c59289mec return (mod_remove(&modlinkage));
8b464eb836173b92f2b7a65623cd06c8c3c59289mec}