xref: /titanic_44/usr/src/uts/sun4/vm/vm_dep.c (revision 75d94465dbafa487b716482dc36d5150a4ec9853)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5d0662dbfSelowe  * Common Development and Distribution License (the "License").
6d0662dbfSelowe  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22d94ffb28Sjmcp  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23d94ffb28Sjmcp  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * UNIX machine dependent virtual memory support.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <sys/vm.h>
317c478bd9Sstevel@tonic-gate #include <sys/exec.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <sys/exechdr.h>
347c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
357c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
367c478bd9Sstevel@tonic-gate #include <sys/archsystm.h>
377c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
387c478bd9Sstevel@tonic-gate #include <sys/kdi.h>
397c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include <sys/memnode.h>
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #include <sys/mem_config.h>
467c478bd9Sstevel@tonic-gate #include <sys/mem_cage.h>
477c478bd9Sstevel@tonic-gate #include <vm/vm_dep.h>
485d07b933Sdp78419 #include <vm/page.h>
497c478bd9Sstevel@tonic-gate #include <sys/platform_module.h>
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate  * These variables are set by module specific config routines.
5305d3dc4bSpaulsan  * They are only set by modules which will use physical cache page coloring.
547c478bd9Sstevel@tonic-gate  */
557c478bd9Sstevel@tonic-gate int do_pg_coloring = 0;
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  * These variables can be conveniently patched at kernel load time to
5905d3dc4bSpaulsan  * prevent do_pg_coloring from being enabled by
607c478bd9Sstevel@tonic-gate  * module specific config routines.
617c478bd9Sstevel@tonic-gate  */
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate int use_page_coloring = 1;
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate /*
667c478bd9Sstevel@tonic-gate  * initialized by page_coloring_init()
677c478bd9Sstevel@tonic-gate  */
687c478bd9Sstevel@tonic-gate extern uint_t page_colors;
697c478bd9Sstevel@tonic-gate extern uint_t page_colors_mask;
707c478bd9Sstevel@tonic-gate extern uint_t page_coloring_shift;
717c478bd9Sstevel@tonic-gate int cpu_page_colors;
727c478bd9Sstevel@tonic-gate uint_t vac_colors = 0;
737c478bd9Sstevel@tonic-gate uint_t vac_colors_mask = 0;
747c478bd9Sstevel@tonic-gate 
755d07b933Sdp78419 /* cpu specific coloring initialization */
765d07b933Sdp78419 extern void page_coloring_init_cpu();
775d07b933Sdp78419 #pragma weak page_coloring_init_cpu
785d07b933Sdp78419 
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate  * get the ecache setsize for the current cpu.
817c478bd9Sstevel@tonic-gate  */
827c478bd9Sstevel@tonic-gate #define	CPUSETSIZE()	(cpunodes[CPU->cpu_id].ecache_setsize)
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate plcnt_t		plcnt;		/* page list count */
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate /*
877c478bd9Sstevel@tonic-gate  * This variable is set by the cpu module to contain the lowest
887c478bd9Sstevel@tonic-gate  * address not affected by the SF_ERRATA_57 workaround.  It should
897c478bd9Sstevel@tonic-gate  * remain 0 if the workaround is not needed.
907c478bd9Sstevel@tonic-gate  */
917c478bd9Sstevel@tonic-gate #if defined(SF_ERRATA_57)
927c478bd9Sstevel@tonic-gate caddr_t errata57_limit;
937c478bd9Sstevel@tonic-gate #endif
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate extern void page_relocate_hash(page_t *, page_t *);
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate  * these must be defined in platform specific areas
997c478bd9Sstevel@tonic-gate  */
1007c478bd9Sstevel@tonic-gate extern void map_addr_proc(caddr_t *, size_t, offset_t, int, caddr_t,
1017c478bd9Sstevel@tonic-gate 	struct proc *, uint_t);
1027c478bd9Sstevel@tonic-gate extern page_t *page_get_freelist(struct vnode *, u_offset_t, struct seg *,
1037c478bd9Sstevel@tonic-gate 	caddr_t, size_t, uint_t, struct lgrp *);
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate  * Convert page frame number to an OBMEM page frame number
1067c478bd9Sstevel@tonic-gate  * (i.e. put in the type bits -- zero for this implementation)
1077c478bd9Sstevel@tonic-gate  */
1087c478bd9Sstevel@tonic-gate pfn_t
impl_obmem_pfnum(pfn_t pf)1097c478bd9Sstevel@tonic-gate impl_obmem_pfnum(pfn_t pf)
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate 	return (pf);
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /*
1157c478bd9Sstevel@tonic-gate  * Use physmax to determine the highest physical page of DRAM memory
1167c478bd9Sstevel@tonic-gate  * It is assumed that any physical addresses above physmax is in IO space.
1177c478bd9Sstevel@tonic-gate  * We don't bother checking the low end because we assume that memory space
1187c478bd9Sstevel@tonic-gate  * begins at physical page frame 0.
1197c478bd9Sstevel@tonic-gate  *
1207c478bd9Sstevel@tonic-gate  * Return 1 if the page frame is onboard DRAM memory, else 0.
1217c478bd9Sstevel@tonic-gate  * Returns 0 for nvram so it won't be cached.
1227c478bd9Sstevel@tonic-gate  */
1237c478bd9Sstevel@tonic-gate int
pf_is_memory(pfn_t pf)1247c478bd9Sstevel@tonic-gate pf_is_memory(pfn_t pf)
1257c478bd9Sstevel@tonic-gate {
1267c478bd9Sstevel@tonic-gate 	/* We must be IO space */
1277c478bd9Sstevel@tonic-gate 	if (pf > physmax)
1287c478bd9Sstevel@tonic-gate 		return (0);
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	/* We must be memory space */
1317c478bd9Sstevel@tonic-gate 	return (1);
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate /*
1357c478bd9Sstevel@tonic-gate  * Handle a pagefault.
1367c478bd9Sstevel@tonic-gate  */
1377c478bd9Sstevel@tonic-gate faultcode_t
pagefault(caddr_t addr,enum fault_type type,enum seg_rw rw,int iskernel)1387c478bd9Sstevel@tonic-gate pagefault(caddr_t addr, enum fault_type type, enum seg_rw rw, int iskernel)
1397c478bd9Sstevel@tonic-gate {
1407c478bd9Sstevel@tonic-gate 	struct as *as;
1417c478bd9Sstevel@tonic-gate 	struct proc *p;
1427c478bd9Sstevel@tonic-gate 	faultcode_t res;
1437c478bd9Sstevel@tonic-gate 	caddr_t base;
1447c478bd9Sstevel@tonic-gate 	size_t len;
1457c478bd9Sstevel@tonic-gate 	int err;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	if (INVALID_VADDR(addr))
1487c478bd9Sstevel@tonic-gate 		return (FC_NOMAP);
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	if (iskernel) {
1517c478bd9Sstevel@tonic-gate 		as = &kas;
1527c478bd9Sstevel@tonic-gate 	} else {
1537c478bd9Sstevel@tonic-gate 		p = curproc;
1547c478bd9Sstevel@tonic-gate 		as = p->p_as;
1557c478bd9Sstevel@tonic-gate #if defined(SF_ERRATA_57)
1567c478bd9Sstevel@tonic-gate 		/*
1577c478bd9Sstevel@tonic-gate 		 * Prevent infinite loops due to a segment driver
1587c478bd9Sstevel@tonic-gate 		 * setting the execute permissions and the sfmmu hat
1597c478bd9Sstevel@tonic-gate 		 * silently ignoring them.
1607c478bd9Sstevel@tonic-gate 		 */
1617c478bd9Sstevel@tonic-gate 		if (rw == S_EXEC && AS_TYPE_64BIT(as) &&
1627c478bd9Sstevel@tonic-gate 		    addr < errata57_limit) {
1637c478bd9Sstevel@tonic-gate 			res = FC_NOMAP;
1647c478bd9Sstevel@tonic-gate 			goto out;
1657c478bd9Sstevel@tonic-gate 		}
1667c478bd9Sstevel@tonic-gate #endif
1677c478bd9Sstevel@tonic-gate 	}
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	/*
1707c478bd9Sstevel@tonic-gate 	 * Dispatch pagefault.
1717c478bd9Sstevel@tonic-gate 	 */
1727c478bd9Sstevel@tonic-gate 	res = as_fault(as->a_hat, as, addr, 1, type, rw);
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	/*
1757c478bd9Sstevel@tonic-gate 	 * If this isn't a potential unmapped hole in the user's
1767c478bd9Sstevel@tonic-gate 	 * UNIX data or stack segments, just return status info.
1777c478bd9Sstevel@tonic-gate 	 */
1787c478bd9Sstevel@tonic-gate 	if (!(res == FC_NOMAP && iskernel == 0))
1797c478bd9Sstevel@tonic-gate 		goto out;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	/*
1827c478bd9Sstevel@tonic-gate 	 * Check to see if we happened to faulted on a currently unmapped
1837c478bd9Sstevel@tonic-gate 	 * part of the UNIX data or stack segments.  If so, create a zfod
1847c478bd9Sstevel@tonic-gate 	 * mapping there and then try calling the fault routine again.
1857c478bd9Sstevel@tonic-gate 	 */
1867c478bd9Sstevel@tonic-gate 	base = p->p_brkbase;
1877c478bd9Sstevel@tonic-gate 	len = p->p_brksize;
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	if (addr < base || addr >= base + len) {		/* data seg? */
1907c478bd9Sstevel@tonic-gate 		base = (caddr_t)(p->p_usrstack - p->p_stksize);
1917c478bd9Sstevel@tonic-gate 		len = p->p_stksize;
1927c478bd9Sstevel@tonic-gate 		if (addr < base || addr >= p->p_usrstack) {	/* stack seg? */
1937c478bd9Sstevel@tonic-gate 			/* not in either UNIX data or stack segments */
1947c478bd9Sstevel@tonic-gate 			res = FC_NOMAP;
1957c478bd9Sstevel@tonic-gate 			goto out;
1967c478bd9Sstevel@tonic-gate 		}
1977c478bd9Sstevel@tonic-gate 	}
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	/* the rest of this function implements a 3.X 4.X 5.X compatibility */
2007c478bd9Sstevel@tonic-gate 	/* This code is probably not needed anymore */
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	/* expand the gap to the page boundaries on each side */
2037c478bd9Sstevel@tonic-gate 	len = (((uintptr_t)base + len + PAGEOFFSET) & PAGEMASK) -
2047c478bd9Sstevel@tonic-gate 	    ((uintptr_t)base & PAGEMASK);
2057c478bd9Sstevel@tonic-gate 	base = (caddr_t)((uintptr_t)base & PAGEMASK);
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	as_rangelock(as);
2087c478bd9Sstevel@tonic-gate 	as_purge(as);
2097c478bd9Sstevel@tonic-gate 	if (as_gap(as, PAGESIZE, &base, &len, AH_CONTAIN, addr) == 0) {
2107c478bd9Sstevel@tonic-gate 		err = as_map(as, base, len, segvn_create, zfod_argsp);
2117c478bd9Sstevel@tonic-gate 		as_rangeunlock(as);
2127c478bd9Sstevel@tonic-gate 		if (err) {
2137c478bd9Sstevel@tonic-gate 			res = FC_MAKE_ERR(err);
2147c478bd9Sstevel@tonic-gate 			goto out;
2157c478bd9Sstevel@tonic-gate 		}
2167c478bd9Sstevel@tonic-gate 	} else {
2177c478bd9Sstevel@tonic-gate 		/*
2187c478bd9Sstevel@tonic-gate 		 * This page is already mapped by another thread after we
2197c478bd9Sstevel@tonic-gate 		 * returned from as_fault() above.  We just fallthrough
2207c478bd9Sstevel@tonic-gate 		 * as_fault() below.
2217c478bd9Sstevel@tonic-gate 		 */
2227c478bd9Sstevel@tonic-gate 		as_rangeunlock(as);
2237c478bd9Sstevel@tonic-gate 	}
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	res = as_fault(as->a_hat, as, addr, 1, F_INVAL, rw);
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate out:
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	return (res);
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate /*
2337c478bd9Sstevel@tonic-gate  * This is the routine which defines the address limit implied
2347c478bd9Sstevel@tonic-gate  * by the flag '_MAP_LOW32'.  USERLIMIT32 matches the highest
2357c478bd9Sstevel@tonic-gate  * mappable address in a 32-bit process on this platform (though
2367c478bd9Sstevel@tonic-gate  * perhaps we should make it be UINT32_MAX here?)
2377c478bd9Sstevel@tonic-gate  */
2387c478bd9Sstevel@tonic-gate void
map_addr(caddr_t * addrp,size_t len,offset_t off,int vacalign,uint_t flags)2397c478bd9Sstevel@tonic-gate map_addr(caddr_t *addrp, size_t len, offset_t off, int vacalign, uint_t flags)
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate 	struct proc *p = curproc;
2427c478bd9Sstevel@tonic-gate 	caddr_t userlimit = flags & _MAP_LOW32 ?
2437c478bd9Sstevel@tonic-gate 	    (caddr_t)USERLIMIT32 : p->p_as->a_userlimit;
2447c478bd9Sstevel@tonic-gate 	map_addr_proc(addrp, len, off, vacalign, userlimit, p, flags);
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate /*
2487c478bd9Sstevel@tonic-gate  * Some V9 CPUs have holes in the middle of the 64-bit virtual address range.
2497c478bd9Sstevel@tonic-gate  */
2507c478bd9Sstevel@tonic-gate caddr_t	hole_start, hole_end;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate /*
2537c478bd9Sstevel@tonic-gate  * kpm mapping window
2547c478bd9Sstevel@tonic-gate  */
2557c478bd9Sstevel@tonic-gate caddr_t kpm_vbase;
2567c478bd9Sstevel@tonic-gate size_t  kpm_size;
2577c478bd9Sstevel@tonic-gate uchar_t kpm_size_shift;
2587c478bd9Sstevel@tonic-gate 
25946ab9534Smec int valid_va_range_aligned_wraparound;
2607c478bd9Sstevel@tonic-gate /*
26146ab9534Smec  * Determine whether [*basep, *basep + *lenp) contains a mappable range of
26246ab9534Smec  * addresses at least "minlen" long, where the base of the range is at "off"
26346ab9534Smec  * phase from an "align" boundary and there is space for a "redzone"-sized
26446ab9534Smec  * redzone on either side of the range.  On success, 1 is returned and *basep
26546ab9534Smec  * and *lenp are adjusted to describe the acceptable range (including
26646ab9534Smec  * the redzone).  On failure, 0 is returned.
2677c478bd9Sstevel@tonic-gate  */
2687c478bd9Sstevel@tonic-gate int
valid_va_range_aligned(caddr_t * basep,size_t * lenp,size_t minlen,int dir,size_t align,size_t redzone,size_t off)26946ab9534Smec valid_va_range_aligned(caddr_t *basep, size_t *lenp, size_t minlen, int dir,
27046ab9534Smec     size_t align, size_t redzone, size_t off)
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate 	caddr_t hi, lo;
27346ab9534Smec 	size_t tot_len;
27446ab9534Smec 
27546ab9534Smec 	ASSERT(align == 0 ? off == 0 : off < align);
27646ab9534Smec 	ASSERT(ISP2(align));
27746ab9534Smec 	ASSERT(align == 0 || align >= PAGESIZE);
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	lo = *basep;
2807c478bd9Sstevel@tonic-gate 	hi = lo + *lenp;
28146ab9534Smec 	tot_len = minlen + 2 * redzone;	/* need at least this much space */
2827c478bd9Sstevel@tonic-gate 
28346ab9534Smec 	/* If hi rolled over the top try cutting back. */
2847c478bd9Sstevel@tonic-gate 	if (hi < lo) {
28546ab9534Smec 		*lenp = 0UL - (uintptr_t)lo - 1UL;
28646ab9534Smec 		/* Trying to see if this really happens, and then if so, why */
28746ab9534Smec 		valid_va_range_aligned_wraparound++;
28846ab9534Smec 		hi = lo + *lenp;
28946ab9534Smec 	}
29046ab9534Smec 	if (*lenp < tot_len) {
2917c478bd9Sstevel@tonic-gate 		return (0);
29246ab9534Smec 	}
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	/*
2957c478bd9Sstevel@tonic-gate 	 * Deal with a possible hole in the address range between
2967c478bd9Sstevel@tonic-gate 	 * hole_start and hole_end that should never be mapped by the MMU.
2977c478bd9Sstevel@tonic-gate 	 */
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	if (lo < hole_start) {
3007c478bd9Sstevel@tonic-gate 		if (hi > hole_start)
3017c478bd9Sstevel@tonic-gate 			if (hi < hole_end)
3027c478bd9Sstevel@tonic-gate 				hi = hole_start;
3037c478bd9Sstevel@tonic-gate 			else
3047c478bd9Sstevel@tonic-gate 				/* lo < hole_start && hi >= hole_end */
3057c478bd9Sstevel@tonic-gate 				if (dir == AH_LO) {
3067c478bd9Sstevel@tonic-gate 					/*
3077c478bd9Sstevel@tonic-gate 					 * prefer lowest range
3087c478bd9Sstevel@tonic-gate 					 */
30946ab9534Smec 					if (hole_start - lo >= tot_len)
3107c478bd9Sstevel@tonic-gate 						hi = hole_start;
31146ab9534Smec 					else if (hi - hole_end >= tot_len)
3127c478bd9Sstevel@tonic-gate 						lo = hole_end;
3137c478bd9Sstevel@tonic-gate 					else
3147c478bd9Sstevel@tonic-gate 						return (0);
3157c478bd9Sstevel@tonic-gate 				} else {
3167c478bd9Sstevel@tonic-gate 					/*
3177c478bd9Sstevel@tonic-gate 					 * prefer highest range
3187c478bd9Sstevel@tonic-gate 					 */
31946ab9534Smec 					if (hi - hole_end >= tot_len)
3207c478bd9Sstevel@tonic-gate 						lo = hole_end;
32146ab9534Smec 					else if (hole_start - lo >= tot_len)
3227c478bd9Sstevel@tonic-gate 						hi = hole_start;
3237c478bd9Sstevel@tonic-gate 					else
3247c478bd9Sstevel@tonic-gate 						return (0);
3257c478bd9Sstevel@tonic-gate 				}
3267c478bd9Sstevel@tonic-gate 	} else {
3277c478bd9Sstevel@tonic-gate 		/* lo >= hole_start */
3287c478bd9Sstevel@tonic-gate 		if (hi < hole_end)
3297c478bd9Sstevel@tonic-gate 			return (0);
3307c478bd9Sstevel@tonic-gate 		if (lo < hole_end)
3317c478bd9Sstevel@tonic-gate 			lo = hole_end;
3327c478bd9Sstevel@tonic-gate 	}
3337c478bd9Sstevel@tonic-gate 
33446ab9534Smec 	/* Check if remaining length is too small */
33546ab9534Smec 	if (hi - lo < tot_len) {
3367c478bd9Sstevel@tonic-gate 		return (0);
33746ab9534Smec 	}
33846ab9534Smec 	if (align > 1) {
33946ab9534Smec 		caddr_t tlo = lo + redzone;
34046ab9534Smec 		caddr_t thi = hi - redzone;
34146ab9534Smec 		tlo = (caddr_t)P2PHASEUP((uintptr_t)tlo, align, off);
34246ab9534Smec 		if (tlo < lo + redzone) {
34346ab9534Smec 			return (0);
34446ab9534Smec 		}
34546ab9534Smec 		if (thi < tlo || thi - tlo < minlen) {
34646ab9534Smec 			return (0);
34746ab9534Smec 		}
34846ab9534Smec 	}
3497c478bd9Sstevel@tonic-gate 	*basep = lo;
3507c478bd9Sstevel@tonic-gate 	*lenp = hi - lo;
3517c478bd9Sstevel@tonic-gate 	return (1);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate /*
35546ab9534Smec  * Determine whether [*basep, *basep + *lenp) contains a mappable range of
35646ab9534Smec  * addresses at least "minlen" long.  On success, 1 is returned and *basep
35746ab9534Smec  * and *lenp are adjusted to describe the acceptable range.  On failure, 0
35846ab9534Smec  * is returned.
35946ab9534Smec  */
36046ab9534Smec int
valid_va_range(caddr_t * basep,size_t * lenp,size_t minlen,int dir)36146ab9534Smec valid_va_range(caddr_t *basep, size_t *lenp, size_t minlen, int dir)
36246ab9534Smec {
36346ab9534Smec 	return (valid_va_range_aligned(basep, lenp, minlen, dir, 0, 0, 0));
36446ab9534Smec }
36546ab9534Smec 
36646ab9534Smec /*
3677c478bd9Sstevel@tonic-gate  * Determine whether [addr, addr+len] with protections `prot' are valid
3687c478bd9Sstevel@tonic-gate  * for a user address space.
3697c478bd9Sstevel@tonic-gate  */
3707c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3717c478bd9Sstevel@tonic-gate int
valid_usr_range(caddr_t addr,size_t len,uint_t prot,struct as * as,caddr_t userlimit)3727c478bd9Sstevel@tonic-gate valid_usr_range(caddr_t addr, size_t len, uint_t prot, struct as *as,
3737c478bd9Sstevel@tonic-gate     caddr_t userlimit)
3747c478bd9Sstevel@tonic-gate {
3757c478bd9Sstevel@tonic-gate 	caddr_t eaddr = addr + len;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	if (eaddr <= addr || addr >= userlimit || eaddr > userlimit)
3787c478bd9Sstevel@tonic-gate 		return (RANGE_BADADDR);
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	/*
3817c478bd9Sstevel@tonic-gate 	 * Determine if the address range falls within an illegal
3827c478bd9Sstevel@tonic-gate 	 * range of the MMU.
3837c478bd9Sstevel@tonic-gate 	 */
3847c478bd9Sstevel@tonic-gate 	if (eaddr > hole_start && addr < hole_end)
3857c478bd9Sstevel@tonic-gate 		return (RANGE_BADADDR);
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate #if defined(SF_ERRATA_57)
3887c478bd9Sstevel@tonic-gate 	/*
3897c478bd9Sstevel@tonic-gate 	 * Make sure USERLIMIT isn't raised too high
3907c478bd9Sstevel@tonic-gate 	 */
3917c478bd9Sstevel@tonic-gate 	ASSERT64(addr <= (caddr_t)0xffffffff80000000ul ||
3927c478bd9Sstevel@tonic-gate 	    errata57_limit == 0);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	if (AS_TYPE_64BIT(as) &&
3957c478bd9Sstevel@tonic-gate 	    (addr < errata57_limit) &&
3967c478bd9Sstevel@tonic-gate 	    (prot & PROT_EXEC))
3977c478bd9Sstevel@tonic-gate 		return (RANGE_BADPROT);
3987c478bd9Sstevel@tonic-gate #endif /* SF_ERRATA57 */
3997c478bd9Sstevel@tonic-gate 	return (RANGE_OKAY);
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate /*
4037c478bd9Sstevel@tonic-gate  * Routine used to check to see if an a.out can be executed
4047c478bd9Sstevel@tonic-gate  * by the current machine/architecture.
4057c478bd9Sstevel@tonic-gate  */
4067c478bd9Sstevel@tonic-gate int
chkaout(struct exdata * exp)4077c478bd9Sstevel@tonic-gate chkaout(struct exdata *exp)
4087c478bd9Sstevel@tonic-gate {
4097c478bd9Sstevel@tonic-gate 	if (exp->ux_mach == M_SPARC)
4107c478bd9Sstevel@tonic-gate 		return (0);
4117c478bd9Sstevel@tonic-gate 	else
4127c478bd9Sstevel@tonic-gate 		return (ENOEXEC);
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate /*
4167c478bd9Sstevel@tonic-gate  * The following functions return information about an a.out
4177c478bd9Sstevel@tonic-gate  * which is used when a program is executed.
4187c478bd9Sstevel@tonic-gate  */
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate /*
4217c478bd9Sstevel@tonic-gate  * Return the load memory address for the data segment.
4227c478bd9Sstevel@tonic-gate  */
4237c478bd9Sstevel@tonic-gate caddr_t
getdmem(struct exec * exp)4247c478bd9Sstevel@tonic-gate getdmem(struct exec *exp)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate 	/*
4277c478bd9Sstevel@tonic-gate 	 * XXX - Sparc Reference Hack approaching
4287c478bd9Sstevel@tonic-gate 	 * Remember that we are loading
4297c478bd9Sstevel@tonic-gate 	 * 8k executables into a 4k machine
4307c478bd9Sstevel@tonic-gate 	 * DATA_ALIGN == 2 * PAGESIZE
4317c478bd9Sstevel@tonic-gate 	 */
4327c478bd9Sstevel@tonic-gate 	if (exp->a_text)
4337c478bd9Sstevel@tonic-gate 		return ((caddr_t)(roundup(USRTEXT + exp->a_text, DATA_ALIGN)));
4347c478bd9Sstevel@tonic-gate 	else
4357c478bd9Sstevel@tonic-gate 		return ((caddr_t)USRTEXT);
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate /*
4397c478bd9Sstevel@tonic-gate  * Return the starting disk address for the data segment.
4407c478bd9Sstevel@tonic-gate  */
4417c478bd9Sstevel@tonic-gate ulong_t
getdfile(struct exec * exp)4427c478bd9Sstevel@tonic-gate getdfile(struct exec *exp)
4437c478bd9Sstevel@tonic-gate {
4447c478bd9Sstevel@tonic-gate 	if (exp->a_magic == ZMAGIC)
4457c478bd9Sstevel@tonic-gate 		return (exp->a_text);
4467c478bd9Sstevel@tonic-gate 	else
4477c478bd9Sstevel@tonic-gate 		return (sizeof (struct exec) + exp->a_text);
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate /*
4517c478bd9Sstevel@tonic-gate  * Return the load memory address for the text segment.
4527c478bd9Sstevel@tonic-gate  */
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4557c478bd9Sstevel@tonic-gate caddr_t
gettmem(struct exec * exp)4567c478bd9Sstevel@tonic-gate gettmem(struct exec *exp)
4577c478bd9Sstevel@tonic-gate {
4587c478bd9Sstevel@tonic-gate 	return ((caddr_t)USRTEXT);
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate /*
4627c478bd9Sstevel@tonic-gate  * Return the file byte offset for the text segment.
4637c478bd9Sstevel@tonic-gate  */
4647c478bd9Sstevel@tonic-gate uint_t
gettfile(struct exec * exp)4657c478bd9Sstevel@tonic-gate gettfile(struct exec *exp)
4667c478bd9Sstevel@tonic-gate {
4677c478bd9Sstevel@tonic-gate 	if (exp->a_magic == ZMAGIC)
4687c478bd9Sstevel@tonic-gate 		return (0);
4697c478bd9Sstevel@tonic-gate 	else
4707c478bd9Sstevel@tonic-gate 		return (sizeof (struct exec));
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate void
getexinfo(struct exdata * edp_in,struct exdata * edp_out,int * pagetext,int * pagedata)4747c478bd9Sstevel@tonic-gate getexinfo(
4757c478bd9Sstevel@tonic-gate 	struct exdata *edp_in,
4767c478bd9Sstevel@tonic-gate 	struct exdata *edp_out,
4777c478bd9Sstevel@tonic-gate 	int *pagetext,
4787c478bd9Sstevel@tonic-gate 	int *pagedata)
4797c478bd9Sstevel@tonic-gate {
4807c478bd9Sstevel@tonic-gate 	*edp_out = *edp_in;	/* structure copy */
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	if ((edp_in->ux_mag == ZMAGIC) &&
4837c478bd9Sstevel@tonic-gate 	    ((edp_in->vp->v_flag & VNOMAP) == 0)) {
4847c478bd9Sstevel@tonic-gate 		*pagetext = 1;
4857c478bd9Sstevel@tonic-gate 		*pagedata = 1;
4867c478bd9Sstevel@tonic-gate 	} else {
4877c478bd9Sstevel@tonic-gate 		*pagetext = 0;
4887c478bd9Sstevel@tonic-gate 		*pagedata = 0;
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate 
492ec25b48fSsusans /*
493ec25b48fSsusans  * Return non 0 value if the address may cause a VAC alias with KPM mappings.
494ec25b48fSsusans  * KPM selects an address such that it's equal offset modulo shm_alignment and
495ec25b48fSsusans  * assumes it can't be in VAC conflict with any larger than PAGESIZE mapping.
496ec25b48fSsusans  */
497ec25b48fSsusans int
map_addr_vacalign_check(caddr_t addr,u_offset_t off)498ec25b48fSsusans map_addr_vacalign_check(caddr_t addr, u_offset_t off)
4997c478bd9Sstevel@tonic-gate {
500ec25b48fSsusans 	if (vac) {
501ec25b48fSsusans 		return (((uintptr_t)addr ^ off) & shm_alignment - 1);
502ec25b48fSsusans 	} else {
503ec25b48fSsusans 		return (0);
504ec25b48fSsusans 	}
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate 
507ec25b48fSsusans /*
508ec25b48fSsusans  * Sanity control. Don't use large pages regardless of user
509ec25b48fSsusans  * settings if there's less than priv or shm_lpg_min_physmem memory installed.
510ec25b48fSsusans  * The units for this variable is 8K pages.
511ec25b48fSsusans  */
512ec25b48fSsusans pgcnt_t shm_lpg_min_physmem = 131072;			/* 1GB */
513ec25b48fSsusans pgcnt_t privm_lpg_min_physmem = 131072;			/* 1GB */
5147c478bd9Sstevel@tonic-gate 
515e12a8a13Ssusans static size_t
map_pgszheap(struct proc * p,caddr_t addr,size_t len)5167c478bd9Sstevel@tonic-gate map_pgszheap(struct proc *p, caddr_t addr, size_t len)
5177c478bd9Sstevel@tonic-gate {
518ec25b48fSsusans 	size_t		pgsz = MMU_PAGESIZE;
519ec25b48fSsusans 	int		szc;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	/*
5227c478bd9Sstevel@tonic-gate 	 * If len is zero, retrieve from proc and don't demote the page size.
523ec25b48fSsusans 	 * Use atleast the default pagesize.
5247c478bd9Sstevel@tonic-gate 	 */
5257c478bd9Sstevel@tonic-gate 	if (len == 0) {
526ec25b48fSsusans 		len = p->p_brkbase + p->p_brksize - p->p_bssbase;
527ec25b48fSsusans 	}
528ec25b48fSsusans 	len = MAX(len, default_uheap_lpsize);
529ec25b48fSsusans 
530ec25b48fSsusans 	for (szc = mmu_page_sizes - 1; szc >= 0; szc--) {
531ec25b48fSsusans 		pgsz = hw_page_array[szc].hp_size;
532ec25b48fSsusans 		if ((disable_auto_data_large_pages & (1 << szc)) ||
533ec25b48fSsusans 		    pgsz > max_uheap_lpsize)
534ec25b48fSsusans 			continue;
535ec25b48fSsusans 		if (len >= pgsz) {
536ec25b48fSsusans 			break;
537ec25b48fSsusans 		}
5387c478bd9Sstevel@tonic-gate 	}
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	/*
541ec25b48fSsusans 	 * If addr == 0 we were called by memcntl() when the
5427c478bd9Sstevel@tonic-gate 	 * size code is 0.  Don't set pgsz less than current size.
5437c478bd9Sstevel@tonic-gate 	 */
5447c478bd9Sstevel@tonic-gate 	if (addr == 0 && (pgsz < hw_page_array[p->p_brkpageszc].hp_size)) {
5457c478bd9Sstevel@tonic-gate 		pgsz = hw_page_array[p->p_brkpageszc].hp_size;
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	return (pgsz);
5497c478bd9Sstevel@tonic-gate }
5507c478bd9Sstevel@tonic-gate 
551e12a8a13Ssusans static size_t
map_pgszstk(struct proc * p,caddr_t addr,size_t len)5527c478bd9Sstevel@tonic-gate map_pgszstk(struct proc *p, caddr_t addr, size_t len)
5537c478bd9Sstevel@tonic-gate {
554ec25b48fSsusans 	size_t		pgsz = MMU_PAGESIZE;
555ec25b48fSsusans 	int		szc;
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	/*
5587c478bd9Sstevel@tonic-gate 	 * If len is zero, retrieve from proc and don't demote the page size.
559ec25b48fSsusans 	 * Use atleast the default pagesize.
5607c478bd9Sstevel@tonic-gate 	 */
5617c478bd9Sstevel@tonic-gate 	if (len == 0) {
5627c478bd9Sstevel@tonic-gate 		len = p->p_stksize;
5637c478bd9Sstevel@tonic-gate 	}
564ec25b48fSsusans 	len = MAX(len, default_ustack_lpsize);
5657c478bd9Sstevel@tonic-gate 
566ec25b48fSsusans 	for (szc = mmu_page_sizes - 1; szc >= 0; szc--) {
567ec25b48fSsusans 		pgsz = hw_page_array[szc].hp_size;
568ec25b48fSsusans 		if ((disable_auto_data_large_pages & (1 << szc)) ||
569ec25b48fSsusans 		    pgsz > max_ustack_lpsize)
570ec25b48fSsusans 			continue;
571ec25b48fSsusans 		if (len >= pgsz) {
572ec25b48fSsusans 			break;
5737c478bd9Sstevel@tonic-gate 		}
5747c478bd9Sstevel@tonic-gate 	}
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	/*
5777c478bd9Sstevel@tonic-gate 	 * If addr == 0 we were called by memcntl() or exec_args() when the
5787c478bd9Sstevel@tonic-gate 	 * size code is 0.  Don't set pgsz less than current size.
5797c478bd9Sstevel@tonic-gate 	 */
5807c478bd9Sstevel@tonic-gate 	if (addr == 0 && (pgsz < hw_page_array[p->p_stkpageszc].hp_size)) {
5817c478bd9Sstevel@tonic-gate 		pgsz = hw_page_array[p->p_stkpageszc].hp_size;
5827c478bd9Sstevel@tonic-gate 	}
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	return (pgsz);
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate 
587e12a8a13Ssusans static size_t
map_pgszism(caddr_t addr,size_t len)588e12a8a13Ssusans map_pgszism(caddr_t addr, size_t len)
589e12a8a13Ssusans {
590e12a8a13Ssusans 	uint_t szc;
591e12a8a13Ssusans 	size_t pgsz;
592e12a8a13Ssusans 
593e12a8a13Ssusans 	for (szc = mmu_page_sizes - 1; szc >= TTE4M; szc--) {
594e12a8a13Ssusans 		if (disable_ism_large_pages & (1 << szc))
595e12a8a13Ssusans 			continue;
596e12a8a13Ssusans 
597e12a8a13Ssusans 		pgsz = hw_page_array[szc].hp_size;
598e12a8a13Ssusans 		if ((len >= pgsz) && IS_P2ALIGNED(addr, pgsz))
599e12a8a13Ssusans 			return (pgsz);
600e12a8a13Ssusans 	}
601ec25b48fSsusans 
602e12a8a13Ssusans 	return (DEFAULT_ISM_PAGESIZE);
603e12a8a13Ssusans }
604e12a8a13Ssusans 
605e12a8a13Ssusans /*
606e12a8a13Ssusans  * Suggest a page size to be used to map a segment of type maptype and length
607e12a8a13Ssusans  * len.  Returns a page size (not a size code).
608e12a8a13Ssusans  */
609ec25b48fSsusans /* ARGSUSED */
610e12a8a13Ssusans size_t
map_pgsz(int maptype,struct proc * p,caddr_t addr,size_t len,int memcntl)611ec25b48fSsusans map_pgsz(int maptype, struct proc *p, caddr_t addr, size_t len, int memcntl)
612e12a8a13Ssusans {
613ec25b48fSsusans 	size_t	pgsz = MMU_PAGESIZE;
614e12a8a13Ssusans 
615ec25b48fSsusans 	ASSERT(maptype != MAPPGSZ_VA);
616ec25b48fSsusans 
617ec25b48fSsusans 	if (maptype != MAPPGSZ_ISM && physmem < privm_lpg_min_physmem) {
618ec25b48fSsusans 		return (MMU_PAGESIZE);
619ec25b48fSsusans 	}
620e12a8a13Ssusans 
621e12a8a13Ssusans 	switch (maptype) {
622e12a8a13Ssusans 	case MAPPGSZ_ISM:
623e12a8a13Ssusans 		pgsz = map_pgszism(addr, len);
624e12a8a13Ssusans 		break;
625e12a8a13Ssusans 
626e12a8a13Ssusans 	case MAPPGSZ_STK:
627ec25b48fSsusans 		if (max_ustack_lpsize > MMU_PAGESIZE) {
628e12a8a13Ssusans 			pgsz = map_pgszstk(p, addr, len);
629ec25b48fSsusans 		}
630e12a8a13Ssusans 		break;
631e12a8a13Ssusans 
632e12a8a13Ssusans 	case MAPPGSZ_HEAP:
633ec25b48fSsusans 		if (max_uheap_lpsize > MMU_PAGESIZE) {
634e12a8a13Ssusans 			pgsz = map_pgszheap(p, addr, len);
635ec25b48fSsusans 		}
636e12a8a13Ssusans 		break;
637e12a8a13Ssusans 	}
638e12a8a13Ssusans 	return (pgsz);
639e12a8a13Ssusans }
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate /* assumes TTE8K...TTE4M == szc */
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate static uint_t
map_szcvec(caddr_t addr,size_t size,uintptr_t off,int disable_lpgs,size_t max_lpsize,size_t min_physmem)645ec25b48fSsusans map_szcvec(caddr_t addr, size_t size, uintptr_t off, int disable_lpgs,
646ec25b48fSsusans     size_t max_lpsize, size_t min_physmem)
64707b65a64Saguzovsk {
64807b65a64Saguzovsk 	caddr_t eaddr = addr + size;
64907b65a64Saguzovsk 	uint_t szcvec = 0;
65007b65a64Saguzovsk 	caddr_t raddr;
65107b65a64Saguzovsk 	caddr_t readdr;
65207b65a64Saguzovsk 	size_t pgsz;
653ec25b48fSsusans 	int i;
65407b65a64Saguzovsk 
655ec25b48fSsusans 	if (physmem < min_physmem || max_lpsize <= MMU_PAGESIZE) {
65607b65a64Saguzovsk 		return (0);
65707b65a64Saguzovsk 	}
65807b65a64Saguzovsk 	for (i = mmu_page_sizes - 1; i > 0; i--) {
659ec25b48fSsusans 		if (disable_lpgs & (1 << i)) {
66007b65a64Saguzovsk 			continue;
66107b65a64Saguzovsk 		}
66207b65a64Saguzovsk 		pgsz = page_get_pagesize(i);
663ec25b48fSsusans 		if (pgsz > max_lpsize) {
66407b65a64Saguzovsk 			continue;
66507b65a64Saguzovsk 		}
66607b65a64Saguzovsk 		raddr = (caddr_t)P2ROUNDUP((uintptr_t)addr, pgsz);
66707b65a64Saguzovsk 		readdr = (caddr_t)P2ALIGN((uintptr_t)eaddr, pgsz);
66807b65a64Saguzovsk 		if (raddr < addr || raddr >= readdr) {
66907b65a64Saguzovsk 			continue;
67007b65a64Saguzovsk 		}
67107b65a64Saguzovsk 		if (P2PHASE((uintptr_t)addr ^ off, pgsz)) {
67207b65a64Saguzovsk 			continue;
67307b65a64Saguzovsk 		}
67407b65a64Saguzovsk 		szcvec |= (1 << i);
67507b65a64Saguzovsk 		/*
67607b65a64Saguzovsk 		 * And or in the remaining enabled page sizes.
67707b65a64Saguzovsk 		 */
678ec25b48fSsusans 		szcvec |= P2PHASE(~disable_lpgs, (1 << i));
67907b65a64Saguzovsk 		szcvec &= ~1; /* no need to return 8K pagesize */
68007b65a64Saguzovsk 		break;
68107b65a64Saguzovsk 	}
68207b65a64Saguzovsk 	return (szcvec);
68307b65a64Saguzovsk }
68407b65a64Saguzovsk 
6857c478bd9Sstevel@tonic-gate /*
686ec25b48fSsusans  * Return a bit vector of large page size codes that
687ec25b48fSsusans  * can be used to map [addr, addr + len) region.
688ec25b48fSsusans  */
689ec25b48fSsusans /* ARGSUSED */
690ec25b48fSsusans uint_t
map_pgszcvec(caddr_t addr,size_t size,uintptr_t off,int flags,int type,int memcntl)691ec25b48fSsusans map_pgszcvec(caddr_t addr, size_t size, uintptr_t off, int flags, int type,
692ec25b48fSsusans     int memcntl)
693ec25b48fSsusans {
694ec25b48fSsusans 	if (flags & MAP_TEXT) {
695986fd29aSsetje 		return (map_szcvec(addr, size, off,
696986fd29aSsetje 		    disable_auto_text_large_pages,
697ec25b48fSsusans 		    max_utext_lpsize, shm_lpg_min_physmem));
698ec25b48fSsusans 
699ec25b48fSsusans 	} else if (flags & MAP_INITDATA) {
700986fd29aSsetje 		return (map_szcvec(addr, size, off,
701986fd29aSsetje 		    disable_auto_data_large_pages,
702ec25b48fSsusans 		    max_uidata_lpsize, privm_lpg_min_physmem));
703ec25b48fSsusans 
704ec25b48fSsusans 	} else if (type == MAPPGSZC_SHM) {
705986fd29aSsetje 		return (map_szcvec(addr, size, off,
706986fd29aSsetje 		    disable_auto_data_large_pages,
707ec25b48fSsusans 		    max_shm_lpsize, shm_lpg_min_physmem));
708ec25b48fSsusans 
709ec25b48fSsusans 	} else if (type == MAPPGSZC_HEAP) {
710986fd29aSsetje 		return (map_szcvec(addr, size, off,
711986fd29aSsetje 		    disable_auto_data_large_pages,
712ec25b48fSsusans 		    max_uheap_lpsize, privm_lpg_min_physmem));
713ec25b48fSsusans 
714ec25b48fSsusans 	} else if (type == MAPPGSZC_STACK) {
715986fd29aSsetje 		return (map_szcvec(addr, size, off,
716986fd29aSsetje 		    disable_auto_data_large_pages,
717ec25b48fSsusans 		    max_ustack_lpsize, privm_lpg_min_physmem));
718ec25b48fSsusans 
719ec25b48fSsusans 	} else {
720986fd29aSsetje 		return (map_szcvec(addr, size, off,
721986fd29aSsetje 		    disable_auto_data_large_pages,
722ec25b48fSsusans 		    max_privmap_lpsize, privm_lpg_min_physmem));
723ec25b48fSsusans 	}
724ec25b48fSsusans }
725ec25b48fSsusans 
726ec25b48fSsusans /*
727d94ffb28Sjmcp  * Anchored in the table below are counters used to keep track
728d94ffb28Sjmcp  * of free contiguous physical memory. Each element of the table contains
729d94ffb28Sjmcp  * the array of counters, the size of array which is allocated during
730d94ffb28Sjmcp  * startup based on physmax and a shift value used to convert a pagenum
731d94ffb28Sjmcp  * into a counter array index or vice versa. The table has page size
732d94ffb28Sjmcp  * for rows and region size for columns:
733d94ffb28Sjmcp  *
734d94ffb28Sjmcp  *	page_counters[page_size][region_size]
735d94ffb28Sjmcp  *
736d94ffb28Sjmcp  *	page_size: 	TTE size code of pages on page_size freelist.
737d94ffb28Sjmcp  *
738d94ffb28Sjmcp  *	region_size:	TTE size code of a candidate larger page made up
739d94ffb28Sjmcp  *			made up of contiguous free page_size pages.
740d94ffb28Sjmcp  *
741d94ffb28Sjmcp  * As you go across a page_size row increasing region_size each
742d94ffb28Sjmcp  * element keeps track of how many (region_size - 1) size groups
743d94ffb28Sjmcp  * made up of page_size free pages can be coalesced into a
744d94ffb28Sjmcp  * regsion_size page. Yuck! Lets try an example:
745d94ffb28Sjmcp  *
746d94ffb28Sjmcp  * 	page_counters[1][3] is the table element used for identifying
747d94ffb28Sjmcp  *	candidate 4M pages from contiguous pages off the 64K free list.
748d94ffb28Sjmcp  *	Each index in the page_counters[1][3].array spans 4M. Its the
749d94ffb28Sjmcp  *	number of free 512K size (regsion_size - 1) groups of contiguous
750d94ffb28Sjmcp  *	64K free pages.	So when page_counters[1][3].counters[n] == 8
751d94ffb28Sjmcp  *	we know we have a candidate 4M page made up of 512K size groups
752d94ffb28Sjmcp  *	of 64K free pages.
753d94ffb28Sjmcp  */
754d94ffb28Sjmcp 
755d94ffb28Sjmcp /*
756d94ffb28Sjmcp  * Per page size free lists. 3rd (max_mem_nodes) and 4th (page coloring bins)
757d94ffb28Sjmcp  * dimensions are allocated dynamically.
758d94ffb28Sjmcp  */
759d94ffb28Sjmcp page_t ***page_freelists[MMU_PAGE_SIZES][MAX_MEM_TYPES];
760d94ffb28Sjmcp 
761d94ffb28Sjmcp /*
7627c478bd9Sstevel@tonic-gate  * For now there is only a single size cache list.
7637c478bd9Sstevel@tonic-gate  * Allocated dynamically.
7647c478bd9Sstevel@tonic-gate  */
7657c478bd9Sstevel@tonic-gate page_t ***page_cachelists[MAX_MEM_TYPES];
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate kmutex_t *fpc_mutex[NPC_MUTEX];
7687c478bd9Sstevel@tonic-gate kmutex_t *cpc_mutex[NPC_MUTEX];
7697c478bd9Sstevel@tonic-gate 
770986fd29aSsetje /*
771986fd29aSsetje  * Calculate space needed for page freelists and counters
772986fd29aSsetje  */
773986fd29aSsetje size_t
calc_free_pagelist_sz(void)774986fd29aSsetje calc_free_pagelist_sz(void)
7757c478bd9Sstevel@tonic-gate {
776986fd29aSsetje 	int szc;
777986fd29aSsetje 	size_t alloc_sz, cache_sz, free_sz;
7787c478bd9Sstevel@tonic-gate 
779986fd29aSsetje 	/*
780986fd29aSsetje 	 * one cachelist per color, node, and type
781986fd29aSsetje 	 */
782986fd29aSsetje 	cache_sz = (page_get_pagecolors(0) * sizeof (page_t *)) +
783986fd29aSsetje 	    sizeof (page_t **);
784986fd29aSsetje 	cache_sz *= max_mem_nodes * MAX_MEM_TYPES;
785986fd29aSsetje 
786986fd29aSsetje 	/*
787986fd29aSsetje 	 * one freelist per size, color, node, and type
788986fd29aSsetje 	 */
789986fd29aSsetje 	free_sz = sizeof (page_t **);
790986fd29aSsetje 	for (szc = 0; szc < mmu_page_sizes; szc++)
791986fd29aSsetje 		free_sz += sizeof (page_t *) * page_get_pagecolors(szc);
792986fd29aSsetje 	free_sz *= max_mem_nodes * MAX_MEM_TYPES;
793986fd29aSsetje 
794986fd29aSsetje 	alloc_sz = cache_sz + free_sz + page_ctrs_sz();
795986fd29aSsetje 	return (alloc_sz);
796986fd29aSsetje }
797986fd29aSsetje 
798986fd29aSsetje caddr_t
alloc_page_freelists(caddr_t alloc_base)799986fd29aSsetje alloc_page_freelists(caddr_t alloc_base)
800986fd29aSsetje {
801986fd29aSsetje 	int	mnode, mtype;
802986fd29aSsetje 	int	szc, clrs;
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	/*
8057c478bd9Sstevel@tonic-gate 	 * We only support small pages in the cachelist.
8067c478bd9Sstevel@tonic-gate 	 */
8077c478bd9Sstevel@tonic-gate 	for (mtype = 0; mtype < MAX_MEM_TYPES; mtype++) {
808986fd29aSsetje 		page_cachelists[mtype] = (page_t ***)alloc_base;
809986fd29aSsetje 		alloc_base += (max_mem_nodes * sizeof (page_t **));
810986fd29aSsetje 		for (mnode = 0; mnode < max_mem_nodes; mnode++) {
8117c478bd9Sstevel@tonic-gate 			page_cachelists[mtype][mnode] = (page_t **)alloc_base;
812986fd29aSsetje 			alloc_base +=
813986fd29aSsetje 			    (page_get_pagecolors(0) * sizeof (page_t *));
814986fd29aSsetje 		}
815986fd29aSsetje 	}
816986fd29aSsetje 
8177c478bd9Sstevel@tonic-gate 	/*
8187c478bd9Sstevel@tonic-gate 	 * Allocate freelists bins for all
8197c478bd9Sstevel@tonic-gate 	 * supported page sizes.
8207c478bd9Sstevel@tonic-gate 	 */
8217c478bd9Sstevel@tonic-gate 	for (szc = 0; szc < mmu_page_sizes; szc++) {
822986fd29aSsetje 		clrs = page_get_pagecolors(szc);
823986fd29aSsetje 		for (mtype = 0; mtype < MAX_MEM_TYPES; mtype++) {
824d94ffb28Sjmcp 			page_freelists[szc][mtype] = (page_t ***)alloc_base;
825986fd29aSsetje 			alloc_base += (max_mem_nodes * sizeof (page_t **));
826986fd29aSsetje 			for (mnode = 0; mnode < max_mem_nodes; mnode++) {
827d94ffb28Sjmcp 				page_freelists[szc][mtype][mnode] =
8287c478bd9Sstevel@tonic-gate 				    (page_t **)alloc_base;
829986fd29aSsetje 				alloc_base += (clrs * (sizeof (page_t *)));
830986fd29aSsetje 			}
8317c478bd9Sstevel@tonic-gate 		}
8327c478bd9Sstevel@tonic-gate 	}
8337c478bd9Sstevel@tonic-gate 
834986fd29aSsetje 	alloc_base = page_ctrs_alloc(alloc_base);
8357c478bd9Sstevel@tonic-gate 	return (alloc_base);
8367c478bd9Sstevel@tonic-gate }
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate /*
839986fd29aSsetje  * Allocate page_freelists locks for a memnode from the nucleus data
840986fd29aSsetje  * area. This is the first time that mmu_page_sizes is used during
841986fd29aSsetje  * bootup, so check mmu_page_sizes initialization.
8427c478bd9Sstevel@tonic-gate  */
8437c478bd9Sstevel@tonic-gate int
ndata_alloc_page_mutexs(struct memlist * ndata)844986fd29aSsetje ndata_alloc_page_mutexs(struct memlist *ndata)
8457c478bd9Sstevel@tonic-gate {
8467c478bd9Sstevel@tonic-gate 	size_t alloc_sz;
8477c478bd9Sstevel@tonic-gate 	caddr_t alloc_base;
848986fd29aSsetje 	int	i;
849986fd29aSsetje 	void	page_coloring_init();
8507c478bd9Sstevel@tonic-gate 
851986fd29aSsetje 	page_coloring_init();
8527c478bd9Sstevel@tonic-gate 	if (&mmu_init_mmu_page_sizes) {
853986fd29aSsetje 		if (!mmu_init_mmu_page_sizes(0)) {
8547c478bd9Sstevel@tonic-gate 			cmn_err(CE_PANIC, "mmu_page_sizes %d not initialized",
8557c478bd9Sstevel@tonic-gate 			    mmu_page_sizes);
8567c478bd9Sstevel@tonic-gate 		}
8577c478bd9Sstevel@tonic-gate 	}
8587c478bd9Sstevel@tonic-gate 	ASSERT(mmu_page_sizes >= DEFAULT_MMU_PAGE_SIZES);
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	/* fpc_mutex and cpc_mutex */
861986fd29aSsetje 	alloc_sz = 2 * NPC_MUTEX * max_mem_nodes * sizeof (kmutex_t);
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 	alloc_base = ndata_alloc(ndata, alloc_sz, ecache_alignsize);
8647c478bd9Sstevel@tonic-gate 	if (alloc_base == NULL)
8657c478bd9Sstevel@tonic-gate 		return (-1);
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	ASSERT(((uintptr_t)alloc_base & (ecache_alignsize - 1)) == 0);
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 	for (i = 0; i < NPC_MUTEX; i++) {
8707c478bd9Sstevel@tonic-gate 		fpc_mutex[i] = (kmutex_t *)alloc_base;
8717c478bd9Sstevel@tonic-gate 		alloc_base += (sizeof (kmutex_t) * max_mem_nodes);
8727c478bd9Sstevel@tonic-gate 		cpc_mutex[i] = (kmutex_t *)alloc_base;
8737c478bd9Sstevel@tonic-gate 		alloc_base += (sizeof (kmutex_t) * max_mem_nodes);
8747c478bd9Sstevel@tonic-gate 	}
8757c478bd9Sstevel@tonic-gate 	return (0);
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate /*
8797c478bd9Sstevel@tonic-gate  * To select our starting bin, we stride through the bins with a stride
8807c478bd9Sstevel@tonic-gate  * of 337.  Why 337?  It's prime, it's largeish, and it performs well both
8817c478bd9Sstevel@tonic-gate  * in simulation and practice for different workloads on varying cache sizes.
8827c478bd9Sstevel@tonic-gate  */
8837c478bd9Sstevel@tonic-gate uint32_t color_start_current = 0;
8847c478bd9Sstevel@tonic-gate uint32_t color_start_stride = 337;
8857c478bd9Sstevel@tonic-gate int color_start_random = 0;
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate /* ARGSUSED */
8887c478bd9Sstevel@tonic-gate uint_t
get_color_start(struct as * as)8897c478bd9Sstevel@tonic-gate get_color_start(struct as *as)
8907c478bd9Sstevel@tonic-gate {
8917c478bd9Sstevel@tonic-gate 	uint32_t old, new;
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	if (consistent_coloring == 2 || color_start_random) {
8947c478bd9Sstevel@tonic-gate 		return ((uint_t)(((gettick()) << (vac_shift - MMU_PAGESHIFT)) &
8955d07b933Sdp78419 		    (hw_page_array[0].hp_colors - 1)));
8967c478bd9Sstevel@tonic-gate 	}
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	do {
8997c478bd9Sstevel@tonic-gate 		old = color_start_current;
9007c478bd9Sstevel@tonic-gate 		new = old + (color_start_stride << (vac_shift - MMU_PAGESHIFT));
901*75d94465SJosef 'Jeff' Sipek 	} while (atomic_cas_32(&color_start_current, old, new) != old);
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	return ((uint_t)(new));
9047c478bd9Sstevel@tonic-gate }
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate /*
9077c478bd9Sstevel@tonic-gate  * Called once at startup from kphysm_init() -- before memialloc()
9087c478bd9Sstevel@tonic-gate  * is invoked to do the 1st page_free()/page_freelist_add().
9097c478bd9Sstevel@tonic-gate  *
9107c478bd9Sstevel@tonic-gate  * initializes page_colors and page_colors_mask based on ecache_setsize.
9117c478bd9Sstevel@tonic-gate  *
9127c478bd9Sstevel@tonic-gate  * Also initializes the counter locks.
9137c478bd9Sstevel@tonic-gate  */
9147c478bd9Sstevel@tonic-gate void
page_coloring_init()9157c478bd9Sstevel@tonic-gate page_coloring_init()
9167c478bd9Sstevel@tonic-gate {
9175d07b933Sdp78419 	int	a, i;
9185d07b933Sdp78419 	uint_t colors;
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	if (do_pg_coloring == 0) {
9217c478bd9Sstevel@tonic-gate 		page_colors = 1;
922102033aaSdp78419 		for (i = 0; i < mmu_page_sizes; i++) {
923102033aaSdp78419 			colorequivszc[i] = 0;
9245d07b933Sdp78419 			hw_page_array[i].hp_colors = 1;
925102033aaSdp78419 		}
9267c478bd9Sstevel@tonic-gate 		return;
9277c478bd9Sstevel@tonic-gate 	}
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 	/*
9307c478bd9Sstevel@tonic-gate 	 * Calculate page_colors from ecache_setsize. ecache_setsize contains
9317c478bd9Sstevel@tonic-gate 	 * the max ecache setsize of all cpus configured in the system or, for
9327c478bd9Sstevel@tonic-gate 	 * cheetah+ systems, the max possible ecache setsize for all possible
9337c478bd9Sstevel@tonic-gate 	 * cheetah+ cpus.
9347c478bd9Sstevel@tonic-gate 	 */
9357c478bd9Sstevel@tonic-gate 	page_colors = ecache_setsize / MMU_PAGESIZE;
9367c478bd9Sstevel@tonic-gate 	page_colors_mask = page_colors - 1;
9377c478bd9Sstevel@tonic-gate 
9385d07b933Sdp78419 	vac_colors = vac_size / MMU_PAGESIZE;
9395d07b933Sdp78419 	vac_colors_mask = vac_colors -1;
9405d07b933Sdp78419 
9415d07b933Sdp78419 	page_coloring_shift = 0;
9425d07b933Sdp78419 	a = ecache_setsize;
9435d07b933Sdp78419 	while (a >>= 1) {
9445d07b933Sdp78419 		page_coloring_shift++;
9455d07b933Sdp78419 	}
9465d07b933Sdp78419 
9475d07b933Sdp78419 	/* initialize number of colors per page size */
9485d07b933Sdp78419 	for (i = 0; i < mmu_page_sizes; i++) {
9495d07b933Sdp78419 		hw_page_array[i].hp_colors = (page_colors_mask >>
9505d07b933Sdp78419 		    (hw_page_array[i].hp_shift - hw_page_array[0].hp_shift))
9515d07b933Sdp78419 		    + 1;
952102033aaSdp78419 		colorequivszc[i] = 0;
9535d07b933Sdp78419 	}
9545d07b933Sdp78419 
9557c478bd9Sstevel@tonic-gate 	/*
9567c478bd9Sstevel@tonic-gate 	 * initialize cpu_page_colors if ecache setsizes are homogenous.
9577c478bd9Sstevel@tonic-gate 	 * cpu_page_colors set to -1 during DR operation or during startup
9587c478bd9Sstevel@tonic-gate 	 * if setsizes are heterogenous.
9597c478bd9Sstevel@tonic-gate 	 *
9607c478bd9Sstevel@tonic-gate 	 * The value of cpu_page_colors determines if additional color bins
9617c478bd9Sstevel@tonic-gate 	 * need to be checked for a particular color in the page_get routines.
9627c478bd9Sstevel@tonic-gate 	 */
963102033aaSdp78419 	if (cpu_setsize > 0 && cpu_page_colors == 0 &&
964102033aaSdp78419 	    cpu_setsize < ecache_setsize) {
9657c478bd9Sstevel@tonic-gate 		cpu_page_colors = cpu_setsize / MMU_PAGESIZE;
9665d07b933Sdp78419 		a = lowbit(page_colors) - lowbit(cpu_page_colors);
9675d07b933Sdp78419 		ASSERT(a > 0);
9685d07b933Sdp78419 		ASSERT(a < 16);
9697c478bd9Sstevel@tonic-gate 
9705d07b933Sdp78419 		for (i = 0; i < mmu_page_sizes; i++) {
9715d07b933Sdp78419 			if ((colors = hw_page_array[i].hp_colors) <= 1) {
9725d07b933Sdp78419 				continue;
9735d07b933Sdp78419 			}
9745d07b933Sdp78419 			while ((colors >> a) == 0)
9755d07b933Sdp78419 				a--;
9765d07b933Sdp78419 			ASSERT(a >= 0);
9777c478bd9Sstevel@tonic-gate 
9785d07b933Sdp78419 			/* higher 4 bits encodes color equiv mask */
9795d07b933Sdp78419 			colorequivszc[i] = (a << 4);
9805d07b933Sdp78419 		}
9815d07b933Sdp78419 	}
9825d07b933Sdp78419 
9835d07b933Sdp78419 	/* do cpu specific color initialization */
9845d07b933Sdp78419 	if (&page_coloring_init_cpu) {
9855d07b933Sdp78419 		page_coloring_init_cpu();
9867c478bd9Sstevel@tonic-gate 	}
9877c478bd9Sstevel@tonic-gate }
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate int
bp_color(struct buf * bp)9907c478bd9Sstevel@tonic-gate bp_color(struct buf *bp)
9917c478bd9Sstevel@tonic-gate {
9927c478bd9Sstevel@tonic-gate 	int color = -1;
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 	if (vac) {
9957c478bd9Sstevel@tonic-gate 		if ((bp->b_flags & B_PAGEIO) != 0) {
9967c478bd9Sstevel@tonic-gate 			color = sfmmu_get_ppvcolor(bp->b_pages);
9977c478bd9Sstevel@tonic-gate 		} else if (bp->b_un.b_addr != NULL) {
9987c478bd9Sstevel@tonic-gate 			color = sfmmu_get_addrvcolor(bp->b_un.b_addr);
9997c478bd9Sstevel@tonic-gate 		}
10007c478bd9Sstevel@tonic-gate 	}
10017c478bd9Sstevel@tonic-gate 	return (color < 0 ? 0 : ptob(color));
10027c478bd9Sstevel@tonic-gate }
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate /*
10057c478bd9Sstevel@tonic-gate  * Function for flushing D-cache when performing module relocations
10067c478bd9Sstevel@tonic-gate  * to an alternate mapping.  Stubbed out on all platforms except sun4u,
10077c478bd9Sstevel@tonic-gate  * at least for now.
10087c478bd9Sstevel@tonic-gate  */
10097c478bd9Sstevel@tonic-gate void
dcache_flushall()10107c478bd9Sstevel@tonic-gate dcache_flushall()
10117c478bd9Sstevel@tonic-gate {
10127c478bd9Sstevel@tonic-gate 	sfmmu_cache_flushall();
10137c478bd9Sstevel@tonic-gate }
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate static int
kdi_range_overlap(uintptr_t va1,size_t sz1,uintptr_t va2,size_t sz2)10167c478bd9Sstevel@tonic-gate kdi_range_overlap(uintptr_t va1, size_t sz1, uintptr_t va2, size_t sz2)
10177c478bd9Sstevel@tonic-gate {
10187c478bd9Sstevel@tonic-gate 	if (va1 < va2 && va1 + sz1 <= va2)
10197c478bd9Sstevel@tonic-gate 		return (0);
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	if (va2 < va1 && va2 + sz2 <= va1)
10227c478bd9Sstevel@tonic-gate 		return (0);
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	return (1);
10257c478bd9Sstevel@tonic-gate }
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate /*
10287c478bd9Sstevel@tonic-gate  * Return the number of bytes, relative to the beginning of a given range, that
10297c478bd9Sstevel@tonic-gate  * are non-toxic (can be read from and written to with relative impunity).
10307c478bd9Sstevel@tonic-gate  */
10317c478bd9Sstevel@tonic-gate size_t
kdi_range_is_nontoxic(uintptr_t va,size_t sz,int write)10327c478bd9Sstevel@tonic-gate kdi_range_is_nontoxic(uintptr_t va, size_t sz, int write)
10337c478bd9Sstevel@tonic-gate {
10347c478bd9Sstevel@tonic-gate 	/* OBP reads are harmless, but we don't want people writing there */
10357c478bd9Sstevel@tonic-gate 	if (write && kdi_range_overlap(va, sz, OFW_START_ADDR, OFW_END_ADDR -
10367c478bd9Sstevel@tonic-gate 	    OFW_START_ADDR + 1))
10377c478bd9Sstevel@tonic-gate 		return (va < OFW_START_ADDR ? OFW_START_ADDR - va : 0);
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	if (kdi_range_overlap(va, sz, PIOMAPBASE, PIOMAPSIZE))
10407c478bd9Sstevel@tonic-gate 		return (va < PIOMAPBASE ? PIOMAPBASE - va : 0);
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	return (sz); /* no overlap */
10437c478bd9Sstevel@tonic-gate }
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate /*
10467c478bd9Sstevel@tonic-gate  * Minimum physmem required for enabling large pages for kernel heap
10477c478bd9Sstevel@tonic-gate  * Currently we do not enable lp for kmem on systems with less
10487c478bd9Sstevel@tonic-gate  * than 1GB of memory. This value can be changed via /etc/system
10497c478bd9Sstevel@tonic-gate  */
10507c478bd9Sstevel@tonic-gate size_t segkmem_lpminphysmem = 0x40000000;	/* 1GB */
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate /*
10537c478bd9Sstevel@tonic-gate  * this function chooses large page size for kernel heap
10547c478bd9Sstevel@tonic-gate  */
10557c478bd9Sstevel@tonic-gate size_t
get_segkmem_lpsize(size_t lpsize)10567c478bd9Sstevel@tonic-gate get_segkmem_lpsize(size_t lpsize)
10577c478bd9Sstevel@tonic-gate {
10587c478bd9Sstevel@tonic-gate 	size_t memtotal = physmem * PAGESIZE;
1059d0662dbfSelowe 	size_t mmusz;
1060d0662dbfSelowe 	uint_t szc;
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	if (memtotal < segkmem_lpminphysmem)
10637c478bd9Sstevel@tonic-gate 		return (PAGESIZE);
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 	if (plat_lpkmem_is_supported != NULL &&
10667c478bd9Sstevel@tonic-gate 	    plat_lpkmem_is_supported() == 0)
10677c478bd9Sstevel@tonic-gate 		return (PAGESIZE);
10687c478bd9Sstevel@tonic-gate 
1069d0662dbfSelowe 	mmusz = mmu_get_kernel_lpsize(lpsize);
1070d0662dbfSelowe 	szc = page_szc(mmusz);
1071d0662dbfSelowe 
1072d0662dbfSelowe 	while (szc) {
1073d0662dbfSelowe 		if (!(disable_large_pages & (1 << szc)))
1074d0662dbfSelowe 			return (page_get_pagesize(szc));
1075d0662dbfSelowe 		szc--;
1076d0662dbfSelowe 	}
1077d0662dbfSelowe 	return (PAGESIZE);
10787c478bd9Sstevel@tonic-gate }
1079