#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" /* * - locks * - auxilary structure allocation and sizing * - largest size * - could instead coalesce free items on demand (cf. Wulf) * - or lazy buddy (cf. Barkley) */ #define dprint(...) do {if(0)iprint(__VA_ARGS__);}while(0) enum{ MinK= PGSHIFT, MinBsize= (uintmem)1<>MinK) #define IB(x) (((uintmem)(x)< round up */ n = (uint)m; if(sizeof(uintmem)>sizeof(uint) && n != m){ n = (u64int)m>>32; r += 32; } if((n>>8) == 0) return log2v[n] + r; if((n>>16) == 0) return 8 + log2v[n>>8] + r; if((n>>24) == 0) return 16 + log2v[n>>16] + r; return 24 + log2v[n>>24] + r; } void physinit(uintmem top) { int k; uvlong vtop; Blk *b; loginit(); vtop = top; if(vtop > 48ull*1073741824u) top = 48ull*1073741824u; phys.maxb = BI(top); phys.blocks = xalloc((phys.maxb+1)*sizeof(*phys.blocks)); if(phys.blocks == nil) panic("physinit: can't allocate %ud blocks", phys.maxb+1); for(k = 0; k < nelem(phys.blist); k++){ b = &phys.blist[k]; b->forw = b->back = b; } phys.kofb = xalloc((phys.maxb+1)*sizeof(*phys.kofb)); if(phys.kofb == nil) panic("physinit: can't allocate %ud kofb", phys.maxb+1); memset(phys.kofb, 0, sizeof(phys.kofb)); dprint("phys space top=%#P maxb=%#ux (%d)\n", top, phys.maxb, phys.maxb); } uintmem physalloc(usize size) { int j, k; Blk *b, *b2; uintmem a, a2; uint bi; k = log2of(size); if(k < MinK) k = MinK; dprint("size=%lud k=%d\n", size, k); lock(&phys.lk); for(j = k;;){ b = phys.blist[j].forw; if(b != &phys.blist[j]) break; if(++j > MaxK){ unlock(&phys.lk); return 0; /* out of space */ } } b->forw->back = b->back; b->back->forw = b->forw; /* set busy state */ bi = b-phys.blocks; a = IB(bi); phys.kofb[bi] = k | Busy; while(j != k){ /* split */ j--; a2 = a+((uintmem)1<forw = &phys.blist[j]; b2->back = phys.blist[j].back; phys.blist[j].back = b2; b2->back->forw = b2; } unlock(&phys.lk); return a; } void physfree(uintmem a, usize size) { int k; Blk *b, *b2; uintmem a2; uint bi, bi2; k = log2of(size); /* could look it up in phys.kofb */ if(k < MinK) k = MinK; dprint("free %#P %d\n", a, k); bi = BI(a); lock(&phys.lk); if(phys.kofb[bi] != 0 && phys.kofb[bi] != (Busy|k)){ unlock(&phys.lk); panic("balfree: busy %#P odd k k=%d kfob=%#ux", a, k, phys.kofb[bi]); } for(; k != MaxK; k++){ a2 = a ^ ((uintmem)1<= phys.maxb || phys.kofb[bi2] != k) /* valid, not busy, matching size */ break; dprint("combine %#P %#P %d %#P\n", a, a2, k, (uintmem)1<back->forw = b2->forw; b2->forw->back = b2->back; if(a2 < a){ a = a2; bi = bi2; } } phys.kofb[bi] = k; /* sets size and resets Busy */ b = &phys.blocks[bi]; b->forw = &phys.blist[k]; b->back = phys.blist[k].back; phys.blist[k].back = b; b->back->forw = b; unlock(&phys.lk); } void physallocrange(usize *low, usize *high) { *low = 1< phys.maxb){ print("physinitfree: address space too large"); lim = IB(phys.maxb); } /* round base to min block alignment */ base = (base + MinBsize-1) & ~(MinBsize-1); size = lim - base; if(size < MinBsize) return; dprint("physinitfree %#P-%#P [%#P]\n", base, lim, size); /* move up from base in largest blocks that remain aligned */ for(i=0; i= m){ if(base & (m-1)){ print(" ** error: %#P %#P\n", base, m); return; } physfree(base, m); base += m; size -= m; } /* free remaining chunks, decreasing alignment */ for(; size != 0; m >>= 1){ if(size & m){ dprint("\t%#P %#P\n", base, m); if(base & (m-1)){ print(" ** error: %#P %#P\n", base, m); return; } physfree(base, m); base += m; size &= ~m; } } } void physdump(void) { char *s; uintmem a; uint bi; int i, k; Blk *b; s = getconf("*physdump"); if(s == 0 || atoi(s) == 0) return; for(i=0; iforw){ bi = b-phys.blocks; a = IB(bi); k = phys.kofb[bi]; print(" [%#P %d %#ux b=%#P]", a, k, 1<