Changeset 085d973 in mainline for generic/src/mm/frame.c


Ignore:
Timestamp:
2006-02-08T12:34:05Z (19 years ago)
Author:
Ondrej Palkovsky <ondrap@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
5e3757d
Parents:
eb1b8b6
Message:

Cleanup o frame allocator.
Removed early_malloc & initial heap.
Will break ia64, ppc & sparc.
Added e820 table print.

File:
1 edited

Legend:

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

    reb1b8b6 r085d973  
    2828 */
    2929
     30/*
     31 * Locking order
     32 *
     33 * In order to access particular zone, the process must first lock
     34 * the zones.lock, then lock the zone and then unlock the zones.lock.
     35 * This insures, that we can fiddle with the zones in runtime without
     36 * affecting the processes.
     37 *
     38 */
     39
    3040#include <typedefs.h>
    3141#include <arch/types.h>
    32 #include <mm/heap.h>
    3342#include <mm/frame.h>
    3443#include <mm/as.h>
     
    4150#include <print.h>
    4251#include <align.h>
    43 
    44 SPINLOCK_INITIALIZE(zone_head_lock);    /**< this lock protects zone_head list */
    45 LIST_INITIALIZE(zone_head);             /**< list of all zones in the system */
    46 
    47 /** Blacklist containing non-available areas of memory.
    48  *
    49  * This blacklist is used to exclude frames that cannot be allocated
    50  * (e.g. kernel memory) from available memory map.
    51  */
    52 region_t zone_blacklist[ZONE_BLACKLIST_SIZE];
    53 count_t zone_blacklist_count = 0;
     52#include <mm/slab.h>
     53
     54typedef struct {
     55        count_t refcount;       /**< tracking of shared frames  */
     56        __u8 buddy_order;       /**< buddy system block order */
     57        link_t buddy_link;      /**< link to the next free block inside one order */
     58        void *parent;           /**< If allocated by slab, this points there */
     59}frame_t;
     60
     61typedef struct {
     62        SPINLOCK_DECLARE(lock); /**< this lock protects everything below */
     63        pfn_t base;     /**< frame_no of the first frame in the frames array */
     64        pfn_t count;          /**< Size of zone */
     65
     66        frame_t *frames;        /**< array of frame_t structures in this zone */
     67        count_t free_count;     /**< number of free frame_t structures */
     68        count_t busy_count;     /**< number of busy frame_t structures */
     69       
     70        buddy_system_t * buddy_system; /**< buddy system for the zone */
     71        int flags;
     72}zone_t;
     73
     74/*
     75 * The zoneinfo.lock must be locked when accessing zoneinfo structure.
     76 * Some of the attributes in zone_t structures are 'read-only'
     77 */
     78
     79struct {
     80        SPINLOCK_DECLARE(lock);
     81        int count;
     82        zone_t *info[ZONES_MAX];
     83}zones;
     84
     85
     86/*********************************/
     87/* Helper functions */
     88static inline index_t frame_index(zone_t *zone, frame_t *frame)
     89{
     90        return (index_t)(frame - zone->frames);
     91}
     92static inline index_t frame_index_abs(zone_t *zone, frame_t *frame)
     93{
     94        return (index_t)(frame - zone->frames) + zone->base;
     95}
     96static inline int frame_index_valid(zone_t *zone, index_t index)
     97{
     98        return index >= 0 && index < zone->count;
     99}
     100
     101/** Compute pfn_t from frame_t pointer & zone pointer */
     102static pfn_t make_frame_index(zone_t *zone, frame_t *frame)
     103{
     104        return frame - zone->frames;
     105}
     106
     107/** Initialize frame structure
     108 *
     109 * Initialize frame structure.
     110 *
     111 * @param frame Frame structure to be initialized.
     112 */
     113static void frame_initialize(frame_t *frame)
     114{
     115        frame->refcount = 1;
     116        frame->buddy_order = 0;
     117}
     118
     119/*************************************/
     120/* Zoneinfo functions */
     121
     122/**
     123 * Insert-sort zone into zones list
     124 */
     125static void zones_add_zone(zone_t *zone)
     126{
     127        int i;
     128
     129        spinlock_lock(&zones.lock);
     130        /* Try to merge */
     131        if (zone->flags & ZONE_JOIN) {
     132                for (i=0; i < zones.count; i++) {
     133                        spinlock_lock(&zones.info[i]->lock);
     134                       
     135                        /* Join forward, join backward */
     136                        panic("Not implemented");
     137
     138                        spinlock_unlock(&zones.info[i]->lock);
     139                }
     140                spinlock_unlock(&zones.lock);
     141        } else {
     142                if (zones.count+1 == ZONES_MAX)
     143                        panic("Maximum zone(%d) count exceeded.", ZONES_MAX);
     144                zones.info[zones.count++] = zone;
     145        }
     146        spinlock_unlock(&zones.lock);
     147}
     148
     149/**
     150 * Try to find a zone where can we find the frame
     151 *
     152 * @param hint Start searching in zone 'hint'
     153 * @param lock Lock zone if true
     154 *
     155 * Assume interrupts disable
     156 */
     157static zone_t * find_zone_and_lock(pfn_t frame, int *pzone)
     158{
     159        int i;
     160        int hint = pzone ? *pzone : 0;
     161        zone_t *z;
     162       
     163        spinlock_lock(&zones.lock);
     164
     165        if (hint >= zones.count || hint < 0)
     166                hint = 0;
     167       
     168        i = hint;
     169        do {
     170                z = zones.info[i];
     171                spinlock_lock(&z->lock);
     172                if (z->base <= frame && z->base + z->count > frame) {
     173                        spinlock_unlock(&zones.lock); /* Unlock the global lock */
     174                        if (pzone)
     175                                *pzone = i;
     176                        return z;
     177                }
     178                spinlock_unlock(&z->lock);
     179
     180                i++;
     181                if (i >= zones.count)
     182                        i = 0;
     183        } while(i != hint);
     184
     185        spinlock_unlock(&zones.lock);
     186        return NULL;
     187}
     188
     189/**
     190 * Find AND LOCK zone that can allocate order frames
     191 *
     192 * Assume interrupts are disabled!!
     193 *
     194 * @param pzone Pointer to preferred zone or NULL, on return contains zone number
     195 */
     196static zone_t * find_free_zone_lock(__u8 order, int *pzone)
     197{
     198        int i;
     199        zone_t *z;
     200        int hint = pzone ? *pzone : 0;
     201       
     202        spinlock_lock(&zones.lock);
     203        if (hint >= zones.count)
     204                hint = 0;
     205        i = hint;
     206        do {
     207                z = zones.info[i];
     208               
     209                spinlock_lock(&z->lock);
     210
     211                /* Check if the zone has 2^order frames area available  */
     212                if (buddy_system_can_alloc(z->buddy_system, order)) {
     213                        spinlock_unlock(&zones.lock);
     214                        if (pzone)
     215                                *pzone = i;
     216                        return z;
     217                }
     218                spinlock_unlock(&z->lock);
     219                if (++i >= zones.count)
     220                        i = 0;
     221        } while(i != hint);
     222        spinlock_unlock(&zones.lock);
     223        return NULL;
     224}
     225
     226/********************************************/
     227/* Buddy system functions */
     228
     229/** Buddy system find_block implementation
     230 *
     231 * Find block that is parent of current list.
     232 * That means go to lower addresses, until such block is found
     233 *
     234 * @param order - Order of parent must be different then this parameter!!
     235 */
     236static link_t *zone_buddy_find_block(buddy_system_t *b, link_t *child,
     237                                     __u8 order)
     238{
     239        frame_t * frame;
     240        zone_t * zone;
     241        index_t index;
     242       
     243        frame = list_get_instance(child, frame_t, buddy_link);
     244        zone = (zone_t *) b->data;
     245
     246        index = frame_index(zone, frame);
     247        do {
     248                if (zone->frames[index].buddy_order != order) {
     249                        return &zone->frames[index].buddy_link;
     250                }
     251        } while(index-- > 0);
     252        return NULL;
     253}
     254
     255                                     
     256
     257/** Buddy system find_buddy implementation
     258 *
     259 * @param b Buddy system.
     260 * @param block Block for which buddy should be found
     261 *
     262 * @return Buddy for given block if found
     263 */
     264static link_t * zone_buddy_find_buddy(buddy_system_t *b, link_t * block)
     265{
     266        frame_t * frame;
     267        zone_t * zone;
     268        index_t index;
     269        bool is_left, is_right;
     270
     271        frame = list_get_instance(block, frame_t, buddy_link);
     272        zone = (zone_t *) b->data;
     273        ASSERT(IS_BUDDY_ORDER_OK(frame_index_abs(zone, frame), frame->buddy_order));
     274       
     275        is_left = IS_BUDDY_LEFT_BLOCK_ABS(zone, frame);
     276        is_right = IS_BUDDY_RIGHT_BLOCK_ABS(zone, frame);
     277
     278        ASSERT(is_left ^ is_right);
     279        if (is_left) {
     280                index = (frame_index(zone, frame)) + (1 << frame->buddy_order);
     281        } else { // if (is_right)
     282                index = (frame_index(zone, frame)) - (1 << frame->buddy_order);
     283        }
     284       
     285
     286        if (frame_index_valid(zone, index)) {
     287                if (zone->frames[index].buddy_order == frame->buddy_order &&
     288                    zone->frames[index].refcount == 0) {
     289                        return &zone->frames[index].buddy_link;
     290                }
     291        }
     292
     293        return NULL;   
     294}
     295
     296/** Buddy system bisect implementation
     297 *
     298 * @param b Buddy system.
     299 * @param block Block to bisect
     300 *
     301 * @return right block
     302 */
     303static link_t * zone_buddy_bisect(buddy_system_t *b, link_t * block) {
     304        frame_t * frame_l, * frame_r;
     305
     306        frame_l = list_get_instance(block, frame_t, buddy_link);
     307        frame_r = (frame_l + (1 << (frame_l->buddy_order - 1)));
     308       
     309        return &frame_r->buddy_link;
     310}
     311
     312/** Buddy system coalesce implementation
     313 *
     314 * @param b Buddy system.
     315 * @param block_1 First block
     316 * @param block_2 First block's buddy
     317 *
     318 * @return Coalesced block (actually block that represents lower address)
     319 */
     320static link_t * zone_buddy_coalesce(buddy_system_t *b, link_t * block_1,
     321                                    link_t * block_2) {
     322        frame_t *frame1, *frame2;
     323       
     324        frame1 = list_get_instance(block_1, frame_t, buddy_link);
     325        frame2 = list_get_instance(block_2, frame_t, buddy_link);
     326       
     327        return frame1 < frame2 ? block_1 : block_2;
     328}
     329
     330/** Buddy system set_order implementation
     331 *
     332 * @param b Buddy system.
     333 * @param block Buddy system block
     334 * @param order Order to set
     335 */
     336static void zone_buddy_set_order(buddy_system_t *b, link_t * block, __u8 order) {
     337        frame_t * frame;
     338        frame = list_get_instance(block, frame_t, buddy_link);
     339        frame->buddy_order = order;
     340}
     341
     342/** Buddy system get_order implementation
     343 *
     344 * @param b Buddy system.
     345 * @param block Buddy system block
     346 *
     347 * @return Order of block
     348 */
     349static __u8 zone_buddy_get_order(buddy_system_t *b, link_t * block) {
     350        frame_t * frame;
     351        frame = list_get_instance(block, frame_t, buddy_link);
     352        return frame->buddy_order;
     353}
     354
     355/** Buddy system mark_busy implementation
     356 *
     357 * @param b Buddy system
     358 * @param block Buddy system block
     359 *
     360 */
     361static void zone_buddy_mark_busy(buddy_system_t *b, link_t * block) {
     362        frame_t * frame;
     363        frame = list_get_instance(block, frame_t, buddy_link);
     364        frame->refcount = 1;
     365}
     366
     367/** Buddy system mark_available implementation
     368 *
     369 * @param b Buddy system
     370 * @param block Buddy system block
     371 *
     372 */
     373static void zone_buddy_mark_available(buddy_system_t *b, link_t * block) {
     374        frame_t * frame;
     375        frame = list_get_instance(block, frame_t, buddy_link);
     376        frame->refcount = 0;
     377}
    54378
    55379static struct buddy_system_operations  zone_buddy_system_operations = {
     
    60384        .get_order = zone_buddy_get_order,
    61385        .mark_busy = zone_buddy_mark_busy,
     386        .mark_available = zone_buddy_mark_available,
     387        .find_block = zone_buddy_find_block
    62388};
    63389
    64 /** Initialize physical memory management
    65  *
    66  * Initialize physical memory managemnt.
    67  */
    68 void frame_init(void)
    69 {
    70         if (config.cpu_active == 1) {
    71                 frame_region_not_free(KA2PA(config.base), config.kernel_size);
    72                 if (config.init_size > 0)
    73                         frame_region_not_free(KA2PA(config.init_addr), config.init_size);
    74         }
    75 
    76         frame_arch_init();
    77 }
    78 
    79 /**
    80  * Find AND LOCK zone that can allocate order frames
    81  *
    82  * Assume zone_head_lock is locked.
    83  */
    84 static zone_t * find_free_zone(__u8 order)
    85 {
    86         link_t *cur;
     390/*************************************/
     391/* Zone functions */
     392
     393/** Allocate frame in particular zone
     394 *
     395 * Assume zone is locked
     396 *
     397 * @return Frame index in zone
     398 */
     399static pfn_t zone_frame_alloc(zone_t *zone,__u8 order, int flags, int *status)
     400{
     401        pfn_t v;
     402        link_t *tmp;
     403        frame_t *frame;
     404
     405        /* Allocate frames from zone buddy system */
     406        tmp = buddy_system_alloc(zone->buddy_system, order);
     407       
     408        ASSERT(tmp);
     409       
     410        /* Update zone information. */
     411        zone->free_count -= (1 << order);
     412        zone->busy_count += (1 << order);
     413
     414        /* Frame will be actually a first frame of the block. */
     415        frame = list_get_instance(tmp, frame_t, buddy_link);
     416       
     417        /* get frame address */
     418        v = make_frame_index(zone, frame);
     419        return v;
     420}
     421
     422/** Free frame from zone
     423 *
     424 * Assume zone is locked
     425 */
     426static void zone_frame_free(zone_t *zone, pfn_t frame_idx)
     427{
     428        frame_t *frame;
     429        __u8 order;
     430
     431        frame = &zone->frames[frame_idx];
     432       
     433        /* remember frame order */
     434        order = frame->buddy_order;
     435
     436        ASSERT(frame->refcount);
     437
     438        if (!--frame->refcount) {
     439                buddy_system_free(zone->buddy_system, &frame->buddy_link);
     440        }
     441
     442        /* Update zone information. */
     443        zone->free_count += (1 << order);
     444        zone->busy_count -= (1 << order);
     445}
     446
     447/** Return frame from zone */
     448static frame_t * zone_get_frame(zone_t *zone, pfn_t frame_idx)
     449{
     450        ASSERT(frame_idx < zone->count);
     451        return &zone->frames[frame_idx];
     452}
     453
     454/** Mark frame in zone unavailable to allocation */
     455static void zone_mark_unavailable(zone_t *zone, pfn_t frame_idx)
     456{
     457        frame_t *frame;
     458        link_t *link;
     459
     460        frame = zone_get_frame(zone, frame_idx);
     461        link = buddy_system_alloc_block(zone->buddy_system,
     462                                        &frame->buddy_link);
     463        ASSERT(link);
     464        zone->free_count--;
     465}
     466
     467/** Create frame zone
     468 *
     469 * Create new frame zone.
     470 *
     471 * @param start Physical address of the first frame within the zone.
     472 * @param size Size of the zone. Must be a multiple of FRAME_SIZE.
     473 * @param conffram Address of configuration frame
     474 * @param flags Zone flags.
     475 *
     476 * @return Initialized zone.
     477 */
     478static zone_t * zone_construct(pfn_t start, pfn_t count,
     479                               zone_t *z, int flags)
     480{
     481        int i;
     482        __u8 max_order;
     483
     484        spinlock_initialize(&z->lock, "zone_lock");
     485        z->base = start;
     486        z->count = count;
     487        z->flags = flags;
     488        z->free_count = count;
     489        z->busy_count = 0;
     490
     491        /*
     492         * Compute order for buddy system, initialize
     493         */
     494        for (max_order = 0; count >> max_order; max_order++)
     495                ;
     496        z->buddy_system = (buddy_system_t *)&z[1];
     497       
     498        buddy_system_create(z->buddy_system, max_order,
     499                            &zone_buddy_system_operations,
     500                            (void *) z);
     501       
     502        /* Allocate frames _after_ the conframe */
     503        /* Check sizes */
     504        z->frames = (frame_t *)((void *)z->buddy_system+buddy_conf_size(max_order));
     505
     506        for (i = 0; i<count; i++) {
     507                frame_initialize(&z->frames[i]);
     508        }
     509        /* Stuffing frames */
     510        for (i = 0; i < count; i++) {
     511                z->frames[i].refcount = 0;
     512                buddy_system_free(z->buddy_system, &z->frames[i].buddy_link);
     513        }
     514        return z;
     515}
     516
     517
     518/** Compute configuration data size for zone */
     519__address zone_conf_size(pfn_t start, pfn_t count)
     520{
     521        int size = sizeof(zone_t) + count*sizeof(frame_t);
     522        int max_order;
     523
     524        for (max_order = 0; count >> max_order; max_order++)
     525                ;
     526        size += buddy_conf_size(max_order);
     527        return size;
     528}
     529
     530/** Create and add zone to system
     531 *
     532 * @param confframe Where configuration frame is supposed to be.
     533 *                  Always check, that we will not disturb kernel pages
     534 *                  the kernel and possibly init.
     535 *                  If confframe is given _outside_ this zone, it is expected,
     536 *                  that the area is already marked BUSY and big enough
     537 *                  to contain zone_conf_size() amount of data
     538 */
     539void zone_create(pfn_t start, pfn_t count, pfn_t confframe, int flags)
     540{
    87541        zone_t *z;
    88 
    89         for (cur = zone_head.next; cur != &zone_head;cur = cur->next) {
    90                 z = list_get_instance(cur, zone_t, link);
    91                
    92                 spinlock_lock(&z->lock);
    93                
    94                 /* Check if the zone has 2^order frames area available  */
    95                 if (buddy_system_can_alloc(z->buddy_system, order))
    96                         return z;
    97                
    98                 spinlock_unlock(&z->lock);
    99         }
    100         return NULL;
     542        __address addr,endaddr;
     543        pfn_t confcount;
     544        int i;
     545
     546        /* Theoretically we could have here 0, practically make sure
     547         * nobody tries to do that. If some platform requires, remove
     548         * the assert
     549         */
     550        ASSERT(confframe);
     551        /* If conframe is supposed to be inside our zone, then make sure
     552         * it does not span kernel & init
     553         */
     554        confcount = SIZE2PFN(zone_conf_size(start,count));
     555        if (confframe >= start && confframe < start+count) {
     556                for (;confframe < start+count;confframe++) {
     557                        addr = PFN2ADDR(confframe);
     558                        endaddr =  PFN2ADDR (confframe + confcount);
     559                        if (overlaps(addr, endaddr, KA2PA(config.base),
     560                                     KA2PA(config.base+config.kernel_size)))
     561                                continue;
     562                        if (config.init_addr)
     563                                if (overlaps(addr,endaddr,
     564                                             KA2PA(config.init_addr),
     565                                             KA2PA(config.init_addr+config.init_size)))
     566                                        continue;
     567                        break;
     568                }
     569                if (confframe >= start+count)
     570                        panic("Cannot find configuration data for zone.");
     571        }
     572
     573        z = zone_construct(start, count, (zone_t *)PA2KA(PFN2ADDR(confframe)), flags);
     574        zones_add_zone(z);
     575       
     576        /* If confdata in zone, mark as unavailable */
     577        if (confframe >= start && confframe < start+count)
     578                for (i=confframe; i<confframe+confcount; i++) {
     579                        zone_mark_unavailable(z, i - z->base);
     580                }
     581}
     582
     583/***************************************/
     584/* Frame functions */
     585
     586/** Set parent of frame */
     587void frame_set_parent(pfn_t pfn, void *data, int hint)
     588{
     589        zone_t *zone = find_zone_and_lock(pfn, &hint);
     590
     591        ASSERT(zone);
     592
     593        zone_get_frame(zone, pfn-zone->base)->parent = data;
     594        spinlock_unlock(&zone->lock);
     595}
     596
     597void * frame_get_parent(pfn_t pfn, int hint)
     598{
     599        zone_t *zone = find_zone_and_lock(pfn, &hint);
     600        void *res;
     601
     602        ASSERT(zone);
     603        res = zone_get_frame(zone, pfn - zone->base)->parent;
     604       
     605        spinlock_unlock(&zone->lock);
     606        return res;
    101607}
    102608
     
    105611 * @param flags Flags for host zone selection and address processing.
    106612 * @param order Allocate exactly 2^order frames.
    107  * @param pzone Pointer to preferred zone pointer, on output it changes
    108  *              to the zone that the frame was really allocated to
     613 * @param pzone Preferred zone
    109614 *
    110615 * @return Allocated frame.
    111616 */
    112 __address frame_alloc_generic(__u8 order, int flags, int * status, zone_t **pzone)
     617pfn_t frame_alloc_generic(__u8 order, int flags, int * status, int *pzone)
    113618{
    114619        ipl_t ipl;
    115         link_t *tmp;
    116         zone_t *zone = NULL;
    117         frame_t *frame = NULL;
    118620        int freed;
    119         __address v;
     621        pfn_t v;
     622        zone_t *zone;
    120623       
    121624loop:
    122625        ipl = interrupts_disable();
    123         spinlock_lock(&zone_head_lock);
    124 
    125626        /*
    126627         * First, find suitable frame zone.
    127628         */
    128         if (pzone && *pzone) {
    129                 spinlock_lock(&(*pzone)->lock);
    130                 if (!buddy_system_can_alloc((*pzone)->buddy_system, order))
    131                         spinlock_unlock(&(*pzone)->lock);
    132                 else
    133                         zone = *pzone;
    134         }
    135         if (!zone) {
    136                 zone = find_free_zone(order);
    137                 /* If no memory, reclaim some slab memory,
    138                    if it does not help, reclaim all */
    139                 if (!zone && !(flags & FRAME_NO_RECLAIM)) {
    140                         spinlock_unlock(&zone_head_lock);
    141                         freed = slab_reclaim(0);
    142                         spinlock_lock(&zone_head_lock);
     629        zone = find_free_zone_lock(order,pzone);
     630        /* If no memory, reclaim some slab memory,
     631           if it does not help, reclaim all */
     632        if (!zone && !(flags & FRAME_NO_RECLAIM)) {
     633                freed = slab_reclaim(0);
     634                if (freed)
     635                        zone = find_free_zone_lock(order,pzone);
     636                if (!zone) {
     637                        freed = slab_reclaim(SLAB_RECLAIM_ALL);
    143638                        if (freed)
    144                                 zone = find_free_zone(order);
    145                         if (!zone) {
    146                                 spinlock_unlock(&zone_head_lock);
    147                                 freed = slab_reclaim(SLAB_RECLAIM_ALL);
    148                                 spinlock_lock(&zone_head_lock);
    149                                 if (freed)
    150                                         zone = find_free_zone(order);
    151                         }
    152                 }
    153         }
    154 
     639                                zone = find_free_zone_lock(order,pzone);
     640                }
     641        }
    155642        if (!zone) {
    156643                if (flags & FRAME_PANIC)
     
    160647                 * TODO: Sleep until frames are available again.
    161648                 */
    162                 spinlock_unlock(&zone_head_lock);
    163649                interrupts_restore(ipl);
    164650
    165651                if (flags & FRAME_ATOMIC) {
    166652                        ASSERT(status != NULL);
    167                         *status = FRAME_NO_MEMORY;
     653                        if (status)
     654                                *status = FRAME_NO_MEMORY;
    168655                        return NULL;
    169656                }
     
    172659                goto loop;
    173660        }
    174                
    175         /* Allocate frames from zone buddy system */
    176         tmp = buddy_system_alloc(zone->buddy_system, order);
    177        
    178         ASSERT(tmp);
    179        
    180         /* Update zone information. */
    181         zone->free_count -= (1 << order);
    182         zone->busy_count += (1 << order);
    183 
    184         /* Frame will be actually a first frame of the block. */
    185         frame = list_get_instance(tmp, frame_t, buddy_link);
    186        
    187         /* get frame address */
    188         v = FRAME2ADDR(zone, frame);
     661        v = zone_frame_alloc(zone,order,flags,status);
     662        v += zone->base;
    189663
    190664        spinlock_unlock(&zone->lock);
    191         spinlock_unlock(&zone_head_lock);
    192665        interrupts_restore(ipl);
    193666
    194         ASSERT(v == ALIGN_UP(v, FRAME_SIZE << order));
    195 
    196         if (flags & FRAME_KA)
    197                 v = PA2KA(v);
    198        
    199667        if (status)
    200668                *status = FRAME_OK;
    201 
    202         if (pzone)
    203                 *pzone = zone;
    204669        return v;
    205670}
    206 
    207 /** Convert address to zone pointer
    208  *
    209  * Assume zone_head_lock is held
    210  *
    211  * @param addr Physical address
    212  * @param lock If true, lock the zone
    213  */
    214 static zone_t * addr2zone(__address addr, int lock)
    215 {
    216         link_t *cur;
    217         zone_t *z = NULL;
    218 
    219         for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
    220                 z = list_get_instance(cur, zone_t, link);
    221                
    222                 spinlock_lock(&z->lock);
    223                
    224                 /*
    225                  * Check if addr belongs to z.
    226                  */
    227                 if ((addr >= z->base) && (addr <= z->base + (z->free_count + z->busy_count) * FRAME_SIZE)) {
    228                         if (!lock)
    229                                 spinlock_unlock(&z->lock);
    230                         return z;
    231                 }
    232 
    233                 spinlock_unlock(&z->lock);
    234         }
    235 
    236         panic("Cannot find addr2zone: 0x%X", addr);
    237 }
    238 
    239 /** Return frame_t structure corresponding to address
    240  *
    241  *
    242  */
    243 frame_t * frame_addr2frame(__address addr)
    244 {
    245         ipl_t ipl;
    246         frame_t *frame;
    247         zone_t *zone;
    248 
    249         if (IS_KA(addr))
    250                 addr = KA2PA(addr);
    251 
    252         /* Disable interrupts to avoid deadlocks with interrupt handlers */
    253         ipl = interrupts_disable();
    254         spinlock_lock(&zone_head_lock);
    255        
    256         zone = addr2zone(addr,0);
    257         frame = ADDR2FRAME(zone, addr);
    258 
    259         spinlock_unlock(&zone_head_lock);
    260         interrupts_restore(ipl);
    261 
    262         return frame;
    263 }
    264 
    265671
    266672/** Free a frame.
     
    270676 * If it drops to zero, move the frame structure to free list.
    271677 *
    272  * @param addr Address of the frame to be freed. It must be a multiple of FRAME_SIZE.
    273  */
    274 void frame_free(__address addr)
     678 * @param frame Frame no to be freed.
     679 */
     680void frame_free(pfn_t pfn)
    275681{
    276682        ipl_t ipl;
    277683        zone_t *zone;
    278         frame_t *frame;
    279         int order;
    280        
    281         ASSERT(addr % FRAME_SIZE == 0);
    282        
    283         if (IS_KA(addr))
    284                 addr = KA2PA(addr);
    285684
    286685        ipl = interrupts_disable();
    287         spinlock_lock(&zone_head_lock);
    288686       
    289687        /*
    290688         * First, find host frame zone for addr.
    291689         */
    292         zone = addr2zone(addr, 1); /* This locks the zone automatically */
    293        
    294         frame = ADDR2FRAME(zone, addr);
    295        
    296         /* remember frame order */
    297         order = frame->buddy_order;
    298 
    299         ASSERT(frame->refcount);
    300 
    301         if (!--frame->refcount) {
    302                 buddy_system_free(zone->buddy_system, &frame->buddy_link);
    303         }
    304 
    305         /* Update zone information. */
    306         zone->free_count += (1 << order);
    307         zone->busy_count -= (1 << order);
     690        zone = find_zone_and_lock(pfn,NULL);
     691        ASSERT(zone);
     692       
     693        zone_frame_free(zone, pfn-zone->base);
    308694       
    309695        spinlock_unlock(&zone->lock);
    310         spinlock_unlock(&zone_head_lock);
    311696        interrupts_restore(ipl);
    312697}
    313698
    314 /** Mark frame region not free.
    315  *
    316  * Mark frame region not free.
    317  *
    318  * @param base Base address of non-available region.
    319  * @param size Size of non-available region.
    320  */
    321 void frame_region_not_free(__address base, size_t size)
    322 {
    323         index_t index;
    324         index = zone_blacklist_count++;
    325 
    326         /* Force base to the nearest lower address frame boundary. */
    327         base = ALIGN_DOWN(base, FRAME_SIZE);
    328         /* Align size to frame boundary. */
    329         size = ALIGN_UP(size, FRAME_SIZE);
    330 
    331         ASSERT(index < ZONE_BLACKLIST_SIZE);
    332         zone_blacklist[index].base = base;
    333         zone_blacklist[index].size = size;
    334 }
    335 
    336 /** Create frame zones in region of available memory.
    337  *
    338  * Avoid any black listed areas of non-available memory.
    339  * Assume that the black listed areas cannot overlap
    340  * one another or cross available memory region boundaries.
    341  *
    342  * @param base Base address of available memory region.
    343  * @param size Size of the region.
    344  */
    345 void zone_create_in_region(__address base, size_t size) {
     699
     700
     701/** Mark given range unavailable in frame zones */
     702void frame_mark_unavailable(pfn_t start, pfn_t count)
     703{
    346704        int i;
    347         zone_t * z;
    348         __address s;
    349         size_t sz;
    350        
    351         ASSERT(base % FRAME_SIZE == 0);
    352         ASSERT(size % FRAME_SIZE == 0);
    353        
    354         if (!size)
    355                 return;
    356 
    357         for (i = 0; i < zone_blacklist_count; i++) {
    358                 if (zone_blacklist[i].base >= base && zone_blacklist[i].base < base + size) {
    359                         s = base; sz = zone_blacklist[i].base - base;
    360                         ASSERT(base != s || sz != size);
    361                         zone_create_in_region(s, sz);
    362                        
    363                         s = zone_blacklist[i].base + zone_blacklist[i].size;
    364                         sz = (base + size) - (zone_blacklist[i].base + zone_blacklist[i].size);
    365                         ASSERT(base != s || sz != size);
    366                         zone_create_in_region(s, sz);
    367                         return;
    368                
    369                 }
    370         }
    371        
    372         z = zone_create(base, size, 0);
    373 
    374         if (!z) {
    375                 panic("Cannot allocate zone (base=%P, size=%d).\n", base, size);
    376         }
    377        
    378         zone_attach(z);
    379 }
    380 
    381 
    382 /** Create frame zone
    383  *
    384  * Create new frame zone.
    385  *
    386  * @param start Physical address of the first frame within the zone.
    387  * @param size Size of the zone. Must be a multiple of FRAME_SIZE.
    388  * @param flags Zone flags.
    389  *
    390  * @return Initialized zone.
    391  */
    392 zone_t * zone_create(__address start, size_t size, int flags)
    393 {
    394         zone_t *z;
    395         count_t cnt;
    396         int i;
    397         __u8 max_order;
    398 
    399         ASSERT(start % FRAME_SIZE == 0);
    400         ASSERT(size % FRAME_SIZE == 0);
    401        
    402         cnt = size / FRAME_SIZE;
    403        
    404         z = (zone_t *) early_malloc(sizeof(zone_t));
    405         if (z) {
    406                 link_initialize(&z->link);
    407                 spinlock_initialize(&z->lock, "zone_lock");
    408        
    409                 z->base = start;
    410                 z->base_index = start / FRAME_SIZE;
    411                
    412                 z->flags = flags;
    413 
    414                 z->free_count = cnt;
    415                 z->busy_count = 0;
    416                
    417                 z->frames = (frame_t *) early_malloc(cnt * sizeof(frame_t));
    418                 if (!z->frames) {
    419                         early_free(z);
    420                         return NULL;
    421                 }
    422                
    423                 for (i = 0; i<cnt; i++) {
    424                         frame_initialize(&z->frames[i], z);
    425                 }
    426                
    427                 /*
    428                  * Create buddy system for the zone
    429                  */
    430                 for (max_order = 0; cnt >> max_order; max_order++)
    431                         ;
    432                 z->buddy_system = buddy_system_create(max_order, &zone_buddy_system_operations, (void *) z);
    433                
    434                 /* Stuffing frames */
    435                 for (i = 0; i<cnt; i++) {
    436                         z->frames[i].refcount = 0;
    437                         buddy_system_free(z->buddy_system, &z->frames[i].buddy_link);   
    438                 }
    439                
    440         }
    441         return z;
    442 }
    443 
    444 /** Attach frame zone
    445  *
    446  * Attach frame zone to zone list.
    447  *
    448  * @param zone Zone to be attached.
    449  */
    450 void zone_attach(zone_t *zone)
    451 {
    452         ipl_t ipl;
    453        
    454         ipl = interrupts_disable();
    455         spinlock_lock(&zone_head_lock);
    456        
    457         list_append(&zone->link, &zone_head);
    458        
    459         spinlock_unlock(&zone_head_lock);
    460         interrupts_restore(ipl);
    461 }
    462 
    463 /** Initialize frame structure
    464  *
    465  * Initialize frame structure.
    466  *
    467  * @param frame Frame structure to be initialized.
    468  * @param zone Host frame zone.
    469  */
    470 void frame_initialize(frame_t *frame, zone_t *zone)
    471 {
    472         frame->refcount = 1;
    473         frame->buddy_order = 0;
    474 }
    475 
    476 
    477 /** Buddy system find_buddy implementation
    478  *
    479  * @param b Buddy system.
    480  * @param block Block for which buddy should be found
    481  *
    482  * @return Buddy for given block if found
    483  */
    484 link_t * zone_buddy_find_buddy(buddy_system_t *b, link_t * block) {
    485         frame_t * frame;
    486         zone_t * zone;
    487         index_t index;
    488         bool is_left, is_right;
    489 
    490         frame = list_get_instance(block, frame_t, buddy_link);
    491         zone = (zone_t *) b->data;
    492         ASSERT(IS_BUDDY_ORDER_OK(FRAME_INDEX_ABS(zone, frame), frame->buddy_order));
    493        
    494        
    495         is_left = IS_BUDDY_LEFT_BLOCK_ABS(zone, frame);
    496         is_right = IS_BUDDY_RIGHT_BLOCK_ABS(zone, frame);
    497        
    498         ASSERT(is_left ^ is_right);
    499        
    500         if (is_left) {
    501                 index = (FRAME_INDEX(zone, frame)) + (1 << frame->buddy_order);
    502         } else { // if (is_right)
    503                 index = (FRAME_INDEX(zone, frame)) - (1 << frame->buddy_order);
    504         }
    505        
    506         if (FRAME_INDEX_VALID(zone, index)) {
    507                 if (    zone->frames[index].buddy_order == frame->buddy_order &&
    508                         zone->frames[index].refcount == 0) {
    509                         return &zone->frames[index].buddy_link;
    510                 }
    511         }
    512        
    513         return NULL;   
    514 }
    515 
    516 /** Buddy system bisect implementation
    517  *
    518  * @param b Buddy system.
    519  * @param block Block to bisect
    520  *
    521  * @return right block
    522  */
    523 link_t * zone_buddy_bisect(buddy_system_t *b, link_t * block) {
    524         frame_t * frame_l, * frame_r;
    525 
    526         frame_l = list_get_instance(block, frame_t, buddy_link);
    527         frame_r = (frame_l + (1 << (frame_l->buddy_order - 1)));
    528        
    529         return &frame_r->buddy_link;
    530 }
    531 
    532 /** Buddy system coalesce implementation
    533  *
    534  * @param b Buddy system.
    535  * @param block_1 First block
    536  * @param block_2 First block's buddy
    537  *
    538  * @return Coalesced block (actually block that represents lower address)
    539  */
    540 link_t * zone_buddy_coalesce(buddy_system_t *b, link_t * block_1, link_t * block_2) {
    541         frame_t * frame1, * frame2;
    542        
    543         frame1 = list_get_instance(block_1, frame_t, buddy_link);
    544         frame2 = list_get_instance(block_2, frame_t, buddy_link);
    545        
    546         return frame1 < frame2 ? block_1 : block_2;
    547 }
    548 
    549 /** Buddy system set_order implementation
    550  *
    551  * @param b Buddy system.
    552  * @param block Buddy system block
    553  * @param order Order to set
    554  */
    555 void zone_buddy_set_order(buddy_system_t *b, link_t * block, __u8 order) {
    556         frame_t * frame;
    557         frame = list_get_instance(block, frame_t, buddy_link);
    558         frame->buddy_order = order;
    559 }
    560 
    561 /** Buddy system get_order implementation
    562  *
    563  * @param b Buddy system.
    564  * @param block Buddy system block
    565  *
    566  * @return Order of block
    567  */
    568 __u8 zone_buddy_get_order(buddy_system_t *b, link_t * block) {
    569         frame_t * frame;
    570         frame = list_get_instance(block, frame_t, buddy_link);
    571         return frame->buddy_order;
    572 }
    573 
    574 /** Buddy system mark_busy implementation
    575  *
    576  * @param b Buddy system
    577  * @param block Buddy system block
    578  *
    579  */
    580 void zone_buddy_mark_busy(buddy_system_t *b, link_t * block) {
    581         frame_t * frame;
    582         frame = list_get_instance(block, frame_t, buddy_link);
    583         frame->refcount = 1;
    584 }
     705        zone_t *zone;
     706        int prefzone = 0;
     707
     708        for (i=0; i<count; i++) {
     709                zone = find_zone_and_lock(start+i,&prefzone);
     710                if (!zone) /* PFN not found */
     711                        continue;
     712                zone_mark_unavailable(zone, start+i-zone->base);
     713
     714                spinlock_unlock(&zone->lock);
     715        }
     716}
     717
     718/** Initialize physical memory management
     719 *
     720 * Initialize physical memory managemnt.
     721 */
     722void frame_init(void)
     723{
     724        if (config.cpu_active == 1) {
     725                zones.count = 0;
     726                spinlock_initialize(&zones.lock,"zones_glob_lock");
     727        }
     728        /* Tell the architecture to create some memory */
     729        frame_arch_init();
     730        if (config.cpu_active == 1) {
     731                frame_mark_unavailable(ADDR2PFN(KA2PA(config.base)),
     732                                       SIZE2PFN(config.kernel_size));
     733                if (config.init_size > 0)
     734                        frame_mark_unavailable(ADDR2PFN(KA2PA(config.init_addr)),
     735                                               SIZE2PFN(config.init_size));
     736        }
     737}
     738
     739
    585740
    586741/** Prints list of zones
     
    589744void zone_print_list(void) {
    590745        zone_t *zone = NULL;
    591         link_t *cur;
     746        int i;
    592747        ipl_t ipl;
    593748
    594749        ipl = interrupts_disable();
    595         spinlock_lock(&zone_head_lock);
     750        spinlock_lock(&zones.lock);
    596751        printf("Base address\tFree Frames\tBusy Frames\n");
    597752        printf("------------\t-----------\t-----------\n");
    598         for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
    599                 zone = list_get_instance(cur, zone_t, link);
     753        for (i=0;i<zones.count;i++) {
     754                zone = zones.info[i];
    600755                spinlock_lock(&zone->lock);
    601                 printf("%L\t%d\t\t%d\n",zone->base, zone->free_count, zone->busy_count);
     756                printf("%L\t%d\t\t%d\n",PFN2ADDR(zone->base),
     757                       zone->free_count, zone->busy_count);
    602758                spinlock_unlock(&zone->lock);
    603759        }
    604         spinlock_unlock(&zone_head_lock);
     760        spinlock_unlock(&zones.lock);
    605761        interrupts_restore(ipl);
    606762}
     
    610766 * @param base Zone base address
    611767 */
    612 void zone_print_one(__address base) {
    613         zone_t *zone = NULL, *z ;
    614         link_t *cur;
     768void zone_print_one(int znum) {
     769        zone_t *zone = NULL;
    615770        ipl_t ipl;
    616771
    617772        ipl = interrupts_disable();
    618         spinlock_lock(&zone_head_lock);
    619        
    620         for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
    621                 z = list_get_instance(cur, zone_t, link);
    622                 if (base == z->base) {
    623                         zone = z;
    624                         break;
    625                 }
    626         }
    627        
    628         if (!zone) {
    629                 spinlock_unlock(&zone_head_lock);
     773        spinlock_lock(&zones.lock);
     774       
     775        if (znum >= zones.count || znum < 0) {
     776                printf("Zone number out of bounds.\n");
     777                spinlock_unlock(&zones.lock);
    630778                interrupts_restore(ipl);
    631                 printf("No zone with address %X\n", base);
    632779                return;
    633780        }
     781       
     782        zone = zones.info[znum];
    634783       
    635784        spinlock_lock(&zone->lock);
    636785        printf("Memory zone information\n\n");
    637         printf("Zone base address: %P\n", zone->base);
    638         printf("Zone size: %d frames (%dK)\n", zone->free_count + zone->busy_count, ((zone->free_count + zone->busy_count) * FRAME_SIZE) >> 10);
     786        printf("Zone base address: %P\n", PFN2ADDR(zone->base));
     787        printf("Zone size: %d frames (%dK)\n", zone->count, ((zone->count) * FRAME_SIZE) >> 10);
    639788        printf("Allocated space: %d frames (%dK)\n", zone->busy_count, (zone->busy_count * FRAME_SIZE) >> 10);
    640789        printf("Available space: %d (%dK)\n", zone->free_count, (zone->free_count * FRAME_SIZE) >> 10);
     
    644793       
    645794        spinlock_unlock(&zone->lock);
    646         spinlock_unlock(&zone_head_lock);
     795        spinlock_unlock(&zones.lock);
    647796        interrupts_restore(ipl);
    648797}
Note: See TracChangeset for help on using the changeset viewer.