123382Smckusick /* 229102Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323382Smckusick * All rights reserved. The Berkeley software License Agreement 423382Smckusick * specifies the terms and conditions for redistribution. 523382Smckusick * 6*33605Skarels * @(#)subr_rmap.c 7.2 (Berkeley) 02/27/88 723382Smckusick */ 827Sbill 917094Sbloom #include "param.h" 1017094Sbloom #include "systm.h" 1117094Sbloom #include "map.h" 1217094Sbloom #include "dir.h" 1317094Sbloom #include "user.h" 1417094Sbloom #include "proc.h" 1517094Sbloom #include "text.h" 1617094Sbloom #include "kernel.h" 1727Sbill 1827Sbill /* 192781Swnj * Resource map handling routines. 202781Swnj * 212781Swnj * A resource map is an array of structures each 222781Swnj * of which describes a segment of the address space of an available 232781Swnj * resource. The segments are described by their base address and 242781Swnj * length, and sorted in address order. Each resource map has a fixed 252781Swnj * maximum number of segments allowed. Resources are allocated 262781Swnj * by taking part or all of one of the segments of the map. 272781Swnj * 282781Swnj * Returning of resources will require another segment if 292781Swnj * the returned resources are not adjacent in the address 302781Swnj * space to an existing segment. If the return of a segment 312781Swnj * would require a slot which is not available, then one of 322781Swnj * the resource map segments is discarded after a warning is printed. 332781Swnj * Returning of resources may also cause the map to collapse 342781Swnj * by coalescing two existing segments and the returned space 352781Swnj * into a single segment. In this case the resource map is 362781Swnj * made smaller by copying together to fill the resultant gap. 372781Swnj * 382781Swnj * N.B.: the current implementation uses a dense array and does 392781Swnj * not admit the value ``0'' as a legal address, since that is used 402781Swnj * as a delimiter. 412781Swnj */ 422781Swnj 432781Swnj /* 442781Swnj * Initialize map mp to have (mapsize-2) segments 452781Swnj * and to be called ``name'', which we print if 462781Swnj * the slots become so fragmented that we lose space. 472781Swnj * The map itself is initialized with size elements free 482781Swnj * starting at addr. 492781Swnj */ 502781Swnj rminit(mp, size, addr, name, mapsize) 512781Swnj register struct map *mp; 528790Sroot long size, addr; 532781Swnj char *name; 542781Swnj int mapsize; 552781Swnj { 562781Swnj register struct mapent *ep = (struct mapent *)(mp+1); 572781Swnj 582781Swnj mp->m_name = name; 592781Swnj /* N.B.: WE ASSUME HERE THAT sizeof (struct map) == sizeof (struct mapent) */ 602781Swnj /* 612781Swnj * One of the mapsize slots is taken by the map structure, 622781Swnj * segments has size 0 and addr 0, and acts as a delimiter. 632781Swnj * We insure that we never use segments past the end of 642781Swnj * the array which is given by mp->m_limit. 652781Swnj * Instead, when excess segments occur we discard some resources. 662781Swnj */ 672781Swnj mp->m_limit = (struct mapent *)&mp[mapsize]; 682781Swnj /* 692781Swnj * Simulate a rmfree(), but with the option to 702781Swnj * call with size 0 and addr 0 when we just want 712781Swnj * to initialize without freeing. 722781Swnj */ 732781Swnj ep->m_size = size; 742781Swnj ep->m_addr = addr; 75*33605Skarels (++ep)->m_size = 0; 76*33605Skarels ep->m_addr = 0; 772781Swnj } 782781Swnj 792781Swnj /* 8027Sbill * Allocate 'size' units from the given 812781Swnj * map. Return the base of the allocated space. 8227Sbill * In a map, the addresses are increasing and the 8327Sbill * list is terminated by a 0 size. 842781Swnj * 8527Sbill * Algorithm is first-fit. 862781Swnj * 872781Swnj * This routine knows about the interleaving of the swapmap 882781Swnj * and handles that. 8927Sbill */ 908766Sroot long 912781Swnj rmalloc(mp, size) 922781Swnj register struct map *mp; 938766Sroot long size; 9427Sbill { 952781Swnj register struct mapent *ep = (struct mapent *)(mp+1); 962781Swnj register int addr; 972781Swnj register struct mapent *bp; 98307Sbill swblk_t first, rest; 9927Sbill 10012489Ssam if (size <= 0 || mp == swapmap && size > dmmax) 1012781Swnj panic("rmalloc"); 1022781Swnj /* 1032781Swnj * Search for a piece of the resource map which has enough 1042781Swnj * free space to accomodate the request. 1052781Swnj */ 1062781Swnj for (bp = ep; bp->m_size; bp++) { 10727Sbill if (bp->m_size >= size) { 1082781Swnj /* 1092781Swnj * If allocating from swapmap, 1102781Swnj * then have to respect interleaving 1112781Swnj * boundaries. 1122781Swnj */ 11312489Ssam if (mp == swapmap && nswdev > 1 && 11412489Ssam (first = dmmax - bp->m_addr%dmmax) < bp->m_size) { 115307Sbill if (bp->m_size - first < size) 116307Sbill continue; 1172781Swnj addr = bp->m_addr + first; 118307Sbill rest = bp->m_size - first - size; 119307Sbill bp->m_size = first; 120307Sbill if (rest) 1212781Swnj rmfree(swapmap, rest, addr+size); 1222781Swnj return (addr); 123307Sbill } 1242781Swnj /* 1252781Swnj * Allocate from the map. 1262781Swnj * If there is no space left of the piece 1272781Swnj * we allocated from, move the rest of 1282781Swnj * the pieces to the left. 1292781Swnj */ 1302781Swnj addr = bp->m_addr; 13127Sbill bp->m_addr += size; 13227Sbill if ((bp->m_size -= size) == 0) { 13327Sbill do { 13427Sbill bp++; 13527Sbill (bp-1)->m_addr = bp->m_addr; 13627Sbill } while ((bp-1)->m_size = bp->m_size); 13727Sbill } 1382781Swnj if (mp == swapmap && addr % CLSIZE) 1392781Swnj panic("rmalloc swapmap"); 1402781Swnj return (addr); 14127Sbill } 14227Sbill } 1432781Swnj return (0); 14427Sbill } 14527Sbill 14627Sbill /* 1472781Swnj * Free the previously allocated space at addr 14827Sbill * of size units into the specified map. 1492781Swnj * Sort addr into map and combine on 15027Sbill * one or both ends if possible. 15127Sbill */ 1522781Swnj rmfree(mp, size, addr) 1532781Swnj struct map *mp; 1548766Sroot long size, addr; 15527Sbill { 1562781Swnj struct mapent *firstbp; 1572781Swnj register struct mapent *bp; 15827Sbill register int t; 15927Sbill 1602781Swnj /* 1612781Swnj * Both address and size must be 1622781Swnj * positive, or the protocol has broken down. 1632781Swnj */ 1642781Swnj if (addr <= 0 || size <= 0) 1652781Swnj goto badrmfree; 1662781Swnj /* 1672781Swnj * Locate the piece of the map which starts after the 1682781Swnj * returned space (or the end of the map). 1692781Swnj */ 1702781Swnj firstbp = bp = (struct mapent *)(mp + 1); 1712781Swnj for (; bp->m_addr <= addr && bp->m_size != 0; bp++) 17227Sbill continue; 1732781Swnj /* 1742781Swnj * If the piece on the left abuts us, 1752781Swnj * then we should combine with it. 1762781Swnj */ 1772781Swnj if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) { 1782781Swnj /* 1792781Swnj * Check no overlap (internal error). 1802781Swnj */ 1812781Swnj if ((bp-1)->m_addr+(bp-1)->m_size > addr) 1822781Swnj goto badrmfree; 1832781Swnj /* 1842781Swnj * Add into piece on the left by increasing its size. 1852781Swnj */ 18627Sbill (bp-1)->m_size += size; 1872781Swnj /* 1882781Swnj * If the combined piece abuts the piece on 1892781Swnj * the right now, compress it in also, 1902781Swnj * by shifting the remaining pieces of the map over. 1912781Swnj */ 1922781Swnj if (bp->m_addr && addr+size >= bp->m_addr) { 1932781Swnj if (addr+size > bp->m_addr) 1942781Swnj goto badrmfree; 19527Sbill (bp-1)->m_size += bp->m_size; 19627Sbill while (bp->m_size) { 19727Sbill bp++; 19827Sbill (bp-1)->m_addr = bp->m_addr; 19927Sbill (bp-1)->m_size = bp->m_size; 20027Sbill } 20127Sbill } 2022781Swnj goto done; 20327Sbill } 2042781Swnj /* 2052781Swnj * Don't abut on the left, check for abutting on 2062781Swnj * the right. 2072781Swnj */ 2082781Swnj if (addr+size >= bp->m_addr && bp->m_size) { 2092781Swnj if (addr+size > bp->m_addr) 2102781Swnj goto badrmfree; 2112781Swnj bp->m_addr -= size; 2122781Swnj bp->m_size += size; 2132781Swnj goto done; 2142781Swnj } 2152781Swnj /* 2162781Swnj * Don't abut at all. Make a new entry 2172781Swnj * and check for map overflow. 2182781Swnj */ 2192781Swnj do { 2202781Swnj t = bp->m_addr; 2212781Swnj bp->m_addr = addr; 2222781Swnj addr = t; 2232781Swnj t = bp->m_size; 2242781Swnj bp->m_size = size; 2252781Swnj bp++; 2262781Swnj } while (size = t); 2272781Swnj /* 2282781Swnj * Segment at bp is to be the delimiter; 2292781Swnj * If there is not room for it 2302781Swnj * then the table is too full 2312781Swnj * and we must discard something. 2322781Swnj */ 2332781Swnj if (bp+1 > mp->m_limit) { 2342781Swnj /* 2352781Swnj * Back bp up to last available segment. 2362781Swnj * which contains a segment already and must 2372781Swnj * be made into the delimiter. 2382781Swnj * Discard second to last entry, 2392781Swnj * since it is presumably smaller than the last 2402781Swnj * and move the last entry back one. 2412781Swnj */ 2422781Swnj bp--; 2432937Swnj printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name, 2442781Swnj (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size); 2452781Swnj bp[-1] = bp[0]; 2462781Swnj bp[0].m_size = bp[0].m_addr = 0; 2472781Swnj } 2482781Swnj done: 2492781Swnj /* 2502781Swnj * THIS IS RIDICULOUS... IT DOESN'T BELONG HERE! 2512781Swnj */ 25227Sbill if ((mp == kernelmap) && kmapwnt) { 25327Sbill kmapwnt = 0; 25427Sbill wakeup((caddr_t)kernelmap); 25527Sbill } 2562781Swnj return; 2572781Swnj badrmfree: 2582781Swnj panic("bad rmfree"); 25927Sbill } 2606516Sfeldman 2616516Sfeldman /* 2626516Sfeldman * Allocate 'size' units from the given map, starting at address 'addr'. 2636516Sfeldman * Return 'addr' if successful, 0 if not. 2646516Sfeldman * This may cause the creation or destruction of a resource map segment. 2656516Sfeldman * 2666516Sfeldman * This routine will return failure status if there is not enough room 2676516Sfeldman * for a required additional map segment. 2686516Sfeldman * 2696516Sfeldman * An attempt to use this on 'swapmap' will result in 2706516Sfeldman * a failure return. This is due mainly to laziness and could be fixed 2716516Sfeldman * to do the right thing, although it probably will never be used. 2726516Sfeldman */ 2736516Sfeldman rmget(mp, size, addr) 2746516Sfeldman register struct map *mp; 2756516Sfeldman { 2766516Sfeldman register struct mapent *ep = (struct mapent *)(mp+1); 2776516Sfeldman register struct mapent *bp, *bp2; 2786516Sfeldman 2796516Sfeldman if (size <= 0) 2806516Sfeldman panic("rmget"); 2816516Sfeldman if (mp == swapmap) 2826516Sfeldman return (0); 2836516Sfeldman /* 2846516Sfeldman * Look for a map segment containing the requested address. 2856516Sfeldman * If none found, return failure. 2866516Sfeldman */ 2876516Sfeldman for (bp = ep; bp->m_size; bp++) 2886516Sfeldman if (bp->m_addr <= addr && bp->m_addr + bp->m_size > addr) 2896516Sfeldman break; 2906516Sfeldman if (bp->m_size == 0) 2916516Sfeldman return (0); 2926516Sfeldman 2936516Sfeldman /* 2946516Sfeldman * If segment is too small, return failure. 2956516Sfeldman * If big enough, allocate the block, compressing or expanding 2966516Sfeldman * the map as necessary. 2976516Sfeldman */ 2986516Sfeldman if (bp->m_addr + bp->m_size < addr + size) 2996516Sfeldman return (0); 3006516Sfeldman if (bp->m_addr == addr) 3016516Sfeldman if (bp->m_addr + bp->m_size == addr + size) { 3026516Sfeldman /* 3036516Sfeldman * Allocate entire segment and compress map 3046516Sfeldman */ 3056516Sfeldman bp2 = bp; 3066516Sfeldman while (bp2->m_size) { 3076516Sfeldman bp2++; 3086516Sfeldman (bp2-1)->m_addr = bp2->m_addr; 3096516Sfeldman (bp2-1)->m_size = bp2->m_size; 3106516Sfeldman } 3116516Sfeldman } else { 3126516Sfeldman /* 3136516Sfeldman * Allocate first part of segment 3146516Sfeldman */ 3156516Sfeldman bp->m_addr += size; 3166516Sfeldman bp->m_size -= size; 3176516Sfeldman } 3186516Sfeldman else 3196516Sfeldman if (bp->m_addr + bp->m_size == addr + size) { 3206516Sfeldman /* 3216516Sfeldman * Allocate last part of segment 3226516Sfeldman */ 3236516Sfeldman bp->m_size -= size; 3246516Sfeldman } else { 3256516Sfeldman /* 3266516Sfeldman * Allocate from middle of segment, but only 3276516Sfeldman * if table can be expanded. 3286516Sfeldman */ 3296516Sfeldman for (bp2=bp; bp2->m_size; bp2++) 3306516Sfeldman ; 33125113Sbloom if (bp2 + 1 >= mp->m_limit) 3326516Sfeldman return (0); 3336516Sfeldman while (bp2 > bp) { 3346516Sfeldman (bp2+1)->m_addr = bp2->m_addr; 3356516Sfeldman (bp2+1)->m_size = bp2->m_size; 3366516Sfeldman bp2--; 3376516Sfeldman } 3386516Sfeldman (bp+1)->m_addr = addr + size; 3396516Sfeldman (bp+1)->m_size = 3406516Sfeldman bp->m_addr + bp->m_size - (addr + size); 3416516Sfeldman bp->m_size = addr - bp->m_addr; 3426516Sfeldman } 3436516Sfeldman return (addr); 3446516Sfeldman } 345