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

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

bitmap frame allocator does not keep track of the size of the allocated frame blocks
to avoid memory leaks the number of allocated frames needs to be passed explicitly during deallocation

  • Property mode set to 100644
File size: 31.3 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.
[b0c2075]40 * The frame allocator is built on top of the two-level bitmap structure.
[9179d0a]41 *
42 */
43
[d99c1d2]44#include <typedefs.h>
[f761f1eb]45#include <mm/frame.h>
[89bcb520]46#include <mm/reserve.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>
[933cadf]61#include <str.h>
[18e0a6c]62
[b0c2075]63#define BITMAP_BLOCK_SIZE 1024
64
[e49e234]65zones_t zones;
[f761f1eb]66
[1a1744e]67/*
68 * Synchronization primitives used to sleep when there is no memory
69 * available.
70 */
[da1bafb]71static mutex_t mem_avail_mtx;
72static condvar_t mem_avail_cv;
73static size_t mem_avail_req = 0; /**< Number of frames requested. */
74static size_t mem_avail_gen = 0; /**< Generation counter. */
[a294ad0]75
[71eef11]76/********************/
[085d973]77/* Helper functions */
[71eef11]78/********************/
79
[7a0359b]80NO_TRACE static inline size_t frame_index(zone_t *zone, frame_t *frame)
[085d973]81{
[98000fb]82 return (size_t) (frame - zone->frames);
[a294ad0]83}
[71eef11]84
[7a0359b]85NO_TRACE static inline size_t frame_index_abs(zone_t *zone, frame_t *frame)
[f761f1eb]86{
[98000fb]87 return (size_t) (frame - zone->frames) + zone->base;
[f761f1eb]88}
[71eef11]89
[7a0359b]90NO_TRACE static inline bool frame_index_valid(zone_t *zone, size_t index)
[a294ad0]91{
[6c441cf8]92 return (index < zone->count);
[a294ad0]93}
94
[deaf8d5]95/** Initialize frame structure.
[84dd253]96 *
[5f0f29ce]97 * @param frame Frame structure to be initialized.
98 *
[f761f1eb]99 */
[7a0359b]100NO_TRACE static void frame_initialize(frame_t *frame)
[f761f1eb]101{
[b0c2075]102 frame->refcount = 0;
103 frame->parent = NULL;
[f761f1eb]104}
105
[5f0f29ce]106/*******************/
107/* Zones functions */
108/*******************/
[085d973]109
[deaf8d5]110/** Insert-sort zone into zones list.
[bb68433]111 *
[5f0f29ce]112 * Assume interrupts are disabled and zones lock is
113 * locked.
114 *
115 * @param base Base frame of the newly inserted zone.
116 * @param count Number of frames of the newly inserted zone.
117 *
118 * @return Zone number on success, -1 on error.
119 *
[84dd253]120 */
[e2650d3]121NO_TRACE static size_t zones_insert_zone(pfn_t base, size_t count,
122 zone_flags_t flags)
[f761f1eb]123{
[71eef11]124 if (zones.count + 1 == ZONES_MAX) {
125 printf("Maximum zone count %u exceeded!\n", ZONES_MAX);
[98000fb]126 return (size_t) -1;
[71eef11]127 }
128
[98000fb]129 size_t i;
[b6b576c]130 for (i = 0; i < zones.count; i++) {
[5f0f29ce]131 /* Check for overlap */
[e2650d3]132 if (overlaps(zones.info[i].base, zones.info[i].count,
133 base, count)) {
134
135 /*
136 * If the overlaping zones are of the same type
137 * and the new zone is completely within the previous
138 * one, then quietly ignore the new zone.
139 *
140 */
141
142 if ((zones.info[i].flags != flags) ||
143 (!iswithin(zones.info[i].base, zones.info[i].count,
144 base, count))) {
[7e752b2]145 printf("Zone (%p, %p) overlaps "
146 "with previous zone (%p %p)!\n",
147 (void *) PFN2ADDR(base), (void *) PFN2ADDR(count),
148 (void *) PFN2ADDR(zones.info[i].base),
149 (void *) PFN2ADDR(zones.info[i].count));
[e2650d3]150 }
151
[98000fb]152 return (size_t) -1;
[085d973]153 }
[5f0f29ce]154 if (base < zones.info[i].base)
[bb68433]155 break;
[085d973]156 }
[71eef11]157
[bb68433]158 /* Move other zones up */
[b0c2075]159 for (size_t j = zones.count; j > i; j--)
[e49e234]160 zones.info[j] = zones.info[j - 1];
[71eef11]161
[bb68433]162 zones.count++;
[71eef11]163
[bb68433]164 return i;
[f761f1eb]165}
[fcacfb7]166
[5f0f29ce]167/** Get total available frames.
168 *
169 * Assume interrupts are disabled and zones lock is
170 * locked.
[71eef11]171 *
[5f0f29ce]172 * @return Total number of available frames.
[71eef11]173 *
[eef75f6]174 */
[8d308b9]175NO_TRACE static size_t frame_total_free_get_internal(void)
[085d973]176{
[98000fb]177 size_t total = 0;
178 size_t i;
[8d308b9]179
[5f0f29ce]180 for (i = 0; i < zones.count; i++)
181 total += zones.info[i].free_count;
[328f2934]182
[5f0f29ce]183 return total;
184}
[8d308b9]185
186NO_TRACE size_t frame_total_free_get(void)
187{
188 size_t total;
189
190 irq_spinlock_lock(&zones.lock, true);
191 total = frame_total_free_get_internal();
192 irq_spinlock_unlock(&zones.lock, true);
193
194 return total;
195}
196
[4457455]197
[e49e234]198/** Find a zone with a given frames.
[5f0f29ce]199 *
200 * Assume interrupts are disabled and zones lock is
201 * locked.
202 *
203 * @param frame Frame number contained in zone.
[e49e234]204 * @param count Number of frames to look for.
[5f0f29ce]205 * @param hint Used as zone hint.
206 *
207 * @return Zone index or -1 if not found.
208 *
209 */
[97bdb4a]210NO_TRACE size_t find_zone(pfn_t frame, size_t count, size_t hint)
[5f0f29ce]211{
[6c441cf8]212 if (hint >= zones.count)
[085d973]213 hint = 0;
[328f2934]214
[98000fb]215 size_t i = hint;
[085d973]216 do {
[5f0f29ce]217 if ((zones.info[i].base <= frame)
[e49e234]218 && (zones.info[i].base + zones.info[i].count >= frame + count))
[5f0f29ce]219 return i;
220
[085d973]221 i++;
222 if (i >= zones.count)
223 i = 0;
[da1bafb]224
[5f7a0ef]225 } while (i != hint);
[5f0f29ce]226
[98000fb]227 return (size_t) -1;
[085d973]228}
[328f2934]229
[b0c2075]230/** @return True if zone can allocate specified number of frames */
231NO_TRACE static bool zone_can_alloc(zone_t *zone, size_t count,
232 pfn_t constraint)
[bb68433]233{
[b0c2075]234 /*
235 * The function bitmap_allocate_range() does not modify
236 * the bitmap if the last argument is NULL.
237 */
[e6c4b94]238 return ((zone->flags & ZONE_AVAILABLE) &&
[b0c2075]239 bitmap_allocate_range(&zone->bitmap, count, zone->base,
240 constraint, NULL));
[bb68433]241}
242
[b0c2075]243/** Find a zone that can allocate specified number of frames
[5f0f29ce]244 *
245 * Assume interrupts are disabled and zones lock is
246 * locked.
[fcacfb7]247 *
[b0c2075]248 * @param count Number of free frames we are trying to find.
249 * @param flags Required flags of the target zone.
250 * @param constraint Indication of bits that cannot be set in the
251 * physical frame number of the first allocated frame.
252 * @param hind Preferred zone.
[fcacfb7]253 *
254 */
[b0c2075]255NO_TRACE static size_t find_free_zone(size_t count, zone_flags_t flags,
256 pfn_t constraint, size_t hint)
[fcacfb7]257{
[085d973]258 if (hint >= zones.count)
259 hint = 0;
[5f0f29ce]260
[98000fb]261 size_t i = hint;
[085d973]262 do {
[5f7a0ef]263 /*
264 * Check whether the zone meets the search criteria.
265 */
[e6c4b94]266 if (ZONE_FLAGS_MATCH(zones.info[i].flags, flags)) {
[5f7a0ef]267 /*
[b0c2075]268 * Check if the zone can satisfy the allocation request.
[5f7a0ef]269 */
[b0c2075]270 if (zone_can_alloc(&zones.info[i], count, constraint))
[5f0f29ce]271 return i;
[328f2934]272 }
[5f0f29ce]273
274 i++;
275 if (i >= zones.count)
[085d973]276 i = 0;
[da1bafb]277
[5f7a0ef]278 } while (i != hint);
[5f0f29ce]279
[98000fb]280 return (size_t) -1;
[fcacfb7]281}
282
[b0c2075]283/******************/
284/* Zone functions */
285/******************/
[6e8b3c8]286
[b0c2075]287/** Return frame from zone. */
288NO_TRACE static frame_t *zone_get_frame(zone_t *zone, size_t index)
[bb68433]289{
[b0c2075]290 ASSERT(index < zone->count);
[b87f418]291
[b0c2075]292 return &zone->frames[index];
[6e8b3c8]293}
294
[deaf8d5]295/** Allocate frame in particular zone.
[085d973]296 *
[5f0f29ce]297 * Assume zone is locked and is available for allocation.
[9a68b34d]298 * Panics if allocation is impossible.
299 *
[b0c2075]300 * @param zone Zone to allocate from.
301 * @param count Number of frames to allocate
302 * @param constraint Indication of bits that cannot be set in the
303 * physical frame number of the first allocated frame.
[085d973]304 *
[5f0f29ce]305 * @return Frame index in zone.
[9a68b34d]306 *
[085d973]307 */
[b0c2075]308NO_TRACE static size_t zone_frame_alloc(zone_t *zone, size_t count,
309 pfn_t constraint)
[085d973]310{
[e6c4b94]311 ASSERT(zone->flags & ZONE_AVAILABLE);
[5f0f29ce]312
[b0c2075]313 /* Allocate frames from zone */
314 size_t index;
315 int avail = bitmap_allocate_range(&zone->bitmap, count, zone->base,
316 constraint, &index);
317
318 ASSERT(avail);
[085d973]319
[b0c2075]320 /* Update frame reference count */
321 for (size_t i = 0; i < count; i++) {
322 frame_t *frame = zone_get_frame(zone, index + i);
323
324 ASSERT(frame->refcount == 0);
325 frame->refcount = 1;
326 }
[085d973]327
328 /* Update zone information. */
[b0c2075]329 zone->free_count -= count;
330 zone->busy_count += count;
[5f0f29ce]331
[b0c2075]332 return index;
[085d973]333}
334
[deaf8d5]335/** Free frame from zone.
[085d973]336 *
[5f0f29ce]337 * Assume zone is locked and is available for deallocation.
338 *
[b0c2075]339 * @param zone Pointer to zone from which the frame is to be freed.
340 * @param index Frame index relative to zone.
[eb3d379]341 *
[b0c2075]342 * @return Number of freed frames.
[89bcb520]343 *
[085d973]344 */
[b0c2075]345NO_TRACE static size_t zone_frame_free(zone_t *zone, size_t index)
[085d973]346{
[e6c4b94]347 ASSERT(zone->flags & ZONE_AVAILABLE);
[5f0f29ce]348
[b0c2075]349 frame_t *frame = zone_get_frame(zone, index);
[085d973]350
[b0c2075]351 ASSERT(frame->refcount > 0);
[5f0f29ce]352
[085d973]353 if (!--frame->refcount) {
[b0c2075]354 bitmap_free_range(&zone->bitmap, index, 1);
355
[d3dfa42]356 /* Update zone information. */
[b0c2075]357 zone->free_count++;
358 zone->busy_count--;
359
[5df1963]360 return 1;
[085d973]361 }
[89bcb520]362
[5df1963]363 return 0;
[085d973]364}
365
[deaf8d5]366/** Mark frame in zone unavailable to allocation. */
[b0c2075]367NO_TRACE static void zone_mark_unavailable(zone_t *zone, size_t index)
[085d973]368{
[aaceebc4]369 if (!(zone->flags & ZONE_AVAILABLE))
370 return;
[5f0f29ce]371
[b0c2075]372 frame_t *frame = zone_get_frame(zone, index);
373 if (frame->refcount > 0)
[bb68433]374 return;
[5f0f29ce]375
[b0c2075]376 bitmap_set_range(&zone->bitmap, index, 1);
[5f0f29ce]377
[085d973]378 zone->free_count--;
[d060900]379 reserve_force_alloc(1);
[085d973]380}
381
[5f0f29ce]382/** Merge two zones.
[bb68433]383 *
[5f0f29ce]384 * Assume z1 & z2 are locked and compatible and zones lock is
385 * locked.
[bb68433]386 *
[b0c2075]387 * @param z1 First zone to merge.
388 * @param z2 Second zone to merge.
389 * @param old_z1 Original data of the first zone.
390 * @param confdata Merged zone configuration data.
[eb3d379]391 *
[bb68433]392 */
[7a0359b]393NO_TRACE static void zone_merge_internal(size_t z1, size_t z2, zone_t *old_z1,
[b0c2075]394 void *confdata)
[bb68433]395{
[e6c4b94]396 ASSERT(zones.info[z1].flags & ZONE_AVAILABLE);
397 ASSERT(zones.info[z2].flags & ZONE_AVAILABLE);
[5f0f29ce]398 ASSERT(zones.info[z1].flags == zones.info[z2].flags);
399 ASSERT(zones.info[z1].base < zones.info[z2].base);
400 ASSERT(!overlaps(zones.info[z1].base, zones.info[z1].count,
401 zones.info[z2].base, zones.info[z2].count));
402
403 /* Difference between zone bases */
404 pfn_t base_diff = zones.info[z2].base - zones.info[z1].base;
405
406 zones.info[z1].count = base_diff + zones.info[z2].count;
407 zones.info[z1].free_count += zones.info[z2].free_count;
408 zones.info[z1].busy_count += zones.info[z2].busy_count;
409
[b0c2075]410 bitmap_initialize(&zones.info[z1].bitmap, zones.info[z1].count,
411 BITMAP_BLOCK_SIZE, confdata +
412 (sizeof(frame_t) * zones.info[z1].count));
[5f0f29ce]413
[b0c2075]414 zones.info[z1].frames = (frame_t *) confdata;
[5f0f29ce]415
[b0c2075]416 /*
417 * Copy frames and bits from both zones to preserve parents, etc.
[bb68433]418 */
[5f0f29ce]419
[b0c2075]420 for (size_t i = 0; i < old_z1->count; i++) {
421 bitmap_set(&zones.info[z1].bitmap, i,
422 bitmap_get(&old_z1->bitmap, i));
423 zones.info[z1].frames[i] = old_z1->frames[i];
[bb68433]424 }
[5f0f29ce]425
[b0c2075]426 for (size_t i = 0; i < zones.info[z2].count; i++) {
427 bitmap_set(&zones.info[z1].bitmap, base_diff + i,
428 bitmap_get(&zones.info[z2].bitmap, i));
429 zones.info[z1].frames[base_diff + i] =
430 zones.info[z2].frames[i];
[bb68433]431 }
432}
433
[deaf8d5]434/** Return old configuration frames into the zone.
[bb68433]435 *
[5f0f29ce]436 * We have two cases:
437 * - The configuration data is outside the zone
438 * -> do nothing (perhaps call frame_free?)
439 * - The configuration data was created by zone_create
440 * or updated by reduce_region -> free every frame
441 *
442 * @param znum The actual zone where freeing should occur.
443 * @param pfn Old zone configuration frame.
444 * @param count Old zone frame count.
[874878a]445 *
[bb68433]446 */
[7a0359b]447NO_TRACE static void return_config_frames(size_t znum, pfn_t pfn, size_t count)
[bb68433]448{
[e6c4b94]449 ASSERT(zones.info[znum].flags & ZONE_AVAILABLE);
[5f0f29ce]450
[98000fb]451 size_t cframes = SIZE2FRAMES(zone_conf_size(count));
[bb68433]452
[b0c2075]453 if ((pfn < zones.info[znum].base) ||
454 (pfn >= zones.info[znum].base + zones.info[znum].count))
[bb68433]455 return;
[5f0f29ce]456
[b0c2075]457 for (size_t i = 0; i < cframes; i++)
[89bcb520]458 (void) zone_frame_free(&zones.info[znum],
[5f0f29ce]459 pfn - zones.info[znum].base + i);
[874878a]460}
461
[deaf8d5]462/** Merge zones z1 and z2.
[bb68433]463 *
[5f0f29ce]464 * The merged zones must be 2 zones with no zone existing in between
465 * (which means that z2 = z1 + 1). Both zones must be available zones
466 * with the same flags.
467 *
468 * When you create a new zone, the frame allocator configuration does
469 * not to be 2^order size. Once the allocator is running it is no longer
470 * possible, merged configuration data occupies more space :-/
471 *
[bb68433]472 */
[98000fb]473bool zone_merge(size_t z1, size_t z2)
[bb68433]474{
[da1bafb]475 irq_spinlock_lock(&zones.lock, true);
[5f0f29ce]476
477 bool ret = true;
478
[b0c2075]479 /*
480 * We can join only 2 zones with none existing inbetween,
[5f0f29ce]481 * the zones have to be available and with the same
482 * set of flags
483 */
[e6c4b94]484 if ((z1 >= zones.count) || (z2 >= zones.count) || (z2 - z1 != 1) ||
485 (zones.info[z1].flags != zones.info[z2].flags)) {
[5f0f29ce]486 ret = false;
[bb68433]487 goto errout;
[5f0f29ce]488 }
489
490 pfn_t cframes = SIZE2FRAMES(zone_conf_size(
491 zones.info[z2].base - zones.info[z1].base
492 + zones.info[z2].count));
493
494 /* Allocate merged zone data inside one of the zones */
495 pfn_t pfn;
[b0c2075]496 if (zone_can_alloc(&zones.info[z1], cframes, 0)) {
497 pfn = zones.info[z1].base +
498 zone_frame_alloc(&zones.info[z1], cframes, 0);
499 } else if (zone_can_alloc(&zones.info[z2], cframes, 0)) {
500 pfn = zones.info[z2].base +
501 zone_frame_alloc(&zones.info[z2], cframes, 0);
[5f0f29ce]502 } else {
503 ret = false;
504 goto errout;
505 }
506
507 /* Preserve original data from z1 */
508 zone_t old_z1 = zones.info[z1];
509
510 /* Do zone merging */
[b0c2075]511 zone_merge_internal(z1, z2, &old_z1, (void *) PA2KA(PFN2ADDR(pfn)));
[5f0f29ce]512
[bb68433]513 /* Subtract zone information from busy frames */
[5f0f29ce]514 zones.info[z1].busy_count -= cframes;
515
516 /* Free old zone information */
517 return_config_frames(z1,
518 ADDR2PFN(KA2PA((uintptr_t) old_z1.frames)), old_z1.count);
519 return_config_frames(z1,
520 ADDR2PFN(KA2PA((uintptr_t) zones.info[z2].frames)),
521 zones.info[z2].count);
522
[e49e234]523 /* Move zones down */
[b0c2075]524 for (size_t i = z2 + 1; i < zones.count; i++)
[b6b576c]525 zones.info[i - 1] = zones.info[i];
[e49e234]526
[bb68433]527 zones.count--;
[5f0f29ce]528
[bb68433]529errout:
[da1bafb]530 irq_spinlock_unlock(&zones.lock, true);
[5f0f29ce]531
532 return ret;
[bb68433]533}
534
[5f0f29ce]535/** Merge all mergeable zones into one big zone.
536 *
537 * It is reasonable to do this on systems where
538 * BIOS reports parts in chunks, so that we could
539 * have 1 zone (it's faster).
[bb68433]540 *
541 */
542void zone_merge_all(void)
543{
[b0c2075]544 size_t i = 1;
545
[5f0f29ce]546 while (i < zones.count) {
[b0c2075]547 if (!zone_merge(i - 1, i))
[5f0f29ce]548 i++;
[bb68433]549 }
550}
551
[deaf8d5]552/** Create new frame zone.
[085d973]553 *
[b0c2075]554 * @param zone Zone to construct.
555 * @param start Physical address of the first frame within the zone.
556 * @param count Count of frames in zone.
557 * @param flags Zone flags.
558 * @param confdata Configuration data of the zone.
[5f0f29ce]559 *
560 * @return Initialized zone.
[085d973]561 *
562 */
[b0c2075]563NO_TRACE static void zone_construct(zone_t *zone, pfn_t start, size_t count,
564 zone_flags_t flags, void *confdata)
[085d973]565{
[5f0f29ce]566 zone->base = start;
567 zone->count = count;
568 zone->flags = flags;
569 zone->free_count = count;
570 zone->busy_count = 0;
[085d973]571
[e6c4b94]572 if (flags & ZONE_AVAILABLE) {
[5f0f29ce]573 /*
[b0c2075]574 * Initialize frame bitmap (located after the array of
575 * frame_t structures in the configuration space).
[5f0f29ce]576 */
577
[b0c2075]578 bitmap_initialize(&zone->bitmap, count, BITMAP_BLOCK_SIZE,
579 confdata + (sizeof(frame_t) * count));
[5f0f29ce]580
[b0c2075]581 /*
582 * Initialize the array of frame_t structures.
583 */
[5f0f29ce]584
[b0c2075]585 zone->frames = (frame_t *) confdata;
[5f0f29ce]586
[b0c2075]587 for (size_t i = 0; i < count; i++)
588 frame_initialize(&zone->frames[i]);
589 } else {
590 bitmap_initialize(&zone->bitmap, 0, 0, NULL);
[5f0f29ce]591 zone->frames = NULL;
[b0c2075]592 }
[085d973]593}
594
[deaf8d5]595/** Compute configuration data size for zone.
[eb3d379]596 *
[5f0f29ce]597 * @param count Size of zone in frames.
598 *
599 * @return Size of zone configuration info (in bytes).
600 *
[eb3d379]601 */
[bbfdf62]602size_t zone_conf_size(size_t count)
[085d973]603{
[b0c2075]604 return (count * sizeof(frame_t) +
605 bitmap_size(count, BITMAP_BLOCK_SIZE));
[085d973]606}
607
[8bdcffa]608/** Allocate external configuration frames from low memory. */
609pfn_t zone_external_conf_alloc(size_t count)
610{
[b0c2075]611 size_t frames = SIZE2FRAMES(zone_conf_size(count));
612
613 return ADDR2PFN((uintptr_t)
614 frame_alloc(frames, FRAME_LOWMEM | FRAME_ATOMIC, 0));
[8bdcffa]615}
616
[deaf8d5]617/** Create and add zone to system.
[085d973]618 *
[5f0f29ce]619 * @param start First frame number (absolute).
620 * @param count Size of zone in frames.
621 * @param confframe Where configuration frames are supposed to be.
[b0c2075]622 * Automatically checks that we will not disturb the
[5f0f29ce]623 * kernel and possibly init. If confframe is given
624 * _outside_ this zone, it is expected, that the area is
625 * already marked BUSY and big enough to contain
626 * zone_conf_size() amount of data. If the confframe is
627 * inside the area, the zone free frame information is
628 * modified not to include it.
629 *
630 * @return Zone number or -1 on error.
631 *
[085d973]632 */
[da1bafb]633size_t zone_create(pfn_t start, size_t count, pfn_t confframe,
634 zone_flags_t flags)
[085d973]635{
[da1bafb]636 irq_spinlock_lock(&zones.lock, true);
[5f0f29ce]637
[e6c4b94]638 if (flags & ZONE_AVAILABLE) { /* Create available zone */
[b0c2075]639 /*
640 * Theoretically we could have NULL here, practically make sure
[5f0f29ce]641 * nobody tries to do that. If some platform requires, remove
642 * the assert
643 */
[0b4a67a]644 ASSERT(confframe != ADDR2PFN((uintptr_t ) NULL));
[b0c2075]645
[40c8c17]646 /* Update the known end of physical memory. */
647 config.physmem_end = max(config.physmem_end, PFN2ADDR(start + count));
[5f0f29ce]648
[b0c2075]649 /*
650 * If confframe is supposed to be inside our zone, then make sure
[5f0f29ce]651 * it does not span kernel & init
652 */
[98000fb]653 size_t confcount = SIZE2FRAMES(zone_conf_size(count));
[b0c2075]654
[5f0f29ce]655 if ((confframe >= start) && (confframe < start + count)) {
656 for (; confframe < start + count; confframe++) {
657 uintptr_t addr = PFN2ADDR(confframe);
658 if (overlaps(addr, PFN2ADDR(confcount),
659 KA2PA(config.base), config.kernel_size))
660 continue;
661
[4638401]662 if (overlaps(addr, PFN2ADDR(confcount),
[5f0f29ce]663 KA2PA(config.stack_base), config.stack_size))
664 continue;
665
666 bool overlap = false;
[b0c2075]667 for (size_t i = 0; i < init.cnt; i++) {
[5f0f29ce]668 if (overlaps(addr, PFN2ADDR(confcount),
[32817cc]669 init.tasks[i].paddr,
[5f0f29ce]670 init.tasks[i].size)) {
671 overlap = true;
672 break;
673 }
[b0c2075]674 }
675
[5f0f29ce]676 if (overlap)
677 continue;
678
679 break;
680 }
[b6b576c]681
[b0c2075]682 if (confframe >= start + count)
683 panic("Cannot find configuration data for zone.");
[085d973]684 }
[5f0f29ce]685
[e2650d3]686 size_t znum = zones_insert_zone(start, count, flags);
[98000fb]687 if (znum == (size_t) -1) {
[da1bafb]688 irq_spinlock_unlock(&zones.lock, true);
[98000fb]689 return (size_t) -1;
[5f0f29ce]690 }
691
[b0c2075]692 void *confdata = (void *) PA2KA(PFN2ADDR(confframe));
693 zone_construct(&zones.info[znum], start, count, flags, confdata);
[5f0f29ce]694
695 /* If confdata in zone, mark as unavailable */
696 if ((confframe >= start) && (confframe < start + count)) {
[b0c2075]697 for (size_t i = confframe; i < confframe + confcount; i++)
[5f0f29ce]698 zone_mark_unavailable(&zones.info[znum],
699 i - zones.info[znum].base);
[085d973]700 }
[5f0f29ce]701
[da1bafb]702 irq_spinlock_unlock(&zones.lock, true);
[5f0f29ce]703
704 return znum;
705 }
[b0c2075]706
[5f0f29ce]707 /* Non-available zone */
[e2650d3]708 size_t znum = zones_insert_zone(start, count, flags);
[98000fb]709 if (znum == (size_t) -1) {
[da1bafb]710 irq_spinlock_unlock(&zones.lock, true);
[98000fb]711 return (size_t) -1;
[5f0f29ce]712 }
[b0c2075]713
714 zone_construct(&zones.info[znum], start, count, flags, NULL);
[5f0f29ce]715
[da1bafb]716 irq_spinlock_unlock(&zones.lock, true);
[1bb3766]717
[bb68433]718 return znum;
[085d973]719}
720
[5f0f29ce]721/*******************/
[085d973]722/* Frame functions */
[5f0f29ce]723/*******************/
[085d973]724
[deaf8d5]725/** Set parent of frame. */
[98000fb]726void frame_set_parent(pfn_t pfn, void *data, size_t hint)
[085d973]727{
[da1bafb]728 irq_spinlock_lock(&zones.lock, true);
[5f0f29ce]729
[98000fb]730 size_t znum = find_zone(pfn, 1, hint);
[5f0f29ce]731
[98000fb]732 ASSERT(znum != (size_t) -1);
[5f0f29ce]733
734 zone_get_frame(&zones.info[znum],
735 pfn - zones.info[znum].base)->parent = data;
736
[da1bafb]737 irq_spinlock_unlock(&zones.lock, true);
[085d973]738}
739
[98000fb]740void *frame_get_parent(pfn_t pfn, size_t hint)
[085d973]741{
[da1bafb]742 irq_spinlock_lock(&zones.lock, true);
[5f0f29ce]743
[98000fb]744 size_t znum = find_zone(pfn, 1, hint);
[5f0f29ce]745
[98000fb]746 ASSERT(znum != (size_t) -1);
[5f0f29ce]747
748 void *res = zone_get_frame(&zones.info[znum],
749 pfn - zones.info[znum].base)->parent;
750
[da1bafb]751 irq_spinlock_unlock(&zones.lock, true);
[085d973]752
753 return res;
754}
755
[b0c2075]756/** Allocate frames of physical memory.
[085d973]757 *
[b0c2075]758 * @param count Number of continuous frames to allocate.
759 * @param flags Flags for host zone selection and address processing.
760 * @param constraint Indication of physical address bits that cannot be
761 * set in the address of the first allocated frame.
762 * @param pzone Preferred zone.
[085d973]763 *
[5f0f29ce]764 * @return Physical address of the allocated frame.
[9a68b34d]765 *
[085d973]766 */
[b0c2075]767uintptr_t frame_alloc_generic(size_t count, frame_flags_t flags,
[8cbf1c3]768 uintptr_t constraint, size_t *pzone)
[085d973]769{
[b0c2075]770 ASSERT(count > 0);
771
[98000fb]772 size_t hint = pzone ? (*pzone) : 0;
[b0c2075]773 pfn_t frame_constraint = ADDR2PFN(constraint);
[085d973]774
[89bcb520]775 /*
776 * If not told otherwise, we must first reserve the memory.
777 */
[b0c2075]778 if (!(flags & FRAME_NO_RESERVE))
779 reserve_force_alloc(count);
780
[085d973]781loop:
[da1bafb]782 irq_spinlock_lock(&zones.lock, true);
[9a68b34d]783
[085d973]784 /*
785 * First, find suitable frame zone.
786 */
[b0c2075]787 size_t znum = find_free_zone(count, FRAME_TO_ZONE_FLAGS(flags),
788 frame_constraint, hint);
[9a68b34d]789
[b0c2075]790 /*
791 * If no memory, reclaim some slab memory,
792 * if it does not help, reclaim all.
793 */
[98000fb]794 if ((znum == (size_t) -1) && (!(flags & FRAME_NO_RECLAIM))) {
[da1bafb]795 irq_spinlock_unlock(&zones.lock, true);
[98000fb]796 size_t freed = slab_reclaim(0);
[da1bafb]797 irq_spinlock_lock(&zones.lock, true);
[f049eec]798
[5f0f29ce]799 if (freed > 0)
[b0c2075]800 znum = find_free_zone(count, FRAME_TO_ZONE_FLAGS(flags),
801 frame_constraint, hint);
[5f0f29ce]802
[98000fb]803 if (znum == (size_t) -1) {
[da1bafb]804 irq_spinlock_unlock(&zones.lock, true);
[085d973]805 freed = slab_reclaim(SLAB_RECLAIM_ALL);
[da1bafb]806 irq_spinlock_lock(&zones.lock, true);
[f049eec]807
[5f0f29ce]808 if (freed > 0)
[b0c2075]809 znum = find_free_zone(count, FRAME_TO_ZONE_FLAGS(flags),
810 frame_constraint, hint);
[085d973]811 }
812 }
[5f0f29ce]813
[98000fb]814 if (znum == (size_t) -1) {
[1a1744e]815 if (flags & FRAME_ATOMIC) {
[da1bafb]816 irq_spinlock_unlock(&zones.lock, true);
[b0c2075]817
[89bcb520]818 if (!(flags & FRAME_NO_RESERVE))
[b0c2075]819 reserve_free(count);
820
[8cbf1c3]821 return 0;
[1a1744e]822 }
[085d973]823
[1a1744e]824#ifdef CONFIG_DEBUG
[8d308b9]825 size_t avail = frame_total_free_get_internal();
[1a1744e]826#endif
[5f0f29ce]827
[da1bafb]828 irq_spinlock_unlock(&zones.lock, true);
829
[05411e8]830 if (!THREAD)
831 panic("Cannot wait for memory to become available.");
[5f0f29ce]832
833 /*
834 * Sleep until some frames are available again.
835 */
836
837#ifdef CONFIG_DEBUG
[7e752b2]838 printf("Thread %" PRIu64 " waiting for %zu frames, "
[b0c2075]839 "%zu available.\n", THREAD->tid, count, avail);
[5f0f29ce]840#endif
841
[905721b]842 /*
[b0c2075]843 * Since the mem_avail_mtx is an active mutex, we need to
844 * disable interrupts to prevent deadlock with TLB shootdown.
[905721b]845 */
846 ipl_t ipl = interrupts_disable();
[1bb3766]847 mutex_lock(&mem_avail_mtx);
[5f0f29ce]848
849 if (mem_avail_req > 0)
[b0c2075]850 mem_avail_req = min(mem_avail_req, count);
[5f0f29ce]851 else
[b0c2075]852 mem_avail_req = count;
853
[98000fb]854 size_t gen = mem_avail_gen;
[5f0f29ce]855
856 while (gen == mem_avail_gen)
[1bb3766]857 condvar_wait(&mem_avail_cv, &mem_avail_mtx);
[5f0f29ce]858
[1bb3766]859 mutex_unlock(&mem_avail_mtx);
[905721b]860 interrupts_restore(ipl);
[5f0f29ce]861
[1a1744e]862#ifdef CONFIG_DEBUG
[5f0f29ce]863 printf("Thread %" PRIu64 " woken up.\n", THREAD->tid);
[1a1744e]864#endif
[5f0f29ce]865
[085d973]866 goto loop;
867 }
[9a68b34d]868
[b0c2075]869 pfn_t pfn = zone_frame_alloc(&zones.info[znum], count,
870 frame_constraint) + zones.info[znum].base;
[1bb3766]871
[da1bafb]872 irq_spinlock_unlock(&zones.lock, true);
[5f0f29ce]873
874 if (pzone)
875 *pzone = znum;
876
[8cbf1c3]877 return PFN2ADDR(pfn);
[085d973]878}
879
[b0c2075]880uintptr_t frame_alloc(size_t count, frame_flags_t flags, uintptr_t constraint)
[0139747]881{
[b0c2075]882 return frame_alloc_generic(count, flags, constraint, NULL);
[0139747]883}
884
[b0c2075]885uintptr_t frame_alloc_noreserve(size_t count, frame_flags_t flags,
[8cbf1c3]886 uintptr_t constraint)
[e608cbe]887{
[b0c2075]888 return frame_alloc_generic(count, flags | FRAME_NO_RESERVE, constraint,
[8cbf1c3]889 NULL);
[e608cbe]890}
891
[5df1963]892/** Free frames of physical memory.
[085d973]893 *
[5df1963]894 * Find respective frame structures for supplied physical frames.
895 * Decrement each frame reference count. If it drops to zero, mark
896 * the frames as available.
[5f0f29ce]897 *
[5df1963]898 * @param start Physical Address of the first frame to be freed.
899 * @param count Number of frames to free.
[c32e6bc]900 * @param flags Flags to control memory reservation.
[085d973]901 *
902 */
[5df1963]903void frame_free_generic(uintptr_t start, size_t count, frame_flags_t flags)
[085d973]904{
[5df1963]905 size_t freed = 0;
[5f0f29ce]906
[5df1963]907 irq_spinlock_lock(&zones.lock, true);
[085d973]908
[5df1963]909 for (size_t i = 0; i < count; i++) {
910 /*
911 * First, find host frame zone for addr.
912 */
913 pfn_t pfn = ADDR2PFN(start) + i;
914 size_t znum = find_zone(pfn, 1, 0);
915
916 ASSERT(znum != (size_t) -1);
917
918 freed += zone_frame_free(&zones.info[znum],
919 pfn - zones.info[znum].base);
920 }
[085d973]921
[da1bafb]922 irq_spinlock_unlock(&zones.lock, true);
[1a1744e]923
924 /*
925 * Signal that some memory has been freed.
[5df1963]926 * Since the mem_avail_mtx is an active mutex,
927 * we need to disable interruptsto prevent deadlock
928 * with TLB shootdown.
[905721b]929 */
[b0c2075]930
[905721b]931 ipl_t ipl = interrupts_disable();
[1bb3766]932 mutex_lock(&mem_avail_mtx);
[b0c2075]933
[5f0f29ce]934 if (mem_avail_req > 0)
[5df1963]935 mem_avail_req -= min(mem_avail_req, freed);
[5f0f29ce]936
937 if (mem_avail_req == 0) {
938 mem_avail_gen++;
939 condvar_broadcast(&mem_avail_cv);
940 }
[b0c2075]941
[1bb3766]942 mutex_unlock(&mem_avail_mtx);
[905721b]943 interrupts_restore(ipl);
[89bcb520]944
945 if (!(flags & FRAME_NO_RESERVE))
[5df1963]946 reserve_free(freed);
[085d973]947}
948
[5df1963]949void frame_free(uintptr_t frame, size_t count)
[c32e6bc]950{
[5df1963]951 frame_free_generic(frame, count, 0);
[c32e6bc]952}
953
[5df1963]954void frame_free_noreserve(uintptr_t frame, size_t count)
[e608cbe]955{
[5df1963]956 frame_free_generic(frame, count, FRAME_NO_RESERVE);
[e608cbe]957}
958
[f3ac636]959/** Add reference to frame.
960 *
961 * Find respective frame structure for supplied PFN and
962 * increment frame reference count.
963 *
[5f0f29ce]964 * @param pfn Frame number of the frame to be freed.
965 *
[f3ac636]966 */
[97bdb4a]967NO_TRACE void frame_reference_add(pfn_t pfn)
[f3ac636]968{
[da1bafb]969 irq_spinlock_lock(&zones.lock, true);
[f3ac636]970
971 /*
972 * First, find host frame zone for addr.
973 */
[0b4a67a]974 size_t znum = find_zone(pfn, 1, 0);
[5f0f29ce]975
[98000fb]976 ASSERT(znum != (size_t) -1);
[f3ac636]977
[5f0f29ce]978 zones.info[znum].frames[pfn - zones.info[znum].base].refcount++;
[f3ac636]979
[da1bafb]980 irq_spinlock_unlock(&zones.lock, true);
[f3ac636]981}
[085d973]982
[da1bafb]983/** Mark given range unavailable in frame zones.
984 *
985 */
[97bdb4a]986NO_TRACE void frame_mark_unavailable(pfn_t start, size_t count)
[085d973]987{
[da1bafb]988 irq_spinlock_lock(&zones.lock, true);
[052da81]989
[b0c2075]990 for (size_t i = 0; i < count; i++) {
[98000fb]991 size_t znum = find_zone(start + i, 1, 0);
[b0c2075]992
[98000fb]993 if (znum == (size_t) -1) /* PFN not found */
[085d973]994 continue;
[5f0f29ce]995
996 zone_mark_unavailable(&zones.info[znum],
997 start + i - zones.info[znum].base);
[085d973]998 }
[5f0f29ce]999
[da1bafb]1000 irq_spinlock_unlock(&zones.lock, true);
[085d973]1001}
1002
[da1bafb]1003/** Initialize physical memory management.
1004 *
1005 */
[085d973]1006void frame_init(void)
1007{
1008 if (config.cpu_active == 1) {
1009 zones.count = 0;
[da1bafb]1010 irq_spinlock_initialize(&zones.lock, "frame.zones.lock");
[1bb3766]1011 mutex_initialize(&mem_avail_mtx, MUTEX_ACTIVE);
1012 condvar_initialize(&mem_avail_cv);
[085d973]1013 }
[5f0f29ce]1014
[085d973]1015 /* Tell the architecture to create some memory */
[ddcc8a0]1016 frame_low_arch_init();
[b0c2075]1017
[085d973]1018 if (config.cpu_active == 1) {
[4638401]1019 frame_mark_unavailable(ADDR2PFN(KA2PA(config.base)),
1020 SIZE2FRAMES(config.kernel_size));
1021 frame_mark_unavailable(ADDR2PFN(KA2PA(config.stack_base)),
1022 SIZE2FRAMES(config.stack_size));
[b6b576c]1023
[b0c2075]1024 for (size_t i = 0; i < init.cnt; i++)
1025 frame_mark_unavailable(ADDR2PFN(init.tasks[i].paddr),
[4638401]1026 SIZE2FRAMES(init.tasks[i].size));
[5f0f29ce]1027
[61e90dd]1028 if (ballocs.size)
[4638401]1029 frame_mark_unavailable(ADDR2PFN(KA2PA(ballocs.base)),
1030 SIZE2FRAMES(ballocs.size));
[5f0f29ce]1031
[b0c2075]1032 /*
1033 * Blacklist first frame, as allocating NULL would
[5f0f29ce]1034 * fail in some places
1035 */
[bffa0b06]1036 frame_mark_unavailable(0, 1);
[085d973]1037 }
[b0c2075]1038
[ddcc8a0]1039 frame_high_arch_init();
[085d973]1040}
1041
[ad12b5ea]1042/** Adjust bounds of physical memory region according to low/high memory split.
1043 *
[b0c2075]1044 * @param low[in] If true, the adjustment is performed to make the region
1045 * fit in the low memory. Otherwise the adjustment is
1046 * performed to make the region fit in the high memory.
1047 * @param basep[inout] Pointer to a variable which contains the region's base
1048 * address and which may receive the adjusted base address.
1049 * @param sizep[inout] Pointer to a variable which contains the region's size
1050 * and which may receive the adjusted size.
1051 *
1052 * @return True if the region still exists even after the adjustment.
1053 * @return False otherwise.
1054 *
[ad12b5ea]1055 */
1056bool frame_adjust_zone_bounds(bool low, uintptr_t *basep, size_t *sizep)
1057{
[2cc7f16]1058 uintptr_t limit = KA2PA(config.identity_base) + config.identity_size;
[b0c2075]1059
[ad12b5ea]1060 if (low) {
1061 if (*basep > limit)
1062 return false;
[b0c2075]1063
[ad12b5ea]1064 if (*basep + *sizep > limit)
1065 *sizep = limit - *basep;
1066 } else {
1067 if (*basep + *sizep <= limit)
1068 return false;
[b0c2075]1069
[ad12b5ea]1070 if (*basep <= limit) {
1071 *sizep -= limit - *basep;
1072 *basep = limit;
1073 }
1074 }
[b0c2075]1075
[ad12b5ea]1076 return true;
1077}
1078
[da1bafb]1079/** Return total size of all zones.
1080 *
1081 */
[9dae191e]1082uint64_t zones_total_size(void)
[deaf8d5]1083{
[da1bafb]1084 irq_spinlock_lock(&zones.lock, true);
[71eef11]1085
[5f0f29ce]1086 uint64_t total = 0;
[b0c2075]1087
1088 for (size_t i = 0; i < zones.count; i++)
[5f0f29ce]1089 total += (uint64_t) FRAMES2SIZE(zones.info[i].count);
[71eef11]1090
[da1bafb]1091 irq_spinlock_unlock(&zones.lock, true);
[71eef11]1092
1093 return total;
1094}
1095
[9dae191e]1096void zones_stats(uint64_t *total, uint64_t *unavail, uint64_t *busy,
1097 uint64_t *free)
[516adce]1098{
[9dae191e]1099 ASSERT(total != NULL);
1100 ASSERT(unavail != NULL);
1101 ASSERT(busy != NULL);
1102 ASSERT(free != NULL);
1103
[da1bafb]1104 irq_spinlock_lock(&zones.lock, true);
[9dae191e]1105
1106 *total = 0;
1107 *unavail = 0;
1108 *busy = 0;
1109 *free = 0;
1110
[b0c2075]1111 for (size_t i = 0; i < zones.count; i++) {
[9dae191e]1112 *total += (uint64_t) FRAMES2SIZE(zones.info[i].count);
1113
[e6c4b94]1114 if (zones.info[i].flags & ZONE_AVAILABLE) {
[9dae191e]1115 *busy += (uint64_t) FRAMES2SIZE(zones.info[i].busy_count);
1116 *free += (uint64_t) FRAMES2SIZE(zones.info[i].free_count);
1117 } else
1118 *unavail += (uint64_t) FRAMES2SIZE(zones.info[i].count);
[516adce]1119 }
[9dae191e]1120
[da1bafb]1121 irq_spinlock_unlock(&zones.lock, true);
[516adce]1122}
1123
[da1bafb]1124/** Prints list of zones.
1125 *
1126 */
[9dae191e]1127void zones_print_list(void)
[deaf8d5]1128{
[5f0f29ce]1129#ifdef __32_BITS__
[74c5a1ca]1130 printf("[nr] [base addr] [frames ] [flags ] [free frames ] [busy frames ]\n");
[2b8b0ca]1131#endif
1132
1133#ifdef __64_BITS__
[74c5a1ca]1134 printf("[nr] [base address ] [frames ] [flags ] [free frames ] [busy frames ]\n");
[2b8b0ca]1135#endif
[43b1e86]1136
[000350f8]1137 /*
1138 * Because printing may require allocation of memory, we may not hold
1139 * the frame allocator locks when printing zone statistics. Therefore,
1140 * we simply gather the statistics under the protection of the locks and
1141 * print the statistics when the locks have been released.
1142 *
1143 * When someone adds/removes zones while we are printing the statistics,
1144 * we may end up with inaccurate output (e.g. a zone being skipped from
1145 * the listing).
1146 */
[5f0f29ce]1147
[b0c2075]1148 for (size_t i = 0;; i++) {
[da1bafb]1149 irq_spinlock_lock(&zones.lock, true);
[000350f8]1150
1151 if (i >= zones.count) {
[da1bafb]1152 irq_spinlock_unlock(&zones.lock, true);
[000350f8]1153 break;
1154 }
[5f0f29ce]1155
1156 uintptr_t base = PFN2ADDR(zones.info[i].base);
[98000fb]1157 size_t count = zones.info[i].count;
[5f0f29ce]1158 zone_flags_t flags = zones.info[i].flags;
[98000fb]1159 size_t free_count = zones.info[i].free_count;
1160 size_t busy_count = zones.info[i].busy_count;
[000350f8]1161
[da1bafb]1162 irq_spinlock_unlock(&zones.lock, true);
[5f0f29ce]1163
[e6c4b94]1164 bool available = ((flags & ZONE_AVAILABLE) != 0);
[5f0f29ce]1165
[7e752b2]1166 printf("%-4zu", i);
[e49e234]1167
[2b8b0ca]1168#ifdef __32_BITS__
[7e752b2]1169 printf(" %p", (void *) base);
[2b8b0ca]1170#endif
[5f0f29ce]1171
[2b8b0ca]1172#ifdef __64_BITS__
[7e752b2]1173 printf(" %p", (void *) base);
[e49e234]1174#endif
1175
[e6c4b94]1176 printf(" %12zu %c%c%c%c%c ", count,
1177 available ? 'A' : '-',
1178 (flags & ZONE_RESERVED) ? 'R' : '-',
1179 (flags & ZONE_FIRMWARE) ? 'F' : '-',
1180 (flags & ZONE_LOWMEM) ? 'L' : '-',
1181 (flags & ZONE_HIGHMEM) ? 'H' : '-');
[43b1e86]1182
[5f0f29ce]1183 if (available)
[7e752b2]1184 printf("%14zu %14zu",
[5f0f29ce]1185 free_count, busy_count);
[e49e234]1186
[5f0f29ce]1187 printf("\n");
[dfd9186]1188 }
1189}
1190
[abbc16e]1191/** Prints zone details.
[96cacc1]1192 *
[5f0f29ce]1193 * @param num Zone base address or zone number.
1194 *
[96cacc1]1195 */
[98000fb]1196void zone_print_one(size_t num)
[deaf8d5]1197{
[da1bafb]1198 irq_spinlock_lock(&zones.lock, true);
[98000fb]1199 size_t znum = (size_t) -1;
[5f0f29ce]1200
[b0c2075]1201 for (size_t i = 0; i < zones.count; i++) {
[5f0f29ce]1202 if ((i == num) || (PFN2ADDR(zones.info[i].base) == num)) {
1203 znum = i;
[bb68433]1204 break;
1205 }
1206 }
[5f0f29ce]1207
[98000fb]1208 if (znum == (size_t) -1) {
[da1bafb]1209 irq_spinlock_unlock(&zones.lock, true);
[bb68433]1210 printf("Zone not found.\n");
[2ec725f]1211 return;
[dfd9186]1212 }
[085d973]1213
[b0c2075]1214 uintptr_t base = PFN2ADDR(zones.info[znum].base);
1215 zone_flags_t flags = zones.info[znum].flags;
1216 size_t count = zones.info[znum].count;
1217 size_t free_count = zones.info[znum].free_count;
1218 size_t busy_count = zones.info[znum].busy_count;
[5f0f29ce]1219
[da1bafb]1220 irq_spinlock_unlock(&zones.lock, true);
[5f0f29ce]1221
[e6c4b94]1222 bool available = ((flags & ZONE_AVAILABLE) != 0);
[5f0f29ce]1223
[933cadf]1224 uint64_t size;
1225 const char *size_suffix;
1226 bin_order_suffix(FRAMES2SIZE(count), &size, &size_suffix, false);
1227
[7e752b2]1228 printf("Zone number: %zu\n", znum);
1229 printf("Zone base address: %p\n", (void *) base);
[933cadf]1230 printf("Zone size: %zu frames (%" PRIu64 " %s)\n", count,
1231 size, size_suffix);
[e6c4b94]1232 printf("Zone flags: %c%c%c%c%c\n",
1233 available ? 'A' : '-',
1234 (flags & ZONE_RESERVED) ? 'R' : '-',
1235 (flags & ZONE_FIRMWARE) ? 'F' : '-',
1236 (flags & ZONE_LOWMEM) ? 'L' : '-',
1237 (flags & ZONE_HIGHMEM) ? 'H' : '-');
[5f0f29ce]1238
1239 if (available) {
[933cadf]1240 bin_order_suffix(FRAMES2SIZE(busy_count), &size, &size_suffix,
1241 false);
1242 printf("Allocated space: %zu frames (%" PRIu64 " %s)\n",
1243 busy_count, size, size_suffix);
1244 bin_order_suffix(FRAMES2SIZE(free_count), &size, &size_suffix,
1245 false);
1246 printf("Available space: %zu frames (%" PRIu64 " %s)\n",
1247 free_count, size, size_suffix);
[5f0f29ce]1248 }
[dfd9186]1249}
1250
[cc73a8a1]1251/** @}
[b45c443]1252 */
Note: See TracBrowser for help on using the repository browser.