physalloc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /*
  10. * Buddy allocator for physical memory allocation.
  11. * One per ACPI affinity domain, to color pages depending on their
  12. * NUMA location.
  13. *
  14. */
  15. #include "u.h"
  16. #include "../port/lib.h"
  17. #include "mem.h"
  18. #include "dat.h"
  19. #include "fns.h"
  20. #define ISPOWEROF2(x) (((x) != 0) && !((x) & ((x)-1)))
  21. #define UNO ((u64)1)
  22. #undef DBG
  23. #define DBG print
  24. enum {
  25. BKmin = 21, /* Minimum lg2 */
  26. BKmax = 30, /* Maximum lg2 */
  27. Ndoms = 16, /* Max # of domains */
  28. Used = 0,
  29. Avail = 1,
  30. };
  31. #define INDEX(b, v) ((u32)(((v)) / (b)->bminsz))
  32. #define BLOCK(b, i) ((i)-INDEX((b), (b)->memory))
  33. typedef struct Buddy Buddy;
  34. struct Buddy {
  35. i16 tag; /* Used or Avail */
  36. i16 kval;
  37. u32 next;
  38. u32 prev;
  39. void *p;
  40. };
  41. /*
  42. * Bals should allocate using its base address as 0.
  43. * For now, all of them refer to the entire memory and we record
  44. * the base and size for each one.
  45. */
  46. typedef struct Bal Bal;
  47. struct Bal {
  48. u64 base;
  49. u64 size;
  50. usize nfree;
  51. usize nblocks;
  52. int kmin; /* Minimum lg2 */
  53. int kmax; /* Maximum lg2 */
  54. u64 bminsz; /* minimum block sz */
  55. u64 memory;
  56. u32 kspan;
  57. Buddy *blocks;
  58. Buddy *avail;
  59. };
  60. static Bal bal[Ndoms];
  61. static int ndoms;
  62. static Lock budlock;
  63. char *
  64. seprintphysstats(char *s, char *e)
  65. {
  66. Bal *b;
  67. int i;
  68. lock(&budlock);
  69. for(i = 0; i < Ndoms; i++){
  70. b = &bal[i];
  71. if(b->size > 0)
  72. s = seprint(s, e, "%lu/%lu %lluK color %d blocks avail\n",
  73. b->nfree, b->nblocks, b->bminsz / KiB, i);
  74. }
  75. unlock(&budlock);
  76. return s;
  77. }
  78. static void
  79. xphysfree(Bal *b, u64 data, u64 size)
  80. {
  81. u32 i;
  82. Buddy *l, *p;
  83. Buddy *blocks, *avail;
  84. DBG("physfree\n");
  85. /*
  86. * Knuth's Algorithm S (Buddy System Liberation).
  87. */
  88. blocks = b->blocks;
  89. avail = b->avail;
  90. if(data == 0 /*|| !ALIGNED(data, b->bminsz)*/)
  91. return;
  92. i = INDEX(b, data);
  93. lock(&budlock);
  94. S1:
  95. /*
  96. * Find buddy.
  97. */
  98. l = &blocks[BLOCK(b, i)];
  99. l->p = nil;
  100. DBG("\tbsl: BLOCK(b,i) %d index %llu kval %d\n",
  101. BLOCK(b, i), BLOCK(b, i) / ((1 << l->kval) / b->bminsz), l->kval);
  102. if((BLOCK(b, i) / ((1 << l->kval) / b->bminsz)) & 1) /* simpler test? */
  103. p = l - (1 << l->kval) / b->bminsz;
  104. else
  105. p = l + (1 << l->kval) / (b->bminsz);
  106. DBG("\tbsl: l @ %ld buddy @ %ld\n", l - blocks, p - blocks);
  107. /*
  108. * Is buddy available?
  109. * Can't merge if:
  110. * this is the largest block;
  111. * buddy isn't free;
  112. * buddy has been subsequently split again.
  113. */
  114. if(l->kval == b->kmax || p->tag == Used || (p->tag == Avail && p->kval != l->kval)){
  115. /*
  116. * Put on list.
  117. */
  118. l->tag = Avail;
  119. l->next = avail[l->kval].next;
  120. l->prev = 0;
  121. if(l->next != 0)
  122. blocks[BLOCK(b, l->next)].prev = i;
  123. avail[l->kval].next = i;
  124. b->nfree += size / b->bminsz;
  125. unlock(&budlock);
  126. DBG("bsl: free @ i %d BLOCK(b,i) %d kval %d next %d %s\n",
  127. i, BLOCK(b, i), l->kval, l->next, l->tag ? "avail" : "used");
  128. return;
  129. }
  130. /*
  131. * Combine with buddy.
  132. * This removes block P from the avail list.
  133. */
  134. if(p->prev != 0){
  135. blocks[BLOCK(b, p->prev)].next = p->next;
  136. p->prev = 0;
  137. } else
  138. avail[p->kval].next = 0;
  139. if(p->next != 0){
  140. blocks[BLOCK(b, p->next)].prev = p->prev;
  141. p->next = 0;
  142. }
  143. p->tag = Used;
  144. /*
  145. * Now can try to merge this larger block.
  146. k++;
  147. */
  148. DBG("\tbsl: l @ %ld p @ %ld\n", l - blocks, p - blocks);
  149. if(p < l)
  150. l = p;
  151. i = l - blocks + INDEX(b, b->memory);
  152. l->kval++;
  153. DBG("bsl: merge @ i %d BLOCK(b,i) %d kval %d next %d tag %s\n",
  154. i, BLOCK(b, i), l->kval, l->next, l->tag ? "avail" : "used");
  155. goto S1;
  156. }
  157. void
  158. physfree(u64 data, u64 size)
  159. {
  160. Bal *b;
  161. int i;
  162. for(i = 0; i < Ndoms; i++){
  163. b = &bal[i];
  164. if(b->base <= data && data < b->base + b->size){
  165. xphysfree(b, data, size);
  166. return;
  167. }
  168. }
  169. panic("physfree: no bal");
  170. }
  171. static void *
  172. xphystag(Bal *b, u64 data)
  173. {
  174. u32 i;
  175. Buddy *blocks;
  176. DBG("phystag\n");
  177. blocks = b->blocks;
  178. if(data == 0 /*|| !ALIGNED(data, b->bminsz)*/)
  179. return nil;
  180. i = INDEX(b, data);
  181. return blocks[BLOCK(b, i)].p;
  182. }
  183. void *
  184. phystag(u64 data)
  185. {
  186. Bal *b;
  187. int i;
  188. for(i = 0; i < Ndoms; i++){
  189. b = &bal[i];
  190. if(b->base <= data && data < b->base + b->size)
  191. return xphystag(b, data);
  192. }
  193. return nil;
  194. }
  195. static u8 lg2table[256] = {
  196. 0,
  197. 0,
  198. 1,
  199. 1,
  200. 2,
  201. 2,
  202. 2,
  203. 2,
  204. 3,
  205. 3,
  206. 3,
  207. 3,
  208. 3,
  209. 3,
  210. 3,
  211. 3,
  212. 4,
  213. 4,
  214. 4,
  215. 4,
  216. 4,
  217. 4,
  218. 4,
  219. 4,
  220. 4,
  221. 4,
  222. 4,
  223. 4,
  224. 4,
  225. 4,
  226. 4,
  227. 4,
  228. 5,
  229. 5,
  230. 5,
  231. 5,
  232. 5,
  233. 5,
  234. 5,
  235. 5,
  236. 5,
  237. 5,
  238. 5,
  239. 5,
  240. 5,
  241. 5,
  242. 5,
  243. 5,
  244. 5,
  245. 5,
  246. 5,
  247. 5,
  248. 5,
  249. 5,
  250. 5,
  251. 5,
  252. 5,
  253. 5,
  254. 5,
  255. 5,
  256. 5,
  257. 5,
  258. 5,
  259. 5,
  260. 6,
  261. 6,
  262. 6,
  263. 6,
  264. 6,
  265. 6,
  266. 6,
  267. 6,
  268. 6,
  269. 6,
  270. 6,
  271. 6,
  272. 6,
  273. 6,
  274. 6,
  275. 6,
  276. 6,
  277. 6,
  278. 6,
  279. 6,
  280. 6,
  281. 6,
  282. 6,
  283. 6,
  284. 6,
  285. 6,
  286. 6,
  287. 6,
  288. 6,
  289. 6,
  290. 6,
  291. 6,
  292. 6,
  293. 6,
  294. 6,
  295. 6,
  296. 6,
  297. 6,
  298. 6,
  299. 6,
  300. 6,
  301. 6,
  302. 6,
  303. 6,
  304. 6,
  305. 6,
  306. 6,
  307. 6,
  308. 6,
  309. 6,
  310. 6,
  311. 6,
  312. 6,
  313. 6,
  314. 6,
  315. 6,
  316. 6,
  317. 6,
  318. 6,
  319. 6,
  320. 6,
  321. 6,
  322. 6,
  323. 6,
  324. 7,
  325. 7,
  326. 7,
  327. 7,
  328. 7,
  329. 7,
  330. 7,
  331. 7,
  332. 7,
  333. 7,
  334. 7,
  335. 7,
  336. 7,
  337. 7,
  338. 7,
  339. 7,
  340. 7,
  341. 7,
  342. 7,
  343. 7,
  344. 7,
  345. 7,
  346. 7,
  347. 7,
  348. 7,
  349. 7,
  350. 7,
  351. 7,
  352. 7,
  353. 7,
  354. 7,
  355. 7,
  356. 7,
  357. 7,
  358. 7,
  359. 7,
  360. 7,
  361. 7,
  362. 7,
  363. 7,
  364. 7,
  365. 7,
  366. 7,
  367. 7,
  368. 7,
  369. 7,
  370. 7,
  371. 7,
  372. 7,
  373. 7,
  374. 7,
  375. 7,
  376. 7,
  377. 7,
  378. 7,
  379. 7,
  380. 7,
  381. 7,
  382. 7,
  383. 7,
  384. 7,
  385. 7,
  386. 7,
  387. 7,
  388. 7,
  389. 7,
  390. 7,
  391. 7,
  392. 7,
  393. 7,
  394. 7,
  395. 7,
  396. 7,
  397. 7,
  398. 7,
  399. 7,
  400. 7,
  401. 7,
  402. 7,
  403. 7,
  404. 7,
  405. 7,
  406. 7,
  407. 7,
  408. 7,
  409. 7,
  410. 7,
  411. 7,
  412. 7,
  413. 7,
  414. 7,
  415. 7,
  416. 7,
  417. 7,
  418. 7,
  419. 7,
  420. 7,
  421. 7,
  422. 7,
  423. 7,
  424. 7,
  425. 7,
  426. 7,
  427. 7,
  428. 7,
  429. 7,
  430. 7,
  431. 7,
  432. 7,
  433. 7,
  434. 7,
  435. 7,
  436. 7,
  437. 7,
  438. 7,
  439. 7,
  440. 7,
  441. 7,
  442. 7,
  443. 7,
  444. 7,
  445. 7,
  446. 7,
  447. 7,
  448. 7,
  449. 7,
  450. 7,
  451. 7,
  452. };
  453. static int
  454. lg2floor(u64 w)
  455. {
  456. u64 hi, lo;
  457. if((lo = (w >> 48)) != 0){
  458. if((hi = (lo >> 8)) != 0)
  459. return 56 + lg2table[hi];
  460. return 48 + lg2table[lo];
  461. }
  462. if((lo = (w >> 32)) != 0){
  463. if((hi = (lo >> 8)) != 0)
  464. return 40 + lg2table[hi];
  465. return 32 + lg2table[lo];
  466. }
  467. if((lo = (w >> 16)) != 0){
  468. if((hi = (lo >> 8)) != 0)
  469. return 24 + lg2table[hi];
  470. return 16 + lg2table[lo];
  471. }
  472. if((hi = (w >> 8)) != 0)
  473. return 8 + lg2table[hi];
  474. return lg2table[w];
  475. }
  476. static u64
  477. xphysalloc(Bal *b, u64 size, void *tag)
  478. {
  479. u32 i, j, k;
  480. Buddy *l, *p;
  481. Buddy *avail, *blocks;
  482. u64 m;
  483. DBG("physalloc\n");
  484. assert(b->size > 0);
  485. avail = b->avail;
  486. blocks = b->blocks;
  487. /*
  488. * Knuth's Algorithm R (Buddy System Reservation).
  489. */
  490. if(size < b->bminsz)
  491. size = b->bminsz;
  492. /*
  493. * Find block.
  494. */
  495. if(!ISPOWEROF2(size))
  496. return 0;
  497. k = lg2floor(size);
  498. lock(&budlock);
  499. for(j = k; j <= b->kmax; j++){
  500. if(avail[j].next != 0)
  501. break;
  502. }
  503. DBG("bsr: size %#llud k %d j %d\n", size, k, j);
  504. if(j > b->kmax){
  505. unlock(&budlock);
  506. return 0;
  507. }
  508. /*
  509. * Remove from list.
  510. */
  511. i = avail[j].next;
  512. l = &blocks[BLOCK(b, i)];
  513. DBG("bsr: block @ i %d BLOCK(b,i) %d kval %d next %d %s\n",
  514. i, BLOCK(b, i), l->kval, l->next, l->tag ? "avail" : "used");
  515. avail[j].next = l->next;
  516. blocks[avail[j].next].prev = 0;
  517. l->prev = l->next = 0;
  518. l->tag = Used;
  519. l->kval = k;
  520. /*
  521. * Split required?
  522. */
  523. while(j > k){
  524. /*
  525. * Split.
  526. */
  527. j--;
  528. p = &blocks[BLOCK(b, i) + (UNO << j) / (b->bminsz)];
  529. p->tag = Avail;
  530. p->kval = j;
  531. p->next = avail[j].next;
  532. p->prev = 0;
  533. if(p->next != 0)
  534. blocks[BLOCK(b, p->next)].prev = i + (UNO << j) / (b->bminsz);
  535. avail[j].next = i + (UNO << j) / (b->bminsz);
  536. DBG("bsr: split @ i %d BLOCK(b,i) %ld j %d next %d (%d) %s\n",
  537. i, p - blocks, j, p->next, BLOCK(b, p->next),
  538. p->tag ? "avail" : "used");
  539. }
  540. b->nfree -= size / b->bminsz;
  541. unlock(&budlock);
  542. m = b->memory + b->bminsz * BLOCK(b, i);
  543. assert(m >= b->base && m < b->base + b->size);
  544. blocks[BLOCK(b, i)].p = tag;
  545. return m;
  546. }
  547. u64
  548. physalloc(u64 size, int *colorp, void *tag)
  549. {
  550. int i, color;
  551. u64 m;
  552. m = 0;
  553. color = *colorp;
  554. if(color >= 0){
  555. color %= ndoms;
  556. if(bal[color].kmin > 0){
  557. *colorp = color;
  558. m = xphysalloc(&bal[color], size, tag);
  559. }
  560. }
  561. if(m == 0)
  562. for(i = 0; i < ndoms; i++)
  563. if(bal[i].kmin > 0)
  564. if((m = xphysalloc(&bal[i], size, tag)) != 0){
  565. *colorp = i;
  566. return m;
  567. }
  568. print("physalloc: return %p\n", m);
  569. return m;
  570. }
  571. #if 0
  572. static void
  573. dump(Bal *b)
  574. {
  575. u32 bi, i, k;
  576. Buddy *blocks;
  577. blocks = b->blocks;
  578. for(i = 0; i < (UNO<<(b->kmax-b->kmin+1)); i++){
  579. if(blocks[i].tag == Used)
  580. continue;
  581. print("blocks[%d]: size %d prev %d next %d\n",
  582. i, 1<<b->blocks[i].kval, blocks[i].prev, blocks[i].next);
  583. //i += (1<<blocks[i].kval)/b->bminsz-1;
  584. }
  585. for(k = 0; k <= b->kmax; k++){
  586. print("a[%d]:", k);
  587. for(bi = b->avail[k].next; bi != 0; bi = blocks[BLOCK(b,bi)].next){
  588. print(" %d", bi);
  589. }
  590. print("\n");
  591. }
  592. }
  593. #endif
  594. void
  595. physallocdump(void)
  596. {
  597. int n;
  598. for(n = 0; n < Ndoms; n++)
  599. if(bal[n].size > 0)
  600. print("physalloc color=%d base=%#llx size=%#llx\n",
  601. n, bal[n].base, bal[n].size);
  602. }
  603. static int
  604. plop(Bal *b, u64 a, int k, int type)
  605. {
  606. u32 i;
  607. Buddy *l;
  608. DBG("plop(a %#p k %d type %d)\n", a, k, type);
  609. i = INDEX(b, a);
  610. l = &b->blocks[BLOCK(b, i)];
  611. l->kval = k;
  612. xphysfree(b, a, 1 << k);
  613. return 1;
  614. }
  615. static int
  616. iimbchunk(Bal *b, u64 a, u64 e, int type)
  617. {
  618. int k;
  619. u32 s;
  620. a = ROUNDUP(a, b->bminsz);
  621. e = ROUNDDN(e, b->bminsz);
  622. DBG("iimbchunk: start a %#P e %#P\n", a, e);
  623. b->nblocks += (e - a) / b->bminsz;
  624. for(k = b->kmin, s = b->bminsz; a + s < e && k < b->kmax; s <<= 1, k += 1){
  625. if(a & s){
  626. plop(b, a, k, type);
  627. a += s;
  628. }
  629. }
  630. DBG("done1 a %#P e %#P s %#x %d\n", a, e, s, k);
  631. while(a + s <= e){
  632. plop(b, a, k, type);
  633. a += s;
  634. }
  635. DBG("done2 a %#P e %#P s %#x %d\n", a, e, s, k);
  636. for(k -= 1, s >>= 1; a < e; s >>= 1, k -= 1){
  637. if(a + s <= e){
  638. plop(b, a, k, type);
  639. a += s;
  640. }
  641. }
  642. DBG("done3 a %#P e %#P s %#x %d\n", a, e, s, k);
  643. return 0;
  644. }
  645. /*
  646. * Called from umeminit to initialize user memory allocators.
  647. */
  648. void
  649. physinit(u64 a, u64 size)
  650. {
  651. u64 dtsz;
  652. Bal *b;
  653. int i, dom;
  654. u64 addr, len;
  655. DBG("physinit %#llx %#llx\n", a, size);
  656. for(addr = a; addr < a + size; addr += len){
  657. dom = 0;
  658. len = 0; // acpimblocksize(addr, &dom);
  659. /* len can be zero if there's no acpi information about addr */
  660. if(len == 0 || addr + len > a + size)
  661. len = a + size - addr;
  662. /*
  663. * Each block belongs to a different domain (ie. cpu/mem socket)
  664. * We must create a buddy allocator for each block, so we could
  665. * allocate memory from different domains.
  666. *
  667. * This code assumes that a domain may be extended later and
  668. * that there is no interleaving of domains. Ok by now.
  669. */
  670. DBG("physmem block dom %d addr %#llx size %#llx\n",
  671. dom, addr, len);
  672. if(dom < 0 || dom >= Ndoms){
  673. print("physinit: invalid dom %d\n", dom);
  674. dom = 0;
  675. }
  676. b = &bal[dom];
  677. if(dom >= ndoms)
  678. ndoms = dom + 1;
  679. if(b->kmin == 0){
  680. b->base = addr;
  681. b->size = len;
  682. b->kmin = BKmin;
  683. b->kmax = BKmax;
  684. b->bminsz = (UNO << b->kmin);
  685. b->memory = sys->pmstart;
  686. b->kspan = lg2floor(sys->pmend);
  687. if(!ISPOWEROF2(sys->pmend))
  688. b->kspan++;
  689. dtsz = sizeof(Buddy) * (UNO << (b->kspan - b->kmin + 1));
  690. DBG("kspan %u (arrysz = %llu)\n", b->kspan, dtsz);
  691. b->blocks = malloc(dtsz);
  692. if(b->blocks == nil)
  693. panic("physinit: no blocks");
  694. memset(b->blocks, 0, dtsz);
  695. b->avail = malloc(sizeof(Buddy) * (b->kmax + 1));
  696. if(b->avail == nil)
  697. panic("physinit: no avail");
  698. memset(b->avail, 0, sizeof(Buddy) * (b->kmax + 1));
  699. } else {
  700. if(addr < b->base)
  701. panic("physinit: decreasing base");
  702. if(b->base + b->size < addr + len)
  703. b->size = (addr - b->base) + len;
  704. for(i = 0; i < Ndoms; i++)
  705. if(bal[i].kmin && &bal[i] != b)
  706. if(bal[i].base < b->base + b->size &&
  707. bal[i].base + bal[i].size > b->base + b->size)
  708. panic("physinit: doms overlap");
  709. }
  710. assert(addr >= b->base && addr + len <= b->base + b->size);
  711. iimbchunk(b, addr, addr + len, 0);
  712. }
  713. }