source: mainline/kernel/generic/src/mm/frame.c@ 566da7f8

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 566da7f8 was 566da7f8, checked in by Vojtech Horky <vojtechhorky@…>, 11 years ago

Fix another bunch of maybe-uninitialized warnings

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