Subversion Repositories HelenOS

Rev

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

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