1*17094Sbloom /* subr_rmap.c 6.2 84/08/29 */ 227Sbill 3*17094Sbloom #include "param.h" 4*17094Sbloom #include "systm.h" 5*17094Sbloom #include "map.h" 6*17094Sbloom #include "dir.h" 7*17094Sbloom #include "user.h" 8*17094Sbloom #include "proc.h" 9*17094Sbloom #include "text.h" 10*17094Sbloom #include "kernel.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; 468790Sroot long 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 */ 828766Sroot long 832781Swnj rmalloc(mp, size) 842781Swnj register struct map *mp; 858766Sroot long size; 8627Sbill { 872781Swnj register struct mapent *ep = (struct mapent *)(mp+1); 882781Swnj register int addr; 892781Swnj register struct mapent *bp; 90307Sbill swblk_t first, rest; 9127Sbill 9212489Ssam if (size <= 0 || mp == swapmap && size > dmmax) 932781Swnj panic("rmalloc"); 942781Swnj /* 952781Swnj * Search for a piece of the resource map which has enough 962781Swnj * free space to accomodate the request. 972781Swnj */ 982781Swnj for (bp = ep; bp->m_size; bp++) { 9927Sbill if (bp->m_size >= size) { 1002781Swnj /* 1012781Swnj * If allocating from swapmap, 1022781Swnj * then have to respect interleaving 1032781Swnj * boundaries. 1042781Swnj */ 10512489Ssam if (mp == swapmap && nswdev > 1 && 10612489Ssam (first = dmmax - bp->m_addr%dmmax) < bp->m_size) { 107307Sbill if (bp->m_size - first < size) 108307Sbill continue; 1092781Swnj addr = bp->m_addr + first; 110307Sbill rest = bp->m_size - first - size; 111307Sbill bp->m_size = first; 112307Sbill if (rest) 1132781Swnj rmfree(swapmap, rest, addr+size); 1142781Swnj return (addr); 115307Sbill } 1162781Swnj /* 1172781Swnj * Allocate from the map. 1182781Swnj * If there is no space left of the piece 1192781Swnj * we allocated from, move the rest of 1202781Swnj * the pieces to the left. 1212781Swnj */ 1222781Swnj addr = bp->m_addr; 12327Sbill bp->m_addr += size; 12427Sbill if ((bp->m_size -= size) == 0) { 12527Sbill do { 12627Sbill bp++; 12727Sbill (bp-1)->m_addr = bp->m_addr; 12827Sbill } while ((bp-1)->m_size = bp->m_size); 12927Sbill } 1302781Swnj if (mp == swapmap && addr % CLSIZE) 1312781Swnj panic("rmalloc swapmap"); 1322781Swnj return (addr); 13327Sbill } 13427Sbill } 1352781Swnj return (0); 13627Sbill } 13727Sbill 13827Sbill /* 1392781Swnj * Free the previously allocated space at addr 14027Sbill * of size units into the specified map. 1412781Swnj * Sort addr into map and combine on 14227Sbill * one or both ends if possible. 14327Sbill */ 1442781Swnj rmfree(mp, size, addr) 1452781Swnj struct map *mp; 1468766Sroot long size, addr; 14727Sbill { 1482781Swnj struct mapent *firstbp; 1492781Swnj register struct mapent *bp; 15027Sbill register int t; 15127Sbill 1522781Swnj /* 1532781Swnj * Both address and size must be 1542781Swnj * positive, or the protocol has broken down. 1552781Swnj */ 1562781Swnj if (addr <= 0 || size <= 0) 1572781Swnj goto badrmfree; 1582781Swnj /* 1592781Swnj * Locate the piece of the map which starts after the 1602781Swnj * returned space (or the end of the map). 1612781Swnj */ 1622781Swnj firstbp = bp = (struct mapent *)(mp + 1); 1632781Swnj for (; bp->m_addr <= addr && bp->m_size != 0; bp++) 16427Sbill continue; 1652781Swnj /* 1662781Swnj * If the piece on the left abuts us, 1672781Swnj * then we should combine with it. 1682781Swnj */ 1692781Swnj if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) { 1702781Swnj /* 1712781Swnj * Check no overlap (internal error). 1722781Swnj */ 1732781Swnj if ((bp-1)->m_addr+(bp-1)->m_size > addr) 1742781Swnj goto badrmfree; 1752781Swnj /* 1762781Swnj * Add into piece on the left by increasing its size. 1772781Swnj */ 17827Sbill (bp-1)->m_size += size; 1792781Swnj /* 1802781Swnj * If the combined piece abuts the piece on 1812781Swnj * the right now, compress it in also, 1822781Swnj * by shifting the remaining pieces of the map over. 1832781Swnj */ 1842781Swnj if (bp->m_addr && addr+size >= bp->m_addr) { 1852781Swnj if (addr+size > bp->m_addr) 1862781Swnj goto badrmfree; 18727Sbill (bp-1)->m_size += bp->m_size; 18827Sbill while (bp->m_size) { 18927Sbill bp++; 19027Sbill (bp-1)->m_addr = bp->m_addr; 19127Sbill (bp-1)->m_size = bp->m_size; 19227Sbill } 19327Sbill } 1942781Swnj goto done; 19527Sbill } 1962781Swnj /* 1972781Swnj * Don't abut on the left, check for abutting on 1982781Swnj * the right. 1992781Swnj */ 2002781Swnj if (addr+size >= bp->m_addr && bp->m_size) { 2012781Swnj if (addr+size > bp->m_addr) 2022781Swnj goto badrmfree; 2032781Swnj bp->m_addr -= size; 2042781Swnj bp->m_size += size; 2052781Swnj goto done; 2062781Swnj } 2072781Swnj /* 2082781Swnj * Don't abut at all. Make a new entry 2092781Swnj * and check for map overflow. 2102781Swnj */ 2112781Swnj do { 2122781Swnj t = bp->m_addr; 2132781Swnj bp->m_addr = addr; 2142781Swnj addr = t; 2152781Swnj t = bp->m_size; 2162781Swnj bp->m_size = size; 2172781Swnj bp++; 2182781Swnj } while (size = t); 2192781Swnj /* 2202781Swnj * Segment at bp is to be the delimiter; 2212781Swnj * If there is not room for it 2222781Swnj * then the table is too full 2232781Swnj * and we must discard something. 2242781Swnj */ 2252781Swnj if (bp+1 > mp->m_limit) { 2262781Swnj /* 2272781Swnj * Back bp up to last available segment. 2282781Swnj * which contains a segment already and must 2292781Swnj * be made into the delimiter. 2302781Swnj * Discard second to last entry, 2312781Swnj * since it is presumably smaller than the last 2322781Swnj * and move the last entry back one. 2332781Swnj */ 2342781Swnj bp--; 2352937Swnj printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name, 2362781Swnj (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size); 2372781Swnj bp[-1] = bp[0]; 2382781Swnj bp[0].m_size = bp[0].m_addr = 0; 2392781Swnj } 2402781Swnj done: 2412781Swnj /* 2422781Swnj * THIS IS RIDICULOUS... IT DOESN'T BELONG HERE! 2432781Swnj */ 24427Sbill if ((mp == kernelmap) && kmapwnt) { 24527Sbill kmapwnt = 0; 24627Sbill wakeup((caddr_t)kernelmap); 24727Sbill } 2482781Swnj return; 2492781Swnj badrmfree: 2502781Swnj panic("bad rmfree"); 25127Sbill } 2526516Sfeldman 2536516Sfeldman /* 2546516Sfeldman * Allocate 'size' units from the given map, starting at address 'addr'. 2556516Sfeldman * Return 'addr' if successful, 0 if not. 2566516Sfeldman * This may cause the creation or destruction of a resource map segment. 2576516Sfeldman * 2586516Sfeldman * This routine will return failure status if there is not enough room 2596516Sfeldman * for a required additional map segment. 2606516Sfeldman * 2616516Sfeldman * An attempt to use this on 'swapmap' will result in 2626516Sfeldman * a failure return. This is due mainly to laziness and could be fixed 2636516Sfeldman * to do the right thing, although it probably will never be used. 2646516Sfeldman */ 2656516Sfeldman rmget(mp, size, addr) 2666516Sfeldman register struct map *mp; 2676516Sfeldman { 2686516Sfeldman register struct mapent *ep = (struct mapent *)(mp+1); 2696516Sfeldman register struct mapent *bp, *bp2; 2706516Sfeldman 2716516Sfeldman if (size <= 0) 2726516Sfeldman panic("rmget"); 2736516Sfeldman if (mp == swapmap) 2746516Sfeldman return (0); 2756516Sfeldman /* 2766516Sfeldman * Look for a map segment containing the requested address. 2776516Sfeldman * If none found, return failure. 2786516Sfeldman */ 2796516Sfeldman for (bp = ep; bp->m_size; bp++) 2806516Sfeldman if (bp->m_addr <= addr && bp->m_addr + bp->m_size > addr) 2816516Sfeldman break; 2826516Sfeldman if (bp->m_size == 0) 2836516Sfeldman return (0); 2846516Sfeldman 2856516Sfeldman /* 2866516Sfeldman * If segment is too small, return failure. 2876516Sfeldman * If big enough, allocate the block, compressing or expanding 2886516Sfeldman * the map as necessary. 2896516Sfeldman */ 2906516Sfeldman if (bp->m_addr + bp->m_size < addr + size) 2916516Sfeldman return (0); 2926516Sfeldman if (bp->m_addr == addr) 2936516Sfeldman if (bp->m_addr + bp->m_size == addr + size) { 2946516Sfeldman /* 2956516Sfeldman * Allocate entire segment and compress map 2966516Sfeldman */ 2976516Sfeldman bp2 = bp; 2986516Sfeldman while (bp2->m_size) { 2996516Sfeldman bp2++; 3006516Sfeldman (bp2-1)->m_addr = bp2->m_addr; 3016516Sfeldman (bp2-1)->m_size = bp2->m_size; 3026516Sfeldman } 3036516Sfeldman } else { 3046516Sfeldman /* 3056516Sfeldman * Allocate first part of segment 3066516Sfeldman */ 3076516Sfeldman bp->m_addr += size; 3086516Sfeldman bp->m_size -= size; 3096516Sfeldman } 3106516Sfeldman else 3116516Sfeldman if (bp->m_addr + bp->m_size == addr + size) { 3126516Sfeldman /* 3136516Sfeldman * Allocate last part of segment 3146516Sfeldman */ 3156516Sfeldman bp->m_size -= size; 3166516Sfeldman } else { 3176516Sfeldman /* 3186516Sfeldman * Allocate from middle of segment, but only 3196516Sfeldman * if table can be expanded. 3206516Sfeldman */ 3216516Sfeldman for (bp2=bp; bp2->m_size; bp2++) 3226516Sfeldman ; 3236516Sfeldman if (bp2 == mp->m_limit) 3246516Sfeldman return (0); 3256516Sfeldman while (bp2 > bp) { 3266516Sfeldman (bp2+1)->m_addr = bp2->m_addr; 3276516Sfeldman (bp2+1)->m_size = bp2->m_size; 3286516Sfeldman bp2--; 3296516Sfeldman } 3306516Sfeldman (bp+1)->m_addr = addr + size; 3316516Sfeldman (bp+1)->m_size = 3326516Sfeldman bp->m_addr + bp->m_size - (addr + size); 3336516Sfeldman bp->m_size = addr - bp->m_addr; 3346516Sfeldman } 3356516Sfeldman return (addr); 3366516Sfeldman } 337