Ignore:
File:
1 edited

Legend:

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

    radb252c0 raaceebc4  
    3838 *
    3939 * This file contains the physical frame allocator and memory zone management.
    40  * The frame allocator is built on top of the two-level bitmap structure.
    41  *
     40 * The frame allocator is built on top of the buddy allocator.
     41 *
     42 * @see buddy.c
    4243 */
    4344
     
    6162#include <str.h>
    6263
    63 #define BITMAP_BLOCK_SIZE  1024
    64 
    6564zones_t zones;
    6665
     
    9392}
    9493
     94NO_TRACE static inline size_t make_frame_index(zone_t *zone, frame_t *frame)
     95{
     96        return (frame - zone->frames);
     97}
     98
    9599/** Initialize frame structure.
    96100 *
     
    100104NO_TRACE static void frame_initialize(frame_t *frame)
    101105{
    102         frame->refcount = 0;
    103         frame->parent = NULL;
     106        frame->refcount = 1;
     107        frame->buddy_order = 0;
    104108}
    105109
     
    157161       
    158162        /* Move other zones up */
    159         for (size_t j = zones.count; j > i; j--)
     163        size_t j;
     164        for (j = zones.count; j > i; j--) {
    160165                zones.info[j] = zones.info[j - 1];
     166                if (zones.info[j].buddy_system != NULL)
     167                        zones.info[j].buddy_system->data =
     168                            (void *) &zones.info[j];
     169        }
    161170       
    162171        zones.count++;
     
    228237}
    229238
    230 /** @return True if zone can allocate specified number of frames */
    231 NO_TRACE static bool zone_can_alloc(zone_t *zone, size_t count,
    232     pfn_t constraint)
    233 {
    234         /*
    235          * The function bitmap_allocate_range() does not modify
    236          * the bitmap if the last argument is NULL.
    237          */
     239/** @return True if zone can allocate specified order */
     240NO_TRACE static bool zone_can_alloc(zone_t *zone, uint8_t order)
     241{
    238242        return ((zone->flags & ZONE_AVAILABLE) &&
    239             bitmap_allocate_range(&zone->bitmap, count, zone->base,
    240             constraint, NULL));
    241 }
    242 
    243 /** Find a zone that can allocate specified number of frames
     243            buddy_system_can_alloc(zone->buddy_system, order));
     244}
     245
     246/** Find a zone that can allocate order frames.
    244247 *
    245248 * Assume interrupts are disabled and zones lock is
    246249 * locked.
    247250 *
    248  * @param count      Number of free frames we are trying to find.
    249  * @param flags      Required flags of the target zone.
    250  * @param constraint Indication of bits that cannot be set in the
    251  *                   physical frame number of the first allocated frame.
    252  * @param hind       Preferred zone.
    253  *
    254  */
    255 NO_TRACE static size_t find_free_zone(size_t count, zone_flags_t flags,
    256     pfn_t constraint, size_t hint)
     251 * @param order Size (2^order) of free space we are trying to find.
     252 * @param flags Required flags of the target zone.
     253 * @param hind  Preferred zone.
     254 *
     255 */
     256NO_TRACE static size_t find_free_zone(uint8_t order, zone_flags_t flags,
     257    size_t hint)
    257258{
    258259        if (hint >= zones.count)
     
    266267                if (ZONE_FLAGS_MATCH(zones.info[i].flags, flags)) {
    267268                        /*
    268                          * Check if the zone can satisfy the allocation request.
     269                         * Check if the zone has 2^order frames area available.
    269270                         */
    270                         if (zone_can_alloc(&zones.info[i], count, constraint))
     271                        if (zone_can_alloc(&zones.info[i], order))
    271272                                return i;
    272273                }
     
    281282}
    282283
     284/**************************/
     285/* Buddy system functions */
     286/**************************/
     287
     288/** Buddy system find_block implementation.
     289 *
     290 * Find block that is parent of current list.
     291 * That means go to lower addresses, until such block is found
     292 *
     293 * @param order Order of parent must be different then this
     294 *              parameter!!
     295 *
     296 */
     297NO_TRACE static link_t *zone_buddy_find_block(buddy_system_t *buddy,
     298    link_t *child, uint8_t order)
     299{
     300        frame_t *frame = list_get_instance(child, frame_t, buddy_link);
     301        zone_t *zone = (zone_t *) buddy->data;
     302       
     303        size_t index = frame_index(zone, frame);
     304        do {
     305                if (zone->frames[index].buddy_order != order)
     306                        return &zone->frames[index].buddy_link;
     307        } while (index-- > 0);
     308       
     309        return NULL;
     310}
     311
     312/** Buddy system find_buddy implementation.
     313 *
     314 * @param buddy Buddy system.
     315 * @param block Block for which buddy should be found.
     316 *
     317 * @return Buddy for given block if found.
     318 *
     319 */
     320NO_TRACE static link_t *zone_buddy_find_buddy(buddy_system_t *buddy,
     321    link_t *block)
     322{
     323        frame_t *frame = list_get_instance(block, frame_t, buddy_link);
     324        zone_t *zone = (zone_t *) buddy->data;
     325        ASSERT(IS_BUDDY_ORDER_OK(frame_index_abs(zone, frame),
     326            frame->buddy_order));
     327       
     328        bool is_left = IS_BUDDY_LEFT_BLOCK_ABS(zone, frame);
     329       
     330        size_t index;
     331        if (is_left) {
     332                index = (frame_index(zone, frame)) +
     333                    (1 << frame->buddy_order);
     334        } else {  /* is_right */
     335                index = (frame_index(zone, frame)) -
     336                    (1 << frame->buddy_order);
     337        }
     338       
     339        if (frame_index_valid(zone, index)) {
     340                if ((zone->frames[index].buddy_order == frame->buddy_order) &&
     341                    (zone->frames[index].refcount == 0)) {
     342                        return &zone->frames[index].buddy_link;
     343                }
     344        }
     345       
     346        return NULL;
     347}
     348
     349/** Buddy system bisect implementation.
     350 *
     351 * @param buddy Buddy system.
     352 * @param block Block to bisect.
     353 *
     354 * @return Right block.
     355 *
     356 */
     357NO_TRACE static link_t *zone_buddy_bisect(buddy_system_t *buddy, link_t *block)
     358{
     359        frame_t *frame_l = list_get_instance(block, frame_t, buddy_link);
     360        frame_t *frame_r = (frame_l + (1 << (frame_l->buddy_order - 1)));
     361       
     362        return &frame_r->buddy_link;
     363}
     364
     365/** Buddy system coalesce implementation.
     366 *
     367 * @param buddy   Buddy system.
     368 * @param block_1 First block.
     369 * @param block_2 First block's buddy.
     370 *
     371 * @return Coalesced block (actually block that represents lower
     372 *         address).
     373 *
     374 */
     375NO_TRACE static link_t *zone_buddy_coalesce(buddy_system_t *buddy,
     376    link_t *block_1, link_t *block_2)
     377{
     378        frame_t *frame1 = list_get_instance(block_1, frame_t, buddy_link);
     379        frame_t *frame2 = list_get_instance(block_2, frame_t, buddy_link);
     380       
     381        return ((frame1 < frame2) ? block_1 : block_2);
     382}
     383
     384/** Buddy system set_order implementation.
     385 *
     386 * @param buddy Buddy system.
     387 * @param block Buddy system block.
     388 * @param order Order to set.
     389 *
     390 */
     391NO_TRACE static void zone_buddy_set_order(buddy_system_t *buddy, link_t *block,
     392    uint8_t order)
     393{
     394        list_get_instance(block, frame_t, buddy_link)->buddy_order = order;
     395}
     396
     397/** Buddy system get_order implementation.
     398 *
     399 * @param buddy Buddy system.
     400 * @param block Buddy system block.
     401 *
     402 * @return Order of block.
     403 *
     404 */
     405NO_TRACE static uint8_t zone_buddy_get_order(buddy_system_t *buddy,
     406    link_t *block)
     407{
     408        return list_get_instance(block, frame_t, buddy_link)->buddy_order;
     409}
     410
     411/** Buddy system mark_busy implementation.
     412 *
     413 * @param buddy Buddy system.
     414 * @param block Buddy system block.
     415 *
     416 */
     417NO_TRACE static void zone_buddy_mark_busy(buddy_system_t *buddy, link_t *block)
     418{
     419        list_get_instance(block, frame_t, buddy_link)->refcount = 1;
     420}
     421
     422/** Buddy system mark_available implementation.
     423 *
     424 * @param buddy Buddy system.
     425 * @param block Buddy system block.
     426 *
     427 */
     428NO_TRACE static void zone_buddy_mark_available(buddy_system_t *buddy,
     429    link_t *block)
     430{
     431        list_get_instance(block, frame_t, buddy_link)->refcount = 0;
     432}
     433
     434static buddy_system_operations_t zone_buddy_system_operations = {
     435        .find_buddy = zone_buddy_find_buddy,
     436        .bisect = zone_buddy_bisect,
     437        .coalesce = zone_buddy_coalesce,
     438        .set_order = zone_buddy_set_order,
     439        .get_order = zone_buddy_get_order,
     440        .mark_busy = zone_buddy_mark_busy,
     441        .mark_available = zone_buddy_mark_available,
     442        .find_block = zone_buddy_find_block
     443};
     444
    283445/******************/
    284446/* Zone functions */
    285447/******************/
    286448
    287 /** Return frame from zone. */
    288 NO_TRACE static frame_t *zone_get_frame(zone_t *zone, size_t index)
    289 {
    290         ASSERT(index < zone->count);
    291        
    292         return &zone->frames[index];
    293 }
    294 
    295449/** Allocate frame in particular zone.
    296450 *
     
    298452 * Panics if allocation is impossible.
    299453 *
    300  * @param zone       Zone to allocate from.
    301  * @param count      Number of frames to allocate
    302  * @param constraint Indication of bits that cannot be set in the
    303  *                   physical frame number of the first allocated frame.
     454 * @param zone  Zone to allocate from.
     455 * @param order Allocate exactly 2^order frames.
    304456 *
    305457 * @return Frame index in zone.
    306458 *
    307459 */
    308 NO_TRACE static size_t zone_frame_alloc(zone_t *zone, size_t count,
    309     pfn_t constraint)
     460NO_TRACE static pfn_t zone_frame_alloc(zone_t *zone, uint8_t order)
    310461{
    311462        ASSERT(zone->flags & ZONE_AVAILABLE);
    312463       
    313         /* Allocate frames from zone */
    314         size_t index;
    315         int avail = bitmap_allocate_range(&zone->bitmap, count, zone->base,
    316             constraint, &index);
    317        
    318         ASSERT(avail);
    319        
    320         /* Update frame reference count */
    321         for (size_t i = 0; i < count; i++) {
    322                 frame_t *frame = zone_get_frame(zone, index + i);
    323                
    324                 ASSERT(frame->refcount == 0);
    325                 frame->refcount = 1;
    326         }
     464        /* Allocate frames from zone buddy system */
     465        link_t *link = buddy_system_alloc(zone->buddy_system, order);
     466       
     467        ASSERT(link);
    327468       
    328469        /* Update zone information. */
    329         zone->free_count -= count;
    330         zone->busy_count += count;
    331        
    332         return index;
     470        zone->free_count -= (1 << order);
     471        zone->busy_count += (1 << order);
     472       
     473        /* Frame will be actually a first frame of the block. */
     474        frame_t *frame = list_get_instance(link, frame_t, buddy_link);
     475       
     476        /* Get frame address */
     477        return make_frame_index(zone, frame);
    333478}
    334479
     
    337482 * Assume zone is locked and is available for deallocation.
    338483 *
    339  * @param zone  Pointer to zone from which the frame is to be freed.
    340  * @param index Frame index relative to zone.
    341  *
    342  * @return Number of freed frames.
    343  *
    344  */
    345 NO_TRACE static size_t zone_frame_free(zone_t *zone, size_t index)
     484 * @param zone      Pointer to zone from which the frame is to be freed.
     485 * @param frame_idx Frame index relative to zone.
     486 *
     487 * @return          Number of freed frames.
     488 *
     489 */
     490NO_TRACE static size_t zone_frame_free(zone_t *zone, size_t frame_idx)
    346491{
    347492        ASSERT(zone->flags & ZONE_AVAILABLE);
    348493       
    349         frame_t *frame = zone_get_frame(zone, index);
    350        
    351         ASSERT(frame->refcount > 0);
     494        frame_t *frame = &zone->frames[frame_idx];
     495        size_t size = 0;
     496       
     497        ASSERT(frame->refcount);
    352498       
    353499        if (!--frame->refcount) {
    354                 bitmap_free_range(&zone->bitmap, index, 1);
    355                
     500                size = 1 << frame->buddy_order;
     501                buddy_system_free(zone->buddy_system, &frame->buddy_link);             
    356502                /* Update zone information. */
    357                 zone->free_count++;
    358                 zone->busy_count--;
    359                
    360                 return 1;
    361         }
    362        
    363         return 0;
     503                zone->free_count += size;
     504                zone->busy_count -= size;
     505        }
     506       
     507        return size;
     508}
     509
     510/** Return frame from zone. */
     511NO_TRACE static frame_t *zone_get_frame(zone_t *zone, size_t frame_idx)
     512{
     513        ASSERT(frame_idx < zone->count);
     514        return &zone->frames[frame_idx];
    364515}
    365516
    366517/** Mark frame in zone unavailable to allocation. */
    367 NO_TRACE static void zone_mark_unavailable(zone_t *zone, size_t index)
     518NO_TRACE static void zone_mark_unavailable(zone_t *zone, size_t frame_idx)
    368519{
    369520        if (!(zone->flags & ZONE_AVAILABLE))
    370521                return;
    371        
    372         frame_t *frame = zone_get_frame(zone, index);
    373         if (frame->refcount > 0)
     522//      ASSERT(zone->flags & ZONE_AVAILABLE);
     523       
     524        frame_t *frame = zone_get_frame(zone, frame_idx);
     525        if (frame->refcount)
    374526                return;
    375527       
    376         frame->refcount = 1;
    377         bitmap_set_range(&zone->bitmap, index, 1);
    378        
     528        link_t *link __attribute__ ((unused));
     529       
     530        link = buddy_system_alloc_block(zone->buddy_system,
     531            &frame->buddy_link);
     532       
     533        ASSERT(link);
    379534        zone->free_count--;
    380535        reserve_force_alloc(1);
     
    383538/** Merge two zones.
    384539 *
     540 * Expect buddy to point to space at least zone_conf_size large.
    385541 * Assume z1 & z2 are locked and compatible and zones lock is
    386542 * locked.
    387543 *
    388  * @param z1       First zone to merge.
    389  * @param z2       Second zone to merge.
    390  * @param old_z1   Original data of the first zone.
    391  * @param confdata Merged zone configuration data.
     544 * @param z1     First zone to merge.
     545 * @param z2     Second zone to merge.
     546 * @param old_z1 Original date of the first zone.
     547 * @param buddy  Merged zone buddy.
    392548 *
    393549 */
    394550NO_TRACE static void zone_merge_internal(size_t z1, size_t z2, zone_t *old_z1,
    395     void *confdata)
     551    buddy_system_t *buddy)
    396552{
    397553        ASSERT(zones.info[z1].flags & ZONE_AVAILABLE);
     
    408564        zones.info[z1].free_count += zones.info[z2].free_count;
    409565        zones.info[z1].busy_count += zones.info[z2].busy_count;
    410        
    411         bitmap_initialize(&zones.info[z1].bitmap, zones.info[z1].count,
    412             BITMAP_BLOCK_SIZE, confdata +
    413             (sizeof(frame_t) * zones.info[z1].count));
    414         bitmap_clear_range(&zones.info[z1].bitmap, 0, zones.info[z1].count);
    415        
    416         zones.info[z1].frames = (frame_t *) confdata;
    417        
    418         /*
    419          * Copy frames and bits from both zones to preserve parents, etc.
     566        zones.info[z1].buddy_system = buddy;
     567       
     568        uint8_t order = fnzb(zones.info[z1].count);
     569        buddy_system_create(zones.info[z1].buddy_system, order,
     570            &zone_buddy_system_operations, (void *) &zones.info[z1]);
     571       
     572        zones.info[z1].frames =
     573            (frame_t *) ((uint8_t *) zones.info[z1].buddy_system
     574            + buddy_conf_size(order));
     575       
     576        /* This marks all frames busy */
     577        size_t i;
     578        for (i = 0; i < zones.info[z1].count; i++)
     579                frame_initialize(&zones.info[z1].frames[i]);
     580       
     581        /* Copy frames from both zones to preserve full frame orders,
     582         * parents etc. Set all free frames with refcount = 0 to 1, because
     583         * we add all free frames to buddy allocator later again, clearing
     584         * order to 0. Don't set busy frames with refcount = 0, as they
     585         * will not be reallocated during merge and it would make later
     586         * problems with allocation/free.
    420587         */
    421        
    422         for (size_t i = 0; i < old_z1->count; i++) {
    423                 bitmap_set(&zones.info[z1].bitmap, i,
    424                     bitmap_get(&old_z1->bitmap, i));
     588        for (i = 0; i < old_z1->count; i++)
    425589                zones.info[z1].frames[i] = old_z1->frames[i];
    426         }
    427        
    428         for (size_t i = 0; i < zones.info[z2].count; i++) {
    429                 bitmap_set(&zones.info[z1].bitmap, base_diff + i,
    430                     bitmap_get(&zones.info[z2].bitmap, i));
    431                 zones.info[z1].frames[base_diff + i] =
    432                     zones.info[z2].frames[i];
     590       
     591        for (i = 0; i < zones.info[z2].count; i++)
     592                zones.info[z1].frames[base_diff + i]
     593                    = zones.info[z2].frames[i];
     594       
     595        i = 0;
     596        while (i < zones.info[z1].count) {
     597                if (zones.info[z1].frames[i].refcount) {
     598                        /* Skip busy frames */
     599                        i += 1 << zones.info[z1].frames[i].buddy_order;
     600                } else {
     601                        /* Free frames, set refcount = 1
     602                         * (all free frames have refcount == 0, we need not
     603                         * to check the order)
     604                         */
     605                        zones.info[z1].frames[i].refcount = 1;
     606                        zones.info[z1].frames[i].buddy_order = 0;
     607                        i++;
     608                }
     609        }
     610       
     611        /* Add free blocks from the original zone z1 */
     612        while (zone_can_alloc(old_z1, 0)) {
     613                /* Allocate from the original zone */
     614                pfn_t frame_idx = zone_frame_alloc(old_z1, 0);
     615               
     616                /* Free the frame from the merged zone */
     617                frame_t *frame = &zones.info[z1].frames[frame_idx];
     618                frame->refcount = 0;
     619                buddy_system_free(zones.info[z1].buddy_system, &frame->buddy_link);
     620        }
     621       
     622        /* Add free blocks from the original zone z2 */
     623        while (zone_can_alloc(&zones.info[z2], 0)) {
     624                /* Allocate from the original zone */
     625                pfn_t frame_idx = zone_frame_alloc(&zones.info[z2], 0);
     626               
     627                /* Free the frame from the merged zone */
     628                frame_t *frame = &zones.info[z1].frames[base_diff + frame_idx];
     629                frame->refcount = 0;
     630                buddy_system_free(zones.info[z1].buddy_system, &frame->buddy_link);
    433631        }
    434632}
     
    453651        size_t cframes = SIZE2FRAMES(zone_conf_size(count));
    454652       
    455         if ((pfn < zones.info[znum].base) ||
    456             (pfn >= zones.info[znum].base + zones.info[znum].count))
     653        if ((pfn < zones.info[znum].base)
     654            || (pfn >= zones.info[znum].base + zones.info[znum].count))
    457655                return;
    458656       
    459         for (size_t i = 0; i < cframes; i++)
     657        frame_t *frame __attribute__ ((unused));
     658
     659        frame = &zones.info[znum].frames[pfn - zones.info[znum].base];
     660        ASSERT(!frame->buddy_order);
     661       
     662        size_t i;
     663        for (i = 0; i < cframes; i++) {
     664                zones.info[znum].busy_count++;
    460665                (void) zone_frame_free(&zones.info[znum],
    461666                    pfn - zones.info[znum].base + i);
     667        }
     668}
     669
     670/** Reduce allocated block to count of order 0 frames.
     671 *
     672 * The allocated block needs 2^order frames. Reduce all frames
     673 * in the block to order 0 and free the unneeded frames. This means that
     674 * when freeing the previously allocated block starting with frame_idx,
     675 * you have to free every frame.
     676 *
     677 * @param znum      Zone.
     678 * @param frame_idx Index the first frame of the block.
     679 * @param count     Allocated frames in block.
     680 *
     681 */
     682NO_TRACE static void zone_reduce_region(size_t znum, pfn_t frame_idx,
     683    size_t count)
     684{
     685        ASSERT(zones.info[znum].flags & ZONE_AVAILABLE);
     686        ASSERT(frame_idx + count < zones.info[znum].count);
     687       
     688        uint8_t order = zones.info[znum].frames[frame_idx].buddy_order;
     689        ASSERT((size_t) (1 << order) >= count);
     690       
     691        /* Reduce all blocks to order 0 */
     692        size_t i;
     693        for (i = 0; i < (size_t) (1 << order); i++) {
     694                frame_t *frame = &zones.info[znum].frames[i + frame_idx];
     695                frame->buddy_order = 0;
     696                if (!frame->refcount)
     697                        frame->refcount = 1;
     698                ASSERT(frame->refcount == 1);
     699        }
     700       
     701        /* Free unneeded frames */
     702        for (i = count; i < (size_t) (1 << order); i++)
     703                (void) zone_frame_free(&zones.info[znum], i + frame_idx);
    462704}
    463705
     
    479721        bool ret = true;
    480722       
    481         /*
    482          * We can join only 2 zones with none existing inbetween,
     723        /* We can join only 2 zones with none existing inbetween,
    483724         * the zones have to be available and with the same
    484725         * set of flags
     
    494735            + zones.info[z2].count));
    495736       
     737        uint8_t order;
     738        if (cframes == 1)
     739                order = 0;
     740        else
     741                order = fnzb(cframes - 1) + 1;
     742       
    496743        /* Allocate merged zone data inside one of the zones */
    497744        pfn_t pfn;
    498         if (zone_can_alloc(&zones.info[z1], cframes, 0)) {
    499                 pfn = zones.info[z1].base +
    500                     zone_frame_alloc(&zones.info[z1], cframes, 0);
    501         } else if (zone_can_alloc(&zones.info[z2], cframes, 0)) {
    502                 pfn = zones.info[z2].base +
    503                     zone_frame_alloc(&zones.info[z2], cframes, 0);
     745        if (zone_can_alloc(&zones.info[z1], order)) {
     746                pfn = zones.info[z1].base + zone_frame_alloc(&zones.info[z1], order);
     747        } else if (zone_can_alloc(&zones.info[z2], order)) {
     748                pfn = zones.info[z2].base + zone_frame_alloc(&zones.info[z2], order);
    504749        } else {
    505750                ret = false;
     
    509754        /* Preserve original data from z1 */
    510755        zone_t old_z1 = zones.info[z1];
     756        old_z1.buddy_system->data = (void *) &old_z1;
    511757       
    512758        /* Do zone merging */
    513         zone_merge_internal(z1, z2, &old_z1, (void *) PA2KA(PFN2ADDR(pfn)));
     759        buddy_system_t *buddy = (buddy_system_t *) PA2KA(PFN2ADDR(pfn));
     760        zone_merge_internal(z1, z2, &old_z1, buddy);
     761       
     762        /* Free unneeded config frames */
     763        zone_reduce_region(z1, pfn - zones.info[z1].base, cframes);
    514764       
    515765        /* Subtract zone information from busy frames */
     
    524774       
    525775        /* Move zones down */
    526         for (size_t i = z2 + 1; i < zones.count; i++)
     776        size_t i;
     777        for (i = z2 + 1; i < zones.count; i++) {
    527778                zones.info[i - 1] = zones.info[i];
     779                if (zones.info[i - 1].buddy_system != NULL)
     780                        zones.info[i - 1].buddy_system->data =
     781                            (void *) &zones.info[i - 1];
     782        }
    528783       
    529784        zones.count--;
     
    544799void zone_merge_all(void)
    545800{
    546         size_t i = 1;
    547        
     801        size_t i = 0;
    548802        while (i < zones.count) {
    549                 if (!zone_merge(i - 1, i))
     803                if (!zone_merge(i, i + 1))
    550804                        i++;
    551805        }
     
    554808/** Create new frame zone.
    555809 *
    556  * @param zone     Zone to construct.
    557  * @param start    Physical address of the first frame within the zone.
    558  * @param count    Count of frames in zone.
    559  * @param flags    Zone flags.
    560  * @param confdata Configuration data of the zone.
     810 * @param zone  Zone to construct.
     811 * @param buddy Address of buddy system configuration information.
     812 * @param start Physical address of the first frame within the zone.
     813 * @param count Count of frames in zone.
     814 * @param flags Zone flags.
    561815 *
    562816 * @return Initialized zone.
    563817 *
    564818 */
    565 NO_TRACE static void zone_construct(zone_t *zone, pfn_t start, size_t count,
    566     zone_flags_t flags, void *confdata)
     819NO_TRACE static void zone_construct(zone_t *zone, buddy_system_t *buddy,
     820    pfn_t start, size_t count, zone_flags_t flags)
    567821{
    568822        zone->base = start;
     
    571825        zone->free_count = count;
    572826        zone->busy_count = 0;
     827        zone->buddy_system = buddy;
    573828       
    574829        if (flags & ZONE_AVAILABLE) {
    575830                /*
    576                  * Initialize frame bitmap (located after the array of
    577                  * frame_t structures in the configuration space).
     831                 * Compute order for buddy system and initialize
    578832                 */
    579                
    580                 bitmap_initialize(&zone->bitmap, count, BITMAP_BLOCK_SIZE,
    581                     confdata + (sizeof(frame_t) * count));
    582                 bitmap_clear_range(&zone->bitmap, 0, count);
    583                
    584                 /*
    585                  * Initialize the array of frame_t structures.
    586                  */
    587                
    588                 zone->frames = (frame_t *) confdata;
    589                
    590                 for (size_t i = 0; i < count; i++)
     833                uint8_t order = fnzb(count);
     834                buddy_system_create(zone->buddy_system, order,
     835                    &zone_buddy_system_operations, (void *) zone);
     836               
     837                /* Allocate frames _after_ the confframe */
     838               
     839                /* Check sizes */
     840                zone->frames = (frame_t *) ((uint8_t *) zone->buddy_system +
     841                    buddy_conf_size(order));
     842               
     843                size_t i;
     844                for (i = 0; i < count; i++)
    591845                        frame_initialize(&zone->frames[i]);
    592         } else {
    593                 bitmap_initialize(&zone->bitmap, 0, 0, NULL);
     846               
     847                /* Stuffing frames */
     848                for (i = 0; i < count; i++) {
     849                        zone->frames[i].refcount = 0;
     850                        buddy_system_free(zone->buddy_system, &zone->frames[i].buddy_link);
     851                }
     852        } else
    594853                zone->frames = NULL;
    595         }
    596854}
    597855
     
    605863size_t zone_conf_size(size_t count)
    606864{
    607         return (count * sizeof(frame_t) +
    608             bitmap_size(count, BITMAP_BLOCK_SIZE));
     865        return (count * sizeof(frame_t) + buddy_conf_size(fnzb(count)));
    609866}
    610867
     
    612869pfn_t zone_external_conf_alloc(size_t count)
    613870{
    614         size_t frames = SIZE2FRAMES(zone_conf_size(count));
    615        
    616         return ADDR2PFN((uintptr_t)
    617             frame_alloc(frames, FRAME_LOWMEM | FRAME_ATOMIC, 0));
     871        size_t size = zone_conf_size(count);
     872        size_t order = ispwr2(size) ? fnzb(size) : (fnzb(size) + 1);
     873
     874        return ADDR2PFN((uintptr_t) frame_alloc(order - FRAME_WIDTH,
     875            FRAME_LOWMEM | FRAME_ATOMIC));
    618876}
    619877
     
    623881 * @param count     Size of zone in frames.
    624882 * @param confframe Where configuration frames are supposed to be.
    625  *                  Automatically checks that we will not disturb the
     883 *                  Automatically checks, that we will not disturb the
    626884 *                  kernel and possibly init. If confframe is given
    627885 *                  _outside_ this zone, it is expected, that the area is
     
    640898       
    641899        if (flags & ZONE_AVAILABLE) {  /* Create available zone */
    642                 /*
    643                  * Theoretically we could have NULL here, practically make sure
     900                /* Theoretically we could have NULL here, practically make sure
    644901                 * nobody tries to do that. If some platform requires, remove
    645902                 * the assert
    646903                 */
    647904                ASSERT(confframe != ADDR2PFN((uintptr_t ) NULL));
    648                
     905
    649906                /* Update the known end of physical memory. */
    650907                config.physmem_end = max(config.physmem_end, PFN2ADDR(start + count));
    651908               
    652                 /*
    653                  * If confframe is supposed to be inside our zone, then make sure
     909                /* If confframe is supposed to be inside our zone, then make sure
    654910                 * it does not span kernel & init
    655911                 */
    656912                size_t confcount = SIZE2FRAMES(zone_conf_size(count));
    657                
    658913                if ((confframe >= start) && (confframe < start + count)) {
    659914                        for (; confframe < start + count; confframe++) {
     
    668923                               
    669924                                bool overlap = false;
    670                                 for (size_t i = 0; i < init.cnt; i++) {
     925                                size_t i;
     926                                for (i = 0; i < init.cnt; i++)
    671927                                        if (overlaps(addr, PFN2ADDR(confcount),
    672928                                            init.tasks[i].paddr,
     
    675931                                                break;
    676932                                        }
    677                                 }
    678                                
    679933                                if (overlap)
    680934                                        continue;
     
    683937                        }
    684938                       
    685                         if (confframe >= start + count)
    686                                 panic("Cannot find configuration data for zone.");
     939                        if (confframe >= start + count) {
     940                                flags &= ~ZONE_AVAILABLE;
     941                                goto nonavail;
     942//                              panic("Cannot find configuration data for zone.");
     943                        }
    687944                }
    688945               
     
    693950                }
    694951               
    695                 void *confdata = (void *) PA2KA(PFN2ADDR(confframe));
    696                 zone_construct(&zones.info[znum], start, count, flags, confdata);
     952                buddy_system_t *buddy = (buddy_system_t *) PA2KA(PFN2ADDR(confframe));
     953                zone_construct(&zones.info[znum], buddy, start, count, flags);
    697954               
    698955                /* If confdata in zone, mark as unavailable */
    699956                if ((confframe >= start) && (confframe < start + count)) {
    700                         for (size_t i = confframe; i < confframe + confcount; i++)
     957                        size_t i;
     958                        for (i = confframe; i < confframe + confcount; i++)
    701959                                zone_mark_unavailable(&zones.info[znum],
    702960                                    i - zones.info[znum].base);
     
    707965                return znum;
    708966        }
    709        
     967nonavail:
     968        (void)0; // label trick
    710969        /* Non-available zone */
    711970        size_t znum = zones_insert_zone(start, count, flags);
     
    714973                return (size_t) -1;
    715974        }
    716        
    717         zone_construct(&zones.info[znum], start, count, flags, NULL);
     975        zone_construct(&zones.info[znum], NULL, start, count, flags);
    718976       
    719977        irq_spinlock_unlock(&zones.lock, true);
     
    7571015}
    7581016
    759 /** Allocate frames of physical memory.
    760  *
    761  * @param count      Number of continuous frames to allocate.
    762  * @param flags      Flags for host zone selection and address processing.
    763  * @param constraint Indication of physical address bits that cannot be
    764  *                   set in the address of the first allocated frame.
    765  * @param pzone      Preferred zone.
     1017/** Allocate power-of-two frames of physical memory.
     1018 *
     1019 * @param order Allocate exactly 2^order frames.
     1020 * @param flags Flags for host zone selection and address processing.
     1021 * @param pzone Preferred zone.
    7661022 *
    7671023 * @return Physical address of the allocated frame.
    7681024 *
    7691025 */
    770 uintptr_t frame_alloc_generic(size_t count, frame_flags_t flags,
    771     uintptr_t constraint, size_t *pzone)
    772 {
    773         ASSERT(count > 0);
    774        
     1026void *frame_alloc_generic(uint8_t order, frame_flags_t flags, size_t *pzone)
     1027{
     1028        size_t size = ((size_t) 1) << order;
    7751029        size_t hint = pzone ? (*pzone) : 0;
    776         pfn_t frame_constraint = ADDR2PFN(constraint);
    7771030       
    7781031        /*
    7791032         * If not told otherwise, we must first reserve the memory.
    7801033         */
    781         if (!(flags & FRAME_NO_RESERVE))
    782                 reserve_force_alloc(count);
    783        
     1034        if (!(flags & FRAME_NO_RESERVE)) 
     1035                reserve_force_alloc(size);
     1036
    7841037loop:
    7851038        irq_spinlock_lock(&zones.lock, true);
     
    7881041         * First, find suitable frame zone.
    7891042         */
    790         size_t znum = find_free_zone(count, FRAME_TO_ZONE_FLAGS(flags),
    791             frame_constraint, hint);
    792        
    793         /*
    794          * If no memory, reclaim some slab memory,
    795          * if it does not help, reclaim all.
    796          */
     1043        size_t znum = find_free_zone(order,
     1044            FRAME_TO_ZONE_FLAGS(flags), hint);
     1045       
     1046        /* If no memory, reclaim some slab memory,
     1047           if it does not help, reclaim all */
    7971048        if ((znum == (size_t) -1) && (!(flags & FRAME_NO_RECLAIM))) {
    7981049                irq_spinlock_unlock(&zones.lock, true);
     
    8011052               
    8021053                if (freed > 0)
    803                         znum = find_free_zone(count, FRAME_TO_ZONE_FLAGS(flags),
    804                             frame_constraint, hint);
     1054                        znum = find_free_zone(order,
     1055                            FRAME_TO_ZONE_FLAGS(flags), hint);
    8051056               
    8061057                if (znum == (size_t) -1) {
     
    8101061                       
    8111062                        if (freed > 0)
    812                                 znum = find_free_zone(count, FRAME_TO_ZONE_FLAGS(flags),
    813                                     frame_constraint, hint);
     1063                                znum = find_free_zone(order,
     1064                                    FRAME_TO_ZONE_FLAGS(flags), hint);
    8141065                }
    8151066        }
     
    8181069                if (flags & FRAME_ATOMIC) {
    8191070                        irq_spinlock_unlock(&zones.lock, true);
    820                        
    8211071                        if (!(flags & FRAME_NO_RESERVE))
    822                                 reserve_free(count);
    823                        
    824                         return 0;
     1072                                reserve_free(size);
     1073                        return NULL;
    8251074                }
    8261075               
     
    8321081               
    8331082                if (!THREAD)
    834                         panic("Cannot wait for %zu frames to become available "
    835                             "(%zu available).", count, avail);
     1083                        panic("Cannot wait for memory to become available.");
    8361084               
    8371085                /*
     
    8401088               
    8411089#ifdef CONFIG_DEBUG
    842                 printf("Thread %" PRIu64 " waiting for %zu frames "
    843                     "(%zu available).\n", THREAD->tid, count, avail);
     1090                printf("Thread %" PRIu64 " waiting for %zu frames, "
     1091                    "%zu available.\n", THREAD->tid, size, avail);
    8441092#endif
    8451093               
    8461094                /*
    847                  * Since the mem_avail_mtx is an active mutex, we need to
    848                  * disable interrupts to prevent deadlock with TLB shootdown.
     1095                 * Since the mem_avail_mtx is an active mutex, we need to disable interrupts
     1096                 * to prevent deadlock with TLB shootdown.
    8491097                 */
    8501098                ipl_t ipl = interrupts_disable();
     
    8521100               
    8531101                if (mem_avail_req > 0)
    854                         mem_avail_req = min(mem_avail_req, count);
     1102                        mem_avail_req = min(mem_avail_req, size);
    8551103                else
    856                         mem_avail_req = count;
    857                
     1104                        mem_avail_req = size;
    8581105                size_t gen = mem_avail_gen;
    8591106               
     
    8711118        }
    8721119       
    873         pfn_t pfn = zone_frame_alloc(&zones.info[znum], count,
    874             frame_constraint) + zones.info[znum].base;
     1120        pfn_t pfn = zone_frame_alloc(&zones.info[znum], order)
     1121            + zones.info[znum].base;
    8751122       
    8761123        irq_spinlock_unlock(&zones.lock, true);
     
    8791126                *pzone = znum;
    8801127       
    881         return PFN2ADDR(pfn);
    882 }
    883 
    884 uintptr_t frame_alloc(size_t count, frame_flags_t flags, uintptr_t constraint)
    885 {
    886         return frame_alloc_generic(count, flags, constraint, NULL);
    887 }
    888 
    889 uintptr_t frame_alloc_noreserve(size_t count, frame_flags_t flags,
    890     uintptr_t constraint)
    891 {
    892         return frame_alloc_generic(count, flags | FRAME_NO_RESERVE, constraint,
    893             NULL);
    894 }
    895 
    896 /** Free frames of physical memory.
    897  *
    898  * Find respective frame structures for supplied physical frames.
    899  * Decrement each frame reference count. If it drops to zero, mark
    900  * the frames as available.
    901  *
    902  * @param start Physical Address of the first frame to be freed.
    903  * @param count Number of frames to free.
     1128        if (flags & FRAME_KA)
     1129                return (void *) PA2KA(PFN2ADDR(pfn));
     1130       
     1131        return (void *) PFN2ADDR(pfn);
     1132}
     1133
     1134void *frame_alloc(uint8_t order, frame_flags_t flags)
     1135{
     1136        return frame_alloc_generic(order, flags, NULL);
     1137}
     1138
     1139void *frame_alloc_noreserve(uint8_t order, frame_flags_t flags)
     1140{
     1141        return frame_alloc_generic(order, flags | FRAME_NO_RESERVE, NULL);
     1142}
     1143
     1144/** Free a frame.
     1145 *
     1146 * Find respective frame structure for supplied physical frame address.
     1147 * Decrement frame reference count. If it drops to zero, move the frame
     1148 * structure to free list.
     1149 *
     1150 * @param frame Physical Address of of the frame to be freed.
    9041151 * @param flags Flags to control memory reservation.
    9051152 *
    9061153 */
    907 void frame_free_generic(uintptr_t start, size_t count, frame_flags_t flags)
    908 {
    909         size_t freed = 0;
     1154void frame_free_generic(uintptr_t frame, frame_flags_t flags)
     1155{
     1156        size_t size;
    9101157       
    9111158        irq_spinlock_lock(&zones.lock, true);
    9121159       
    913         for (size_t i = 0; i < count; i++) {
    914                 /*
    915                  * First, find host frame zone for addr.
    916                  */
    917                 pfn_t pfn = ADDR2PFN(start) + i;
    918                 size_t znum = find_zone(pfn, 1, 0);
    919                
    920                 ASSERT(znum != (size_t) -1);
    921                
    922                 freed += zone_frame_free(&zones.info[znum],
    923                     pfn - zones.info[znum].base);
    924         }
     1160        /*
     1161         * First, find host frame zone for addr.
     1162         */
     1163        pfn_t pfn = ADDR2PFN(frame);
     1164        size_t znum = find_zone(pfn, 1, 0);
     1165
     1166        ASSERT(znum != (size_t) -1);
     1167       
     1168        size = zone_frame_free(&zones.info[znum], pfn - zones.info[znum].base);
    9251169       
    9261170        irq_spinlock_unlock(&zones.lock, true);
     
    9281172        /*
    9291173         * Signal that some memory has been freed.
    930          * Since the mem_avail_mtx is an active mutex,
    931          * we need to disable interruptsto prevent deadlock
    932          * with TLB shootdown.
    9331174         */
    934        
     1175
     1176       
     1177        /*
     1178         * Since the mem_avail_mtx is an active mutex, we need to disable interrupts
     1179         * to prevent deadlock with TLB shootdown.
     1180         */
    9351181        ipl_t ipl = interrupts_disable();
    9361182        mutex_lock(&mem_avail_mtx);
    937        
    9381183        if (mem_avail_req > 0)
    939                 mem_avail_req -= min(mem_avail_req, freed);
     1184                mem_avail_req -= min(mem_avail_req, size);
    9401185       
    9411186        if (mem_avail_req == 0) {
     
    9431188                condvar_broadcast(&mem_avail_cv);
    9441189        }
    945        
    9461190        mutex_unlock(&mem_avail_mtx);
    9471191        interrupts_restore(ipl);
    9481192       
    9491193        if (!(flags & FRAME_NO_RESERVE))
    950                 reserve_free(freed);
    951 }
    952 
    953 void frame_free(uintptr_t frame, size_t count)
    954 {
    955         frame_free_generic(frame, count, 0);
    956 }
    957 
    958 void frame_free_noreserve(uintptr_t frame, size_t count)
    959 {
    960         frame_free_generic(frame, count, FRAME_NO_RESERVE);
     1194                reserve_free(size);
     1195}
     1196
     1197void frame_free(uintptr_t frame)
     1198{
     1199        frame_free_generic(frame, 0);
     1200}
     1201
     1202void frame_free_noreserve(uintptr_t frame)
     1203{
     1204        frame_free_generic(frame, FRAME_NO_RESERVE);
    9611205}
    9621206
     
    9921236        irq_spinlock_lock(&zones.lock, true);
    9931237       
    994         for (size_t i = 0; i < count; i++) {
     1238        size_t i;
     1239        for (i = 0; i < count; i++) {
    9951240                size_t znum = find_zone(start + i, 1, 0);
    996                
    9971241                if (znum == (size_t) -1)  /* PFN not found */
    9981242                        continue;
     
    10191263        /* Tell the architecture to create some memory */
    10201264        frame_low_arch_init();
    1021        
    10221265        if (config.cpu_active == 1) {
    10231266                frame_mark_unavailable(ADDR2PFN(KA2PA(config.base)),
     
    10261269                    SIZE2FRAMES(config.stack_size));
    10271270               
    1028                 for (size_t i = 0; i < init.cnt; i++)
    1029                         frame_mark_unavailable(ADDR2PFN(init.tasks[i].paddr),
     1271                size_t i;
     1272                for (i = 0; i < init.cnt; i++) {
     1273                        pfn_t pfn = ADDR2PFN(init.tasks[i].paddr);
     1274                        frame_mark_unavailable(pfn,
    10301275                            SIZE2FRAMES(init.tasks[i].size));
     1276                }
    10311277               
    10321278                if (ballocs.size)
     
    10341280                            SIZE2FRAMES(ballocs.size));
    10351281               
    1036                 /*
    1037                  * Blacklist first frame, as allocating NULL would
     1282                /* Black list first frame, as allocating NULL would
    10381283                 * fail in some places
    10391284                 */
    10401285                frame_mark_unavailable(0, 1);
    10411286        }
    1042        
    10431287        frame_high_arch_init();
    10441288}
     
    10461290/** Adjust bounds of physical memory region according to low/high memory split.
    10471291 *
    1048  * @param low[in]      If true, the adjustment is performed to make the region
    1049  *                     fit in the low memory. Otherwise the adjustment is
    1050  *                     performed to make the region fit in the high memory.
    1051  * @param basep[inout] Pointer to a variable which contains the region's base
    1052  *                     address and which may receive the adjusted base address.
    1053  * @param sizep[inout] Pointer to a variable which contains the region's size
    1054  *                     and which may receive the adjusted size.
    1055  *
    1056  * @return True if the region still exists even after the adjustment.
    1057  * @return False otherwise.
    1058  *
     1292 * @param low[in]       If true, the adjustment is performed to make the region
     1293 *                      fit in the low memory. Otherwise the adjustment is
     1294 *                      performed to make the region fit in the high memory.
     1295 * @param basep[inout]  Pointer to a variable which contains the region's base
     1296 *                      address and which may receive the adjusted base address.
     1297 * @param sizep[inout]  Pointer to a variable which contains the region's size
     1298 *                      and which may receive the adjusted size.
     1299 * @retun               True if the region still exists even after the
     1300 *                      adjustment, false otherwise.
    10591301 */
    10601302bool frame_adjust_zone_bounds(bool low, uintptr_t *basep, size_t *sizep)
    10611303{
    10621304        uintptr_t limit = KA2PA(config.identity_base) + config.identity_size;
    1063        
     1305
    10641306        if (low) {
    10651307                if (*basep > limit)
    10661308                        return false;
    1067                
    10681309                if (*basep + *sizep > limit)
    10691310                        *sizep = limit - *basep;
     
    10711312                if (*basep + *sizep <= limit)
    10721313                        return false;
    1073                
    10741314                if (*basep <= limit) {
    10751315                        *sizep -= limit - *basep;
     
    10771317                }
    10781318        }
    1079        
    10801319        return true;
    10811320}
     
    10891328       
    10901329        uint64_t total = 0;
    1091        
    1092         for (size_t i = 0; i < zones.count; i++)
     1330        size_t i;
     1331        for (i = 0; i < zones.count; i++)
    10931332                total += (uint64_t) FRAMES2SIZE(zones.info[i].count);
    10941333       
     
    11131352        *free = 0;
    11141353       
    1115         for (size_t i = 0; i < zones.count; i++) {
     1354        size_t i;
     1355        for (i = 0; i < zones.count; i++) {
    11161356                *total += (uint64_t) FRAMES2SIZE(zones.info[i].count);
    11171357               
     
    11501390         */
    11511391       
    1152         for (size_t i = 0;; i++) {
     1392        size_t i;
     1393        for (i = 0;; i++) {
    11531394                irq_spinlock_lock(&zones.lock, true);
    11541395               
     
    12031444        size_t znum = (size_t) -1;
    12041445       
    1205         for (size_t i = 0; i < zones.count; i++) {
     1446        size_t i;
     1447        for (i = 0; i < zones.count; i++) {
    12061448                if ((i == num) || (PFN2ADDR(zones.info[i].base) == num)) {
    12071449                        znum = i;
     
    12161458        }
    12171459       
    1218         uintptr_t base = PFN2ADDR(zones.info[znum].base);
    1219         zone_flags_t flags = zones.info[znum].flags;
    1220         size_t count = zones.info[znum].count;
    1221         size_t free_count = zones.info[znum].free_count;
    1222         size_t busy_count = zones.info[znum].busy_count;
     1460        uintptr_t base = PFN2ADDR(zones.info[i].base);
     1461        zone_flags_t flags = zones.info[i].flags;
     1462        size_t count = zones.info[i].count;
     1463        size_t free_count = zones.info[i].free_count;
     1464        size_t busy_count = zones.info[i].busy_count;
    12231465       
    12241466        irq_spinlock_unlock(&zones.lock, true);
Note: See TracChangeset for help on using the changeset viewer.