|
|
1.1 ! root 1: /* lib.c ! 2: * tag: simple function library ! 3: * ! 4: * Copyright (C) 2003 Stefan Reinauer ! 5: * ! 6: * See the file "COPYING" for further information about ! 7: * the copyright and warranty status of this work. ! 8: */ ! 9: ! 10: #include "config.h" ! 11: #include "libc/vsprintf.h" ! 12: #include "libopenbios/bindings.h" ! 13: #include "spitfire.h" ! 14: #include "libopenbios/sys_info.h" ! 15: #include "boot.h" ! 16: ! 17: #include "ofmem_sparc64.h" ! 18: ! 19: static ucell *va2ttedata = 0; ! 20: ! 21: /* Format a string and print it on the screen, just like the libc ! 22: * function printf. ! 23: */ ! 24: int printk( const char *fmt, ... ) ! 25: { ! 26: char *p, buf[512]; ! 27: va_list args; ! 28: int i; ! 29: ! 30: va_start(args, fmt); ! 31: i = vsnprintf(buf, sizeof(buf), fmt, args); ! 32: va_end(args); ! 33: ! 34: for( p=buf; *p; p++ ) ! 35: putchar(*p); ! 36: return i; ! 37: } ! 38: ! 39: /* Private functions for mapping between physical/virtual addresses */ ! 40: phys_addr_t ! 41: va2pa(unsigned long va) ! 42: { ! 43: if ((va >= (unsigned long)&_start) && ! 44: (va < (unsigned long)&_end)) ! 45: return va - va_shift; ! 46: else ! 47: return va; ! 48: } ! 49: ! 50: unsigned long ! 51: pa2va(phys_addr_t pa) ! 52: { ! 53: if ((pa + va_shift >= (unsigned long)&_start) && ! 54: (pa + va_shift < (unsigned long)&_end)) ! 55: return pa + va_shift; ! 56: else ! 57: return pa; ! 58: } ! 59: ! 60: void *malloc(int size) ! 61: { ! 62: return ofmem_malloc(size); ! 63: } ! 64: ! 65: void* realloc( void *ptr, size_t size ) ! 66: { ! 67: return ofmem_realloc(ptr, size); ! 68: } ! 69: ! 70: void free(void *ptr) ! 71: { ! 72: ofmem_free(ptr); ! 73: } ! 74: ! 75: #define PAGE_SIZE_4M (4 * 1024 * 1024) ! 76: #define PAGE_SIZE_512K (512 * 1024) ! 77: #define PAGE_SIZE_64K (64 * 1024) ! 78: #define PAGE_SIZE_8K (8 * 1024) ! 79: #define PAGE_MASK_4M (4 * 1024 * 1024 - 1) ! 80: #define PAGE_MASK_512K (512 * 1024 - 1) ! 81: #define PAGE_MASK_64K (64 * 1024 - 1) ! 82: #define PAGE_MASK_8K (8 * 1024 - 1) ! 83: ! 84: static void ! 85: mmu_open(void) ! 86: { ! 87: RET(-1); ! 88: } ! 89: ! 90: static void ! 91: mmu_close(void) ! 92: { ! 93: } ! 94: ! 95: void ofmem_walk_boot_map(translation_entry_cb cb) ! 96: { ! 97: unsigned long phys, virt, size, mode, data, mask; ! 98: unsigned int i; ! 99: ! 100: for (i = 0; i < 64; i++) { ! 101: data = spitfire_get_dtlb_data(i); ! 102: if (data & SPITFIRE_TTE_VALID) { ! 103: switch ((data >> 61) & 3) { ! 104: default: ! 105: case 0x0: /* 8k */ ! 106: mask = 0xffffffffffffe000ULL; ! 107: size = PAGE_SIZE_8K; ! 108: break; ! 109: case 0x1: /* 64k */ ! 110: mask = 0xffffffffffff0000ULL; ! 111: size = PAGE_SIZE_64K; ! 112: break; ! 113: case 0x2: /* 512k */ ! 114: mask = 0xfffffffffff80000ULL; ! 115: size = PAGE_SIZE_512K; ! 116: break; ! 117: case 0x3: /* 4M */ ! 118: mask = 0xffffffffffc00000ULL; ! 119: size = PAGE_SIZE_4M; ! 120: break; ! 121: } ! 122: ! 123: virt = spitfire_get_dtlb_tag(i); ! 124: virt &= mask; ! 125: ! 126: /* extract 41bit physical address */ ! 127: phys = data & 0x000001fffffff000ULL; ! 128: phys &= mask; ! 129: ! 130: mode = data & 0xfff; ! 131: ! 132: cb(phys, virt, size, mode); ! 133: } ! 134: } ! 135: } ! 136: ! 137: /* ! 138: 3.6.5 translate ! 139: ( virt -- false | phys.lo ... phys.hi mode true ) ! 140: */ ! 141: static void ! 142: mmu_translate(void) ! 143: { ! 144: ucell virt, mode; ! 145: phys_addr_t phys; ! 146: ! 147: virt = POP(); ! 148: ! 149: phys = ofmem_translate(virt, &mode); ! 150: ! 151: if (phys != -1UL) { ! 152: PUSH(phys & 0xffffffff); ! 153: PUSH(phys >> 32); ! 154: PUSH(mode); ! 155: PUSH(-1); ! 156: } ! 157: else { ! 158: PUSH(0); ! 159: } ! 160: } ! 161: ! 162: /* ! 163: * D5.3 pgmap@ ( va -- tte ) ! 164: */ ! 165: static void ! 166: pgmap_fetch(void) ! 167: { ! 168: translation_t *t = *g_ofmem_translations; ! 169: unsigned long va, tte_data; ! 170: ! 171: va = POP(); ! 172: ! 173: /* Search the ofmem linked list for this virtual address */ ! 174: while (t != NULL) { ! 175: /* Find the correct range */ ! 176: if (va >= t->virt && va < (t->virt + t->size)) { ! 177: ! 178: /* valid tte, 8k size */ ! 179: tte_data = SPITFIRE_TTE_VALID; ! 180: ! 181: /* mix in phys address mode */ ! 182: tte_data |= t->mode; ! 183: ! 184: /* mix in page physical address = t->phys + offset */ ! 185: tte_data |= t->phys + (va - t->virt); ! 186: ! 187: /* return tte_data */ ! 188: PUSH(tte_data); ! 189: ! 190: return; ! 191: } ! 192: t = t->next; ! 193: } ! 194: ! 195: /* If we get here, there was no entry */ ! 196: PUSH(0); ! 197: } ! 198: ! 199: static void ! 200: dtlb_load2(unsigned long vaddr, unsigned long tte_data) ! 201: { ! 202: asm("stxa %0, [%1] %2\n" ! 203: "stxa %3, [%%g0] %4\n" ! 204: : : "r" (vaddr), "r" (48), "i" (ASI_DMMU), ! 205: "r" (tte_data), "i" (ASI_DTLB_DATA_IN)); ! 206: } ! 207: ! 208: static void ! 209: dtlb_load3(unsigned long vaddr, unsigned long tte_data, ! 210: unsigned long tte_index) ! 211: { ! 212: asm("stxa %0, [%1] %2\n" ! 213: "stxa %3, [%4] %5\n" ! 214: : : "r" (vaddr), "r" (48), "i" (ASI_DMMU), ! 215: "r" (tte_data), "r" (tte_index << 3), "i" (ASI_DTLB_DATA_ACCESS)); ! 216: } ! 217: ! 218: static unsigned long ! 219: dtlb_faultva(void) ! 220: { ! 221: unsigned long faultva; ! 222: ! 223: asm("ldxa [%1] %2, %0\n" ! 224: : "=r" (faultva) ! 225: : "r" (48), "i" (ASI_DMMU)); ! 226: ! 227: return faultva; ! 228: } ! 229: ! 230: /* ! 231: ( index tte_data vaddr -- ? ) ! 232: */ ! 233: static void ! 234: dtlb_load(void) ! 235: { ! 236: unsigned long vaddr, tte_data, idx; ! 237: ! 238: vaddr = POP(); ! 239: tte_data = POP(); ! 240: idx = POP(); ! 241: dtlb_load3(vaddr, tte_data, idx); ! 242: } ! 243: ! 244: /* MMU D-TLB miss handler */ ! 245: void ! 246: dtlb_miss_handler(void) ! 247: { ! 248: unsigned long faultva, tte_data = 0; ! 249: ! 250: /* Grab fault address from MMU and round to nearest 8k page */ ! 251: faultva = dtlb_faultva(); ! 252: faultva >>= 13; ! 253: faultva <<= 13; ! 254: ! 255: /* If a valid va>tte-data routine has been set, invoke that Forth xt instead */ ! 256: if (va2ttedata && *va2ttedata != 0) { ! 257: ! 258: /* va>tte-data ( addr cnum -- false | tte-data true ) */ ! 259: PUSH(faultva); ! 260: PUSH(0); ! 261: enterforth(*va2ttedata); ! 262: ! 263: /* Check the result first... */ ! 264: tte_data = POP(); ! 265: if (!tte_data) { ! 266: bug(); ! 267: } else { ! 268: /* Grab the real data */ ! 269: tte_data = POP(); ! 270: } ! 271: } else { ! 272: /* Search the ofmem linked list for this virtual address */ ! 273: PUSH(faultva); ! 274: pgmap_fetch(); ! 275: tte_data = POP(); ! 276: } ! 277: ! 278: if (tte_data) { ! 279: /* Update MMU */ ! 280: dtlb_load2(faultva, tte_data); ! 281: } else { ! 282: /* If we got here, there was no translation so fail */ ! 283: bug(); ! 284: } ! 285: ! 286: } ! 287: ! 288: static void ! 289: itlb_load2(unsigned long vaddr, unsigned long tte_data) ! 290: { ! 291: asm("stxa %0, [%1] %2\n" ! 292: "stxa %3, [%%g0] %4\n" ! 293: : : "r" (vaddr), "r" (48), "i" (ASI_IMMU), ! 294: "r" (tte_data), "i" (ASI_ITLB_DATA_IN)); ! 295: } ! 296: ! 297: static void ! 298: itlb_load3(unsigned long vaddr, unsigned long tte_data, ! 299: unsigned long tte_index) ! 300: { ! 301: asm("stxa %0, [%1] %2\n" ! 302: "stxa %3, [%4] %5\n" ! 303: : : "r" (vaddr), "r" (48), "i" (ASI_IMMU), ! 304: "r" (tte_data), "r" (tte_index << 3), "i" (ASI_ITLB_DATA_ACCESS)); ! 305: } ! 306: ! 307: /* ! 308: ( index tte_data vaddr -- ? ) ! 309: */ ! 310: static void ! 311: itlb_load(void) ! 312: { ! 313: unsigned long vaddr, tte_data, idx; ! 314: ! 315: vaddr = POP(); ! 316: tte_data = POP(); ! 317: idx = POP(); ! 318: itlb_load3(vaddr, tte_data, idx); ! 319: } ! 320: ! 321: static unsigned long ! 322: itlb_faultva(void) ! 323: { ! 324: unsigned long faultva; ! 325: ! 326: asm("ldxa [%1] %2, %0\n" ! 327: : "=r" (faultva) ! 328: : "r" (48), "i" (ASI_IMMU)); ! 329: ! 330: return faultva; ! 331: } ! 332: ! 333: /* MMU I-TLB miss handler */ ! 334: void ! 335: itlb_miss_handler(void) ! 336: { ! 337: unsigned long faultva, tte_data = 0; ! 338: ! 339: /* Grab fault address from MMU and round to nearest 8k page */ ! 340: faultva = itlb_faultva(); ! 341: faultva >>= 13; ! 342: faultva <<= 13; ! 343: ! 344: /* If a valid va>tte-data routine has been set, invoke that Forth xt instead */ ! 345: if (va2ttedata && *va2ttedata != 0) { ! 346: ! 347: /* va>tte-data ( addr cnum -- false | tte-data true ) */ ! 348: PUSH(faultva); ! 349: PUSH(0); ! 350: enterforth(*va2ttedata); ! 351: ! 352: /* Check the result first... */ ! 353: tte_data = POP(); ! 354: if (!tte_data) { ! 355: bug(); ! 356: } else { ! 357: /* Grab the real data */ ! 358: tte_data = POP(); ! 359: } ! 360: } else { ! 361: /* Search the ofmem linked list for this virtual address */ ! 362: PUSH(faultva); ! 363: pgmap_fetch(); ! 364: tte_data = POP(); ! 365: } ! 366: ! 367: if (tte_data) { ! 368: /* Update MMU */ ! 369: itlb_load2(faultva, tte_data); ! 370: } else { ! 371: /* If we got here, there was no translation so fail */ ! 372: bug(); ! 373: } ! 374: } ! 375: ! 376: static void ! 377: map_pages(phys_addr_t phys, unsigned long virt, ! 378: unsigned long size, unsigned long mode) ! 379: { ! 380: unsigned long tte_data, currsize; ! 381: ! 382: /* aligned to 8k page */ ! 383: size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K; ! 384: ! 385: while (size > 0) { ! 386: currsize = size; ! 387: if (currsize >= PAGE_SIZE_4M && ! 388: (virt & PAGE_MASK_4M) == 0 && ! 389: (phys & PAGE_MASK_4M) == 0) { ! 390: currsize = PAGE_SIZE_4M; ! 391: tte_data = 6ULL << 60; ! 392: } else if (currsize >= PAGE_SIZE_512K && ! 393: (virt & PAGE_MASK_512K) == 0 && ! 394: (phys & PAGE_MASK_512K) == 0) { ! 395: currsize = PAGE_SIZE_512K; ! 396: tte_data = 4ULL << 60; ! 397: } else if (currsize >= PAGE_SIZE_64K && ! 398: (virt & PAGE_MASK_64K) == 0 && ! 399: (phys & PAGE_MASK_64K) == 0) { ! 400: currsize = PAGE_SIZE_64K; ! 401: tte_data = 2ULL << 60; ! 402: } else { ! 403: currsize = PAGE_SIZE_8K; ! 404: tte_data = 0; ! 405: } ! 406: ! 407: tte_data |= phys | mode | SPITFIRE_TTE_VALID; ! 408: ! 409: itlb_load2(virt, tte_data); ! 410: dtlb_load2(virt, tte_data); ! 411: ! 412: size -= currsize; ! 413: phys += currsize; ! 414: virt += currsize; ! 415: } ! 416: } ! 417: ! 418: void ofmem_map_pages(phys_addr_t phys, ucell virt, ucell size, ucell mode) ! 419: { ! 420: return map_pages(phys, virt, size, mode); ! 421: } ! 422: ! 423: /* ! 424: 3.6.5 map ! 425: ( phys.lo ... phys.hi virt size mode -- ) ! 426: */ ! 427: static void ! 428: mmu_map(void) ! 429: { ! 430: ucell virt, size, mode; ! 431: phys_addr_t phys; ! 432: ! 433: mode = POP(); ! 434: size = POP(); ! 435: virt = POP(); ! 436: phys = POP(); ! 437: phys <<= 32; ! 438: phys |= POP(); ! 439: ! 440: ofmem_map(phys, virt, size, mode); ! 441: } ! 442: ! 443: static void ! 444: itlb_demap(unsigned long vaddr) ! 445: { ! 446: asm("stxa %0, [%0] %1\n" ! 447: : : "r" (vaddr), "i" (ASI_IMMU_DEMAP)); ! 448: } ! 449: ! 450: static void ! 451: dtlb_demap(unsigned long vaddr) ! 452: { ! 453: asm("stxa %0, [%0] %1\n" ! 454: : : "r" (vaddr), "i" (ASI_DMMU_DEMAP)); ! 455: } ! 456: ! 457: static void ! 458: unmap_pages(ucell virt, ucell size) ! 459: { ! 460: ucell va; ! 461: ! 462: /* align address to 8k */ ! 463: virt &= ~PAGE_MASK_8K; ! 464: ! 465: /* align size to 8k */ ! 466: size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K; ! 467: ! 468: for (va = virt; va < virt + size; va += PAGE_SIZE_8K) { ! 469: itlb_demap(va); ! 470: dtlb_demap(va); ! 471: } ! 472: } ! 473: ! 474: void ofmem_arch_unmap_pages(ucell virt, ucell size) ! 475: { ! 476: unmap_pages(virt, size); ! 477: } ! 478: ! 479: void ofmem_arch_early_map_pages(phys_addr_t phys, ucell virt, ucell size, ucell mode) ! 480: { ! 481: if (mode & SPITFIRE_TTE_LOCKED) { ! 482: // install locked tlb entries now ! 483: ofmem_map_pages(phys, virt, size, mode); ! 484: } ! 485: } ! 486: ! 487: /* ! 488: 3.6.5 unmap ! 489: ( virt size -- ) ! 490: */ ! 491: static void ! 492: mmu_unmap(void) ! 493: { ! 494: ucell virt, size; ! 495: ! 496: size = POP(); ! 497: virt = POP(); ! 498: ofmem_unmap(virt, size); ! 499: } ! 500: ! 501: /* ! 502: 3.6.5 claim ! 503: ( virt size align -- base ) ! 504: */ ! 505: static void ! 506: mmu_claim(void) ! 507: { ! 508: ucell virt=-1UL, size, align; ! 509: ! 510: align = POP(); ! 511: size = POP(); ! 512: if (!align) { ! 513: virt = POP(); ! 514: } ! 515: ! 516: virt = ofmem_claim_virt(virt, size, align); ! 517: ! 518: PUSH(virt); ! 519: } ! 520: ! 521: /* ! 522: 3.6.5 release ! 523: ( virt size -- ) ! 524: */ ! 525: static void ! 526: mmu_release(void) ! 527: { ! 528: ucell virt, size; ! 529: ! 530: size = POP(); ! 531: virt = POP(); ! 532: ! 533: ofmem_release_virt(virt, size); ! 534: } ! 535: ! 536: /* ( phys size align --- base ) */ ! 537: static void ! 538: mem_claim( void ) ! 539: { ! 540: ucell size, align; ! 541: phys_addr_t phys=-1UL; ! 542: ! 543: align = POP(); ! 544: size = POP(); ! 545: if (!align) { ! 546: phys = POP(); ! 547: phys <<= 32; ! 548: phys |= POP(); ! 549: } ! 550: ! 551: phys = ofmem_claim_phys(phys, size, align); ! 552: ! 553: PUSH(phys & 0xffffffffUL); ! 554: PUSH(phys >> 32); ! 555: } ! 556: ! 557: /* ( phys size --- ) */ ! 558: static void ! 559: mem_release( void ) ! 560: { ! 561: phys_addr_t phys; ! 562: ucell size; ! 563: ! 564: size = POP(); ! 565: phys = POP(); ! 566: phys <<= 32; ! 567: phys |= POP(); ! 568: ! 569: ofmem_release_phys(phys, size); ! 570: } ! 571: ! 572: /* ( name-cstr phys size align --- phys ) */ ! 573: static void ! 574: mem_retain ( void ) ! 575: { ! 576: ucell size, align; ! 577: phys_addr_t phys=-1UL; ! 578: ! 579: align = POP(); ! 580: size = POP(); ! 581: if (!align) { ! 582: phys = POP(); ! 583: phys <<= 32; ! 584: phys |= POP(); ! 585: } ! 586: ! 587: /* Currently do nothing with the name */ ! 588: POP(); ! 589: ! 590: phys = ofmem_retain(phys, size, align); ! 591: ! 592: PUSH(phys & 0xffffffffUL); ! 593: PUSH(phys >> 32); ! 594: } ! 595: ! 596: /* ( virt size align -- baseaddr|-1 ) */ ! 597: static void ! 598: ciface_claim( void ) ! 599: { ! 600: ucell align = POP(); ! 601: ucell size = POP(); ! 602: ucell virt = POP(); ! 603: ucell ret = ofmem_claim( virt, size, align ); ! 604: ! 605: /* printk("ciface_claim: %08x %08x %x\n", virt, size, align ); */ ! 606: PUSH( ret ); ! 607: } ! 608: ! 609: /* ( virt size -- ) */ ! 610: static void ! 611: ciface_release( void ) ! 612: { ! 613: ucell size = POP(); ! 614: ucell virt = POP(); ! 615: ofmem_release(virt, size); ! 616: } ! 617: ! 618: DECLARE_NODE(memory, INSTALL_OPEN, 0, "/memory"); ! 619: ! 620: NODE_METHODS( memory ) = { ! 621: { "claim", mem_claim }, ! 622: { "release", mem_release }, ! 623: { "SUNW,retain", mem_retain }, ! 624: }; ! 625: ! 626: DECLARE_NODE(mmu, INSTALL_OPEN, 0, "/virtual-memory"); ! 627: ! 628: NODE_METHODS(mmu) = { ! 629: { "open", mmu_open }, ! 630: { "close", mmu_close }, ! 631: { "translate", mmu_translate }, ! 632: { "SUNW,dtlb-load", dtlb_load }, ! 633: { "SUNW,itlb-load", itlb_load }, ! 634: { "map", mmu_map }, ! 635: { "unmap", mmu_unmap }, ! 636: { "claim", mmu_claim }, ! 637: { "release", mmu_release }, ! 638: }; ! 639: ! 640: void ob_mmu_init(const char *cpuname, uint64_t ram_size) ! 641: { ! 642: /* memory node */ ! 643: REGISTER_NODE_METHODS(memory, "/memory"); ! 644: ! 645: /* MMU node */ ! 646: REGISTER_NODE_METHODS(mmu, "/virtual-memory"); ! 647: ! 648: ofmem_register(find_dev("/memory"), find_dev("/virtual-memory")); ! 649: ! 650: push_str("/chosen"); ! 651: fword("find-device"); ! 652: ! 653: push_str("/virtual-memory"); ! 654: fword("open-dev"); ! 655: fword("encode-int"); ! 656: push_str("mmu"); ! 657: fword("property"); ! 658: ! 659: push_str("/memory"); ! 660: fword("find-device"); ! 661: ! 662: /* All memory: 0 to RAM_size */ ! 663: PUSH(0); ! 664: fword("encode-int"); ! 665: PUSH(0); ! 666: fword("encode-int"); ! 667: fword("encode+"); ! 668: PUSH((int)(ram_size >> 32)); ! 669: fword("encode-int"); ! 670: fword("encode+"); ! 671: PUSH((int)(ram_size & 0xffffffff)); ! 672: fword("encode-int"); ! 673: fword("encode+"); ! 674: push_str("reg"); ! 675: fword("property"); ! 676: ! 677: push_str("/openprom/client-services"); ! 678: fword("find-device"); ! 679: bind_func("cif-claim", ciface_claim); ! 680: bind_func("cif-release", ciface_release); ! 681: ! 682: /* Other MMU functions */ ! 683: PUSH(0); ! 684: fword("active-package!"); ! 685: bind_func("pgmap@", pgmap_fetch); ! 686: ! 687: /* Find address of va2ttedata defer word contents for MMU miss handlers */ ! 688: va2ttedata = (ucell *)findword("va>tte-data"); ! 689: va2ttedata++; ! 690: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.