Changeset bb68433 in mainline for generic/src/mm/frame.c


Ignore:
Timestamp:
2006-02-08T22:58:06Z (19 years ago)
Author:
Ondrej Palkovsky <ondrap@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
7e4e532
Parents:
85dc2e7
Message:

Changed malloc to include second parameter and documented
recommended usage.
Added zone merging, made ia32 & amd64 to merge found zones.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • generic/src/mm/frame.c

    r85dc2e7 rbb68433  
    5151#include <align.h>
    5252#include <mm/slab.h>
     53#include <bitops.h>
    5354
    5455typedef struct {
     
    122123/**
    123124 * Insert-sort zone into zones list
    124  */
    125 static void zones_add_zone(zone_t *zone)
    126 {
    127         int i;
    128 
     125 *
     126 * @return zone number on success, -1 on error
     127 */
     128static int zones_add_zone(zone_t *newzone)
     129{
     130        int i,j;
     131        ipl_t ipl;
     132        zone_t *z;
     133
     134        ipl = interrupts_disable();
    129135        spinlock_lock(&zones.lock);
    130136        /* Try to merge */
    131         if (zone->flags & ZONE_JOIN) {
    132                 for (i=0; i < zones.count; i++) {
    133                         spinlock_lock(&zones.info[i]->lock);
    134                        
    135                         /* Join forward, join backward */
    136                         panic("Not implemented");
    137 
    138                         spinlock_unlock(&zones.info[i]->lock);
     137        if (zones.count+1 == ZONES_MAX)
     138                panic("Maximum zone(%d) count exceeded.", ZONES_MAX);
     139
     140        for (i=0; i < zones.count; i++) {
     141                /* Check for overflow */
     142                z = zones.info[zones.count];
     143                if (overlaps(newzone->base,newzone->count,
     144                             z->base, z->count)) {
     145                        printf("Zones overlap!\n");
     146                        return -1;
    139147                }
    140                 spinlock_unlock(&zones.lock);
    141         } else {
    142                 if (zones.count+1 == ZONES_MAX)
    143                         panic("Maximum zone(%d) count exceeded.", ZONES_MAX);
    144                 zones.info[zones.count++] = zone;
    145         }
     148                if (z->base < newzone->base)
     149                        break;
     150        }
     151        /* Move other zones up */
     152        for (j=i;j < zones.count;j++)
     153                zones.info[j+1] = zones.info[j];
     154
     155        zones.info[i] = newzone;
     156        zones.count++;
     157
    146158        spinlock_unlock(&zones.lock);
     159        interrupts_restore(ipl);
     160
     161        return i;
    147162}
    148163
     
    187202}
    188203
     204/** @return True if zone can allocate specified order */
     205static int zone_can_alloc(zone_t *z, __u8 order)
     206{
     207        return buddy_system_can_alloc(z->buddy_system, order);
     208}
     209
    189210/**
    190211 * Find AND LOCK zone that can allocate order frames
     
    210231
    211232                /* Check if the zone has 2^order frames area available  */
    212                 if (buddy_system_can_alloc(z->buddy_system, order)) {
     233                if (zone_can_alloc(z, order)) {
    213234                        spinlock_unlock(&zones.lock);
    214235                        if (pzone)
     
    253274}
    254275
    255                                      
     276static void zone_buddy_print_id(buddy_system_t *b, link_t *block)
     277{
     278        frame_t * frame;
     279        zone_t * zone;
     280        index_t index;
     281
     282        frame = list_get_instance(block, frame_t, buddy_link);
     283        zone = (zone_t *) b->data;
     284        index = frame_index(zone, frame);
     285        printf("%d", index);
     286}                                   
    256287
    257288/** Buddy system find_buddy implementation
     
    319350 */
    320351static link_t * zone_buddy_coalesce(buddy_system_t *b, link_t * block_1,
    321                                     link_t * block_2) {
     352                                    link_t * block_2)
     353{
    322354        frame_t *frame1, *frame2;
    323355       
     
    361393static void zone_buddy_mark_busy(buddy_system_t *b, link_t * block) {
    362394        frame_t * frame;
     395
    363396        frame = list_get_instance(block, frame_t, buddy_link);
    364397        frame->refcount = 1;
     
    385418        .mark_busy = zone_buddy_mark_busy,
    386419        .mark_available = zone_buddy_mark_available,
    387         .find_block = zone_buddy_find_block
     420        .find_block = zone_buddy_find_block,
     421        .print_id = zone_buddy_print_id
    388422};
    389423
     
    394428 *
    395429 * Assume zone is locked
     430 * Panics, if allocation is impossible.
    396431 *
    397432 * @return Frame index in zone
    398433 */
    399 static pfn_t zone_frame_alloc(zone_t *zone,__u8 order, int flags, int *status)
     434static pfn_t zone_frame_alloc(zone_t *zone,__u8 order)
    400435{
    401436        pfn_t v;
     
    459494
    460495        frame = zone_get_frame(zone, frame_idx);
     496        if (frame->refcount)
     497                return;
    461498        link = buddy_system_alloc_block(zone->buddy_system,
    462499                                        &frame->buddy_link);
     
    465502}
    466503
     504/**
     505 * Join 2 zones
     506 *
     507 * Expect zone_t *z to point to space at least zone_conf_size large
     508 *
     509 * Assume z1 & z2 are locked
     510 */
     511
     512static void _zone_merge(zone_t *z, zone_t *z1, zone_t *z2)
     513{
     514        __u8 max_order;
     515        int i, z2idx;
     516        pfn_t frame_idx;
     517        frame_t *frame;
     518
     519        ASSERT(!overlaps(z1->base,z1->count,z2->base,z2->count));
     520        ASSERT(z1->base < z2->base);
     521
     522        spinlock_initialize(&z->lock, "zone_lock");
     523        z->base = z1->base;
     524        z->count = z2->base+z2->count - z1->base;
     525        z->flags = z1->flags & z2->flags;
     526
     527        z->free_count = z1->free_count + z2->free_count;
     528        z->busy_count = z1->busy_count + z2->busy_count;
     529       
     530        max_order = fnzb(z->count);
     531
     532        z->buddy_system = (buddy_system_t *)&z[1];
     533        buddy_system_create(z->buddy_system, max_order,
     534                            &zone_buddy_system_operations,
     535                            (void *) z);
     536
     537        z->frames = (frame_t *)((void *)z->buddy_system+buddy_conf_size(max_order));
     538        for (i = 0; i < z->count; i++) {
     539                /* This marks all frames busy */
     540                frame_initialize(&z->frames[i]);
     541        }
     542        /* Copy frames from both zones to preserve full frame orders,
     543         * parents etc. Set all frames with refcount=0 to 1, because
     544         * we add all free frames to buddy allocator later again, clear
     545         * order to 0.
     546         */
     547        for (i=0; i<z1->count; i++)
     548                z->frames[i] = z1->frames[i];
     549        for (i=0; i < z2->count; i++) {
     550                z2idx = i + (z2->base - z1->base);
     551                z->frames[z2idx] = z2->frames[i];
     552        }
     553        for (i=0; i < z->count; i++) {
     554                if (!z->frames[i].refcount) {
     555                        z->frames[i].refcount = 1;
     556                        z->frames[i].buddy_order = 0;
     557                }
     558        }
     559        /* Add free blocks from the 2 original zones */
     560        while (zone_can_alloc(z1, 0)) {
     561                frame_idx = zone_frame_alloc(z1, 0);
     562                frame = &z->frames[frame_idx];
     563                frame->refcount = 0;
     564                buddy_system_free(z->buddy_system, &frame->buddy_link);
     565        }
     566        while (zone_can_alloc(z2, 0)) {
     567                frame_idx = zone_frame_alloc(z2, 0);
     568                frame = &z->frames[frame_idx + (z2->base-z1->base)];
     569                frame->refcount = 0;
     570                buddy_system_free(z->buddy_system, &frame->buddy_link);
     571        }
     572}
     573
     574/** Return old configuration frames into the zone
     575 *
     576 * We have several cases
     577 * - the conf. data is outside of zone -> exit, shall we call frame_free??
     578 * - the conf. data was created by zone_create -> free every frame
     579 * - the conf. data was created by merge in frame_alloc -> free first frame
     580 *   (the difference is in order)
     581 */
     582static void return_config_frames(zone_t *newzone, zone_t *oldzone)
     583{
     584        pfn_t pfn;
     585        frame_t *frame;
     586        count_t cframes;
     587        int i;
     588
     589        pfn = ADDR2PFN((__address)KA2PA(oldzone));
     590        cframes = SIZE2FRAMES(zone_conf_size(oldzone->count));
     591       
     592        if (pfn < newzone->base || pfn >= newzone->base + newzone->count)
     593                return;
     594
     595        frame = &newzone->frames[pfn - newzone->base];
     596        if (frame->buddy_order) {
     597                /* Normally zone config data is hidden, show it again */
     598                newzone->busy_count += (1 << frame->buddy_order);
     599                zone_frame_free(newzone, pfn - newzone->base);
     600                return;
     601        }
     602
     603        for (i=0; i < cframes; i++) {
     604                newzone->busy_count++;
     605                zone_frame_free(newzone, pfn+i-newzone->base);
     606        }
     607}
     608
     609/** Merge zones z1 and z2
     610 *
     611 * - the zones must be 2 zones with no zone existing in between,
     612 *   which means that z2 = z1+1
     613 *
     614 * - When you create a new zone, the frame allocator configuration does
     615 *   not to be 2^order size. Once the allocator is running it is no longer
     616 *   possible, merged configuration data occupies more space :-/
     617 */
     618void zone_merge(int z1, int z2)
     619{
     620        ipl_t ipl;
     621        zone_t *zone1, *zone2, *newzone;
     622        int cframes;
     623        __u8 order;
     624        int i;
     625        pfn_t pfn;
     626
     627        ipl = interrupts_disable();
     628        spinlock_lock(&zones.lock);
     629
     630        if (z1 < 0 || z1 >= zones.count || z2 < 0 || z2 >= zones.count)
     631                goto errout;
     632        /* We can join only 2 zones with none existing inbetween */
     633        if (z2-z1 != 1)
     634                goto errout;
     635
     636        zone1 = zones.info[z1];
     637        zone2 = zones.info[z2];
     638        spinlock_lock(&zone1->lock);
     639        spinlock_lock(&zone2->lock);
     640
     641        cframes = SIZE2FRAMES(zone_conf_size(zone2->base+zone2->count-zone1->base));
     642        order = fnzb(cframes) + 1;
     643
     644        /* Allocate zonedata inside one of the zones */
     645        if (zone_can_alloc(zone1, order))
     646                pfn = zone1->base + zone_frame_alloc(zone1, order);
     647        else if (zone_can_alloc(zone2, order))
     648                pfn = zone2->base + zone_frame_alloc(zone2, order);
     649        else
     650                goto errout2;
     651
     652        newzone = (zone_t *)PA2KA(PFN2ADDR(pfn));
     653
     654        _zone_merge(newzone, zone1, zone2);
     655
     656        /* Subtract zone information from busy frames */
     657        newzone->busy_count -= (1 << order);
     658
     659        zones.info[z1] = newzone;
     660        for (i=z2+1;i < zones.count;i++)
     661                zones.info[i-1] = zones.info[i];
     662        zones.count--;
     663
     664        /* Free old zone information */
     665        return_config_frames(newzone, zone1);
     666        return_config_frames(newzone, zone2);
     667errout2:
     668        /* Nobody is allowed to enter to zone, so we are safe
     669         * to touch the spinlocks last time */
     670        spinlock_unlock(&zone1->lock);
     671        spinlock_unlock(&zone2->lock);
     672errout:
     673        spinlock_unlock(&zones.lock);
     674        interrupts_restore(ipl);
     675}
     676
     677
     678/**
     679 * Merge all zones into one big zone
     680 *
     681 * It is reasonable to do this on systems whose bios reports parts in chunks,
     682 * so that we could have 1 zone (it's faster).
     683 */
     684void zone_merge_all(void)
     685{
     686        int count = zones.count;
     687
     688        while (zones.count > 1 && --count) {
     689                zone_merge(0,1);
     690                break;
     691        }
     692}
     693
    467694/** Create frame zone
    468695 *
     
    476703 * @return Initialized zone.
    477704 */
    478 static zone_t * zone_construct(pfn_t start, count_t count,
    479                                zone_t *z, int flags)
     705static void zone_construct(pfn_t start, count_t count, zone_t *z, int flags)
    480706{
    481707        int i;
     
    492718         * Compute order for buddy system, initialize
    493719         */
    494         for (max_order = 0; count >> max_order; max_order++)
    495                 ;
     720        max_order = fnzb(count);
    496721        z->buddy_system = (buddy_system_t *)&z[1];
    497722       
     
    503728        /* Check sizes */
    504729        z->frames = (frame_t *)((void *)z->buddy_system+buddy_conf_size(max_order));
    505 
    506730        for (i = 0; i<count; i++) {
    507731                frame_initialize(&z->frames[i]);
    508732        }
     733
    509734        /* Stuffing frames */
    510735        for (i = 0; i < count; i++) {
     
    512737                buddy_system_free(z->buddy_system, &z->frames[i].buddy_link);
    513738        }
    514         return z;
    515739}
    516740
    517741
    518742/** Compute configuration data size for zone */
    519 __address zone_conf_size(pfn_t start, count_t count)
     743__address zone_conf_size(count_t count)
    520744{
    521745        int size = sizeof(zone_t) + count*sizeof(frame_t);
    522746        int max_order;
    523747
    524         for (max_order = 0; count >> max_order; max_order++)
    525                 ;
     748        max_order = fnzb(count);
    526749        size += buddy_conf_size(max_order);
    527750        return size;
    528751}
     752
    529753
    530754/** Create and add zone to system
     
    535759 *                  that the area is already marked BUSY and big enough
    536760 *                  to contain zone_conf_size() amount of data
    537  */
    538 void zone_create(pfn_t start, count_t count, pfn_t confframe, int flags)
     761 *
     762 * @return Zone number or -1 on error
     763 */
     764int zone_create(pfn_t start, count_t count, pfn_t confframe, int flags)
    539765{
    540766        zone_t *z;
    541         __address addr,endaddr;
     767        __address addr;
    542768        count_t confcount;
    543769        int i;
     770        int znum;
    544771
    545772        /* Theoretically we could have here 0, practically make sure
     
    551778         * it does not span kernel & init
    552779         */
    553         confcount = SIZE2FRAMES(zone_conf_size(start,count));
     780        confcount = SIZE2FRAMES(zone_conf_size(count));
    554781        if (confframe >= start && confframe < start+count) {
    555782                for (;confframe < start+count;confframe++) {
    556783                        addr = PFN2ADDR(confframe);
    557                         endaddr =  PFN2ADDR (confframe + confcount);
    558                         if (overlaps(addr, endaddr, KA2PA(config.base),
    559                                      KA2PA(config.base+config.kernel_size)))
     784                        if (overlaps(addr, PFN2ADDR(confcount),
     785                                     KA2PA(config.base),config.kernel_size))
    560786                                continue;
    561787                        if (config.init_addr)
    562                                 if (overlaps(addr,endaddr,
     788                                if (overlaps(addr,PFN2ADDR(confcount),
    563789                                             KA2PA(config.init_addr),
    564                                              KA2PA(config.init_addr+config.init_size)))
     790                                             config.init_size))
    565791                                        continue;
    566792                        break;
     
    570796        }
    571797
    572         z = zone_construct(start, count, (zone_t *)PA2KA(PFN2ADDR(confframe)), flags);
    573         zones_add_zone(z);
    574        
     798        z = (zone_t *)PA2KA(PFN2ADDR(confframe));
     799        zone_construct(start, count, z, flags);
     800        znum = zones_add_zone(z);
     801        if (znum == -1)
     802                return -1;
     803
    575804        /* If confdata in zone, mark as unavailable */
    576805        if (confframe >= start && confframe < start+count)
     
    578807                        zone_mark_unavailable(z, i - z->base);
    579808                }
     809
     810        return znum;
    580811}
    581812
     
    658889                goto loop;
    659890        }
    660         v = zone_frame_alloc(zone,order,flags,status);
     891        v = zone_frame_alloc(zone,order);
    661892        v += zone->base;
    662893
     
    671902/** Free a frame.
    672903 *
    673  * Find respective frame structrue for supplied addr.
     904 * Find respective frame structure for supplied addr.
    674905 * Decrement frame reference count.
    675906 * If it drops to zero, move the frame structure to free list.
     
    705936        int prefzone = 0;
    706937
    707         for (i=0; i<count; i++) {
     938        for (i=0; i < count; i++) {
    708939                zone = find_zone_and_lock(start+i,&prefzone);
    709940                if (!zone) /* PFN not found */
     
    748979        ipl = interrupts_disable();
    749980        spinlock_lock(&zones.lock);
    750         printf("Base address\tFree Frames\tBusy Frames\n");
    751         printf("------------\t-----------\t-----------\n");
     981        printf("Base address\tFree Frames\tBusy Frames\n");
     982        printf("   ------------\t-----------\t-----------\n");
    752983        for (i=0;i<zones.count;i++) {
    753984                zone = zones.info[i];
    754985                spinlock_lock(&zone->lock);
    755                 printf("%L\t%d\t\t%d\n",PFN2ADDR(zone->base),
     986                printf("%d  %L\t%d\t\t%d\n",i,PFN2ADDR(zone->base),
    756987                       zone->free_count, zone->busy_count);
    757988                spinlock_unlock(&zone->lock);
     
    763994/** Prints zone details
    764995 *
    765  * @param base Zone base address
    766  */
    767 void zone_print_one(int znum) {
     996 * @param base Zone base address OR zone number
     997 */
     998void zone_print_one(int num) {
    768999        zone_t *zone = NULL;
    7691000        ipl_t ipl;
     1001        int i;
    7701002
    7711003        ipl = interrupts_disable();
    7721004        spinlock_lock(&zones.lock);
    773        
    774         if (znum >= zones.count || znum < 0) {
    775                 printf("Zone number out of bounds.\n");
    776                 spinlock_unlock(&zones.lock);
    777                 interrupts_restore(ipl);
    778                 return;
    779         }
    780        
    781         zone = zones.info[znum];
     1005
     1006        for (i=0;i < zones.count; i++) {
     1007                if (i == num || zones.info[i]->base == ADDR2PFN(num)) {
     1008                        zone = zones.info[i];
     1009                        break;
     1010                }
     1011        }
     1012        if (!zone) {
     1013                printf("Zone not found.\n");
     1014                goto out;
     1015        }
    7821016       
    7831017        spinlock_lock(&zone->lock);
    784         printf("Memory zone information\n\n");
     1018        printf("Memory zone information\n");
    7851019        printf("Zone base address: %P\n", PFN2ADDR(zone->base));
    7861020        printf("Zone size: %d frames (%dK)\n", zone->count, ((zone->count) * FRAME_SIZE) >> 10);
    7871021        printf("Allocated space: %d frames (%dK)\n", zone->busy_count, (zone->busy_count * FRAME_SIZE) >> 10);
    7881022        printf("Available space: %d (%dK)\n", zone->free_count, (zone->free_count * FRAME_SIZE) >> 10);
    789        
    790         printf("\nBuddy allocator structures:\n\n");
    7911023        buddy_system_structure_print(zone->buddy_system, FRAME_SIZE);
    7921024       
    7931025        spinlock_unlock(&zone->lock);
     1026out:
    7941027        spinlock_unlock(&zones.lock);
    7951028        interrupts_restore(ipl);
Note: See TracChangeset for help on using the changeset viewer.