Subversion Repositories HelenOS

Rev

Rev 3211 | Rev 4346 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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