xref: /csrg-svn/sys/kern/subr_rmap.c (revision 2937)
1*2937Swnj /*	subr_rmap.c	4.3	03/06/81	*/
227Sbill 
327Sbill #include "../h/param.h"
427Sbill #include "../h/systm.h"
527Sbill #include "../h/map.h"
627Sbill #include "../h/dir.h"
727Sbill #include "../h/user.h"
827Sbill #include "../h/proc.h"
927Sbill #include "../h/mtpr.h"
1027Sbill #include "../h/text.h"
1127Sbill 
1227Sbill /*
132781Swnj  * Resource map handling routines.
142781Swnj  *
152781Swnj  * A resource map is an array of structures each
162781Swnj  * of which describes a segment of the address space of an available
172781Swnj  * resource.  The segments are described by their base address and
182781Swnj  * length, and sorted in address order.  Each resource map has a fixed
192781Swnj  * maximum number of segments allowed.  Resources are allocated
202781Swnj  * by taking part or all of one of the segments of the map.
212781Swnj  *
222781Swnj  * Returning of resources will require another segment if
232781Swnj  * the returned resources are not adjacent in the address
242781Swnj  * space to an existing segment.  If the return of a segment
252781Swnj  * would require a slot which is not available, then one of
262781Swnj  * the resource map segments is discarded after a warning is printed.
272781Swnj  * Returning of resources may also cause the map to collapse
282781Swnj  * by coalescing two existing segments and the returned space
292781Swnj  * into a single segment.  In this case the resource map is
302781Swnj  * made smaller by copying together to fill the resultant gap.
312781Swnj  *
322781Swnj  * N.B.: the current implementation uses a dense array and does
332781Swnj  * not admit the value ``0'' as a legal address, since that is used
342781Swnj  * as a delimiter.
352781Swnj  */
362781Swnj 
372781Swnj /*
382781Swnj  * Initialize map mp to have (mapsize-2) segments
392781Swnj  * and to be called ``name'', which we print if
402781Swnj  * the slots become so fragmented that we lose space.
412781Swnj  * The map itself is initialized with size elements free
422781Swnj  * starting at addr.
432781Swnj  */
442781Swnj rminit(mp, size, addr, name, mapsize)
452781Swnj 	register struct map *mp;
462781Swnj 	int size, addr;
472781Swnj 	char *name;
482781Swnj 	int mapsize;
492781Swnj {
502781Swnj 	register struct mapent *ep = (struct mapent *)(mp+1);
512781Swnj 
522781Swnj 	mp->m_name = name;
532781Swnj /* N.B.: WE ASSUME HERE THAT sizeof (struct map) == sizeof (struct mapent) */
542781Swnj 	/*
552781Swnj 	 * One of the mapsize slots is taken by the map structure,
562781Swnj 	 * segments has size 0 and addr 0, and acts as a delimiter.
572781Swnj 	 * We insure that we never use segments past the end of
582781Swnj 	 * the array which is given by mp->m_limit.
592781Swnj 	 * Instead, when excess segments occur we discard some resources.
602781Swnj 	 */
612781Swnj 	mp->m_limit = (struct mapent *)&mp[mapsize];
622781Swnj 	/*
632781Swnj 	 * Simulate a rmfree(), but with the option to
642781Swnj 	 * call with size 0 and addr 0 when we just want
652781Swnj 	 * to initialize without freeing.
662781Swnj 	 */
672781Swnj 	ep->m_size = size;
682781Swnj 	ep->m_addr = addr;
692781Swnj }
702781Swnj 
712781Swnj /*
7227Sbill  * Allocate 'size' units from the given
732781Swnj  * map. Return the base of the allocated space.
7427Sbill  * In a map, the addresses are increasing and the
7527Sbill  * list is terminated by a 0 size.
762781Swnj  *
7727Sbill  * Algorithm is first-fit.
782781Swnj  *
792781Swnj  * This routine knows about the interleaving of the swapmap
802781Swnj  * and handles that.
8127Sbill  */
822781Swnj rmalloc(mp, size)
832781Swnj 	register struct map *mp;
8427Sbill {
852781Swnj 	register struct mapent *ep = (struct mapent *)(mp+1);
862781Swnj 	register int addr;
872781Swnj 	register struct mapent *bp;
88307Sbill 	swblk_t first, rest;
8927Sbill 
90307Sbill 	if (size <= 0 || mp == swapmap && size > DMMAX)
912781Swnj 		panic("rmalloc");
922781Swnj 	/*
932781Swnj 	 * Search for a piece of the resource map which has enough
942781Swnj 	 * free space to accomodate the request.
952781Swnj 	 */
962781Swnj 	for (bp = ep; bp->m_size; bp++) {
9727Sbill 		if (bp->m_size >= size) {
982781Swnj 			/*
992781Swnj 			 * If allocating from swapmap,
1002781Swnj 			 * then have to respect interleaving
1012781Swnj 			 * boundaries.
1022781Swnj 			 */
103307Sbill 			if (mp == swapmap &&
104307Sbill 			    (first = DMMAX - bp->m_addr%DMMAX) < bp->m_size) {
105307Sbill 				if (bp->m_size - first < size)
106307Sbill 					continue;
1072781Swnj 				addr = bp->m_addr + first;
108307Sbill 				rest = bp->m_size - first - size;
109307Sbill 				bp->m_size = first;
110307Sbill 				if (rest)
1112781Swnj 					rmfree(swapmap, rest, addr+size);
1122781Swnj 				return (addr);
113307Sbill 			}
1142781Swnj 			/*
1152781Swnj 			 * Allocate from the map.
1162781Swnj 			 * If there is no space left of the piece
1172781Swnj 			 * we allocated from, move the rest of
1182781Swnj 			 * the pieces to the left.
1192781Swnj 			 */
1202781Swnj 			addr = bp->m_addr;
12127Sbill 			bp->m_addr += size;
12227Sbill 			if ((bp->m_size -= size) == 0) {
12327Sbill 				do {
12427Sbill 					bp++;
12527Sbill 					(bp-1)->m_addr = bp->m_addr;
12627Sbill 				} while ((bp-1)->m_size = bp->m_size);
12727Sbill 			}
1282781Swnj 			if (mp == swapmap && addr % CLSIZE)
1292781Swnj 				panic("rmalloc swapmap");
1302781Swnj 			return (addr);
13127Sbill 		}
13227Sbill 	}
1332781Swnj 	return (0);
13427Sbill }
13527Sbill 
13627Sbill /*
1372781Swnj  * Free the previously allocated space at addr
13827Sbill  * of size units into the specified map.
1392781Swnj  * Sort addr into map and combine on
14027Sbill  * one or both ends if possible.
14127Sbill  */
1422781Swnj rmfree(mp, size, addr)
1432781Swnj 	struct map *mp;
1442781Swnj 	register int size, addr;
14527Sbill {
1462781Swnj 	struct mapent *firstbp;
1472781Swnj 	register struct mapent *bp;
14827Sbill 	register int t;
14927Sbill 
1502781Swnj 	/*
1512781Swnj 	 * Both address and size must be
1522781Swnj 	 * positive, or the protocol has broken down.
1532781Swnj 	 */
1542781Swnj 	if (addr <= 0 || size <= 0)
1552781Swnj 		goto badrmfree;
1562781Swnj 	/*
1572781Swnj 	 * Locate the piece of the map which starts after the
1582781Swnj 	 * returned space (or the end of the map).
1592781Swnj 	 */
1602781Swnj 	firstbp = bp = (struct mapent *)(mp + 1);
1612781Swnj 	for (; bp->m_addr <= addr && bp->m_size != 0; bp++)
16227Sbill 		continue;
1632781Swnj 	/*
1642781Swnj 	 * If the piece on the left abuts us,
1652781Swnj 	 * then we should combine with it.
1662781Swnj 	 */
1672781Swnj 	if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) {
1682781Swnj 		/*
1692781Swnj 		 * Check no overlap (internal error).
1702781Swnj 		 */
1712781Swnj 		if ((bp-1)->m_addr+(bp-1)->m_size > addr)
1722781Swnj 			goto badrmfree;
1732781Swnj 		/*
1742781Swnj 		 * Add into piece on the left by increasing its size.
1752781Swnj 		 */
17627Sbill 		(bp-1)->m_size += size;
1772781Swnj 		/*
1782781Swnj 		 * If the combined piece abuts the piece on
1792781Swnj 		 * the right now, compress it in also,
1802781Swnj 		 * by shifting the remaining pieces of the map over.
1812781Swnj 		 */
1822781Swnj 		if (bp->m_addr && addr+size >= bp->m_addr) {
1832781Swnj 			if (addr+size > bp->m_addr)
1842781Swnj 				goto badrmfree;
18527Sbill 			(bp-1)->m_size += bp->m_size;
18627Sbill 			while (bp->m_size) {
18727Sbill 				bp++;
18827Sbill 				(bp-1)->m_addr = bp->m_addr;
18927Sbill 				(bp-1)->m_size = bp->m_size;
19027Sbill 			}
19127Sbill 		}
1922781Swnj 		goto done;
19327Sbill 	}
1942781Swnj 	/*
1952781Swnj 	 * Don't abut on the left, check for abutting on
1962781Swnj 	 * the right.
1972781Swnj 	 */
1982781Swnj 	if (addr+size >= bp->m_addr && bp->m_size) {
1992781Swnj 		if (addr+size > bp->m_addr)
2002781Swnj 			goto badrmfree;
2012781Swnj 		bp->m_addr -= size;
2022781Swnj 		bp->m_size += size;
2032781Swnj 		goto done;
2042781Swnj 	}
2052781Swnj 	/*
2062781Swnj 	 * Don't abut at all.  Make a new entry
2072781Swnj 	 * and check for map overflow.
2082781Swnj 	 */
2092781Swnj 	do {
2102781Swnj 		t = bp->m_addr;
2112781Swnj 		bp->m_addr = addr;
2122781Swnj 		addr = t;
2132781Swnj 		t = bp->m_size;
2142781Swnj 		bp->m_size = size;
2152781Swnj 		bp++;
2162781Swnj 	} while (size = t);
2172781Swnj 	/*
2182781Swnj 	 * Segment at bp is to be the delimiter;
2192781Swnj 	 * If there is not room for it
2202781Swnj 	 * then the table is too full
2212781Swnj 	 * and we must discard something.
2222781Swnj 	 */
2232781Swnj 	if (bp+1 > mp->m_limit) {
2242781Swnj 		/*
2252781Swnj 		 * Back bp up to last available segment.
2262781Swnj 		 * which contains a segment already and must
2272781Swnj 		 * be made into the delimiter.
2282781Swnj 		 * Discard second to last entry,
2292781Swnj 		 * since it is presumably smaller than the last
2302781Swnj 		 * and move the last entry back one.
2312781Swnj 		 */
2322781Swnj 		bp--;
233*2937Swnj 		printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name,
2342781Swnj 		    (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size);
2352781Swnj 		bp[-1] = bp[0];
2362781Swnj 		bp[0].m_size = bp[0].m_addr = 0;
2372781Swnj 	}
2382781Swnj done:
2392781Swnj 	/*
2402781Swnj 	 * THIS IS RIDICULOUS... IT DOESN'T BELONG HERE!
2412781Swnj 	 */
24227Sbill 	if ((mp == kernelmap) && kmapwnt) {
24327Sbill 		kmapwnt = 0;
24427Sbill 		wakeup((caddr_t)kernelmap);
24527Sbill 	}
2462781Swnj 	return;
2472781Swnj badrmfree:
2482781Swnj 	panic("bad rmfree");
24927Sbill }
250