Annotation of qemu/roms/openbios/arch/sparc32/lib.c, revision 1.1.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.