1*49589Sbostic /*- 2*49589Sbostic * Copyright (c) 1982, 1986 The Regents of the University of California. 3*49589Sbostic * All rights reserved. 423382Smckusick * 5*49589Sbostic * %sccs.include.proprietary.c% 6*49589Sbostic * 7*49589Sbostic * @(#)subr_rmap.c 7.8 (Berkeley) 05/09/91 823382Smckusick */ 927Sbill 1017094Sbloom #include "param.h" 1117094Sbloom #include "systm.h" 1217094Sbloom #include "map.h" 1347540Skarels #include "dmap.h" /* XXX */ 1417094Sbloom #include "proc.h" 1517094Sbloom #include "kernel.h" 1627Sbill 1727Sbill /* 182781Swnj * Resource map handling routines. 192781Swnj * 202781Swnj * A resource map is an array of structures each 212781Swnj * of which describes a segment of the address space of an available 222781Swnj * resource. The segments are described by their base address and 232781Swnj * length, and sorted in address order. Each resource map has a fixed 242781Swnj * maximum number of segments allowed. Resources are allocated 252781Swnj * by taking part or all of one of the segments of the map. 262781Swnj * 272781Swnj * Returning of resources will require another segment if 282781Swnj * the returned resources are not adjacent in the address 292781Swnj * space to an existing segment. If the return of a segment 302781Swnj * would require a slot which is not available, then one of 312781Swnj * the resource map segments is discarded after a warning is printed. 322781Swnj * Returning of resources may also cause the map to collapse 332781Swnj * by coalescing two existing segments and the returned space 342781Swnj * into a single segment. In this case the resource map is 352781Swnj * made smaller by copying together to fill the resultant gap. 362781Swnj * 372781Swnj * N.B.: the current implementation uses a dense array and does 382781Swnj * not admit the value ``0'' as a legal address, since that is used 392781Swnj * as a delimiter. 402781Swnj */ 412781Swnj 422781Swnj /* 432781Swnj * Initialize map mp to have (mapsize-2) segments 442781Swnj * and to be called ``name'', which we print if 452781Swnj * the slots become so fragmented that we lose space. 462781Swnj * The map itself is initialized with size elements free 472781Swnj * starting at addr. 482781Swnj */ 492781Swnj rminit(mp, size, addr, name, mapsize) 502781Swnj register struct map *mp; 518790Sroot long size, addr; 522781Swnj char *name; 532781Swnj int mapsize; 542781Swnj { 552781Swnj register struct mapent *ep = (struct mapent *)(mp+1); 562781Swnj 572781Swnj mp->m_name = name; 582781Swnj /* N.B.: WE ASSUME HERE THAT sizeof (struct map) == sizeof (struct mapent) */ 592781Swnj /* 602781Swnj * One of the mapsize slots is taken by the map structure, 612781Swnj * segments has size 0 and addr 0, and acts as a delimiter. 622781Swnj * We insure that we never use segments past the end of 632781Swnj * the array which is given by mp->m_limit. 642781Swnj * Instead, when excess segments occur we discard some resources. 652781Swnj */ 662781Swnj mp->m_limit = (struct mapent *)&mp[mapsize]; 672781Swnj /* 682781Swnj * Simulate a rmfree(), but with the option to 692781Swnj * call with size 0 and addr 0 when we just want 702781Swnj * to initialize without freeing. 712781Swnj */ 722781Swnj ep->m_size = size; 732781Swnj ep->m_addr = addr; 7433605Skarels (++ep)->m_size = 0; 7533605Skarels ep->m_addr = 0; 762781Swnj } 772781Swnj 782781Swnj /* 7927Sbill * Allocate 'size' units from the given 802781Swnj * map. Return the base of the allocated space. 8127Sbill * In a map, the addresses are increasing and the 8227Sbill * list is terminated by a 0 size. 832781Swnj * 8427Sbill * Algorithm is first-fit. 852781Swnj * 862781Swnj * This routine knows about the interleaving of the swapmap 872781Swnj * and handles that. 8827Sbill */ 898766Sroot long 902781Swnj rmalloc(mp, size) 912781Swnj register struct map *mp; 928766Sroot long size; 9327Sbill { 942781Swnj register struct mapent *ep = (struct mapent *)(mp+1); 952781Swnj register int addr; 962781Swnj register struct mapent *bp; 97307Sbill swblk_t first, rest; 9827Sbill 9912489Ssam if (size <= 0 || mp == swapmap && size > dmmax) 1002781Swnj panic("rmalloc"); 1012781Swnj /* 1022781Swnj * Search for a piece of the resource map which has enough 1032781Swnj * free space to accomodate the request. 1042781Swnj */ 1052781Swnj for (bp = ep; bp->m_size; bp++) { 10627Sbill if (bp->m_size >= size) { 1072781Swnj /* 1082781Swnj * If allocating from swapmap, 1092781Swnj * then have to respect interleaving 1102781Swnj * boundaries. 1112781Swnj */ 11212489Ssam if (mp == swapmap && nswdev > 1 && 11341988Smckusick (first = dmmax - bp->m_addr%dmmax) < size) { 114307Sbill if (bp->m_size - first < size) 115307Sbill continue; 1162781Swnj addr = bp->m_addr + first; 117307Sbill rest = bp->m_size - first - size; 118307Sbill bp->m_size = first; 119307Sbill if (rest) 1202781Swnj rmfree(swapmap, rest, addr+size); 1212781Swnj return (addr); 122307Sbill } 1232781Swnj /* 1242781Swnj * Allocate from the map. 1252781Swnj * If there is no space left of the piece 1262781Swnj * we allocated from, move the rest of 1272781Swnj * the pieces to the left. 1282781Swnj */ 1292781Swnj addr = bp->m_addr; 13027Sbill bp->m_addr += size; 13127Sbill if ((bp->m_size -= size) == 0) { 13227Sbill do { 13327Sbill bp++; 13427Sbill (bp-1)->m_addr = bp->m_addr; 13527Sbill } while ((bp-1)->m_size = bp->m_size); 13627Sbill } 1372781Swnj if (mp == swapmap && addr % CLSIZE) 1382781Swnj panic("rmalloc swapmap"); 1392781Swnj return (addr); 14027Sbill } 14127Sbill } 1422781Swnj return (0); 14327Sbill } 14427Sbill 14527Sbill /* 1462781Swnj * Free the previously allocated space at addr 14727Sbill * of size units into the specified map. 1482781Swnj * Sort addr into map and combine on 14927Sbill * one or both ends if possible. 15027Sbill */ 1512781Swnj rmfree(mp, size, addr) 1522781Swnj struct map *mp; 1538766Sroot long size, addr; 15427Sbill { 1552781Swnj struct mapent *firstbp; 1562781Swnj register struct mapent *bp; 15727Sbill register int t; 15827Sbill 1592781Swnj /* 1602781Swnj * Both address and size must be 1612781Swnj * positive, or the protocol has broken down. 1622781Swnj */ 1632781Swnj if (addr <= 0 || size <= 0) 1642781Swnj goto badrmfree; 1652781Swnj /* 1662781Swnj * Locate the piece of the map which starts after the 1672781Swnj * returned space (or the end of the map). 1682781Swnj */ 1692781Swnj firstbp = bp = (struct mapent *)(mp + 1); 1702781Swnj for (; bp->m_addr <= addr && bp->m_size != 0; bp++) 17127Sbill continue; 1722781Swnj /* 1732781Swnj * If the piece on the left abuts us, 1742781Swnj * then we should combine with it. 1752781Swnj */ 1762781Swnj if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) { 1772781Swnj /* 1782781Swnj * Check no overlap (internal error). 1792781Swnj */ 1802781Swnj if ((bp-1)->m_addr+(bp-1)->m_size > addr) 1812781Swnj goto badrmfree; 1822781Swnj /* 1832781Swnj * Add into piece on the left by increasing its size. 1842781Swnj */ 18527Sbill (bp-1)->m_size += size; 1862781Swnj /* 1872781Swnj * If the combined piece abuts the piece on 1882781Swnj * the right now, compress it in also, 1892781Swnj * by shifting the remaining pieces of the map over. 1902781Swnj */ 1912781Swnj if (bp->m_addr && addr+size >= bp->m_addr) { 1922781Swnj if (addr+size > bp->m_addr) 1932781Swnj goto badrmfree; 19427Sbill (bp-1)->m_size += bp->m_size; 19527Sbill while (bp->m_size) { 19627Sbill bp++; 19727Sbill (bp-1)->m_addr = bp->m_addr; 19827Sbill (bp-1)->m_size = bp->m_size; 19927Sbill } 20027Sbill } 20149281Shibler return; 20227Sbill } 2032781Swnj /* 2042781Swnj * Don't abut on the left, check for abutting on 2052781Swnj * the right. 2062781Swnj */ 2072781Swnj if (addr+size >= bp->m_addr && bp->m_size) { 2082781Swnj if (addr+size > bp->m_addr) 2092781Swnj goto badrmfree; 2102781Swnj bp->m_addr -= size; 2112781Swnj bp->m_size += size; 21249281Shibler return; 2132781Swnj } 2142781Swnj /* 2152781Swnj * Don't abut at all. Make a new entry 2162781Swnj * and check for map overflow. 2172781Swnj */ 2182781Swnj do { 2192781Swnj t = bp->m_addr; 2202781Swnj bp->m_addr = addr; 2212781Swnj addr = t; 2222781Swnj t = bp->m_size; 2232781Swnj bp->m_size = size; 2242781Swnj bp++; 2252781Swnj } while (size = t); 2262781Swnj /* 2272781Swnj * Segment at bp is to be the delimiter; 2282781Swnj * If there is not room for it 2292781Swnj * then the table is too full 2302781Swnj * and we must discard something. 2312781Swnj */ 2322781Swnj if (bp+1 > mp->m_limit) { 2332781Swnj /* 2342781Swnj * Back bp up to last available segment. 2352781Swnj * which contains a segment already and must 2362781Swnj * be made into the delimiter. 2372781Swnj * Discard second to last entry, 2382781Swnj * since it is presumably smaller than the last 2392781Swnj * and move the last entry back one. 2402781Swnj */ 2412781Swnj bp--; 2422937Swnj printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name, 2432781Swnj (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size); 2442781Swnj bp[-1] = bp[0]; 2452781Swnj bp[0].m_size = bp[0].m_addr = 0; 2462781Swnj } 2472781Swnj return; 2482781Swnj badrmfree: 2492781Swnj panic("bad rmfree"); 25027Sbill } 2516516Sfeldman 2526516Sfeldman /* 2536516Sfeldman * Allocate 'size' units from the given map, starting at address 'addr'. 2546516Sfeldman * Return 'addr' if successful, 0 if not. 2556516Sfeldman * This may cause the creation or destruction of a resource map segment. 2566516Sfeldman * 2576516Sfeldman * This routine will return failure status if there is not enough room 2586516Sfeldman * for a required additional map segment. 2596516Sfeldman * 2606516Sfeldman * An attempt to use this on 'swapmap' will result in 2616516Sfeldman * a failure return. This is due mainly to laziness and could be fixed 2626516Sfeldman * to do the right thing, although it probably will never be used. 2636516Sfeldman */ 2646516Sfeldman rmget(mp, size, addr) 2656516Sfeldman register struct map *mp; 2666516Sfeldman { 2676516Sfeldman register struct mapent *ep = (struct mapent *)(mp+1); 2686516Sfeldman register struct mapent *bp, *bp2; 2696516Sfeldman 2706516Sfeldman if (size <= 0) 2716516Sfeldman panic("rmget"); 2726516Sfeldman if (mp == swapmap) 2736516Sfeldman return (0); 2746516Sfeldman /* 2756516Sfeldman * Look for a map segment containing the requested address. 2766516Sfeldman * If none found, return failure. 2776516Sfeldman */ 2786516Sfeldman for (bp = ep; bp->m_size; bp++) 2796516Sfeldman if (bp->m_addr <= addr && bp->m_addr + bp->m_size > addr) 2806516Sfeldman break; 2816516Sfeldman if (bp->m_size == 0) 2826516Sfeldman return (0); 2836516Sfeldman 2846516Sfeldman /* 2856516Sfeldman * If segment is too small, return failure. 2866516Sfeldman * If big enough, allocate the block, compressing or expanding 2876516Sfeldman * the map as necessary. 2886516Sfeldman */ 2896516Sfeldman if (bp->m_addr + bp->m_size < addr + size) 2906516Sfeldman return (0); 2916516Sfeldman if (bp->m_addr == addr) 2926516Sfeldman if (bp->m_addr + bp->m_size == addr + size) { 2936516Sfeldman /* 2946516Sfeldman * Allocate entire segment and compress map 2956516Sfeldman */ 2966516Sfeldman bp2 = bp; 2976516Sfeldman while (bp2->m_size) { 2986516Sfeldman bp2++; 2996516Sfeldman (bp2-1)->m_addr = bp2->m_addr; 3006516Sfeldman (bp2-1)->m_size = bp2->m_size; 3016516Sfeldman } 3026516Sfeldman } else { 3036516Sfeldman /* 3046516Sfeldman * Allocate first part of segment 3056516Sfeldman */ 3066516Sfeldman bp->m_addr += size; 3076516Sfeldman bp->m_size -= size; 3086516Sfeldman } 3096516Sfeldman else 3106516Sfeldman if (bp->m_addr + bp->m_size == addr + size) { 3116516Sfeldman /* 3126516Sfeldman * Allocate last part of segment 3136516Sfeldman */ 3146516Sfeldman bp->m_size -= size; 3156516Sfeldman } else { 3166516Sfeldman /* 3176516Sfeldman * Allocate from middle of segment, but only 3186516Sfeldman * if table can be expanded. 3196516Sfeldman */ 3206516Sfeldman for (bp2=bp; bp2->m_size; bp2++) 3216516Sfeldman ; 32225113Sbloom if (bp2 + 1 >= mp->m_limit) 3236516Sfeldman return (0); 3246516Sfeldman while (bp2 > bp) { 3256516Sfeldman (bp2+1)->m_addr = bp2->m_addr; 3266516Sfeldman (bp2+1)->m_size = bp2->m_size; 3276516Sfeldman bp2--; 3286516Sfeldman } 3296516Sfeldman (bp+1)->m_addr = addr + size; 3306516Sfeldman (bp+1)->m_size = 3316516Sfeldman bp->m_addr + bp->m_size - (addr + size); 3326516Sfeldman bp->m_size = addr - bp->m_addr; 3336516Sfeldman } 3346516Sfeldman return (addr); 3356516Sfeldman } 336