xref: /onnv-gate/usr/src/uts/sun4v/vm/mach_vm_dep.c (revision 3177:6d48ee59c4fc)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51859Sha137994  * Common Development and Distribution License (the "License").
61859Sha137994  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
221859Sha137994  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
270Sstevel@tonic-gate /*	All Rights Reserved   */
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
310Sstevel@tonic-gate  * under license from the Regents of the University of California.
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
350Sstevel@tonic-gate 
360Sstevel@tonic-gate /*
370Sstevel@tonic-gate  * UNIX machine dependent virtual memory support.
380Sstevel@tonic-gate  */
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #include <sys/vm.h>
410Sstevel@tonic-gate #include <sys/exec.h>
420Sstevel@tonic-gate #include <sys/cmn_err.h>
430Sstevel@tonic-gate #include <sys/cpu_module.h>
440Sstevel@tonic-gate #include <sys/cpu.h>
450Sstevel@tonic-gate #include <sys/elf_SPARC.h>
460Sstevel@tonic-gate #include <sys/archsystm.h>
470Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
480Sstevel@tonic-gate #include <sys/memnode.h>
490Sstevel@tonic-gate #include <sys/mem_cage.h>
500Sstevel@tonic-gate #include <vm/vm_dep.h>
510Sstevel@tonic-gate #include <sys/error.h>
520Sstevel@tonic-gate #include <sys/machsystm.h>
530Sstevel@tonic-gate #include <vm/seg_kmem.h>
54*3177Sdp78419 #include <sys/stack.h>
55*3177Sdp78419 #include <sys/atomic.h>
560Sstevel@tonic-gate 
570Sstevel@tonic-gate uint_t page_colors = 0;
580Sstevel@tonic-gate uint_t page_colors_mask = 0;
590Sstevel@tonic-gate uint_t page_coloring_shift = 0;
600Sstevel@tonic-gate int consistent_coloring;
610Sstevel@tonic-gate 
620Sstevel@tonic-gate uint_t mmu_page_sizes = MMU_PAGE_SIZES;
630Sstevel@tonic-gate uint_t max_mmu_page_sizes = MMU_PAGE_SIZES;
640Sstevel@tonic-gate uint_t mmu_hashcnt = MAX_HASHCNT;
650Sstevel@tonic-gate uint_t max_mmu_hashcnt = MAX_HASHCNT;
660Sstevel@tonic-gate size_t mmu_ism_pagesize = DEFAULT_ISM_PAGESIZE;
670Sstevel@tonic-gate 
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate  * A bitmask of the page sizes supported by hardware based upon szc.
700Sstevel@tonic-gate  * The base pagesize (p_szc == 0) must always be supported by the hardware.
710Sstevel@tonic-gate  */
720Sstevel@tonic-gate int mmu_exported_pagesize_mask;
730Sstevel@tonic-gate uint_t mmu_exported_page_sizes;
740Sstevel@tonic-gate 
750Sstevel@tonic-gate uint_t szc_2_userszc[MMU_PAGE_SIZES];
760Sstevel@tonic-gate uint_t userszc_2_szc[MMU_PAGE_SIZES];
770Sstevel@tonic-gate 
780Sstevel@tonic-gate extern uint_t vac_colors_mask;
790Sstevel@tonic-gate extern int vac_shift;
800Sstevel@tonic-gate 
810Sstevel@tonic-gate hw_pagesize_t hw_page_array[] = {
822961Sdp78419 	{MMU_PAGESIZE, MMU_PAGESHIFT, 0, MMU_PAGESIZE >> MMU_PAGESHIFT},
832961Sdp78419 	{MMU_PAGESIZE64K, MMU_PAGESHIFT64K, 0,
842961Sdp78419 	    MMU_PAGESIZE64K >> MMU_PAGESHIFT},
852961Sdp78419 	{MMU_PAGESIZE512K, MMU_PAGESHIFT512K, 0,
860Sstevel@tonic-gate 	    MMU_PAGESIZE512K >> MMU_PAGESHIFT},
872961Sdp78419 	{MMU_PAGESIZE4M, MMU_PAGESHIFT4M, 0, MMU_PAGESIZE4M >> MMU_PAGESHIFT},
882961Sdp78419 	{MMU_PAGESIZE32M, MMU_PAGESHIFT32M, 0,
892961Sdp78419 	    MMU_PAGESIZE32M >> MMU_PAGESHIFT},
902961Sdp78419 	{MMU_PAGESIZE256M, MMU_PAGESHIFT256M, 0,
910Sstevel@tonic-gate 	    MMU_PAGESIZE256M >> MMU_PAGESHIFT},
922961Sdp78419 	{0, 0, 0, 0}
930Sstevel@tonic-gate };
940Sstevel@tonic-gate 
950Sstevel@tonic-gate /*
962991Ssusans  * Maximum and default segment size tunables for user heap, stack, private
972991Ssusans  * and shared anonymous memory, and user text and initialized data.
980Sstevel@tonic-gate  */
992991Ssusans size_t max_uheap_lpsize = MMU_PAGESIZE64K;
1002991Ssusans size_t default_uheap_lpsize = MMU_PAGESIZE64K;
1012991Ssusans size_t max_ustack_lpsize = MMU_PAGESIZE64K;
1022991Ssusans size_t default_ustack_lpsize = MMU_PAGESIZE64K;
1032991Ssusans size_t max_privmap_lpsize = MMU_PAGESIZE64K;
1042991Ssusans size_t max_uidata_lpsize = MMU_PAGESIZE64K;
1052991Ssusans size_t max_utext_lpsize = MMU_PAGESIZE4M;
1062414Saguzovsk size_t max_shm_lpsize = MMU_PAGESIZE4M;
1072414Saguzovsk 
1080Sstevel@tonic-gate /*
1090Sstevel@tonic-gate  * map_addr_proc() is the routine called when the system is to
1100Sstevel@tonic-gate  * choose an address for the user.  We will pick an address
1110Sstevel@tonic-gate  * range which is just below the current stack limit.  The
1120Sstevel@tonic-gate  * algorithm used for cache consistency on machines with virtual
1130Sstevel@tonic-gate  * address caches is such that offset 0 in the vnode is always
1140Sstevel@tonic-gate  * on a shm_alignment'ed aligned address.  Unfortunately, this
1150Sstevel@tonic-gate  * means that vnodes which are demand paged will not be mapped
1160Sstevel@tonic-gate  * cache consistently with the executable images.  When the
1170Sstevel@tonic-gate  * cache alignment for a given object is inconsistent, the
1180Sstevel@tonic-gate  * lower level code must manage the translations so that this
1190Sstevel@tonic-gate  * is not seen here (at the cost of efficiency, of course).
1200Sstevel@tonic-gate  *
1210Sstevel@tonic-gate  * addrp is a value/result parameter.
1220Sstevel@tonic-gate  *	On input it is a hint from the user to be used in a completely
1230Sstevel@tonic-gate  *	machine dependent fashion.  For MAP_ALIGN, addrp contains the
1240Sstevel@tonic-gate  *	minimal alignment.
1250Sstevel@tonic-gate  *
1260Sstevel@tonic-gate  *	On output it is NULL if no address can be found in the current
1270Sstevel@tonic-gate  *	processes address space or else an address that is currently
1280Sstevel@tonic-gate  *	not mapped for len bytes with a page of red zone on either side.
1290Sstevel@tonic-gate  *	If vacalign is true, then the selected address will obey the alignment
1300Sstevel@tonic-gate  *	constraints of a vac machine based on the given off value.
1310Sstevel@tonic-gate  */
1320Sstevel@tonic-gate /*ARGSUSED3*/
1330Sstevel@tonic-gate void
1340Sstevel@tonic-gate map_addr_proc(caddr_t *addrp, size_t len, offset_t off, int vacalign,
1350Sstevel@tonic-gate     caddr_t userlimit, struct proc *p, uint_t flags)
1360Sstevel@tonic-gate {
1370Sstevel@tonic-gate 	struct as *as = p->p_as;
1380Sstevel@tonic-gate 	caddr_t addr;
1390Sstevel@tonic-gate 	caddr_t base;
1400Sstevel@tonic-gate 	size_t slen;
1410Sstevel@tonic-gate 	uintptr_t align_amount;
1420Sstevel@tonic-gate 	int allow_largepage_alignment = 1;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	base = p->p_brkbase;
1450Sstevel@tonic-gate 	if (userlimit < as->a_userlimit) {
1460Sstevel@tonic-gate 		/*
1470Sstevel@tonic-gate 		 * This happens when a program wants to map something in
1480Sstevel@tonic-gate 		 * a range that's accessible to a program in a smaller
1490Sstevel@tonic-gate 		 * address space.  For example, a 64-bit program might
1500Sstevel@tonic-gate 		 * be calling mmap32(2) to guarantee that the returned
1510Sstevel@tonic-gate 		 * address is below 4Gbytes.
1520Sstevel@tonic-gate 		 */
1530Sstevel@tonic-gate 		ASSERT(userlimit > base);
1540Sstevel@tonic-gate 		slen = userlimit - base;
1550Sstevel@tonic-gate 	} else {
1560Sstevel@tonic-gate 		slen = p->p_usrstack - base - (((size_t)rctl_enforced_value(
1570Sstevel@tonic-gate 		    rctlproc_legacy[RLIMIT_STACK], p->p_rctls, p) + PAGEOFFSET)
1580Sstevel@tonic-gate 		    & PAGEMASK);
1590Sstevel@tonic-gate 	}
1600Sstevel@tonic-gate 	len = (len + PAGEOFFSET) & PAGEMASK;
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	/*
1630Sstevel@tonic-gate 	 * Redzone for each side of the request. This is done to leave
1640Sstevel@tonic-gate 	 * one page unmapped between segments. This is not required, but
1650Sstevel@tonic-gate 	 * it's useful for the user because if their program strays across
1660Sstevel@tonic-gate 	 * a segment boundary, it will catch a fault immediately making
1670Sstevel@tonic-gate 	 * debugging a little easier.
1680Sstevel@tonic-gate 	 */
1690Sstevel@tonic-gate 	len += (2 * PAGESIZE);
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	/*
1720Sstevel@tonic-gate 	 *  If the request is larger than the size of a particular
1730Sstevel@tonic-gate 	 *  mmu level, then we use that level to map the request.
1740Sstevel@tonic-gate 	 *  But this requires that both the virtual and the physical
1750Sstevel@tonic-gate 	 *  addresses be aligned with respect to that level, so we
1760Sstevel@tonic-gate 	 *  do the virtual bit of nastiness here.
1770Sstevel@tonic-gate 	 *
1780Sstevel@tonic-gate 	 *  For 32-bit processes, only those which have specified
1790Sstevel@tonic-gate 	 *  MAP_ALIGN or an addr will be aligned on a page size > 4MB. Otherwise
1800Sstevel@tonic-gate 	 *  we can potentially waste up to 256MB of the 4G process address
1810Sstevel@tonic-gate 	 *  space just for alignment.
1820Sstevel@tonic-gate 	 *
1830Sstevel@tonic-gate 	 * XXXQ Should iterate trough hw_page_array here to catch
1840Sstevel@tonic-gate 	 * all supported pagesizes
1850Sstevel@tonic-gate 	 */
1860Sstevel@tonic-gate 	if (p->p_model == DATAMODEL_ILP32 && ((flags & MAP_ALIGN) == 0 ||
1870Sstevel@tonic-gate 	    ((uintptr_t)*addrp) != 0)) {
1880Sstevel@tonic-gate 		allow_largepage_alignment = 0;
1890Sstevel@tonic-gate 	}
1900Sstevel@tonic-gate 	if ((mmu_page_sizes == max_mmu_page_sizes) &&
1910Sstevel@tonic-gate 	    allow_largepage_alignment &&
1920Sstevel@tonic-gate 		(len >= MMU_PAGESIZE256M)) {	/* 256MB mappings */
1930Sstevel@tonic-gate 		align_amount = MMU_PAGESIZE256M;
1940Sstevel@tonic-gate 	} else if ((mmu_page_sizes == max_mmu_page_sizes) &&
1950Sstevel@tonic-gate 	    allow_largepage_alignment &&
1960Sstevel@tonic-gate 		(len >= MMU_PAGESIZE32M)) {	/* 32MB mappings */
1970Sstevel@tonic-gate 		align_amount = MMU_PAGESIZE32M;
1980Sstevel@tonic-gate 	} else if (len >= MMU_PAGESIZE4M) {  /* 4MB mappings */
1990Sstevel@tonic-gate 		align_amount = MMU_PAGESIZE4M;
2000Sstevel@tonic-gate 	} else if (len >= MMU_PAGESIZE512K) { /* 512KB mappings */
2010Sstevel@tonic-gate 		align_amount = MMU_PAGESIZE512K;
2020Sstevel@tonic-gate 	} else if (len >= MMU_PAGESIZE64K) { /* 64KB mappings */
2030Sstevel@tonic-gate 		align_amount = MMU_PAGESIZE64K;
2040Sstevel@tonic-gate 	} else  {
2050Sstevel@tonic-gate 		/*
2060Sstevel@tonic-gate 		 * Align virtual addresses on a 64K boundary to ensure
2070Sstevel@tonic-gate 		 * that ELF shared libraries are mapped with the appropriate
2080Sstevel@tonic-gate 		 * alignment constraints by the run-time linker.
2090Sstevel@tonic-gate 		 */
2100Sstevel@tonic-gate 		align_amount = ELF_SPARC_MAXPGSZ;
2110Sstevel@tonic-gate 		if ((flags & MAP_ALIGN) && ((uintptr_t)*addrp != 0) &&
2120Sstevel@tonic-gate 			((uintptr_t)*addrp < align_amount))
2130Sstevel@tonic-gate 			align_amount = (uintptr_t)*addrp;
2140Sstevel@tonic-gate 	}
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	/*
2170Sstevel@tonic-gate 	 * 64-bit processes require 1024K alignment of ELF shared libraries.
2180Sstevel@tonic-gate 	 */
2190Sstevel@tonic-gate 	if (p->p_model == DATAMODEL_LP64)
2200Sstevel@tonic-gate 		align_amount = MAX(align_amount, ELF_SPARCV9_MAXPGSZ);
2210Sstevel@tonic-gate #ifdef VAC
2220Sstevel@tonic-gate 	if (vac && vacalign && (align_amount < shm_alignment))
2230Sstevel@tonic-gate 		align_amount = shm_alignment;
2240Sstevel@tonic-gate #endif
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	if ((flags & MAP_ALIGN) && ((uintptr_t)*addrp > align_amount)) {
2270Sstevel@tonic-gate 		align_amount = (uintptr_t)*addrp;
2280Sstevel@tonic-gate 	}
2290Sstevel@tonic-gate 	len += align_amount;
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	/*
2320Sstevel@tonic-gate 	 * Look for a large enough hole starting below the stack limit.
2330Sstevel@tonic-gate 	 * After finding it, use the upper part.  Addition of PAGESIZE is
2340Sstevel@tonic-gate 	 * for the redzone as described above.
2350Sstevel@tonic-gate 	 */
2360Sstevel@tonic-gate 	as_purge(as);
2370Sstevel@tonic-gate 	if (as_gap(as, len, &base, &slen, AH_HI, NULL) == 0) {
2380Sstevel@tonic-gate 		caddr_t as_addr;
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 		addr = base + slen - len + PAGESIZE;
2410Sstevel@tonic-gate 		as_addr = addr;
2420Sstevel@tonic-gate 		/*
2430Sstevel@tonic-gate 		 * Round address DOWN to the alignment amount,
2440Sstevel@tonic-gate 		 * add the offset, and if this address is less
2450Sstevel@tonic-gate 		 * than the original address, add alignment amount.
2460Sstevel@tonic-gate 		 */
2470Sstevel@tonic-gate 		addr = (caddr_t)((uintptr_t)addr & (~(align_amount - 1l)));
2480Sstevel@tonic-gate 		addr += (long)(off & (align_amount - 1l));
2490Sstevel@tonic-gate 		if (addr < as_addr) {
2500Sstevel@tonic-gate 			addr += align_amount;
2510Sstevel@tonic-gate 		}
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 		ASSERT(addr <= (as_addr + align_amount));
2540Sstevel@tonic-gate 		ASSERT(((uintptr_t)addr & (align_amount - 1l)) ==
2550Sstevel@tonic-gate 		    ((uintptr_t)(off & (align_amount - 1l))));
2560Sstevel@tonic-gate 		*addrp = addr;
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	} else {
2590Sstevel@tonic-gate 		*addrp = NULL;	/* no more virtual space */
2600Sstevel@tonic-gate 	}
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate /*
2640Sstevel@tonic-gate  * Platform-dependent page scrub call.
2650Sstevel@tonic-gate  * We call hypervisor to scrub the page.
2660Sstevel@tonic-gate  */
2670Sstevel@tonic-gate void
2680Sstevel@tonic-gate pagescrub(page_t *pp, uint_t off, uint_t len)
2690Sstevel@tonic-gate {
2700Sstevel@tonic-gate 	uint64_t pa, length;
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	pa = (uint64_t)(pp->p_pagenum << MMU_PAGESHIFT + off);
2730Sstevel@tonic-gate 	length = (uint64_t)len;
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	(void) mem_scrub(pa, length);
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate void
2790Sstevel@tonic-gate sync_data_memory(caddr_t va, size_t len)
2800Sstevel@tonic-gate {
2810Sstevel@tonic-gate 	/* Call memory sync function */
2820Sstevel@tonic-gate 	mem_sync(va, len);
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate size_t
2860Sstevel@tonic-gate mmu_get_kernel_lpsize(size_t lpsize)
2870Sstevel@tonic-gate {
2880Sstevel@tonic-gate 	extern int mmu_exported_pagesize_mask;
2890Sstevel@tonic-gate 	uint_t tte;
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	if (lpsize == 0) {
2920Sstevel@tonic-gate 		/* no setting for segkmem_lpsize in /etc/system: use default */
2930Sstevel@tonic-gate 		if (mmu_exported_pagesize_mask & (1 << TTE256M)) {
2940Sstevel@tonic-gate 			lpsize = MMU_PAGESIZE256M;
2950Sstevel@tonic-gate 		} else if (mmu_exported_pagesize_mask & (1 << TTE4M)) {
2960Sstevel@tonic-gate 			lpsize = MMU_PAGESIZE4M;
2970Sstevel@tonic-gate 		} else if (mmu_exported_pagesize_mask & (1 << TTE64K)) {
2980Sstevel@tonic-gate 			lpsize = MMU_PAGESIZE64K;
2990Sstevel@tonic-gate 		} else {
3000Sstevel@tonic-gate 			lpsize = MMU_PAGESIZE;
3010Sstevel@tonic-gate 		}
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 		return (lpsize);
3040Sstevel@tonic-gate 	}
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	for (tte = TTE8K; tte <= TTE256M; tte++) {
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 		if ((mmu_exported_pagesize_mask & (1 << tte)) == 0)
3090Sstevel@tonic-gate 			continue;
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 		if (lpsize == TTEBYTES(tte))
3120Sstevel@tonic-gate 			return (lpsize);
3130Sstevel@tonic-gate 	}
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	lpsize = TTEBYTES(TTE8K);
3160Sstevel@tonic-gate 	return (lpsize);
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate void
3200Sstevel@tonic-gate mmu_init_kcontext()
3210Sstevel@tonic-gate {
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate /*ARGSUSED*/
3250Sstevel@tonic-gate void
3260Sstevel@tonic-gate mmu_init_kernel_pgsz(struct hat *hat)
3270Sstevel@tonic-gate {
3280Sstevel@tonic-gate }
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate #define	QUANTUM_SIZE	64
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate static	vmem_t	*contig_mem_slab_arena;
3330Sstevel@tonic-gate static	vmem_t	*contig_mem_arena;
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate uint_t contig_mem_slab_size = MMU_PAGESIZE4M;
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate static void *
3380Sstevel@tonic-gate contig_mem_span_alloc(vmem_t *vmp, size_t size, int vmflag)
3390Sstevel@tonic-gate {
3400Sstevel@tonic-gate 	page_t *ppl;
3410Sstevel@tonic-gate 	page_t *rootpp;
3420Sstevel@tonic-gate 	caddr_t addr = NULL;
3430Sstevel@tonic-gate 	pgcnt_t npages = btopr(size);
3440Sstevel@tonic-gate 	page_t **ppa;
3450Sstevel@tonic-gate 	int pgflags;
3460Sstevel@tonic-gate 	int i = 0;
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 
3491859Sha137994 	/*
3501859Sha137994 	 * The import request should be at least
3511859Sha137994 	 * contig_mem_slab_size because that is the
3521859Sha137994 	 * slab arena's quantum. The size can be
3531859Sha137994 	 * further restricted since contiguous
3541859Sha137994 	 * allocations larger than contig_mem_slab_size
3551859Sha137994 	 * are not supported here.
3561859Sha137994 	 */
3571859Sha137994 	ASSERT(size == contig_mem_slab_size);
3581859Sha137994 
3590Sstevel@tonic-gate 	if ((addr = vmem_xalloc(vmp, size, size, 0, 0,
3600Sstevel@tonic-gate 	    NULL, NULL, vmflag)) == NULL) {
3610Sstevel@tonic-gate 		return (NULL);
3620Sstevel@tonic-gate 	}
3630Sstevel@tonic-gate 
3641859Sha137994 	/* The address should be slab-size aligned. */
3650Sstevel@tonic-gate 	ASSERT(((uintptr_t)addr & (contig_mem_slab_size - 1)) == 0);
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	if (page_resv(npages, vmflag & VM_KMFLAGS) == 0) {
3680Sstevel@tonic-gate 		vmem_xfree(vmp, addr, size);
3690Sstevel@tonic-gate 		return (NULL);
3700Sstevel@tonic-gate 	}
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	pgflags = PG_EXCL;
3730Sstevel@tonic-gate 	if ((vmflag & VM_NOSLEEP) == 0)
3740Sstevel@tonic-gate 		pgflags |= PG_WAIT;
3750Sstevel@tonic-gate 	if (vmflag & VM_PANIC)
3760Sstevel@tonic-gate 		pgflags |= PG_PANIC;
3770Sstevel@tonic-gate 	if (vmflag & VM_PUSHPAGE)
3780Sstevel@tonic-gate 		pgflags |= PG_PUSHPAGE;
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	ppl = page_create_va_large(&kvp, (u_offset_t)(uintptr_t)addr, size,
3810Sstevel@tonic-gate 	    pgflags, &kvseg, addr, NULL);
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	if (ppl == NULL) {
3840Sstevel@tonic-gate 		vmem_xfree(vmp, addr, size);
3850Sstevel@tonic-gate 		page_unresv(npages);
3860Sstevel@tonic-gate 		return (NULL);
3870Sstevel@tonic-gate 	}
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	rootpp = ppl;
3900Sstevel@tonic-gate 	ppa = kmem_zalloc(npages * sizeof (page_t *), KM_SLEEP);
3910Sstevel@tonic-gate 	while (ppl != NULL) {
3920Sstevel@tonic-gate 		page_t *pp = ppl;
3930Sstevel@tonic-gate 		ppa[i++] = pp;
3940Sstevel@tonic-gate 		page_sub(&ppl, pp);
3950Sstevel@tonic-gate 		ASSERT(page_iolock_assert(pp));
3960Sstevel@tonic-gate 		page_io_unlock(pp);
3970Sstevel@tonic-gate 	}
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	/*
4000Sstevel@tonic-gate 	 * Load the locked entry.  It's OK to preload the entry into
4010Sstevel@tonic-gate 	 * the TSB since we now support large mappings in the kernel TSB.
4020Sstevel@tonic-gate 	 */
4030Sstevel@tonic-gate 	hat_memload_array(kas.a_hat, (caddr_t)rootpp->p_offset, size,
4040Sstevel@tonic-gate 	    ppa, (PROT_ALL & ~PROT_USER) | HAT_NOSYNC, HAT_LOAD_LOCK);
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	for (--i; i >= 0; --i) {
4070Sstevel@tonic-gate 		(void) page_pp_lock(ppa[i], 0, 1);
4080Sstevel@tonic-gate 		page_unlock(ppa[i]);
4090Sstevel@tonic-gate 	}
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	kmem_free(ppa, npages * sizeof (page_t *));
4120Sstevel@tonic-gate 	return (addr);
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate void
4160Sstevel@tonic-gate contig_mem_span_free(vmem_t *vmp, void *inaddr, size_t size)
4170Sstevel@tonic-gate {
4180Sstevel@tonic-gate 	page_t *pp;
4190Sstevel@tonic-gate 	caddr_t addr = inaddr;
4200Sstevel@tonic-gate 	caddr_t eaddr;
4210Sstevel@tonic-gate 	pgcnt_t npages = btopr(size);
4220Sstevel@tonic-gate 	pgcnt_t pgs_left = npages;
4230Sstevel@tonic-gate 	page_t *rootpp = NULL;
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	ASSERT(((uintptr_t)addr & (contig_mem_slab_size - 1)) == 0);
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	hat_unload(kas.a_hat, addr, size, HAT_UNLOAD_UNLOCK);
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	for (eaddr = addr + size; addr < eaddr; addr += PAGESIZE) {
4300Sstevel@tonic-gate 		pp = page_lookup(&kvp, (u_offset_t)(uintptr_t)addr, SE_EXCL);
4310Sstevel@tonic-gate 		if (pp == NULL)
4320Sstevel@tonic-gate 			panic("contig_mem_span_free: page not found");
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 		ASSERT(PAGE_EXCL(pp));
4350Sstevel@tonic-gate 		page_pp_unlock(pp, 0, 1);
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 		if (rootpp == NULL)
4380Sstevel@tonic-gate 			rootpp = pp;
4390Sstevel@tonic-gate 		if (--pgs_left == 0) {
4400Sstevel@tonic-gate 			/*
4410Sstevel@tonic-gate 			 * similar logic to segspt_free_pages, but we know we
4420Sstevel@tonic-gate 			 * have one large page.
4430Sstevel@tonic-gate 			 */
4440Sstevel@tonic-gate 			page_destroy_pages(rootpp);
4450Sstevel@tonic-gate 		}
4460Sstevel@tonic-gate 	}
4470Sstevel@tonic-gate 	page_unresv(npages);
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	if (vmp != NULL)
4500Sstevel@tonic-gate 		vmem_xfree(vmp, inaddr, size);
4510Sstevel@tonic-gate }
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate static void *
4540Sstevel@tonic-gate contig_vmem_xalloc_aligned_wrapper(vmem_t *vmp, size_t size, int vmflag)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate 	return (vmem_xalloc(vmp, size, size, 0, 0, NULL, NULL, vmflag));
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate 
459288Sarao /*
460288Sarao  * conting_mem_alloc_align allocates real contiguous memory with the specified
461288Sarao  * alignment upto contig_mem_slab_size. The alignment must be a power of 2.
462288Sarao  */
463288Sarao void *
464288Sarao contig_mem_alloc_align(size_t size, size_t align)
465288Sarao {
4661859Sha137994 	ASSERT(align <= contig_mem_slab_size);
4671859Sha137994 
468288Sarao 	if ((align & (align - 1)) != 0)
469288Sarao 		return (NULL);
470288Sarao 
471288Sarao 	return (vmem_xalloc(contig_mem_arena, size, align, 0, 0,
472288Sarao 	    NULL, NULL, VM_NOSLEEP));
473288Sarao }
474288Sarao 
475288Sarao /*
476288Sarao  * Allocates size aligned contiguous memory upto contig_mem_slab_size.
477288Sarao  * Size must be a power of 2.
478288Sarao  */
4790Sstevel@tonic-gate void *
4800Sstevel@tonic-gate contig_mem_alloc(size_t size)
4810Sstevel@tonic-gate {
482288Sarao 	ASSERT((size & (size - 1)) == 0);
483288Sarao 	return (contig_mem_alloc_align(size, size));
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate void
4870Sstevel@tonic-gate contig_mem_free(void *vaddr, size_t size)
4880Sstevel@tonic-gate {
4890Sstevel@tonic-gate 	vmem_xfree(contig_mem_arena, vaddr, size);
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate /*
4930Sstevel@tonic-gate  * We create a set of stacked vmem arenas to enable us to
4940Sstevel@tonic-gate  * allocate large >PAGESIZE chucks of contiguous Real Address space
4950Sstevel@tonic-gate  * This is  what the Dynamics TSB support does for TSBs.
4960Sstevel@tonic-gate  * The contig_mem_arena import functions are exactly the same as the
4970Sstevel@tonic-gate  * TSB kmem_default arena import functions.
4980Sstevel@tonic-gate  */
4990Sstevel@tonic-gate void
5000Sstevel@tonic-gate contig_mem_init(void)
5010Sstevel@tonic-gate {
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	contig_mem_slab_arena = vmem_create("contig_mem_slab_arena", NULL, 0,
5040Sstevel@tonic-gate 	    contig_mem_slab_size, contig_vmem_xalloc_aligned_wrapper,
5050Sstevel@tonic-gate 	    vmem_xfree, heap_arena, 0, VM_SLEEP);
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	contig_mem_arena = vmem_create("contig_mem_arena", NULL, 0,
5080Sstevel@tonic-gate 	    QUANTUM_SIZE, contig_mem_span_alloc, contig_mem_span_free,
5090Sstevel@tonic-gate 	    contig_mem_slab_arena, 0, VM_SLEEP | VM_BESTFIT);
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate }
512*3177Sdp78419 
513*3177Sdp78419 
514*3177Sdp78419 static uint_t sp_color_stride = 16;
515*3177Sdp78419 static uint_t sp_color_mask = 0x1f;
516*3177Sdp78419 static uint_t sp_current_color = (uint_t)-1;
517*3177Sdp78419 
518*3177Sdp78419 size_t
519*3177Sdp78419 exec_get_spslew(void)
520*3177Sdp78419 {
521*3177Sdp78419 	uint_t spcolor = atomic_inc_32_nv(&sp_current_color);
522*3177Sdp78419 	return ((size_t)((spcolor & sp_color_mask) * SA(sp_color_stride)));
523*3177Sdp78419 }
524