xref: /titanic_51/usr/src/lib/libbc/libc/gen/common/plock.c (revision 5d54f3d8999eac1762fe0a8c7177d20f1f201fae)
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
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*5d54f3d8Smuffin  * Copyright 1989 Sun Microsystems, Inc.  All rights reserved.
24*5d54f3d8Smuffin  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27*5d54f3d8Smuffin #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*5d54f3d8Smuffin 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * plock - lock "segments" in physical memory.
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  * Supports SVID-compatible plock, taking into account dynamically linked
337c478bd9Sstevel@tonic-gate  * objects (such as shared libraries).
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include <sys/types.h>
377c478bd9Sstevel@tonic-gate #include <sys/mman.h>
387c478bd9Sstevel@tonic-gate #include <sys/lock.h>
397c478bd9Sstevel@tonic-gate #include <sys/time.h>
407c478bd9Sstevel@tonic-gate #include <sys/resource.h>
417c478bd9Sstevel@tonic-gate #include <machine/param.h>
427c478bd9Sstevel@tonic-gate #include <machine/vmparam.h>
437c478bd9Sstevel@tonic-gate #include <a.out.h>
447c478bd9Sstevel@tonic-gate #include <link.h>
457c478bd9Sstevel@tonic-gate #include <errno.h>
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate /*
487c478bd9Sstevel@tonic-gate  * Globals we reference.
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate extern	struct link_dynamic _DYNAMIC;
517c478bd9Sstevel@tonic-gate extern	int mlock();
527c478bd9Sstevel@tonic-gate extern	int munlock();
53*5d54f3d8Smuffin extern	caddr_t sbrk();		/* find end of data segment */
54*5d54f3d8Smuffin extern	caddr_t etext;		/* end of text segment */
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /*
577c478bd9Sstevel@tonic-gate  * Module-scope variables.
587c478bd9Sstevel@tonic-gate  */
597c478bd9Sstevel@tonic-gate static	int page_size = 0;		/* cached result of getpagesize() */
607c478bd9Sstevel@tonic-gate static	int lock_state = 0;		/* lock state */
617c478bd9Sstevel@tonic-gate static	int state_pid = -1;		/* pid to which state belongs */
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate  * Local worker routine to lock text and data segments.  Handles
657c478bd9Sstevel@tonic-gate  * dynamically loaded objects.  This routine is highly dependent
667c478bd9Sstevel@tonic-gate  * on executable format and layout.
67*5d54f3d8Smuffin  *
68*5d54f3d8Smuffin  * Arguments:
69*5d54f3d8Smuffin  *	op:	desired operation
70*5d54f3d8Smuffin  *	f:	function to perform
717c478bd9Sstevel@tonic-gate  */
727c478bd9Sstevel@tonic-gate static int
73*5d54f3d8Smuffin apply_lock(int op, int (*f)(caddr_t, u_int))
747c478bd9Sstevel@tonic-gate {
757c478bd9Sstevel@tonic-gate 	int	e = 0;			/* return value */
767c478bd9Sstevel@tonic-gate 	caddr_t	a;			/* address of operation */
777c478bd9Sstevel@tonic-gate 	u_int	l;			/* length of operation */
787c478bd9Sstevel@tonic-gate 	struct	link_map *lmp;		/* link map walker */
797c478bd9Sstevel@tonic-gate 	struct	exec *eh;		/* exec header */
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	/*
827c478bd9Sstevel@tonic-gate 	 * Operate on application segment first.
837c478bd9Sstevel@tonic-gate 	 */
847c478bd9Sstevel@tonic-gate 	switch (op) {
857c478bd9Sstevel@tonic-gate 	case TXTLOCK:
867c478bd9Sstevel@tonic-gate 		a = (caddr_t)USRTEXT;	/* note: old Sun-2 not handled */
877c478bd9Sstevel@tonic-gate 		l = (u_int)&etext -  USRTEXT;
887c478bd9Sstevel@tonic-gate 		break;
897c478bd9Sstevel@tonic-gate 	case DATLOCK:
907c478bd9Sstevel@tonic-gate 		a = (caddr_t)(((int)&etext + (SEGSIZ - 1)) & ~(SEGSIZ - 1));
917c478bd9Sstevel@tonic-gate 		l = (u_int)(sbrk(0) - a);
927c478bd9Sstevel@tonic-gate 		break;
937c478bd9Sstevel@tonic-gate 	}
947c478bd9Sstevel@tonic-gate 	l = (l + (page_size - 1)) & (u_int)~(page_size - 1);
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	/*
977c478bd9Sstevel@tonic-gate 	 * Perform the operation -- if failure, return immediately.
987c478bd9Sstevel@tonic-gate 	 */
997c478bd9Sstevel@tonic-gate 	if (e = (*f)(a, l))
1007c478bd9Sstevel@tonic-gate 		return (e);
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	/*
1037c478bd9Sstevel@tonic-gate 	 * If we're not a dynamically linked program, we are finished.
1047c478bd9Sstevel@tonic-gate 	 */
1057c478bd9Sstevel@tonic-gate 	if (&_DYNAMIC == 0)
1067c478bd9Sstevel@tonic-gate 		return (0);
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	/*
1097c478bd9Sstevel@tonic-gate 	 * Find the list of dynamically linked objects.  If we get
1107c478bd9Sstevel@tonic-gate 	 * dynamic linking formats we don't recognize, then punt.
1117c478bd9Sstevel@tonic-gate 	 */
1127c478bd9Sstevel@tonic-gate 	switch (_DYNAMIC.ld_version) {
1137c478bd9Sstevel@tonic-gate 	case 2:
114*5d54f3d8Smuffin #if	defined(__sparc)
1157c478bd9Sstevel@tonic-gate 	case 3:
116*5d54f3d8Smuffin #endif	/* __sparc */
1177c478bd9Sstevel@tonic-gate 		lmp = _DYNAMIC.ld_un.ld_2->ld_loaded;
1187c478bd9Sstevel@tonic-gate 		break;
1197c478bd9Sstevel@tonic-gate 	default:
1207c478bd9Sstevel@tonic-gate 		return (0);
1217c478bd9Sstevel@tonic-gate 	}
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	/*
1247c478bd9Sstevel@tonic-gate 	 * Loop over all objects.  Extract the addresses and lengths as
1257c478bd9Sstevel@tonic-gate 	 * required, and perform the appropriate operation.
1267c478bd9Sstevel@tonic-gate 	 */
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	while (lmp) {
1297c478bd9Sstevel@tonic-gate 		eh = (struct exec *)lmp->lm_addr;
1307c478bd9Sstevel@tonic-gate 		switch (op) {
1317c478bd9Sstevel@tonic-gate 		case TXTLOCK:
1327c478bd9Sstevel@tonic-gate 			a = (caddr_t)eh;
1337c478bd9Sstevel@tonic-gate 			l = (u_int)eh->a_text;
1347c478bd9Sstevel@tonic-gate 			break;
1357c478bd9Sstevel@tonic-gate 		case DATLOCK:
1367c478bd9Sstevel@tonic-gate 			a = (caddr_t)((u_int)eh + N_DATADDR(*eh) -
1377c478bd9Sstevel@tonic-gate 			    N_TXTADDR(*eh));
1387c478bd9Sstevel@tonic-gate 			l = (u_int)eh->a_data + (u_int)eh->a_bss;
1397c478bd9Sstevel@tonic-gate 			break;
1407c478bd9Sstevel@tonic-gate 		}
1417c478bd9Sstevel@tonic-gate 		l = (l + (page_size - 1)) & ~(page_size - 1);
1427c478bd9Sstevel@tonic-gate 		if (e = (*f)(a, l))
1437c478bd9Sstevel@tonic-gate 			return (e);
1447c478bd9Sstevel@tonic-gate 		lmp = lmp->lm_next;
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate 	return (0);
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * plock
151*5d54f3d8Smuffin  *
152*5d54f3d8Smuffin  * Argument:
153*5d54f3d8Smuffin  *	op:	desired operation
1547c478bd9Sstevel@tonic-gate  */
1557c478bd9Sstevel@tonic-gate int
156*5d54f3d8Smuffin plock(int op)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate 	int 	e = 0;			/* return value */
1597c478bd9Sstevel@tonic-gate 	int	pid;			/* current pid */
1607c478bd9Sstevel@tonic-gate 	caddr_t	a1, a2;			/* loop variables */
1617c478bd9Sstevel@tonic-gate 	struct	rlimit rl;		/* resource limit */
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	/*
1647c478bd9Sstevel@tonic-gate 	 * Initialize static caches.
1657c478bd9Sstevel@tonic-gate 	 */
1667c478bd9Sstevel@tonic-gate 	if (page_size == 0)
1677c478bd9Sstevel@tonic-gate 		page_size = getpagesize();
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	/*
1707c478bd9Sstevel@tonic-gate 	 * Validate state of lock's.  If parent has forked, then
1717c478bd9Sstevel@tonic-gate 	 * the lock state needs to be reset (children do not inherit
1727c478bd9Sstevel@tonic-gate 	 * memory locks, and thus do not inherit their state).
1737c478bd9Sstevel@tonic-gate 	 */
1747c478bd9Sstevel@tonic-gate 	if ((pid = getpid()) != state_pid) {
1757c478bd9Sstevel@tonic-gate 		lock_state = 0;
1767c478bd9Sstevel@tonic-gate 		state_pid = pid;
1777c478bd9Sstevel@tonic-gate 	}
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	/*
1807c478bd9Sstevel@tonic-gate 	 * Dispatch on operation.  Note: plock and its relatives depend
1817c478bd9Sstevel@tonic-gate 	 * upon "op" being bit encoded.
1827c478bd9Sstevel@tonic-gate 	 */
1837c478bd9Sstevel@tonic-gate 	switch (op) {
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	/*
1867c478bd9Sstevel@tonic-gate 	 * UNLOCK: remove all memory locks.  Requires that some be set!
1877c478bd9Sstevel@tonic-gate 	 */
1887c478bd9Sstevel@tonic-gate 	case UNLOCK:
1897c478bd9Sstevel@tonic-gate 		if (lock_state == 0) {
1907c478bd9Sstevel@tonic-gate 			errno = EINVAL;
1917c478bd9Sstevel@tonic-gate 			return (-1);
1927c478bd9Sstevel@tonic-gate 		}
1937c478bd9Sstevel@tonic-gate 		if (e = munlockall())
1947c478bd9Sstevel@tonic-gate 			return (-1);
1957c478bd9Sstevel@tonic-gate 		else {
1967c478bd9Sstevel@tonic-gate 			lock_state = 0;
1977c478bd9Sstevel@tonic-gate 			return (0);
1987c478bd9Sstevel@tonic-gate 		}
1997c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	/*
2027c478bd9Sstevel@tonic-gate 	 * TXTLOCK: locks text segments.
2037c478bd9Sstevel@tonic-gate 	 */
2047c478bd9Sstevel@tonic-gate 	case TXTLOCK:
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 		/*
2077c478bd9Sstevel@tonic-gate 		 * If a text or process lock is already set, then fail.
2087c478bd9Sstevel@tonic-gate 		 */
2097c478bd9Sstevel@tonic-gate 		if ((lock_state & TXTLOCK) || (lock_state & PROCLOCK)) {
2107c478bd9Sstevel@tonic-gate 			errno = EINVAL;
2117c478bd9Sstevel@tonic-gate 			return (-1);
2127c478bd9Sstevel@tonic-gate 		}
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 		/*
2157c478bd9Sstevel@tonic-gate 		 * Try to apply the lock(s).  If a failure occurs,
2167c478bd9Sstevel@tonic-gate 		 * back them out.  On success, remember that a text
2177c478bd9Sstevel@tonic-gate 		 * lock was set.
2187c478bd9Sstevel@tonic-gate 		 */
2197c478bd9Sstevel@tonic-gate 		if (e = apply_lock(op, mlock))
2207c478bd9Sstevel@tonic-gate 			(void) apply_lock(op, munlock);
2217c478bd9Sstevel@tonic-gate 		else
2227c478bd9Sstevel@tonic-gate 			lock_state |= TXTLOCK;
2237c478bd9Sstevel@tonic-gate 		return (e);
2247c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	/*
2277c478bd9Sstevel@tonic-gate 	 * DATLOCK: locks data segment(s), including the stack and all
2287c478bd9Sstevel@tonic-gate 	 * future growth in the address space.
2297c478bd9Sstevel@tonic-gate 	 */
2307c478bd9Sstevel@tonic-gate 	case DATLOCK:
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 		/*
2337c478bd9Sstevel@tonic-gate 		 * If a data or process lock is already set, then fail.
2347c478bd9Sstevel@tonic-gate 		 */
2357c478bd9Sstevel@tonic-gate 		if ((lock_state & DATLOCK) || (lock_state & PROCLOCK)) {
2367c478bd9Sstevel@tonic-gate 			errno = EINVAL;
2377c478bd9Sstevel@tonic-gate 			return (-1);
2387c478bd9Sstevel@tonic-gate 		}
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 		/*
2417c478bd9Sstevel@tonic-gate 		 * Try to lock the data segments.  On failure, back out
2427c478bd9Sstevel@tonic-gate 		 * the locks and return.
2437c478bd9Sstevel@tonic-gate 		 */
2447c478bd9Sstevel@tonic-gate 		if (e = apply_lock(op, mlock)) {
2457c478bd9Sstevel@tonic-gate 			(void) apply_lock(op, munlock);
2467c478bd9Sstevel@tonic-gate 			return (-1);
2477c478bd9Sstevel@tonic-gate 		}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 		/*
2507c478bd9Sstevel@tonic-gate 		 * Try to lock the stack segment.  Find out the extent
2517c478bd9Sstevel@tonic-gate 		 * and start of the stack (there should be a function for
2527c478bd9Sstevel@tonic-gate 		 * this!) and then iterate over the pages of the stack
2537c478bd9Sstevel@tonic-gate 		 * locking them.  The stack *could* be sparely populated.
2547c478bd9Sstevel@tonic-gate 		 * Ignore lock failures resulting from the absence of a
2557c478bd9Sstevel@tonic-gate 		 * mapping.
2567c478bd9Sstevel@tonic-gate 		 */
2577c478bd9Sstevel@tonic-gate 		(void) getrlimit(RLIMIT_STACK, &rl);
2587c478bd9Sstevel@tonic-gate 		for (a1 = (caddr_t)USRSTACK - page_size;
2597c478bd9Sstevel@tonic-gate 		    a1 != (caddr_t)USRSTACK - rl.rlim_cur; a1 -= page_size)
2607c478bd9Sstevel@tonic-gate 			if (e = mlock(a1, page_size)) {
2617c478bd9Sstevel@tonic-gate 				if (errno == ENOMEM)
2627c478bd9Sstevel@tonic-gate 					e = 0;
2637c478bd9Sstevel@tonic-gate 				break;
2647c478bd9Sstevel@tonic-gate 			}
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 		/*
2677c478bd9Sstevel@tonic-gate 		 * If we were successful in locking the stack, then
2687c478bd9Sstevel@tonic-gate 		 * try to set a lock for all future mappings.
2697c478bd9Sstevel@tonic-gate 		 */
2707c478bd9Sstevel@tonic-gate 		if (!e)
2717c478bd9Sstevel@tonic-gate 			e = mlockall(MCL_FUTURE);
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 		/*
2747c478bd9Sstevel@tonic-gate 		 * If failures have occurred, back out the locks
2757c478bd9Sstevel@tonic-gate 		 * and return failure.
2767c478bd9Sstevel@tonic-gate 		 */
2777c478bd9Sstevel@tonic-gate 		if (e) {
2787c478bd9Sstevel@tonic-gate 			e = errno;
2797c478bd9Sstevel@tonic-gate 			(void) apply_lock(op, munlock);
2807c478bd9Sstevel@tonic-gate 			for (a2 = (caddr_t)USRSTACK - page_size; a2 != a1;
2817c478bd9Sstevel@tonic-gate 			    a2 -= page_size)
2827c478bd9Sstevel@tonic-gate 				(void) munlock(a2, page_size);
2837c478bd9Sstevel@tonic-gate 			errno = e;
2847c478bd9Sstevel@tonic-gate 			return (-1);
2857c478bd9Sstevel@tonic-gate 		}
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 		/*
2887c478bd9Sstevel@tonic-gate 		 * Data, stack, and growth have been locked.  Set state
2897c478bd9Sstevel@tonic-gate 		 * and return success.
2907c478bd9Sstevel@tonic-gate 		 */
2917c478bd9Sstevel@tonic-gate 		lock_state |= DATLOCK;
2927c478bd9Sstevel@tonic-gate 		return (0);
2937c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	/*
2967c478bd9Sstevel@tonic-gate 	 * PROCLOCK: lock everything, and all future things as well.
2977c478bd9Sstevel@tonic-gate 	 * There should be nothing locked when this is called.
2987c478bd9Sstevel@tonic-gate 	 */
2997c478bd9Sstevel@tonic-gate 	case PROCLOCK:
3007c478bd9Sstevel@tonic-gate 		if (lock_state) {
3017c478bd9Sstevel@tonic-gate 			errno = EINVAL;
3027c478bd9Sstevel@tonic-gate 			return (-1);
3037c478bd9Sstevel@tonic-gate 		}
3047c478bd9Sstevel@tonic-gate 		if (mlockall(MCL_CURRENT | MCL_FUTURE) == 0) {
3057c478bd9Sstevel@tonic-gate 			lock_state |= PROCLOCK;
3067c478bd9Sstevel@tonic-gate 			return (0);
3077c478bd9Sstevel@tonic-gate 		} else
3087c478bd9Sstevel@tonic-gate 			return (-1);
3097c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	/*
3127c478bd9Sstevel@tonic-gate 	 * Invalid operation.
3137c478bd9Sstevel@tonic-gate 	 */
3147c478bd9Sstevel@tonic-gate 	default:
3157c478bd9Sstevel@tonic-gate 		errno = EINVAL;
3167c478bd9Sstevel@tonic-gate 		return (-1);
3177c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
3187c478bd9Sstevel@tonic-gate 	}
3197c478bd9Sstevel@tonic-gate }
320