Annotation of qemu/roms/openbios/libopenbios/ofmem_common.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  *     <ofmem_common.c>
                      3:  *
                      4:  *     OF Memory manager
                      5:  *
                      6:  *   Copyright (C) 1999-2004 Samuel Rydh ([email protected])
                      7:  *   Copyright (C) 2004 Stefan Reinauer
                      8:  *
                      9:  *   This program is free software; you can redistribute it and/or
                     10:  *   modify it under the terms of the GNU General Public License
                     11:  *   as published by the Free Software Foundation
                     12:  *
                     13:  */
                     14: 
                     15: #include "config.h"
                     16: #include "libopenbios/bindings.h"
                     17: #include "libopenbios/ofmem.h"
                     18: 
                     19: /* Default size of memory allocated for each of the MMU properties (in bytes) */
                     20: #define OFMEM_DEFAULT_PROP_SIZE 2048
                     21: 
                     22: /*
                     23:  * define OFMEM_FILL_RANGE to claim any unclaimed virtual and
                     24:  * physical memory in the range for ofmem_map
                     25:  *
                     26:  * TODO: remove this macro and wrapped code if not needed by implementations
                     27:  */
                     28: //#define OFMEM_FILL_RANGE
                     29: 
                     30: 
                     31: static inline size_t align_size(size_t x, size_t a)
                     32: {
                     33:     return (x + a - 1) & ~(a - 1);
                     34: }
                     35: 
                     36: static inline phys_addr_t align_ptr(uintptr_t x, size_t a)
                     37: {
                     38:     return (x + a - 1) & ~(a - 1);
                     39: }
                     40: 
                     41: static ucell get_ram_size( void )
                     42: {
                     43:        ofmem_t *ofmem = ofmem_arch_get_private();
                     44:        return ofmem->ramsize;
                     45: }
                     46: 
                     47: /************************************************************************/
                     48: /* debug                                                                */
                     49: /************************************************************************/
                     50: 
                     51: #if 0
                     52: static void
                     53: print_range( range_t *r, char *str )
                     54: {
                     55:        printk("--- Range %s ---\n", str );
                     56:        for( ; r; r=r->next )
                     57:                printk(FMT_plx " - " FMT_plx "\n", r->start, r->start + r->size - 1);
                     58:        printk("\n");
                     59: }
                     60: 
                     61: static void
                     62: print_phys_range()
                     63: {
                     64:        print_range( ofmem.phys_range, "phys" );
                     65: }
                     66: 
                     67: static void
                     68: print_virt_range()
                     69: {
                     70:        print_range( ofmem.virt_range, "virt" );
                     71: }
                     72: 
                     73: static void
                     74: print_trans( void )
                     75: {
                     76:        translation_t *t = ofmem.trans;
                     77: 
                     78:        printk("--- Translations ---\n");
                     79:        for( ; t; t=t->next )
                     80:                printk("%08lx -> " FMT_plx " [size %lx]\n", t->virt, t->phys, t->size);
                     81:        printk("\n");
                     82: }
                     83: #endif
                     84: 
                     85: /************************************************************************/
                     86: /* OF private allocations                                               */
                     87: /************************************************************************/
                     88: 
                     89: int ofmem_posix_memalign( void **memptr, size_t alignment, size_t size )
                     90: {
                     91:        ofmem_t *ofmem = ofmem_arch_get_private();
                     92:        alloc_desc_t *d, **pp;
                     93:        void *ret;
                     94:        ucell top;
                     95:        phys_addr_t pa;
                     96: 
                     97:        if( !size )
                     98:                return ENOMEM;
                     99: 
                    100:        if( !ofmem->next_malloc )
                    101:                ofmem->next_malloc = (char*)ofmem_arch_get_malloc_base();
                    102: 
                    103:        size = align_size(size + sizeof(alloc_desc_t), alignment);
                    104: 
                    105:        /* look in the freelist */
                    106:        for( pp=&ofmem->mfree; *pp && (**pp).size < size; pp = &(**pp).next ) {
                    107:        }
                    108: 
                    109:        /* waste at most 4K by taking an entry from the freelist */
                    110:        if( *pp && (**pp).size < size + 0x1000 ) {
                    111:                /* Alignment should be on physical not virtual address */
                    112:                pa = va2pa((uintptr_t)*pp + sizeof(alloc_desc_t));
                    113:                pa = align_ptr(pa, alignment);
                    114:                ret = (void *)pa2va(pa);
                    115: 
                    116:                memset( ret, 0, (**pp).size - sizeof(alloc_desc_t) );
                    117:                *pp = (**pp).next;
                    118: 
                    119:                *memptr = ret;
                    120:                return 0;
                    121:        }
                    122: 
                    123:        top = ofmem_arch_get_heap_top();
                    124: 
                    125:        /* Alignment should be on physical not virtual address */
                    126:        pa = va2pa((uintptr_t)ofmem->next_malloc + sizeof(alloc_desc_t));
                    127:        pa = align_ptr(pa, alignment);
                    128:        ret = (void *)pa2va(pa);
                    129: 
                    130:        if( pointer2cell(ret) + size > top ) {
                    131:                printk("out of malloc memory (%x)!\n", size );
                    132:                return ENOMEM;
                    133:        }
                    134: 
                    135:        d = (alloc_desc_t*)((uintptr_t)ret - sizeof(alloc_desc_t));
                    136:        ofmem->next_malloc += size;
                    137: 
                    138:        d->next = NULL;
                    139:        d->size = size;
                    140: 
                    141:        memset( ret, 0, size - sizeof(alloc_desc_t) );
                    142: 
                    143:        *memptr = ret;
                    144:        return 0;
                    145: }
                    146: 
                    147: void* ofmem_malloc( size_t size )
                    148: {
                    149:        void *memptr;
                    150:        int res;
                    151:        
                    152:        res = ofmem_posix_memalign( &memptr, CONFIG_OFMEM_MALLOC_ALIGN, size );
                    153:        if (!res) {
                    154:                /* Success */
                    155:                return memptr;
                    156:        } else {
                    157:                /* Failure */
                    158:                return NULL;
                    159:        }
                    160: }
                    161: 
                    162: void ofmem_free( void *ptr )
                    163: {
                    164:        ofmem_t *ofmem = ofmem_arch_get_private();
                    165:        alloc_desc_t **pp, *d;
                    166: 
                    167:        /* it is legal to free NULL pointers (size zero allocations) */
                    168:        if( !ptr )
                    169:                return;
                    170: 
                    171:        d = (alloc_desc_t*)((char *)ptr - sizeof(alloc_desc_t));
                    172:        d->next = ofmem->mfree;
                    173: 
                    174:        /* insert in the (sorted) freelist */
                    175:        for( pp=&ofmem->mfree; *pp && (**pp).size < d->size ; pp = &(**pp).next ) {
                    176:        }
                    177: 
                    178:        d->next = *pp;
                    179:        *pp = d;
                    180: }
                    181: 
                    182: void* ofmem_realloc( void *ptr, size_t size )
                    183: {
                    184:        alloc_desc_t *d = (alloc_desc_t*)((char *)ptr - sizeof(alloc_desc_t));
                    185:        char *p;
                    186: 
                    187:        if( !ptr )
                    188:                return malloc( size );
                    189:        if( !size ) {
                    190:                free( ptr );
                    191:                return NULL;
                    192:        }
                    193:        p = malloc( size );
                    194:        memcpy( p, ptr, MIN(d->size - sizeof(alloc_desc_t),size) );
                    195:        free( ptr );
                    196:        return p;
                    197: }
                    198: 
                    199: 
                    200: /************************************************************************/
                    201: /* "translations" and "available" property tracking                     */
                    202: /************************************************************************/
                    203: 
                    204: static int trans_prop_size = 0, phys_range_prop_size = 0, virt_range_prop_size = 0;
                    205: static int trans_prop_used = 0, phys_range_prop_used = 0, virt_range_prop_used = 0;
                    206: static ucell *trans_prop, *phys_range_prop, *virt_range_prop;
                    207: 
                    208: static void
                    209: ofmem_set_property( phandle_t ph, const char *name, const char *buf, int len )
                    210: {
                    211:        /* This is very similar to set_property() in libopenbios/bindings.c but allows
                    212:           us to set the property pointer directly, rather than having to copy it
                    213:           into the Forth dictonary every time we update the memory properties */
                    214:        if( !ph ) {
                    215:                printk("ofmem_set_property: NULL phandle\n");
                    216:                return;
                    217:        }
                    218:        PUSH(pointer2cell(buf));
                    219:        PUSH(len);
                    220:        push_str(name);
                    221:        PUSH_ph(ph);
                    222:        fword("encode-property");
                    223: }
                    224: 
                    225: phandle_t s_phandle_memory = 0;
                    226: phandle_t s_phandle_mmu = 0;
                    227: 
                    228: static void ofmem_update_mmu_translations( void )
                    229: {
                    230:        ofmem_t *ofmem = ofmem_arch_get_private();
                    231:        translation_t *t;
                    232:        int ncells, prop_used, prop_size;
                    233: 
                    234:        if (s_phandle_mmu == 0)
                    235:                return;
                    236: 
                    237:        for( t = ofmem->trans, ncells = 0; t ; t=t->next, ncells++ ) {
                    238:        }
                    239: 
                    240:        /* Get the current number of bytes required for the MMU translation property */
                    241:        prop_used = ncells * sizeof(ucell) * ofmem_arch_get_translation_entry_size();
                    242: 
                    243:        if (prop_used > trans_prop_size) {
                    244: 
                    245:                /* The property doesn't fit within the existing space, so keep doubling it
                    246:                   until it does */
                    247:                prop_size = trans_prop_size;
                    248:                while (prop_size < prop_used) {
                    249:                        prop_size *= 2;
                    250:                } 
                    251: 
                    252:                /* Allocate the new memory and copy all of the existing information across */
                    253:                trans_prop = realloc(trans_prop, prop_size);
                    254:                trans_prop_size = prop_size;
                    255:                trans_prop_used = prop_used;
                    256:        }
                    257: 
                    258:        if (trans_prop == NULL) {
                    259:                /* out of memory! */
                    260:                printk("Unable to allocate memory for translations property!\n");
                    261:                return;
                    262:        }
                    263: 
                    264:        /* Call architecture-specific routines to generate translation entries */
                    265:        for( t = ofmem->trans, ncells = 0 ; t ; t=t->next ) {
                    266:                ofmem_arch_create_translation_entry(&trans_prop[ncells], t);
                    267:                ncells += ofmem_arch_get_translation_entry_size();
                    268:        }
                    269: 
                    270:        ofmem_set_property(s_phandle_mmu, "translations",
                    271:                        (char*)trans_prop, ncells * sizeof(trans_prop[0]));
                    272: 
                    273: }
                    274: 
                    275: 
                    276: static void ofmem_update_memory_available( phandle_t ph, range_t *range,
                    277:                ucell **mem_prop, int *mem_prop_size, int *mem_prop_used, u64 top_address )
                    278: {
                    279:        range_t *r;
                    280:        int ncells, prop_used, prop_size;
                    281:        phys_addr_t start;
                    282:        ucell size, *prop;
                    283: 
                    284:        if (s_phandle_memory == 0)
                    285:                return;
                    286: 
                    287:        /* count phys_range list entries */
                    288:        for( r = range, ncells = 0; r ; r=r->next, ncells++ ) {
                    289:        }
                    290: 
                    291:        /* inverse of phys_range list could take 2 or more additional cells for the tail
                    292:           For /memory, physical addresses may be wider than one ucell. */
                    293:        prop_used = (ncells + 1) * sizeof(ucell) * ofmem_arch_get_available_entry_size(ph) + 1;
                    294: 
                    295:        if (prop_used > *mem_prop_size) {
                    296: 
                    297:                /* The property doesn't fit within the existing space, so keep doubling it
                    298:                   until it does */
                    299:                prop_size = *mem_prop_size;
                    300:                while (prop_size < prop_used) {
                    301:                        prop_size *= 2;
                    302:                }
                    303: 
                    304:                /* Allocate the new memory and copy all of the existing information across */
                    305:                *mem_prop = realloc(*mem_prop, prop_size);
                    306:                *mem_prop_size = prop_size;
                    307:                *mem_prop_used = prop_used;
                    308:        }
                    309: 
                    310:        if (*mem_prop == NULL) {
                    311:                /* out of memory! */
                    312:                printk("Unable to allocate memory for memory range property!\n");
                    313:                return;
                    314:        }
                    315: 
                    316:        start = 0;
                    317:        ncells = 0;
                    318:        prop = *mem_prop;
                    319: 
                    320:        for (r = range; r; r=r->next) {
                    321:                if (r->start >= top_address) {
                    322:                        break;
                    323:                }
                    324: 
                    325:                size = r->start - start;
                    326:                if (size) {
                    327:                        ofmem_arch_create_available_entry(ph, &prop[ncells], start, size);
                    328:                        ncells += ofmem_arch_get_available_entry_size(ph);
                    329:                }
                    330:                start = r->start + r->size;
                    331:        }
                    332: 
                    333:        /* tail */
                    334:        if (start < top_address) {
                    335:                ofmem_arch_create_available_entry(ph, &prop[ncells], start, top_address - start);
                    336:                ncells += ofmem_arch_get_available_entry_size(ph);
                    337:        }
                    338: 
                    339:        ofmem_set_property(ph, "available",
                    340:                        (char*)prop, ncells * sizeof(prop[0]));
                    341: }
                    342: 
                    343: static void ofmem_update_translations( void )
                    344: {
                    345:        ofmem_t *ofmem = ofmem_arch_get_private();
                    346: 
                    347:        ofmem_update_memory_available(s_phandle_memory, ofmem->phys_range, 
                    348:                        &phys_range_prop, &phys_range_prop_size, &phys_range_prop_used, ofmem_arch_get_phys_top());
                    349:        ofmem_update_memory_available(s_phandle_mmu, ofmem->virt_range, 
                    350:                        &virt_range_prop, &virt_range_prop_size, &virt_range_prop_used, (ucell)-1);
                    351:        ofmem_update_mmu_translations();
                    352: }
                    353: 
                    354: 
                    355: /************************************************************************/
                    356: /* client interface                                                     */
                    357: /************************************************************************/
                    358: 
                    359: static int is_free( phys_addr_t ea, ucell size, range_t *r )
                    360: {
                    361:        if( size == 0 )
                    362:                return 1;
                    363:        for( ; r ; r=r->next ) {
                    364:                if( r->start + r->size - 1 >= ea && r->start <= ea )
                    365:                        return 0;
                    366:                if( r->start >= ea && r->start <= ea + size - 1 )
                    367:                        return 0;
                    368:        }
                    369:        return 1;
                    370: }
                    371: 
                    372: static void add_entry_( phys_addr_t ea, ucell size, range_t **r )
                    373: {
                    374:        range_t *nr;
                    375: 
                    376:        for( ; *r && (**r).start < ea; r=&(**r).next ) {
                    377:        }
                    378: 
                    379:        nr = (range_t*)malloc( sizeof(range_t) );
                    380:        nr->next = *r;
                    381:        nr->start = ea;
                    382:        nr->size = size;
                    383:        *r = nr;
                    384: }
                    385: 
                    386: static int add_entry( phys_addr_t ea, ucell size, range_t **r )
                    387: {
                    388:        if( !is_free( ea, size, *r ) ) {
                    389:                OFMEM_TRACE("add_entry: range not free!\n");
                    390:                return -1;
                    391:        }
                    392:        add_entry_( ea, size, r );
                    393:        return 0;
                    394: }
                    395: 
                    396: #if defined(OFMEM_FILL_RANGE)
                    397: static void join_ranges( range_t **rr )
                    398: {
                    399:        range_t *n, *r = *rr;
                    400:        while( r ) {
                    401:                if( !(n=r->next) )
                    402:                        break;
                    403: 
                    404:                if( r->start + r->size - 1 >= n->start -1 ) {
                    405:                        int s = n->size + (n->start - r->start - r->size);
                    406:                        if( s > 0 )
                    407:                                r->size += s;
                    408:                        r->next = n->next;
                    409:                        free( n );
                    410:                        continue;
                    411:                }
                    412:                r=r->next;
                    413:        }
                    414: }
                    415: 
                    416: static void fill_range( phys_addr_t ea, ucell size, range_t **rr )
                    417: {
                    418:        add_entry_( ea, size, rr );
                    419:        join_ranges( rr );
                    420: }
                    421: #endif
                    422: 
                    423: static ucell find_area( ucell align, ucell size, range_t *r,
                    424:                phys_addr_t min, phys_addr_t max, int reverse )
                    425: {
                    426:        phys_addr_t base = min;
                    427:        range_t *r2;
                    428: 
                    429:        if( (align & (align-1)) ) {
                    430:                OFMEM_TRACE("bad alignment " FMT_ucell "\n", align);
                    431:                align = 0x1000;
                    432:        }
                    433:        if( !align )
                    434:                align = 0x1000;
                    435: 
                    436:        base = reverse ? max - size : min;
                    437:        r2 = reverse ? NULL : r;
                    438: 
                    439:        for( ;; ) {
                    440:                if( !reverse ) {
                    441:                        base = (base + align - 1) & ~(align-1);
                    442:                        if( base < min )
                    443:                                base = min;
                    444:                        if( base + size - 1 >= max -1 )
                    445:                                break;
                    446:                } else {
                    447:                        if( base > max - size )
                    448:                                base = max - size;
                    449:                        base -= base & (align-1);
                    450:                }
                    451:                if( is_free( base, size, r ) )
                    452:                        return base;
                    453: 
                    454:                if( !reverse ) {
                    455:                        if( !r2 )
                    456:                                break;
                    457:                        base = r2->start + r2->size;
                    458:                        r2 = r2->next;
                    459:                } else {
                    460:                        range_t *rp;
                    461: 
                    462:                        for( rp=r; rp && rp->next != r2 ; rp=rp->next ) {
                    463:                        }
                    464: 
                    465:                        r2 = rp;
                    466:                        if( !r2 )
                    467:                                break;
                    468:                        base = r2->start - size;
                    469:                }
                    470:        }
                    471:        return -1;
                    472: }
                    473: 
                    474: static phys_addr_t ofmem_claim_phys_( phys_addr_t phys, ucell size, ucell align,
                    475:                phys_addr_t min, phys_addr_t max, int reverse )
                    476: {
                    477:        ofmem_t *ofmem = ofmem_arch_get_private();
                    478:        if( !align ) {
                    479:                if( !is_free( phys, size, ofmem->phys_range ) ) {
                    480:                        OFMEM_TRACE("Non-free physical memory claimed!\n");
                    481:                        return -1;
                    482:                }
                    483:                add_entry( phys, size, &ofmem->phys_range );
                    484:                ofmem_update_translations();
                    485:                return phys;
                    486:        }
                    487:        phys = find_area( align, size, ofmem->phys_range, min, max, reverse );
                    488:        if( phys == -1 ) {
                    489:                printk("ofmem_claim_phys - out of space (failed request for " FMT_ucellx " bytes)\n", size);
                    490:                return -1;
                    491:        }
                    492:        add_entry( phys, size, &ofmem->phys_range );
                    493: 
                    494:        ofmem_update_translations();
                    495: 
                    496:        return phys;
                    497: }
                    498: 
                    499: /* if align != 0, phys is ignored. Returns -1 on error */
                    500: phys_addr_t ofmem_claim_phys( phys_addr_t phys, ucell size, ucell align )
                    501: {
                    502:     OFMEM_TRACE("ofmem_claim phys=" FMT_plx " size=" FMT_ucellx
                    503:                 " align=" FMT_ucellx "\n",
                    504:                 phys, size, align);
                    505: 
                    506:        return ofmem_claim_phys_( phys, size, align, 0, ofmem_arch_get_phys_top(), 1 );
                    507: }
                    508: 
                    509: static ucell ofmem_claim_virt_( ucell virt, ucell size, ucell align,
                    510:                ucell min, ucell max, int reverse )
                    511: {
                    512:        ofmem_t *ofmem = ofmem_arch_get_private();
                    513:        if( !align ) {
                    514:                if( !is_free( virt, size, ofmem->virt_range ) ) {
                    515:                        OFMEM_TRACE("Non-free virtual memory claimed!\n");
                    516:                        return -1;
                    517:                }
                    518:                add_entry( virt, size, &ofmem->virt_range );
                    519:                ofmem_update_translations();
                    520:                return virt;
                    521:        }
                    522: 
                    523:        virt = find_area( align, size, ofmem->virt_range, min, max, reverse );
                    524:        if( virt == -1 ) {
                    525:                printk("ofmem_claim_virt - out of space (failed request for " FMT_ucellx " bytes)\n", size);
                    526:                return -1;
                    527:        }
                    528:        add_entry( virt, size, &ofmem->virt_range );
                    529:        
                    530:        ofmem_update_translations();
                    531:        
                    532:        return virt;
                    533: }
                    534: 
                    535: ucell ofmem_claim_virt( ucell virt, ucell size, ucell align )
                    536: {
                    537:     OFMEM_TRACE("ofmem_claim_virt virt=" FMT_ucellx " size=" FMT_ucellx
                    538:                 " align=" FMT_ucellx "\n",
                    539:                 virt, size, align);
                    540: 
                    541:        /* printk("+ ofmem_claim virt %08lx %lx %ld\n", virt, size, align ); */
                    542:        return ofmem_claim_virt_( virt, size, align,
                    543:                        get_ram_size(), ofmem_arch_get_virt_top(), 1 );
                    544: }
                    545: 
                    546: static ucell ofmem_claim_io_( ucell virt, ucell size, ucell align,
                    547:                ucell min, ucell max, int reverse )
                    548: {
                    549:        ofmem_t *ofmem = ofmem_arch_get_private();
                    550:        if( !align ) {
                    551:                if( !is_free( virt, size, ofmem->io_range ) ) {
                    552:                        OFMEM_TRACE("Non-free I/O memory claimed!\n");
                    553:                        return -1;
                    554:                }
                    555:                add_entry( virt, size, &ofmem->io_range );
                    556:                return virt;
                    557:        }
                    558: 
                    559:        virt = find_area( align, size, ofmem->io_range, min, max, reverse );
                    560:        if( virt == -1 ) {
                    561:                printk("ofmem_claim_io - out of space (failed request for " FMT_ucellx " bytes)\n", size);
                    562:                return -1;
                    563:        }
                    564:        add_entry( virt, size, &ofmem->io_range );
                    565:        return virt;
                    566: }
                    567: 
                    568: ucell ofmem_claim_io( ucell virt, ucell size, ucell align )
                    569: {
                    570:        /* Claim a section of memory from the I/O range */
                    571:        return ofmem_claim_io_( virt, size, align,
                    572:                        ofmem_arch_get_iomem_base(), ofmem_arch_get_iomem_top(), 0 );
                    573: }
                    574: 
                    575: /* if align != 0, phys is ignored. Returns -1 on error */
                    576: phys_addr_t ofmem_retain( phys_addr_t phys, ucell size, ucell align )
                    577: {
                    578:     retain_t *retained = ofmem_arch_get_retained();
                    579:     phys_addr_t retain_phys;
                    580: 
                    581:     OFMEM_TRACE("ofmem_retain phys=" FMT_plx " size=" FMT_ucellx
                    582:                 " align=" FMT_ucellx "\n",
                    583:                 phys, size, align);
                    584: 
                    585:        retain_phys = ofmem_claim_phys_( phys, size, align, 0, get_ram_size(), 0 );
                    586: 
                    587:        /* Add to the retain_phys_range list */
                    588:        retained->retain_phys_range[retained->numentries].next = NULL;
                    589:        retained->retain_phys_range[retained->numentries].start = retain_phys;
                    590:        retained->retain_phys_range[retained->numentries].size = size;
                    591:        retained->numentries++;
                    592: 
                    593:        return retain_phys;
                    594: }
                    595: 
                    596: /* allocate both physical and virtual space and add a translation */
                    597: ucell ofmem_claim( ucell addr, ucell size, ucell align )
                    598: {
                    599:        ofmem_t *ofmem = ofmem_arch_get_private();
                    600:        ucell virt;
                    601:        phys_addr_t phys;
                    602:        ucell offs = addr & 0xfff;
                    603: 
                    604:        OFMEM_TRACE("ofmem_claim " FMT_ucellx " " FMT_ucellx " " FMT_ucellx "\n", addr, size, align );
                    605:        virt = phys = 0;
                    606:        if( !align ) {
                    607:                if( is_free(addr, size, ofmem->virt_range) &&
                    608:                    is_free(addr, size, ofmem->phys_range) ) {
                    609:                        ofmem_claim_phys_( addr, size, 0, 0, 0, 0 );
                    610:                        ofmem_claim_virt_( addr, size, 0, 0, 0, 0 );
                    611:                        virt = phys = addr;
                    612:                } else {
                    613:                        OFMEM_TRACE("**** ofmem_claim failure ***!\n");
                    614:                        return -1;
                    615:                }
                    616:        } else {
                    617:                if( align < 0x1000 )
                    618:                        align = 0x1000;
                    619:                phys = ofmem_claim_phys_( addr, size, align, 0, ofmem_arch_get_phys_top(), 1 /* reverse */ );
                    620:                virt = ofmem_claim_virt_( addr, size, align, 0, get_ram_size(), 1 /* reverse */ );
                    621:                if( phys == -1 || virt == -1 ) {
                    622:                        OFMEM_TRACE("ofmem_claim failed\n");
                    623:                        return -1;
                    624:                }
                    625:                /* printk("...phys = %08lX, virt = %08lX, size = %08lX\n", phys, virt, size ); */
                    626:        }
                    627: 
                    628:        /* align */
                    629:        if( phys & 0xfff ) {
                    630:                size += (phys & 0xfff);
                    631:                virt -= (phys & 0xfff);
                    632:                phys &= ~0xfff;
                    633:        }
                    634:        if( size & 0xfff )
                    635:                size = (size + 0xfff) & ~0xfff;
                    636: 
                    637:        /* printk("...free memory found... phys: %08lX, virt: %08lX, size %lX\n", phys, virt, size ); */
                    638:        ofmem_map( phys, virt, size, -1 );
                    639:        return virt + offs;
                    640: }
                    641: 
                    642: 
                    643: /************************************************************************/
                    644: /* keep track of ea -> phys translations                                */
                    645: /************************************************************************/
                    646: 
                    647: static void split_trans( ucell virt )
                    648: {
                    649:        ofmem_t *ofmem = ofmem_arch_get_private();
                    650:        translation_t *t, *t2;
                    651: 
                    652:        for( t=ofmem->trans; t; t=t->next ) {
                    653:                if( virt > t->virt && virt < t->virt + t->size-1 ) {
                    654:                        t2 = (translation_t*)malloc( sizeof(translation_t) );
                    655:                        t2->virt = virt;
                    656:                        t2->size = t->size - (virt - t->virt);
                    657:                        t->size = virt - t->virt;
                    658:                        t2->phys = t->phys + t->size;
                    659:                        t2->mode = t->mode;
                    660:                        t2->next = t->next;
                    661:                        t->next = t2;
                    662:                }
                    663:        }
                    664: }
                    665: 
                    666: int ofmem_map_page_range( phys_addr_t phys, ucell virt, ucell size, ucell mode )
                    667: {
                    668:        ofmem_t *ofmem = ofmem_arch_get_private();
                    669:        translation_t *t, **tt;
                    670: 
                    671:        OFMEM_TRACE("ofmem_map_page_range " FMT_ucellx
                    672:                        " -> " FMT_plx " " FMT_ucellx " mode " FMT_ucellx "\n",
                    673:                        virt, phys, size, mode );
                    674: 
                    675:        split_trans( virt );
                    676:        split_trans( virt + size );
                    677: 
                    678:        /* detect remappings */
                    679:        for( t=ofmem->trans; t; ) {
                    680:                if( virt == t->virt || (virt < t->virt && virt + size > t->virt )) {
                    681:                        if( t->phys + virt - t->virt != phys ) {
                    682:                                OFMEM_TRACE("mapping altered virt=" FMT_ucellx ")\n", t->virt );
                    683:                        } else if( t->mode != mode ){
                    684:                                OFMEM_TRACE("mapping mode altered virt=" FMT_ucellx
                    685:                                                " old mode=" FMT_ucellx " new mode=" FMT_ucellx "\n",
                    686:                                                t->virt, t->mode, mode);
                    687:                        }
                    688: 
                    689:                        for( tt=&ofmem->trans; *tt != t ; tt=&(**tt).next ) {
                    690:                        }
                    691: 
                    692:                        *tt = t->next;
                    693: 
                    694:                        /* really unmap these pages */
                    695:                        ofmem_arch_unmap_pages(t->virt, t->size);
                    696: 
                    697:                        free((char*)t);
                    698: 
                    699:                        t=ofmem->trans;
                    700:                        continue;
                    701:                }
                    702:                t=t->next;
                    703:        }
                    704: 
                    705:        /* add mapping */
                    706:        for( tt=&ofmem->trans; *tt && (**tt).virt < virt ; tt=&(**tt).next ) {
                    707:        }
                    708: 
                    709:        t = (translation_t*)malloc( sizeof(translation_t) );
                    710:        t->virt = virt;
                    711:        t->phys = phys;
                    712:        t->size = size;
                    713:        t->mode = mode;
                    714:        t->next = *tt;
                    715:        *tt = t;
                    716: 
                    717:        ofmem_update_translations();
                    718: 
                    719:        return 0;
                    720: }
                    721: 
                    722: static int unmap_page_range( ucell virt, ucell size )
                    723: {
                    724:        ofmem_t *ofmem = ofmem_arch_get_private();
                    725:        translation_t **plink;
                    726: 
                    727:        /* make sure there is exactly one matching translation entry */
                    728: 
                    729:        split_trans( virt );
                    730:        split_trans( virt + size );
                    731: 
                    732:        /* find and unlink entries in range */
                    733:        plink = &ofmem->trans;
                    734: 
                    735:        while (*plink && (*plink)->virt < virt+size) {
                    736:                translation_t **plinkentry = plink;
                    737:                translation_t *t = *plink;
                    738: 
                    739:                /* move ahead */
                    740:                plink = &t->next;
                    741: 
                    742:                if (t->virt >= virt && t->virt + t->size <= virt+size) {
                    743: 
                    744:                        /* unlink entry */
                    745:                        *plinkentry = t->next;
                    746: 
                    747:                        OFMEM_TRACE("unmap_page_range found "
                    748:                                        FMT_ucellx " -> " FMT_plx " " FMT_ucellx
                    749:                                        " mode " FMT_ucellx "\n",
                    750:                                        t->virt, t->phys, t->size, t->mode );
                    751: 
                    752:                        // really map these pages
                    753:                        ofmem_arch_unmap_pages(t->virt, t->size);
                    754: 
                    755:                        free((char*)t);
                    756:                }
                    757:        }
                    758: 
                    759:        ofmem_update_translations();
                    760: 
                    761:        return 0;
                    762: }
                    763: 
                    764: int ofmem_map( phys_addr_t phys, ucell virt, ucell size, ucell mode )
                    765: {
                    766:        /* printk("+ofmem_map: %08lX --> %08lX (size %08lX, mode 0x%02X)\n",
                    767:           virt, phys, size, mode ); */
                    768: 
                    769:        if( (phys & 0xfff) || (virt & 0xfff) || (size & 0xfff) ) {
                    770: 
                    771:                OFMEM_TRACE("ofmem_map: Bad parameters ("
                    772:                                FMT_plx " " FMT_ucellX " " FMT_ucellX ")\n",
                    773:                                phys, virt, size );
                    774: 
                    775:                phys &= ~0xfff;
                    776:                virt &= ~0xfff;
                    777:                size = (size + 0xfff) & ~0xfff;
                    778:        }
                    779: 
                    780: #if defined(OFMEM_FILL_RANGE)
                    781:        {
                    782:                ofmem_t *ofmem = ofmem_arch_get_private();
                    783:                /* claim any unclaimed virtual memory in the range */
                    784:                fill_range( virt, size, &ofmem->virt_range );
                    785:                /* hmm... we better claim the physical range too */
                    786:                fill_range( phys, size, &ofmem->phys_range );
                    787:        }
                    788: #endif
                    789: 
                    790:        if (mode==-1) {
                    791:                mode = ofmem_arch_default_translation_mode(phys);
                    792:        }
                    793: 
                    794:        /* install translations */
                    795:        ofmem_map_page_range(phys, virt, size, mode);
                    796: 
                    797:        /* allow arch to install mappings early, e.g. for locked mappings */
                    798:        ofmem_arch_early_map_pages(phys, virt, size, mode);
                    799: 
                    800:        return 0;
                    801: }
                    802: 
                    803: int ofmem_unmap( ucell virt, ucell size )
                    804: {
                    805:        OFMEM_TRACE("ofmem_unmap " FMT_ucellx " " FMT_ucellx "\n",
                    806:                        virt, size );
                    807: 
                    808:        if( (virt & 0xfff) || (size & 0xfff) ) {
                    809:                /* printk("ofmem_unmap: Bad parameters (%08lX %08lX)\n",
                    810:                                virt, size ); */
                    811:                virt &= ~0xfff;
                    812:                size = (size + 0xfff) & ~0xfff;
                    813:        }
                    814: 
                    815:        /* remove translations and unmap pages */
                    816:        unmap_page_range(virt, size);
                    817: 
                    818:        return 0;
                    819: }
                    820: 
                    821: ucell ofmem_map_io( phys_addr_t phys, ucell size )
                    822: {
                    823:        /* Claim virtual memory from the I/O range and map the page-aligned
                    824:           physical address phys to it, returning the newly allocated
                    825:           virtual address */
                    826:        ucell virt, mode;
                    827:        phys_addr_t off;
                    828:        int npages;
                    829: 
                    830:        off = phys & (PAGE_SIZE - 1);
                    831:        npages = (off + size - 1) / PAGE_SIZE + 1;
                    832:        phys &= ~(PAGE_SIZE - 1);
                    833: 
                    834:        virt = ofmem_claim_io(-1, npages * PAGE_SIZE, PAGE_SIZE);
                    835: 
                    836:        mode = ofmem_arch_io_translation_mode(off);
                    837: 
                    838:        ofmem_map_page_range(phys, virt, npages * PAGE_SIZE, mode);
                    839:        ofmem_arch_early_map_pages(phys, virt, npages * PAGE_SIZE, mode);
                    840: 
                    841:        return (virt + off);
                    842: }
                    843: 
                    844: /* virtual -> physical. */
                    845: phys_addr_t ofmem_translate( ucell virt, ucell *mode )
                    846: {
                    847:        ofmem_t *ofmem = ofmem_arch_get_private();
                    848:        translation_t *t;
                    849: 
                    850:        for( t=ofmem->trans; t && t->virt <= virt ; t=t->next ) {
                    851:                ucell offs;
                    852:                if( t->virt + t->size - 1 < virt )
                    853:                        continue;
                    854:                offs = virt - t->virt;
                    855:                *mode = t->mode;
                    856:                return t->phys + offs;
                    857:        }
                    858: 
                    859:        /*printk("ofmem_translate: no translation defined (%08lx)\n", virt);*/
                    860:        /*print_trans();*/
                    861:        return -1;
                    862: }
                    863: 
                    864: static void remove_range( ucell ea, ucell size, range_t **r )
                    865: {
                    866:     OFMEM_TRACE("%s: not implemented\n", __func__);
                    867: }
                    868: 
                    869: /* release memory allocated by ofmem_claim_phys */
                    870: void ofmem_release_phys( phys_addr_t phys, ucell size )
                    871: {
                    872:     OFMEM_TRACE("ofmem_release_phys addr=" FMT_plx " size=" FMT_ucellx "\n",
                    873:                 phys, size);
                    874: 
                    875:     ofmem_t *ofmem = ofmem_arch_get_private();
                    876:     remove_range(phys, size, &ofmem->phys_range);
                    877: }
                    878: 
                    879: /* release memory allocated by ofmem_claim_virt */
                    880: void ofmem_release_virt( ucell virt, ucell size )
                    881: {
                    882:     OFMEM_TRACE("ofmem_release_virt addr=" FMT_ucellx " size=" FMT_ucellx "\n",
                    883:                 virt, size);
                    884: 
                    885:     ofmem_t *ofmem = ofmem_arch_get_private();
                    886:     remove_range(virt, size, &ofmem->virt_range);
                    887: }
                    888: 
                    889: /* release memory allocated by ofmem_claim - 6.3.2.4 */
                    890: void ofmem_release( ucell virt, ucell size )
                    891: {
                    892:     OFMEM_TRACE("%s addr=" FMT_ucellx " size=" FMT_ucellx "\n",
                    893:                 __func__, virt, size);
                    894: 
                    895:     ucell mode;
                    896:     phys_addr_t phys = ofmem_translate(virt, &mode);
                    897:     if (phys == (phys_addr_t)-1) {
                    898:         OFMEM_TRACE("%s: no mapping\n", __func__);
                    899:         return;
                    900:     }
                    901:     ofmem_unmap(virt, size);
                    902:     ofmem_release_virt(virt, size);
                    903:     ofmem_release_phys(phys, size);
                    904: }
                    905: 
                    906: /************************************************************************/
                    907: /* init / cleanup                                                       */
                    908: /************************************************************************/
                    909: 
                    910: void ofmem_register( phandle_t ph_memory, phandle_t ph_mmu )
                    911: {
                    912:        s_phandle_memory = ph_memory;
                    913:        s_phandle_mmu = ph_mmu;
                    914: 
                    915:        /* Initialise some default property sizes  */
                    916:        trans_prop_size = phys_range_prop_size = virt_range_prop_size = OFMEM_DEFAULT_PROP_SIZE;
                    917:        trans_prop = malloc(trans_prop_size);
                    918:        phys_range_prop = malloc(phys_range_prop_size);
                    919:        virt_range_prop = malloc(virt_range_prop_size);
                    920: 
                    921:        ofmem_update_translations();
                    922: }

unix.superglobalmegacorp.com

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