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.sav 7.1 (Berkeley) 06/05/86 7 */ 8 9#include "param.h" 10#include "systm.h" 11#include "map.h" 12#include "dir.h" 13#include "user.h" 14#include "proc.h" 15#include "text.h" 16#include "kernel.h" 17 18/* 19 * Resource map handling routines. 20 * 21 * A resource map is an array of structures each 22 * of which describes a segment of the address space of an available 23 * resource. The segments are described by their base address and 24 * length, and sorted in address order. Each resource map has a fixed 25 * maximum number of segments allowed. Resources are allocated 26 * by taking part or all of one of the segments of the map. 27 * 28 * Returning of resources will require another segment if 29 * the returned resources are not adjacent in the address 30 * space to an existing segment. If the return of a segment 31 * would require a slot which is not available, then one of 32 * the resource map segments is discarded after a warning is printed. 33 * Returning of resources may also cause the map to collapse 34 * by coalescing two existing segments and the returned space 35 * into a single segment. In this case the resource map is 36 * made smaller by copying together to fill the resultant gap. 37 * 38 * N.B.: the current implementation uses a dense array and does 39 * not admit the value ``0'' as a legal address, since that is used 40 * as a delimiter. 41 */ 42 43/* 44 * Initialize map mp to have (mapsize-2) segments 45 * and to be called ``name'', which we print if 46 * the slots become so fragmented that we lose space. 47 * The map itself is initialized with size elements free 48 * starting at addr. 49 */ 50rminit(mp, size, addr, name, mapsize) 51 register struct map *mp; 52 long size, addr; 53 char *name; 54 int mapsize; 55{ 56 register struct mapent *ep = (struct mapent *)(mp+1); 57 58 mp->m_name = name; 59/* N.B.: WE ASSUME HERE THAT sizeof (struct map) == sizeof (struct mapent) */ 60 /* 61 * One of the mapsize slots is taken by the map structure, 62 * segments has size 0 and addr 0, and acts as a delimiter. 63 * We insure that we never use segments past the end of 64 * the array which is given by mp->m_limit. 65 * Instead, when excess segments occur we discard some resources. 66 */ 67 mp->m_limit = (struct mapent *)&mp[mapsize]; 68 /* 69 * Simulate a rmfree(), but with the option to 70 * call with size 0 and addr 0 when we just want 71 * to initialize without freeing. 72 */ 73 ep->m_size = size; 74 ep->m_addr = addr; 75} 76 77/* 78 * Allocate 'size' units from the given 79 * map. Return the base of the allocated space. 80 * In a map, the addresses are increasing and the 81 * list is terminated by a 0 size. 82 * 83 * Algorithm is first-fit. 84 * 85 * This routine knows about the interleaving of the swapmap 86 * and handles that. 87 */ 88long 89rmalloc(mp, size) 90 register struct map *mp; 91 long size; 92{ 93 register struct mapent *ep = (struct mapent *)(mp+1); 94 register int addr; 95 register struct mapent *bp; 96 swblk_t first, rest; 97 98 if (size <= 0 || mp == swapmap && size > dmmax) 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++) { 105 if (bp->m_size >= size) { 106 /* 107 * If allocating from swapmap, 108 * then have to respect interleaving 109 * boundaries. 110 */ 111 if (mp == swapmap && nswdev > 1 && 112 (first = dmmax - bp->m_addr%dmmax) < bp->m_size) { 113 if (bp->m_size - first < size) 114 continue; 115 addr = bp->m_addr + first; 116 rest = bp->m_size - first - size; 117 bp->m_size = first; 118 if (rest) 119 rmfree(swapmap, rest, addr+size); 120 return (addr); 121 } 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; 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 } 136 if (mp == swapmap && addr % CLSIZE) 137 panic("rmalloc swapmap"); 138 return (addr); 139 } 140 } 141 return (0); 142} 143 144/* 145 * Free the previously allocated space at addr 146 * of size units into the specified map. 147 * Sort addr into map and combine on 148 * one or both ends if possible. 149 */ 150rmfree(mp, size, addr) 151 struct map *mp; 152 long size, addr; 153{ 154 struct mapent *firstbp; 155 register struct mapent *bp; 156 register int t; 157 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++) 170 continue; 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 */ 184 (bp-1)->m_size += size; 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; 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 } 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--; 241 printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name, 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; 245 } 246done: 247 /* 248 * THIS IS RIDICULOUS... IT DOESN'T BELONG HERE! 249 */ 250 if ((mp == kernelmap) && kmapwnt) { 251 kmapwnt = 0; 252 wakeup((caddr_t)kernelmap); 253 } 254 return; 255badrmfree: 256 panic("bad rmfree"); 257} 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 ; 329 if (bp2 + 1 >= mp->m_limit) 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} 343