149589Sbostic /*- 249589Sbostic * Copyright (c) 1982, 1986 The Regents of the University of California. 349589Sbostic * All rights reserved. 423382Smckusick * 549589Sbostic * %sccs.include.proprietary.c% 649589Sbostic * 7*56517Sbostic * @(#)subr_rmap.c 7.11 (Berkeley) 10/11/92 823382Smckusick */ 927Sbill 10*56517Sbostic #include <sys/param.h> 11*56517Sbostic #include <sys/systm.h> 12*56517Sbostic #include <sys/map.h> 13*56517Sbostic #include <sys/dmap.h> /* XXX */ 14*56517Sbostic #include <sys/proc.h> 15*56517Sbostic #include <sys/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 */ 4953470Sbostic void 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; 7533605Skarels (++ep)->m_size = 0; 7633605Skarels ep->m_addr = 0; 772781Swnj } 782781Swnj 792781Swnj /* 8049673Smckusick * A piece of memory of at least size units is allocated from the 8149673Smckusick * specified map using a first-fit algorithm. It returns the starting 8249673Smckusick * address of the allocated space. 832781Swnj * 8449673Smckusick * This routine knows about and handles the interleaving of the swapmap. 8527Sbill */ 868766Sroot long 872781Swnj rmalloc(mp, size) 882781Swnj register struct map *mp; 898766Sroot long size; 9027Sbill { 912781Swnj register struct mapent *ep = (struct mapent *)(mp+1); 922781Swnj register int addr; 932781Swnj register struct mapent *bp; 94307Sbill swblk_t first, rest; 9527Sbill 9612489Ssam if (size <= 0 || mp == swapmap && size > dmmax) 972781Swnj panic("rmalloc"); 982781Swnj /* 992781Swnj * Search for a piece of the resource map which has enough 1002781Swnj * free space to accomodate the request. 1012781Swnj */ 1022781Swnj for (bp = ep; bp->m_size; bp++) { 10327Sbill if (bp->m_size >= size) { 1042781Swnj /* 1052781Swnj * If allocating from swapmap, 1062781Swnj * then have to respect interleaving 1072781Swnj * boundaries. 1082781Swnj */ 10912489Ssam if (mp == swapmap && nswdev > 1 && 11041988Smckusick (first = dmmax - bp->m_addr%dmmax) < size) { 111307Sbill if (bp->m_size - first < size) 112307Sbill continue; 1132781Swnj addr = bp->m_addr + first; 114307Sbill rest = bp->m_size - first - size; 115307Sbill bp->m_size = first; 116307Sbill if (rest) 1172781Swnj rmfree(swapmap, rest, addr+size); 1182781Swnj return (addr); 119307Sbill } 1202781Swnj /* 1212781Swnj * Allocate from the map. 1222781Swnj * If there is no space left of the piece 1232781Swnj * we allocated from, move the rest of 1242781Swnj * the pieces to the left. 1252781Swnj */ 1262781Swnj addr = bp->m_addr; 12727Sbill bp->m_addr += size; 12827Sbill if ((bp->m_size -= size) == 0) { 12927Sbill do { 13027Sbill bp++; 13127Sbill (bp-1)->m_addr = bp->m_addr; 13227Sbill } while ((bp-1)->m_size = bp->m_size); 13327Sbill } 1342781Swnj if (mp == swapmap && addr % CLSIZE) 1352781Swnj panic("rmalloc swapmap"); 1362781Swnj return (addr); 13727Sbill } 13827Sbill } 1392781Swnj return (0); 14027Sbill } 14127Sbill 14227Sbill /* 14349673Smckusick * The previously allocated space at addr of size units is freed 14449673Smckusick * into the specified map. This routine is responsible for sorting 14549673Smckusick * the frred space into the correct location in the map, and coalescing 14649673Smckusick * it with free space on either side if they adjoin. 14727Sbill */ 14853470Sbostic void 1492781Swnj rmfree(mp, size, addr) 1502781Swnj struct map *mp; 1518766Sroot long size, addr; 15227Sbill { 1532781Swnj struct mapent *firstbp; 1542781Swnj register struct mapent *bp; 15527Sbill register int t; 15627Sbill 1572781Swnj /* 1582781Swnj * Both address and size must be 1592781Swnj * positive, or the protocol has broken down. 1602781Swnj */ 1612781Swnj if (addr <= 0 || size <= 0) 1622781Swnj goto badrmfree; 1632781Swnj /* 1642781Swnj * Locate the piece of the map which starts after the 1652781Swnj * returned space (or the end of the map). 1662781Swnj */ 1672781Swnj firstbp = bp = (struct mapent *)(mp + 1); 1682781Swnj for (; bp->m_addr <= addr && bp->m_size != 0; bp++) 16927Sbill continue; 1702781Swnj /* 1712781Swnj * If the piece on the left abuts us, 1722781Swnj * then we should combine with it. 1732781Swnj */ 1742781Swnj if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) { 1752781Swnj /* 1762781Swnj * Check no overlap (internal error). 1772781Swnj */ 1782781Swnj if ((bp-1)->m_addr+(bp-1)->m_size > addr) 1792781Swnj goto badrmfree; 1802781Swnj /* 1812781Swnj * Add into piece on the left by increasing its size. 1822781Swnj */ 18327Sbill (bp-1)->m_size += size; 1842781Swnj /* 1852781Swnj * If the combined piece abuts the piece on 1862781Swnj * the right now, compress it in also, 1872781Swnj * by shifting the remaining pieces of the map over. 1882781Swnj */ 1892781Swnj if (bp->m_addr && addr+size >= bp->m_addr) { 1902781Swnj if (addr+size > bp->m_addr) 1912781Swnj goto badrmfree; 19227Sbill (bp-1)->m_size += bp->m_size; 19327Sbill while (bp->m_size) { 19427Sbill bp++; 19527Sbill (bp-1)->m_addr = bp->m_addr; 19627Sbill (bp-1)->m_size = bp->m_size; 19727Sbill } 19827Sbill } 19949281Shibler return; 20027Sbill } 2012781Swnj /* 2022781Swnj * Don't abut on the left, check for abutting on 2032781Swnj * the right. 2042781Swnj */ 2052781Swnj if (addr+size >= bp->m_addr && bp->m_size) { 2062781Swnj if (addr+size > bp->m_addr) 2072781Swnj goto badrmfree; 2082781Swnj bp->m_addr -= size; 2092781Swnj bp->m_size += size; 21049281Shibler return; 2112781Swnj } 2122781Swnj /* 2132781Swnj * Don't abut at all. Make a new entry 2142781Swnj * and check for map overflow. 2152781Swnj */ 2162781Swnj do { 2172781Swnj t = bp->m_addr; 2182781Swnj bp->m_addr = addr; 2192781Swnj addr = t; 2202781Swnj t = bp->m_size; 2212781Swnj bp->m_size = size; 2222781Swnj bp++; 2232781Swnj } while (size = t); 2242781Swnj /* 2252781Swnj * Segment at bp is to be the delimiter; 2262781Swnj * If there is not room for it 2272781Swnj * then the table is too full 2282781Swnj * and we must discard something. 2292781Swnj */ 2302781Swnj if (bp+1 > mp->m_limit) { 2312781Swnj /* 2322781Swnj * Back bp up to last available segment. 2332781Swnj * which contains a segment already and must 2342781Swnj * be made into the delimiter. 2352781Swnj * Discard second to last entry, 2362781Swnj * since it is presumably smaller than the last 2372781Swnj * and move the last entry back one. 2382781Swnj */ 2392781Swnj bp--; 2402937Swnj printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name, 2412781Swnj (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size); 2422781Swnj bp[-1] = bp[0]; 2432781Swnj bp[0].m_size = bp[0].m_addr = 0; 2442781Swnj } 2452781Swnj return; 2462781Swnj badrmfree: 2472781Swnj panic("bad rmfree"); 24827Sbill } 249