Subversion Repositories HelenOS-historic

Rev

Rev 564 | Rev 623 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (C) 2001-2005 Jakub Jermar
  3.  * Copyright (C) 2005 Sergey Bondari
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  *
  10.  * - Redistributions of source code must retain the above copyright
  11.  *   notice, this list of conditions and the following disclaimer.
  12.  * - Redistributions in binary form must reproduce the above copyright
  13.  *   notice, this list of conditions and the following disclaimer in the
  14.  *   documentation and/or other materials provided with the distribution.
  15.  * - The name of the author may not be used to endorse or promote products
  16.  *   derived from this software without specific prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  19.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  20.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  22.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  23.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28.  */
  29.  
  30. #include <typedefs.h>
  31. #include <arch/types.h>
  32. #include <mm/heap.h>
  33. #include <mm/frame.h>
  34. #include <mm/vm.h>
  35. #include <panic.h>
  36. #include <debug.h>
  37. #include <list.h>
  38. #include <synch/spinlock.h>
  39. #include <arch/asm.h>
  40. #include <arch.h>
  41. #include <print.h>
  42. #include <align.h>
  43.  
  44. spinlock_t zone_head_lock;       /**< this lock protects zone_head list */
  45. link_t zone_head;                /**< list of all zones in the system */
  46.  
  47. /** Blacklist containing non-available areas of memory.
  48.  *
  49.  * This blacklist is used to exclude frames that cannot be allocated
  50.  * (e.g. kernel memory) from available memory map.
  51.  */
  52. region_t zone_blacklist[ZONE_BLACKLIST_SIZE];
  53. count_t zone_blacklist_count = 0;
  54.  
  55. static struct buddy_system_operations  zone_buddy_system_operations = {
  56.     .find_buddy = zone_buddy_find_buddy,
  57.     .bisect = zone_buddy_bisect,
  58.     .coalesce = zone_buddy_coalesce,
  59.     .set_order = zone_buddy_set_order,
  60.     .get_order = zone_buddy_get_order,
  61.     .mark_busy = zone_buddy_mark_busy,
  62. };
  63.  
  64. /** Initialize physical memory management
  65.  *
  66.  * Initialize physical memory managemnt.
  67.  */
  68. void frame_init(void)
  69. {
  70.     if (config.cpu_active == 1) {
  71.         zone_init();
  72.         frame_region_not_free(KA2PA(config.base), config.kernel_size);
  73.     }
  74.  
  75.     frame_arch_init();
  76. }
  77.  
  78. /** Allocate power-of-two frames of physical memory.
  79.  *
  80.  * @param flags Flags for host zone selection and address processing.
  81.  * @param order Allocate exactly 2^order frames.
  82.  *
  83.  * @return Allocated frame.
  84.  */
  85. __address frame_alloc(int flags, __u8 order)
  86. {
  87.     ipl_t ipl;
  88.     link_t *cur, *tmp;
  89.     zone_t *z;
  90.     zone_t *zone = NULL;
  91.     frame_t *frame = NULL;
  92.     __address v;
  93.    
  94. loop:
  95.     ipl = interrupts_disable();
  96.     spinlock_lock(&zone_head_lock);
  97.  
  98.     /*
  99.      * First, find suitable frame zone.
  100.      */
  101.     for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
  102.         z = list_get_instance(cur, zone_t, link);
  103.        
  104.         spinlock_lock(&z->lock);
  105.  
  106.         /* Check if the zone has 2^order frames area available  */
  107.         if (buddy_system_can_alloc(z->buddy_system, order)) {
  108.             zone = z;
  109.             break;
  110.         }
  111.        
  112.         spinlock_unlock(&z->lock);
  113.     }
  114.    
  115.     if (!zone) {
  116.         if (flags & FRAME_PANIC)
  117.             panic("Can't allocate frame.\n");
  118.        
  119.         /*
  120.          * TODO: Sleep until frames are available again.
  121.          */
  122.         spinlock_unlock(&zone_head_lock);
  123.         interrupts_restore(ipl);
  124.  
  125.         panic("Sleep not implemented.\n");
  126.         goto loop;
  127.     }
  128.        
  129.  
  130.     /* Allocate frames from zone buddy system */
  131.     tmp = buddy_system_alloc(zone->buddy_system, order);
  132.    
  133.     ASSERT(tmp);
  134.    
  135.     /* Update zone information. */
  136.     zone->free_count -= (1 << order);
  137.     zone->busy_count += (1 << order);
  138.  
  139.     /* Frame will be actually a first frame of the block. */
  140.     frame = list_get_instance(tmp, frame_t, buddy_link);
  141.    
  142.     /* get frame address */
  143.     v = FRAME2ADDR(zone, frame);
  144.  
  145.     spinlock_unlock(&zone->lock);
  146.     spinlock_unlock(&zone_head_lock);
  147.     interrupts_restore(ipl);
  148.  
  149.  
  150.     if (flags & FRAME_KA)
  151.         v = PA2KA(v);
  152.    
  153.     return v;
  154. }
  155.  
  156. /** Free a frame.
  157.  *
  158.  * Find respective frame structrue for supplied addr.
  159.  * Decrement frame reference count.
  160.  * If it drops to zero, move the frame structure to free list.
  161.  *
  162.  * @param addr Address of the frame to be freed. It must be a multiple of FRAME_SIZE.
  163.  */
  164. void frame_free(__address addr)
  165. {
  166.     ipl_t ipl;
  167.     link_t *cur;
  168.     zone_t *z;
  169.     zone_t *zone = NULL;
  170.     frame_t *frame;
  171.     ASSERT(addr % FRAME_SIZE == 0);
  172.    
  173.     ipl = interrupts_disable();
  174.     spinlock_lock(&zone_head_lock);
  175.    
  176.     /*
  177.      * First, find host frame zone for addr.
  178.      */
  179.     for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
  180.         z = list_get_instance(cur, zone_t, link);
  181.        
  182.         spinlock_lock(&z->lock);
  183.        
  184.         if (IS_KA(addr))
  185.             addr = KA2PA(addr);
  186.        
  187.         /*
  188.          * Check if addr belongs to z.
  189.          */
  190.         if ((addr >= z->base) && (addr <= z->base + (z->free_count + z->busy_count) * FRAME_SIZE)) {
  191.             zone = z;
  192.             break;
  193.         }
  194.         spinlock_unlock(&z->lock);
  195.     }
  196.    
  197.     ASSERT(zone != NULL);
  198.    
  199.     frame = ADDR2FRAME(zone, addr);
  200.  
  201.     ASSERT(frame->refcount);
  202.  
  203.     if (!--frame->refcount) {
  204.         buddy_system_free(zone->buddy_system, &frame->buddy_link);
  205.     }
  206.  
  207.     /* Update zone information. */
  208.     zone->free_count += (1 << frame->buddy_order);
  209.     zone->busy_count -= (1 << frame->buddy_order);
  210.    
  211.     spinlock_unlock(&zone->lock);
  212.     spinlock_unlock(&zone_head_lock);
  213.     interrupts_restore(ipl);
  214. }
  215.  
  216. /** Mark frame region not free.
  217.  *
  218.  * Mark frame region not free.
  219.  *
  220.  * @param base Base address of non-available region.
  221.  * @param size Size of non-available region.
  222.  */
  223. void frame_region_not_free(__address base, size_t size)
  224. {
  225.     index_t index;
  226.     index = zone_blacklist_count++;
  227.  
  228.     /* Force base to the nearest lower address frame boundary. */
  229.     base = ALIGN_DOWN(base, FRAME_SIZE);
  230.     /* Align size to frame boundary. */
  231.     size = ALIGN_UP(size, FRAME_SIZE);
  232.  
  233.     ASSERT(index < ZONE_BLACKLIST_SIZE);
  234.     zone_blacklist[index].base = base;
  235.     zone_blacklist[index].size = size;
  236. }
  237.  
  238.  
  239. /** Initialize zonekeeping
  240.  *
  241.  * Initialize zonekeeping.
  242.  */
  243. void zone_init(void)
  244. {
  245.     spinlock_initialize(&zone_head_lock, "zone_head_lock");
  246.     list_initialize(&zone_head);
  247. }
  248.  
  249. /** Create frame zones in region of available memory.
  250.  *
  251.  * Avoid any black listed areas of non-available memory.
  252.  * Assume that the black listed areas cannot overlap
  253.  * one another or cross available memory region boundaries.
  254.  *
  255.  * @param base Base address of available memory region.
  256.  * @param size Size of the region.
  257.  */
  258. void zone_create_in_region(__address base, size_t size) {
  259.     int i;
  260.     zone_t * z;
  261.     __address s;
  262.     size_t sz;
  263.    
  264.     ASSERT(base % FRAME_SIZE == 0);
  265.     ASSERT(size % FRAME_SIZE == 0);
  266.    
  267.     if (!size)
  268.         return;
  269.  
  270.     for (i = 0; i < zone_blacklist_count; i++) {
  271.         if (zone_blacklist[i].base >= base && zone_blacklist[i].base < base + size) {
  272.             s = base; sz = zone_blacklist[i].base - base;
  273.             ASSERT(base != s || sz != size);
  274.             zone_create_in_region(s, sz);
  275.            
  276.             s = zone_blacklist[i].base + zone_blacklist[i].size;
  277.             sz = (base + size) - (zone_blacklist[i].base + zone_blacklist[i].size);
  278.             ASSERT(base != s || sz != size);
  279.             zone_create_in_region(s, sz);
  280.             return;
  281.        
  282.         }
  283.     }
  284.    
  285.     z = zone_create(base, size, 0);
  286.  
  287.     if (!z) {
  288.         panic("Cannot allocate zone (base=%P, size=%d).\n", base, size);
  289.     }
  290.    
  291.     zone_attach(z);
  292. }
  293.  
  294.  
  295. /** Create frame zone
  296.  *
  297.  * Create new frame zone.
  298.  *
  299.  * @param start Physical address of the first frame within the zone.
  300.  * @param size Size of the zone. Must be a multiple of FRAME_SIZE.
  301.  * @param flags Zone flags.
  302.  *
  303.  * @return Initialized zone.
  304.  */
  305. zone_t * zone_create(__address start, size_t size, int flags)
  306. {
  307.     zone_t *z;
  308.     count_t cnt;
  309.     int i;
  310.     __u8 max_order;
  311.  
  312.     ASSERT(start % FRAME_SIZE == 0);
  313.     ASSERT(size % FRAME_SIZE == 0);
  314.    
  315.     cnt = size / FRAME_SIZE;
  316.    
  317.     z = (zone_t *) early_malloc(sizeof(zone_t));
  318.     if (z) {
  319.         link_initialize(&z->link);
  320.         spinlock_initialize(&z->lock, "zone_lock");
  321.    
  322.         z->base = start;
  323.         z->flags = flags;
  324.  
  325.         z->free_count = cnt;
  326.         z->busy_count = 0;
  327.        
  328.         z->frames = (frame_t *) early_malloc(cnt * sizeof(frame_t));
  329.         if (!z->frames) {
  330.             early_free(z);
  331.             return NULL;
  332.         }
  333.        
  334.         for (i = 0; i<cnt; i++) {
  335.             frame_initialize(&z->frames[i], z);
  336.         }
  337.        
  338.         /*
  339.          * Create buddy system for the zone
  340.          */
  341.         for (max_order = 0; cnt >> max_order; max_order++)
  342.             ;
  343.         z->buddy_system = buddy_system_create(max_order, &zone_buddy_system_operations, (void *) z);
  344.        
  345.         /* Stuffing frames */
  346.         for (i = 0; i<cnt; i++) {
  347.             z->frames[i].refcount = 0;
  348.             buddy_system_free(z->buddy_system, &z->frames[i].buddy_link);  
  349.         }
  350.     }
  351.     return z;
  352. }
  353.  
  354. /** Attach frame zone
  355.  *
  356.  * Attach frame zone to zone list.
  357.  *
  358.  * @param zone Zone to be attached.
  359.  */
  360. void zone_attach(zone_t *zone)
  361. {
  362.     ipl_t ipl;
  363.    
  364.     ipl = interrupts_disable();
  365.     spinlock_lock(&zone_head_lock);
  366.    
  367.     list_append(&zone->link, &zone_head);
  368.    
  369.     spinlock_unlock(&zone_head_lock);
  370.     interrupts_restore(ipl);
  371. }
  372.  
  373. /** Initialize frame structure
  374.  *
  375.  * Initialize frame structure.
  376.  *
  377.  * @param frame Frame structure to be initialized.
  378.  * @param zone Host frame zone.
  379.  */
  380. void frame_initialize(frame_t *frame, zone_t *zone)
  381. {
  382.     frame->refcount = 1;
  383.     frame->buddy_order = 0;
  384. }
  385.  
  386.  
  387. /** Buddy system find_buddy implementation
  388.  *
  389.  * @param b Buddy system.
  390.  * @param block Block for which buddy should be found
  391.  *
  392.  * @return Buddy for given block if found
  393.  */
  394. link_t * zone_buddy_find_buddy(buddy_system_t *b, link_t * block) {
  395.     frame_t * frame;
  396.     zone_t * zone;
  397.     index_t index;
  398.     bool is_left, is_right;
  399.  
  400.     frame = list_get_instance(block, frame_t, buddy_link);
  401.     zone = (zone_t *) b->data;
  402.    
  403.     ASSERT(IS_BUDDY_ORDER_OK(FRAME_INDEX(zone, frame), frame->buddy_order));
  404.    
  405.     is_left = IS_BUDDY_LEFT_BLOCK(zone, frame);
  406.     is_right = IS_BUDDY_RIGHT_BLOCK(zone, frame);
  407.    
  408.     ASSERT(is_left ^ is_right);
  409.    
  410.     if (is_left) {
  411.         index = (FRAME_INDEX(zone, frame)) + (1 << frame->buddy_order);
  412.     } else { // if (is_right)
  413.         index = (FRAME_INDEX(zone, frame)) - (1 << frame->buddy_order);
  414.     }
  415.    
  416.     if (FRAME_INDEX_VALID(zone, index)) {
  417.         if (    zone->frames[index].buddy_order == frame->buddy_order &&
  418.             zone->frames[index].refcount == 0) {
  419.             return &zone->frames[index].buddy_link;
  420.         }
  421.     }
  422.    
  423.     return NULL;   
  424. }
  425.  
  426. /** Buddy system bisect implementation
  427.  *
  428.  * @param b Buddy system.
  429.  * @param block Block to bisect
  430.  *
  431.  * @return right block
  432.  */
  433. link_t * zone_buddy_bisect(buddy_system_t *b, link_t * block) {
  434.     frame_t * frame_l, * frame_r;
  435.  
  436.     frame_l = list_get_instance(block, frame_t, buddy_link);
  437.     frame_r = (frame_l + (1 << (frame_l->buddy_order - 1)));
  438.    
  439.     return &frame_r->buddy_link;
  440. }
  441.  
  442. /** Buddy system coalesce implementation
  443.  *
  444.  * @param b Buddy system.
  445.  * @param block_1 First block
  446.  * @param block_2 First block's buddy
  447.  *
  448.  * @return Coalesced block (actually block that represents lower address)
  449.  */
  450. link_t * zone_buddy_coalesce(buddy_system_t *b, link_t * block_1, link_t * block_2) {
  451.     frame_t * frame1, * frame2;
  452.    
  453.     frame1 = list_get_instance(block_1, frame_t, buddy_link);
  454.     frame2 = list_get_instance(block_2, frame_t, buddy_link);
  455.    
  456.     return frame1 < frame2 ? block_1 : block_2;
  457. }
  458.  
  459. /** Buddy system set_order implementation
  460.  *
  461.  * @param b Buddy system.
  462.  * @param block Buddy system block
  463.  * @param order Order to set
  464.  */
  465. void zone_buddy_set_order(buddy_system_t *b, link_t * block, __u8 order) {
  466.     frame_t * frame;
  467.     frame = list_get_instance(block, frame_t, buddy_link);
  468.     frame->buddy_order = order;
  469. }
  470.  
  471. /** Buddy system get_order implementation
  472.  *
  473.  * @param b Buddy system.
  474.  * @param block Buddy system block
  475.  *
  476.  * @return Order of block
  477.  */
  478. __u8 zone_buddy_get_order(buddy_system_t *b, link_t * block) {
  479.     frame_t * frame;
  480.     frame = list_get_instance(block, frame_t, buddy_link);
  481.     return frame->buddy_order;
  482. }
  483.  
  484. /** Buddy system mark_busy implementation
  485.  *
  486.  * @param b Buddy system
  487.  * @param block Buddy system block
  488.  *
  489.  */
  490. void zone_buddy_mark_busy(buddy_system_t *b, link_t * block) {
  491.     frame_t * frame;
  492.     frame = list_get_instance(block, frame_t, buddy_link);
  493.     frame->refcount = 1;
  494. }
  495.