|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: *
6: * @(#)subr_rmap.c 7.4 (Berkeley) 5/15/90
7: */
8:
9: #include "param.h"
10: #include "systm.h"
11: #include "map.h"
12: #include "user.h"
13: #include "proc.h"
14: #include "text.h"
15: #include "kernel.h"
16:
17: /*
18: * Resource map handling routines.
19: *
20: * A resource map is an array of structures each
21: * of which describes a segment of the address space of an available
22: * resource. The segments are described by their base address and
23: * length, and sorted in address order. Each resource map has a fixed
24: * maximum number of segments allowed. Resources are allocated
25: * by taking part or all of one of the segments of the map.
26: *
27: * Returning of resources will require another segment if
28: * the returned resources are not adjacent in the address
29: * space to an existing segment. If the return of a segment
30: * would require a slot which is not available, then one of
31: * the resource map segments is discarded after a warning is printed.
32: * Returning of resources may also cause the map to collapse
33: * by coalescing two existing segments and the returned space
34: * into a single segment. In this case the resource map is
35: * made smaller by copying together to fill the resultant gap.
36: *
37: * N.B.: the current implementation uses a dense array and does
38: * not admit the value ``0'' as a legal address, since that is used
39: * as a delimiter.
40: */
41:
42: /*
43: * Initialize map mp to have (mapsize-2) segments
44: * and to be called ``name'', which we print if
45: * the slots become so fragmented that we lose space.
46: * The map itself is initialized with size elements free
47: * starting at addr.
48: */
49: rminit(mp, size, addr, name, mapsize)
50: register struct map *mp;
51: long size, addr;
52: char *name;
53: int mapsize;
54: {
55: register struct mapent *ep = (struct mapent *)(mp+1);
56:
57: mp->m_name = name;
58: /* N.B.: WE ASSUME HERE THAT sizeof (struct map) == sizeof (struct mapent) */
59: /*
60: * One of the mapsize slots is taken by the map structure,
61: * segments has size 0 and addr 0, and acts as a delimiter.
62: * We insure that we never use segments past the end of
63: * the array which is given by mp->m_limit.
64: * Instead, when excess segments occur we discard some resources.
65: */
66: mp->m_limit = (struct mapent *)&mp[mapsize];
67: /*
68: * Simulate a rmfree(), but with the option to
69: * call with size 0 and addr 0 when we just want
70: * to initialize without freeing.
71: */
72: ep->m_size = size;
73: ep->m_addr = addr;
74: (++ep)->m_size = 0;
75: ep->m_addr = 0;
76: }
77:
78: /*
79: * Allocate 'size' units from the given
80: * map. Return the base of the allocated space.
81: * In a map, the addresses are increasing and the
82: * list is terminated by a 0 size.
83: *
84: * Algorithm is first-fit.
85: *
86: * This routine knows about the interleaving of the swapmap
87: * and handles that.
88: */
89: long
90: rmalloc(mp, size)
91: register struct map *mp;
92: long size;
93: {
94: register struct mapent *ep = (struct mapent *)(mp+1);
95: register int addr;
96: register struct mapent *bp;
97: swblk_t first, rest;
98:
99: if (size <= 0 || mp == swapmap && size > dmmax)
100: panic("rmalloc");
101: /*
102: * Search for a piece of the resource map which has enough
103: * free space to accomodate the request.
104: */
105: for (bp = ep; bp->m_size; bp++) {
106: if (bp->m_size >= size) {
107: /*
108: * If allocating from swapmap,
109: * then have to respect interleaving
110: * boundaries.
111: */
112: if (mp == swapmap && nswdev > 1 &&
113: (first = dmmax - bp->m_addr%dmmax) < size) {
114: if (bp->m_size - first < size)
115: continue;
116: addr = bp->m_addr + first;
117: rest = bp->m_size - first - size;
118: bp->m_size = first;
119: if (rest)
120: rmfree(swapmap, rest, addr+size);
121: return (addr);
122: }
123: /*
124: * Allocate from the map.
125: * If there is no space left of the piece
126: * we allocated from, move the rest of
127: * the pieces to the left.
128: */
129: addr = bp->m_addr;
130: bp->m_addr += size;
131: if ((bp->m_size -= size) == 0) {
132: do {
133: bp++;
134: (bp-1)->m_addr = bp->m_addr;
135: } while ((bp-1)->m_size = bp->m_size);
136: }
137: if (mp == swapmap && addr % CLSIZE)
138: panic("rmalloc swapmap");
139: return (addr);
140: }
141: }
142: return (0);
143: }
144:
145: /*
146: * Free the previously allocated space at addr
147: * of size units into the specified map.
148: * Sort addr into map and combine on
149: * one or both ends if possible.
150: */
151: rmfree(mp, size, addr)
152: struct map *mp;
153: long size, addr;
154: {
155: struct mapent *firstbp;
156: register struct mapent *bp;
157: register int t;
158:
159: /*
160: * Both address and size must be
161: * positive, or the protocol has broken down.
162: */
163: if (addr <= 0 || size <= 0)
164: goto badrmfree;
165: /*
166: * Locate the piece of the map which starts after the
167: * returned space (or the end of the map).
168: */
169: firstbp = bp = (struct mapent *)(mp + 1);
170: for (; bp->m_addr <= addr && bp->m_size != 0; bp++)
171: continue;
172: /*
173: * If the piece on the left abuts us,
174: * then we should combine with it.
175: */
176: if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) {
177: /*
178: * Check no overlap (internal error).
179: */
180: if ((bp-1)->m_addr+(bp-1)->m_size > addr)
181: goto badrmfree;
182: /*
183: * Add into piece on the left by increasing its size.
184: */
185: (bp-1)->m_size += size;
186: /*
187: * If the combined piece abuts the piece on
188: * the right now, compress it in also,
189: * by shifting the remaining pieces of the map over.
190: */
191: if (bp->m_addr && addr+size >= bp->m_addr) {
192: if (addr+size > bp->m_addr)
193: goto badrmfree;
194: (bp-1)->m_size += bp->m_size;
195: while (bp->m_size) {
196: bp++;
197: (bp-1)->m_addr = bp->m_addr;
198: (bp-1)->m_size = bp->m_size;
199: }
200: }
201: goto done;
202: }
203: /*
204: * Don't abut on the left, check for abutting on
205: * the right.
206: */
207: if (addr+size >= bp->m_addr && bp->m_size) {
208: if (addr+size > bp->m_addr)
209: goto badrmfree;
210: bp->m_addr -= size;
211: bp->m_size += size;
212: goto done;
213: }
214: /*
215: * Don't abut at all. Make a new entry
216: * and check for map overflow.
217: */
218: do {
219: t = bp->m_addr;
220: bp->m_addr = addr;
221: addr = t;
222: t = bp->m_size;
223: bp->m_size = size;
224: bp++;
225: } while (size = t);
226: /*
227: * Segment at bp is to be the delimiter;
228: * If there is not room for it
229: * then the table is too full
230: * and we must discard something.
231: */
232: if (bp+1 > mp->m_limit) {
233: /*
234: * Back bp up to last available segment.
235: * which contains a segment already and must
236: * be made into the delimiter.
237: * Discard second to last entry,
238: * since it is presumably smaller than the last
239: * and move the last entry back one.
240: */
241: bp--;
242: printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name,
243: (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size);
244: bp[-1] = bp[0];
245: bp[0].m_size = bp[0].m_addr = 0;
246: }
247: done:
248: /*
249: * THIS IS RIDICULOUS... IT DOESN'T BELONG HERE!
250: */
251: if ((mp == kernelmap) && kmapwnt) {
252: kmapwnt = 0;
253: wakeup((caddr_t)kernelmap);
254: }
255: return;
256: badrmfree:
257: panic("bad rmfree");
258: }
259:
260: /*
261: * Allocate 'size' units from the given map, starting at address 'addr'.
262: * Return 'addr' if successful, 0 if not.
263: * This may cause the creation or destruction of a resource map segment.
264: *
265: * This routine will return failure status if there is not enough room
266: * for a required additional map segment.
267: *
268: * An attempt to use this on 'swapmap' will result in
269: * a failure return. This is due mainly to laziness and could be fixed
270: * to do the right thing, although it probably will never be used.
271: */
272: rmget(mp, size, addr)
273: register struct map *mp;
274: {
275: register struct mapent *ep = (struct mapent *)(mp+1);
276: register struct mapent *bp, *bp2;
277:
278: if (size <= 0)
279: panic("rmget");
280: if (mp == swapmap)
281: return (0);
282: /*
283: * Look for a map segment containing the requested address.
284: * If none found, return failure.
285: */
286: for (bp = ep; bp->m_size; bp++)
287: if (bp->m_addr <= addr && bp->m_addr + bp->m_size > addr)
288: break;
289: if (bp->m_size == 0)
290: return (0);
291:
292: /*
293: * If segment is too small, return failure.
294: * If big enough, allocate the block, compressing or expanding
295: * the map as necessary.
296: */
297: if (bp->m_addr + bp->m_size < addr + size)
298: return (0);
299: if (bp->m_addr == addr)
300: if (bp->m_addr + bp->m_size == addr + size) {
301: /*
302: * Allocate entire segment and compress map
303: */
304: bp2 = bp;
305: while (bp2->m_size) {
306: bp2++;
307: (bp2-1)->m_addr = bp2->m_addr;
308: (bp2-1)->m_size = bp2->m_size;
309: }
310: } else {
311: /*
312: * Allocate first part of segment
313: */
314: bp->m_addr += size;
315: bp->m_size -= size;
316: }
317: else
318: if (bp->m_addr + bp->m_size == addr + size) {
319: /*
320: * Allocate last part of segment
321: */
322: bp->m_size -= size;
323: } else {
324: /*
325: * Allocate from middle of segment, but only
326: * if table can be expanded.
327: */
328: for (bp2=bp; bp2->m_size; bp2++)
329: ;
330: if (bp2 + 1 >= mp->m_limit)
331: return (0);
332: while (bp2 > bp) {
333: (bp2+1)->m_addr = bp2->m_addr;
334: (bp2+1)->m_size = bp2->m_size;
335: bp2--;
336: }
337: (bp+1)->m_addr = addr + size;
338: (bp+1)->m_size =
339: bp->m_addr + bp->m_size - (addr + size);
340: bp->m_size = addr - bp->m_addr;
341: }
342: return (addr);
343: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.