Subversion Repositories HelenOS

Rev

Rev 3972 | Rev 4048 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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