1*2781Swnj /* subr_rmap.c 4.2 02/28/81 */ 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 /* 13*2781Swnj * Resource map handling routines. 14*2781Swnj * 15*2781Swnj * A resource map is an array of structures each 16*2781Swnj * of which describes a segment of the address space of an available 17*2781Swnj * resource. The segments are described by their base address and 18*2781Swnj * length, and sorted in address order. Each resource map has a fixed 19*2781Swnj * maximum number of segments allowed. Resources are allocated 20*2781Swnj * by taking part or all of one of the segments of the map. 21*2781Swnj * 22*2781Swnj * Returning of resources will require another segment if 23*2781Swnj * the returned resources are not adjacent in the address 24*2781Swnj * space to an existing segment. If the return of a segment 25*2781Swnj * would require a slot which is not available, then one of 26*2781Swnj * the resource map segments is discarded after a warning is printed. 27*2781Swnj * Returning of resources may also cause the map to collapse 28*2781Swnj * by coalescing two existing segments and the returned space 29*2781Swnj * into a single segment. In this case the resource map is 30*2781Swnj * made smaller by copying together to fill the resultant gap. 31*2781Swnj * 32*2781Swnj * N.B.: the current implementation uses a dense array and does 33*2781Swnj * not admit the value ``0'' as a legal address, since that is used 34*2781Swnj * as a delimiter. 35*2781Swnj */ 36*2781Swnj 37*2781Swnj /* 38*2781Swnj * Initialize map mp to have (mapsize-2) segments 39*2781Swnj * and to be called ``name'', which we print if 40*2781Swnj * the slots become so fragmented that we lose space. 41*2781Swnj * The map itself is initialized with size elements free 42*2781Swnj * starting at addr. 43*2781Swnj */ 44*2781Swnj rminit(mp, size, addr, name, mapsize) 45*2781Swnj register struct map *mp; 46*2781Swnj int size, addr; 47*2781Swnj char *name; 48*2781Swnj int mapsize; 49*2781Swnj { 50*2781Swnj register struct mapent *ep = (struct mapent *)(mp+1); 51*2781Swnj 52*2781Swnj mp->m_name = name; 53*2781Swnj /* N.B.: WE ASSUME HERE THAT sizeof (struct map) == sizeof (struct mapent) */ 54*2781Swnj /* 55*2781Swnj * One of the mapsize slots is taken by the map structure, 56*2781Swnj * segments has size 0 and addr 0, and acts as a delimiter. 57*2781Swnj * We insure that we never use segments past the end of 58*2781Swnj * the array which is given by mp->m_limit. 59*2781Swnj * Instead, when excess segments occur we discard some resources. 60*2781Swnj */ 61*2781Swnj mp->m_limit = (struct mapent *)&mp[mapsize]; 62*2781Swnj /* 63*2781Swnj * Simulate a rmfree(), but with the option to 64*2781Swnj * call with size 0 and addr 0 when we just want 65*2781Swnj * to initialize without freeing. 66*2781Swnj */ 67*2781Swnj ep->m_size = size; 68*2781Swnj ep->m_addr = addr; 69*2781Swnj } 70*2781Swnj 71*2781Swnj /* 7227Sbill * Allocate 'size' units from the given 73*2781Swnj * 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. 76*2781Swnj * 7727Sbill * Algorithm is first-fit. 78*2781Swnj * 79*2781Swnj * This routine knows about the interleaving of the swapmap 80*2781Swnj * and handles that. 8127Sbill */ 82*2781Swnj rmalloc(mp, size) 83*2781Swnj register struct map *mp; 8427Sbill { 85*2781Swnj register struct mapent *ep = (struct mapent *)(mp+1); 86*2781Swnj register int addr; 87*2781Swnj register struct mapent *bp; 88307Sbill swblk_t first, rest; 8927Sbill 90307Sbill if (size <= 0 || mp == swapmap && size > DMMAX) 91*2781Swnj panic("rmalloc"); 92*2781Swnj /* 93*2781Swnj * Search for a piece of the resource map which has enough 94*2781Swnj * free space to accomodate the request. 95*2781Swnj */ 96*2781Swnj for (bp = ep; bp->m_size; bp++) { 9727Sbill if (bp->m_size >= size) { 98*2781Swnj /* 99*2781Swnj * If allocating from swapmap, 100*2781Swnj * then have to respect interleaving 101*2781Swnj * boundaries. 102*2781Swnj */ 103307Sbill if (mp == swapmap && 104307Sbill (first = DMMAX - bp->m_addr%DMMAX) < bp->m_size) { 105307Sbill if (bp->m_size - first < size) 106307Sbill continue; 107*2781Swnj addr = bp->m_addr + first; 108307Sbill rest = bp->m_size - first - size; 109307Sbill bp->m_size = first; 110307Sbill if (rest) 111*2781Swnj rmfree(swapmap, rest, addr+size); 112*2781Swnj return (addr); 113307Sbill } 114*2781Swnj /* 115*2781Swnj * Allocate from the map. 116*2781Swnj * If there is no space left of the piece 117*2781Swnj * we allocated from, move the rest of 118*2781Swnj * the pieces to the left. 119*2781Swnj */ 120*2781Swnj 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 } 128*2781Swnj if (mp == swapmap && addr % CLSIZE) 129*2781Swnj panic("rmalloc swapmap"); 130*2781Swnj return (addr); 13127Sbill } 13227Sbill } 133*2781Swnj return (0); 13427Sbill } 13527Sbill 13627Sbill /* 137*2781Swnj * Free the previously allocated space at addr 13827Sbill * of size units into the specified map. 139*2781Swnj * Sort addr into map and combine on 14027Sbill * one or both ends if possible. 14127Sbill */ 142*2781Swnj rmfree(mp, size, addr) 143*2781Swnj struct map *mp; 144*2781Swnj register int size, addr; 14527Sbill { 146*2781Swnj struct mapent *firstbp; 147*2781Swnj register struct mapent *bp; 14827Sbill register int t; 14927Sbill 150*2781Swnj /* 151*2781Swnj * Both address and size must be 152*2781Swnj * positive, or the protocol has broken down. 153*2781Swnj */ 154*2781Swnj if (addr <= 0 || size <= 0) 155*2781Swnj goto badrmfree; 156*2781Swnj /* 157*2781Swnj * Locate the piece of the map which starts after the 158*2781Swnj * returned space (or the end of the map). 159*2781Swnj */ 160*2781Swnj firstbp = bp = (struct mapent *)(mp + 1); 161*2781Swnj for (; bp->m_addr <= addr && bp->m_size != 0; bp++) 16227Sbill continue; 163*2781Swnj /* 164*2781Swnj * If the piece on the left abuts us, 165*2781Swnj * then we should combine with it. 166*2781Swnj */ 167*2781Swnj if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) { 168*2781Swnj /* 169*2781Swnj * Check no overlap (internal error). 170*2781Swnj */ 171*2781Swnj if ((bp-1)->m_addr+(bp-1)->m_size > addr) 172*2781Swnj goto badrmfree; 173*2781Swnj /* 174*2781Swnj * Add into piece on the left by increasing its size. 175*2781Swnj */ 17627Sbill (bp-1)->m_size += size; 177*2781Swnj /* 178*2781Swnj * If the combined piece abuts the piece on 179*2781Swnj * the right now, compress it in also, 180*2781Swnj * by shifting the remaining pieces of the map over. 181*2781Swnj */ 182*2781Swnj if (bp->m_addr && addr+size >= bp->m_addr) { 183*2781Swnj if (addr+size > bp->m_addr) 184*2781Swnj 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 } 192*2781Swnj goto done; 19327Sbill } 194*2781Swnj /* 195*2781Swnj * Don't abut on the left, check for abutting on 196*2781Swnj * the right. 197*2781Swnj */ 198*2781Swnj if (addr+size >= bp->m_addr && bp->m_size) { 199*2781Swnj if (addr+size > bp->m_addr) 200*2781Swnj goto badrmfree; 201*2781Swnj bp->m_addr -= size; 202*2781Swnj bp->m_size += size; 203*2781Swnj goto done; 204*2781Swnj } 205*2781Swnj /* 206*2781Swnj * Don't abut at all. Make a new entry 207*2781Swnj * and check for map overflow. 208*2781Swnj */ 209*2781Swnj do { 210*2781Swnj t = bp->m_addr; 211*2781Swnj bp->m_addr = addr; 212*2781Swnj addr = t; 213*2781Swnj t = bp->m_size; 214*2781Swnj bp->m_size = size; 215*2781Swnj bp++; 216*2781Swnj } while (size = t); 217*2781Swnj /* 218*2781Swnj * Segment at bp is to be the delimiter; 219*2781Swnj * If there is not room for it 220*2781Swnj * then the table is too full 221*2781Swnj * and we must discard something. 222*2781Swnj */ 223*2781Swnj if (bp+1 > mp->m_limit) { 224*2781Swnj /* 225*2781Swnj * Back bp up to last available segment. 226*2781Swnj * which contains a segment already and must 227*2781Swnj * be made into the delimiter. 228*2781Swnj * Discard second to last entry, 229*2781Swnj * since it is presumably smaller than the last 230*2781Swnj * and move the last entry back one. 231*2781Swnj */ 232*2781Swnj bp--; 233*2781Swnj printf("%s rmap overflow, lost [%d,%d)\n", mp->m_name, 234*2781Swnj (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size); 235*2781Swnj bp[-1] = bp[0]; 236*2781Swnj bp[0].m_size = bp[0].m_addr = 0; 237*2781Swnj } 238*2781Swnj done: 239*2781Swnj /* 240*2781Swnj * THIS IS RIDICULOUS... IT DOESN'T BELONG HERE! 241*2781Swnj */ 24227Sbill if ((mp == kernelmap) && kmapwnt) { 24327Sbill kmapwnt = 0; 24427Sbill wakeup((caddr_t)kernelmap); 24527Sbill } 246*2781Swnj return; 247*2781Swnj badrmfree: 248*2781Swnj panic("bad rmfree"); 24927Sbill } 250