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