Changeset 328f2934 in mainline for generic/src/mm/frame.c


Ignore:
Timestamp:
2005-12-04T19:37:13Z (20 years ago)
Author:
Sergey Bondari <bondari@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
cf585c9
Parents:
d7ac642
Message:

Buddy allocator for physical memory complete implementation.
Tested on IA32, AMD64, MIPS32. RWLock Test #5 is not passed.
NOTE: Other architectures could be broken (but should not be)

File:
1 edited

Legend:

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

    rd7ac642 r328f2934  
    3838#include <arch/asm.h>
    3939#include <arch.h>
     40#include <print.h>
    4041
    4142spinlock_t zone_head_lock;       /**< this lock protects zone_head list */
    4243link_t zone_head;                /**< list of all zones in the system */
     44
     45region_t zone_blacklist[ZONE_BLACKLIST_SIZE];
     46count_t zone_blacklist_count = 0;
    4347
    4448static struct buddy_system_operations  zone_buddy_system_operations = {
     
    4852        .set_order = zone_buddy_set_order,
    4953        .get_order = zone_buddy_get_order,
     54        .mark_busy = zone_buddy_mark_busy,
    5055};
    5156
     
    5863        if (config.cpu_active == 1) {
    5964                zone_init();
     65                frame_region_not_free(config.base, config.base + config.kernel_size + CONFIG_STACK_SIZE);
    6066        }
    6167
    6268        frame_arch_init();
    63        
    64         if (config.cpu_active == 1) {
    65                 frame_region_not_free(config.base, config.base + config.kernel_size + CONFIG_STACK_SIZE);
    66         }       
    6769}
    6870
     
    7577 * @return Allocated frame.
    7678 */
    77 __address frame_alloc(int flags)
     79__address frame_alloc(int flags, __u8 order)
    7880{
    7981        ipl_t ipl;
     
    8789        ipl = interrupts_disable();
    8890        spinlock_lock(&zone_head_lock);
    89        
     91
    9092        /*
    9193         * First, find suitable frame zone.
     
    9597               
    9698                spinlock_lock(&z->lock);
    97                 /*
    98                  * Check if the zone has any free frames.
    99                  */
    100                 if (z->free_count) {
     99
     100                /* Check if the zone has 2^order frames area available  */
     101                if (buddy_system_can_alloc(z->buddy_system, order)) {
    101102                        zone = z;
    102103                        break;
    103104                }
     105               
    104106                spinlock_unlock(&z->lock);
    105107        }
     
    119121        }
    120122               
    121         tmp = zone->free_head.next;
    122         frame = list_get_instance(tmp, frame_t, link);
    123 
    124         frame->refcount++;
    125         list_remove(tmp);                       /* remove frame from free_head */
    126         zone->free_count--;
    127         zone->busy_count++;
    128        
    129         //v = zone->base + (frame - zone->frames) * FRAME_SIZE;
     123
     124        /* Allocate frames from zone buddy system */
     125        cur = buddy_system_alloc(zone->buddy_system, order);
     126       
     127        /* frame will be actually a first frame of the block */
     128        frame = list_get_instance(cur, frame_t, buddy_link);
     129       
     130        /* get frame address */
    130131        v = FRAME2ADDR(zone, frame);
    131        
     132
    132133        if (flags & FRAME_KA)
    133134                v = PA2KA(v);
    134135       
    135136        spinlock_unlock(&zone->lock);
    136        
    137137        spinlock_unlock(&zone_head_lock);
    138138        interrupts_restore(ipl);
    139        
    140139        return v;
     140
    141141}
    142142
     
    156156        zone_t *zone = NULL;
    157157        frame_t *frame;
    158        
    159158        ASSERT(addr % FRAME_SIZE == 0);
    160159       
     
    186185       
    187186        frame = ADDR2FRAME(zone, addr);
    188         // frame = &zone->frames[(addr - zone->base)/FRAME_SIZE];
     187
    189188        ASSERT(frame->refcount);
    190189
    191190        if (!--frame->refcount) {
    192                 list_append(&frame->link, &zone->free_head);    /* append frame to free_head */
    193                 zone->free_count++;
    194                 zone->busy_count--;
     191                buddy_system_free(zone->buddy_system, &frame->buddy_link);
    195192        }
    196193       
     
    201198}
    202199
    203 /** Mark frame not free.
    204  *
    205  * Find respective frame structrue for supplied addr.
    206  * Increment frame reference count and remove the frame structure from free list.
    207  *
    208  * @param addr Address of the frame to be marked. It must be a multiple of FRAME_SIZE.
    209  */
    210 void frame_not_free(__address addr)
    211 {
    212         ipl_t ipl;
    213         link_t *cur;
    214         zone_t *z;
    215         zone_t *zone = NULL;
    216         frame_t *frame;
    217        
    218         ASSERT(addr % FRAME_SIZE == 0);
    219        
    220         ipl = interrupts_disable();
    221         spinlock_lock(&zone_head_lock);
    222        
    223         /*
    224          * First, find host frame zone for addr.
    225          */
    226         for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
    227                 z = list_get_instance(cur, zone_t, link);
    228                
    229                 spinlock_lock(&z->lock);
    230                
    231                 if (IS_KA(addr))
    232                         addr = KA2PA(addr);
    233                
    234                 /*
    235                  * Check if addr belongs to z.
    236                  */
    237                 if ((addr >= z->base) && (addr <= z->base + (z->free_count + z->busy_count) * FRAME_SIZE)) {
    238                         zone = z;
    239                         break;
    240                 }
    241                 spinlock_unlock(&z->lock);
    242         }
    243        
    244         ASSERT(zone != NULL);
    245        
    246         //frame = &zone->frames[(addr - zone->base)/FRAME_SIZE];
    247         frame = ADDR2FRAME(zone, addr);
    248 
    249         if (!frame->refcount) {
    250                 frame->refcount++;
    251 
    252                 list_remove(&frame->link);                      /* remove frame from free_head */
    253                 zone->free_count--;
    254                 zone->busy_count++;
    255         }
    256        
    257         spinlock_unlock(&zone->lock);   
    258        
    259         spinlock_unlock(&zone_head_lock);
    260         interrupts_restore(ipl);
    261 }
    262 
    263200/** Mark frame region not free.
    264201 *
     
    268205 * @param stop Last address.
    269206 */
    270 void frame_region_not_free(__address start, __address stop)
    271 {
    272         __address a;
    273 
    274         start /= FRAME_SIZE;
    275         stop /= FRAME_SIZE;
    276         for (a = start; a <= stop; a++)
    277                 frame_not_free(a * FRAME_SIZE);
     207void frame_region_not_free(__address base, size_t size)
     208{
     209        count_t index;
     210        index = zone_blacklist_count++;
     211        ASSERT(base % FRAME_SIZE == 0);
     212       
     213        if (size % FRAME_SIZE != 0) {
     214                size = size + (FRAME_SIZE - size % FRAME_SIZE);
     215        }
     216        ASSERT(size % FRAME_SIZE == 0);
     217        ASSERT(zone_blacklist_count <= ZONE_BLACKLIST_SIZE);
     218        zone_blacklist[index].base = base;
     219        zone_blacklist[index].size = size;
    278220}
    279221
     
    288230        list_initialize(&zone_head);
    289231}
     232
     233
     234void zone_create_in_region(__address base, size_t size) {
     235        int i;
     236        zone_t * z;
     237        __address s; size_t sz;
     238       
     239        ASSERT(base % FRAME_SIZE == 0);
     240        ASSERT(size % FRAME_SIZE == 0);
     241       
     242        if (!size) return;
     243       
     244        for (i = 0; i < zone_blacklist_count; i++) {
     245                if (zone_blacklist[i].base >= base && zone_blacklist[i].base < base + size) {
     246                        s = base; sz = zone_blacklist[i].base - base;
     247                        ASSERT(base != s || sz != size);
     248                        zone_create_in_region(s, sz);
     249                       
     250                        s = zone_blacklist[i].base + zone_blacklist[i].size;
     251                        sz = (base + size) - (zone_blacklist[i].base + zone_blacklist[i].size);
     252                        ASSERT(base != s || sz != size);
     253                        zone_create_in_region(s, sz);
     254                        return;
     255               
     256                }
     257        }
     258       
     259        z = zone_create(base, size, 0);
     260
     261        if (!z) {
     262                panic("Cannot allocate zone (%dB).\n", size);
     263        }
     264       
     265        zone_attach(z);
     266}
     267
     268
    290269
    291270/** Create frame zone
     
    299278 * @return Initialized zone.
    300279 */
    301 zone_t *zone_create(__address start, size_t size, int flags)
     280zone_t * zone_create(__address start, size_t size, int flags)
    302281{
    303282        zone_t *z;
     
    305284        int i;
    306285        __u8 max_order;
    307        
     286
     287        /* hack for bug #10 */
     288        // if (start == 0x100000) size -= (FRAME_SIZE * 256);
     289
     290        // printf("ZONE_CREATE()   %X - %X (%d kbytes)                  \n", start, start+size, size/1024);     
    308291        ASSERT(start % FRAME_SIZE == 0);
    309292        ASSERT(size % FRAME_SIZE == 0);
     
    340323                for (max_order = 0; cnt >> max_order; max_order++);
    341324                z->buddy_system = buddy_system_create(max_order, &zone_buddy_system_operations, (void *) z);
    342         }
    343        
     325               
     326                /* Stuffing frames */
     327                for (i = 0; i<cnt; i++) {
     328                        z->frames[i].refcount = 0;
     329                        buddy_system_free(z->buddy_system, &z->frames[i].buddy_link);   
     330                }
     331        }
    344332        return z;
    345333}
     
    373361void frame_initialize(frame_t *frame, zone_t *zone)
    374362{
    375         frame->refcount = 0;
     363        frame->refcount = 1;
     364        frame->buddy_order = 0;
    376365        link_initialize(&frame->link);
    377366}
    378367
    379 
    380 
    381 /*
    382  * buddy system functions (under construction)
    383  *
    384  */
    385 
    386 
    387 /** Allocate 2^order frames
    388  *
    389  */
    390 __address zone_buddy_frame_alloc(int flags, __u8 order) {
    391         ipl_t ipl;
    392         link_t *cur, *tmp;
    393         zone_t *z;
    394         zone_t *zone = NULL;
    395         frame_t *frame = NULL;
    396         __address v;
    397        
    398 loop:
    399         ipl = interrupts_disable();
    400         spinlock_lock(&zone_head_lock);
    401        
    402         /*
    403          * First, find suitable frame zone.
    404          */
    405         for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
    406                 z = list_get_instance(cur, zone_t, link);
    407                
    408                 spinlock_lock(&z->lock);
    409                 /*
    410                  * Check if the zone has 2^order frames area available
    411                  * TODO: Must check if buddy system has at least block in order >= given order
    412                  */
    413                 if (z->free_count == (1 >> order)) {
    414                         zone = z;
    415                         break;
    416                 }
    417                
    418                 spinlock_unlock(&z->lock);
    419         }
    420        
    421         if (!zone) {
    422                 if (flags & FRAME_PANIC)
    423                         panic("Can't allocate frame.\n");
    424                
    425                 /*
    426                  * TODO: Sleep until frames are available again.
    427                  */
    428                 spinlock_unlock(&zone_head_lock);
    429                 interrupts_restore(ipl);
    430 
    431                 panic("Sleep not implemented.\n");
    432                 goto loop;
    433         }
    434                
    435 
    436         /* Allocate frames from zone buddy system */
    437         cur = buddy_system_alloc(zone->buddy_system, order);
    438        
    439         /* frame will be actually a first frame of the block */
    440         frame = list_get_instance(cur, frame_t, buddy_link);
    441        
    442         /* get frame address */
    443         v = FRAME2ADDR(zone, frame);
    444        
    445         if (flags & FRAME_KA)
    446                 v = PA2KA(v);
    447        
    448         spinlock_unlock(&zone->lock);
    449         spinlock_unlock(&zone_head_lock);
    450         interrupts_restore(ipl);
    451        
    452         return v;
    453 }
    454 
    455 
    456 /** Free frame(s)
    457  *
    458  * @param addr Address of the frame(s) to be freed. It must be a multiple of FRAME_SIZE.
    459  */
    460 void zone_buddy_frame_free(__address addr)
    461 {
    462         ipl_t ipl;
    463         link_t *cur;
    464         zone_t *z;
    465         zone_t *zone = NULL;
    466         frame_t *frame;
    467        
    468         ASSERT(addr % FRAME_SIZE == 0);
    469        
    470         ipl = interrupts_disable();
    471         spinlock_lock(&zone_head_lock);
    472        
    473         /*
    474          * First, find host frame zone for addr.
    475          */
    476         for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
    477                 z = list_get_instance(cur, zone_t, link);
    478                
    479                 spinlock_lock(&z->lock);
    480                
    481                 if (IS_KA(addr))
    482                         addr = KA2PA(addr);
    483                
    484                 /*
    485                  * Check if addr belongs to z.
    486                  */
    487                 if ((addr >= z->base) && (addr <= z->base + (z->free_count + z->busy_count) * FRAME_SIZE)) {
    488                         zone = z;
    489                         break;
    490                 }
    491                 spinlock_unlock(&z->lock);
    492         }
    493        
    494         ASSERT(zone != NULL);
    495        
    496         frame = ADDR2FRAME(zone, addr);
    497 
    498         ASSERT(frame->refcount);
    499 
    500         if (!--frame->refcount) {
    501                 buddy_system_free(zone->buddy_system, &frame->buddy_link);
    502         }
    503        
    504         spinlock_unlock(&zone->lock);   
    505        
    506         spinlock_unlock(&zone_head_lock);
    507         interrupts_restore(ipl);
    508 }
    509 
    510 /** Guess zone by frame instance address
    511  *
    512  * @param frame Frame
    513  *
    514  * @return Zone of given frame
    515  */
    516 zone_t * get_zone_by_frame(frame_t * frame) {
    517         link_t * cur;
    518         zone_t * zone, *z;
    519 
    520         ASSERT(frame);
    521         /*
    522          * First, find host frame zone for addr.
    523          */
    524         for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
    525                 z = list_get_instance(cur, zone_t, link);
    526                
    527                 spinlock_lock(&z->lock);
    528                
    529                 /*
    530                  * Check if frame address belongs to z.
    531                  */
    532                 if ((frame >= z->frames) && (frame <= z->frames + (z->free_count + z->busy_count))) {
    533                         zone = z;
    534                         break;
    535                 }
    536                 spinlock_unlock(&z->lock);
    537         }
    538         ASSERT(zone);
    539        
    540         return zone;
    541 
    542 
    543 }
    544368
    545369/** Buddy system find_buddy implementation
     
    554378        zone_t * zone;
    555379        link_t * cur;
     380        count_t index;
    556381        bool is_left, is_right;
    557382
    558383        frame = list_get_instance(block, frame_t, buddy_link);
    559         zone = get_zone_by_frame(frame);
    560        
     384        zone = (zone_t *) b->data;
    561385       
    562386        /*
     
    564388         * (FRAME_INDEX % 2^(ORDER+1)) == 2^(ORDER) ===> RIGHT BUDDY
    565389         */
    566          
     390
    567391        is_left = IS_BUDDY_LEFT_BLOCK(zone, frame);
    568392        is_right = IS_BUDDY_RIGHT_BLOCK(zone, frame);
     
    570394        ASSERT((is_left || is_right) && (!is_left || !is_right));
    571395       
    572         for (cur = &zone->buddy_system->order[frame->buddy_order]; cur; cur = cur->next) {
    573                 f = list_get_instance(cur, frame_t, buddy_link);
    574                
    575                 ASSERT(f->buddy_order == frame->buddy_order);
    576                
    577                 /*
    578                  * if found frame is coherent with our frame from the left
    579                  */
    580                 if ((FRAME_INDEX(zone, f) + 1 >> frame->buddy_order == FRAME_INDEX(zone, frame)) && is_right) {
    581                         return cur;
    582                 }
    583                
    584                 /*
    585                  * if found frame is coherent with our frame from the right
    586                  */
    587                 if ((FRAME_INDEX(zone,f) - 1 >> frame->buddy_order == FRAME_INDEX(zone, frame)) && is_left) {
    588                         return cur;
    589                 }
    590                
     396        /*
     397         * test left buddy
     398         */
     399        if (is_left) {
     400                index = (FRAME_INDEX(zone, frame)) + (1 << frame->buddy_order);
     401        } else if (is_right) {
     402                index = (FRAME_INDEX(zone, frame)) - (1 << frame->buddy_order);
     403        }
     404       
     405        if (FRAME_INDEX_VALID(zone, index)) {
     406                if (    zone->frames[index].buddy_order == frame->buddy_order &&
     407                        zone->frames[index].refcount == 0) {
     408                        return &zone->frames[index].buddy_link;
     409                }
    591410        }
    592411       
    593412        return NULL;
    594        
    595413       
    596414}
     
    605423link_t * zone_buddy_bisect(buddy_system_t *b, link_t * block) {
    606424        frame_t * frame_l, * frame_r;
    607        
    608425        frame_l = list_get_instance(block, frame_t, buddy_link);
    609 
    610         frame_r = (frame_t *) (&frame_l + (1>>frame_l->buddy_order-1));
    611 
     426        frame_r = (frame_l + (1 << (frame_l->buddy_order - 1)));
    612427        return &frame_r->buddy_link;
    613        
    614428}
    615429
     
    624438link_t * zone_buddy_coalesce(buddy_system_t *b, link_t * block_1, link_t * block_2) {
    625439        frame_t * frame1, * frame2;
    626        
    627440        frame1 = list_get_instance(block_1, frame_t, buddy_link);
    628441        frame2 = list_get_instance(block_2, frame_t, buddy_link);
    629        
    630         return &frame1 < &frame2 ? block_1 : block_2;
     442        return frame1 < frame2 ? block_1 : block_2;
    631443}
    632444
     
    655467        return frame->buddy_order;
    656468}
     469
     470/** Buddy system mark_busy implementation
     471 *
     472 * @param b Buddy system
     473 * @param block Buddy system block
     474 *
     475 */
     476void zone_buddy_mark_busy(buddy_system_t *b, link_t * block) {
     477        frame_t * frame;
     478        frame = list_get_instance(block, frame_t, buddy_link);
     479        frame->refcount = 1;
     480}
Note: See TracChangeset for help on using the changeset viewer.