|
|
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 "libc/vsprintf.h" ! 11: #include "libopenbios/bindings.h" ! 12: #include "libopenbios/ofmem.h" ! 13: #include "asm/asi.h" ! 14: #include "pgtsrmmu.h" ! 15: #include "openprom.h" ! 16: #include "libopenbios/sys_info.h" ! 17: #include "boot.h" ! 18: #include "romvec.h" ! 19: ! 20: #define NCTX_SWIFT 0x100 ! 21: #define LOWMEMSZ 32 * 1024 * 1024 ! 22: ! 23: #ifdef CONFIG_DEBUG_MEM ! 24: #define DPRINTF(fmt, args...) \ ! 25: do { printk(fmt , ##args); } while (0) ! 26: #else ! 27: #define DPRINTF(fmt, args...) ! 28: #endif ! 29: ! 30: /* Format a string and print it on the screen, just like the libc ! 31: * function printf. ! 32: */ ! 33: int printk( const char *fmt, ... ) ! 34: { ! 35: char *p, buf[512]; ! 36: va_list args; ! 37: int i; ! 38: ! 39: va_start(args, fmt); ! 40: i = vsnprintf(buf, sizeof(buf), fmt, args); ! 41: va_end(args); ! 42: ! 43: for( p=buf; *p; p++ ) ! 44: putchar(*p); ! 45: return i; ! 46: } ! 47: ! 48: /* ! 49: * Allocatable memory chunk. ! 50: */ ! 51: struct mem { ! 52: char *start, *uplim; ! 53: char *curp; ! 54: }; ! 55: ! 56: struct mem cdvmem; /* Current device virtual memory space */ ! 57: ! 58: unsigned int va_shift; ! 59: static unsigned long *context_table; ! 60: static unsigned long *l1; ! 61: ! 62: static ucell *mem_reg = 0; ! 63: static ucell *mem_avail = 0; ! 64: static ucell *virt_avail = 0; ! 65: ! 66: static struct linux_mlist_v0 totphys[1]; ! 67: static struct linux_mlist_v0 totmap[1]; ! 68: static struct linux_mlist_v0 totavail[1]; ! 69: ! 70: struct linux_mlist_v0 *ptphys; ! 71: struct linux_mlist_v0 *ptmap; ! 72: struct linux_mlist_v0 *ptavail; ! 73: ! 74: /* Private functions for mapping between physical/virtual addresses */ ! 75: phys_addr_t ! 76: va2pa(unsigned long va) ! 77: { ! 78: if ((va >= (unsigned long)&_start) && ! 79: (va < (unsigned long)&_end)) ! 80: return va - va_shift; ! 81: else ! 82: return va; ! 83: } ! 84: ! 85: unsigned long ! 86: pa2va(phys_addr_t pa) ! 87: { ! 88: if ((pa + va_shift >= (unsigned long)&_start) && ! 89: (pa + va_shift < (unsigned long)&_end)) ! 90: return pa + va_shift; ! 91: else ! 92: return pa; ! 93: } ! 94: ! 95: void * ! 96: malloc(int size) ! 97: { ! 98: return ofmem_malloc(size); ! 99: } ! 100: ! 101: void * ! 102: realloc( void *ptr, size_t size ) ! 103: { ! 104: return ofmem_realloc(ptr, size); ! 105: } ! 106: ! 107: void ! 108: free(void *ptr) ! 109: { ! 110: ofmem_free(ptr); ! 111: } ! 112: ! 113: /* ! 114: * Allocate memory. This is reusable. ! 115: */ ! 116: void ! 117: mem_init(struct mem *t, char *begin, char *limit) ! 118: { ! 119: t->start = begin; ! 120: t->uplim = limit; ! 121: t->curp = begin; ! 122: } ! 123: ! 124: void * ! 125: mem_alloc(struct mem *t, int size, int align) ! 126: { ! 127: char *p; ! 128: unsigned long pa; ! 129: ! 130: // The alignment restrictions refer to physical, not virtual ! 131: // addresses ! 132: pa = va2pa((unsigned long)t->curp) + (align - 1); ! 133: pa &= ~(align - 1); ! 134: p = (char *)pa2va(pa); ! 135: ! 136: if ((unsigned long)p >= (unsigned long)t->uplim || ! 137: (unsigned long)p + size > (unsigned long)t->uplim) ! 138: return NULL; ! 139: t->curp = p + size; ! 140: ! 141: return p; ! 142: } ! 143: ! 144: static unsigned long ! 145: find_pte(unsigned long va, int alloc) ! 146: { ! 147: uint32_t pte; ! 148: void *p; ! 149: unsigned long pa; ! 150: int ret; ! 151: ! 152: pte = l1[(va >> SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD - 1)]; ! 153: if ((pte & SRMMU_ET_MASK) == SRMMU_ET_INVALID) { ! 154: if (alloc) { ! 155: ret = ofmem_posix_memalign(&p, SRMMU_PTRS_PER_PMD * sizeof(int), ! 156: SRMMU_PTRS_PER_PMD * sizeof(int)); ! 157: if (ret != 0) ! 158: return ret; ! 159: pte = SRMMU_ET_PTD | ((va2pa((unsigned long)p)) >> 4); ! 160: l1[(va >> SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD - 1)] = pte; ! 161: /* barrier() */ ! 162: } else { ! 163: return -1; ! 164: } ! 165: } ! 166: ! 167: pa = (pte & 0xFFFFFFF0) << 4; ! 168: pa += ((va >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1)) << 2; ! 169: pte = *(uint32_t *)pa2va(pa); ! 170: if ((pte & SRMMU_ET_MASK) == SRMMU_ET_INVALID) { ! 171: if (alloc) { ! 172: ret = ofmem_posix_memalign(&p, SRMMU_PTRS_PER_PTE * sizeof(void *), ! 173: SRMMU_PTRS_PER_PTE * sizeof(void *)); ! 174: if (ret != 0) ! 175: return ret; ! 176: pte = SRMMU_ET_PTD | ((va2pa((unsigned int)p)) >> 4); ! 177: *(uint32_t *)pa2va(pa) = pte; ! 178: } else { ! 179: return -2; ! 180: } ! 181: } ! 182: ! 183: pa = (pte & 0xFFFFFFF0) << 4; ! 184: pa += ((va >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1)) << 2; ! 185: ! 186: return pa2va(pa); ! 187: } ! 188: ! 189: static void ! 190: map_pages(phys_addr_t phys, unsigned long virt, ! 191: unsigned long size, unsigned long mode) ! 192: { ! 193: unsigned long npages, off; ! 194: uint32_t pte; ! 195: unsigned long pa; ! 196: ! 197: DPRINTF("map_pages: va 0x%lx, pa 0x%llx, size 0x%lx\n", virt, phys, size); ! 198: ! 199: off = phys & (PAGE_SIZE - 1); ! 200: npages = (off + (size - 1) + (PAGE_SIZE - 1)) / PAGE_SIZE; ! 201: phys &= ~(uint64_t)(PAGE_SIZE - 1); ! 202: ! 203: while (npages-- != 0) { ! 204: pa = find_pte(virt, 1); ! 205: ! 206: pte = SRMMU_ET_PTE | ((phys & PAGE_MASK) >> 4); ! 207: pte |= mode; ! 208: ! 209: *(uint32_t *)pa = pte; ! 210: ! 211: virt += PAGE_SIZE; ! 212: phys += PAGE_SIZE; ! 213: } ! 214: } ! 215: ! 216: /* ! 217: * D5.3 pgmap@ ( va -- pte ) ! 218: */ ! 219: static void ! 220: pgmap_fetch(void) ! 221: { ! 222: uint32_t pte; ! 223: unsigned long va, pa; ! 224: ! 225: va = POP(); ! 226: ! 227: pa = find_pte(va, 0); ! 228: if (pa == 1 || pa == 2) ! 229: goto error; ! 230: pte = *(uint32_t *)pa; ! 231: DPRINTF("pgmap@: va 0x%lx pa 0x%lx pte 0x%x\n", va, pa, pte); ! 232: ! 233: PUSH(pte); ! 234: return; ! 235: error: ! 236: PUSH(0); ! 237: } ! 238: ! 239: /* ! 240: * D5.3 pgmap! ( pte va -- ) ! 241: */ ! 242: static void ! 243: pgmap_store(void) ! 244: { ! 245: uint32_t pte; ! 246: unsigned long va, pa; ! 247: ! 248: va = POP(); ! 249: pte = POP(); ! 250: ! 251: pa = find_pte(va, 1); ! 252: *(uint32_t *)pa = pte; ! 253: DPRINTF("pgmap!: va 0x%lx pa 0x%lx pte 0x%x\n", va, pa, pte); ! 254: } ! 255: ! 256: /* ! 257: * D5.3 map-pages ( pa space va size -- ) ! 258: */ ! 259: static void ! 260: ob_map_pages(void) ! 261: { ! 262: unsigned long va; ! 263: int size; ! 264: uint64_t pa; ! 265: ! 266: size = POP(); ! 267: va = POP(); ! 268: pa = POP(); ! 269: pa <<= 32; ! 270: pa |= POP() & 0xffffffff; ! 271: ! 272: map_pages(pa, va, size, ofmem_arch_default_translation_mode(pa)); ! 273: DPRINTF("map-page: va 0x%lx pa 0x%llx size 0x%x\n", va, pa, size); ! 274: } ! 275: ! 276: static void ! 277: update_memory_properties(void) ! 278: { ! 279: /* Update the device tree memory properties from the master ! 280: totphys, totmap and totavail romvec arrays */ ! 281: mem_reg[0] = 0; ! 282: mem_reg[1] = pointer2cell(totphys[0].start_adr); ! 283: mem_reg[2] = totphys[0].num_bytes; ! 284: ! 285: virt_avail[0] = 0; ! 286: virt_avail[1] = 0; ! 287: virt_avail[2] = pointer2cell(totmap[0].start_adr); ! 288: ! 289: mem_avail[0] = 0; ! 290: mem_avail[1] = pointer2cell(totavail[0].start_adr); ! 291: mem_avail[2] = totavail[0].num_bytes; ! 292: } ! 293: ! 294: static void ! 295: init_romvec_mem(void) ! 296: { ! 297: ptphys = totphys; ! 298: ptmap = totmap; ! 299: ptavail = totavail; ! 300: ! 301: /* ! 302: * Form memory descriptors. ! 303: */ ! 304: totphys[0].theres_more = NULL; ! 305: totphys[0].start_adr = (char *) 0; ! 306: totphys[0].num_bytes = qemu_mem_size; ! 307: ! 308: totavail[0].theres_more = NULL; ! 309: totavail[0].start_adr = (char *) 0; ! 310: totavail[0].num_bytes = va2pa((int)&_start) - PAGE_SIZE; ! 311: ! 312: totmap[0].theres_more = NULL; ! 313: totmap[0].start_adr = &_start; ! 314: totmap[0].num_bytes = (unsigned long) &_iomem - ! 315: (unsigned long) &_start + PAGE_SIZE; ! 316: ! 317: /* Pointers to device tree memory properties */ ! 318: mem_reg = malloc(sizeof(ucell) * 3); ! 319: mem_avail = malloc(sizeof(ucell) * 3); ! 320: virt_avail = malloc(sizeof(ucell) * 3); ! 321: ! 322: update_memory_properties(); ! 323: } ! 324: ! 325: char *obp_dumb_mmap(char *va, int which_io, unsigned int pa, ! 326: unsigned int size) ! 327: { ! 328: uint64_t mpa = ((uint64_t)which_io << 32) | (uint64_t)pa; ! 329: ! 330: map_pages(mpa, (unsigned long)va, size, ofmem_arch_default_translation_mode(mpa)); ! 331: return va; ! 332: } ! 333: ! 334: void obp_dumb_munmap(__attribute__((unused)) char *va, ! 335: __attribute__((unused)) unsigned int size) ! 336: { ! 337: DPRINTF("obp_dumb_munmap: virta 0x%x, sz %d\n", (unsigned int)va, size); ! 338: } ! 339: ! 340: void ofmem_arch_unmap_pages(ucell virt, ucell size) ! 341: { ! 342: /* Currently do nothing */ ! 343: } ! 344: ! 345: void ofmem_arch_early_map_pages(phys_addr_t phys, ucell virt, ucell size, ucell mode) ! 346: { ! 347: map_pages(phys, virt, size, mode); ! 348: } ! 349: ! 350: char *obp_memalloc(char *va, unsigned int size, unsigned int align) ! 351: { ! 352: phys_addr_t phys; ! 353: ucell virt; ! 354: ! 355: /* Claim physical memory */ ! 356: phys = ofmem_claim_phys(-1, size, align); ! 357: ! 358: /* Claim virtual memory */ ! 359: virt = ofmem_claim_virt(pointer2cell(va), size, 0); ! 360: ! 361: /* Map the memory */ ! 362: ofmem_map(phys, virt, size, ofmem_arch_default_translation_mode(phys)); ! 363: ! 364: return cell2pointer(virt); ! 365: } ! 366: ! 367: char *obp_dumb_memalloc(char *va, unsigned int size) ! 368: { ! 369: unsigned long align; ! 370: int i; ! 371: ! 372: /* Solaris seems to assume that the returned value is physically aligned to size. For ! 373: example, not having this here causes the Solaris 8 kernel to fault because the ! 374: IOMMU page table base address is calculated incorrectly. */ ! 375: ! 376: /* Enforce a minimum alignment of CONFIG_OFMEM_MALLOC_ALIGN, and choose an alignment ! 377: which is the next power of 2 higher than the specified size */ ! 378: align = size; ! 379: if (align <= CONFIG_OFMEM_MALLOC_ALIGN) { ! 380: align = CONFIG_OFMEM_MALLOC_ALIGN; ! 381: } else { ! 382: align--; ! 383: for (i = 1; i < sizeof(unsigned long) * 8; i<<=1) { ! 384: align |= align >> i; ! 385: } ! 386: align++; ! 387: } ! 388: ! 389: return obp_memalloc(va, size, align); ! 390: } ! 391: ! 392: void obp_dumb_memfree(__attribute__((unused))char *va, ! 393: __attribute__((unused))unsigned sz) ! 394: { ! 395: DPRINTF("obp_dumb_memfree 0x%p (size %d)\n", va, sz); ! 396: } ! 397: ! 398: void ! 399: ob_init_mmu(void) ! 400: { ! 401: ucell *memreg; ! 402: ucell *virtreg; ! 403: phys_addr_t virtregsize; ! 404: ofmem_t *ofmem = ofmem_arch_get_private(); ! 405: ! 406: init_romvec_mem(); ! 407: ! 408: /* Find the phandles for the /memory and /virtual-memory nodes */ ! 409: push_str("/memory"); ! 410: fword("find-package"); ! 411: POP(); ! 412: s_phandle_memory = POP(); ! 413: ! 414: push_str("/virtual-memory"); ! 415: fword("find-package"); ! 416: POP(); ! 417: s_phandle_mmu = POP(); ! 418: ! 419: ofmem_register(s_phandle_memory, s_phandle_mmu); ! 420: ! 421: /* Setup /memory:reg (totphys) property */ ! 422: memreg = malloc(3 * sizeof(ucell)); ! 423: ofmem_arch_encode_physaddr(memreg, 0); /* physical base */ ! 424: memreg[2] = (ucell)ofmem->ramsize; /* size */ ! 425: ! 426: push_str("/memory"); ! 427: fword("find-device"); ! 428: PUSH(pointer2cell(memreg)); ! 429: PUSH(3 * sizeof(ucell)); ! 430: push_str("reg"); ! 431: PUSH_ph(s_phandle_memory); ! 432: fword("encode-property"); ! 433: ! 434: /* Setup /virtual-memory:reg property */ ! 435: virtregsize = ((phys_addr_t)((ucell)-1) + 1) / 2; ! 436: ! 437: virtreg = malloc(6 * sizeof(ucell)); ! 438: ofmem_arch_encode_physaddr(virtreg, 0); ! 439: virtreg[2] = virtregsize; ! 440: ofmem_arch_encode_physaddr(&virtreg[3], virtregsize); ! 441: virtreg[5] = virtregsize; ! 442: ! 443: push_str("/virtual-memory"); ! 444: fword("find-device"); ! 445: PUSH(pointer2cell(virtreg)); ! 446: PUSH(6 * sizeof(ucell)); ! 447: push_str("reg"); ! 448: PUSH_ph(s_phandle_mmu); ! 449: fword("encode-property"); ! 450: ! 451: PUSH(0); ! 452: fword("active-package!"); ! 453: bind_func("pgmap@", pgmap_fetch); ! 454: bind_func("pgmap!", pgmap_store); ! 455: bind_func("map-pages", ob_map_pages); ! 456: } ! 457: ! 458: /* ! 459: * Switch page tables. ! 460: */ ! 461: void ! 462: init_mmu_swift(void) ! 463: { ! 464: unsigned int addr, i; ! 465: unsigned long pa, va; ! 466: int size; ! 467: ! 468: ofmem_posix_memalign((void *)&context_table, NCTX_SWIFT * sizeof(int), ! 469: NCTX_SWIFT * sizeof(int)); ! 470: ofmem_posix_memalign((void *)&l1, 256 * sizeof(int), 256 * sizeof(int)); ! 471: ! 472: context_table[0] = (((unsigned long)va2pa((unsigned long)l1)) >> 4) | ! 473: SRMMU_ET_PTD; ! 474: ! 475: for (i = 1; i < NCTX_SWIFT; i++) { ! 476: context_table[i] = SRMMU_ET_INVALID; ! 477: } ! 478: for (i = 0; i < 256; i += 4) { ! 479: l1[i] = SRMMU_ET_INVALID; ! 480: } ! 481: ! 482: // text, rodata, data, and bss mapped to end of RAM ! 483: va = (unsigned long)&_start; ! 484: size = (unsigned long)&_end - (unsigned long)&_start; ! 485: pa = va2pa(va); ! 486: map_pages(pa, va, size, ofmem_arch_default_translation_mode(pa)); ! 487: ! 488: // 1:1 mapping for RAM ! 489: map_pages(0, 0, LOWMEMSZ, ofmem_arch_default_translation_mode(0)); ! 490: ! 491: /* ! 492: * Flush cache ! 493: */ ! 494: for (addr = 0; addr < 0x2000; addr += 0x10) { ! 495: __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : : ! 496: "r" (addr), "i" (ASI_M_DATAC_TAG)); ! 497: __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : : ! 498: "r" (addr<<1), "i" (ASI_M_TXTC_TAG)); ! 499: } ! 500: srmmu_set_context(0); ! 501: srmmu_set_ctable_ptr(va2pa((unsigned long)context_table)); ! 502: srmmu_flush_whole_tlb(); ! 503: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.