xref: /csrg-svn/sys/kern/subr_rmap.c.sav (revision 2937)
1*2937Swnj/*	subr_rmap.c.sav	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 */
442781Swnjrminit(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 */
822781Swnjrmalloc(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 */
1422781Swnjrmfree(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	}
2382781Swnjdone:
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;
2472781Swnjbadrmfree:
2482781Swnj	panic("bad rmfree");
24927Sbill}
250