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