Annotation of qemu/roms/openbios/libopenbios/ofmem_common.c, revision 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.