12c57ff9fSDavid du Colombier /*
22c57ff9fSDavid du Colombier * Buddy allocator for physical memory allocation.
32c57ff9fSDavid du Colombier * One per ACPI affinity domain, to color pages depending on their
42c57ff9fSDavid du Colombier * NUMA location.
52c57ff9fSDavid du Colombier *
62c57ff9fSDavid du Colombier */
72c57ff9fSDavid du Colombier #include "u.h"
82c57ff9fSDavid du Colombier #include "../port/lib.h"
92c57ff9fSDavid du Colombier #include "mem.h"
102c57ff9fSDavid du Colombier #include "dat.h"
112c57ff9fSDavid du Colombier #include "fns.h"
122c57ff9fSDavid du Colombier #include "acpi.h"
132c57ff9fSDavid du Colombier
142c57ff9fSDavid du Colombier #define ISPOWEROF2(x) (((x) != 0) && !((x) & ((x)-1)))
152c57ff9fSDavid du Colombier #define UNO ((uintmem)1)
162c57ff9fSDavid du Colombier
172c57ff9fSDavid du Colombier enum {
185663e489SDavid du Colombier BKmin = 12, /* Minimum lg2 */
192c57ff9fSDavid du Colombier BKmax = 30, /* Maximum lg2 */
202c57ff9fSDavid du Colombier
212c57ff9fSDavid du Colombier Ndoms = 16, /* Max # of domains */
222c57ff9fSDavid du Colombier
232c57ff9fSDavid du Colombier Used = 0,
242c57ff9fSDavid du Colombier Avail = 1,
252c57ff9fSDavid du Colombier };
262c57ff9fSDavid du Colombier
272c57ff9fSDavid du Colombier
282c57ff9fSDavid du Colombier #define INDEX(b, v) ((uint)(((v))/(b)->bminsz))
292c57ff9fSDavid du Colombier #define BLOCK(b, i) ((i)-INDEX((b),(b)->memory))
302c57ff9fSDavid du Colombier
312c57ff9fSDavid du Colombier typedef struct Buddy Buddy;
322c57ff9fSDavid du Colombier struct Buddy {
332c57ff9fSDavid du Colombier short tag; /* Used or Avail */
342c57ff9fSDavid du Colombier short kval;
352c57ff9fSDavid du Colombier uint next;
362c57ff9fSDavid du Colombier uint prev;
372c57ff9fSDavid du Colombier void *p;
382c57ff9fSDavid du Colombier };
392c57ff9fSDavid du Colombier
402c57ff9fSDavid du Colombier /*
412c57ff9fSDavid du Colombier * Bals should allocate using its base address as 0.
422c57ff9fSDavid du Colombier * For now, all of them refer to the entire memory and we record
432c57ff9fSDavid du Colombier * the base and size for each one.
442c57ff9fSDavid du Colombier */
452c57ff9fSDavid du Colombier typedef struct Bal Bal;
462c57ff9fSDavid du Colombier struct Bal {
472c57ff9fSDavid du Colombier uintmem base;
482c57ff9fSDavid du Colombier u64int size;
492c57ff9fSDavid du Colombier usize nfree;
502c57ff9fSDavid du Colombier usize nblocks;
512c57ff9fSDavid du Colombier int kmin; /* Minimum lg2 */
522c57ff9fSDavid du Colombier int kmax; /* Maximum lg2 */
532c57ff9fSDavid du Colombier uintmem bminsz; /* minimum block sz */
542c57ff9fSDavid du Colombier uintmem memory;
552c57ff9fSDavid du Colombier uint kspan;
562c57ff9fSDavid du Colombier
572c57ff9fSDavid du Colombier Buddy* blocks;
582c57ff9fSDavid du Colombier Buddy* avail;
592c57ff9fSDavid du Colombier };
602c57ff9fSDavid du Colombier
612c57ff9fSDavid du Colombier static Bal bal[Ndoms];
622c57ff9fSDavid du Colombier static int ndoms;
632c57ff9fSDavid du Colombier static Lock budlock;
642c57ff9fSDavid du Colombier
652c57ff9fSDavid du Colombier char*
seprintphysstats(char * s,char * e)662c57ff9fSDavid du Colombier seprintphysstats(char *s, char *e)
672c57ff9fSDavid du Colombier {
682c57ff9fSDavid du Colombier Bal *b;
692c57ff9fSDavid du Colombier int i;
702c57ff9fSDavid du Colombier
712c57ff9fSDavid du Colombier lock(&budlock);
722c57ff9fSDavid du Colombier for(i = 0; i < Ndoms; i++){
732c57ff9fSDavid du Colombier b = &bal[i];
742c57ff9fSDavid du Colombier if(b->size > 0)
752c57ff9fSDavid du Colombier s = seprint(s, e, "%uld/%uld %ulldK color %d blocks avail\n",
762c57ff9fSDavid du Colombier b->nfree, b->nblocks, b->bminsz/KiB, i);
772c57ff9fSDavid du Colombier }
782c57ff9fSDavid du Colombier unlock(&budlock);
792c57ff9fSDavid du Colombier return s;
802c57ff9fSDavid du Colombier }
812c57ff9fSDavid du Colombier
822c57ff9fSDavid du Colombier static void
xphysfree(Bal * b,uintmem data,u64int size)832c57ff9fSDavid du Colombier xphysfree(Bal *b, uintmem data, u64int size)
842c57ff9fSDavid du Colombier {
852c57ff9fSDavid du Colombier uint i;
862c57ff9fSDavid du Colombier Buddy *l, *p;
872c57ff9fSDavid du Colombier Buddy *blocks, *avail;
882c57ff9fSDavid du Colombier
892c57ff9fSDavid du Colombier DBG("physfree\n");
902c57ff9fSDavid du Colombier
912c57ff9fSDavid du Colombier /*
922c57ff9fSDavid du Colombier * Knuth's Algorithm S (Buddy System Liberation).
932c57ff9fSDavid du Colombier */
942c57ff9fSDavid du Colombier blocks = b->blocks;
952c57ff9fSDavid du Colombier avail = b->avail;
962c57ff9fSDavid du Colombier
972c57ff9fSDavid du Colombier if(data == 0 /*|| !ALIGNED(data, b->bminsz)*/)
982c57ff9fSDavid du Colombier return;
992c57ff9fSDavid du Colombier i = INDEX(b,data);
1002c57ff9fSDavid du Colombier
1012c57ff9fSDavid du Colombier lock(&budlock);
1022c57ff9fSDavid du Colombier S1:
1032c57ff9fSDavid du Colombier /*
1042c57ff9fSDavid du Colombier * Find buddy.
1052c57ff9fSDavid du Colombier */
1062c57ff9fSDavid du Colombier l = &blocks[BLOCK(b,i)];
1072c57ff9fSDavid du Colombier l->p = nil;
1082c57ff9fSDavid du Colombier DBG("\tbsl: BLOCK(b,i) %d index %ulld kval %d\n",
1092c57ff9fSDavid du Colombier BLOCK(b,i), BLOCK(b,i)/((1<<l->kval)/b->bminsz), l->kval);
1102c57ff9fSDavid du Colombier if((BLOCK(b,i)/((1<<l->kval)/b->bminsz)) & 1) /* simpler test? */
1112c57ff9fSDavid du Colombier p = l - (1<<l->kval)/b->bminsz;
1122c57ff9fSDavid du Colombier else
1132c57ff9fSDavid du Colombier p = l + (1<<l->kval)/(b->bminsz);
1142c57ff9fSDavid du Colombier DBG("\tbsl: l @ %ld buddy @ %ld\n", l - blocks, p - blocks);
1152c57ff9fSDavid du Colombier
1162c57ff9fSDavid du Colombier /*
1172c57ff9fSDavid du Colombier * Is buddy available?
1182c57ff9fSDavid du Colombier * Can't merge if:
1192c57ff9fSDavid du Colombier * this is the largest block;
1202c57ff9fSDavid du Colombier * buddy isn't free;
1212c57ff9fSDavid du Colombier * buddy has been subsequently split again.
1222c57ff9fSDavid du Colombier */
1232c57ff9fSDavid du Colombier if(l->kval == b->kmax || p->tag == Used || (p->tag == Avail && p->kval != l->kval)){
1242c57ff9fSDavid du Colombier /*
1252c57ff9fSDavid du Colombier * Put on list.
1262c57ff9fSDavid du Colombier */
1272c57ff9fSDavid du Colombier l->tag = Avail;
1282c57ff9fSDavid du Colombier l->next = avail[l->kval].next;
1292c57ff9fSDavid du Colombier l->prev = 0;
1302c57ff9fSDavid du Colombier if(l->next != 0)
1312c57ff9fSDavid du Colombier blocks[BLOCK(b,l->next)].prev = i;
1322c57ff9fSDavid du Colombier avail[l->kval].next = i;
1332c57ff9fSDavid du Colombier
1342c57ff9fSDavid du Colombier b->nfree += size/b->bminsz;
1352c57ff9fSDavid du Colombier
1362c57ff9fSDavid du Colombier unlock(&budlock);
1372c57ff9fSDavid du Colombier DBG("bsl: free @ i %d BLOCK(b,i) %d kval %d next %d %s\n",
1382c57ff9fSDavid du Colombier i, BLOCK(b,i), l->kval, l->next, l->tag?"avail":"used");
1392c57ff9fSDavid du Colombier return;
1402c57ff9fSDavid du Colombier }
1412c57ff9fSDavid du Colombier
1422c57ff9fSDavid du Colombier /*
1432c57ff9fSDavid du Colombier * Combine with buddy.
1442c57ff9fSDavid du Colombier * This removes block P from the avail list.
1452c57ff9fSDavid du Colombier */
146*491cc0e5SDavid du Colombier if(p->prev != 0)
1472c57ff9fSDavid du Colombier blocks[BLOCK(b,p->prev)].next = p->next;
1482c57ff9fSDavid du Colombier else
149*491cc0e5SDavid du Colombier avail[p->kval].next = p->next;
150*491cc0e5SDavid du Colombier if(p->next != 0)
1512c57ff9fSDavid du Colombier blocks[BLOCK(b,p->next)].prev = p->prev;
152*491cc0e5SDavid du Colombier p->next = p->prev = 0;
1532c57ff9fSDavid du Colombier p->tag = Used;
1542c57ff9fSDavid du Colombier
1552c57ff9fSDavid du Colombier /*
1562c57ff9fSDavid du Colombier * Now can try to merge this larger block.
1572c57ff9fSDavid du Colombier k++;
1582c57ff9fSDavid du Colombier */
1592c57ff9fSDavid du Colombier DBG("\tbsl: l @ %ld p @ %ld\n", l - blocks, p - blocks);
1602c57ff9fSDavid du Colombier if(p < l)
1612c57ff9fSDavid du Colombier l = p;
1622c57ff9fSDavid du Colombier i = l - blocks + INDEX(b,b->memory);
1632c57ff9fSDavid du Colombier l->kval++;
1642c57ff9fSDavid du Colombier DBG("bsl: merge @ i %d BLOCK(b,i) %d kval %d next %d tag %s\n",
1652c57ff9fSDavid du Colombier i, BLOCK(b,i), l->kval, l->next, l->tag?"avail":"used");
1662c57ff9fSDavid du Colombier goto S1;
1672c57ff9fSDavid du Colombier }
1682c57ff9fSDavid du Colombier
1692c57ff9fSDavid du Colombier void
physfree(uintmem data,u64int size)1702c57ff9fSDavid du Colombier physfree(uintmem data, u64int size)
1712c57ff9fSDavid du Colombier {
1722c57ff9fSDavid du Colombier Bal *b;
1732c57ff9fSDavid du Colombier int i;
1742c57ff9fSDavid du Colombier
1752c57ff9fSDavid du Colombier for(i = 0; i < Ndoms; i++){
1762c57ff9fSDavid du Colombier b = &bal[i];
1772c57ff9fSDavid du Colombier if(b->base <= data && data < b->base + b->size){
1782c57ff9fSDavid du Colombier xphysfree(b, data, size);
1792c57ff9fSDavid du Colombier return;
1802c57ff9fSDavid du Colombier }
1812c57ff9fSDavid du Colombier }
1822c57ff9fSDavid du Colombier panic("physfree: no bal");
1832c57ff9fSDavid du Colombier }
1842c57ff9fSDavid du Colombier
1852c57ff9fSDavid du Colombier static void*
xphystag(Bal * b,uintmem data)1862c57ff9fSDavid du Colombier xphystag(Bal *b, uintmem data)
1872c57ff9fSDavid du Colombier {
1882c57ff9fSDavid du Colombier uint i;
1892c57ff9fSDavid du Colombier Buddy *blocks;
1902c57ff9fSDavid du Colombier
1912c57ff9fSDavid du Colombier DBG("phystag\n");
1922c57ff9fSDavid du Colombier
1932c57ff9fSDavid du Colombier blocks = b->blocks;
1942c57ff9fSDavid du Colombier
1952c57ff9fSDavid du Colombier if(data == 0 /*|| !ALIGNED(data, b->bminsz)*/)
1962c57ff9fSDavid du Colombier return nil;
1972c57ff9fSDavid du Colombier i = INDEX(b,data);
1982c57ff9fSDavid du Colombier return blocks[BLOCK(b,i)].p;
1992c57ff9fSDavid du Colombier }
2002c57ff9fSDavid du Colombier
2012c57ff9fSDavid du Colombier void*
phystag(uintmem data)2022c57ff9fSDavid du Colombier phystag(uintmem data)
2032c57ff9fSDavid du Colombier {
2042c57ff9fSDavid du Colombier Bal *b;
2052c57ff9fSDavid du Colombier int i;
2062c57ff9fSDavid du Colombier
2072c57ff9fSDavid du Colombier for(i = 0; i < Ndoms; i++){
2082c57ff9fSDavid du Colombier b = &bal[i];
2092c57ff9fSDavid du Colombier if(b->base <= data && data < b->base + b->size)
2102c57ff9fSDavid du Colombier return xphystag(b, data);
2112c57ff9fSDavid du Colombier }
2122c57ff9fSDavid du Colombier return nil;
2132c57ff9fSDavid du Colombier }
2142c57ff9fSDavid du Colombier
2152c57ff9fSDavid du Colombier static uchar lg2table[256] = {
2162c57ff9fSDavid du Colombier 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
2172c57ff9fSDavid du Colombier 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
2182c57ff9fSDavid du Colombier 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2192c57ff9fSDavid du Colombier 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2202c57ff9fSDavid du Colombier 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2212c57ff9fSDavid du Colombier 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2222c57ff9fSDavid du Colombier 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2232c57ff9fSDavid du Colombier 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2242c57ff9fSDavid du Colombier 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2252c57ff9fSDavid du Colombier 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2262c57ff9fSDavid du Colombier 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2272c57ff9fSDavid du Colombier 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2282c57ff9fSDavid du Colombier 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2292c57ff9fSDavid du Colombier 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2302c57ff9fSDavid du Colombier 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2312c57ff9fSDavid du Colombier 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2322c57ff9fSDavid du Colombier };
2332c57ff9fSDavid du Colombier
2342c57ff9fSDavid du Colombier static int
lg2floor(u64int w)2352c57ff9fSDavid du Colombier lg2floor(u64int w)
2362c57ff9fSDavid du Colombier {
2372c57ff9fSDavid du Colombier u64int hi, lo;
2382c57ff9fSDavid du Colombier
2392c57ff9fSDavid du Colombier if((lo = (w>>48)) != 0){
2402c57ff9fSDavid du Colombier if((hi = (lo>>8)) != 0)
2412c57ff9fSDavid du Colombier return 56+lg2table[hi];
2422c57ff9fSDavid du Colombier return 48+lg2table[lo];
2432c57ff9fSDavid du Colombier }
2442c57ff9fSDavid du Colombier if((lo = (w>>32)) != 0){
2452c57ff9fSDavid du Colombier if((hi = (lo>>8)) != 0)
2462c57ff9fSDavid du Colombier return 40+lg2table[hi];
2472c57ff9fSDavid du Colombier return 32+lg2table[lo];
2482c57ff9fSDavid du Colombier }
2492c57ff9fSDavid du Colombier if((lo = (w>>16)) != 0){
2502c57ff9fSDavid du Colombier if((hi = (lo>>8)) != 0)
2512c57ff9fSDavid du Colombier return 24+lg2table[hi];
2522c57ff9fSDavid du Colombier return 16+lg2table[lo];
2532c57ff9fSDavid du Colombier }
2542c57ff9fSDavid du Colombier if((hi = (w>>8)) != 0)
2552c57ff9fSDavid du Colombier return 8+lg2table[hi];
2562c57ff9fSDavid du Colombier return lg2table[w];
2572c57ff9fSDavid du Colombier }
2582c57ff9fSDavid du Colombier
2592c57ff9fSDavid du Colombier static uintmem
xphysalloc(Bal * b,u64int size,void * tag)2602c57ff9fSDavid du Colombier xphysalloc(Bal *b, u64int size, void *tag)
2612c57ff9fSDavid du Colombier {
2622c57ff9fSDavid du Colombier uint i, j, k;
2632c57ff9fSDavid du Colombier Buddy *l, *p;
2642c57ff9fSDavid du Colombier Buddy *avail, *blocks;
2652c57ff9fSDavid du Colombier uintmem m;
2662c57ff9fSDavid du Colombier
2672c57ff9fSDavid du Colombier DBG("physalloc\n");
2682c57ff9fSDavid du Colombier assert(b->size > 0);
2692c57ff9fSDavid du Colombier
2702c57ff9fSDavid du Colombier avail = b->avail;
2712c57ff9fSDavid du Colombier blocks = b->blocks;
2722c57ff9fSDavid du Colombier
2732c57ff9fSDavid du Colombier /*
2742c57ff9fSDavid du Colombier * Knuth's Algorithm R (Buddy System Reservation).
2752c57ff9fSDavid du Colombier */
2762c57ff9fSDavid du Colombier if(size < b->bminsz)
2772c57ff9fSDavid du Colombier size = b->bminsz;
2782c57ff9fSDavid du Colombier
2792c57ff9fSDavid du Colombier /*
2802c57ff9fSDavid du Colombier * Find block.
2812c57ff9fSDavid du Colombier */
2822c57ff9fSDavid du Colombier if(!ISPOWEROF2(size))
2832c57ff9fSDavid du Colombier return 0;
2842c57ff9fSDavid du Colombier k = lg2floor(size);
2852c57ff9fSDavid du Colombier
2862c57ff9fSDavid du Colombier lock(&budlock);
2872c57ff9fSDavid du Colombier for(j = k; j <= b->kmax; j++){
2882c57ff9fSDavid du Colombier if(avail[j].next != 0)
2892c57ff9fSDavid du Colombier break;
2902c57ff9fSDavid du Colombier }
2912c57ff9fSDavid du Colombier DBG("bsr: size %#llud k %d j %d\n", size, k, j);
2922c57ff9fSDavid du Colombier if(j > b->kmax){
2932c57ff9fSDavid du Colombier unlock(&budlock);
2942c57ff9fSDavid du Colombier return 0;
2952c57ff9fSDavid du Colombier }
2962c57ff9fSDavid du Colombier
2972c57ff9fSDavid du Colombier /*
2982c57ff9fSDavid du Colombier * Remove from list.
2992c57ff9fSDavid du Colombier */
3002c57ff9fSDavid du Colombier i = avail[j].next;
3012c57ff9fSDavid du Colombier l = &blocks[BLOCK(b,i)];
3022c57ff9fSDavid du Colombier DBG("bsr: block @ i %d BLOCK(b,i) %d kval %d next %d %s\n",
3032c57ff9fSDavid du Colombier i, BLOCK(b,i), l->kval, l->next, l->tag?"avail":"used");
3042c57ff9fSDavid du Colombier avail[j].next = l->next;
305*491cc0e5SDavid du Colombier if(avail[j].next != 0)
306*491cc0e5SDavid du Colombier blocks[BLOCK(b,avail[j].next)].prev = 0;
3072c57ff9fSDavid du Colombier l->prev = l->next = 0;
3082c57ff9fSDavid du Colombier l->tag = Used;
3092c57ff9fSDavid du Colombier l->kval = k;
3102c57ff9fSDavid du Colombier
3112c57ff9fSDavid du Colombier /*
3122c57ff9fSDavid du Colombier * Split required?
3132c57ff9fSDavid du Colombier */
3142c57ff9fSDavid du Colombier while(j > k){
3152c57ff9fSDavid du Colombier /*
3162c57ff9fSDavid du Colombier * Split.
3172c57ff9fSDavid du Colombier */
3182c57ff9fSDavid du Colombier j--;
3192c57ff9fSDavid du Colombier p = &blocks[BLOCK(b,i) + (UNO<<j)/(b->bminsz)];
3202c57ff9fSDavid du Colombier p->tag = Avail;
3212c57ff9fSDavid du Colombier p->kval = j;
3222c57ff9fSDavid du Colombier p->next = avail[j].next;
3232c57ff9fSDavid du Colombier p->prev = 0;
3242c57ff9fSDavid du Colombier if(p->next != 0)
3252c57ff9fSDavid du Colombier blocks[BLOCK(b,p->next)].prev = i + (UNO<<j)/(b->bminsz);
3262c57ff9fSDavid du Colombier avail[j].next = i + (UNO<<j)/(b->bminsz);
3272c57ff9fSDavid du Colombier DBG("bsr: split @ i %d BLOCK(b,i) %ld j %d next %d (%d) %s\n",
3282c57ff9fSDavid du Colombier i, p - blocks, j, p->next, BLOCK(b,p->next),
3292c57ff9fSDavid du Colombier p->tag?"avail":"used");
3302c57ff9fSDavid du Colombier }
3312c57ff9fSDavid du Colombier b->nfree -= size/b->bminsz;
3322c57ff9fSDavid du Colombier unlock(&budlock);
3332c57ff9fSDavid du Colombier
3342c57ff9fSDavid du Colombier m = b->memory + b->bminsz*BLOCK(b,i);
3352c57ff9fSDavid du Colombier assert(m >= b->base && m < b->base + b->size);
3362c57ff9fSDavid du Colombier blocks[BLOCK(b,i)].p = tag;
3372c57ff9fSDavid du Colombier
3382c57ff9fSDavid du Colombier return m;
3392c57ff9fSDavid du Colombier }
3402c57ff9fSDavid du Colombier
3412c57ff9fSDavid du Colombier uintmem
physalloc(u64int size,int * colorp,void * tag)3422c57ff9fSDavid du Colombier physalloc(u64int size, int *colorp, void *tag)
3432c57ff9fSDavid du Colombier {
3442c57ff9fSDavid du Colombier int i, color;
3452c57ff9fSDavid du Colombier uintmem m;
3462c57ff9fSDavid du Colombier
3472c57ff9fSDavid du Colombier m = 0;
3482c57ff9fSDavid du Colombier
3492c57ff9fSDavid du Colombier color = *colorp;
3502c57ff9fSDavid du Colombier if(color >= 0){
3512c57ff9fSDavid du Colombier color %= ndoms;
3522c57ff9fSDavid du Colombier if(bal[color].kmin > 0){
3532c57ff9fSDavid du Colombier *colorp = color;
3542c57ff9fSDavid du Colombier m = xphysalloc(&bal[color], size, tag);
3552c57ff9fSDavid du Colombier }
3562c57ff9fSDavid du Colombier }
3572c57ff9fSDavid du Colombier if(m == 0)
3582c57ff9fSDavid du Colombier for(i = 0; i < ndoms; i++)
3592c57ff9fSDavid du Colombier if(bal[i].kmin > 0)
3602c57ff9fSDavid du Colombier if((m = xphysalloc(&bal[i], size, tag)) != 0){
3612c57ff9fSDavid du Colombier *colorp = i;
3622c57ff9fSDavid du Colombier return m;
3632c57ff9fSDavid du Colombier }
3642c57ff9fSDavid du Colombier return m;
3652c57ff9fSDavid du Colombier }
3662c57ff9fSDavid du Colombier
3672c57ff9fSDavid du Colombier static void
dump(Bal * b)3682c57ff9fSDavid du Colombier dump(Bal *b)
3692c57ff9fSDavid du Colombier {
3702c57ff9fSDavid du Colombier uint bi, i, k;
3712c57ff9fSDavid du Colombier Buddy *blocks;
3722c57ff9fSDavid du Colombier
3732c57ff9fSDavid du Colombier blocks = b->blocks;
3742c57ff9fSDavid du Colombier for(i = 0; i < (UNO<<(b->kmax-b->kmin+1)); i++){
3752c57ff9fSDavid du Colombier if(blocks[i].tag == Used)
3762c57ff9fSDavid du Colombier continue;
3772c57ff9fSDavid du Colombier print("blocks[%d]: size %d prev %d next %d\n",
3782c57ff9fSDavid du Colombier i, 1<<b->blocks[i].kval, blocks[i].prev, blocks[i].next);
3792c57ff9fSDavid du Colombier //i += (1<<blocks[i].kval)/b->bminsz-1;
3802c57ff9fSDavid du Colombier }
3812c57ff9fSDavid du Colombier
3822c57ff9fSDavid du Colombier for(k = 0; k <= b->kmax; k++){
3832c57ff9fSDavid du Colombier print("a[%d]:", k);
3842c57ff9fSDavid du Colombier for(bi = b->avail[k].next; bi != 0; bi = blocks[BLOCK(b,bi)].next){
3852c57ff9fSDavid du Colombier print(" %d", bi);
3862c57ff9fSDavid du Colombier }
3872c57ff9fSDavid du Colombier print("\n");
3882c57ff9fSDavid du Colombier }
3892c57ff9fSDavid du Colombier }
3902c57ff9fSDavid du Colombier
3912c57ff9fSDavid du Colombier void
physallocdump(void)3922c57ff9fSDavid du Colombier physallocdump(void)
3932c57ff9fSDavid du Colombier {
3942c57ff9fSDavid du Colombier int n;
3952c57ff9fSDavid du Colombier
3962c57ff9fSDavid du Colombier for(n = 0; n < Ndoms; n++)
3972c57ff9fSDavid du Colombier if(bal[n].size > 0)
3982c57ff9fSDavid du Colombier print("physalloc color=%d base=%#ullx size=%#ullx\n",
3992c57ff9fSDavid du Colombier n, bal[n].base, bal[n].size);
4002c57ff9fSDavid du Colombier }
4012c57ff9fSDavid du Colombier
4022c57ff9fSDavid du Colombier static int
plop(Bal * b,uintmem a,int k,int type)4032c57ff9fSDavid du Colombier plop(Bal *b, uintmem a, int k, int type)
4042c57ff9fSDavid du Colombier {
4052c57ff9fSDavid du Colombier uint i;
4062c57ff9fSDavid du Colombier Buddy *l;
4072c57ff9fSDavid du Colombier
4082c57ff9fSDavid du Colombier
4092c57ff9fSDavid du Colombier DBG("plop(a %#p k %d type %d)\n", a, k, type);
4102c57ff9fSDavid du Colombier
4112c57ff9fSDavid du Colombier i = INDEX(b,a);
4122c57ff9fSDavid du Colombier l = &b->blocks[BLOCK(b,i)];
4132c57ff9fSDavid du Colombier
4142c57ff9fSDavid du Colombier l->kval = k;
4152c57ff9fSDavid du Colombier xphysfree(b, a, 1<<k);
4162c57ff9fSDavid du Colombier
4172c57ff9fSDavid du Colombier return 1;
4182c57ff9fSDavid du Colombier }
4192c57ff9fSDavid du Colombier
4202c57ff9fSDavid du Colombier static int
iimbchunk(Bal * b,uintmem a,uintmem e,int type)4212c57ff9fSDavid du Colombier iimbchunk(Bal *b, uintmem a, uintmem e, int type)
4222c57ff9fSDavid du Colombier {
4232c57ff9fSDavid du Colombier int k;
4242c57ff9fSDavid du Colombier uint s;
4252c57ff9fSDavid du Colombier
4262c57ff9fSDavid du Colombier a = ROUNDUP(a, b->bminsz);
4272c57ff9fSDavid du Colombier e = ROUNDDN(e, b->bminsz);
4282c57ff9fSDavid du Colombier DBG("iimbchunk: start a %#P e %#P\n", a, e);
4292c57ff9fSDavid du Colombier
4302c57ff9fSDavid du Colombier b->nblocks += (e-a)/b->bminsz;
4312c57ff9fSDavid du Colombier
4322c57ff9fSDavid du Colombier for(k = b->kmin, s = b->bminsz; a+s < e && k < b->kmax; s <<= 1, k += 1){
4332c57ff9fSDavid du Colombier if(a & s){
4342c57ff9fSDavid du Colombier plop(b, a, k, type);
4352c57ff9fSDavid du Colombier a += s;
4362c57ff9fSDavid du Colombier }
4372c57ff9fSDavid du Colombier }
4382c57ff9fSDavid du Colombier DBG("done1 a %#P e %#P s %#ux %d\n", a, e, s, k);
4392c57ff9fSDavid du Colombier
4402c57ff9fSDavid du Colombier while(a+s <= e){
4412c57ff9fSDavid du Colombier plop(b, a, k, type);
4422c57ff9fSDavid du Colombier a += s;
4432c57ff9fSDavid du Colombier }
4442c57ff9fSDavid du Colombier DBG("done2 a %#P e %#P s %#ux %d\n", a, e, s, k);
4452c57ff9fSDavid du Colombier
4462c57ff9fSDavid du Colombier for(k -= 1, s >>= 1; a < e; s >>= 1, k -= 1){
4472c57ff9fSDavid du Colombier if(a+s <= e){
4482c57ff9fSDavid du Colombier plop(b, a, k, type);
4492c57ff9fSDavid du Colombier a += s;
4502c57ff9fSDavid du Colombier }
4512c57ff9fSDavid du Colombier }
4522c57ff9fSDavid du Colombier DBG("done3 a %#P e %#P s %#ux %d\n", a, e, s, k);
4532c57ff9fSDavid du Colombier
4542c57ff9fSDavid du Colombier return 0;
4552c57ff9fSDavid du Colombier }
4562c57ff9fSDavid du Colombier
4572c57ff9fSDavid du Colombier /*
4582c57ff9fSDavid du Colombier * Called from umeminit to initialize user memory allocators.
4592c57ff9fSDavid du Colombier */
4602c57ff9fSDavid du Colombier void
physinit(uintmem a,u64int size)4612c57ff9fSDavid du Colombier physinit(uintmem a, u64int size)
4622c57ff9fSDavid du Colombier {
4632c57ff9fSDavid du Colombier uintmem dtsz;
4642c57ff9fSDavid du Colombier Bal *b;
4652c57ff9fSDavid du Colombier int i, dom;
4662c57ff9fSDavid du Colombier uintmem addr, len;
4672c57ff9fSDavid du Colombier
4682c57ff9fSDavid du Colombier DBG("physinit %#ullx %#ullx\n", a, size);
4692c57ff9fSDavid du Colombier
4702c57ff9fSDavid du Colombier for(addr = a; addr < a+size; addr += len){
4712c57ff9fSDavid du Colombier dom = 0;
4722c57ff9fSDavid du Colombier len = acpimblocksize(addr, &dom);
4732c57ff9fSDavid du Colombier /* len can be zero if there's no acpi information about addr */
4742c57ff9fSDavid du Colombier if(len == 0 || addr + len > a + size)
4752c57ff9fSDavid du Colombier len = a + size - addr;
4762c57ff9fSDavid du Colombier /*
4772c57ff9fSDavid du Colombier * Each block belongs to a different domain (ie. cpu/mem socket)
4782c57ff9fSDavid du Colombier * We must create a buddy allocator for each block, so we could
4792c57ff9fSDavid du Colombier * allocate memory from different domains.
4802c57ff9fSDavid du Colombier *
4812c57ff9fSDavid du Colombier * This code assumes that a domain may be extended later and
4822c57ff9fSDavid du Colombier * that there is no interleaving of domains. Ok by now.
4832c57ff9fSDavid du Colombier */
4842c57ff9fSDavid du Colombier DBG("physmem block dom %d addr %#ullx size %#ullx\n",
4852c57ff9fSDavid du Colombier dom, addr, len);
4862c57ff9fSDavid du Colombier if(dom < 0 || dom >= Ndoms){
4872c57ff9fSDavid du Colombier print("physinit: invalid dom %d\n", dom);
4882c57ff9fSDavid du Colombier dom = 0;
4892c57ff9fSDavid du Colombier }
4902c57ff9fSDavid du Colombier b = &bal[dom];
4912c57ff9fSDavid du Colombier if(dom >= ndoms)
4922c57ff9fSDavid du Colombier ndoms = dom+1;
4932c57ff9fSDavid du Colombier if(b->kmin == 0){
4942c57ff9fSDavid du Colombier b->base = addr;
4952c57ff9fSDavid du Colombier b->size = len;
4962c57ff9fSDavid du Colombier b->kmin = BKmin;
4972c57ff9fSDavid du Colombier b->kmax = BKmax;
4982c57ff9fSDavid du Colombier b->bminsz = (UNO<<b->kmin);
4992c57ff9fSDavid du Colombier b->memory = sys->pmstart;
5002c57ff9fSDavid du Colombier b->kspan = lg2floor(sys->pmend);
5012c57ff9fSDavid du Colombier if(!ISPOWEROF2(sys->pmend))
5022c57ff9fSDavid du Colombier b->kspan++;
5032c57ff9fSDavid du Colombier dtsz = sizeof(Buddy)*(UNO<<(b->kspan-b->kmin+1));
5042c57ff9fSDavid du Colombier DBG("kspan %ud (arrysz = %llud)\n", b->kspan, dtsz);
5052c57ff9fSDavid du Colombier b->blocks = malloc(dtsz);
5062c57ff9fSDavid du Colombier if(b->blocks == nil)
5072c57ff9fSDavid du Colombier panic("physinit: no blocks");
5082c57ff9fSDavid du Colombier memset(b->blocks, 0, dtsz);
5092c57ff9fSDavid du Colombier b->avail = malloc(sizeof(Buddy)*(b->kmax+1));
5102c57ff9fSDavid du Colombier if(b->avail == nil)
5112c57ff9fSDavid du Colombier panic("physinit: no avail");
5122c57ff9fSDavid du Colombier memset(b->avail, 0, sizeof(Buddy)*(b->kmax+1));
5132c57ff9fSDavid du Colombier }else{
5142c57ff9fSDavid du Colombier if(addr < b->base)
5152c57ff9fSDavid du Colombier panic("physinit: decreasing base");
5162c57ff9fSDavid du Colombier if(b->base+b->size < addr + len)
5172c57ff9fSDavid du Colombier b->size = (addr-b->base) + len;
5182c57ff9fSDavid du Colombier for(i = 0; i < Ndoms; i++)
5192c57ff9fSDavid du Colombier if(bal[i].kmin && &bal[i] != b)
5202c57ff9fSDavid du Colombier if(bal[i].base < b->base + b->size &&
5212c57ff9fSDavid du Colombier bal[i].base + bal[i].size > b->base + b->size)
5222c57ff9fSDavid du Colombier panic("physinit: doms overlap");
5232c57ff9fSDavid du Colombier }
5242c57ff9fSDavid du Colombier assert(addr >= b->base && addr+len <= b->base + b->size);
5252c57ff9fSDavid du Colombier
5262c57ff9fSDavid du Colombier iimbchunk(b, addr, addr+len, 0);
5272c57ff9fSDavid du Colombier }
5282c57ff9fSDavid du Colombier
5292c57ff9fSDavid du Colombier
5302c57ff9fSDavid du Colombier }
531