Subversion Repositories HelenOS

Rev

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

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