1*6516Sfeldman /* subr_rmap.c 4.5 82/04/11 */ 227Sbill 327Sbill #include "../h/param.h" 427Sbill #include "../h/systm.h" 527Sbill #include "../h/map.h" 627Sbill #include "../h/dir.h" 727Sbill #include "../h/user.h" 827Sbill #include "../h/proc.h" 927Sbill #include "../h/mtpr.h" 1027Sbill #include "../h/text.h" 1127Sbill 1227Sbill /* 132781Swnj * Resource map handling routines. 142781Swnj * 152781Swnj * A resource map is an array of structures each 162781Swnj * of which describes a segment of the address space of an available 172781Swnj * resource. The segments are described by their base address and 182781Swnj * length, and sorted in address order. Each resource map has a fixed 192781Swnj * maximum number of segments allowed. Resources are allocated 202781Swnj * by taking part or all of one of the segments of the map. 212781Swnj * 222781Swnj * Returning of resources will require another segment if 232781Swnj * the returned resources are not adjacent in the address 242781Swnj * space to an existing segment. If the return of a segment 252781Swnj * would require a slot which is not available, then one of 262781Swnj * the resource map segments is discarded after a warning is printed. 272781Swnj * Returning of resources may also cause the map to collapse 282781Swnj * by coalescing two existing segments and the returned space 292781Swnj * into a single segment. In this case the resource map is 302781Swnj * made smaller by copying together to fill the resultant gap. 312781Swnj * 322781Swnj * N.B.: the current implementation uses a dense array and does 332781Swnj * not admit the value ``0'' as a legal address, since that is used 342781Swnj * as a delimiter. 352781Swnj */ 362781Swnj 372781Swnj /* 382781Swnj * Initialize map mp to have (mapsize-2) segments 392781Swnj * and to be called ``name'', which we print if 402781Swnj * the slots become so fragmented that we lose space. 412781Swnj * The map itself is initialized with size elements free 422781Swnj * starting at addr. 432781Swnj */ 442781Swnj rminit(mp, size, addr, name, mapsize) 452781Swnj register struct map *mp; 462781Swnj int size, addr; 472781Swnj char *name; 482781Swnj int mapsize; 492781Swnj { 502781Swnj register struct mapent *ep = (struct mapent *)(mp+1); 512781Swnj 522781Swnj mp->m_name = name; 532781Swnj /* N.B.: WE ASSUME HERE THAT sizeof (struct map) == sizeof (struct mapent) */ 542781Swnj /* 552781Swnj * One of the mapsize slots is taken by the map structure, 562781Swnj * segments has size 0 and addr 0, and acts as a delimiter. 572781Swnj * We insure that we never use segments past the end of 582781Swnj * the array which is given by mp->m_limit. 592781Swnj * Instead, when excess segments occur we discard some resources. 602781Swnj */ 612781Swnj mp->m_limit = (struct mapent *)&mp[mapsize]; 622781Swnj /* 632781Swnj * Simulate a rmfree(), but with the option to 642781Swnj * call with size 0 and addr 0 when we just want 652781Swnj * to initialize without freeing. 662781Swnj */ 672781Swnj ep->m_size = size; 682781Swnj ep->m_addr = addr; 692781Swnj } 702781Swnj 712781Swnj /* 7227Sbill * Allocate 'size' units from the given 732781Swnj * map. Return the base of the allocated space. 7427Sbill * In a map, the addresses are increasing and the 7527Sbill * list is terminated by a 0 size. 762781Swnj * 7727Sbill * Algorithm is first-fit. 782781Swnj * 792781Swnj * This routine knows about the interleaving of the swapmap 802781Swnj * and handles that. 8127Sbill */ 822781Swnj rmalloc(mp, size) 832781Swnj register struct map *mp; 8427Sbill { 852781Swnj register struct mapent *ep = (struct mapent *)(mp+1); 862781Swnj register int addr; 872781Swnj register struct mapent *bp; 88307Sbill swblk_t first, rest; 8927Sbill 90307Sbill if (size <= 0 || mp == swapmap && size > DMMAX) 912781Swnj panic("rmalloc"); 922781Swnj /* 932781Swnj * Search for a piece of the resource map which has enough 942781Swnj * free space to accomodate the request. 952781Swnj */ 962781Swnj for (bp = ep; bp->m_size; bp++) { 9727Sbill if (bp->m_size >= size) { 982781Swnj /* 992781Swnj * If allocating from swapmap, 1002781Swnj * then have to respect interleaving 1012781Swnj * boundaries. 1022781Swnj */ 103307Sbill if (mp == swapmap && 104307Sbill (first = DMMAX - bp->m_addr%DMMAX) < bp->m_size) { 105307Sbill if (bp->m_size - first < size) 106307Sbill continue; 1072781Swnj addr = bp->m_addr + first; 108307Sbill rest = bp->m_size - first - size; 109307Sbill bp->m_size = first; 110307Sbill if (rest) 1112781Swnj rmfree(swapmap, rest, addr+size); 1122781Swnj return (addr); 113307Sbill } 1142781Swnj /* 1152781Swnj * Allocate from the map. 1162781Swnj * If there is no space left of the piece 1172781Swnj * we allocated from, move the rest of 1182781Swnj * the pieces to the left. 1192781Swnj */ 1202781Swnj addr = bp->m_addr; 12127Sbill bp->m_addr += size; 12227Sbill if ((bp->m_size -= size) == 0) { 12327Sbill do { 12427Sbill bp++; 12527Sbill (bp-1)->m_addr = bp->m_addr; 12627Sbill } while ((bp-1)->m_size = bp->m_size); 12727Sbill } 1282781Swnj if (mp == swapmap && addr % CLSIZE) 1292781Swnj panic("rmalloc swapmap"); 1302781Swnj return (addr); 13127Sbill } 13227Sbill } 1332781Swnj return (0); 13427Sbill } 13527Sbill 13627Sbill /* 1372781Swnj * Free the previously allocated space at addr 13827Sbill * of size units into the specified map. 1392781Swnj * Sort addr into map and combine on 14027Sbill * one or both ends if possible. 14127Sbill */ 1422781Swnj rmfree(mp, size, addr) 1432781Swnj struct map *mp; 1442781Swnj register int size, addr; 14527Sbill { 1462781Swnj struct mapent *firstbp; 1472781Swnj register struct mapent *bp; 14827Sbill register int t; 14927Sbill 1502781Swnj /* 1512781Swnj * Both address and size must be 1522781Swnj * positive, or the protocol has broken down. 1532781Swnj */ 1542781Swnj if (addr <= 0 || size <= 0) 1552781Swnj goto badrmfree; 1562781Swnj /* 1572781Swnj * Locate the piece of the map which starts after the 1582781Swnj * returned space (or the end of the map). 1592781Swnj */ 1602781Swnj firstbp = bp = (struct mapent *)(mp + 1); 1612781Swnj for (; bp->m_addr <= addr && bp->m_size != 0; bp++) 16227Sbill continue; 1632781Swnj /* 1642781Swnj * If the piece on the left abuts us, 1652781Swnj * then we should combine with it. 1662781Swnj */ 1672781Swnj if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) { 1682781Swnj /* 1692781Swnj * Check no overlap (internal error). 1702781Swnj */ 1712781Swnj if ((bp-1)->m_addr+(bp-1)->m_size > addr) 1722781Swnj goto badrmfree; 1732781Swnj /* 1742781Swnj * Add into piece on the left by increasing its size. 1752781Swnj */ 17627Sbill (bp-1)->m_size += size; 1772781Swnj /* 1782781Swnj * If the combined piece abuts the piece on 1792781Swnj * the right now, compress it in also, 1802781Swnj * by shifting the remaining pieces of the map over. 1812781Swnj */ 1822781Swnj if (bp->m_addr && addr+size >= bp->m_addr) { 1832781Swnj if (addr+size > bp->m_addr) 1842781Swnj goto badrmfree; 18527Sbill (bp-1)->m_size += bp->m_size; 18627Sbill while (bp->m_size) { 18727Sbill bp++; 18827Sbill (bp-1)->m_addr = bp->m_addr; 18927Sbill (bp-1)->m_size = bp->m_size; 19027Sbill } 19127Sbill } 1922781Swnj goto done; 19327Sbill } 1942781Swnj /* 1952781Swnj * Don't abut on the left, check for abutting on 1962781Swnj * the right. 1972781Swnj */ 1982781Swnj if (addr+size >= bp->m_addr && bp->m_size) { 1992781Swnj if (addr+size > bp->m_addr) 2002781Swnj goto badrmfree; 2012781Swnj bp->m_addr -= size; 2022781Swnj bp->m_size += size; 2032781Swnj goto done; 2042781Swnj } 2052781Swnj /* 2062781Swnj * Don't abut at all. Make a new entry 2072781Swnj * and check for map overflow. 2082781Swnj */ 2092781Swnj do { 2102781Swnj t = bp->m_addr; 2112781Swnj bp->m_addr = addr; 2122781Swnj addr = t; 2132781Swnj t = bp->m_size; 2142781Swnj bp->m_size = size; 2152781Swnj bp++; 2162781Swnj } while (size = t); 2172781Swnj /* 2182781Swnj * Segment at bp is to be the delimiter; 2192781Swnj * If there is not room for it 2202781Swnj * then the table is too full 2212781Swnj * and we must discard something. 2222781Swnj */ 2232781Swnj if (bp+1 > mp->m_limit) { 2242781Swnj /* 2252781Swnj * Back bp up to last available segment. 2262781Swnj * which contains a segment already and must 2272781Swnj * be made into the delimiter. 2282781Swnj * Discard second to last entry, 2292781Swnj * since it is presumably smaller than the last 2302781Swnj * and move the last entry back one. 2312781Swnj */ 2322781Swnj bp--; 2332937Swnj printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name, 2342781Swnj (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size); 2352781Swnj bp[-1] = bp[0]; 2362781Swnj bp[0].m_size = bp[0].m_addr = 0; 2372781Swnj } 2382781Swnj done: 2392781Swnj /* 2402781Swnj * THIS IS RIDICULOUS... IT DOESN'T BELONG HERE! 2412781Swnj */ 24227Sbill if ((mp == kernelmap) && kmapwnt) { 24327Sbill kmapwnt = 0; 24427Sbill wakeup((caddr_t)kernelmap); 24527Sbill } 2462781Swnj return; 2472781Swnj badrmfree: 2482781Swnj panic("bad rmfree"); 24927Sbill } 250*6516Sfeldman 251*6516Sfeldman /* 252*6516Sfeldman * Allocate 'size' units from the given map, starting at address 'addr'. 253*6516Sfeldman * Return 'addr' if successful, 0 if not. 254*6516Sfeldman * This may cause the creation or destruction of a resource map segment. 255*6516Sfeldman * 256*6516Sfeldman * This routine will return failure status if there is not enough room 257*6516Sfeldman * for a required additional map segment. 258*6516Sfeldman * 259*6516Sfeldman * An attempt to use this on 'swapmap' will result in 260*6516Sfeldman * a failure return. This is due mainly to laziness and could be fixed 261*6516Sfeldman * to do the right thing, although it probably will never be used. 262*6516Sfeldman */ 263*6516Sfeldman rmget(mp, size, addr) 264*6516Sfeldman register struct map *mp; 265*6516Sfeldman { 266*6516Sfeldman register struct mapent *ep = (struct mapent *)(mp+1); 267*6516Sfeldman register struct mapent *bp, *bp2; 268*6516Sfeldman 269*6516Sfeldman if (size <= 0) 270*6516Sfeldman panic("rmget"); 271*6516Sfeldman if (mp == swapmap) 272*6516Sfeldman return (0); 273*6516Sfeldman /* 274*6516Sfeldman * Look for a map segment containing the requested address. 275*6516Sfeldman * If none found, return failure. 276*6516Sfeldman */ 277*6516Sfeldman for (bp = ep; bp->m_size; bp++) 278*6516Sfeldman if (bp->m_addr <= addr && bp->m_addr + bp->m_size > addr) 279*6516Sfeldman break; 280*6516Sfeldman if (bp->m_size == 0) 281*6516Sfeldman return (0); 282*6516Sfeldman 283*6516Sfeldman /* 284*6516Sfeldman * If segment is too small, return failure. 285*6516Sfeldman * If big enough, allocate the block, compressing or expanding 286*6516Sfeldman * the map as necessary. 287*6516Sfeldman */ 288*6516Sfeldman if (bp->m_addr + bp->m_size < addr + size) 289*6516Sfeldman return (0); 290*6516Sfeldman if (bp->m_addr == addr) 291*6516Sfeldman if (bp->m_addr + bp->m_size == addr + size) { 292*6516Sfeldman /* 293*6516Sfeldman * Allocate entire segment and compress map 294*6516Sfeldman */ 295*6516Sfeldman bp2 = bp; 296*6516Sfeldman while (bp2->m_size) { 297*6516Sfeldman bp2++; 298*6516Sfeldman (bp2-1)->m_addr = bp2->m_addr; 299*6516Sfeldman (bp2-1)->m_size = bp2->m_size; 300*6516Sfeldman } 301*6516Sfeldman } else { 302*6516Sfeldman /* 303*6516Sfeldman * Allocate first part of segment 304*6516Sfeldman */ 305*6516Sfeldman bp->m_addr += size; 306*6516Sfeldman bp->m_size -= size; 307*6516Sfeldman } 308*6516Sfeldman else 309*6516Sfeldman if (bp->m_addr + bp->m_size == addr + size) { 310*6516Sfeldman /* 311*6516Sfeldman * Allocate last part of segment 312*6516Sfeldman */ 313*6516Sfeldman bp->m_size -= size; 314*6516Sfeldman } else { 315*6516Sfeldman /* 316*6516Sfeldman * Allocate from middle of segment, but only 317*6516Sfeldman * if table can be expanded. 318*6516Sfeldman */ 319*6516Sfeldman for (bp2=bp; bp2->m_size; bp2++) 320*6516Sfeldman ; 321*6516Sfeldman if (bp2 == mp->m_limit) 322*6516Sfeldman return (0); 323*6516Sfeldman while (bp2 > bp) { 324*6516Sfeldman (bp2+1)->m_addr = bp2->m_addr; 325*6516Sfeldman (bp2+1)->m_size = bp2->m_size; 326*6516Sfeldman bp2--; 327*6516Sfeldman } 328*6516Sfeldman (bp+1)->m_addr = addr + size; 329*6516Sfeldman (bp+1)->m_size = 330*6516Sfeldman bp->m_addr + bp->m_size - (addr + size); 331*6516Sfeldman bp->m_size = addr - bp->m_addr; 332*6516Sfeldman } 333*6516Sfeldman return (addr); 334*6516Sfeldman } 335