source: mainline/kernel/generic/src/mm/frame.c@ 498b201

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

The real intention of the previous commit was to put the boundary
on 4 GiB, not 16 GiB.

  • 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. */
[498b201]268 flags &= FRAME_LOW_4_GiB;
[5f7a0ef]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. */
[498b201]826 flags &= ~FRAME_LOW_4_GiB;
[5f7a0ef]827 /* Determine calculated flags. */
[498b201]828 if (z->base + count < (1ULL << (32 - FRAME_WIDTH))) /* 4 GiB */
829 flags |= FRAME_LOW_4_GiB;
[5f7a0ef]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.