memory.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  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. * Size memory and create the kernel page-tables on the fly while doing so.
  11. * Called from main(), this code should only be run by the bootstrap processor.
  12. */
  13. #include "u.h"
  14. #include "lib.h"
  15. #include "mem.h"
  16. #include "dat.h"
  17. #include "fns.h"
  18. #include "io.h"
  19. #define MEMDEBUG 0
  20. #define PDX(va) ((((ulong)(va))>>22) & 0x03FF)
  21. #define PTX(va) ((((ulong)(va))>>12) & 0x03FF)
  22. enum {
  23. MemUPA = 0, /* unbacked physical address */
  24. MemRAM = 1, /* physical memory */
  25. MemUMB = 2, /* upper memory block (<16MiB) */
  26. NMemType = 3,
  27. MemMinMiB = 4, /* minimum physical memory (<=4MiB) */
  28. MemMaxMiB = 768, /* maximum physical memory to check */
  29. NMemBase = 10,
  30. };
  31. typedef struct Map Map;
  32. struct Map {
  33. uintptr addr;
  34. uint32_t size;
  35. };
  36. typedef struct {
  37. char* name;
  38. Map* map;
  39. Map* mapend;
  40. Lock;
  41. } RMap;
  42. static Map mapupa[8];
  43. static RMap rmapupa = {
  44. "unallocated unbacked physical memory",
  45. mapupa,
  46. &mapupa[7],
  47. };
  48. static Map xmapupa[8];
  49. static RMap xrmapupa = {
  50. "unbacked physical memory",
  51. xmapupa,
  52. &xmapupa[7],
  53. };
  54. static Map mapram[8];
  55. static RMap rmapram = {
  56. "physical memory",
  57. mapram,
  58. &mapram[7],
  59. };
  60. static Map mapumb[64];
  61. static RMap rmapumb = {
  62. "upper memory block",
  63. mapumb,
  64. &mapumb[63],
  65. };
  66. static Map mapumbrw[8];
  67. static RMap rmapumbrw = {
  68. "UMB device memory",
  69. mapumbrw,
  70. &mapumbrw[7],
  71. };
  72. void
  73. mapprint(RMap* rmap)
  74. {
  75. Map *mp;
  76. print("%s\n", rmap->name);
  77. for(mp = rmap->map; mp->size; mp++){
  78. print("\t%#16.16p %#8.8lux %#16.16p\n",
  79. mp->addr, mp->size, mp->addr+mp->size);
  80. }
  81. }
  82. void
  83. memdebug(void)
  84. {
  85. uintptr maxpa, maxpa1, maxpa2;
  86. if(!MEMDEBUG)
  87. return;
  88. maxpa = (nvramread(0x18)<<8)|nvramread(0x17);
  89. maxpa1 = (nvramread(0x31)<<8)|nvramread(0x30);
  90. maxpa2 = (nvramread(0x16)<<8)|nvramread(0x15);
  91. print("maxpa = %#p -> %#p, maxpa1 = %#p maxpa2 = %#p\n",
  92. maxpa, MiB+maxpa*KiB, maxpa1, maxpa2);
  93. mapprint(&rmapram);
  94. mapprint(&rmapumb);
  95. mapprint(&rmapumbrw);
  96. mapprint(&rmapupa);
  97. }
  98. void
  99. mapfree(RMap* rmap, uint32_t addr, uint32_t size)
  100. {
  101. Map *mp;
  102. uint32_t t;
  103. if(size == 0)
  104. return;
  105. lock(rmap);
  106. for(mp = rmap->map; mp->addr <= addr && mp->size; mp++)
  107. ;
  108. if(mp > rmap->map && (mp-1)->addr+(mp-1)->size == addr){
  109. (mp-1)->size += size;
  110. if(addr+size == mp->addr){
  111. (mp-1)->size += mp->size;
  112. while(mp->size){
  113. mp++;
  114. (mp-1)->addr = mp->addr;
  115. (mp-1)->size = mp->size;
  116. }
  117. }
  118. }
  119. else{
  120. if(addr+size == mp->addr && mp->size){
  121. mp->addr -= size;
  122. mp->size += size;
  123. }
  124. else do{
  125. if(mp >= rmap->mapend){
  126. print("mapfree: %s: losing 0x%luX, %lud\n",
  127. rmap->name, addr, size);
  128. break;
  129. }
  130. t = mp->addr;
  131. mp->addr = addr;
  132. addr = t;
  133. t = mp->size;
  134. mp->size = size;
  135. mp++;
  136. }while(size = t);
  137. }
  138. unlock(rmap);
  139. }
  140. uint32_t
  141. mapalloc(RMap* rmap, uint32_t addr, int size, int align)
  142. {
  143. Map *mp;
  144. uint32_t maddr, oaddr;
  145. lock(rmap);
  146. for(mp = rmap->map; mp->size; mp++){
  147. maddr = mp->addr;
  148. if(addr){
  149. /*
  150. * A specific address range has been given:
  151. * if the current map entry is greater then
  152. * the address is not in the map;
  153. * if the current map entry does not overlap
  154. * the beginning of the requested range then
  155. * continue on to the next map entry;
  156. * if the current map entry does not entirely
  157. * contain the requested range then the range
  158. * is not in the map.
  159. */
  160. if(maddr > addr)
  161. break;
  162. if(mp->size < addr - maddr) /* maddr+mp->size < addr, but no overflow */
  163. continue;
  164. if(addr - maddr > mp->size - size) /* addr+size > maddr+mp->size, but no overflow */
  165. break;
  166. maddr = addr;
  167. }
  168. if(align > 0)
  169. maddr = ((maddr+align-1)/align)*align;
  170. if(mp->addr+mp->size-maddr < size)
  171. continue;
  172. oaddr = mp->addr;
  173. mp->addr = maddr+size;
  174. mp->size -= maddr-oaddr+size;
  175. if(mp->size == 0){
  176. do{
  177. mp++;
  178. (mp-1)->addr = mp->addr;
  179. }while((mp-1)->size = mp->size);
  180. }
  181. unlock(rmap);
  182. if(oaddr != maddr)
  183. mapfree(rmap, oaddr, maddr-oaddr);
  184. return maddr;
  185. }
  186. unlock(rmap);
  187. return 0;
  188. }
  189. static void
  190. umbscan(void)
  191. {
  192. uint8_t *p;
  193. /*
  194. * Scan the Upper Memory Blocks (0xA0000->0xF0000) for pieces
  195. * which aren't used; they can be used later for devices which
  196. * want to allocate some virtual address space.
  197. * Check for two things:
  198. * 1) device BIOS ROM. This should start with a two-byte header
  199. * of 0x55 0xAA, followed by a byte giving the size of the ROM
  200. * in 512-byte chunks. These ROM's must start on a 2KiB boundary.
  201. * 2) device memory. This is read-write.
  202. * There are some assumptions: there's VGA memory at 0xA0000 and
  203. * the VGA BIOS ROM is at 0xC0000. Also, if there's no ROM signature
  204. * at 0xE0000 then the whole 64KiB up to 0xF0000 is theoretically up
  205. * for grabs; check anyway.
  206. */
  207. p = KADDR(0xD0000); /*RSC: changed from 0xC0000 */
  208. while(p < (uint8_t*)KADDR(0xE0000)){
  209. if (p[0] == 0x55 && p[1] == 0xAA) {
  210. /* Skip p[2] chunks of 512 bytes. Test for 0x55 AA before
  211. poking obtrusively, or else the Thinkpad X20 dies when
  212. setting up the cardbus (PB) */
  213. p += p[2] * 512;
  214. continue;
  215. }
  216. p[0] = 0xCC;
  217. p[2*KiB-1] = 0xCC;
  218. if(p[0] != 0xCC || p[2*KiB-1] != 0xCC){
  219. p[0] = 0x55;
  220. p[1] = 0xAA;
  221. p[2] = 4;
  222. if(p[0] == 0x55 && p[1] == 0xAA){
  223. p += p[2]*512;
  224. continue;
  225. }
  226. if(p[0] == 0xFF && p[1] == 0xFF)
  227. mapfree(&rmapumb, PADDR(p), 2*KiB);
  228. }
  229. else
  230. mapfree(&rmapumbrw, PADDR(p), 2*KiB);
  231. p += 2*KiB;
  232. }
  233. p = KADDR(0xE0000);
  234. if(p[0] != 0x55 || p[1] != 0xAA){
  235. p[0] = 0xCC;
  236. p[64*KiB-1] = 0xCC;
  237. if(p[0] != 0xCC && p[64*KiB-1] != 0xCC)
  238. mapfree(&rmapumb, PADDR(p), 64*KiB);
  239. }
  240. }
  241. void
  242. meminit(uint32_t)
  243. {
  244. MMap *map;
  245. uint32_t modend;
  246. uint64_t addr, last, len;
  247. umbscan();
  248. modend = PADDR(memstart);
  249. last = 0;
  250. for(map = mmap; map < &mmap[nmmap]; map++){
  251. addr = (((uint64_t)map->base[1])<<32)|map->base[0];
  252. len = (((uint64_t)map->length[1])<<32)|map->length[0];
  253. switch(map->type){
  254. default:
  255. case 2: /* reserved */
  256. case 3: /* ACPI Reclaim Memory */
  257. case 4: /* ACPI NVS Memory */
  258. break;
  259. case 1: /* Memory */
  260. if(addr < 1*MiB || addr+len < modend)
  261. break;
  262. if(addr < modend){
  263. len -= modend - addr;
  264. addr = modend;
  265. }
  266. mapraminit(addr, len);
  267. break;
  268. }
  269. if(addr != last && addr > modend){
  270. /*
  271. * See the comments in main about space < 1MiB.
  272. */
  273. if(addr >= 1*MiB || addr < 0x000A0000)
  274. mapupainit(last, addr-last);
  275. }
  276. last = addr+len;
  277. }
  278. /*
  279. changeconf("*noe820scan=1\n");
  280. */
  281. if(MEMDEBUG)
  282. memdebug();
  283. }
  284. uint32_t
  285. umbmalloc(uint32_t addr, int size, int align)
  286. {
  287. uint32_t a;
  288. if(a = mapalloc(&rmapumb, addr, size, align))
  289. return (uint32_t)KADDR(a);
  290. return 0;
  291. }
  292. void
  293. umbfree(uint32_t addr, int size)
  294. {
  295. mapfree(&rmapumb, PADDR(addr), size);
  296. }
  297. uint32_t
  298. umbrwmalloc(uint32_t addr, int size, int align)
  299. {
  300. uint32_t a;
  301. uint8_t *p;
  302. if(a = mapalloc(&rmapumbrw, addr, size, align))
  303. return(uint32_t)KADDR(a);
  304. /*
  305. * Perhaps the memory wasn't visible before
  306. * the interface is initialised, so try again.
  307. */
  308. if((a = umbmalloc(addr, size, align)) == 0)
  309. return 0;
  310. p = (uint8_t*)a;
  311. p[0] = 0xCC;
  312. p[size-1] = 0xCC;
  313. if(p[0] == 0xCC && p[size-1] == 0xCC)
  314. return a;
  315. umbfree(a, size);
  316. return 0;
  317. }
  318. void
  319. umbrwfree(uint32_t addr, int size)
  320. {
  321. mapfree(&rmapumbrw, PADDR(addr), size);
  322. }
  323. uint32_t*
  324. mmuwalk(uint32_t* pdb, uint32_t va, int level, int create)
  325. {
  326. uint32_t pa, *table;
  327. /*
  328. * Walk the page-table pointed to by pdb and return a pointer
  329. * to the entry for virtual address va at the requested level.
  330. * If the entry is invalid and create isn't requested then bail
  331. * out early. Otherwise, for the 2nd level walk, allocate a new
  332. * page-table page and register it in the 1st level.
  333. */
  334. table = &pdb[PDX(va)];
  335. if(!(*table & PTEVALID) && create == 0)
  336. return 0;
  337. switch(level){
  338. default:
  339. return 0;
  340. case 1:
  341. return table;
  342. case 2:
  343. if(*table & PTESIZE)
  344. panic("mmuwalk2: va 0x%ux entry 0x%ux\n", va, *table);
  345. if(!(*table & PTEVALID)){
  346. pa = PADDR(ialloc(BY2PG, BY2PG));
  347. *table = pa|PTEWRITE|PTEVALID;
  348. }
  349. table = KADDR(PPN(*table));
  350. return &table[PTX(va)];
  351. }
  352. }
  353. static Lock mmukmaplock;
  354. uint32_t
  355. mmukmap(uint32_t pa, uint32_t va, int size)
  356. {
  357. uint32_t pae, *table, *pdb, pgsz, *pte, x;
  358. int pse, sync;
  359. extern int cpuidax, cpuiddx;
  360. pdb = KADDR(getcr3());
  361. if((cpuiddx & 0x08) && (getcr4() & 0x10))
  362. pse = 1;
  363. else
  364. pse = 0;
  365. sync = 0;
  366. pa = PPN(pa);
  367. if(va == 0)
  368. va = (uint32_t)KADDR(pa);
  369. else
  370. va = PPN(va);
  371. pae = pa + size;
  372. lock(&mmukmaplock);
  373. while(pa < pae){
  374. table = &pdb[PDX(va)];
  375. /*
  376. * Possibly already mapped.
  377. */
  378. if(*table & PTEVALID){
  379. if(*table & PTESIZE){
  380. /*
  381. * Big page. Does it fit within?
  382. * If it does, adjust pgsz so the correct end can be
  383. * returned and get out.
  384. * If not, adjust pgsz up to the next 4MiB boundary
  385. * and continue.
  386. */
  387. x = PPN(*table);
  388. if(x != pa)
  389. panic("mmukmap1: pa 0x%ux entry 0x%ux\n",
  390. pa, *table);
  391. x += 4*MiB;
  392. if(pae <= x){
  393. pa = pae;
  394. break;
  395. }
  396. pgsz = x - pa;
  397. pa += pgsz;
  398. va += pgsz;
  399. continue;
  400. }
  401. else{
  402. /*
  403. * Little page. Walk to the entry.
  404. * If the entry is valid, set pgsz and continue.
  405. * If not, make it so, set pgsz, sync and continue.
  406. */
  407. pte = mmuwalk(pdb, va, 2, 0);
  408. if(pte && *pte & PTEVALID){
  409. x = PPN(*pte);
  410. if(x != pa)
  411. panic("mmukmap2: pa 0x%ux entry 0x%ux\n",
  412. pa, *pte);
  413. pgsz = BY2PG;
  414. pa += pgsz;
  415. va += pgsz;
  416. sync++;
  417. continue;
  418. }
  419. }
  420. }
  421. /*
  422. * Not mapped. Check if it can be mapped using a big page -
  423. * starts on a 4MiB boundary, size >= 4MiB and processor can do it.
  424. * If not a big page, walk the walk, talk the talk.
  425. * Sync is set.
  426. */
  427. if(pse && (pa % (4*MiB)) == 0 && (pae >= pa+4*MiB)){
  428. *table = pa|PTESIZE|PTEWRITE|PTEUNCACHED|PTEVALID;
  429. pgsz = 4*MiB;
  430. }
  431. else{
  432. pte = mmuwalk(pdb, va, 2, 1);
  433. *pte = pa|PTEWRITE|PTEUNCACHED|PTEVALID;
  434. pgsz = BY2PG;
  435. }
  436. pa += pgsz;
  437. va += pgsz;
  438. sync++;
  439. }
  440. unlock(&mmukmaplock);
  441. /*
  442. * If something was added
  443. * then need to sync up.
  444. */
  445. if(sync)
  446. putcr3(PADDR(pdb));
  447. return pa;
  448. }
  449. uint32_t
  450. upamalloc(uint32_t addr, int size, int align)
  451. {
  452. uint32_t ae, a;
  453. USED(align);
  454. if((a = mapalloc(&rmapupa, addr, size, align)) == 0){
  455. memdebug();
  456. return 0;
  457. }
  458. /*
  459. * This is a travesty, but they all are.
  460. */
  461. ae = mmukmap(a, 0, size);
  462. /*
  463. * Should check here that it was all delivered
  464. * and put it back and barf if not.
  465. */
  466. USED(ae);
  467. /*
  468. * Be very careful this returns a PHYSICAL address.
  469. */
  470. return a;
  471. }
  472. void
  473. upafree(uint32_t pa, int size)
  474. {
  475. USED(pa, size);
  476. }
  477. void
  478. mapraminit(uint64_t addr, uint32_t size)
  479. {
  480. uint32_t s;
  481. uint64_t a;
  482. /*
  483. * Careful - physical address.
  484. * Boot time only to populate map.
  485. */
  486. a = PGROUND(addr);
  487. s = a - addr;
  488. if(s >= size)
  489. return;
  490. mapfree(&rmapram, a, size-s);
  491. }
  492. void
  493. mapupainit(uint64_t addr, uint32_t size)
  494. {
  495. uint32_t s;
  496. uint64_t a;
  497. /*
  498. * Careful - physical address.
  499. * Boot time only to populate map.
  500. */
  501. a = PGROUND(addr);
  502. s = a - addr;
  503. if(s >= size)
  504. return;
  505. mapfree(&rmapupa, a, size-s);
  506. }