source: mainline/kernel/generic/src/mm/frame.c@ 98000fb

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 98000fb was 98000fb, checked in by Martin Decky <martin@…>, 16 years ago

remove redundant index_t and count_t types (which were always quite ambiguous and not actually needed)

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