Annotation of qemu/roms/openbios/arch/sparc64/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 "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: }

unix.superglobalmegacorp.com

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