Subversion Repositories HelenOS

Rev

Rev 3973 | Rev 4230 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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