source: mainline/kernel/generic/src/mm/frame.c@ 5f7a0ef

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5f7a0ef was 5f7a0ef, checked in by Jakub Jermar <jakub@…>, 17 years ago

Introduce FRAME_LOW_16_GiB slab/frame allocator flag. When specified, the
allocators will not allocate memory above 16 GiB. Each architecture needs to
make sure not to merge zones from below and above 16 GiB. Allocations that
require memory below 16 GiB need to be altered to use this flag.

  • Property mode set to 100644
File size: 32.5 KB
RevLine 
[f761f1eb]1/*
[df4ed85]2 * Copyright (c) 2001-2005 Jakub Jermar
3 * Copyright (c) 2005 Sergey Bondari
[f761f1eb]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
[cc73a8a1]30/** @addtogroup genericmm
[b45c443]31 * @{
32 */
33
[9179d0a]34/**
[b45c443]35 * @file
[9179d0a]36 * @brief Physical frame allocator.
37 *
38 * This file contains the physical frame allocator and memory zone management.
39 * The frame allocator is built on top of the buddy allocator.
40 *
41 * @see buddy.c
42 */
43
[085d973]44/*
45 * Locking order
46 *
47 * In order to access particular zone, the process must first lock
48 * the zones.lock, then lock the zone and then unlock the zones.lock.
49 * This insures, that we can fiddle with the zones in runtime without
50 * affecting the processes.
51 *
52 */
53
[f761f1eb]54#include <arch/types.h>
55#include <mm/frame.h>
[20d50a1]56#include <mm/as.h>
[f761f1eb]57#include <panic.h>
[fcacfb7]58#include <debug.h>
[5c9a08b]59#include <adt/list.h>
[f761f1eb]60#include <synch/spinlock.h>
[1a1744e]61#include <synch/mutex.h>
62#include <synch/condvar.h>
[18e0a6c]63#include <arch/asm.h>
[9c0a9b3]64#include <arch.h>
[328f2934]65#include <print.h>
[9ebc238]66#include <align.h>
[085d973]67#include <mm/slab.h>
[bb68433]68#include <bitops.h>
[93165be]69#include <macros.h>
[d630139]70#include <config.h>
[18e0a6c]71
[085d973]72typedef struct {
73 count_t refcount; /**< tracking of shared frames */
[7f1c620]74 uint8_t buddy_order; /**< buddy system block order */
[4638401]75 link_t buddy_link; /**< link to the next free block inside one
76 order */
[085d973]77 void *parent; /**< If allocated by slab, this points there */
[f3ac636]78} frame_t;
[fcacfb7]79
[085d973]80typedef struct {
81 SPINLOCK_DECLARE(lock); /**< this lock protects everything below */
[4638401]82 pfn_t base; /**< frame_no of the first frame in the frames
83 array */
[42744880]84 count_t count; /**< Size of zone */
[328f2934]85
[4638401]86 frame_t *frames; /**< array of frame_t structures in this
87 zone */
[085d973]88 count_t free_count; /**< number of free frame_t structures */
89 count_t busy_count; /**< number of busy frame_t structures */
90
[b43eaba0]91 buddy_system_t *buddy_system; /**< buddy system for the zone */
[085d973]92 int flags;
[f3ac636]93} zone_t;
[6e8b3c8]94
[085d973]95/*
96 * The zoneinfo.lock must be locked when accessing zoneinfo structure.
97 * Some of the attributes in zone_t structures are 'read-only'
[84dd253]98 */
[f761f1eb]99
[55b4437]100typedef struct {
[085d973]101 SPINLOCK_DECLARE(lock);
[2936eef]102 unsigned int count;
[085d973]103 zone_t *info[ZONES_MAX];
[55b4437]104} zones_t;
105
106static zones_t zones;
[f761f1eb]107
[1a1744e]108/*
109 * Synchronization primitives used to sleep when there is no memory
110 * available.
111 */
[1bb3766]112mutex_t mem_avail_mtx;
113condvar_t mem_avail_cv;
114unsigned long mem_avail_frames = 0; /**< Number of available frames. */
115unsigned long mem_avail_gen = 0; /**< Generation counter. */
[a294ad0]116
[71eef11]117/********************/
[085d973]118/* Helper functions */
[71eef11]119/********************/
120
[085d973]121static inline index_t frame_index(zone_t *zone, frame_t *frame)
122{
[71eef11]123 return (index_t) (frame - zone->frames);
[a294ad0]124}
[71eef11]125
[085d973]126static inline index_t frame_index_abs(zone_t *zone, frame_t *frame)
[f761f1eb]127{
[71eef11]128 return (index_t) (frame - zone->frames) + zone->base;
[f761f1eb]129}
[71eef11]130
[085d973]131static inline int frame_index_valid(zone_t *zone, index_t index)
[a294ad0]132{
[6c441cf8]133 return (index < zone->count);
[a294ad0]134}
135
[085d973]136/** Compute pfn_t from frame_t pointer & zone pointer */
[42744880]137static index_t make_frame_index(zone_t *zone, frame_t *frame)
[a294ad0]138{
[71eef11]139 return (frame - zone->frames);
[a294ad0]140}
141
[deaf8d5]142/** Initialize frame structure.
[84dd253]143 *
[1bb3766]144 * @param frame Frame structure to be initialized.
[f761f1eb]145 */
[085d973]146static void frame_initialize(frame_t *frame)
[f761f1eb]147{
[085d973]148 frame->refcount = 1;
149 frame->buddy_order = 0;
[f761f1eb]150}
151
[71eef11]152/**********************/
[085d973]153/* Zoneinfo functions */
[71eef11]154/**********************/
[085d973]155
[deaf8d5]156/** Insert-sort zone into zones list.
[bb68433]157 *
[deaf8d5]158 * @param newzone New zone to be inserted into zone list.
159 * @return Zone number on success, -1 on error.
[84dd253]160 */
[bb68433]161static int zones_add_zone(zone_t *newzone)
[f761f1eb]162{
[2936eef]163 unsigned int i, j;
[bb68433]164 ipl_t ipl;
165 zone_t *z;
[4457455]166
[bb68433]167 ipl = interrupts_disable();
[085d973]168 spinlock_lock(&zones.lock);
[71eef11]169
[085d973]170 /* Try to merge */
[71eef11]171 if (zones.count + 1 == ZONES_MAX) {
172 printf("Maximum zone count %u exceeded!\n", ZONES_MAX);
173 spinlock_unlock(&zones.lock);
174 interrupts_restore(ipl);
175 return -1;
176 }
177
[b6b576c]178 for (i = 0; i < zones.count; i++) {
[bb68433]179 /* Check for overflow */
[052da81]180 z = zones.info[i];
[deaf8d5]181 if (overlaps(newzone->base, newzone->count, z->base,
182 z->count)) {
[bb68433]183 printf("Zones overlap!\n");
184 return -1;
[085d973]185 }
[052da81]186 if (newzone->base < z->base)
[bb68433]187 break;
[085d973]188 }
[71eef11]189
[bb68433]190 /* Move other zones up */
[4638401]191 for (j = i; j < zones.count; j++)
[b6b576c]192 zones.info[j + 1] = zones.info[j];
[71eef11]193
[bb68433]194 zones.info[i] = newzone;
195 zones.count++;
[71eef11]196
[085d973]197 spinlock_unlock(&zones.lock);
[bb68433]198 interrupts_restore(ipl);
199
200 return i;
[f761f1eb]201}
[fcacfb7]202
[5f7a0ef]203/** Try to find a zone where can we find the frame.
[71eef11]204 *
[b43eaba0]205 * Assume interrupts are disabled.
[71eef11]206 *
[deaf8d5]207 * @param frame Frame number contained in zone.
208 * @param pzone If not null, it is used as zone hint. Zone index is
209 * filled into the variable on success.
210 * @return Pointer to locked zone containing frame.
[eef75f6]211 */
[deaf8d5]212static zone_t *find_zone_and_lock(pfn_t frame, unsigned int *pzone)
[085d973]213{
[2936eef]214 unsigned int i;
215 unsigned int hint = pzone ? *pzone : 0;
[085d973]216 zone_t *z;
[328f2934]217
[085d973]218 spinlock_lock(&zones.lock);
[4457455]219
[6c441cf8]220 if (hint >= zones.count)
[085d973]221 hint = 0;
[328f2934]222
[085d973]223 i = hint;
224 do {
225 z = zones.info[i];
226 spinlock_lock(&z->lock);
227 if (z->base <= frame && z->base + z->count > frame) {
[4638401]228 /* Unlock the global lock */
229 spinlock_unlock(&zones.lock);
[085d973]230 if (pzone)
231 *pzone = i;
232 return z;
233 }
234 spinlock_unlock(&z->lock);
[328f2934]235
[085d973]236 i++;
237 if (i >= zones.count)
238 i = 0;
[5f7a0ef]239 } while (i != hint);
[328f2934]240
[085d973]241 spinlock_unlock(&zones.lock);
242 return NULL;
243}
[328f2934]244
[bb68433]245/** @return True if zone can allocate specified order */
[7f1c620]246static int zone_can_alloc(zone_t *z, uint8_t order)
[bb68433]247{
248 return buddy_system_can_alloc(z->buddy_system, order);
249}
250
[b43eaba0]251/** Find and lock zone that can allocate order frames.
[fcacfb7]252 *
[b43eaba0]253 * Assume interrupts are disabled.
[fcacfb7]254 *
[deaf8d5]255 * @param order Size (2^order) of free space we are trying to find.
[5f7a0ef]256 * @param flags Required flags of the target zone.
[deaf8d5]257 * @param pzone Pointer to preferred zone or NULL, on return contains
258 * zone number.
[fcacfb7]259 */
[5f7a0ef]260static zone_t *
261find_free_zone_and_lock(uint8_t order, int flags, unsigned int *pzone)
[fcacfb7]262{
[2936eef]263 unsigned int i;
[085d973]264 zone_t *z;
[2936eef]265 unsigned int hint = pzone ? *pzone : 0;
[085d973]266
[5f7a0ef]267 /* Mask off flags that are not applicable. */
268 flags &= FRAME_LOW_16_GiB;
269
[085d973]270 spinlock_lock(&zones.lock);
271 if (hint >= zones.count)
272 hint = 0;
273 i = hint;
274 do {
275 z = zones.info[i];
[5d2ab23]276
[085d973]277 spinlock_lock(&z->lock);
[fcacfb7]278
[5f7a0ef]279 /*
280 * Check whether the zone meets the search criteria.
281 */
282 if ((z->flags & flags) == flags) {
283 /*
284 * Check if the zone has 2^order frames area available.
285 */
286 if (zone_can_alloc(z, order)) {
287 spinlock_unlock(&zones.lock);
288 if (pzone)
289 *pzone = i;
290 return z;
291 }
[328f2934]292 }
[085d973]293 spinlock_unlock(&z->lock);
294 if (++i >= zones.count)
295 i = 0;
[5f7a0ef]296 } while (i != hint);
[085d973]297 spinlock_unlock(&zones.lock);
298 return NULL;
[fcacfb7]299}
300
[b43eaba0]301/**************************/
[085d973]302/* Buddy system functions */
[b43eaba0]303/**************************/
[085d973]304
[deaf8d5]305/** Buddy system find_block implementation.
[fcacfb7]306 *
[085d973]307 * Find block that is parent of current list.
308 * That means go to lower addresses, until such block is found
[fcacfb7]309 *
[deaf8d5]310 * @param order Order of parent must be different then this
311 * parameter!!
[fcacfb7]312 */
[085d973]313static link_t *zone_buddy_find_block(buddy_system_t *b, link_t *child,
[4638401]314 uint8_t order)
[fcacfb7]315{
[4638401]316 frame_t *frame;
317 zone_t *zone;
[085d973]318 index_t index;
[fcacfb7]319
[085d973]320 frame = list_get_instance(child, frame_t, buddy_link);
321 zone = (zone_t *) b->data;
[fcacfb7]322
[085d973]323 index = frame_index(zone, frame);
324 do {
325 if (zone->frames[index].buddy_order != order) {
326 return &zone->frames[index].buddy_link;
327 }
328 } while(index-- > 0);
329 return NULL;
[fcacfb7]330}
[6e8b3c8]331
[deaf8d5]332/** Buddy system find_buddy implementation.
[594a468]333 *
[deaf8d5]334 * @param b Buddy system.
335 * @param block Block for which buddy should be found.
[6e8b3c8]336 *
[deaf8d5]337 * @return Buddy for given block if found.
[6e8b3c8]338 */
[4638401]339static link_t *zone_buddy_find_buddy(buddy_system_t *b, link_t *block)
[085d973]340{
[4638401]341 frame_t *frame;
342 zone_t *zone;
[b87f418]343 index_t index;
[30187eb]344 bool is_left, is_right;
[6e8b3c8]345
[30187eb]346 frame = list_get_instance(block, frame_t, buddy_link);
[328f2934]347 zone = (zone_t *) b->data;
[4638401]348 ASSERT(IS_BUDDY_ORDER_OK(frame_index_abs(zone, frame),
349 frame->buddy_order));
[b87f418]350
[5d2ab23]351 is_left = IS_BUDDY_LEFT_BLOCK_ABS(zone, frame);
352 is_right = IS_BUDDY_RIGHT_BLOCK_ABS(zone, frame);
[085d973]353
[b87f418]354 ASSERT(is_left ^ is_right);
[328f2934]355 if (is_left) {
[deaf8d5]356 index = (frame_index(zone, frame)) +
357 (1 << frame->buddy_order);
[e5a2ee8]358 } else { /* if (is_right) */
[deaf8d5]359 index = (frame_index(zone, frame)) -
360 (1 << frame->buddy_order);
[328f2934]361 }
362
[085d973]363 if (frame_index_valid(zone, index)) {
364 if (zone->frames[index].buddy_order == frame->buddy_order &&
365 zone->frames[index].refcount == 0) {
[328f2934]366 return &zone->frames[index].buddy_link;
[30187eb]367 }
368 }
[085d973]369
[eef75f6]370 return NULL;
[6e8b3c8]371}
372
[deaf8d5]373/** Buddy system bisect implementation.
[6e8b3c8]374 *
[deaf8d5]375 * @param b Buddy system.
376 * @param block Block to bisect.
[30187eb]377 *
[deaf8d5]378 * @return Right block.
[6e8b3c8]379 */
[deaf8d5]380static link_t *zone_buddy_bisect(buddy_system_t *b, link_t *block)
381{
[4638401]382 frame_t *frame_l, *frame_r;
[b87f418]383
[30187eb]384 frame_l = list_get_instance(block, frame_t, buddy_link);
[328f2934]385 frame_r = (frame_l + (1 << (frame_l->buddy_order - 1)));
[b87f418]386
[30187eb]387 return &frame_r->buddy_link;
[6e8b3c8]388}
389
[deaf8d5]390/** Buddy system coalesce implementation.
[6e8b3c8]391 *
[deaf8d5]392 * @param b Buddy system.
393 * @param block_1 First block.
394 * @param block_2 First block's buddy.
[30187eb]395 *
[deaf8d5]396 * @return Coalesced block (actually block that represents lower
397 * address).
[6e8b3c8]398 */
[4638401]399static link_t *zone_buddy_coalesce(buddy_system_t *b, link_t *block_1,
400 link_t *block_2)
[bb68433]401{
[085d973]402 frame_t *frame1, *frame2;
[b87f418]403
[30187eb]404 frame1 = list_get_instance(block_1, frame_t, buddy_link);
405 frame2 = list_get_instance(block_2, frame_t, buddy_link);
[b87f418]406
[328f2934]407 return frame1 < frame2 ? block_1 : block_2;
[6e8b3c8]408}
409
[deaf8d5]410/** Buddy system set_order implementation.
[594a468]411 *
[deaf8d5]412 * @param b Buddy system.
413 * @param block Buddy system block.
414 * @param order Order to set.
[6e8b3c8]415 */
[4638401]416static void zone_buddy_set_order(buddy_system_t *b, link_t *block,
[deaf8d5]417 uint8_t order)
418{
[4638401]419 frame_t *frame;
[30187eb]420 frame = list_get_instance(block, frame_t, buddy_link);
421 frame->buddy_order = order;
[6e8b3c8]422}
423
[deaf8d5]424/** Buddy system get_order implementation.
[594a468]425 *
[deaf8d5]426 * @param b Buddy system.
427 * @param block Buddy system block.
[6e8b3c8]428 *
[deaf8d5]429 * @return Order of block.
[6e8b3c8]430 */
[deaf8d5]431static uint8_t zone_buddy_get_order(buddy_system_t *b, link_t *block)
432{
[4638401]433 frame_t *frame;
[30187eb]434 frame = list_get_instance(block, frame_t, buddy_link);
435 return frame->buddy_order;
[6e8b3c8]436}
[328f2934]437
[deaf8d5]438/** Buddy system mark_busy implementation.
[328f2934]439 *
[deaf8d5]440 * @param b Buddy system.
441 * @param block Buddy system block.
[328f2934]442 */
[deaf8d5]443static void zone_buddy_mark_busy(buddy_system_t *b, link_t * block)
444{
[328f2934]445 frame_t * frame;
[bb68433]446
[328f2934]447 frame = list_get_instance(block, frame_t, buddy_link);
448 frame->refcount = 1;
449}
[dfd9186]450
[deaf8d5]451/** Buddy system mark_available implementation.
[085d973]452 *
[deaf8d5]453 * @param b Buddy system.
454 * @param block Buddy system block.
[085d973]455 */
[deaf8d5]456static void zone_buddy_mark_available(buddy_system_t *b, link_t *block)
457{
[4638401]458 frame_t *frame;
[085d973]459 frame = list_get_instance(block, frame_t, buddy_link);
460 frame->refcount = 0;
461}
462
[0f3fc9b]463static buddy_system_operations_t zone_buddy_system_operations = {
[085d973]464 .find_buddy = zone_buddy_find_buddy,
465 .bisect = zone_buddy_bisect,
466 .coalesce = zone_buddy_coalesce,
467 .set_order = zone_buddy_set_order,
468 .get_order = zone_buddy_get_order,
469 .mark_busy = zone_buddy_mark_busy,
470 .mark_available = zone_buddy_mark_available,
[2ec725f]471 .find_block = zone_buddy_find_block
[085d973]472};
473
[b43eaba0]474/******************/
[085d973]475/* Zone functions */
[b43eaba0]476/******************/
[085d973]477
[deaf8d5]478/** Allocate frame in particular zone.
[085d973]479 *
[deaf8d5]480 * Assume zone is locked.
[9a68b34d]481 * Panics if allocation is impossible.
482 *
[deaf8d5]483 * @param zone Zone to allocate from.
484 * @param order Allocate exactly 2^order frames.
[085d973]485 *
[deaf8d5]486 * @return Frame index in zone.
[9a68b34d]487 *
[085d973]488 */
[7f1c620]489static pfn_t zone_frame_alloc(zone_t *zone, uint8_t order)
[085d973]490{
491 pfn_t v;
492 link_t *tmp;
493 frame_t *frame;
494
495 /* Allocate frames from zone buddy system */
496 tmp = buddy_system_alloc(zone->buddy_system, order);
497
498 ASSERT(tmp);
499
500 /* Update zone information. */
501 zone->free_count -= (1 << order);
502 zone->busy_count += (1 << order);
503
504 /* Frame will be actually a first frame of the block. */
505 frame = list_get_instance(tmp, frame_t, buddy_link);
506
507 /* get frame address */
508 v = make_frame_index(zone, frame);
509 return v;
510}
511
[deaf8d5]512/** Free frame from zone.
[085d973]513 *
[deaf8d5]514 * Assume zone is locked.
[eb3d379]515 *
[deaf8d5]516 * @param zone Pointer to zone from which the frame is to be freed.
517 * @param frame_idx Frame index relative to zone.
[085d973]518 */
[42744880]519static void zone_frame_free(zone_t *zone, index_t frame_idx)
[085d973]520{
521 frame_t *frame;
[7f1c620]522 uint8_t order;
[085d973]523
524 frame = &zone->frames[frame_idx];
525
526 /* remember frame order */
527 order = frame->buddy_order;
528
529 ASSERT(frame->refcount);
530
531 if (!--frame->refcount) {
532 buddy_system_free(zone->buddy_system, &frame->buddy_link);
[d3dfa42]533
534 /* Update zone information. */
535 zone->free_count += (1 << order);
536 zone->busy_count -= (1 << order);
[085d973]537 }
538}
539
[deaf8d5]540/** Return frame from zone. */
[1bb3766]541static frame_t *zone_get_frame(zone_t *zone, index_t frame_idx)
[085d973]542{
543 ASSERT(frame_idx < zone->count);
544 return &zone->frames[frame_idx];
545}
546
[deaf8d5]547/** Mark frame in zone unavailable to allocation. */
[42744880]548static void zone_mark_unavailable(zone_t *zone, index_t frame_idx)
[085d973]549{
550 frame_t *frame;
551 link_t *link;
552
553 frame = zone_get_frame(zone, frame_idx);
[bb68433]554 if (frame->refcount)
555 return;
[4638401]556 link = buddy_system_alloc_block(zone->buddy_system,
557 &frame->buddy_link);
[085d973]558 ASSERT(link);
559 zone->free_count--;
[1bb3766]560
561 mutex_lock(&mem_avail_mtx);
562 mem_avail_frames--;
563 mutex_unlock(&mem_avail_mtx);
[085d973]564}
565
[deaf8d5]566/** Join two zones.
[bb68433]567 *
[deaf8d5]568 * Expect zone_t *z to point to space at least zone_conf_size large.
[bb68433]569 *
[deaf8d5]570 * Assume z1 & z2 are locked.
[eb3d379]571 *
[deaf8d5]572 * @param z Target zone structure pointer.
573 * @param z1 Zone to merge.
574 * @param z2 Zone to merge.
[bb68433]575 */
576static void _zone_merge(zone_t *z, zone_t *z1, zone_t *z2)
577{
[7f1c620]578 uint8_t max_order;
[2936eef]579 unsigned int i;
580 int z2idx;
[bb68433]581 pfn_t frame_idx;
582 frame_t *frame;
583
[4638401]584 ASSERT(!overlaps(z1->base, z1->count, z2->base, z2->count));
[bb68433]585 ASSERT(z1->base < z2->base);
586
587 spinlock_initialize(&z->lock, "zone_lock");
588 z->base = z1->base;
[4638401]589 z->count = z2->base + z2->count - z1->base;
[bb68433]590 z->flags = z1->flags & z2->flags;
591
592 z->free_count = z1->free_count + z2->free_count;
593 z->busy_count = z1->busy_count + z2->busy_count;
594
595 max_order = fnzb(z->count);
596
[4638401]597 z->buddy_system = (buddy_system_t *) &z[1];
598 buddy_system_create(z->buddy_system, max_order,
599 &zone_buddy_system_operations, (void *) z);
[bb68433]600
[4638401]601 z->frames = (frame_t *)((uint8_t *) z->buddy_system +
602 buddy_conf_size(max_order));
[bb68433]603 for (i = 0; i < z->count; i++) {
604 /* This marks all frames busy */
605 frame_initialize(&z->frames[i]);
606 }
607 /* Copy frames from both zones to preserve full frame orders,
[ad64a2d]608 * parents etc. Set all free frames with refcount=0 to 1, because
[bb68433]609 * we add all free frames to buddy allocator later again, clear
[ad64a2d]610 * order to 0. Don't set busy frames with refcount=0, as they
611 * will not be reallocated during merge and it would make later
612 * problems with allocation/free.
[bb68433]613 */
[2936eef]614 for (i = 0; i < z1->count; i++)
[bb68433]615 z->frames[i] = z1->frames[i];
[2936eef]616 for (i = 0; i < z2->count; i++) {
[bb68433]617 z2idx = i + (z2->base - z1->base);
618 z->frames[z2idx] = z2->frames[i];
619 }
[ad64a2d]620 i = 0;
621 while (i < z->count) {
622 if (z->frames[i].refcount) {
623 /* skip busy frames */
624 i += 1 << z->frames[i].buddy_order;
625 } else { /* Free frames, set refcount=1 */
626 /* All free frames have refcount=0, we need not
627 * to check the order */
[bb68433]628 z->frames[i].refcount = 1;
629 z->frames[i].buddy_order = 0;
[ad64a2d]630 i++;
[bb68433]631 }
632 }
633 /* Add free blocks from the 2 original zones */
634 while (zone_can_alloc(z1, 0)) {
635 frame_idx = zone_frame_alloc(z1, 0);
636 frame = &z->frames[frame_idx];
637 frame->refcount = 0;
638 buddy_system_free(z->buddy_system, &frame->buddy_link);
639 }
640 while (zone_can_alloc(z2, 0)) {
641 frame_idx = zone_frame_alloc(z2, 0);
[4638401]642 frame = &z->frames[frame_idx + (z2->base - z1->base)];
[bb68433]643 frame->refcount = 0;
644 buddy_system_free(z->buddy_system, &frame->buddy_link);
645 }
646}
647
[deaf8d5]648/** Return old configuration frames into the zone.
[bb68433]649 *
650 * We have several cases
651 * - the conf. data is outside of zone -> exit, shall we call frame_free??
[874878a]652 * - the conf. data was created by zone_create or
653 * updated with reduce_region -> free every frame
654 *
[deaf8d5]655 * @param newzone The actual zone where freeing should occur.
656 * @param oldzone Pointer to old zone configuration data that should
657 * be freed from new zone.
[bb68433]658 */
659static void return_config_frames(zone_t *newzone, zone_t *oldzone)
660{
661 pfn_t pfn;
662 frame_t *frame;
663 count_t cframes;
[2936eef]664 unsigned int i;
[bb68433]665
[7f1c620]666 pfn = ADDR2PFN((uintptr_t)KA2PA(oldzone));
[bb68433]667 cframes = SIZE2FRAMES(zone_conf_size(oldzone->count));
668
669 if (pfn < newzone->base || pfn >= newzone->base + newzone->count)
670 return;
671
672 frame = &newzone->frames[pfn - newzone->base];
[874878a]673 ASSERT(!frame->buddy_order);
[bb68433]674
[2936eef]675 for (i = 0; i < cframes; i++) {
[bb68433]676 newzone->busy_count++;
677 zone_frame_free(newzone, pfn+i-newzone->base);
678 }
679}
680
[deaf8d5]681/** Reduce allocated block to count of order 0 frames.
[874878a]682 *
683 * The allocated block need 2^order frames of space. Reduce all frames
[eb3d379]684 * in block to order 0 and free the unneeded frames. This means, that
685 * when freeing the previously allocated block starting with frame_idx,
686 * you have to free every frame.
[874878a]687 *
688 * @param zone
[deaf8d5]689 * @param frame_idx Index to block.
690 * @param count Allocated space in block.
[874878a]691 */
692static void zone_reduce_region(zone_t *zone, pfn_t frame_idx, count_t count)
693{
694 count_t i;
[7f1c620]695 uint8_t order;
[874878a]696 frame_t *frame;
697
[2936eef]698 ASSERT(frame_idx + count < zone->count);
[874878a]699
700 order = zone->frames[frame_idx].buddy_order;
[2936eef]701 ASSERT((count_t) (1 << order) >= count);
[874878a]702
703 /* Reduce all blocks to order 0 */
[2936eef]704 for (i = 0; i < (count_t) (1 << order); i++) {
[874878a]705 frame = &zone->frames[i + frame_idx];
706 frame->buddy_order = 0;
[4638401]707 if (!frame->refcount)
[874878a]708 frame->refcount = 1;
709 ASSERT(frame->refcount == 1);
710 }
711 /* Free unneeded frames */
[2936eef]712 for (i = count; i < (count_t) (1 << order); i++) {
[874878a]713 zone_frame_free(zone, i + frame_idx);
714 }
715}
716
[deaf8d5]717/** Merge zones z1 and z2.
[bb68433]718 *
719 * - the zones must be 2 zones with no zone existing in between,
720 * which means that z2 = z1+1
721 *
722 * - When you create a new zone, the frame allocator configuration does
723 * not to be 2^order size. Once the allocator is running it is no longer
724 * possible, merged configuration data occupies more space :-/
725 */
[2936eef]726void zone_merge(unsigned int z1, unsigned int z2)
[bb68433]727{
728 ipl_t ipl;
729 zone_t *zone1, *zone2, *newzone;
[2936eef]730 unsigned int cframes;
[7f1c620]731 uint8_t order;
[2936eef]732 unsigned int i;
[bb68433]733 pfn_t pfn;
734
735 ipl = interrupts_disable();
736 spinlock_lock(&zones.lock);
737
[6c441cf8]738 if ((z1 >= zones.count) || (z2 >= zones.count))
[bb68433]739 goto errout;
740 /* We can join only 2 zones with none existing inbetween */
[1bb3766]741 if (z2 - z1 != 1)
[bb68433]742 goto errout;
743
744 zone1 = zones.info[z1];
745 zone2 = zones.info[z2];
746 spinlock_lock(&zone1->lock);
747 spinlock_lock(&zone2->lock);
748
[4638401]749 cframes = SIZE2FRAMES(zone_conf_size(zone2->base + zone2->count -
750 zone1->base));
[279952c]751 if (cframes == 1)
752 order = 0;
753 else
754 order = fnzb(cframes - 1) + 1;
[bb68433]755
756 /* Allocate zonedata inside one of the zones */
757 if (zone_can_alloc(zone1, order))
758 pfn = zone1->base + zone_frame_alloc(zone1, order);
759 else if (zone_can_alloc(zone2, order))
760 pfn = zone2->base + zone_frame_alloc(zone2, order);
761 else
762 goto errout2;
763
[2936eef]764 newzone = (zone_t *) PA2KA(PFN2ADDR(pfn));
[bb68433]765
766 _zone_merge(newzone, zone1, zone2);
767
[874878a]768 /* Free unneeded config frames */
769 zone_reduce_region(newzone, pfn - newzone->base, cframes);
[bb68433]770 /* Subtract zone information from busy frames */
[874878a]771 newzone->busy_count -= cframes;
[bb68433]772
[874878a]773 /* Replace existing zones in zoneinfo list */
[bb68433]774 zones.info[z1] = newzone;
[b6b576c]775 for (i = z2 + 1; i < zones.count; i++)
776 zones.info[i - 1] = zones.info[i];
[bb68433]777 zones.count--;
778
779 /* Free old zone information */
780 return_config_frames(newzone, zone1);
781 return_config_frames(newzone, zone2);
782errout2:
783 /* Nobody is allowed to enter to zone, so we are safe
784 * to touch the spinlocks last time */
785 spinlock_unlock(&zone1->lock);
786 spinlock_unlock(&zone2->lock);
787errout:
788 spinlock_unlock(&zones.lock);
789 interrupts_restore(ipl);
790}
791
[deaf8d5]792/** Merge all zones into one big zone.
[bb68433]793 *
794 * It is reasonable to do this on systems whose bios reports parts in chunks,
795 * so that we could have 1 zone (it's faster).
796 */
797void zone_merge_all(void)
798{
799 int count = zones.count;
800
801 while (zones.count > 1 && --count) {
[1bb3766]802 zone_merge(0, 1);
[bb68433]803 break;
804 }
805}
806
[deaf8d5]807/** Create new frame zone.
[085d973]808 *
[deaf8d5]809 * @param start Physical address of the first frame within the zone.
810 * @param count Count of frames in zone.
811 * @param z Address of configuration information of zone.
812 * @param flags Zone flags.
[085d973]813 *
[deaf8d5]814 * @return Initialized zone.
[085d973]815 */
[bb68433]816static void zone_construct(pfn_t start, count_t count, zone_t *z, int flags)
[085d973]817{
[2936eef]818 unsigned int i;
[7f1c620]819 uint8_t max_order;
[085d973]820
821 spinlock_initialize(&z->lock, "zone_lock");
822 z->base = start;
823 z->count = count;
[5f7a0ef]824
825 /* Mask off flags that are calculated automatically. */
826 flags &= ~FRAME_LOW_16_GiB;
827 /* Determine calculated flags. */
828 if (z->base + count < (1ULL << (34 - FRAME_WIDTH))) /* 16 GiB */
829 flags |= FRAME_LOW_16_GiB;
830
[085d973]831 z->flags = flags;
[5f7a0ef]832
[085d973]833 z->free_count = count;
834 z->busy_count = 0;
835
836 /*
837 * Compute order for buddy system, initialize
838 */
[bb68433]839 max_order = fnzb(count);
[085d973]840 z->buddy_system = (buddy_system_t *)&z[1];
841
842 buddy_system_create(z->buddy_system, max_order,
[deaf8d5]843 &zone_buddy_system_operations, (void *) z);
[085d973]844
845 /* Allocate frames _after_ the conframe */
846 /* Check sizes */
[4638401]847 z->frames = (frame_t *)((uint8_t *) z->buddy_system +
848 buddy_conf_size(max_order));
[2936eef]849 for (i = 0; i < count; i++) {
[085d973]850 frame_initialize(&z->frames[i]);
851 }
[052da81]852
[085d973]853 /* Stuffing frames */
854 for (i = 0; i < count; i++) {
855 z->frames[i].refcount = 0;
856 buddy_system_free(z->buddy_system, &z->frames[i].buddy_link);
857 }
858}
859
[deaf8d5]860/** Compute configuration data size for zone.
[eb3d379]861 *
[deaf8d5]862 * @param count Size of zone in frames.
863 * @return Size of zone configuration info (in bytes).
[eb3d379]864 */
[7f1c620]865uintptr_t zone_conf_size(count_t count)
[085d973]866{
[2b8b0ca]867 int size = sizeof(zone_t) + count * sizeof(frame_t);
[085d973]868 int max_order;
869
[bb68433]870 max_order = fnzb(count);
[085d973]871 size += buddy_conf_size(max_order);
872 return size;
873}
874
[deaf8d5]875/** Create and add zone to system.
[085d973]876 *
[deaf8d5]877 * @param start First frame number (absolute).
878 * @param count Size of zone in frames.
879 * @param confframe Where configuration frames are supposed to be.
880 * Automatically checks, that we will not disturb the
881 * kernel and possibly init. If confframe is given
882 * _outside_ this zone, it is expected, that the area is
883 * already marked BUSY and big enough to contain
884 * zone_conf_size() amount of data. If the confframe is
885 * inside the area, the zone free frame information is
886 * modified not to include it.
[bb68433]887 *
[deaf8d5]888 * @return Zone number or -1 on error.
[085d973]889 */
[bb68433]890int zone_create(pfn_t start, count_t count, pfn_t confframe, int flags)
[085d973]891{
892 zone_t *z;
[7f1c620]893 uintptr_t addr;
[42744880]894 count_t confcount;
[2936eef]895 unsigned int i;
[bb68433]896 int znum;
[085d973]897
898 /* Theoretically we could have here 0, practically make sure
899 * nobody tries to do that. If some platform requires, remove
900 * the assert
901 */
902 ASSERT(confframe);
903 /* If conframe is supposed to be inside our zone, then make sure
904 * it does not span kernel & init
905 */
[bb68433]906 confcount = SIZE2FRAMES(zone_conf_size(count));
[1bb3766]907 if (confframe >= start && confframe < start + count) {
908 for (; confframe < start + count; confframe++) {
[085d973]909 addr = PFN2ADDR(confframe);
[4638401]910 if (overlaps(addr, PFN2ADDR(confcount),
911 KA2PA(config.base), config.kernel_size))
[085d973]912 continue;
[b6b576c]913
[4638401]914 if (overlaps(addr, PFN2ADDR(confcount),
915 KA2PA(config.stack_base), config.stack_size))
[deaa22f]916 continue;
917
[b6b576c]918 bool overlap = false;
919 count_t i;
920 for (i = 0; i < init.cnt; i++)
[4638401]921 if (overlaps(addr, PFN2ADDR(confcount),
922 KA2PA(init.tasks[i].addr),
923 init.tasks[i].size)) {
[b6b576c]924 overlap = true;
925 break;
926 }
927 if (overlap)
928 continue;
929
[085d973]930 break;
931 }
[b6b576c]932 if (confframe >= start + count)
[085d973]933 panic("Cannot find configuration data for zone.");
934 }
935
[71eef11]936 z = (zone_t *) PA2KA(PFN2ADDR(confframe));
[bb68433]937 zone_construct(start, count, z, flags);
938 znum = zones_add_zone(z);
939 if (znum == -1)
940 return -1;
941
[1bb3766]942 mutex_lock(&mem_avail_mtx);
943 mem_avail_frames += count;
944 mutex_unlock(&mem_avail_mtx);
945
[085d973]946 /* If confdata in zone, mark as unavailable */
[2936eef]947 if (confframe >= start && confframe < start + count)
948 for (i = confframe; i < confframe + confcount; i++) {
[085d973]949 zone_mark_unavailable(z, i - z->base);
950 }
[1bb3766]951
[bb68433]952 return znum;
[085d973]953}
954
955/***************************************/
956/* Frame functions */
957
[deaf8d5]958/** Set parent of frame. */
[2936eef]959void frame_set_parent(pfn_t pfn, void *data, unsigned int hint)
[085d973]960{
961 zone_t *zone = find_zone_and_lock(pfn, &hint);
962
963 ASSERT(zone);
964
[1bb3766]965 zone_get_frame(zone, pfn - zone->base)->parent = data;
[085d973]966 spinlock_unlock(&zone->lock);
967}
968
[4638401]969void *frame_get_parent(pfn_t pfn, unsigned int hint)
[085d973]970{
971 zone_t *zone = find_zone_and_lock(pfn, &hint);
972 void *res;
973
974 ASSERT(zone);
975 res = zone_get_frame(zone, pfn - zone->base)->parent;
976
977 spinlock_unlock(&zone->lock);
978 return res;
979}
980
981/** Allocate power-of-two frames of physical memory.
982 *
[deaf8d5]983 * @param order Allocate exactly 2^order frames.
984 * @param flags Flags for host zone selection and address processing.
985 * @param pzone Preferred zone.
[085d973]986 *
[deaf8d5]987 * @return Physical address of the allocated frame.
[9a68b34d]988 *
[085d973]989 */
[deaf8d5]990void *frame_alloc_generic(uint8_t order, int flags, unsigned int *pzone)
[085d973]991{
992 ipl_t ipl;
993 int freed;
994 pfn_t v;
995 zone_t *zone;
[1bb3766]996 unsigned long gen = 0;
[085d973]997
998loop:
999 ipl = interrupts_disable();
[9a68b34d]1000
[085d973]1001 /*
1002 * First, find suitable frame zone.
1003 */
[5f7a0ef]1004 zone = find_free_zone_and_lock(order, flags, pzone);
[9a68b34d]1005
[085d973]1006 /* If no memory, reclaim some slab memory,
1007 if it does not help, reclaim all */
1008 if (!zone && !(flags & FRAME_NO_RECLAIM)) {
1009 freed = slab_reclaim(0);
1010 if (freed)
[5f7a0ef]1011 zone = find_free_zone_and_lock(order, flags, pzone);
[085d973]1012 if (!zone) {
1013 freed = slab_reclaim(SLAB_RECLAIM_ALL);
1014 if (freed)
[5f7a0ef]1015 zone = find_free_zone_and_lock(order, flags,
1016 pzone);
[085d973]1017 }
1018 }
1019 if (!zone) {
1020 /*
[1a1744e]1021 * Sleep until some frames are available again.
[085d973]1022 */
[1a1744e]1023 if (flags & FRAME_ATOMIC) {
1024 interrupts_restore(ipl);
[2e9eae2]1025 return 0;
[1a1744e]1026 }
[085d973]1027
[1a1744e]1028#ifdef CONFIG_DEBUG
[1bb3766]1029 unsigned long avail;
1030
1031 mutex_lock(&mem_avail_mtx);
1032 avail = mem_avail_frames;
1033 mutex_unlock(&mem_avail_mtx);
1034
1035 printf("Thread %" PRIu64 " waiting for %u frames, "
1036 "%u available.\n", THREAD->tid, 1ULL << order, avail);
[1a1744e]1037#endif
1038
[1bb3766]1039 mutex_lock(&mem_avail_mtx);
1040 while ((mem_avail_frames < (1ULL << order)) ||
1041 gen == mem_avail_gen)
1042 condvar_wait(&mem_avail_cv, &mem_avail_mtx);
1043 gen = mem_avail_gen;
1044 mutex_unlock(&mem_avail_mtx);
[1a1744e]1045
1046#ifdef CONFIG_DEBUG
[1bb3766]1047 mutex_lock(&mem_avail_mtx);
1048 avail = mem_avail_frames;
1049 mutex_unlock(&mem_avail_mtx);
1050
1051 printf("Thread %" PRIu64 " woken up, %u frames available.\n",
1052 THREAD->tid, avail);
[1a1744e]1053#endif
1054
1055 interrupts_restore(ipl);
[085d973]1056 goto loop;
1057 }
[9a68b34d]1058
1059 v = zone_frame_alloc(zone, order);
[085d973]1060 v += zone->base;
1061
1062 spinlock_unlock(&zone->lock);
[1bb3766]1063
1064 mutex_lock(&mem_avail_mtx);
1065 mem_avail_frames -= (1ULL << order);
1066 mutex_unlock(&mem_avail_mtx);
1067
[085d973]1068 interrupts_restore(ipl);
1069
[2e9eae2]1070 if (flags & FRAME_KA)
1071 return (void *)PA2KA(PFN2ADDR(v));
1072 return (void *)PFN2ADDR(v);
[085d973]1073}
1074
1075/** Free a frame.
1076 *
[32fffef0]1077 * Find respective frame structure for supplied physical frame address.
[085d973]1078 * Decrement frame reference count.
1079 * If it drops to zero, move the frame structure to free list.
1080 *
[deaf8d5]1081 * @param frame Physical Address of of the frame to be freed.
[085d973]1082 */
[7f1c620]1083void frame_free(uintptr_t frame)
[085d973]1084{
1085 ipl_t ipl;
1086 zone_t *zone;
[2e9eae2]1087 pfn_t pfn = ADDR2PFN(frame);
[085d973]1088
1089 ipl = interrupts_disable();
[1a1744e]1090
[085d973]1091 /*
1092 * First, find host frame zone for addr.
1093 */
[1a1744e]1094 zone = find_zone_and_lock(pfn, NULL);
[085d973]1095 ASSERT(zone);
1096
[1a1744e]1097 zone_frame_free(zone, pfn - zone->base);
[085d973]1098
1099 spinlock_unlock(&zone->lock);
[1a1744e]1100
1101 /*
1102 * Signal that some memory has been freed.
1103 */
[1bb3766]1104 mutex_lock(&mem_avail_mtx);
1105 mem_avail_frames++;
1106 mem_avail_gen++;
1107 condvar_broadcast(&mem_avail_cv);
1108 mutex_unlock(&mem_avail_mtx);
[1a1744e]1109
[085d973]1110 interrupts_restore(ipl);
1111}
1112
[f3ac636]1113/** Add reference to frame.
1114 *
1115 * Find respective frame structure for supplied PFN and
1116 * increment frame reference count.
1117 *
[deaf8d5]1118 * @param pfn Frame number of the frame to be freed.
[f3ac636]1119 */
1120void frame_reference_add(pfn_t pfn)
1121{
1122 ipl_t ipl;
1123 zone_t *zone;
1124 frame_t *frame;
[085d973]1125
[f3ac636]1126 ipl = interrupts_disable();
1127
1128 /*
1129 * First, find host frame zone for addr.
1130 */
[deaf8d5]1131 zone = find_zone_and_lock(pfn, NULL);
[f3ac636]1132 ASSERT(zone);
1133
[deaf8d5]1134 frame = &zone->frames[pfn - zone->base];
[f3ac636]1135 frame->refcount++;
1136
1137 spinlock_unlock(&zone->lock);
1138 interrupts_restore(ipl);
1139}
[085d973]1140
[deaf8d5]1141/** Mark given range unavailable in frame zones. */
[42744880]1142void frame_mark_unavailable(pfn_t start, count_t count)
[085d973]1143{
[2936eef]1144 unsigned int i;
[085d973]1145 zone_t *zone;
[2936eef]1146 unsigned int prefzone = 0;
[052da81]1147
[2936eef]1148 for (i = 0; i < count; i++) {
[e5a2ee8]1149 zone = find_zone_and_lock(start + i, &prefzone);
[085d973]1150 if (!zone) /* PFN not found */
1151 continue;
[e5a2ee8]1152 zone_mark_unavailable(zone, start + i - zone->base);
[085d973]1153
1154 spinlock_unlock(&zone->lock);
1155 }
1156}
1157
[deaf8d5]1158/** Initialize physical memory management. */
[085d973]1159void frame_init(void)
1160{
1161 if (config.cpu_active == 1) {
1162 zones.count = 0;
[e5a2ee8]1163 spinlock_initialize(&zones.lock, "zones.lock");
[1bb3766]1164 mutex_initialize(&mem_avail_mtx, MUTEX_ACTIVE);
1165 condvar_initialize(&mem_avail_cv);
[085d973]1166 }
1167 /* Tell the architecture to create some memory */
1168 frame_arch_init();
1169 if (config.cpu_active == 1) {
[4638401]1170 frame_mark_unavailable(ADDR2PFN(KA2PA(config.base)),
1171 SIZE2FRAMES(config.kernel_size));
1172 frame_mark_unavailable(ADDR2PFN(KA2PA(config.stack_base)),
1173 SIZE2FRAMES(config.stack_size));
[b6b576c]1174
1175 count_t i;
[4638401]1176 for (i = 0; i < init.cnt; i++) {
1177 pfn_t pfn = ADDR2PFN(KA2PA(init.tasks[i].addr));
1178 frame_mark_unavailable(pfn,
1179 SIZE2FRAMES(init.tasks[i].size));
1180 }
[bffa0b06]1181
[61e90dd]1182 if (ballocs.size)
[4638401]1183 frame_mark_unavailable(ADDR2PFN(KA2PA(ballocs.base)),
1184 SIZE2FRAMES(ballocs.size));
[61e90dd]1185
[bffa0b06]1186 /* Black list first frame, as allocating NULL would
[94d614e]1187 * fail in some places */
[bffa0b06]1188 frame_mark_unavailable(0, 1);
[085d973]1189 }
1190}
1191
1192
[deaf8d5]1193/** Return total size of all zones. */
1194uint64_t zone_total_size(void)
1195{
[71eef11]1196 zone_t *zone = NULL;
1197 unsigned int i;
1198 ipl_t ipl;
1199 uint64_t total = 0;
1200
1201 ipl = interrupts_disable();
1202 spinlock_lock(&zones.lock);
1203
1204 for (i = 0; i < zones.count; i++) {
1205 zone = zones.info[i];
1206 spinlock_lock(&zone->lock);
1207 total += (uint64_t) FRAMES2SIZE(zone->count);
1208 spinlock_unlock(&zone->lock);
1209 }
1210
1211 spinlock_unlock(&zones.lock);
1212 interrupts_restore(ipl);
1213
1214 return total;
1215}
1216
[deaf8d5]1217/** Prints list of zones. */
1218void zone_print_list(void)
1219{
[dfd9186]1220 zone_t *zone = NULL;
[2936eef]1221 unsigned int i;
[263104b]1222 ipl_t ipl;
1223
[2b8b0ca]1224#ifdef __32_BITS__
1225 printf("# base address free frames busy frames\n");
1226 printf("-- ------------ ------------ ------------\n");
1227#endif
1228
1229#ifdef __64_BITS__
1230 printf("# base address free frames busy frames\n");
1231 printf("-- -------------------- ------------ ------------\n");
1232#endif
[43b1e86]1233
[000350f8]1234 /*
1235 * Because printing may require allocation of memory, we may not hold
1236 * the frame allocator locks when printing zone statistics. Therefore,
1237 * we simply gather the statistics under the protection of the locks and
1238 * print the statistics when the locks have been released.
1239 *
1240 * When someone adds/removes zones while we are printing the statistics,
1241 * we may end up with inaccurate output (e.g. a zone being skipped from
1242 * the listing).
1243 */
1244
1245 for (i = 0; ; i++) {
1246 uintptr_t base;
1247 count_t free_count;
1248 count_t busy_count;
1249
1250 ipl = interrupts_disable();
1251 spinlock_lock(&zones.lock);
1252
1253 if (i >= zones.count) {
1254 spinlock_unlock(&zones.lock);
1255 interrupts_restore(ipl);
1256 break;
1257 }
1258
[085d973]1259 zone = zones.info[i];
[566ba81]1260 spinlock_lock(&zone->lock);
[2b8b0ca]1261
[000350f8]1262 base = PFN2ADDR(zone->base);
1263 free_count = zone->free_count;
1264 busy_count = zone->busy_count;
1265
1266 spinlock_unlock(&zone->lock);
1267
1268 spinlock_unlock(&zones.lock);
1269 interrupts_restore(ipl);
1270
[2b8b0ca]1271#ifdef __32_BITS__
[000350f8]1272 printf("%-2u %10p %12" PRIc " %12" PRIc "\n", i, base,
1273 free_count, busy_count);
[2b8b0ca]1274#endif
1275
1276#ifdef __64_BITS__
[000350f8]1277 printf("%-2u %18p %12" PRIc " %12" PRIc "\n", i, base,
1278 free_count, busy_count);
[2b8b0ca]1279#endif
[43b1e86]1280
[dfd9186]1281 }
1282}
1283
[abbc16e]1284/** Prints zone details.
[96cacc1]1285 *
[deaf8d5]1286 * @param num Zone base address or zone number.
[96cacc1]1287 */
[deaf8d5]1288void zone_print_one(unsigned int num)
1289{
[085d973]1290 zone_t *zone = NULL;
[263104b]1291 ipl_t ipl;
[2936eef]1292 unsigned int i;
[2ec725f]1293 uintptr_t base;
1294 count_t count;
1295 count_t busy_count;
1296 count_t free_count;
[263104b]1297
1298 ipl = interrupts_disable();
[085d973]1299 spinlock_lock(&zones.lock);
[bb68433]1300
[b6b576c]1301 for (i = 0; i < zones.count; i++) {
[71eef11]1302 if ((i == num) || (PFN2ADDR(zones.info[i]->base) == num)) {
[bb68433]1303 zone = zones.info[i];
1304 break;
1305 }
1306 }
1307 if (!zone) {
[2ec725f]1308 spinlock_unlock(&zones.lock);
1309 interrupts_restore(ipl);
[bb68433]1310 printf("Zone not found.\n");
[2ec725f]1311 return;
[dfd9186]1312 }
[085d973]1313
[566ba81]1314 spinlock_lock(&zone->lock);
[2ec725f]1315 base = PFN2ADDR(zone->base);
1316 count = zone->count;
1317 busy_count = zone->busy_count;
1318 free_count = zone->free_count;
[566ba81]1319 spinlock_unlock(&zone->lock);
[085d973]1320 spinlock_unlock(&zones.lock);
[263104b]1321 interrupts_restore(ipl);
[2ec725f]1322
1323 printf("Zone base address: %p\n", base);
1324 printf("Zone size: %" PRIc " frames (%" PRIs " KiB)\n", count,
1325 SIZE2KB(FRAMES2SIZE(count)));
1326 printf("Allocated space: %" PRIc " frames (%" PRIs " KiB)\n",
1327 busy_count, SIZE2KB(FRAMES2SIZE(busy_count)));
1328 printf("Available space: %" PRIc " frames (%" PRIs " KiB)\n",
1329 free_count, SIZE2KB(FRAMES2SIZE(free_count)));
[dfd9186]1330}
1331
[cc73a8a1]1332/** @}
[b45c443]1333 */
[4638401]1334
Note: See TracBrowser for help on using the repository browser.