843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * CDDL HEADER START
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * The contents of this file are subject to the terms of the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Common Development and Distribution License (the "License").
843e19887f64dde75055cf8842fc4db2171eff45johnlev * You may not use this file except in compliance with the License.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
843e19887f64dde75055cf8842fc4db2171eff45johnlev * or http://www.opensolaris.org/os/licensing.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * See the License for the specific language governing permissions
843e19887f64dde75055cf8842fc4db2171eff45johnlev * and limitations under the License.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * When distributing Covered Code, include this CDDL HEADER in each
843e19887f64dde75055cf8842fc4db2171eff45johnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * If applicable, add the following below this CDDL HEADER, with the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * fields enclosed by brackets "[]" replaced with your own identifying
843e19887f64dde75055cf8842fc4db2171eff45johnlev * information: Portions Copyright [yyyy] [name of copyright owner]
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * CDDL HEADER END
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Use is subject to license terms.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Machine frame segment driver. This segment driver allows dom0 processes to
843e19887f64dde75055cf8842fc4db2171eff45johnlev * map pages of other domains or Xen (e.g. during save/restore). ioctl()s on
843e19887f64dde75055cf8842fc4db2171eff45johnlev * the privcmd driver provide the MFN values backing each mapping, and we map
843e19887f64dde75055cf8842fc4db2171eff45johnlev * them into the process's address space at this time. Demand-faulting is not
843e19887f64dde75055cf8842fc4db2171eff45johnlev * supported by this driver due to the requirements upon some of the ioctl()s.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/types.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/systm.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/vmsystm.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/mman.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/errno.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/kmem.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/cmn_err.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/vnode.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/conf.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/debug.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/lgrp.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/hypervisor.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <vm/page.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <vm/hat.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <vm/as.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <vm/seg.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <vm/hat_pte.h>
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson#include <vm/hat_i86.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <vm/seg_mf.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/fs/snode.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define VTOCVP(vp) (VTOS(vp)->s_commonvp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev
7eea693d6b672899726e75993fddc4e95b52647fMark Johnsontypedef struct segmf_mfn_s {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson mfn_t m_mfn;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson} segmf_mfn_t;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson/* g_flags */
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson#define SEGMF_GFLAGS_WR 0x1
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson#define SEGMF_GFLAGS_MAPPED 0x2
7eea693d6b672899726e75993fddc4e95b52647fMark Johnsontypedef struct segmf_gref_s {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson uint64_t g_ptep;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson grant_ref_t g_gref;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson uint32_t g_flags;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson grant_handle_t g_handle;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson} segmf_gref_t;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnsontypedef union segmf_mu_u {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson segmf_mfn_t m;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson segmf_gref_t g;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson} segmf_mu_t;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnsontypedef enum {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson SEGMF_MAP_EMPTY = 0,
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson SEGMF_MAP_MFN,
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson SEGMF_MAP_GREF
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson} segmf_map_type_t;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnsontypedef struct segmf_map_s {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson segmf_map_type_t t_type;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson segmf_mu_t u;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson} segmf_map_t;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstruct segmf_data {
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmutex_t lock;
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct vnode *vp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uchar_t prot;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uchar_t maxprot;
843e19887f64dde75055cf8842fc4db2171eff45johnlev size_t softlockcnt;
843e19887f64dde75055cf8842fc4db2171eff45johnlev domid_t domid;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson segmf_map_t *map;
843e19887f64dde75055cf8842fc4db2171eff45johnlev};
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic struct seg_ops segmf_ops;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
7eea693d6b672899726e75993fddc4e95b52647fMark Johnsonstatic int segmf_fault_gref_range(struct seg *seg, caddr_t addr, size_t len);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic struct segmf_data *
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_data_zalloc(struct seg *seg)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct segmf_data *data = kmem_zalloc(sizeof (*data), KM_SLEEP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_init(&data->lock, "segmf.lock", MUTEX_DEFAULT, NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev seg->s_ops = &segmf_ops;
843e19887f64dde75055cf8842fc4db2171eff45johnlev seg->s_data = data;
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (data);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevint
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_create(struct seg *seg, void *args)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct segmf_crargs *a = args;
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct segmf_data *data;
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct as *as = seg->s_as;
843e19887f64dde75055cf8842fc4db2171eff45johnlev pgcnt_t i, npages = seg_pages(seg);
843e19887f64dde75055cf8842fc4db2171eff45johnlev int error;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev hat_map(as->a_hat, seg->s_base, seg->s_size, HAT_MAP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev data = segmf_data_zalloc(seg);
843e19887f64dde75055cf8842fc4db2171eff45johnlev data->vp = specfind(a->dev, VCHR);
843e19887f64dde75055cf8842fc4db2171eff45johnlev data->prot = a->prot;
843e19887f64dde75055cf8842fc4db2171eff45johnlev data->maxprot = a->maxprot;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson data->map = kmem_alloc(npages * sizeof (segmf_map_t), KM_SLEEP);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson for (i = 0; i < npages; i++) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson data->map[i].t_type = SEGMF_MAP_EMPTY;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = VOP_ADDMAP(VTOCVP(data->vp), 0, as, seg->s_base, seg->s_size,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw data->prot, data->maxprot, MAP_SHARED, CRED(), NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (error != 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev hat_unload(as->a_hat,
843e19887f64dde75055cf8842fc4db2171eff45johnlev seg->s_base, seg->s_size, HAT_UNLOAD_UNMAP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (error);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Duplicate a seg and return new segment in newseg.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_dup(struct seg *seg, struct seg *newseg)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct segmf_data *data = seg->s_data;
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct segmf_data *ndata;
843e19887f64dde75055cf8842fc4db2171eff45johnlev pgcnt_t npages = seg_pages(newseg);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson size_t sz;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ndata = segmf_data_zalloc(newseg);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev VN_HOLD(data->vp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ndata->vp = data->vp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ndata->prot = data->prot;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ndata->maxprot = data->maxprot;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ndata->domid = data->domid;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson sz = npages * sizeof (segmf_map_t);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson ndata->map = kmem_alloc(sz, KM_SLEEP);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson bcopy(data->map, ndata->map, sz);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (VOP_ADDMAP(VTOCVP(ndata->vp), 0, newseg->s_as,
843e19887f64dde75055cf8842fc4db2171eff45johnlev newseg->s_base, newseg->s_size, ndata->prot, ndata->maxprot,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw MAP_SHARED, CRED(), NULL));
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * We only support unmapping the whole segment, and we automatically unlock
843e19887f64dde75055cf8842fc4db2171eff45johnlev * what we previously soft-locked.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_unmap(struct seg *seg, caddr_t addr, size_t len)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct segmf_data *data = seg->s_data;
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset_t off;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (addr < seg->s_base || addr + len > seg->s_base + seg->s_size ||
843e19887f64dde75055cf8842fc4db2171eff45johnlev (len & PAGEOFFSET) || ((uintptr_t)addr & PAGEOFFSET))
843e19887f64dde75055cf8842fc4db2171eff45johnlev panic("segmf_unmap");
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (addr != seg->s_base || len != seg->s_size)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENOTSUP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev hat_unload(seg->s_as->a_hat, addr, len,
843e19887f64dde75055cf8842fc4db2171eff45johnlev HAT_UNLOAD_UNMAP | HAT_UNLOAD_UNLOCK);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev off = (offset_t)seg_page(seg, addr);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(data->vp != NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void) VOP_DELMAP(VTOCVP(data->vp), off, seg->s_as, addr, len,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw data->prot, data->maxprot, MAP_SHARED, CRED(), NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev seg_free(seg);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_free(struct seg *seg)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct segmf_data *data = seg->s_data;
843e19887f64dde75055cf8842fc4db2171eff45johnlev pgcnt_t npages = seg_pages(seg);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson kmem_free(data->map, npages * sizeof (segmf_map_t));
843e19887f64dde75055cf8842fc4db2171eff45johnlev VN_RELE(data->vp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_destroy(&data->lock);
843e19887f64dde75055cf8842fc4db2171eff45johnlev kmem_free(data, sizeof (*data));
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int segmf_faultpage_debug = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_faultpage(struct hat *hat, struct seg *seg, caddr_t addr,
843e19887f64dde75055cf8842fc4db2171eff45johnlev enum fault_type type, uint_t prot)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct segmf_data *data = seg->s_data;
843e19887f64dde75055cf8842fc4db2171eff45johnlev uint_t hat_flags = HAT_LOAD_NOCONSIST;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mfn_t mfn;
843e19887f64dde75055cf8842fc4db2171eff45johnlev x86pte_t pte;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson segmf_map_t *map;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson uint_t idx;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson idx = seg_page(seg, addr);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson map = &data->map[idx];
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson ASSERT(map->t_type == SEGMF_MAP_MFN);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson mfn = map->u.m.m_mfn;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (type == F_SOFTLOCK) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&freemem_lock);
843e19887f64dde75055cf8842fc4db2171eff45johnlev data->softlockcnt++;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&freemem_lock);
843e19887f64dde75055cf8842fc4db2171eff45johnlev hat_flags |= HAT_LOAD_LOCK;
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else
843e19887f64dde75055cf8842fc4db2171eff45johnlev hat_flags |= HAT_LOAD;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (segmf_faultpage_debug > 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev uprintf("segmf_faultpage: addr %p domid %x mfn %lx prot %x\n",
843e19887f64dde75055cf8842fc4db2171eff45johnlev (void *)addr, data->domid, mfn, prot);
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_faultpage_debug--;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Ask the HAT to load a throwaway mapping to page zero, then
843e19887f64dde75055cf8842fc4db2171eff45johnlev * overwrite it with our foreign domain mapping. It gets removed
843e19887f64dde75055cf8842fc4db2171eff45johnlev * later via hat_unload()
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev hat_devload(hat, addr, MMU_PAGESIZE, (pfn_t)0,
843e19887f64dde75055cf8842fc4db2171eff45johnlev PROT_READ | HAT_UNORDERED_OK, hat_flags);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev pte = mmu_ptob((x86pte_t)mfn) | PT_VALID | PT_USER | PT_FOREIGN;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (prot & PROT_WRITE)
843e19887f64dde75055cf8842fc4db2171eff45johnlev pte |= PT_WRITABLE;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (HYPERVISOR_update_va_mapping_otherdomain((uintptr_t)addr, pte,
843e19887f64dde75055cf8842fc4db2171eff45johnlev UVMF_INVLPG | UVMF_ALL, data->domid) != 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev hat_flags = HAT_UNLOAD_UNMAP;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (type == F_SOFTLOCK) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev hat_flags |= HAT_UNLOAD_UNLOCK;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&freemem_lock);
843e19887f64dde75055cf8842fc4db2171eff45johnlev data->softlockcnt--;
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&freemem_lock);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev hat_unload(hat, addr, MMU_PAGESIZE, hat_flags);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (FC_MAKE_ERR(EFAULT));
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevseg_rw_to_prot(enum seg_rw rw)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (rw) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev case S_READ:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (PROT_READ);
843e19887f64dde75055cf8842fc4db2171eff45johnlev case S_WRITE:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (PROT_WRITE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev case S_EXEC:
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (PROT_EXEC);
843e19887f64dde75055cf8842fc4db2171eff45johnlev case S_OTHER:
843e19887f64dde75055cf8842fc4db2171eff45johnlev default:
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (PROT_READ | PROT_WRITE | PROT_EXEC);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_softunlock(struct hat *hat, struct seg *seg, caddr_t addr, size_t len)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct segmf_data *data = seg->s_data;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev hat_unlock(hat, addr, len);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&freemem_lock);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ASSERT(data->softlockcnt >= btopr(len));
843e19887f64dde75055cf8842fc4db2171eff45johnlev data->softlockcnt -= btopr(len);
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&freemem_lock);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (data->softlockcnt == 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct as *as = seg->s_as;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (AS_ISUNMAPWAIT(as)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&as->a_contents);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (AS_ISUNMAPWAIT(as)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev AS_CLRUNMAPWAIT(as);
843e19887f64dde75055cf8842fc4db2171eff45johnlev cv_broadcast(&as->a_cv);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&as->a_contents);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_fault_range(struct hat *hat, struct seg *seg, caddr_t addr, size_t len,
843e19887f64dde75055cf8842fc4db2171eff45johnlev enum fault_type type, enum seg_rw rw)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct segmf_data *data = seg->s_data;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int error = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev caddr_t a;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ((data->prot & seg_rw_to_prot(rw)) == 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (FC_PROT);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* loop over the address range handling each fault */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (a = addr; a < addr + len; a += PAGESIZE) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = segmf_faultpage(hat, seg, a, type, data->prot);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (error != 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (error != 0 && type == F_SOFTLOCK) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev size_t done = (size_t)(a - addr);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Undo what's been done so far.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (done > 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_softunlock(hat, seg, addr, done);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (error);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * We never demand-fault for seg_mf.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_fault(struct hat *hat, struct seg *seg, caddr_t addr, size_t len,
843e19887f64dde75055cf8842fc4db2171eff45johnlev enum fault_type type, enum seg_rw rw)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (FC_MAKE_ERR(EFAULT));
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_faulta(struct seg *seg, caddr_t addr)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_setprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EINVAL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_checkprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EINVAL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_kluster(struct seg *seg, caddr_t addr, ssize_t delta)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (-1);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_sync(struct seg *seg, caddr_t addr, size_t len, int attr, uint_t flags)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * XXPV Hmm. Should we say that mf mapping are "in core?"
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic size_t
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_incore(struct seg *seg, caddr_t addr, size_t len, char *vec)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev size_t v;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (v = 0, len = (len + PAGEOFFSET) & PAGEMASK; len;
843e19887f64dde75055cf8842fc4db2171eff45johnlev len -= PAGESIZE, v += PAGESIZE)
843e19887f64dde75055cf8842fc4db2171eff45johnlev *vec++ = 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (v);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_lockop(struct seg *seg, caddr_t addr,
843e19887f64dde75055cf8842fc4db2171eff45johnlev size_t len, int attr, int op, ulong_t *lockmap, size_t pos)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_getprot(struct seg *seg, caddr_t addr, size_t len, uint_t *protv)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct segmf_data *data = seg->s_data;
843e19887f64dde75055cf8842fc4db2171eff45johnlev pgcnt_t pgno = seg_page(seg, addr + len) - seg_page(seg, addr) + 1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (pgno != 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev do
843e19887f64dde75055cf8842fc4db2171eff45johnlev protv[--pgno] = data->prot;
843e19887f64dde75055cf8842fc4db2171eff45johnlev while (pgno != 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev ;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic u_offset_t
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_getoffset(struct seg *seg, caddr_t addr)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (addr - seg->s_base);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_gettype(struct seg *seg, caddr_t addr)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (MAP_SHARED);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED1*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_getvp(struct seg *seg, caddr_t addr, struct vnode **vpp)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct segmf_data *data = seg->s_data;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev *vpp = VTOCVP(data->vp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_advise(struct seg *seg, caddr_t addr, size_t len, uint_t behav)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_dump(struct seg *seg)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_pagelock(struct seg *seg, caddr_t addr, size_t len,
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct page ***ppp, enum lock_type type, enum seg_rw rw)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENOTSUP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_setpagesize(struct seg *seg, caddr_t addr, size_t len, uint_t szc)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (ENOTSUP);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_getmemid(struct seg *seg, caddr_t addr, memid_t *memid)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct segmf_data *data = seg->s_data;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev memid->val[0] = (uintptr_t)VTOCVP(data->vp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev memid->val[1] = (uintptr_t)seg_page(seg, addr);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic lgrp_mem_policy_info_t *
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_getpolicy(struct seg *seg, caddr_t addr)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic int
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_capable(struct seg *seg, segcapability_t capability)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Add a set of contiguous foreign MFNs to the segment. soft-locking them. The
843e19887f64dde75055cf8842fc4db2171eff45johnlev * pre-faulting is necessary due to live migration; in particular we must
843e19887f64dde75055cf8842fc4db2171eff45johnlev * return an error in response to IOCTL_PRIVCMD_MMAPBATCH rather than faulting
843e19887f64dde75055cf8842fc4db2171eff45johnlev * later on a bad MFN. Whilst this isn't necessary for the other MMAP
843e19887f64dde75055cf8842fc4db2171eff45johnlev * ioctl()s, we lock them too, as they should be transitory.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevint
843e19887f64dde75055cf8842fc4db2171eff45johnlevsegmf_add_mfns(struct seg *seg, caddr_t addr, mfn_t mfn,
843e19887f64dde75055cf8842fc4db2171eff45johnlev pgcnt_t pgcnt, domid_t domid)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev struct segmf_data *data = seg->s_data;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson pgcnt_t base;
843e19887f64dde75055cf8842fc4db2171eff45johnlev faultcode_t fc;
843e19887f64dde75055cf8842fc4db2171eff45johnlev pgcnt_t i;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int error = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (seg->s_ops != &segmf_ops)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EINVAL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Don't mess with dom0.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Only allow the domid to be set once for the segment.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * After that attempts to add mappings to this segment for
843e19887f64dde75055cf8842fc4db2171eff45johnlev * other domains explicitly fails.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (domid == 0 || domid == DOMID_SELF)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (EACCES);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_enter(&data->lock);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (data->domid == 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev data->domid = domid;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (data->domid != domid) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = EINVAL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev goto out;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev base = seg_page(seg, addr);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson for (i = 0; i < pgcnt; i++) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson data->map[base + i].t_type = SEGMF_MAP_MFN;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson data->map[base + i].u.m.m_mfn = mfn++;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev fc = segmf_fault_range(seg->s_as->a_hat, seg, addr,
843e19887f64dde75055cf8842fc4db2171eff45johnlev pgcnt * MMU_PAGESIZE, F_SOFTLOCK, S_OTHER);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (fc != 0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev error = fc_decode(fc);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson for (i = 0; i < pgcnt; i++) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson data->map[base + i].t_type = SEGMF_MAP_EMPTY;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevout:
843e19887f64dde75055cf8842fc4db2171eff45johnlev mutex_exit(&data->lock);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (error);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
7eea693d6b672899726e75993fddc4e95b52647fMark Johnsonint
7eea693d6b672899726e75993fddc4e95b52647fMark Johnsonsegmf_add_grefs(struct seg *seg, caddr_t addr, uint_t flags,
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson grant_ref_t *grefs, uint_t cnt, domid_t domid)
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson{
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson struct segmf_data *data;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson segmf_map_t *map;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson faultcode_t fc;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson uint_t idx;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson uint_t i;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson int e;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson if (seg->s_ops != &segmf_ops)
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson return (EINVAL);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson /*
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson * Don't mess with dom0.
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson *
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson * Only allow the domid to be set once for the segment.
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson * After that attempts to add mappings to this segment for
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson * other domains explicitly fails.
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson */
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson if (domid == 0 || domid == DOMID_SELF)
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson return (EACCES);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson data = seg->s_data;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson idx = seg_page(seg, addr);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson map = &data->map[idx];
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson e = 0;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson mutex_enter(&data->lock);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson if (data->domid == 0)
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson data->domid = domid;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson if (data->domid != domid) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson e = EINVAL;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson goto out;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson /* store away the grefs passed in then fault in the pages */
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson for (i = 0; i < cnt; i++) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson map[i].t_type = SEGMF_MAP_GREF;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson map[i].u.g.g_gref = grefs[i];
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson map[i].u.g.g_handle = 0;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson map[i].u.g.g_flags = 0;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson if (flags & SEGMF_GREF_WR) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson map[i].u.g.g_flags |= SEGMF_GFLAGS_WR;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson fc = segmf_fault_gref_range(seg, addr, cnt);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson if (fc != 0) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson e = fc_decode(fc);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson for (i = 0; i < cnt; i++) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson data->map[i].t_type = SEGMF_MAP_EMPTY;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnsonout:
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson mutex_exit(&data->lock);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson return (e);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson}
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnsonint
7eea693d6b672899726e75993fddc4e95b52647fMark Johnsonsegmf_release_grefs(struct seg *seg, caddr_t addr, uint_t cnt)
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson{
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson gnttab_unmap_grant_ref_t mapop[SEGMF_MAX_GREFS];
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson struct segmf_data *data;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson segmf_map_t *map;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson uint_t idx;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson long e;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson int i;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson int n;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson if (cnt > SEGMF_MAX_GREFS) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson return (-1);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson idx = seg_page(seg, addr);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson data = seg->s_data;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson map = &data->map[idx];
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson bzero(mapop, sizeof (gnttab_unmap_grant_ref_t) * cnt);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson /*
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson * for each entry which isn't empty and is currently mapped,
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson * set it up for an unmap then mark them empty.
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson */
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson n = 0;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson for (i = 0; i < cnt; i++) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson ASSERT(map[i].t_type != SEGMF_MAP_MFN);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson if ((map[i].t_type == SEGMF_MAP_GREF) &&
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson (map[i].u.g.g_flags & SEGMF_GFLAGS_MAPPED)) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson mapop[n].handle = map[i].u.g.g_handle;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson mapop[n].host_addr = map[i].u.g.g_ptep;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson mapop[n].dev_bus_addr = 0;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson n++;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson map[i].t_type = SEGMF_MAP_EMPTY;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson /* if there's nothing to unmap, just return */
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson if (n == 0) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson return (0);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson e = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &mapop, n);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson if (e != 0) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson return (-1);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson return (0);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson}
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnsonvoid
7eea693d6b672899726e75993fddc4e95b52647fMark Johnsonsegmf_add_gref_pte(struct seg *seg, caddr_t addr, uint64_t pte_ma)
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson{
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson struct segmf_data *data;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson uint_t idx;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson idx = seg_page(seg, addr);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson data = seg->s_data;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson data->map[idx].u.g.g_ptep = pte_ma;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson}
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnsonstatic int
7eea693d6b672899726e75993fddc4e95b52647fMark Johnsonsegmf_fault_gref_range(struct seg *seg, caddr_t addr, size_t cnt)
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson{
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson gnttab_map_grant_ref_t mapop[SEGMF_MAX_GREFS];
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson struct segmf_data *data;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson segmf_map_t *map;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson uint_t idx;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson int e;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson int i;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson if (cnt > SEGMF_MAX_GREFS) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson return (-1);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson data = seg->s_data;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson idx = seg_page(seg, addr);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson map = &data->map[idx];
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson bzero(mapop, sizeof (gnttab_map_grant_ref_t) * cnt);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson ASSERT(map->t_type == SEGMF_MAP_GREF);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson /*
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson * map in each page passed in into the user apps AS. We do this by
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson * passing the MA of the actual pte of the mapping to the hypervisor.
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson */
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson for (i = 0; i < cnt; i++) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson mapop[i].host_addr = map[i].u.g.g_ptep;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson mapop[i].dom = data->domid;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson mapop[i].ref = map[i].u.g.g_gref;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson mapop[i].flags = GNTMAP_host_map | GNTMAP_application_map |
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson GNTMAP_contains_pte;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson if (!(map[i].u.g.g_flags & SEGMF_GFLAGS_WR)) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson mapop[i].flags |= GNTMAP_readonly;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson e = xen_map_gref(GNTTABOP_map_grant_ref, mapop, cnt, B_TRUE);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson if ((e != 0) || (mapop[0].status != GNTST_okay)) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson return (FC_MAKE_ERR(EFAULT));
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson /* save handle for segmf_release_grefs() and mark it as mapped */
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson for (i = 0; i < cnt; i++) {
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson ASSERT(mapop[i].status == GNTST_okay);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson map[i].u.g.g_handle = mapop[i].handle;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson map[i].u.g.g_flags |= SEGMF_GFLAGS_MAPPED;
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson }
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson return (0);
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson}
7eea693d6b672899726e75993fddc4e95b52647fMark Johnson
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic struct seg_ops segmf_ops = {
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_dup,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_unmap,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_free,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_fault,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_faulta,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_setprot,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_checkprot,
843e19887f64dde75055cf8842fc4db2171eff45johnlev (int (*)())segmf_kluster,
843e19887f64dde75055cf8842fc4db2171eff45johnlev (size_t (*)(struct seg *))NULL, /* swapout */
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_sync,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_incore,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_lockop,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_getprot,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_getoffset,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_gettype,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_getvp,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_advise,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_dump,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_pagelock,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_setpagesize,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_getmemid,
843e19887f64dde75055cf8842fc4db2171eff45johnlev segmf_getpolicy,
9d12795f87b63c2e39e87bff369182edd34677d3Robert Mustacchi segmf_capable,
9d12795f87b63c2e39e87bff369182edd34677d3Robert Mustacchi seg_inherit_notsup
843e19887f64dde75055cf8842fc4db2171eff45johnlev};