xref: /csrg-svn/sys/kern/subr_rmap.c.sav (revision 2781)
1*2781Swnj/*	subr_rmap.c.sav	4.2	02/28/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/*
13*2781Swnj * Resource map handling routines.
14*2781Swnj *
15*2781Swnj * A resource map is an array of structures each
16*2781Swnj * of which describes a segment of the address space of an available
17*2781Swnj * resource.  The segments are described by their base address and
18*2781Swnj * length, and sorted in address order.  Each resource map has a fixed
19*2781Swnj * maximum number of segments allowed.  Resources are allocated
20*2781Swnj * by taking part or all of one of the segments of the map.
21*2781Swnj *
22*2781Swnj * Returning of resources will require another segment if
23*2781Swnj * the returned resources are not adjacent in the address
24*2781Swnj * space to an existing segment.  If the return of a segment
25*2781Swnj * would require a slot which is not available, then one of
26*2781Swnj * the resource map segments is discarded after a warning is printed.
27*2781Swnj * Returning of resources may also cause the map to collapse
28*2781Swnj * by coalescing two existing segments and the returned space
29*2781Swnj * into a single segment.  In this case the resource map is
30*2781Swnj * made smaller by copying together to fill the resultant gap.
31*2781Swnj *
32*2781Swnj * N.B.: the current implementation uses a dense array and does
33*2781Swnj * not admit the value ``0'' as a legal address, since that is used
34*2781Swnj * as a delimiter.
35*2781Swnj */
36*2781Swnj
37*2781Swnj/*
38*2781Swnj * Initialize map mp to have (mapsize-2) segments
39*2781Swnj * and to be called ``name'', which we print if
40*2781Swnj * the slots become so fragmented that we lose space.
41*2781Swnj * The map itself is initialized with size elements free
42*2781Swnj * starting at addr.
43*2781Swnj */
44*2781Swnjrminit(mp, size, addr, name, mapsize)
45*2781Swnj	register struct map *mp;
46*2781Swnj	int size, addr;
47*2781Swnj	char *name;
48*2781Swnj	int mapsize;
49*2781Swnj{
50*2781Swnj	register struct mapent *ep = (struct mapent *)(mp+1);
51*2781Swnj
52*2781Swnj	mp->m_name = name;
53*2781Swnj/* N.B.: WE ASSUME HERE THAT sizeof (struct map) == sizeof (struct mapent) */
54*2781Swnj	/*
55*2781Swnj	 * One of the mapsize slots is taken by the map structure,
56*2781Swnj	 * segments has size 0 and addr 0, and acts as a delimiter.
57*2781Swnj	 * We insure that we never use segments past the end of
58*2781Swnj	 * the array which is given by mp->m_limit.
59*2781Swnj	 * Instead, when excess segments occur we discard some resources.
60*2781Swnj	 */
61*2781Swnj	mp->m_limit = (struct mapent *)&mp[mapsize];
62*2781Swnj	/*
63*2781Swnj	 * Simulate a rmfree(), but with the option to
64*2781Swnj	 * call with size 0 and addr 0 when we just want
65*2781Swnj	 * to initialize without freeing.
66*2781Swnj	 */
67*2781Swnj	ep->m_size = size;
68*2781Swnj	ep->m_addr = addr;
69*2781Swnj}
70*2781Swnj
71*2781Swnj/*
7227Sbill * Allocate 'size' units from the given
73*2781Swnj * 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.
76*2781Swnj *
7727Sbill * Algorithm is first-fit.
78*2781Swnj *
79*2781Swnj * This routine knows about the interleaving of the swapmap
80*2781Swnj * and handles that.
8127Sbill */
82*2781Swnjrmalloc(mp, size)
83*2781Swnj	register struct map *mp;
8427Sbill{
85*2781Swnj	register struct mapent *ep = (struct mapent *)(mp+1);
86*2781Swnj	register int addr;
87*2781Swnj	register struct mapent *bp;
88307Sbill	swblk_t first, rest;
8927Sbill
90307Sbill	if (size <= 0 || mp == swapmap && size > DMMAX)
91*2781Swnj		panic("rmalloc");
92*2781Swnj	/*
93*2781Swnj	 * Search for a piece of the resource map which has enough
94*2781Swnj	 * free space to accomodate the request.
95*2781Swnj	 */
96*2781Swnj	for (bp = ep; bp->m_size; bp++) {
9727Sbill		if (bp->m_size >= size) {
98*2781Swnj			/*
99*2781Swnj			 * If allocating from swapmap,
100*2781Swnj			 * then have to respect interleaving
101*2781Swnj			 * boundaries.
102*2781Swnj			 */
103307Sbill			if (mp == swapmap &&
104307Sbill			    (first = DMMAX - bp->m_addr%DMMAX) < bp->m_size) {
105307Sbill				if (bp->m_size - first < size)
106307Sbill					continue;
107*2781Swnj				addr = bp->m_addr + first;
108307Sbill				rest = bp->m_size - first - size;
109307Sbill				bp->m_size = first;
110307Sbill				if (rest)
111*2781Swnj					rmfree(swapmap, rest, addr+size);
112*2781Swnj				return (addr);
113307Sbill			}
114*2781Swnj			/*
115*2781Swnj			 * Allocate from the map.
116*2781Swnj			 * If there is no space left of the piece
117*2781Swnj			 * we allocated from, move the rest of
118*2781Swnj			 * the pieces to the left.
119*2781Swnj			 */
120*2781Swnj			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			}
128*2781Swnj			if (mp == swapmap && addr % CLSIZE)
129*2781Swnj				panic("rmalloc swapmap");
130*2781Swnj			return (addr);
13127Sbill		}
13227Sbill	}
133*2781Swnj	return (0);
13427Sbill}
13527Sbill
13627Sbill/*
137*2781Swnj * Free the previously allocated space at addr
13827Sbill * of size units into the specified map.
139*2781Swnj * Sort addr into map and combine on
14027Sbill * one or both ends if possible.
14127Sbill */
142*2781Swnjrmfree(mp, size, addr)
143*2781Swnj	struct map *mp;
144*2781Swnj	register int size, addr;
14527Sbill{
146*2781Swnj	struct mapent *firstbp;
147*2781Swnj	register struct mapent *bp;
14827Sbill	register int t;
14927Sbill
150*2781Swnj	/*
151*2781Swnj	 * Both address and size must be
152*2781Swnj	 * positive, or the protocol has broken down.
153*2781Swnj	 */
154*2781Swnj	if (addr <= 0 || size <= 0)
155*2781Swnj		goto badrmfree;
156*2781Swnj	/*
157*2781Swnj	 * Locate the piece of the map which starts after the
158*2781Swnj	 * returned space (or the end of the map).
159*2781Swnj	 */
160*2781Swnj	firstbp = bp = (struct mapent *)(mp + 1);
161*2781Swnj	for (; bp->m_addr <= addr && bp->m_size != 0; bp++)
16227Sbill		continue;
163*2781Swnj	/*
164*2781Swnj	 * If the piece on the left abuts us,
165*2781Swnj	 * then we should combine with it.
166*2781Swnj	 */
167*2781Swnj	if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) {
168*2781Swnj		/*
169*2781Swnj		 * Check no overlap (internal error).
170*2781Swnj		 */
171*2781Swnj		if ((bp-1)->m_addr+(bp-1)->m_size > addr)
172*2781Swnj			goto badrmfree;
173*2781Swnj		/*
174*2781Swnj		 * Add into piece on the left by increasing its size.
175*2781Swnj		 */
17627Sbill		(bp-1)->m_size += size;
177*2781Swnj		/*
178*2781Swnj		 * If the combined piece abuts the piece on
179*2781Swnj		 * the right now, compress it in also,
180*2781Swnj		 * by shifting the remaining pieces of the map over.
181*2781Swnj		 */
182*2781Swnj		if (bp->m_addr && addr+size >= bp->m_addr) {
183*2781Swnj			if (addr+size > bp->m_addr)
184*2781Swnj				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		}
192*2781Swnj		goto done;
19327Sbill	}
194*2781Swnj	/*
195*2781Swnj	 * Don't abut on the left, check for abutting on
196*2781Swnj	 * the right.
197*2781Swnj	 */
198*2781Swnj	if (addr+size >= bp->m_addr && bp->m_size) {
199*2781Swnj		if (addr+size > bp->m_addr)
200*2781Swnj			goto badrmfree;
201*2781Swnj		bp->m_addr -= size;
202*2781Swnj		bp->m_size += size;
203*2781Swnj		goto done;
204*2781Swnj	}
205*2781Swnj	/*
206*2781Swnj	 * Don't abut at all.  Make a new entry
207*2781Swnj	 * and check for map overflow.
208*2781Swnj	 */
209*2781Swnj	do {
210*2781Swnj		t = bp->m_addr;
211*2781Swnj		bp->m_addr = addr;
212*2781Swnj		addr = t;
213*2781Swnj		t = bp->m_size;
214*2781Swnj		bp->m_size = size;
215*2781Swnj		bp++;
216*2781Swnj	} while (size = t);
217*2781Swnj	/*
218*2781Swnj	 * Segment at bp is to be the delimiter;
219*2781Swnj	 * If there is not room for it
220*2781Swnj	 * then the table is too full
221*2781Swnj	 * and we must discard something.
222*2781Swnj	 */
223*2781Swnj	if (bp+1 > mp->m_limit) {
224*2781Swnj		/*
225*2781Swnj		 * Back bp up to last available segment.
226*2781Swnj		 * which contains a segment already and must
227*2781Swnj		 * be made into the delimiter.
228*2781Swnj		 * Discard second to last entry,
229*2781Swnj		 * since it is presumably smaller than the last
230*2781Swnj		 * and move the last entry back one.
231*2781Swnj		 */
232*2781Swnj		bp--;
233*2781Swnj		printf("%s rmap overflow, lost [%d,%d)\n", mp->m_name,
234*2781Swnj		    (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size);
235*2781Swnj		bp[-1] = bp[0];
236*2781Swnj		bp[0].m_size = bp[0].m_addr = 0;
237*2781Swnj	}
238*2781Swnjdone:
239*2781Swnj	/*
240*2781Swnj	 * THIS IS RIDICULOUS... IT DOESN'T BELONG HERE!
241*2781Swnj	 */
24227Sbill	if ((mp == kernelmap) && kmapwnt) {
24327Sbill		kmapwnt = 0;
24427Sbill		wakeup((caddr_t)kernelmap);
24527Sbill	}
246*2781Swnj	return;
247*2781Swnjbadrmfree:
248*2781Swnj	panic("bad rmfree");
24927Sbill}
250