frame.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2005 Jakub Jermar
00003  * Copyright (C) 2005 Sergey Bondari
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * - Redistributions of source code must retain the above copyright
00011  *   notice, this list of conditions and the following disclaimer.
00012  * - Redistributions in binary form must reproduce the above copyright
00013  *   notice, this list of conditions and the following disclaimer in the
00014  *   documentation and/or other materials provided with the distribution.
00015  * - The name of the author may not be used to endorse or promote products
00016  *   derived from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00019  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00020  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00021  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00023  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00024  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00025  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00026  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00027  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00044 /*
00045  * Locking order
00046  *
00047  * In order to access particular zone, the process must first lock
00048  * the zones.lock, then lock the zone and then unlock the zones.lock.
00049  * This insures, that we can fiddle with the zones in runtime without
00050  * affecting the processes. 
00051  *
00052  */
00053 
00054 #include <typedefs.h>
00055 #include <arch/types.h>
00056 #include <mm/frame.h>
00057 #include <mm/as.h>
00058 #include <panic.h>
00059 #include <debug.h>
00060 #include <adt/list.h>
00061 #include <synch/spinlock.h>
00062 #include <arch/asm.h>
00063 #include <arch.h>
00064 #include <print.h>
00065 #include <align.h>
00066 #include <mm/slab.h>
00067 #include <bitops.h>
00068 #include <macros.h>
00069 
00070 typedef struct {
00071         count_t refcount;       
00072         __u8 buddy_order;       
00073         link_t buddy_link;      
00074         void *parent;           
00075 } frame_t;
00076 
00077 typedef struct {
00078         SPINLOCK_DECLARE(lock); 
00079         pfn_t base;             
00080         count_t count;          
00082         frame_t *frames;        
00083         count_t free_count;     
00084         count_t busy_count;     
00086         buddy_system_t * buddy_system; 
00087         int flags;
00088 } zone_t;
00089 
00090 /*
00091  * The zoneinfo.lock must be locked when accessing zoneinfo structure.
00092  * Some of the attributes in zone_t structures are 'read-only'
00093  */
00094 
00095 struct {
00096         SPINLOCK_DECLARE(lock);
00097         int count;
00098         zone_t *info[ZONES_MAX];
00099 } zones;
00100 
00101 
00102 /*********************************/
00103 /* Helper functions */
00104 static inline index_t frame_index(zone_t *zone, frame_t *frame)
00105 {
00106         return (index_t)(frame - zone->frames);
00107 }
00108 static inline index_t frame_index_abs(zone_t *zone, frame_t *frame)
00109 {
00110         return (index_t)(frame - zone->frames) + zone->base;
00111 }
00112 static inline int frame_index_valid(zone_t *zone, index_t index)
00113 {
00114         return index >= 0 && index < zone->count;
00115 }
00116 
00118 static index_t make_frame_index(zone_t *zone, frame_t *frame)
00119 {
00120         return frame - zone->frames;
00121 }
00122 
00129 static void frame_initialize(frame_t *frame)
00130 {
00131         frame->refcount = 1;
00132         frame->buddy_order = 0;
00133 }
00134 
00135 /*************************************/
00136 /* Zoneinfo functions */
00137 
00144 static int zones_add_zone(zone_t *newzone)
00145 {
00146         int i,j;
00147         ipl_t ipl;
00148         zone_t *z;
00149 
00150         ipl = interrupts_disable();
00151         spinlock_lock(&zones.lock);
00152         /* Try to merge */
00153         if (zones.count + 1 == ZONES_MAX)
00154                 panic("Maximum zone(%d) count exceeded.", ZONES_MAX);
00155         for (i = 0; i < zones.count; i++) {
00156                 /* Check for overflow */
00157                 z = zones.info[i];
00158                 if (overlaps(newzone->base,newzone->count,
00159                              z->base, z->count)) {
00160                         printf("Zones overlap!\n");
00161                         return -1;
00162                 }
00163                 if (newzone->base < z->base)
00164                         break;
00165         }
00166         /* Move other zones up */
00167         for (j = i;j < zones.count; j++)
00168                 zones.info[j + 1] = zones.info[j];
00169         zones.info[i] = newzone;
00170         zones.count++;
00171         spinlock_unlock(&zones.lock);
00172         interrupts_restore(ipl);
00173 
00174         return i;
00175 }
00176 
00187 static zone_t * find_zone_and_lock(pfn_t frame, int *pzone)
00188 {
00189         int i;
00190         int hint = pzone ? *pzone : 0;
00191         zone_t *z;
00192         
00193         spinlock_lock(&zones.lock);
00194 
00195         if (hint >= zones.count || hint < 0)
00196                 hint = 0;
00197         
00198         i = hint;
00199         do {
00200                 z = zones.info[i];
00201                 spinlock_lock(&z->lock);
00202                 if (z->base <= frame && z->base + z->count > frame) {
00203                         spinlock_unlock(&zones.lock); /* Unlock the global lock */
00204                         if (pzone)
00205                                 *pzone = i;
00206                         return z;
00207                 }
00208                 spinlock_unlock(&z->lock);
00209 
00210                 i++;
00211                 if (i >= zones.count)
00212                         i = 0;
00213         } while(i != hint);
00214 
00215         spinlock_unlock(&zones.lock);
00216         return NULL;
00217 }
00218 
00220 static int zone_can_alloc(zone_t *z, __u8 order)
00221 {
00222         return buddy_system_can_alloc(z->buddy_system, order);
00223 }
00224 
00233 static zone_t * find_free_zone_lock(__u8 order, int *pzone)
00234 {
00235         int i;
00236         zone_t *z;
00237         int hint = pzone ? *pzone : 0;
00238         
00239         spinlock_lock(&zones.lock);
00240         if (hint >= zones.count)
00241                 hint = 0;
00242         i = hint;
00243         do {
00244                 z = zones.info[i];
00245                 
00246                 spinlock_lock(&z->lock);
00247 
00248                 /* Check if the zone has 2^order frames area available  */
00249                 if (zone_can_alloc(z, order)) {
00250                         spinlock_unlock(&zones.lock);
00251                         if (pzone)
00252                                 *pzone = i;
00253                         return z;
00254                 }
00255                 spinlock_unlock(&z->lock);
00256                 if (++i >= zones.count)
00257                         i = 0;
00258         } while(i != hint);
00259         spinlock_unlock(&zones.lock);
00260         return NULL;
00261 }
00262 
00263 /********************************************/
00264 /* Buddy system functions */
00265 
00273 static link_t *zone_buddy_find_block(buddy_system_t *b, link_t *child,
00274                                      __u8 order)
00275 {
00276         frame_t * frame;
00277         zone_t * zone;
00278         index_t index;
00279         
00280         frame = list_get_instance(child, frame_t, buddy_link);
00281         zone = (zone_t *) b->data;
00282 
00283         index = frame_index(zone, frame);
00284         do {
00285                 if (zone->frames[index].buddy_order != order) {
00286                         return &zone->frames[index].buddy_link;
00287                 }
00288         } while(index-- > 0);
00289         return NULL;
00290 }
00291 
00292 static void zone_buddy_print_id(buddy_system_t *b, link_t *block)
00293 {
00294         frame_t * frame;
00295         zone_t * zone;
00296         index_t index;
00297 
00298         frame = list_get_instance(block, frame_t, buddy_link);
00299         zone = (zone_t *) b->data;
00300         index = frame_index(zone, frame);
00301         printf("%zd", index);
00302 }                                    
00303 
00311 static link_t * zone_buddy_find_buddy(buddy_system_t *b, link_t * block) 
00312 {
00313         frame_t * frame;
00314         zone_t * zone;
00315         index_t index;
00316         bool is_left, is_right;
00317 
00318         frame = list_get_instance(block, frame_t, buddy_link);
00319         zone = (zone_t *) b->data;
00320         ASSERT(IS_BUDDY_ORDER_OK(frame_index_abs(zone, frame), frame->buddy_order));
00321         
00322         is_left = IS_BUDDY_LEFT_BLOCK_ABS(zone, frame);
00323         is_right = IS_BUDDY_RIGHT_BLOCK_ABS(zone, frame);
00324 
00325         ASSERT(is_left ^ is_right);
00326         if (is_left) {
00327                 index = (frame_index(zone, frame)) + (1 << frame->buddy_order);
00328         } else { // if (is_right)
00329                 index = (frame_index(zone, frame)) - (1 << frame->buddy_order);
00330         }
00331         
00332         if (frame_index_valid(zone, index)) {
00333                 if (zone->frames[index].buddy_order == frame->buddy_order && 
00334                     zone->frames[index].refcount == 0) {
00335                         return &zone->frames[index].buddy_link;
00336                 }
00337         }
00338 
00339         return NULL;    
00340 }
00341 
00349 static link_t * zone_buddy_bisect(buddy_system_t *b, link_t * block) {
00350         frame_t * frame_l, * frame_r;
00351 
00352         frame_l = list_get_instance(block, frame_t, buddy_link);
00353         frame_r = (frame_l + (1 << (frame_l->buddy_order - 1)));
00354         
00355         return &frame_r->buddy_link;
00356 }
00357 
00366 static link_t * zone_buddy_coalesce(buddy_system_t *b, link_t * block_1, 
00367                                     link_t * block_2) 
00368 {
00369         frame_t *frame1, *frame2;
00370         
00371         frame1 = list_get_instance(block_1, frame_t, buddy_link);
00372         frame2 = list_get_instance(block_2, frame_t, buddy_link);
00373         
00374         return frame1 < frame2 ? block_1 : block_2;
00375 }
00376 
00383 static void zone_buddy_set_order(buddy_system_t *b, link_t * block, __u8 order) {
00384         frame_t * frame;
00385         frame = list_get_instance(block, frame_t, buddy_link);
00386         frame->buddy_order = order;
00387 }
00388 
00396 static __u8 zone_buddy_get_order(buddy_system_t *b, link_t * block) {
00397         frame_t * frame;
00398         frame = list_get_instance(block, frame_t, buddy_link);
00399         return frame->buddy_order;
00400 }
00401 
00408 static void zone_buddy_mark_busy(buddy_system_t *b, link_t * block) {
00409         frame_t * frame;
00410 
00411         frame = list_get_instance(block, frame_t, buddy_link);
00412         frame->refcount = 1;
00413 }
00414 
00421 static void zone_buddy_mark_available(buddy_system_t *b, link_t * block) {
00422         frame_t * frame;
00423         frame = list_get_instance(block, frame_t, buddy_link);
00424         frame->refcount = 0;
00425 }
00426 
00427 static struct buddy_system_operations  zone_buddy_system_operations = {
00428         .find_buddy = zone_buddy_find_buddy,
00429         .bisect = zone_buddy_bisect,
00430         .coalesce = zone_buddy_coalesce,
00431         .set_order = zone_buddy_set_order,
00432         .get_order = zone_buddy_get_order,
00433         .mark_busy = zone_buddy_mark_busy,
00434         .mark_available = zone_buddy_mark_available,
00435         .find_block = zone_buddy_find_block,
00436         .print_id = zone_buddy_print_id
00437 };
00438 
00439 /*************************************/
00440 /* Zone functions */
00441 
00453 static pfn_t zone_frame_alloc(zone_t *zone, __u8 order)
00454 {
00455         pfn_t v;
00456         link_t *tmp;
00457         frame_t *frame;
00458 
00459         /* Allocate frames from zone buddy system */
00460         tmp = buddy_system_alloc(zone->buddy_system, order);
00461         
00462         ASSERT(tmp);
00463         
00464         /* Update zone information. */
00465         zone->free_count -= (1 << order);
00466         zone->busy_count += (1 << order);
00467 
00468         /* Frame will be actually a first frame of the block. */
00469         frame = list_get_instance(tmp, frame_t, buddy_link);
00470         
00471         /* get frame address */
00472         v = make_frame_index(zone, frame);
00473         return v;
00474 }
00475 
00483 static void zone_frame_free(zone_t *zone, index_t frame_idx)
00484 {
00485         frame_t *frame;
00486         __u8 order;
00487 
00488         frame = &zone->frames[frame_idx];
00489         
00490         /* remember frame order */
00491         order = frame->buddy_order;
00492 
00493         ASSERT(frame->refcount);
00494 
00495         if (!--frame->refcount) {
00496                 buddy_system_free(zone->buddy_system, &frame->buddy_link);
00497         
00498                 /* Update zone information. */
00499                 zone->free_count += (1 << order);
00500                 zone->busy_count -= (1 << order);
00501         }
00502 }
00503 
00505 static frame_t * zone_get_frame(zone_t *zone, index_t frame_idx)
00506 {
00507         ASSERT(frame_idx < zone->count);
00508         return &zone->frames[frame_idx];
00509 }
00510 
00512 static void zone_mark_unavailable(zone_t *zone, index_t frame_idx)
00513 {
00514         frame_t *frame;
00515         link_t *link;
00516 
00517         frame = zone_get_frame(zone, frame_idx);
00518         if (frame->refcount)
00519                 return;
00520         link = buddy_system_alloc_block(zone->buddy_system, 
00521                                         &frame->buddy_link);
00522         ASSERT(link);
00523         zone->free_count--;
00524 }
00525 
00538 static void _zone_merge(zone_t *z, zone_t *z1, zone_t *z2)
00539 {
00540         __u8 max_order;
00541         int i, z2idx;
00542         pfn_t frame_idx;
00543         frame_t *frame;
00544 
00545         ASSERT(!overlaps(z1->base,z1->count,z2->base,z2->count));
00546         ASSERT(z1->base < z2->base);
00547 
00548         spinlock_initialize(&z->lock, "zone_lock");
00549         z->base = z1->base;
00550         z->count = z2->base+z2->count - z1->base;
00551         z->flags = z1->flags & z2->flags;
00552 
00553         z->free_count = z1->free_count + z2->free_count;
00554         z->busy_count = z1->busy_count + z2->busy_count;
00555         
00556         max_order = fnzb(z->count);
00557 
00558         z->buddy_system = (buddy_system_t *)&z[1];
00559         buddy_system_create(z->buddy_system, max_order, 
00560                             &zone_buddy_system_operations, 
00561                             (void *) z);
00562 
00563         z->frames = (frame_t *)((void *)z->buddy_system+buddy_conf_size(max_order));
00564         for (i = 0; i < z->count; i++) {
00565                 /* This marks all frames busy */
00566                 frame_initialize(&z->frames[i]);
00567         }
00568         /* Copy frames from both zones to preserve full frame orders,
00569          * parents etc. Set all free frames with refcount=0 to 1, because
00570          * we add all free frames to buddy allocator later again, clear
00571          * order to 0. Don't set busy frames with refcount=0, as they
00572          * will not be reallocated during merge and it would make later
00573          * problems with allocation/free.
00574          */
00575         for (i=0; i<z1->count; i++)
00576                 z->frames[i] = z1->frames[i];
00577         for (i=0; i < z2->count; i++) {
00578                 z2idx = i + (z2->base - z1->base);
00579                 z->frames[z2idx] = z2->frames[i];
00580         }
00581         i = 0;
00582         while (i < z->count) {
00583                 if (z->frames[i].refcount) {
00584                         /* skip busy frames */
00585                         i += 1 << z->frames[i].buddy_order;
00586                 } else { /* Free frames, set refcount=1 */
00587                         /* All free frames have refcount=0, we need not
00588                          * to check the order */
00589                         z->frames[i].refcount = 1;
00590                         z->frames[i].buddy_order = 0;
00591                         i++;
00592                 }
00593         }
00594         /* Add free blocks from the 2 original zones */
00595         while (zone_can_alloc(z1, 0)) {
00596                 frame_idx = zone_frame_alloc(z1, 0);
00597                 frame = &z->frames[frame_idx];
00598                 frame->refcount = 0;
00599                 buddy_system_free(z->buddy_system, &frame->buddy_link);
00600         }
00601         while (zone_can_alloc(z2, 0)) {
00602                 frame_idx = zone_frame_alloc(z2, 0);
00603                 frame = &z->frames[frame_idx + (z2->base-z1->base)];
00604                 frame->refcount = 0;
00605                 buddy_system_free(z->buddy_system, &frame->buddy_link);
00606         }
00607 }
00608 
00620 static void return_config_frames(zone_t *newzone, zone_t *oldzone)
00621 {
00622         pfn_t pfn;
00623         frame_t *frame;
00624         count_t cframes;
00625         int i;
00626 
00627         pfn = ADDR2PFN((__address)KA2PA(oldzone));
00628         cframes = SIZE2FRAMES(zone_conf_size(oldzone->count));
00629         
00630         if (pfn < newzone->base || pfn >= newzone->base + newzone->count)
00631                 return;
00632 
00633         frame = &newzone->frames[pfn - newzone->base];
00634         ASSERT(!frame->buddy_order);
00635 
00636         for (i=0; i < cframes; i++) {
00637                 newzone->busy_count++;
00638                 zone_frame_free(newzone, pfn+i-newzone->base);
00639         }
00640 }
00641 
00653 static void zone_reduce_region(zone_t *zone, pfn_t frame_idx, count_t count)
00654 {
00655         count_t i;
00656         __u8 order;
00657         frame_t *frame;
00658         
00659         ASSERT(frame_idx+count < zone->count);
00660 
00661         order = zone->frames[frame_idx].buddy_order;
00662         ASSERT((1 << order) >= count);
00663 
00664         /* Reduce all blocks to order 0 */
00665         for (i=0; i < (1 << order); i++) {
00666                 frame = &zone->frames[i + frame_idx];
00667                 frame->buddy_order = 0;
00668                 if (! frame->refcount)
00669                         frame->refcount = 1;
00670                 ASSERT(frame->refcount == 1);
00671         }
00672         /* Free unneeded frames */
00673         for (i=count; i < (1 << order); i++) {
00674                 zone_frame_free(zone, i + frame_idx);
00675         }
00676 }
00677 
00687 void zone_merge(int z1, int z2)
00688 {
00689         ipl_t ipl;
00690         zone_t *zone1, *zone2, *newzone;
00691         int cframes;
00692         __u8 order;
00693         int i;
00694         pfn_t pfn;
00695 
00696         ipl = interrupts_disable();
00697         spinlock_lock(&zones.lock);
00698 
00699         if (z1 < 0 || z1 >= zones.count || z2 < 0 || z2 >= zones.count)
00700                 goto errout;
00701         /* We can join only 2 zones with none existing inbetween */
00702         if (z2-z1 != 1)
00703                 goto errout;
00704 
00705         zone1 = zones.info[z1];
00706         zone2 = zones.info[z2];
00707         spinlock_lock(&zone1->lock);
00708         spinlock_lock(&zone2->lock);
00709 
00710         cframes = SIZE2FRAMES(zone_conf_size(zone2->base+zone2->count-zone1->base));
00711         if (cframes == 1)
00712                 order = 0;
00713         else 
00714                 order = fnzb(cframes - 1) + 1;
00715 
00716         /* Allocate zonedata inside one of the zones */
00717         if (zone_can_alloc(zone1, order))
00718                 pfn = zone1->base + zone_frame_alloc(zone1, order);
00719         else if (zone_can_alloc(zone2, order))
00720                 pfn = zone2->base + zone_frame_alloc(zone2, order);
00721         else
00722                 goto errout2;
00723 
00724         newzone = (zone_t *)PA2KA(PFN2ADDR(pfn));
00725 
00726         _zone_merge(newzone, zone1, zone2);
00727 
00728         /* Free unneeded config frames */
00729         zone_reduce_region(newzone, pfn - newzone->base,  cframes);
00730         /* Subtract zone information from busy frames */
00731         newzone->busy_count -= cframes;
00732 
00733         /* Replace existing zones in zoneinfo list */
00734         zones.info[z1] = newzone;
00735         for (i = z2 + 1; i < zones.count; i++)
00736                 zones.info[i - 1] = zones.info[i];
00737         zones.count--;
00738 
00739         /* Free old zone information */
00740         return_config_frames(newzone, zone1);
00741         return_config_frames(newzone, zone2);
00742 errout2:
00743         /* Nobody is allowed to enter to zone, so we are safe
00744          * to touch the spinlocks last time */
00745         spinlock_unlock(&zone1->lock);
00746         spinlock_unlock(&zone2->lock);
00747 errout:
00748         spinlock_unlock(&zones.lock);
00749         interrupts_restore(ipl);
00750 }
00751 
00758 void zone_merge_all(void)
00759 {
00760         int count = zones.count;
00761 
00762         while (zones.count > 1 && --count) {
00763                 zone_merge(0,1);
00764                 break;
00765         }
00766 }
00767 
00779 static void zone_construct(pfn_t start, count_t count, zone_t *z, int flags)
00780 {
00781         int i;
00782         __u8 max_order;
00783 
00784         spinlock_initialize(&z->lock, "zone_lock");
00785         z->base = start;
00786         z->count = count;
00787         z->flags = flags;
00788         z->free_count = count;
00789         z->busy_count = 0;
00790 
00791         /*
00792          * Compute order for buddy system, initialize
00793          */
00794         max_order = fnzb(count);
00795         z->buddy_system = (buddy_system_t *)&z[1];
00796         
00797         buddy_system_create(z->buddy_system, max_order, 
00798                             &zone_buddy_system_operations, 
00799                             (void *) z);
00800         
00801         /* Allocate frames _after_ the conframe */
00802         /* Check sizes */
00803         z->frames = (frame_t *)((void *)z->buddy_system+buddy_conf_size(max_order));
00804         for (i = 0; i<count; i++) {
00805                 frame_initialize(&z->frames[i]);
00806         }
00807         
00808         /* Stuffing frames */
00809         for (i = 0; i < count; i++) {
00810                 z->frames[i].refcount = 0;
00811                 buddy_system_free(z->buddy_system, &z->frames[i].buddy_link);
00812         }
00813 }
00814 
00820 __address zone_conf_size(count_t count)
00821 {
00822         int size = sizeof(zone_t) + count*sizeof(frame_t);
00823         int max_order;
00824 
00825         max_order = fnzb(count);
00826         size += buddy_conf_size(max_order);
00827         return size;
00828 }
00829 
00845 int zone_create(pfn_t start, count_t count, pfn_t confframe, int flags)
00846 {
00847         zone_t *z;
00848         __address addr;
00849         count_t confcount;
00850         int i;
00851         int znum;
00852 
00853         /* Theoretically we could have here 0, practically make sure
00854          * nobody tries to do that. If some platform requires, remove
00855          * the assert
00856          */
00857         ASSERT(confframe);
00858         /* If conframe is supposed to be inside our zone, then make sure
00859          * it does not span kernel & init
00860          */
00861         confcount = SIZE2FRAMES(zone_conf_size(count));
00862         if (confframe >= start && confframe < start+count) {
00863                 for (;confframe < start + count; confframe++) {
00864                         addr = PFN2ADDR(confframe);
00865                         if (overlaps(addr, PFN2ADDR(confcount), KA2PA(config.base), config.kernel_size))
00866                                 continue;
00867                         
00868                         bool overlap = false;
00869                         count_t i;
00870                         for (i = 0; i < init.cnt; i++)
00871                                 if (overlaps(addr, PFN2ADDR(confcount), KA2PA(init.tasks[i].addr), init.tasks[i].size)) {
00872                                         overlap = true;
00873                                         break;
00874                                 }
00875                         if (overlap)
00876                                 continue;
00877                         
00878                         break;
00879                 }
00880                 if (confframe >= start + count)
00881                         panic("Cannot find configuration data for zone.");
00882         }
00883 
00884         z = (zone_t *)PA2KA(PFN2ADDR(confframe));
00885         zone_construct(start, count, z, flags);
00886         znum = zones_add_zone(z);
00887         if (znum == -1)
00888                 return -1;
00889 
00890         /* If confdata in zone, mark as unavailable */
00891         if (confframe >= start && confframe < start+count)
00892                 for (i=confframe; i<confframe+confcount; i++) {
00893                         zone_mark_unavailable(z, i - z->base);
00894                 }
00895         return znum;
00896 }
00897 
00898 /***************************************/
00899 /* Frame functions */
00900 
00902 void frame_set_parent(pfn_t pfn, void *data, int hint)
00903 {
00904         zone_t *zone = find_zone_and_lock(pfn, &hint);
00905 
00906         ASSERT(zone);
00907 
00908         zone_get_frame(zone, pfn-zone->base)->parent = data;
00909         spinlock_unlock(&zone->lock);
00910 }
00911 
00912 void * frame_get_parent(pfn_t pfn, int hint)
00913 {
00914         zone_t *zone = find_zone_and_lock(pfn, &hint);
00915         void *res;
00916 
00917         ASSERT(zone);
00918         res = zone_get_frame(zone, pfn - zone->base)->parent;
00919         
00920         spinlock_unlock(&zone->lock);
00921         return res;
00922 }
00923 
00934 pfn_t frame_alloc_generic(__u8 order, int flags, int *status, int *pzone) 
00935 {
00936         ipl_t ipl;
00937         int freed;
00938         pfn_t v;
00939         zone_t *zone;
00940         
00941 loop:
00942         ipl = interrupts_disable();
00943         
00944         /*
00945          * First, find suitable frame zone.
00946          */
00947         zone = find_free_zone_lock(order, pzone);
00948         
00949         /* If no memory, reclaim some slab memory,
00950            if it does not help, reclaim all */
00951         if (!zone && !(flags & FRAME_NO_RECLAIM)) {
00952                 freed = slab_reclaim(0);
00953                 if (freed)
00954                         zone = find_free_zone_lock(order, pzone);
00955                 if (!zone) {
00956                         freed = slab_reclaim(SLAB_RECLAIM_ALL);
00957                         if (freed)
00958                                 zone = find_free_zone_lock(order, pzone);
00959                 }
00960         }
00961         if (!zone) {
00962                 if (flags & FRAME_PANIC)
00963                         panic("Can't allocate frame.\n");
00964                 
00965                 /*
00966                  * TODO: Sleep until frames are available again.
00967                  */
00968                 interrupts_restore(ipl);
00969 
00970                 if (flags & FRAME_ATOMIC) {
00971                         ASSERT(status != NULL);
00972                         if (status)
00973                                 *status = FRAME_NO_MEMORY;
00974                         return NULL;
00975                 }
00976                 
00977                 panic("Sleep not implemented.\n");
00978                 goto loop;
00979         }
00980         
00981         v = zone_frame_alloc(zone, order);
00982         v += zone->base;
00983 
00984         spinlock_unlock(&zone->lock);
00985         interrupts_restore(ipl);
00986 
00987         if (status)
00988                 *status = FRAME_OK;
00989         return v;
00990 }
00991 
01000 void frame_free(pfn_t pfn)
01001 {
01002         ipl_t ipl;
01003         zone_t *zone;
01004 
01005         ipl = interrupts_disable();
01006         
01007         /*
01008          * First, find host frame zone for addr.
01009          */
01010         zone = find_zone_and_lock(pfn,NULL);
01011         ASSERT(zone);
01012         
01013         zone_frame_free(zone, pfn-zone->base);
01014         
01015         spinlock_unlock(&zone->lock);
01016         interrupts_restore(ipl);
01017 }
01018 
01026 void frame_reference_add(pfn_t pfn)
01027 {
01028         ipl_t ipl;
01029         zone_t *zone;
01030         frame_t *frame;
01031 
01032         ipl = interrupts_disable();
01033         
01034         /*
01035          * First, find host frame zone for addr.
01036          */
01037         zone = find_zone_and_lock(pfn,NULL);
01038         ASSERT(zone);
01039         
01040         frame = &zone->frames[pfn-zone->base];
01041         frame->refcount++;
01042         
01043         spinlock_unlock(&zone->lock);
01044         interrupts_restore(ipl);
01045 }
01046 
01048 void frame_mark_unavailable(pfn_t start, count_t count)
01049 {
01050         int i;
01051         zone_t *zone;
01052         int prefzone = 0;
01053         
01054         for (i=0; i < count; i++) {
01055                 zone = find_zone_and_lock(start+i,&prefzone);
01056                 if (!zone) /* PFN not found */
01057                         continue;
01058                 zone_mark_unavailable(zone, start+i-zone->base);
01059 
01060                 spinlock_unlock(&zone->lock);
01061         }
01062 }
01063 
01068 void frame_init(void)
01069 {
01070         if (config.cpu_active == 1) {
01071                 zones.count = 0;
01072                 spinlock_initialize(&zones.lock,"zones_glob_lock");
01073         }
01074         /* Tell the architecture to create some memory */
01075         frame_arch_init();
01076         if (config.cpu_active == 1) {
01077                 pfn_t firstframe = ADDR2PFN(KA2PA(config.base));
01078                 pfn_t lastframe = ADDR2PFN(KA2PA(config.base+config.kernel_size));
01079                 frame_mark_unavailable(firstframe,lastframe-firstframe+1);
01080                 
01081                 count_t i;
01082                 for (i = 0; i < init.cnt; i++)
01083                         frame_mark_unavailable(ADDR2PFN(KA2PA(init.tasks[i].addr)), SIZE2FRAMES(init.tasks[i].size));
01084 
01085                 /* Black list first frame, as allocating NULL would
01086                  * fail on some places */
01087                 frame_mark_unavailable(0, 1);
01088         }
01089 }
01090 
01091 
01092 
01096 void zone_print_list(void) {
01097         zone_t *zone = NULL;
01098         int i;
01099         ipl_t ipl;
01100 
01101         ipl = interrupts_disable();
01102         spinlock_lock(&zones.lock);
01103         printf("#  Base address\tFree Frames\tBusy Frames\n");
01104         printf("   ------------\t-----------\t-----------\n");
01105         for (i = 0; i < zones.count; i++) {
01106                 zone = zones.info[i];
01107                 spinlock_lock(&zone->lock);
01108                 printf("%d: %.*p \t%10zd\t%10zd\n", i, sizeof(__address) * 2, PFN2ADDR(zone->base), zone->free_count, zone->busy_count);
01109                 spinlock_unlock(&zone->lock);
01110         }
01111         spinlock_unlock(&zones.lock);
01112         interrupts_restore(ipl);
01113 }
01114 
01119 void zone_print_one(int num) {
01120         zone_t *zone = NULL;
01121         ipl_t ipl;
01122         int i;
01123 
01124         ipl = interrupts_disable();
01125         spinlock_lock(&zones.lock);
01126 
01127         for (i = 0; i < zones.count; i++) {
01128                 if (i == num || PFN2ADDR(zones.info[i]->base) == num) {
01129                         zone = zones.info[i];
01130                         break;
01131                 }
01132         }
01133         if (!zone) {
01134                 printf("Zone not found.\n");
01135                 goto out;
01136         }
01137         
01138         spinlock_lock(&zone->lock);
01139         printf("Memory zone information\n");
01140         printf("Zone base address: %#.*p\n", sizeof(__address) * 2, PFN2ADDR(zone->base));
01141         printf("Zone size: %zd frames (%zdK)\n", zone->count, ((zone->count) * FRAME_SIZE) >> 10);
01142         printf("Allocated space: %zd frames (%zdK)\n", zone->busy_count, (zone->busy_count * FRAME_SIZE) >> 10);
01143         printf("Available space: %zd (%zdK)\n", zone->free_count, (zone->free_count * FRAME_SIZE) >> 10);
01144         buddy_system_structure_print(zone->buddy_system, FRAME_SIZE);
01145         
01146         spinlock_unlock(&zone->lock);
01147 out:
01148         spinlock_unlock(&zones.lock);
01149         interrupts_restore(ipl);
01150 }
01151 
01152 

Generated on Sun Jun 18 17:28:04 2006 for HelenOS Kernel (ppc64) by  doxygen 1.4.6