Annotation of qemu/roms/openbios/arch/sparc32/lib.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.