xref: /illumos-gate/usr/src/uts/intel/io/vmm/seg_vmm.c (revision 7c8c0b82)
14beb21b1SPatrick Mooney /*
24beb21b1SPatrick Mooney  * This file and its contents are supplied under the terms of the
34beb21b1SPatrick Mooney  * Common Development and Distribution License ("CDDL"), version 1.0.
44beb21b1SPatrick Mooney  * You may only use this file in accordance with the terms of version
54beb21b1SPatrick Mooney  * 1.0 of the CDDL.
64beb21b1SPatrick Mooney  *
74beb21b1SPatrick Mooney  * A full copy of the text of the CDDL should have accompanied this
84beb21b1SPatrick Mooney  * source.  A copy of the CDDL is also available via the Internet at
94beb21b1SPatrick Mooney  * http://www.illumos.org/license/CDDL.
104beb21b1SPatrick Mooney  */
114beb21b1SPatrick Mooney 
124beb21b1SPatrick Mooney /*
134beb21b1SPatrick Mooney  * Copyright 2018 Joyent, Inc.
14b57f5d3eSPatrick Mooney  * Copyright 2021 Oxide Computer Company
154beb21b1SPatrick Mooney  */
164beb21b1SPatrick Mooney 
174beb21b1SPatrick Mooney /*
1804909c8cSJohn Levon  * segvmm - Virtual-Machine-Memory segment
194beb21b1SPatrick Mooney  *
204beb21b1SPatrick Mooney  * The vmm segment driver was designed for mapping regions of kernel memory
214beb21b1SPatrick Mooney  * allocated to an HVM instance into userspace for manipulation there.  It
224beb21b1SPatrick Mooney  * draws direct lineage from the umap segment driver, but meant for larger
234beb21b1SPatrick Mooney  * mappings with fewer restrictions.
2404909c8cSJohn Levon  *
2504909c8cSJohn Levon  * seg*k*vmm, in contrast, has mappings for every VMM into kas.  We use its
2604909c8cSJohn Levon  * mappings here only to find the relevant PFNs in segvmm_fault_in().
274beb21b1SPatrick Mooney  */
284beb21b1SPatrick Mooney 
294beb21b1SPatrick Mooney 
304beb21b1SPatrick Mooney #include <sys/types.h>
314beb21b1SPatrick Mooney #include <sys/param.h>
324beb21b1SPatrick Mooney #include <sys/errno.h>
334beb21b1SPatrick Mooney #include <sys/cred.h>
344beb21b1SPatrick Mooney #include <sys/kmem.h>
354beb21b1SPatrick Mooney #include <sys/lgrp.h>
364beb21b1SPatrick Mooney #include <sys/mman.h>
374beb21b1SPatrick Mooney 
384beb21b1SPatrick Mooney #include <vm/hat.h>
394beb21b1SPatrick Mooney #include <vm/hat_pte.h>
404beb21b1SPatrick Mooney #include <vm/htable.h>
414beb21b1SPatrick Mooney #include <vm/as.h>
424beb21b1SPatrick Mooney #include <vm/seg.h>
434beb21b1SPatrick Mooney #include <vm/seg_kmem.h>
44b57f5d3eSPatrick Mooney 
45b57f5d3eSPatrick Mooney #include <sys/seg_vmm.h>
46b57f5d3eSPatrick Mooney 
47b57f5d3eSPatrick Mooney typedef struct segvmm_data {
48b57f5d3eSPatrick Mooney 	krwlock_t	svmd_lock;
490153d828SPatrick Mooney 	vm_object_t	*svmd_vmo;
500153d828SPatrick Mooney 	vm_client_t	*svmd_vmc;
510153d828SPatrick Mooney 	uintptr_t	svmd_off;
52b57f5d3eSPatrick Mooney 	uchar_t		svmd_prot;
53b57f5d3eSPatrick Mooney 	size_t		svmd_softlockcnt;
54b57f5d3eSPatrick Mooney } segvmm_data_t;
554beb21b1SPatrick Mooney 
564beb21b1SPatrick Mooney 
574beb21b1SPatrick Mooney static int segvmm_dup(struct seg *, struct seg *);
584beb21b1SPatrick Mooney static int segvmm_unmap(struct seg *, caddr_t, size_t);
594beb21b1SPatrick Mooney static void segvmm_free(struct seg *);
604beb21b1SPatrick Mooney static faultcode_t segvmm_fault(struct hat *, struct seg *, caddr_t, size_t,
614beb21b1SPatrick Mooney     enum fault_type, enum seg_rw);
624beb21b1SPatrick Mooney static faultcode_t segvmm_faulta(struct seg *, caddr_t);
634beb21b1SPatrick Mooney static int segvmm_setprot(struct seg *, caddr_t, size_t, uint_t);
644beb21b1SPatrick Mooney static int segvmm_checkprot(struct seg *, caddr_t, size_t, uint_t);
654beb21b1SPatrick Mooney static int segvmm_sync(struct seg *, caddr_t, size_t, int, uint_t);
664beb21b1SPatrick Mooney static size_t segvmm_incore(struct seg *, caddr_t, size_t, char *);
674beb21b1SPatrick Mooney static int segvmm_lockop(struct seg *, caddr_t, size_t, int, int, ulong_t *,
684beb21b1SPatrick Mooney     size_t);
694beb21b1SPatrick Mooney static int segvmm_getprot(struct seg *, caddr_t, size_t, uint_t *);
704beb21b1SPatrick Mooney static u_offset_t segvmm_getoffset(struct seg *, caddr_t);
714beb21b1SPatrick Mooney static int segvmm_gettype(struct seg *, caddr_t);
724beb21b1SPatrick Mooney static int segvmm_getvp(struct seg *, caddr_t, struct vnode **);
734beb21b1SPatrick Mooney static int segvmm_advise(struct seg *, caddr_t, size_t, uint_t);
744beb21b1SPatrick Mooney static void segvmm_dump(struct seg *);
754beb21b1SPatrick Mooney static int segvmm_pagelock(struct seg *, caddr_t, size_t, struct page ***,
764beb21b1SPatrick Mooney     enum lock_type, enum seg_rw);
774beb21b1SPatrick Mooney static int segvmm_setpagesize(struct seg *, caddr_t, size_t, uint_t);
784beb21b1SPatrick Mooney static int segvmm_getmemid(struct seg *, caddr_t, memid_t *);
794beb21b1SPatrick Mooney static int segvmm_capable(struct seg *, segcapability_t);
804beb21b1SPatrick Mooney 
814beb21b1SPatrick Mooney static struct seg_ops segvmm_ops = {
824beb21b1SPatrick Mooney 	.dup		= segvmm_dup,
834beb21b1SPatrick Mooney 	.unmap		= segvmm_unmap,
844beb21b1SPatrick Mooney 	.free		= segvmm_free,
854beb21b1SPatrick Mooney 	.fault		= segvmm_fault,
864beb21b1SPatrick Mooney 	.faulta		= segvmm_faulta,
874beb21b1SPatrick Mooney 	.setprot	= segvmm_setprot,
884beb21b1SPatrick Mooney 	.checkprot	= segvmm_checkprot,
894beb21b1SPatrick Mooney 	.kluster	= NULL,
904beb21b1SPatrick Mooney 	.swapout	= NULL,
914beb21b1SPatrick Mooney 	.sync		= segvmm_sync,
924beb21b1SPatrick Mooney 	.incore		= segvmm_incore,
934beb21b1SPatrick Mooney 	.lockop		= segvmm_lockop,
944beb21b1SPatrick Mooney 	.getprot	= segvmm_getprot,
954beb21b1SPatrick Mooney 	.getoffset	= segvmm_getoffset,
964beb21b1SPatrick Mooney 	.gettype	= segvmm_gettype,
974beb21b1SPatrick Mooney 	.getvp		= segvmm_getvp,
984beb21b1SPatrick Mooney 	.advise		= segvmm_advise,
994beb21b1SPatrick Mooney 	.dump		= segvmm_dump,
1004beb21b1SPatrick Mooney 	.pagelock	= segvmm_pagelock,
1014beb21b1SPatrick Mooney 	.setpagesize	= segvmm_setpagesize,
1024beb21b1SPatrick Mooney 	.getmemid	= segvmm_getmemid,
1034beb21b1SPatrick Mooney 	.getpolicy	= NULL,
1044beb21b1SPatrick Mooney 	.capable	= segvmm_capable,
1054beb21b1SPatrick Mooney 	.inherit	= seg_inherit_notsup
1064beb21b1SPatrick Mooney };
1074beb21b1SPatrick Mooney 
1080153d828SPatrick Mooney /*
1090153d828SPatrick Mooney  * Unload a region from the HAT for A/D tracking.
1100153d828SPatrick Mooney  */
1110153d828SPatrick Mooney static void
segvmm_invalidate(void * arg,uintptr_t gpa,size_t sz)1120153d828SPatrick Mooney segvmm_invalidate(void *arg, uintptr_t gpa, size_t sz)
1130153d828SPatrick Mooney {
1140153d828SPatrick Mooney 	struct seg *seg = arg;
1150153d828SPatrick Mooney 	segvmm_data_t *svmd = seg->s_data;
1160153d828SPatrick Mooney 
1170153d828SPatrick Mooney 	/*
1180153d828SPatrick Mooney 	 * Invalidations are only necessary (and configured) for vmspace
1190153d828SPatrick Mooney 	 * mappings.  Direct vm_object mappings are not involved.
1200153d828SPatrick Mooney 	 */
1210153d828SPatrick Mooney 	ASSERT3P(svmd->svmd_vmo, ==, NULL);
1220153d828SPatrick Mooney 
1230153d828SPatrick Mooney 	/*
1240153d828SPatrick Mooney 	 * The region being invalidated may overlap with all, some, or none of
1250153d828SPatrick Mooney 	 * this segment.  We are only concerned about that overlap.
1260153d828SPatrick Mooney 	 */
1270153d828SPatrick Mooney 	const uintptr_t start = MAX(gpa, svmd->svmd_off);
1280153d828SPatrick Mooney 	const uintptr_t end = MIN(gpa + sz, svmd->svmd_off + seg->s_size);
1290153d828SPatrick Mooney 	if (start >= end) {
1300153d828SPatrick Mooney 		return;
1310153d828SPatrick Mooney 	}
1320153d828SPatrick Mooney 	ASSERT(start >= svmd->svmd_off && end <= svmd->svmd_off + seg->s_size);
1330153d828SPatrick Mooney 	ASSERT(start >= gpa && end <= gpa + sz);
1340153d828SPatrick Mooney 	const caddr_t unload_va = seg->s_base + (start - svmd->svmd_off);
1350153d828SPatrick Mooney 	const size_t unload_sz = (end - start);
1360153d828SPatrick Mooney 	ASSERT3U(unload_sz, <=, seg->s_size);
1370153d828SPatrick Mooney 
1380153d828SPatrick Mooney 	hat_unload(seg->s_as->a_hat, unload_va, unload_sz, HAT_UNLOAD);
1390153d828SPatrick Mooney }
1404beb21b1SPatrick Mooney 
1414beb21b1SPatrick Mooney /*
1420153d828SPatrick Mooney  * Create a VMM-memory-backed segment.
1434beb21b1SPatrick Mooney  */
1444beb21b1SPatrick Mooney int
segvmm_create(struct seg ** segpp,void * argsp)1454beb21b1SPatrick Mooney segvmm_create(struct seg **segpp, void *argsp)
1464beb21b1SPatrick Mooney {
1474beb21b1SPatrick Mooney 	struct seg *seg = *segpp;
1484beb21b1SPatrick Mooney 	segvmm_crargs_t *cra = argsp;
1494beb21b1SPatrick Mooney 	segvmm_data_t *data;
1504beb21b1SPatrick Mooney 
1510153d828SPatrick Mooney 	VERIFY((cra->vmo == NULL && cra->vmc != NULL) ||
1520153d828SPatrick Mooney 	    (cra->vmo != NULL && cra->vmc == NULL));
1530153d828SPatrick Mooney 	VERIFY(cra->prot & PROT_USER);
1540153d828SPatrick Mooney 	VERIFY0(cra->offset & PAGEOFFSET);
1550153d828SPatrick Mooney 
1564beb21b1SPatrick Mooney 	data = kmem_zalloc(sizeof (*data), KM_SLEEP);
1574beb21b1SPatrick Mooney 	rw_init(&data->svmd_lock, NULL, RW_DEFAULT, NULL);
1580153d828SPatrick Mooney 	data->svmd_off = cra->offset;
1590153d828SPatrick Mooney 	data->svmd_prot = cra->prot & ~PROT_USER;
1604beb21b1SPatrick Mooney 
1614beb21b1SPatrick Mooney 	seg->s_ops = &segvmm_ops;
1624beb21b1SPatrick Mooney 	seg->s_data = data;
1630153d828SPatrick Mooney 
1640153d828SPatrick Mooney 	if (cra->vmo != NULL) {
1650153d828SPatrick Mooney 		data->svmd_vmo = cra->vmo;
1660153d828SPatrick Mooney 		/* Grab a hold on the VM object for the lifetime of segment */
1670153d828SPatrick Mooney 		vm_object_reference(data->svmd_vmo);
1680153d828SPatrick Mooney 	} else {
1690153d828SPatrick Mooney 		int err;
1700153d828SPatrick Mooney 
1710153d828SPatrick Mooney 		data->svmd_vmc = cra->vmc;
1720153d828SPatrick Mooney 		err = vmc_set_inval_cb(data->svmd_vmc, segvmm_invalidate, seg);
1730153d828SPatrick Mooney 		if (err != 0) {
1740153d828SPatrick Mooney 			seg->s_ops = NULL;
1750153d828SPatrick Mooney 			seg->s_data = NULL;
1760153d828SPatrick Mooney 			kmem_free(data, sizeof (*data));
1770153d828SPatrick Mooney 			return (err);
1780153d828SPatrick Mooney 		}
1790153d828SPatrick Mooney 	}
1804beb21b1SPatrick Mooney 	return (0);
1814beb21b1SPatrick Mooney }
1824beb21b1SPatrick Mooney 
1834beb21b1SPatrick Mooney static int
segvmm_dup(struct seg * seg,struct seg * newseg)1844beb21b1SPatrick Mooney segvmm_dup(struct seg *seg, struct seg *newseg)
1854beb21b1SPatrick Mooney {
1864beb21b1SPatrick Mooney 	segvmm_data_t *svmd = seg->s_data;
1874beb21b1SPatrick Mooney 	segvmm_data_t *newsvmd;
1884beb21b1SPatrick Mooney 
1894beb21b1SPatrick Mooney 	ASSERT(seg->s_as && AS_WRITE_HELD(seg->s_as));
1904beb21b1SPatrick Mooney 
1914beb21b1SPatrick Mooney 	newsvmd = kmem_zalloc(sizeof (segvmm_data_t), KM_SLEEP);
1924beb21b1SPatrick Mooney 	rw_init(&newsvmd->svmd_lock, NULL, RW_DEFAULT, NULL);
1930153d828SPatrick Mooney 	newsvmd->svmd_off = svmd->svmd_off;
1944beb21b1SPatrick Mooney 	newsvmd->svmd_prot = svmd->svmd_prot;
1954beb21b1SPatrick Mooney 
1964beb21b1SPatrick Mooney 	newseg->s_ops = seg->s_ops;
1974beb21b1SPatrick Mooney 	newseg->s_data = newsvmd;
1980153d828SPatrick Mooney 
1990153d828SPatrick Mooney 	if (svmd->svmd_vmo != NULL) {
2000153d828SPatrick Mooney 		/* Grab another hold for the duplicate segment */
2010153d828SPatrick Mooney 		vm_object_reference(svmd->svmd_vmo);
2020153d828SPatrick Mooney 		newsvmd->svmd_vmo = svmd->svmd_vmo;
2030153d828SPatrick Mooney 	} else {
2040153d828SPatrick Mooney 		int err;
2050153d828SPatrick Mooney 
2060153d828SPatrick Mooney 		newsvmd->svmd_vmc = vmc_clone(svmd->svmd_vmc);
2070153d828SPatrick Mooney 		/*
2080153d828SPatrick Mooney 		 * The cloned client does not inherit the invalidation
2090153d828SPatrick Mooney 		 * configuration, so attempt to set it here for the new segment.
2100153d828SPatrick Mooney 		 */
2110153d828SPatrick Mooney 		err = vmc_set_inval_cb(newsvmd->svmd_vmc, segvmm_invalidate,
2120153d828SPatrick Mooney 		    newseg);
2130153d828SPatrick Mooney 		if (err != 0) {
2140153d828SPatrick Mooney 			newseg->s_ops = NULL;
2150153d828SPatrick Mooney 			newseg->s_data = NULL;
2160153d828SPatrick Mooney 			kmem_free(newsvmd, sizeof (*newsvmd));
2170153d828SPatrick Mooney 			return (err);
2180153d828SPatrick Mooney 		}
2190153d828SPatrick Mooney 	}
2200153d828SPatrick Mooney 
2214beb21b1SPatrick Mooney 	return (0);
2224beb21b1SPatrick Mooney }
2234beb21b1SPatrick Mooney 
2244beb21b1SPatrick Mooney static int
segvmm_unmap(struct seg * seg,caddr_t addr,size_t len)2254beb21b1SPatrick Mooney segvmm_unmap(struct seg *seg, caddr_t addr, size_t len)
2264beb21b1SPatrick Mooney {
2274beb21b1SPatrick Mooney 	segvmm_data_t *svmd = seg->s_data;
2284beb21b1SPatrick Mooney 
2294beb21b1SPatrick Mooney 	ASSERT(seg->s_as && AS_WRITE_HELD(seg->s_as));
2304beb21b1SPatrick Mooney 
2314beb21b1SPatrick Mooney 	/* Only allow unmap of entire segment */
2324beb21b1SPatrick Mooney 	if (addr != seg->s_base || len != seg->s_size) {
2334beb21b1SPatrick Mooney 		return (EINVAL);
2344beb21b1SPatrick Mooney 	}
2354beb21b1SPatrick Mooney 	if (svmd->svmd_softlockcnt != 0) {
2364beb21b1SPatrick Mooney 		return (EAGAIN);
2374beb21b1SPatrick Mooney 	}
2384beb21b1SPatrick Mooney 
2394beb21b1SPatrick Mooney 	/* Unconditionally unload the entire segment range.  */
2404beb21b1SPatrick Mooney 	hat_unload(seg->s_as->a_hat, addr, len, HAT_UNLOAD_UNMAP);
2414beb21b1SPatrick Mooney 
2424beb21b1SPatrick Mooney 	seg_free(seg);
2434beb21b1SPatrick Mooney 	return (0);
2444beb21b1SPatrick Mooney }
2454beb21b1SPatrick Mooney 
2464beb21b1SPatrick Mooney static void
segvmm_free(struct seg * seg)2474beb21b1SPatrick Mooney segvmm_free(struct seg *seg)
2484beb21b1SPatrick Mooney {
2490153d828SPatrick Mooney 	segvmm_data_t *svmd = seg->s_data;
2504beb21b1SPatrick Mooney 
2510153d828SPatrick Mooney 	ASSERT(svmd != NULL);
2524beb21b1SPatrick Mooney 
2530153d828SPatrick Mooney 	if (svmd->svmd_vmo != NULL) {
2540153d828SPatrick Mooney 		/* Release the VM object hold this segment possessed */
2550153d828SPatrick Mooney 		vm_object_release(svmd->svmd_vmo);
2560153d828SPatrick Mooney 		svmd->svmd_vmo = NULL;
2570153d828SPatrick Mooney 	} else {
2580153d828SPatrick Mooney 		vmc_destroy(svmd->svmd_vmc);
2590153d828SPatrick Mooney 		svmd->svmd_vmc = NULL;
2600153d828SPatrick Mooney 	}
2610153d828SPatrick Mooney 	rw_destroy(&svmd->svmd_lock);
2620153d828SPatrick Mooney 	VERIFY(svmd->svmd_softlockcnt == 0);
2630153d828SPatrick Mooney 	kmem_free(svmd, sizeof (*svmd));
2644beb21b1SPatrick Mooney 	seg->s_data = NULL;
2654beb21b1SPatrick Mooney }
2664beb21b1SPatrick Mooney 
2674beb21b1SPatrick Mooney static int
segvmm_fault_obj(struct hat * hat,struct seg * seg,uintptr_t va,size_t len)2680153d828SPatrick Mooney segvmm_fault_obj(struct hat *hat, struct seg *seg, uintptr_t va, size_t len)
2694beb21b1SPatrick Mooney {
2704beb21b1SPatrick Mooney 	segvmm_data_t *svmd = seg->s_data;
2714beb21b1SPatrick Mooney 	const uintptr_t end = va + len;
2720153d828SPatrick Mooney 	const int prot = svmd->svmd_prot;
2730153d828SPatrick Mooney 	const int uprot = prot | PROT_USER;
2740153d828SPatrick Mooney 	vm_object_t *vmo = svmd->svmd_vmo;
2750153d828SPatrick Mooney 
2760153d828SPatrick Mooney 	ASSERT(vmo != NULL);
2774beb21b1SPatrick Mooney 
2784beb21b1SPatrick Mooney 	va &= PAGEMASK;
2790153d828SPatrick Mooney 	uintptr_t off = va - (uintptr_t)seg->s_base + svmd->svmd_off;
2804beb21b1SPatrick Mooney 	do {
2814beb21b1SPatrick Mooney 		pfn_t pfn;
2824beb21b1SPatrick Mooney 
2830153d828SPatrick Mooney 		pfn = vm_object_pfn(vmo, off);
2844beb21b1SPatrick Mooney 		if (pfn == PFN_INVALID) {
2850153d828SPatrick Mooney 			return (FC_NOMAP);
2860153d828SPatrick Mooney 		}
2870153d828SPatrick Mooney 
2880153d828SPatrick Mooney 		/* Ignore any large-page possibilities for now */
2890153d828SPatrick Mooney 		hat_devload(hat, (caddr_t)va, PAGESIZE, pfn, uprot, HAT_LOAD);
2900153d828SPatrick Mooney 		va += PAGESIZE;
2910153d828SPatrick Mooney 		off += PAGESIZE;
2920153d828SPatrick Mooney 	} while (va < end);
2930153d828SPatrick Mooney 
2940153d828SPatrick Mooney 	return (0);
2950153d828SPatrick Mooney }
2960153d828SPatrick Mooney 
2970153d828SPatrick Mooney static int
segvmm_fault_space(struct hat * hat,struct seg * seg,uintptr_t va,size_t len)2980153d828SPatrick Mooney segvmm_fault_space(struct hat *hat, struct seg *seg, uintptr_t va, size_t len)
2990153d828SPatrick Mooney {
3000153d828SPatrick Mooney 	segvmm_data_t *svmd = seg->s_data;
3010153d828SPatrick Mooney 	const uintptr_t end = va + len;
3020153d828SPatrick Mooney 	const int prot = svmd->svmd_prot;
3030153d828SPatrick Mooney 	const int uprot = prot | PROT_USER;
3040153d828SPatrick Mooney 	vm_client_t *vmc = svmd->svmd_vmc;
3050153d828SPatrick Mooney 
3060153d828SPatrick Mooney 	ASSERT(vmc != NULL);
3070153d828SPatrick Mooney 
3080153d828SPatrick Mooney 	va &= PAGEMASK;
3090153d828SPatrick Mooney 	uintptr_t off = va - (uintptr_t)seg->s_base + svmd->svmd_off;
3100153d828SPatrick Mooney 
3110153d828SPatrick Mooney 	do {
3120153d828SPatrick Mooney 		vm_page_t *vmp;
3130153d828SPatrick Mooney 		pfn_t pfn;
3140153d828SPatrick Mooney 
3150153d828SPatrick Mooney 		vmp = vmc_hold(vmc, off, prot);
3160153d828SPatrick Mooney 		if (vmp == NULL) {
3170153d828SPatrick Mooney 			return (FC_NOMAP);
3184beb21b1SPatrick Mooney 		}
3194beb21b1SPatrick Mooney 
3200153d828SPatrick Mooney 		pfn = vmp_get_pfn(vmp);
3210153d828SPatrick Mooney 		ASSERT3U(pfn, !=, PFN_INVALID);
3220153d828SPatrick Mooney 
323b57f5d3eSPatrick Mooney 		/* Ignore any large-page possibilities for now */
3240153d828SPatrick Mooney 		hat_devload(hat, (caddr_t)va, PAGESIZE, pfn, uprot, HAT_LOAD);
3250153d828SPatrick Mooney 
3260153d828SPatrick Mooney 		if (vmp_release(vmp)) {
3270153d828SPatrick Mooney 			/*
3280153d828SPatrick Mooney 			 * Region was unmapped from vmspace while we were
3290153d828SPatrick Mooney 			 * loading it into this AS.  Communicate it as if it
3300153d828SPatrick Mooney 			 * were a fault.
3310153d828SPatrick Mooney 			 */
3320153d828SPatrick Mooney 			hat_unload(hat, (caddr_t)va, PAGESIZE, HAT_UNLOAD);
3330153d828SPatrick Mooney 			return (FC_NOMAP);
3340153d828SPatrick Mooney 		}
3350153d828SPatrick Mooney 
336b57f5d3eSPatrick Mooney 		va += PAGESIZE;
337b57f5d3eSPatrick Mooney 		off += PAGESIZE;
3384beb21b1SPatrick Mooney 	} while (va < end);
3394beb21b1SPatrick Mooney 
3404beb21b1SPatrick Mooney 	return (0);
3414beb21b1SPatrick Mooney }
3424beb21b1SPatrick Mooney 
3434beb21b1SPatrick Mooney /* ARGSUSED */
3444beb21b1SPatrick Mooney static faultcode_t
segvmm_fault(struct hat * hat,struct seg * seg,caddr_t addr,size_t len,enum fault_type type,enum seg_rw rw)3454beb21b1SPatrick Mooney segvmm_fault(struct hat *hat, struct seg *seg, caddr_t addr, size_t len,
3460153d828SPatrick Mooney     enum fault_type type, enum seg_rw rw)
3474beb21b1SPatrick Mooney {
3484beb21b1SPatrick Mooney 	segvmm_data_t *svmd = seg->s_data;
3494beb21b1SPatrick Mooney 	int err = 0;
3504beb21b1SPatrick Mooney 
3514beb21b1SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
3524beb21b1SPatrick Mooney 
3534beb21b1SPatrick Mooney 	if (type == F_PROT) {
3544beb21b1SPatrick Mooney 		/*
3554beb21b1SPatrick Mooney 		 * Since protection on the segment is fixed, there is nothing
3564beb21b1SPatrick Mooney 		 * to do but report an error for protection faults.
3574beb21b1SPatrick Mooney 		 */
3584beb21b1SPatrick Mooney 		return (FC_PROT);
3594beb21b1SPatrick Mooney 	} else if (type == F_SOFTUNLOCK) {
3604beb21b1SPatrick Mooney 		size_t plen = btop(len);
3614beb21b1SPatrick Mooney 
3624beb21b1SPatrick Mooney 		rw_enter(&svmd->svmd_lock, RW_WRITER);
3634beb21b1SPatrick Mooney 		VERIFY(svmd->svmd_softlockcnt >= plen);
3644beb21b1SPatrick Mooney 		svmd->svmd_softlockcnt -= plen;
3654beb21b1SPatrick Mooney 		rw_exit(&svmd->svmd_lock);
3664beb21b1SPatrick Mooney 		return (0);
3674beb21b1SPatrick Mooney 	}
3684beb21b1SPatrick Mooney 
3694beb21b1SPatrick Mooney 	VERIFY(type == F_INVAL || type == F_SOFTLOCK);
3704beb21b1SPatrick Mooney 	rw_enter(&svmd->svmd_lock, RW_WRITER);
3714beb21b1SPatrick Mooney 
3720153d828SPatrick Mooney 	if (svmd->svmd_vmo != NULL) {
3730153d828SPatrick Mooney 		err = segvmm_fault_obj(hat, seg, (uintptr_t)addr, len);
3740153d828SPatrick Mooney 	} else {
3750153d828SPatrick Mooney 		err = segvmm_fault_space(hat, seg, (uintptr_t)addr, len);
3760153d828SPatrick Mooney 	}
3774beb21b1SPatrick Mooney 	if (type == F_SOFTLOCK && err == 0) {
3784beb21b1SPatrick Mooney 		size_t nval = svmd->svmd_softlockcnt + btop(len);
3794beb21b1SPatrick Mooney 
3804beb21b1SPatrick Mooney 		if (svmd->svmd_softlockcnt >= nval) {
3814beb21b1SPatrick Mooney 			rw_exit(&svmd->svmd_lock);
3824beb21b1SPatrick Mooney 			return (FC_MAKE_ERR(EOVERFLOW));
3834beb21b1SPatrick Mooney 		}
3844beb21b1SPatrick Mooney 		svmd->svmd_softlockcnt = nval;
3854beb21b1SPatrick Mooney 	}
3864beb21b1SPatrick Mooney 
3874beb21b1SPatrick Mooney 	rw_exit(&svmd->svmd_lock);
3884beb21b1SPatrick Mooney 	return (err);
3894beb21b1SPatrick Mooney }
3904beb21b1SPatrick Mooney 
3914beb21b1SPatrick Mooney /* ARGSUSED */
3924beb21b1SPatrick Mooney static faultcode_t
segvmm_faulta(struct seg * seg,caddr_t addr)3934beb21b1SPatrick Mooney segvmm_faulta(struct seg *seg, caddr_t addr)
3944beb21b1SPatrick Mooney {
3954beb21b1SPatrick Mooney 	/* Do nothing since asynch pagefault should not load translation. */
3964beb21b1SPatrick Mooney 	return (0);
3974beb21b1SPatrick Mooney }
3984beb21b1SPatrick Mooney 
3994beb21b1SPatrick Mooney /* ARGSUSED */
4004beb21b1SPatrick Mooney static int
segvmm_setprot(struct seg * seg,caddr_t addr,size_t len,uint_t prot)4014beb21b1SPatrick Mooney segvmm_setprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot)
4024beb21b1SPatrick Mooney {
4034beb21b1SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
4044beb21b1SPatrick Mooney 
4054beb21b1SPatrick Mooney 	/* The seg_vmm driver does not yet allow protection to be changed. */
4064beb21b1SPatrick Mooney 	return (EACCES);
4074beb21b1SPatrick Mooney }
4084beb21b1SPatrick Mooney 
4094beb21b1SPatrick Mooney /* ARGSUSED */
4104beb21b1SPatrick Mooney static int
segvmm_checkprot(struct seg * seg,caddr_t addr,size_t len,uint_t prot)4114beb21b1SPatrick Mooney segvmm_checkprot(struct seg *seg, caddr_t addr, size_t len, uint_t prot)
4124beb21b1SPatrick Mooney {
4134beb21b1SPatrick Mooney 	segvmm_data_t *svmd = seg->s_data;
4144beb21b1SPatrick Mooney 	int error = 0;
4154beb21b1SPatrick Mooney 
4164beb21b1SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
4174beb21b1SPatrick Mooney 
4184beb21b1SPatrick Mooney 	rw_enter(&svmd->svmd_lock, RW_READER);
4194beb21b1SPatrick Mooney 	if ((svmd->svmd_prot & prot) != prot) {
4204beb21b1SPatrick Mooney 		error = EACCES;
4214beb21b1SPatrick Mooney 	}
4224beb21b1SPatrick Mooney 	rw_exit(&svmd->svmd_lock);
4234beb21b1SPatrick Mooney 	return (error);
4244beb21b1SPatrick Mooney }
4254beb21b1SPatrick Mooney 
4264beb21b1SPatrick Mooney /* ARGSUSED */
4274beb21b1SPatrick Mooney static int
segvmm_sync(struct seg * seg,caddr_t addr,size_t len,int attr,uint_t flags)4284beb21b1SPatrick Mooney segvmm_sync(struct seg *seg, caddr_t addr, size_t len, int attr, uint_t flags)
4294beb21b1SPatrick Mooney {
4304beb21b1SPatrick Mooney 	/* Always succeed since there are no backing store to sync */
4314beb21b1SPatrick Mooney 	return (0);
4324beb21b1SPatrick Mooney }
4334beb21b1SPatrick Mooney 
4344beb21b1SPatrick Mooney /* ARGSUSED */
4354beb21b1SPatrick Mooney static size_t
segvmm_incore(struct seg * seg,caddr_t addr,size_t len,char * vec)4364beb21b1SPatrick Mooney segvmm_incore(struct seg *seg, caddr_t addr, size_t len, char *vec)
4374beb21b1SPatrick Mooney {
4384beb21b1SPatrick Mooney 	size_t sz = 0;
4394beb21b1SPatrick Mooney 
4404beb21b1SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
4414beb21b1SPatrick Mooney 
4424beb21b1SPatrick Mooney 	len = (len + PAGEOFFSET) & PAGEMASK;
4434beb21b1SPatrick Mooney 	while (len > 0) {
4444beb21b1SPatrick Mooney 		*vec = 1;
4454beb21b1SPatrick Mooney 		sz += PAGESIZE;
4464beb21b1SPatrick Mooney 		vec++;
4474beb21b1SPatrick Mooney 		len -= PAGESIZE;
4484beb21b1SPatrick Mooney 	}
4494beb21b1SPatrick Mooney 	return (sz);
4504beb21b1SPatrick Mooney }
4514beb21b1SPatrick Mooney 
4524beb21b1SPatrick Mooney /* ARGSUSED */
4534beb21b1SPatrick Mooney static int
segvmm_lockop(struct seg * seg,caddr_t addr,size_t len,int attr,int op,ulong_t * lockmap,size_t pos)4544beb21b1SPatrick Mooney segvmm_lockop(struct seg *seg, caddr_t addr, size_t len, int attr, int op,
4554beb21b1SPatrick Mooney     ulong_t *lockmap, size_t pos)
4564beb21b1SPatrick Mooney {
4574beb21b1SPatrick Mooney 	/* Report success since kernel pages are always in memory. */
4584beb21b1SPatrick Mooney 	return (0);
4594beb21b1SPatrick Mooney }
4604beb21b1SPatrick Mooney 
4614beb21b1SPatrick Mooney static int
segvmm_getprot(struct seg * seg,caddr_t addr,size_t len,uint_t * protv)4624beb21b1SPatrick Mooney segvmm_getprot(struct seg *seg, caddr_t addr, size_t len, uint_t *protv)
4634beb21b1SPatrick Mooney {
4644beb21b1SPatrick Mooney 	segvmm_data_t *svmd = seg->s_data;
4654beb21b1SPatrick Mooney 	size_t pgno;
4664beb21b1SPatrick Mooney 	uint_t prot;
4674beb21b1SPatrick Mooney 
4684beb21b1SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
4694beb21b1SPatrick Mooney 
4704beb21b1SPatrick Mooney 	rw_enter(&svmd->svmd_lock, RW_READER);
4714beb21b1SPatrick Mooney 	prot = svmd->svmd_prot;
4724beb21b1SPatrick Mooney 	rw_exit(&svmd->svmd_lock);
4734beb21b1SPatrick Mooney 
4744beb21b1SPatrick Mooney 	/*
4754beb21b1SPatrick Mooney 	 * Reporting protection is simple since it is not tracked per-page.
4764beb21b1SPatrick Mooney 	 */
4774beb21b1SPatrick Mooney 	pgno = seg_page(seg, addr + len) - seg_page(seg, addr) + 1;
4784beb21b1SPatrick Mooney 	while (pgno > 0) {
4794beb21b1SPatrick Mooney 		protv[--pgno] = prot;
4804beb21b1SPatrick Mooney 	}
4814beb21b1SPatrick Mooney 	return (0);
4824beb21b1SPatrick Mooney }
4834beb21b1SPatrick Mooney 
4844beb21b1SPatrick Mooney /* ARGSUSED */
4854beb21b1SPatrick Mooney static u_offset_t
segvmm_getoffset(struct seg * seg,caddr_t addr)4864beb21b1SPatrick Mooney segvmm_getoffset(struct seg *seg, caddr_t addr)
4874beb21b1SPatrick Mooney {
4884beb21b1SPatrick Mooney 	/*
4894beb21b1SPatrick Mooney 	 * To avoid leaking information about the layout of the kernel address
4904beb21b1SPatrick Mooney 	 * space, always report '0' as the offset.
4914beb21b1SPatrick Mooney 	 */
4924beb21b1SPatrick Mooney 	return (0);
4934beb21b1SPatrick Mooney }
4944beb21b1SPatrick Mooney 
4954beb21b1SPatrick Mooney /* ARGSUSED */
4964beb21b1SPatrick Mooney static int
segvmm_gettype(struct seg * seg,caddr_t addr)4974beb21b1SPatrick Mooney segvmm_gettype(struct seg *seg, caddr_t addr)
4984beb21b1SPatrick Mooney {
4994beb21b1SPatrick Mooney 	/*
500b57f5d3eSPatrick Mooney 	 * Since already-existing vmm reservoir pages are being mapped into
501b57f5d3eSPatrick Mooney 	 * userspace, always report the segment type as shared.
5024beb21b1SPatrick Mooney 	 */
5034beb21b1SPatrick Mooney 	return (MAP_SHARED);
5044beb21b1SPatrick Mooney }
5054beb21b1SPatrick Mooney 
5064beb21b1SPatrick Mooney /* ARGSUSED */
5074beb21b1SPatrick Mooney static int
segvmm_getvp(struct seg * seg,caddr_t addr,struct vnode ** vpp)5084beb21b1SPatrick Mooney segvmm_getvp(struct seg *seg, caddr_t addr, struct vnode **vpp)
5094beb21b1SPatrick Mooney {
5104beb21b1SPatrick Mooney 	ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as));
5114beb21b1SPatrick Mooney 
5124beb21b1SPatrick Mooney 	*vpp = NULL;
5134beb21b1SPatrick Mooney 	return (0);
5144beb21b1SPatrick Mooney }
5154beb21b1SPatrick Mooney 
5164beb21b1SPatrick Mooney /* ARGSUSED */
5174beb21b1SPatrick Mooney static int
segvmm_advise(struct seg * seg,caddr_t addr,size_t len,uint_t behav)5184beb21b1SPatrick Mooney segvmm_advise(struct seg *seg, caddr_t addr, size_t len, uint_t behav)
5194beb21b1SPatrick Mooney {
5204beb21b1SPatrick Mooney 	if (behav == MADV_PURGE) {
5214beb21b1SPatrick Mooney 		/* Purge does not make sense for this mapping */
5224beb21b1SPatrick Mooney 		return (EINVAL);
5234beb21b1SPatrick Mooney 	}
5244beb21b1SPatrick Mooney 	/* Indicate success for everything else. */
5254beb21b1SPatrick Mooney 	return (0);
5264beb21b1SPatrick Mooney }
5274beb21b1SPatrick Mooney 
5284beb21b1SPatrick Mooney /* ARGSUSED */
5294beb21b1SPatrick Mooney static void
segvmm_dump(struct seg * seg)5304beb21b1SPatrick Mooney segvmm_dump(struct seg *seg)
5314beb21b1SPatrick Mooney {
5324beb21b1SPatrick Mooney 	/*
5334beb21b1SPatrick Mooney 	 * Since this is a mapping to share kernel data with userspace, nothing
5344beb21b1SPatrick Mooney 	 * additional should be dumped.
5354beb21b1SPatrick Mooney 	 */
5364beb21b1SPatrick Mooney }
5374beb21b1SPatrick Mooney 
5384beb21b1SPatrick Mooney /* ARGSUSED */
5394beb21b1SPatrick Mooney static int
segvmm_pagelock(struct seg * seg,caddr_t addr,size_t len,struct page *** ppp,enum lock_type type,enum seg_rw rw)5404beb21b1SPatrick Mooney segvmm_pagelock(struct seg *seg, caddr_t addr, size_t len, struct page ***ppp,
5414beb21b1SPatrick Mooney     enum lock_type type, enum seg_rw rw)
5424beb21b1SPatrick Mooney {
5434beb21b1SPatrick Mooney 	return (ENOTSUP);
5444beb21b1SPatrick Mooney }
5454beb21b1SPatrick Mooney 
5464beb21b1SPatrick Mooney /* ARGSUSED */
5474beb21b1SPatrick Mooney static int
segvmm_setpagesize(struct seg * seg,caddr_t addr,size_t len,uint_t szc)5484beb21b1SPatrick Mooney segvmm_setpagesize(struct seg *seg, caddr_t addr, size_t len, uint_t szc)
5494beb21b1SPatrick Mooney {
5504beb21b1SPatrick Mooney 	return (ENOTSUP);
5514beb21b1SPatrick Mooney }
5524beb21b1SPatrick Mooney 
5534beb21b1SPatrick Mooney static int
segvmm_getmemid(struct seg * seg,caddr_t addr,memid_t * memidp)5544beb21b1SPatrick Mooney segvmm_getmemid(struct seg *seg, caddr_t addr, memid_t *memidp)
5554beb21b1SPatrick Mooney {
5564beb21b1SPatrick Mooney 	segvmm_data_t *svmd = seg->s_data;
5574beb21b1SPatrick Mooney 
5580153d828SPatrick Mooney 	memidp->val[0] = (uintptr_t)svmd->svmd_vmo;
5590153d828SPatrick Mooney 	memidp->val[1] = (uintptr_t)(addr - seg->s_base) + svmd->svmd_off;
5604beb21b1SPatrick Mooney 	return (0);
5614beb21b1SPatrick Mooney }
5624beb21b1SPatrick Mooney 
5634beb21b1SPatrick Mooney /* ARGSUSED */
5644beb21b1SPatrick Mooney static int
segvmm_capable(struct seg * seg,segcapability_t capability)5654beb21b1SPatrick Mooney segvmm_capable(struct seg *seg, segcapability_t capability)
5664beb21b1SPatrick Mooney {
5674beb21b1SPatrick Mooney 	/* no special capablities */
5684beb21b1SPatrick Mooney 	return (0);
5694beb21b1SPatrick Mooney }
570