source: mainline/generic/src/mm/frame.c@ 93354b0

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 93354b0 was 93354b0, checked in by Sergey Bondari <bondari@…>, 20 years ago

Small fix :)

  • Property mode set to 100644
File size: 14.1 KB
Line 
1/*
2 * Copyright (C) 2001-2004 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <typedefs.h>
30#include <arch/types.h>
31#include <mm/heap.h>
32#include <mm/frame.h>
33#include <mm/vm.h>
34#include <panic.h>
35#include <debug.h>
36#include <list.h>
37#include <synch/spinlock.h>
38#include <arch/asm.h>
39#include <arch.h>
40
41spinlock_t zone_head_lock; /**< this lock protects zone_head list */
42link_t zone_head; /**< list of all zones in the system */
43
44static struct buddy_system_operations zone_buddy_system_operations = {
45 .find_buddy = zone_buddy_find_buddy,
46 .bisect = zone_buddy_bisect,
47 .coalesce = zone_buddy_coalesce,
48 .set_order = zone_buddy_set_order,
49 .get_order = zone_buddy_get_order,
50};
51
52/** Initialize physical memory management
53 *
54 * Initialize physical memory managemnt.
55 */
56void frame_init(void)
57{
58 if (config.cpu_active == 1) {
59 zone_init();
60 }
61
62 frame_arch_init();
63
64 if (config.cpu_active == 1) {
65 frame_region_not_free(config.base, config.base + config.kernel_size + CONFIG_STACK_SIZE);
66 }
67}
68
69/** Allocate a frame
70 *
71 * Allocate a frame of physical memory.
72 *
73 * @param flags Flags for host zone selection and address processing.
74 *
75 * @return Allocated frame.
76 */
77__address frame_alloc(int flags)
78{
79 ipl_t ipl;
80 link_t *cur, *tmp;
81 zone_t *z;
82 zone_t *zone = NULL;
83 frame_t *frame = NULL;
84 __address v;
85
86loop:
87 ipl = interrupts_disable();
88 spinlock_lock(&zone_head_lock);
89
90 /*
91 * First, find suitable frame zone.
92 */
93 for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
94 z = list_get_instance(cur, zone_t, link);
95
96 spinlock_lock(&z->lock);
97 /*
98 * Check if the zone has any free frames.
99 */
100 if (z->free_count) {
101 zone = z;
102 break;
103 }
104 spinlock_unlock(&z->lock);
105 }
106
107 if (!zone) {
108 if (flags & FRAME_PANIC)
109 panic("Can't allocate frame.\n");
110
111 /*
112 * TODO: Sleep until frames are available again.
113 */
114 spinlock_unlock(&zone_head_lock);
115 interrupts_restore(ipl);
116
117 panic("Sleep not implemented.\n");
118 goto loop;
119 }
120
121 tmp = zone->free_head.next;
122 frame = list_get_instance(tmp, frame_t, link);
123
124 frame->refcount++;
125 list_remove(tmp); /* remove frame from free_head */
126 zone->free_count--;
127 zone->busy_count++;
128
129 //v = zone->base + (frame - zone->frames) * FRAME_SIZE;
130 v = FRAME2ADDR(zone, frame);
131
132 if (flags & FRAME_KA)
133 v = PA2KA(v);
134
135 spinlock_unlock(&zone->lock);
136
137 spinlock_unlock(&zone_head_lock);
138 interrupts_restore(ipl);
139
140 return v;
141}
142
143/** Free a frame.
144 *
145 * Find respective frame structrue for supplied addr.
146 * Decrement frame reference count.
147 * If it drops to zero, move the frame structure to free list.
148 *
149 * @param addr Address of the frame to be freed. It must be a multiple of FRAME_SIZE.
150 */
151void frame_free(__address addr)
152{
153 ipl_t ipl;
154 link_t *cur;
155 zone_t *z;
156 zone_t *zone = NULL;
157 frame_t *frame;
158
159 ASSERT(addr % FRAME_SIZE == 0);
160
161 ipl = interrupts_disable();
162 spinlock_lock(&zone_head_lock);
163
164 /*
165 * First, find host frame zone for addr.
166 */
167 for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
168 z = list_get_instance(cur, zone_t, link);
169
170 spinlock_lock(&z->lock);
171
172 if (IS_KA(addr))
173 addr = KA2PA(addr);
174
175 /*
176 * Check if addr belongs to z.
177 */
178 if ((addr >= z->base) && (addr <= z->base + (z->free_count + z->busy_count) * FRAME_SIZE)) {
179 zone = z;
180 break;
181 }
182 spinlock_unlock(&z->lock);
183 }
184
185 ASSERT(zone != NULL);
186
187 frame = ADDR2FRAME(zone, addr);
188 // frame = &zone->frames[(addr - zone->base)/FRAME_SIZE];
189 ASSERT(frame->refcount);
190
191 if (!--frame->refcount) {
192 list_append(&frame->link, &zone->free_head); /* append frame to free_head */
193 zone->free_count++;
194 zone->busy_count--;
195 }
196
197 spinlock_unlock(&zone->lock);
198
199 spinlock_unlock(&zone_head_lock);
200 interrupts_restore(ipl);
201}
202
203/** Mark frame not free.
204 *
205 * Find respective frame structrue for supplied addr.
206 * Increment frame reference count and remove the frame structure from free list.
207 *
208 * @param addr Address of the frame to be marked. It must be a multiple of FRAME_SIZE.
209 */
210void frame_not_free(__address addr)
211{
212 ipl_t ipl;
213 link_t *cur;
214 zone_t *z;
215 zone_t *zone = NULL;
216 frame_t *frame;
217
218 ASSERT(addr % FRAME_SIZE == 0);
219
220 ipl = interrupts_disable();
221 spinlock_lock(&zone_head_lock);
222
223 /*
224 * First, find host frame zone for addr.
225 */
226 for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
227 z = list_get_instance(cur, zone_t, link);
228
229 spinlock_lock(&z->lock);
230
231 if (IS_KA(addr))
232 addr = KA2PA(addr);
233
234 /*
235 * Check if addr belongs to z.
236 */
237 if ((addr >= z->base) && (addr <= z->base + (z->free_count + z->busy_count) * FRAME_SIZE)) {
238 zone = z;
239 break;
240 }
241 spinlock_unlock(&z->lock);
242 }
243
244 ASSERT(zone != NULL);
245
246 //frame = &zone->frames[(addr - zone->base)/FRAME_SIZE];
247 frame = ADDR2FRAME(zone, addr);
248
249 if (!frame->refcount) {
250 frame->refcount++;
251
252 list_remove(&frame->link); /* remove frame from free_head */
253 zone->free_count--;
254 zone->busy_count++;
255 }
256
257 spinlock_unlock(&zone->lock);
258
259 spinlock_unlock(&zone_head_lock);
260 interrupts_restore(ipl);
261}
262
263/** Mark frame region not free.
264 *
265 * Mark frame region not free.
266 *
267 * @param start First address.
268 * @param stop Last address.
269 */
270void frame_region_not_free(__address start, __address stop)
271{
272 __address a;
273
274 start /= FRAME_SIZE;
275 stop /= FRAME_SIZE;
276 for (a = start; a <= stop; a++)
277 frame_not_free(a * FRAME_SIZE);
278}
279
280
281/** Initialize zonekeeping
282 *
283 * Initialize zonekeeping.
284 */
285void zone_init(void)
286{
287 spinlock_initialize(&zone_head_lock);
288 list_initialize(&zone_head);
289}
290
291/** Create frame zone
292 *
293 * Create new frame zone.
294 *
295 * @param start Physical address of the first frame within the zone.
296 * @param size Size of the zone. Must be a multiple of FRAME_SIZE.
297 * @param flags Zone flags.
298 *
299 * @return Initialized zone.
300 */
301zone_t *zone_create(__address start, size_t size, int flags)
302{
303 zone_t *z;
304 count_t cnt;
305 int i;
306 __u8 max_order;
307
308 ASSERT(start % FRAME_SIZE == 0);
309 ASSERT(size % FRAME_SIZE == 0);
310
311 cnt = size / FRAME_SIZE;
312
313 z = (zone_t *) early_malloc(sizeof(zone_t));
314 if (z) {
315 link_initialize(&z->link);
316 spinlock_initialize(&z->lock);
317
318 z->base = start;
319 z->flags = flags;
320
321 z->free_count = cnt;
322 list_initialize(&z->free_head);
323
324 z->busy_count = 0;
325
326 z->frames = (frame_t *) early_malloc(cnt * sizeof(frame_t));
327 if (!z->frames) {
328 early_free(z);
329 return NULL;
330 }
331
332 for (i = 0; i<cnt; i++) {
333 frame_initialize(&z->frames[i], z);
334 list_append(&z->frames[i].link, &z->free_head);
335 }
336
337 /*
338 * Create buddy system for the zone
339 */
340 for (max_order = 0; cnt >> max_order; max_order++);
341 z->buddy_system = buddy_system_create(max_order, &zone_buddy_system_operations);
342 }
343
344 return z;
345}
346
347/** Attach frame zone
348 *
349 * Attach frame zone to zone list.
350 *
351 * @param zone Zone to be attached.
352 */
353void zone_attach(zone_t *zone)
354{
355 ipl_t ipl;
356
357 ipl = interrupts_disable();
358 spinlock_lock(&zone_head_lock);
359
360 list_append(&zone->link, &zone_head);
361
362 spinlock_unlock(&zone_head_lock);
363 interrupts_restore(ipl);
364}
365
366/** Initialize frame structure
367 *
368 * Initialize frame structure.
369 *
370 * @param frame Frame structure to be initialized.
371 * @param zone Host frame zone.
372 */
373void frame_initialize(frame_t *frame, zone_t *zone)
374{
375 frame->refcount = 0;
376 link_initialize(&frame->link);
377}
378
379
380
381/*
382 * buddy system functions (under construction)
383 *
384 */
385
386
387/** Allocate 2^order frames
388 *
389 */
390__address zone_buddy_frame_alloc(int flags, __u8 order) {
391 ipl_t ipl;
392 link_t *cur, *tmp;
393 zone_t *z;
394 zone_t *zone = NULL;
395 frame_t *frame = NULL;
396 __address v;
397
398loop:
399 ipl = interrupts_disable();
400 spinlock_lock(&zone_head_lock);
401
402 /*
403 * First, find suitable frame zone.
404 */
405 for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
406 z = list_get_instance(cur, zone_t, link);
407
408 spinlock_lock(&z->lock);
409 /*
410 * Check if the zone has 2^order frames area available
411 * TODO: Must check if buddy system has at least block in order >= given order
412 */
413 if (z->free_count == (1 >> order)) {
414 zone = z;
415 break;
416 }
417
418 spinlock_unlock(&z->lock);
419 }
420
421 if (!zone) {
422 if (flags & FRAME_PANIC)
423 panic("Can't allocate frame.\n");
424
425 /*
426 * TODO: Sleep until frames are available again.
427 */
428 spinlock_unlock(&zone_head_lock);
429 interrupts_restore(ipl);
430
431 panic("Sleep not implemented.\n");
432 goto loop;
433 }
434
435
436 /* Allocate frames from zone buddy system */
437 cur = buddy_system_alloc(zone->buddy_system, order);
438
439 /* frame will be actually a first frame of the block */
440 frame = list_get_instance(cur, frame_t, buddy_link);
441
442 /* get frame address */
443 v = FRAME2ADDR(zone, frame);
444
445 if (flags & FRAME_KA)
446 v = PA2KA(v);
447
448 spinlock_unlock(&zone->lock);
449 spinlock_unlock(&zone_head_lock);
450 interrupts_restore(ipl);
451
452 return v;
453}
454
455
456/** Free frame(s)
457 *
458 * @param addr Address of the frame(s) to be freed. It must be a multiple of FRAME_SIZE.
459 */
460void zone_buddy_frame_free(__address addr)
461{
462 ipl_t ipl;
463 link_t *cur;
464 zone_t *z;
465 zone_t *zone = NULL;
466 frame_t *frame;
467
468 ASSERT(addr % FRAME_SIZE == 0);
469
470 ipl = interrupts_disable();
471 spinlock_lock(&zone_head_lock);
472
473 /*
474 * First, find host frame zone for addr.
475 */
476 for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
477 z = list_get_instance(cur, zone_t, link);
478
479 spinlock_lock(&z->lock);
480
481 if (IS_KA(addr))
482 addr = KA2PA(addr);
483
484 /*
485 * Check if addr belongs to z.
486 */
487 if ((addr >= z->base) && (addr <= z->base + (z->free_count + z->busy_count) * FRAME_SIZE)) {
488 zone = z;
489 break;
490 }
491 spinlock_unlock(&z->lock);
492 }
493
494 ASSERT(zone != NULL);
495
496 frame = ADDR2FRAME(zone, addr);
497
498 ASSERT(frame->refcount);
499
500 if (!--frame->refcount) {
501 buddy_system_free(zone->buddy_system, &frame->buddy_link);
502 }
503
504 spinlock_unlock(&zone->lock);
505
506 spinlock_unlock(&zone_head_lock);
507 interrupts_restore(ipl);
508}
509
510/** Guess zone by frame instance address
511 *
512 * @param frame Frame
513 *
514 * @return Zone of given frame
515 */
516zone_t * get_zone_by_frame(frame_t * frame) {
517 link_t * cur;
518 zone_t * zone, *z;
519
520 ASSERT(frame);
521 /*
522 * First, find host frame zone for addr.
523 */
524 for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
525 z = list_get_instance(cur, zone_t, link);
526
527 spinlock_lock(&z->lock);
528
529 /*
530 * Check if frame address belongs to z.
531 */
532 if ((frame >= z->frames) && (frame <= z->frames + (z->free_count + z->busy_count))) {
533 zone = z;
534 break;
535 }
536 spinlock_unlock(&z->lock);
537 }
538 ASSERT(zone);
539
540 return zone;
541
542
543}
544
545/** Buddy system find_buddy implementation
546 * @param block Block for which buddy should be found
547 *
548 * @return Buddy for given block if found
549 */
550link_t * zone_buddy_find_buddy(link_t * block) {
551 frame_t * frame, * f;
552 zone_t * zone;
553 link_t * cur;
554 bool is_left, is_right;
555
556 frame = list_get_instance(block, frame_t, buddy_link);
557 zone = get_zone_by_frame(frame);
558
559
560 /*
561 * (FRAME_INDEX % 2^(ORDER+1)) == 0 ===> LEFT BUDDY
562 * (FRAME_INDEX % 2^(ORDER+1)) == 2^(ORDER) ===> RIGHT BUDDY
563 */
564
565 is_left = IS_BUDDY_LEFT_BLOCK(zone, frame);
566 is_right = IS_BUDDY_RIGHT_BLOCK(zone, frame);
567
568 ASSERT((is_left || is_right) && (!is_left || !is_right));
569
570 for (cur = &zone->buddy_system->order[frame->buddy_order]; cur; cur = cur->next) {
571 f = list_get_instance(cur, frame_t, buddy_link);
572
573 ASSERT(f->buddy_order == frame->buddy_order);
574
575 /*
576 * if found frame is coherent with our frame from the left
577 */
578 if ((FRAME_INDEX(zone, f) + 1 >> frame->buddy_order == FRAME_INDEX(zone, frame)) && is_right) {
579 return cur;
580 }
581
582 /*
583 * if found frame is coherent with our frame from the right
584 */
585 if ((FRAME_INDEX(zone,f) - 1 >> frame->buddy_order == FRAME_INDEX(zone, frame)) && is_left) {
586 return cur;
587 }
588
589 }
590
591 return NULL;
592
593
594}
595
596/** Buddy system bisect implementation
597 *
598 * @param block Block to bisect
599 *
600 * @return right block
601 */
602link_t * zone_buddy_bisect(link_t * block) {
603 frame_t * frame_l, * frame_r;
604
605 frame_l = list_get_instance(block, frame_t, buddy_link);
606
607 frame_r = (frame_t *) (&frame_l + (1>>frame_l->buddy_order-1));
608
609 return &frame_r->buddy_link;
610
611}
612
613/** Buddy system coalesce implementation
614 *
615 * @param block_1 First block
616 * @param block_2 First block's buddy
617 *
618 * @return Coalesced block (actually block that represents lower address)
619 */
620link_t * zone_buddy_coalesce(link_t * block_1, link_t * block_2) {
621 frame_t * frame1, * frame2;
622
623 frame1 = list_get_instance(block_1, frame_t, buddy_link);
624 frame2 = list_get_instance(block_2, frame_t, buddy_link);
625
626 return &frame1 < &frame2 ? block_1 : block_2;
627}
628
629/** Buddy system set_order implementation
630 * @param block Buddy system block
631 * @param order Order to set
632 */
633void zone_buddy_set_order(link_t * block, __u8 order) {
634 frame_t * frame;
635 frame = list_get_instance(block, frame_t, buddy_link);
636 frame->buddy_order = order;
637}
638
639/** Buddy system get_order implementation
640 * @param block Buddy system block
641 *
642 * @return Order of block
643 */
644__u8 zone_buddy_get_order(link_t * block) {
645 frame_t * frame;
646 frame = list_get_instance(block, frame_t, buddy_link);
647 return frame->buddy_order;
648}
Note: See TracBrowser for help on using the repository browser.