|
|
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.