memory.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. /*
  2. * Size memory and create the kernel page-tables on the fly while doing so.
  3. * Called from main(), this code should only be run by the bootstrap processor.
  4. */
  5. #include "u.h"
  6. #include "../port/lib.h"
  7. #include "mem.h"
  8. #include "dat.h"
  9. #include "fns.h"
  10. #include "io.h"
  11. #define MEMDEBUG 0
  12. enum {
  13. MemUPA = 0, /* unbacked physical address */
  14. MemRAM = 1, /* physical memory */
  15. MemUMB = 2, /* upper memory block (<16MB) */
  16. NMemType = 3,
  17. KB = 1024,
  18. MemMinMB = 4, /* minimum physical memory (<=4MB) */
  19. MemMaxMB = 768, /* maximum physical memory to check */
  20. NMemBase = 10,
  21. };
  22. typedef struct {
  23. int size;
  24. ulong addr;
  25. } Map;
  26. typedef struct {
  27. char* name;
  28. Map* map;
  29. Map* mapend;
  30. Lock;
  31. } RMap;
  32. static Map mapupa[16];
  33. static RMap rmapupa = {
  34. "unallocated unbacked physical memory",
  35. mapupa,
  36. &mapupa[nelem(mapupa)-1],
  37. };
  38. static Map xmapupa[16];
  39. static RMap xrmapupa = {
  40. "unbacked physical memory",
  41. xmapupa,
  42. &xmapupa[nelem(xmapupa)-1],
  43. };
  44. static Map mapram[16];
  45. static RMap rmapram = {
  46. "physical memory",
  47. mapram,
  48. &mapram[nelem(mapram)-1],
  49. };
  50. static Map mapumb[64];
  51. static RMap rmapumb = {
  52. "upper memory block",
  53. mapumb,
  54. &mapumb[nelem(mapumb)-1],
  55. };
  56. static Map mapumbrw[16];
  57. static RMap rmapumbrw = {
  58. "UMB device memory",
  59. mapumbrw,
  60. &mapumbrw[nelem(mapumbrw)-1],
  61. };
  62. void
  63. mapprint(RMap *rmap)
  64. {
  65. Map *mp;
  66. print("%s\n", rmap->name);
  67. for(mp = rmap->map; mp->size; mp++)
  68. print("\t%8.8luX %8.8uX %8.8luX\n", mp->addr, mp->size, mp->addr+mp->size);
  69. }
  70. void
  71. memdebug(void)
  72. {
  73. ulong maxpa, maxpa1, maxpa2;
  74. if(MEMDEBUG == 0)
  75. return;
  76. maxpa = (nvramread(0x18)<<8)|nvramread(0x17);
  77. maxpa1 = (nvramread(0x31)<<8)|nvramread(0x30);
  78. maxpa2 = (nvramread(0x16)<<8)|nvramread(0x15);
  79. print("maxpa = %luX -> %luX, maxpa1 = %luX maxpa2 = %luX\n",
  80. maxpa, MB+maxpa*KB, maxpa1, maxpa2);
  81. mapprint(&rmapram);
  82. mapprint(&rmapumb);
  83. mapprint(&rmapumbrw);
  84. mapprint(&rmapupa);
  85. }
  86. void
  87. mapfree(RMap* rmap, ulong addr, ulong size)
  88. {
  89. Map *mp;
  90. ulong t;
  91. if(size <= 0)
  92. return;
  93. lock(rmap);
  94. for(mp = rmap->map; mp->addr <= addr && mp->size; mp++)
  95. ;
  96. if(mp > rmap->map && (mp-1)->addr+(mp-1)->size == addr){
  97. (mp-1)->size += size;
  98. if(addr+size == mp->addr){
  99. (mp-1)->size += mp->size;
  100. while(mp->size){
  101. mp++;
  102. (mp-1)->addr = mp->addr;
  103. (mp-1)->size = mp->size;
  104. }
  105. }
  106. }
  107. else{
  108. if(addr+size == mp->addr && mp->size){
  109. mp->addr -= size;
  110. mp->size += size;
  111. }
  112. else do{
  113. if(mp >= rmap->mapend){
  114. print("mapfree: %s: losing 0x%luX, %ld\n",
  115. rmap->name, addr, size);
  116. break;
  117. }
  118. t = mp->addr;
  119. mp->addr = addr;
  120. addr = t;
  121. t = mp->size;
  122. mp->size = size;
  123. mp++;
  124. }while(size = t);
  125. }
  126. unlock(rmap);
  127. }
  128. ulong
  129. mapalloc(RMap* rmap, ulong addr, int size, int align)
  130. {
  131. Map *mp;
  132. ulong maddr, oaddr;
  133. lock(rmap);
  134. for(mp = rmap->map; mp->size; mp++){
  135. maddr = mp->addr;
  136. if(addr){
  137. /*
  138. * A specific address range has been given:
  139. * if the current map entry is greater then
  140. * the address is not in the map;
  141. * if the current map entry does not overlap
  142. * the beginning of the requested range then
  143. * continue on to the next map entry;
  144. * if the current map entry does not entirely
  145. * contain the requested range then the range
  146. * is not in the map.
  147. */
  148. if(maddr > addr)
  149. break;
  150. if(mp->size < addr - maddr) /* maddr+mp->size < addr, but no overflow */
  151. continue;
  152. if(addr - maddr > mp->size - size) /* addr+size > maddr+mp->size, but no overflow */
  153. break;
  154. maddr = addr;
  155. }
  156. if(align > 0)
  157. maddr = ((maddr+align-1)/align)*align;
  158. if(mp->addr+mp->size-maddr < size)
  159. continue;
  160. oaddr = mp->addr;
  161. mp->addr = maddr+size;
  162. mp->size -= maddr-oaddr+size;
  163. if(mp->size == 0){
  164. do{
  165. mp++;
  166. (mp-1)->addr = mp->addr;
  167. }while((mp-1)->size = mp->size);
  168. }
  169. unlock(rmap);
  170. if(oaddr != maddr)
  171. mapfree(rmap, oaddr, maddr-oaddr);
  172. return maddr;
  173. }
  174. unlock(rmap);
  175. return 0;
  176. }
  177. static void
  178. umbscan(void)
  179. {
  180. uchar *p;
  181. /*
  182. * Scan the Upper Memory Blocks (0xA0000->0xF0000) for pieces
  183. * which aren't used; they can be used later for devices which
  184. * want to allocate some virtual address space.
  185. * Check for two things:
  186. * 1) device BIOS ROM. This should start with a two-byte header
  187. * of 0x55 0xAA, followed by a byte giving the size of the ROM
  188. * in 512-byte chunks. These ROM's must start on a 2KB boundary.
  189. * 2) device memory. This is read-write.
  190. * There are some assumptions: there's VGA memory at 0xA0000 and
  191. * the VGA BIOS ROM is at 0xC0000. Also, if there's no ROM signature
  192. * at 0xE0000 then the whole 64KB up to 0xF0000 is theoretically up
  193. * for grabs; check anyway.
  194. */
  195. p = KADDR(0xD0000);
  196. while(p < (uchar*)KADDR(0xE0000)){
  197. /*
  198. * Test for 0x55 0xAA before poking obtrusively,
  199. * some machines (e.g. Thinkpad X20) seem to map
  200. * something dynamic here (cardbus?) causing weird
  201. * problems if it is changed.
  202. */
  203. if(p[0] == 0x55 && p[1] == 0xAA){
  204. p += p[2]*512;
  205. continue;
  206. }
  207. p[0] = 0xCC;
  208. p[2*KB-1] = 0xCC;
  209. if(p[0] != 0xCC || p[2*KB-1] != 0xCC){
  210. p[0] = 0x55;
  211. p[1] = 0xAA;
  212. p[2] = 4;
  213. if(p[0] == 0x55 && p[1] == 0xAA){
  214. p += p[2]*512;
  215. continue;
  216. }
  217. if(p[0] == 0xFF && p[1] == 0xFF)
  218. mapfree(&rmapumb, PADDR(p), 2*KB);
  219. }
  220. else
  221. mapfree(&rmapumbrw, PADDR(p), 2*KB);
  222. p += 2*KB;
  223. }
  224. p = KADDR(0xE0000);
  225. if(p[0] != 0x55 || p[1] != 0xAA){
  226. p[0] = 0xCC;
  227. p[64*KB-1] = 0xCC;
  228. if(p[0] != 0xCC && p[64*KB-1] != 0xCC)
  229. mapfree(&rmapumb, PADDR(p), 64*KB);
  230. }
  231. }
  232. static void
  233. ramscan(ulong maxmem)
  234. {
  235. ulong *k0, kzero, map, maxpa, pa, *pte, *table, *va, x, n;
  236. int nvalid[NMemType];
  237. uchar *bda;
  238. /*
  239. * The bootstrap code has has created a prototype page
  240. * table which maps the first MemMinMB of physical memory to KZERO.
  241. * The page directory is at m->pdb and the first page of
  242. * free memory is after the per-processor MMU information.
  243. */
  244. /*
  245. * Initialise the memory bank information for conventional memory
  246. * (i.e. less than 640KB). The base is the first location after the
  247. * bootstrap processor MMU information and the limit is obtained from
  248. * the BIOS data area.
  249. */
  250. x = PADDR(CPU0MACH+BY2PG);
  251. bda = (uchar*)KADDR(0x400);
  252. n = ((bda[0x14]<<8)|bda[0x13])*KB-x;
  253. mapfree(&rmapram, x, n);
  254. memset(KADDR(x), 0, n); /* keep us honest */
  255. x = PADDR(PGROUND((ulong)end));
  256. pa = MemMinMB*MB;
  257. mapfree(&rmapram, x, pa-x);
  258. memset(KADDR(x), 0, pa-x); /* keep us honest */
  259. /*
  260. * Check if the extended memory size can be obtained from the CMOS.
  261. * If it's 0 then it's either not known or >= 64MB. Always check
  262. * at least 24MB in case there's a memory gap (up to 8MB) below 16MB;
  263. * in this case the memory from the gap is remapped to the top of
  264. * memory.
  265. * The value in CMOS is supposed to be the number of KB above 1MB.
  266. */
  267. if(maxmem == 0){
  268. x = (nvramread(0x18)<<8)|nvramread(0x17);
  269. if(x == 0 || x >= (63*KB))
  270. maxpa = MemMaxMB*MB;
  271. else
  272. maxpa = MB+x*KB;
  273. if(maxpa < 24*MB)
  274. maxpa = 24*MB;
  275. maxmem = MemMaxMB*MB;
  276. }
  277. else
  278. maxpa = maxmem;
  279. /*
  280. * March up memory from MemMinMB to maxpa 1MB at a time,
  281. * mapping the first page and checking the page can
  282. * be written and read correctly. The page tables are created here
  283. * on the fly, allocating from low memory as necessary.
  284. */
  285. k0 = (ulong*)KADDR(0);
  286. kzero = *k0;
  287. map = 0;
  288. x = 0x12345678;
  289. memset(nvalid, 0, sizeof(nvalid));
  290. while(pa < maxpa){
  291. /*
  292. * Map the page. Use mapalloc(&rmapram, ...) to make
  293. * the page table if necessary, it will be returned to the
  294. * pool later if it isn't needed.
  295. */
  296. va = KADDR(pa);
  297. table = &m->pdb[PDX(va)];
  298. if(*table == 0){
  299. if(map == 0 && (map = mapalloc(&rmapram, 0, BY2PG, BY2PG)) == 0)
  300. break;
  301. memset(KADDR(map), 0, BY2PG);
  302. *table = map|PTEWRITE|PTEVALID;
  303. memset(nvalid, 0, sizeof(nvalid));
  304. }
  305. table = KADDR(PPN(*table));
  306. pte = &table[PTX(va)];
  307. *pte = pa|PTEWRITE|PTEUNCACHED|PTEVALID;
  308. mmuflushtlb(PADDR(m->pdb));
  309. /*
  310. * Write a pattern to the page and write a different
  311. * pattern to a possible mirror at KZER0. If the data
  312. * reads back correctly the chunk is some type of RAM (possibly
  313. * a linearly-mapped VGA framebuffer, for instance...) and
  314. * can be cleared and added to the memory pool. If not, the
  315. * chunk is marked uncached and added to the UMB pool if <16MB
  316. * or is marked invalid and added to the UPA pool.
  317. */
  318. *va = x;
  319. *k0 = ~x;
  320. if(*va == x){
  321. nvalid[MemRAM] += MB/BY2PG;
  322. mapfree(&rmapram, pa, MB);
  323. do{
  324. *pte++ = pa|PTEWRITE|PTEVALID;
  325. pa += BY2PG;
  326. }while(pa % MB);
  327. mmuflushtlb(PADDR(m->pdb));
  328. /* memset(va, 0, MB); so damn slow to memset all of memory */
  329. }
  330. else if(pa < 16*MB){
  331. nvalid[MemUMB] += MB/BY2PG;
  332. mapfree(&rmapumb, pa, MB);
  333. do{
  334. *pte++ = pa|PTEWRITE|PTEUNCACHED|PTEVALID;
  335. pa += BY2PG;
  336. }while(pa % MB);
  337. }
  338. else{
  339. nvalid[MemUPA] += MB/BY2PG;
  340. mapfree(&rmapupa, pa, MB);
  341. *pte = 0;
  342. pa += MB;
  343. }
  344. /*
  345. * Done with this 4MB chunk, review the options:
  346. * 1) not physical memory and >=16MB - invalidate the PDB entry;
  347. * 2) physical memory - use the 4MB page extension if possible;
  348. * 3) not physical memory and <16MB - use the 4MB page extension
  349. * if possible;
  350. * 4) mixed or no 4MB page extension - commit the already
  351. * initialised space for the page table.
  352. */
  353. if((pa % (4*MB)) == 0){
  354. table = &m->pdb[PDX(va)];
  355. if(nvalid[MemUPA] == (4*MB)/BY2PG)
  356. *table = 0;
  357. else if(nvalid[MemRAM] == (4*MB)/BY2PG && (m->cpuiddx & 0x08))
  358. *table = (pa - 4*MB)|PTESIZE|PTEWRITE|PTEVALID;
  359. else if(nvalid[MemUMB] == (4*MB)/BY2PG && (m->cpuiddx & 0x08))
  360. *table = (pa - 4*MB)|PTESIZE|PTEWRITE|PTEUNCACHED|PTEVALID;
  361. else
  362. map = 0;
  363. }
  364. mmuflushtlb(PADDR(m->pdb));
  365. x += 0x3141526;
  366. }
  367. /*
  368. * If we didn't reach the end of the 4MB chunk, that part won't
  369. * be mapped. Commit the already initialised space for the page table.
  370. */
  371. if(pa % (4*MB))
  372. map = 0;
  373. if(map)
  374. mapfree(&rmapram, map, BY2PG);
  375. if(pa < maxmem)
  376. mapfree(&rmapupa, pa, maxmem-pa);
  377. if(maxmem < 0xFFE00000)
  378. mapfree(&rmapupa, maxmem, 0x00000000-maxmem);
  379. if(MEMDEBUG)
  380. print("maxmem %luX %luX\n", maxmem, 0x00000000-maxmem);
  381. *k0 = kzero;
  382. }
  383. void
  384. meminit(void)
  385. {
  386. Map *mp, *xmp;
  387. ulong pa, *pte;
  388. ulong maxmem;
  389. char *p;
  390. if(p = getconf("*maxmem"))
  391. maxmem = strtoul(p, 0, 0);
  392. else
  393. maxmem = 0;
  394. /*
  395. * Set special attributes for memory between 640KB and 1MB:
  396. * VGA memory is writethrough;
  397. * BIOS ROM's/UMB's are uncached;
  398. * then scan for useful memory.
  399. */
  400. for(pa = 0xA0000; pa < 0xC0000; pa += BY2PG){
  401. pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 2, 0);
  402. *pte |= PTEWT;
  403. }
  404. for(pa = 0xC0000; pa < 0x100000; pa += BY2PG){
  405. pte = mmuwalk(m->pdb, (ulong)KADDR(pa), 2, 0);
  406. *pte |= PTEUNCACHED;
  407. }
  408. mmuflushtlb(PADDR(m->pdb));
  409. umbscan();
  410. ramscan(maxmem);
  411. /*
  412. * Set the conf entries describing two banks of allocatable memory.
  413. * Grab the first and largest entries in rmapram as left by ramscan().
  414. *
  415. * It would be nice to have more than 2 memory banks describable in conf.
  416. */
  417. mp = rmapram.map;
  418. conf.base0 = mp->addr;
  419. conf.npage0 = mp->size/BY2PG;
  420. mp++;
  421. for(xmp = 0; mp->size; mp++){
  422. if(xmp == 0 || mp->size > xmp->size)
  423. xmp = mp;
  424. }
  425. if(xmp){
  426. conf.base1 = xmp->addr;
  427. conf.npage1 = xmp->size/BY2PG;
  428. }
  429. if(MEMDEBUG)
  430. memdebug();
  431. }
  432. ulong
  433. umbmalloc(ulong addr, int size, int align)
  434. {
  435. ulong a;
  436. if(a = mapalloc(&rmapumb, addr, size, align))
  437. return (ulong)KADDR(a);
  438. return 0;
  439. }
  440. void
  441. umbfree(ulong addr, int size)
  442. {
  443. mapfree(&rmapumb, PADDR(addr), size);
  444. }
  445. ulong
  446. umbrwmalloc(ulong addr, int size, int align)
  447. {
  448. ulong a;
  449. uchar *p;
  450. if(a = mapalloc(&rmapumbrw, addr, size, align))
  451. return(ulong)KADDR(a);
  452. /*
  453. * Perhaps the memory wasn't visible before
  454. * the interface is initialised, so try again.
  455. */
  456. if((a = umbmalloc(addr, size, align)) == 0)
  457. return 0;
  458. p = (uchar*)a;
  459. p[0] = 0xCC;
  460. p[size-1] = 0xCC;
  461. if(p[0] == 0xCC && p[size-1] == 0xCC)
  462. return a;
  463. umbfree(a, size);
  464. return 0;
  465. }
  466. void
  467. umbrwfree(ulong addr, int size)
  468. {
  469. mapfree(&rmapumbrw, PADDR(addr), size);
  470. }
  471. ulong
  472. upamalloc(ulong pa, int size, int align)
  473. {
  474. ulong a, ae;
  475. if(a = mapalloc(&xrmapupa, pa, size, align))
  476. return a;
  477. if((a = mapalloc(&rmapupa, pa, size, align)) == 0){
  478. memdebug();
  479. return 0;
  480. }
  481. /*
  482. * Upamalloc is a request to map a range of physical addresses.
  483. * Therefore, if pa is 0 mapalloc will choose the base address.
  484. * Note, however, mmukmap is always asked to give a 1-to-1 mapping
  485. * of va to pa.
  486. ae = mmukmap(a, a, size);
  487. * ...but for the moment go back to the old scheme for VLB cards.
  488. */
  489. ae = mmukmap(a, 0, size);
  490. /*
  491. * Should check here that it was all delivered
  492. * and put it back and barf if not.
  493. */
  494. USED(ae);
  495. /*
  496. * Be very careful this returns a PHYSICAL address
  497. * mapped 1-to-1 with the virtual address.
  498. * If a < KZERO it's probably not a good idea to
  499. * try KADDR(a)...
  500. */
  501. return a;
  502. }
  503. void
  504. upafree(ulong pa, int size)
  505. {
  506. mapfree(&xrmapupa, pa, size);
  507. }