physalloc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  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. #include "acpi.h"
  21. #define ISPOWEROF2(x) (((x) != 0) && !((x) & ((x)-1)))
  22. #define UNO ((u64)1)
  23. enum {
  24. BKmin = 21, /* Minimum lg2 */
  25. BKmax = 30, /* Maximum lg2 */
  26. Ndoms = 16, /* Max # of domains */
  27. Used = 0,
  28. Avail = 1,
  29. };
  30. #define INDEX(b, v) ((u32)(((v)) / (b)->bminsz))
  31. #define BLOCK(b, i) ((i)-INDEX((b), (b)->memory))
  32. typedef struct Buddy Buddy;
  33. struct Buddy {
  34. i16 tag; /* Used or Avail */
  35. i16 kval;
  36. u32 next;
  37. u32 prev;
  38. void *p;
  39. };
  40. /*
  41. * Bals should allocate using its base address as 0.
  42. * For now, all of them refer to the entire memory and we record
  43. * the base and size for each one.
  44. */
  45. typedef struct Bal Bal;
  46. struct Bal {
  47. u64 base;
  48. u64 size;
  49. usize nfree;
  50. usize nblocks;
  51. int kmin; /* Minimum lg2 */
  52. int kmax; /* Maximum lg2 */
  53. u64 bminsz; /* minimum block sz */
  54. u64 memory;
  55. u32 kspan;
  56. Buddy *blocks;
  57. Buddy *avail;
  58. };
  59. static Bal bal[Ndoms];
  60. static int ndoms;
  61. static Lock budlock;
  62. char *
  63. seprintphysstats(char *s, char *e)
  64. {
  65. Bal *b;
  66. int i;
  67. lock(&budlock);
  68. for(i = 0; i < Ndoms; i++){
  69. b = &bal[i];
  70. if(b->size > 0)
  71. s = seprint(s, e, "%lu/%lu %lluK color %d blocks avail\n",
  72. b->nfree, b->nblocks, b->bminsz / KiB, i);
  73. }
  74. unlock(&budlock);
  75. return s;
  76. }
  77. static void
  78. xphysfree(Bal *b, u64 data, u64 size)
  79. {
  80. u32 i;
  81. Buddy *l, *p;
  82. Buddy *blocks, *avail;
  83. DBG("physfree\n");
  84. /*
  85. * Knuth's Algorithm S (Buddy System Liberation).
  86. */
  87. blocks = b->blocks;
  88. avail = b->avail;
  89. if(data == 0 /*|| !ALIGNED(data, b->bminsz)*/)
  90. return;
  91. i = INDEX(b, data);
  92. lock(&budlock);
  93. S1:
  94. /*
  95. * Find buddy.
  96. */
  97. l = &blocks[BLOCK(b, i)];
  98. l->p = nil;
  99. DBG("\tbsl: BLOCK(b,i) %d index %llu kval %d\n",
  100. BLOCK(b, i), BLOCK(b, i) / ((1 << l->kval) / b->bminsz), l->kval);
  101. if((BLOCK(b, i) / ((1 << l->kval) / b->bminsz)) & 1) /* simpler test? */
  102. p = l - (1 << l->kval) / b->bminsz;
  103. else
  104. p = l + (1 << l->kval) / (b->bminsz);
  105. DBG("\tbsl: l @ %ld buddy @ %ld\n", l - blocks, p - blocks);
  106. /*
  107. * Is buddy available?
  108. * Can't merge if:
  109. * this is the largest block;
  110. * buddy isn't free;
  111. * buddy has been subsequently split again.
  112. */
  113. if(l->kval == b->kmax || p->tag == Used || (p->tag == Avail && p->kval != l->kval)){
  114. /*
  115. * Put on list.
  116. */
  117. l->tag = Avail;
  118. l->next = avail[l->kval].next;
  119. l->prev = 0;
  120. if(l->next != 0)
  121. blocks[BLOCK(b, l->next)].prev = i;
  122. avail[l->kval].next = i;
  123. b->nfree += size / b->bminsz;
  124. unlock(&budlock);
  125. DBG("bsl: free @ i %d BLOCK(b,i) %d kval %d next %d %s\n",
  126. i, BLOCK(b, i), l->kval, l->next, l->tag ? "avail" : "used");
  127. return;
  128. }
  129. /*
  130. * Combine with buddy.
  131. * This removes block P from the avail list.
  132. */
  133. if(p->prev != 0){
  134. blocks[BLOCK(b, p->prev)].next = p->next;
  135. p->prev = 0;
  136. } else
  137. avail[p->kval].next = 0;
  138. if(p->next != 0){
  139. blocks[BLOCK(b, p->next)].prev = p->prev;
  140. p->next = 0;
  141. }
  142. p->tag = Used;
  143. /*
  144. * Now can try to merge this larger block.
  145. k++;
  146. */
  147. DBG("\tbsl: l @ %ld p @ %ld\n", l - blocks, p - blocks);
  148. if(p < l)
  149. l = p;
  150. i = l - blocks + INDEX(b, b->memory);
  151. l->kval++;
  152. DBG("bsl: merge @ i %d BLOCK(b,i) %d kval %d next %d tag %s\n",
  153. i, BLOCK(b, i), l->kval, l->next, l->tag ? "avail" : "used");
  154. goto S1;
  155. }
  156. void
  157. physfree(u64 data, u64 size)
  158. {
  159. Bal *b;
  160. int i;
  161. for(i = 0; i < Ndoms; i++){
  162. b = &bal[i];
  163. if(b->base <= data && data < b->base + b->size){
  164. xphysfree(b, data, size);
  165. return;
  166. }
  167. }
  168. panic("physfree: no bal");
  169. }
  170. static void *
  171. xphystag(Bal *b, u64 data)
  172. {
  173. u32 i;
  174. Buddy *blocks;
  175. DBG("phystag\n");
  176. blocks = b->blocks;
  177. if(data == 0 /*|| !ALIGNED(data, b->bminsz)*/)
  178. return nil;
  179. i = INDEX(b, data);
  180. return blocks[BLOCK(b, i)].p;
  181. }
  182. void *
  183. phystag(u64 data)
  184. {
  185. Bal *b;
  186. int i;
  187. for(i = 0; i < Ndoms; i++){
  188. b = &bal[i];
  189. if(b->base <= data && data < b->base + b->size)
  190. return xphystag(b, data);
  191. }
  192. return nil;
  193. }
  194. static u8 lg2table[256] = {
  195. 0,
  196. 0,
  197. 1,
  198. 1,
  199. 2,
  200. 2,
  201. 2,
  202. 2,
  203. 3,
  204. 3,
  205. 3,
  206. 3,
  207. 3,
  208. 3,
  209. 3,
  210. 3,
  211. 4,
  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. 5,
  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. 6,
  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. 7,
  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. };
  452. static int
  453. lg2floor(u64 w)
  454. {
  455. u64 hi, lo;
  456. if((lo = (w >> 48)) != 0){
  457. if((hi = (lo >> 8)) != 0)
  458. return 56 + lg2table[hi];
  459. return 48 + lg2table[lo];
  460. }
  461. if((lo = (w >> 32)) != 0){
  462. if((hi = (lo >> 8)) != 0)
  463. return 40 + lg2table[hi];
  464. return 32 + lg2table[lo];
  465. }
  466. if((lo = (w >> 16)) != 0){
  467. if((hi = (lo >> 8)) != 0)
  468. return 24 + lg2table[hi];
  469. return 16 + lg2table[lo];
  470. }
  471. if((hi = (w >> 8)) != 0)
  472. return 8 + lg2table[hi];
  473. return lg2table[w];
  474. }
  475. static u64
  476. xphysalloc(Bal *b, u64 size, void *tag)
  477. {
  478. u32 i, j, k;
  479. Buddy *l, *p;
  480. Buddy *avail, *blocks;
  481. u64 m;
  482. DBG("physalloc\n");
  483. assert(b->size > 0);
  484. avail = b->avail;
  485. blocks = b->blocks;
  486. /*
  487. * Knuth's Algorithm R (Buddy System Reservation).
  488. */
  489. if(size < b->bminsz)
  490. size = b->bminsz;
  491. /*
  492. * Find block.
  493. */
  494. if(!ISPOWEROF2(size))
  495. return 0;
  496. k = lg2floor(size);
  497. lock(&budlock);
  498. for(j = k; j <= b->kmax; j++){
  499. if(avail[j].next != 0)
  500. break;
  501. }
  502. DBG("bsr: size %#llud k %d j %d\n", size, k, j);
  503. if(j > b->kmax){
  504. unlock(&budlock);
  505. return 0;
  506. }
  507. /*
  508. * Remove from list.
  509. */
  510. i = avail[j].next;
  511. l = &blocks[BLOCK(b, i)];
  512. DBG("bsr: block @ i %d BLOCK(b,i) %d kval %d next %d %s\n",
  513. i, BLOCK(b, i), l->kval, l->next, l->tag ? "avail" : "used");
  514. avail[j].next = l->next;
  515. blocks[avail[j].next].prev = 0;
  516. l->prev = l->next = 0;
  517. l->tag = Used;
  518. l->kval = k;
  519. /*
  520. * Split required?
  521. */
  522. while(j > k){
  523. /*
  524. * Split.
  525. */
  526. j--;
  527. p = &blocks[BLOCK(b, i) + (UNO << j) / (b->bminsz)];
  528. p->tag = Avail;
  529. p->kval = j;
  530. p->next = avail[j].next;
  531. p->prev = 0;
  532. if(p->next != 0)
  533. blocks[BLOCK(b, p->next)].prev = i + (UNO << j) / (b->bminsz);
  534. avail[j].next = i + (UNO << j) / (b->bminsz);
  535. DBG("bsr: split @ i %d BLOCK(b,i) %ld j %d next %d (%d) %s\n",
  536. i, p - blocks, j, p->next, BLOCK(b, p->next),
  537. p->tag ? "avail" : "used");
  538. }
  539. b->nfree -= size / b->bminsz;
  540. unlock(&budlock);
  541. m = b->memory + b->bminsz * BLOCK(b, i);
  542. assert(m >= b->base && m < b->base + b->size);
  543. blocks[BLOCK(b, i)].p = tag;
  544. return m;
  545. }
  546. u64
  547. physalloc(u64 size, int *colorp, void *tag)
  548. {
  549. int i, color;
  550. u64 m;
  551. m = 0;
  552. color = *colorp;
  553. if(color >= 0){
  554. color %= ndoms;
  555. if(bal[color].kmin > 0){
  556. *colorp = color;
  557. m = xphysalloc(&bal[color], size, tag);
  558. }
  559. }
  560. if(m == 0)
  561. for(i = 0; i < ndoms; i++)
  562. if(bal[i].kmin > 0)
  563. if((m = xphysalloc(&bal[i], size, tag)) != 0){
  564. *colorp = i;
  565. return m;
  566. }
  567. return m;
  568. }
  569. #if 0
  570. static void
  571. dump(Bal *b)
  572. {
  573. u32 bi, i, k;
  574. Buddy *blocks;
  575. blocks = b->blocks;
  576. for(i = 0; i < (UNO<<(b->kmax-b->kmin+1)); i++){
  577. if(blocks[i].tag == Used)
  578. continue;
  579. print("blocks[%d]: size %d prev %d next %d\n",
  580. i, 1<<b->blocks[i].kval, blocks[i].prev, blocks[i].next);
  581. //i += (1<<blocks[i].kval)/b->bminsz-1;
  582. }
  583. for(k = 0; k <= b->kmax; k++){
  584. print("a[%d]:", k);
  585. for(bi = b->avail[k].next; bi != 0; bi = blocks[BLOCK(b,bi)].next){
  586. print(" %d", bi);
  587. }
  588. print("\n");
  589. }
  590. }
  591. #endif
  592. void
  593. physallocdump(void)
  594. {
  595. int n;
  596. for(n = 0; n < Ndoms; n++)
  597. if(bal[n].size > 0)
  598. print("physalloc color=%d base=%#llx size=%#llx\n",
  599. n, bal[n].base, bal[n].size);
  600. }
  601. static int
  602. plop(Bal *b, u64 a, int k, int type)
  603. {
  604. u32 i;
  605. Buddy *l;
  606. DBG("plop(a %#p k %d type %d)\n", a, k, type);
  607. i = INDEX(b, a);
  608. l = &b->blocks[BLOCK(b, i)];
  609. l->kval = k;
  610. xphysfree(b, a, 1 << k);
  611. return 1;
  612. }
  613. static int
  614. iimbchunk(Bal *b, u64 a, u64 e, int type)
  615. {
  616. int k;
  617. u32 s;
  618. a = ROUNDUP(a, b->bminsz);
  619. e = ROUNDDN(e, b->bminsz);
  620. DBG("iimbchunk: start a %#P e %#P\n", a, e);
  621. b->nblocks += (e - a) / b->bminsz;
  622. for(k = b->kmin, s = b->bminsz; a + s < e && k < b->kmax; s <<= 1, k += 1){
  623. if(a & s){
  624. plop(b, a, k, type);
  625. a += s;
  626. }
  627. }
  628. DBG("done1 a %#P e %#P s %#x %d\n", a, e, s, k);
  629. while(a + s <= e){
  630. plop(b, a, k, type);
  631. a += s;
  632. }
  633. DBG("done2 a %#P e %#P s %#x %d\n", a, e, s, k);
  634. for(k -= 1, s >>= 1; a < e; s >>= 1, k -= 1){
  635. if(a + s <= e){
  636. plop(b, a, k, type);
  637. a += s;
  638. }
  639. }
  640. DBG("done3 a %#P e %#P s %#x %d\n", a, e, s, k);
  641. return 0;
  642. }
  643. /*
  644. * Called from umeminit to initialize user memory allocators.
  645. */
  646. void
  647. physinit(u64 a, u64 size)
  648. {
  649. u64 dtsz;
  650. Bal *b;
  651. int i, dom;
  652. u64 addr, len;
  653. DBG("physinit %#llx %#llx\n", a, size);
  654. for(addr = a; addr < a + size; addr += len){
  655. dom = 0;
  656. len = 0; // acpimblocksize(addr, &dom);
  657. /* len can be zero if there's no acpi information about addr */
  658. if(len == 0 || addr + len > a + size)
  659. len = a + size - addr;
  660. /*
  661. * Each block belongs to a different domain (ie. cpu/mem socket)
  662. * We must create a buddy allocator for each block, so we could
  663. * allocate memory from different domains.
  664. *
  665. * This code assumes that a domain may be extended later and
  666. * that there is no interleaving of domains. Ok by now.
  667. */
  668. DBG("physmem block dom %d addr %#llx size %#llx\n",
  669. dom, addr, len);
  670. if(dom < 0 || dom >= Ndoms){
  671. print("physinit: invalid dom %d\n", dom);
  672. dom = 0;
  673. }
  674. b = &bal[dom];
  675. if(dom >= ndoms)
  676. ndoms = dom + 1;
  677. if(b->kmin == 0){
  678. b->base = addr;
  679. b->size = len;
  680. b->kmin = BKmin;
  681. b->kmax = BKmax;
  682. b->bminsz = (UNO << b->kmin);
  683. b->memory = sys->pmstart;
  684. b->kspan = lg2floor(sys->pmend);
  685. if(!ISPOWEROF2(sys->pmend))
  686. b->kspan++;
  687. dtsz = sizeof(Buddy) * (UNO << (b->kspan - b->kmin + 1));
  688. DBG("kspan %u (arrysz = %llu)\n", b->kspan, dtsz);
  689. b->blocks = malloc(dtsz);
  690. if(b->blocks == nil)
  691. panic("physinit: no blocks");
  692. memset(b->blocks, 0, dtsz);
  693. b->avail = malloc(sizeof(Buddy) * (b->kmax + 1));
  694. if(b->avail == nil)
  695. panic("physinit: no avail");
  696. memset(b->avail, 0, sizeof(Buddy) * (b->kmax + 1));
  697. } else {
  698. if(addr < b->base)
  699. panic("physinit: decreasing base");
  700. if(b->base + b->size < addr + len)
  701. b->size = (addr - b->base) + len;
  702. for(i = 0; i < Ndoms; i++)
  703. if(bal[i].kmin && &bal[i] != b)
  704. if(bal[i].base < b->base + b->size &&
  705. bal[i].base + bal[i].size > b->base + b->size)
  706. panic("physinit: doms overlap");
  707. }
  708. assert(addr >= b->base && addr + len <= b->base + b->size);
  709. iimbchunk(b, addr, addr + len, 0);
  710. }
  711. }