memory.c 13 KB

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