xref: /csrg-svn/sys/kern/subr_rmap.c.sav (revision 8766)
1*8766Sroot/*	subr_rmap.c.sav	4.7	82/10/21	*/
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/text.h"
10*8766Sroot#include "../h/kernel.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 */
82*8766Srootlong
832781Swnjrmalloc(mp, size)
842781Swnj	register struct map *mp;
85*8766Sroot	long size;
8627Sbill{
872781Swnj	register struct mapent *ep = (struct mapent *)(mp+1);
882781Swnj	register int addr;
892781Swnj	register struct mapent *bp;
90307Sbill	swblk_t first, rest;
9127Sbill
92307Sbill	if (size <= 0 || mp == swapmap && size > DMMAX)
932781Swnj		panic("rmalloc");
942781Swnj	/*
952781Swnj	 * Search for a piece of the resource map which has enough
962781Swnj	 * free space to accomodate the request.
972781Swnj	 */
982781Swnj	for (bp = ep; bp->m_size; bp++) {
9927Sbill		if (bp->m_size >= size) {
1002781Swnj			/*
1012781Swnj			 * If allocating from swapmap,
1022781Swnj			 * then have to respect interleaving
1032781Swnj			 * boundaries.
1042781Swnj			 */
105307Sbill			if (mp == swapmap &&
106307Sbill			    (first = DMMAX - bp->m_addr%DMMAX) < bp->m_size) {
107307Sbill				if (bp->m_size - first < size)
108307Sbill					continue;
1092781Swnj				addr = bp->m_addr + first;
110307Sbill				rest = bp->m_size - first - size;
111307Sbill				bp->m_size = first;
112307Sbill				if (rest)
1132781Swnj					rmfree(swapmap, rest, addr+size);
1142781Swnj				return (addr);
115307Sbill			}
1162781Swnj			/*
1172781Swnj			 * Allocate from the map.
1182781Swnj			 * If there is no space left of the piece
1192781Swnj			 * we allocated from, move the rest of
1202781Swnj			 * the pieces to the left.
1212781Swnj			 */
1222781Swnj			addr = bp->m_addr;
12327Sbill			bp->m_addr += size;
12427Sbill			if ((bp->m_size -= size) == 0) {
12527Sbill				do {
12627Sbill					bp++;
12727Sbill					(bp-1)->m_addr = bp->m_addr;
12827Sbill				} while ((bp-1)->m_size = bp->m_size);
12927Sbill			}
1302781Swnj			if (mp == swapmap && addr % CLSIZE)
1312781Swnj				panic("rmalloc swapmap");
1322781Swnj			return (addr);
13327Sbill		}
13427Sbill	}
1352781Swnj	return (0);
13627Sbill}
13727Sbill
13827Sbill/*
1392781Swnj * Free the previously allocated space at addr
14027Sbill * of size units into the specified map.
1412781Swnj * Sort addr into map and combine on
14227Sbill * one or both ends if possible.
14327Sbill */
1442781Swnjrmfree(mp, size, addr)
1452781Swnj	struct map *mp;
146*8766Sroot	long size, addr;
14727Sbill{
1482781Swnj	struct mapent *firstbp;
1492781Swnj	register struct mapent *bp;
15027Sbill	register int t;
15127Sbill
1522781Swnj	/*
1532781Swnj	 * Both address and size must be
1542781Swnj	 * positive, or the protocol has broken down.
1552781Swnj	 */
1562781Swnj	if (addr <= 0 || size <= 0)
1572781Swnj		goto badrmfree;
1582781Swnj	/*
1592781Swnj	 * Locate the piece of the map which starts after the
1602781Swnj	 * returned space (or the end of the map).
1612781Swnj	 */
1622781Swnj	firstbp = bp = (struct mapent *)(mp + 1);
1632781Swnj	for (; bp->m_addr <= addr && bp->m_size != 0; bp++)
16427Sbill		continue;
1652781Swnj	/*
1662781Swnj	 * If the piece on the left abuts us,
1672781Swnj	 * then we should combine with it.
1682781Swnj	 */
1692781Swnj	if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) {
1702781Swnj		/*
1712781Swnj		 * Check no overlap (internal error).
1722781Swnj		 */
1732781Swnj		if ((bp-1)->m_addr+(bp-1)->m_size > addr)
1742781Swnj			goto badrmfree;
1752781Swnj		/*
1762781Swnj		 * Add into piece on the left by increasing its size.
1772781Swnj		 */
17827Sbill		(bp-1)->m_size += size;
1792781Swnj		/*
1802781Swnj		 * If the combined piece abuts the piece on
1812781Swnj		 * the right now, compress it in also,
1822781Swnj		 * by shifting the remaining pieces of the map over.
1832781Swnj		 */
1842781Swnj		if (bp->m_addr && addr+size >= bp->m_addr) {
1852781Swnj			if (addr+size > bp->m_addr)
1862781Swnj				goto badrmfree;
18727Sbill			(bp-1)->m_size += bp->m_size;
18827Sbill			while (bp->m_size) {
18927Sbill				bp++;
19027Sbill				(bp-1)->m_addr = bp->m_addr;
19127Sbill				(bp-1)->m_size = bp->m_size;
19227Sbill			}
19327Sbill		}
1942781Swnj		goto done;
19527Sbill	}
1962781Swnj	/*
1972781Swnj	 * Don't abut on the left, check for abutting on
1982781Swnj	 * the right.
1992781Swnj	 */
2002781Swnj	if (addr+size >= bp->m_addr && bp->m_size) {
2012781Swnj		if (addr+size > bp->m_addr)
2022781Swnj			goto badrmfree;
2032781Swnj		bp->m_addr -= size;
2042781Swnj		bp->m_size += size;
2052781Swnj		goto done;
2062781Swnj	}
2072781Swnj	/*
2082781Swnj	 * Don't abut at all.  Make a new entry
2092781Swnj	 * and check for map overflow.
2102781Swnj	 */
2112781Swnj	do {
2122781Swnj		t = bp->m_addr;
2132781Swnj		bp->m_addr = addr;
2142781Swnj		addr = t;
2152781Swnj		t = bp->m_size;
2162781Swnj		bp->m_size = size;
2172781Swnj		bp++;
2182781Swnj	} while (size = t);
2192781Swnj	/*
2202781Swnj	 * Segment at bp is to be the delimiter;
2212781Swnj	 * If there is not room for it
2222781Swnj	 * then the table is too full
2232781Swnj	 * and we must discard something.
2242781Swnj	 */
2252781Swnj	if (bp+1 > mp->m_limit) {
2262781Swnj		/*
2272781Swnj		 * Back bp up to last available segment.
2282781Swnj		 * which contains a segment already and must
2292781Swnj		 * be made into the delimiter.
2302781Swnj		 * Discard second to last entry,
2312781Swnj		 * since it is presumably smaller than the last
2322781Swnj		 * and move the last entry back one.
2332781Swnj		 */
2342781Swnj		bp--;
2352937Swnj		printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name,
2362781Swnj		    (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size);
2372781Swnj		bp[-1] = bp[0];
2382781Swnj		bp[0].m_size = bp[0].m_addr = 0;
2392781Swnj	}
2402781Swnjdone:
2412781Swnj	/*
2422781Swnj	 * THIS IS RIDICULOUS... IT DOESN'T BELONG HERE!
2432781Swnj	 */
24427Sbill	if ((mp == kernelmap) && kmapwnt) {
24527Sbill		kmapwnt = 0;
24627Sbill		wakeup((caddr_t)kernelmap);
24727Sbill	}
2482781Swnj	return;
2492781Swnjbadrmfree:
2502781Swnj	panic("bad rmfree");
25127Sbill}
2526516Sfeldman
2536516Sfeldman/*
2546516Sfeldman * Allocate 'size' units from the given map, starting at address 'addr'.
2556516Sfeldman * Return 'addr' if successful, 0 if not.
2566516Sfeldman * This may cause the creation or destruction of a resource map segment.
2576516Sfeldman *
2586516Sfeldman * This routine will return failure status if there is not enough room
2596516Sfeldman * for a required additional map segment.
2606516Sfeldman *
2616516Sfeldman * An attempt to use this on 'swapmap' will result in
2626516Sfeldman * a failure return.  This is due mainly to laziness and could be fixed
2636516Sfeldman * to do the right thing, although it probably will never be used.
2646516Sfeldman */
2656516Sfeldmanrmget(mp, size, addr)
2666516Sfeldman	register struct map *mp;
2676516Sfeldman{
2686516Sfeldman	register struct mapent *ep = (struct mapent *)(mp+1);
2696516Sfeldman	register struct mapent *bp, *bp2;
2706516Sfeldman
2716516Sfeldman	if (size <= 0)
2726516Sfeldman		panic("rmget");
2736516Sfeldman	if (mp == swapmap)
2746516Sfeldman		return (0);
2756516Sfeldman	/*
2766516Sfeldman	 * Look for a map segment containing the requested address.
2776516Sfeldman	 * If none found, return failure.
2786516Sfeldman	 */
2796516Sfeldman	for (bp = ep; bp->m_size; bp++)
2806516Sfeldman		if (bp->m_addr <= addr && bp->m_addr + bp->m_size > addr)
2816516Sfeldman			break;
2826516Sfeldman	if (bp->m_size == 0)
2836516Sfeldman		return (0);
2846516Sfeldman
2856516Sfeldman	/*
2866516Sfeldman	 * If segment is too small, return failure.
2876516Sfeldman	 * If big enough, allocate the block, compressing or expanding
2886516Sfeldman	 * the map as necessary.
2896516Sfeldman	 */
2906516Sfeldman	if (bp->m_addr + bp->m_size < addr + size)
2916516Sfeldman		return (0);
2926516Sfeldman	if (bp->m_addr == addr)
2936516Sfeldman		if (bp->m_addr + bp->m_size == addr + size) {
2946516Sfeldman			/*
2956516Sfeldman			 * Allocate entire segment and compress map
2966516Sfeldman			 */
2976516Sfeldman			bp2 = bp;
2986516Sfeldman			while (bp2->m_size) {
2996516Sfeldman				bp2++;
3006516Sfeldman				(bp2-1)->m_addr = bp2->m_addr;
3016516Sfeldman				(bp2-1)->m_size = bp2->m_size;
3026516Sfeldman			}
3036516Sfeldman		} else {
3046516Sfeldman			/*
3056516Sfeldman			 * Allocate first part of segment
3066516Sfeldman			 */
3076516Sfeldman			bp->m_addr += size;
3086516Sfeldman			bp->m_size -= size;
3096516Sfeldman		}
3106516Sfeldman	else
3116516Sfeldman		if (bp->m_addr + bp->m_size == addr + size) {
3126516Sfeldman			/*
3136516Sfeldman			 * Allocate last part of segment
3146516Sfeldman			 */
3156516Sfeldman			bp->m_size -= size;
3166516Sfeldman		} else {
3176516Sfeldman			/*
3186516Sfeldman			 * Allocate from middle of segment, but only
3196516Sfeldman			 * if table can be expanded.
3206516Sfeldman			 */
3216516Sfeldman			for (bp2=bp; bp2->m_size; bp2++)
3226516Sfeldman				;
3236516Sfeldman			if (bp2 == mp->m_limit)
3246516Sfeldman				return (0);
3256516Sfeldman			while (bp2 > bp) {
3266516Sfeldman				(bp2+1)->m_addr = bp2->m_addr;
3276516Sfeldman				(bp2+1)->m_size = bp2->m_size;
3286516Sfeldman				bp2--;
3296516Sfeldman			}
3306516Sfeldman			(bp+1)->m_addr = addr + size;
3316516Sfeldman			(bp+1)->m_size =
3326516Sfeldman			    bp->m_addr + bp->m_size - (addr + size);
3336516Sfeldman			bp->m_size = addr - bp->m_addr;
3346516Sfeldman		}
3356516Sfeldman	return (addr);
3366516Sfeldman}
337