Subversion Repositories HelenOS-historic

Rev

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

  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. #include <print.h>
  41. #include <align.h>
  42.  
  43. spinlock_t zone_head_lock;       /**< this lock protects zone_head list */
  44. link_t zone_head;                /**< list of all zones in the system */
  45.  
  46. /** Blacklist containing non-available areas of memory.
  47.  *
  48.  * This blacklist is used to exclude frames that cannot be allocated
  49.  * (e.g. kernel memory) from available memory map.
  50.  */
  51. region_t zone_blacklist[ZONE_BLACKLIST_SIZE];
  52. count_t zone_blacklist_count = 0;
  53.  
  54. static struct buddy_system_operations  zone_buddy_system_operations = {
  55.     .find_buddy = zone_buddy_find_buddy,
  56.     .bisect = zone_buddy_bisect,
  57.     .coalesce = zone_buddy_coalesce,
  58.     .set_order = zone_buddy_set_order,
  59.     .get_order = zone_buddy_get_order,
  60.     .mark_busy = zone_buddy_mark_busy,
  61. };
  62.  
  63. /** Initialize physical memory management
  64.  *
  65.  * Initialize physical memory managemnt.
  66.  */
  67. void frame_init(void)
  68. {
  69.     if (config.cpu_active == 1) {
  70.         zone_init();
  71.         frame_region_not_free(KA2PA(config.base), config.kernel_size);
  72.     }
  73.  
  74.     frame_arch_init();
  75. }
  76.  
  77. /** Allocate power-of-two frames of physical memory.
  78.  *
  79.  * @param flags Flags for host zone selection and address processing.
  80.  * @param order Allocate exactly 2^order frames.
  81.  *
  82.  * @return Allocated frame.
  83.  */
  84. __address frame_alloc(int flags, __u8 order)
  85. {
  86.     ipl_t ipl;
  87.     link_t *cur, *tmp;
  88.     zone_t *z;
  89.     zone_t *zone = NULL;
  90.     frame_t *frame = NULL;
  91.     __address v;
  92.    
  93. loop:
  94.     ipl = interrupts_disable();
  95.     spinlock_lock(&zone_head_lock);
  96.  
  97.     /*
  98.      * First, find suitable frame zone.
  99.      */
  100.     for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
  101.         z = list_get_instance(cur, zone_t, link);
  102.        
  103.         spinlock_lock(&z->lock);
  104.  
  105.         /* Check if the zone has 2^order frames area available  */
  106.         if (buddy_system_can_alloc(z->buddy_system, order)) {
  107.             zone = z;
  108.             break;
  109.         }
  110.        
  111.         spinlock_unlock(&z->lock);
  112.     }
  113.    
  114.     if (!zone) {
  115.         if (flags & FRAME_PANIC)
  116.             panic("Can't allocate frame.\n");
  117.        
  118.         /*
  119.          * TODO: Sleep until frames are available again.
  120.          */
  121.         spinlock_unlock(&zone_head_lock);
  122.         interrupts_restore(ipl);
  123.  
  124.         panic("Sleep not implemented.\n");
  125.         goto loop;
  126.     }
  127.        
  128.  
  129.     /* Allocate frames from zone buddy system */
  130.     tmp = buddy_system_alloc(zone->buddy_system, order);
  131.    
  132.     ASSERT(tmp);
  133.    
  134.     /* Update zone information. */
  135.     zone->free_count -= (1 << order);
  136.     zone->busy_count += (1 << order);
  137.  
  138.     /* Frame will be actually a first frame of the block. */
  139.     frame = list_get_instance(tmp, frame_t, buddy_link);
  140.    
  141.     /* get frame address */
  142.     v = FRAME2ADDR(zone, frame);
  143.  
  144.     spinlock_unlock(&zone->lock);
  145.     spinlock_unlock(&zone_head_lock);
  146.     interrupts_restore(ipl);
  147.  
  148.  
  149.     if (flags & FRAME_KA)
  150.         v = PA2KA(v);
  151.    
  152.     return v;
  153. }
  154.  
  155. /** Free a frame.
  156.  *
  157.  * Find respective frame structrue for supplied addr.
  158.  * Decrement frame reference count.
  159.  * If it drops to zero, move the frame structure to free list.
  160.  *
  161.  * @param addr Address of the frame to be freed. It must be a multiple of FRAME_SIZE.
  162.  */
  163. void frame_free(__address addr)
  164. {
  165.     ipl_t ipl;
  166.     link_t *cur;
  167.     zone_t *z;
  168.     zone_t *zone = NULL;
  169.     frame_t *frame;
  170.     ASSERT(addr % FRAME_SIZE == 0);
  171.    
  172.     ipl = interrupts_disable();
  173.     spinlock_lock(&zone_head_lock);
  174.    
  175.     /*
  176.      * First, find host frame zone for addr.
  177.      */
  178.     for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
  179.         z = list_get_instance(cur, zone_t, link);
  180.        
  181.         spinlock_lock(&z->lock);
  182.        
  183.         if (IS_KA(addr))
  184.             addr = KA2PA(addr);
  185.        
  186.         /*
  187.          * Check if addr belongs to z.
  188.          */
  189.         if ((addr >= z->base) && (addr <= z->base + (z->free_count + z->busy_count) * FRAME_SIZE)) {
  190.             zone = z;
  191.             break;
  192.         }
  193.         spinlock_unlock(&z->lock);
  194.     }
  195.    
  196.     ASSERT(zone != NULL);
  197.    
  198.     frame = ADDR2FRAME(zone, addr);
  199.  
  200.     ASSERT(frame->refcount);
  201.  
  202.     if (!--frame->refcount) {
  203.         buddy_system_free(zone->buddy_system, &frame->buddy_link);
  204.     }
  205.  
  206.     /* Update zone information. */
  207.     zone->free_count += (1 << frame->buddy_order);
  208.     zone->busy_count -= (1 << frame->buddy_order);
  209.    
  210.     spinlock_unlock(&zone->lock);
  211.     spinlock_unlock(&zone_head_lock);
  212.     interrupts_restore(ipl);
  213. }
  214.  
  215. /** Mark frame region not free.
  216.  *
  217.  * Mark frame region not free.
  218.  *
  219.  * @param base Base address of non-available region.
  220.  * @param size Size of non-available region.
  221.  */
  222. void frame_region_not_free(__address base, size_t size)
  223. {
  224.     index_t index;
  225.     index = zone_blacklist_count++;
  226.  
  227.     /* Force base to the nearest lower address frame boundary. */
  228.     base &= ~(FRAME_SIZE - 1);
  229.     /* Align size to frame boundary. */
  230.     size = ALIGN(size, FRAME_SIZE);
  231.  
  232.     ASSERT(zone_blacklist_count <= ZONE_BLACKLIST_SIZE);
  233.     zone_blacklist[index].base = base;
  234.     zone_blacklist[index].size = size;
  235. }
  236.  
  237.  
  238. /** Initialize zonekeeping
  239.  *
  240.  * Initialize zonekeeping.
  241.  */
  242. void zone_init(void)
  243. {
  244.     spinlock_initialize(&zone_head_lock, "zone_head_lock");
  245.     list_initialize(&zone_head);
  246. }
  247.  
  248. /** Create frame zones in region of available memory.
  249.  *
  250.  * Avoid any black listed areas of non-available memory.
  251.  * Assume that the black listed areas cannot overlap
  252.  * one another or cross available memory region boundaries.
  253.  *
  254.  * @param base Base address of available memory region.
  255.  * @param size Size of the region.
  256.  */
  257. void zone_create_in_region(__address base, size_t size) {
  258.     int i;
  259.     zone_t * z;
  260.     __address s;
  261.     size_t sz;
  262.    
  263.     ASSERT(base % FRAME_SIZE == 0);
  264.     ASSERT(size % FRAME_SIZE == 0);
  265.    
  266.     if (!size)
  267.         return;
  268.  
  269.     for (i = 0; i < zone_blacklist_count; i++) {
  270.         if (zone_blacklist[i].base >= base && zone_blacklist[i].base < base + size) {
  271.             s = base; sz = zone_blacklist[i].base - base;
  272.             ASSERT(base != s || sz != size);
  273.             zone_create_in_region(s, sz);
  274.            
  275.             s = zone_blacklist[i].base + zone_blacklist[i].size;
  276.             sz = (base + size) - (zone_blacklist[i].base + zone_blacklist[i].size);
  277.             ASSERT(base != s || sz != size);
  278.             zone_create_in_region(s, sz);
  279.             return;
  280.        
  281.         }
  282.     }
  283.    
  284.     z = zone_create(base, size, 0);
  285.  
  286.     if (!z) {
  287.         panic("Cannot allocate zone (%dB).\n", size);
  288.     }
  289.    
  290.     zone_attach(z);
  291. }
  292.  
  293.  
  294. /** Create frame zone
  295.  *
  296.  * Create new frame zone.
  297.  *
  298.  * @param start Physical address of the first frame within the zone.
  299.  * @param size Size of the zone. Must be a multiple of FRAME_SIZE.
  300.  * @param flags Zone flags.
  301.  *
  302.  * @return Initialized zone.
  303.  */
  304. zone_t * zone_create(__address start, size_t size, int flags)
  305. {
  306.     zone_t *z;
  307.     count_t cnt;
  308.     int i;
  309.     __u8 max_order;
  310.  
  311.     ASSERT(start % FRAME_SIZE == 0);
  312.     ASSERT(size % FRAME_SIZE == 0);
  313.    
  314.     cnt = size / FRAME_SIZE;
  315.    
  316.     z = (zone_t *) early_malloc(sizeof(zone_t));
  317.     if (z) {
  318.         link_initialize(&z->link);
  319.         spinlock_initialize(&z->lock, "zone_lock");
  320.    
  321.         z->base = start;
  322.         z->flags = flags;
  323.  
  324.         z->free_count = cnt;
  325.         z->busy_count = 0;
  326.        
  327.         z->frames = (frame_t *) early_malloc(cnt * sizeof(frame_t));
  328.         if (!z->frames) {
  329.             early_free(z);
  330.             return NULL;
  331.         }
  332.        
  333.         for (i = 0; i<cnt; i++) {
  334.             frame_initialize(&z->frames[i], z);
  335.         }
  336.        
  337.         /*
  338.          * Create buddy system for the zone
  339.          */
  340.         for (max_order = 0; cnt >> max_order; max_order++)
  341.             ;
  342.         z->buddy_system = buddy_system_create(max_order, &zone_buddy_system_operations, (void *) z);
  343.        
  344.         /* Stuffing frames */
  345.         for (i = 0; i<cnt; i++) {
  346.             z->frames[i].refcount = 0;
  347.             buddy_system_free(z->buddy_system, &z->frames[i].buddy_link);  
  348.         }
  349.     }
  350.     return z;
  351. }
  352.  
  353. /** Attach frame zone
  354.  *
  355.  * Attach frame zone to zone list.
  356.  *
  357.  * @param zone Zone to be attached.
  358.  */
  359. void zone_attach(zone_t *zone)
  360. {
  361.     ipl_t ipl;
  362.    
  363.     ipl = interrupts_disable();
  364.     spinlock_lock(&zone_head_lock);
  365.    
  366.     list_append(&zone->link, &zone_head);
  367.    
  368.     spinlock_unlock(&zone_head_lock);
  369.     interrupts_restore(ipl);
  370. }
  371.  
  372. /** Initialize frame structure
  373.  *
  374.  * Initialize frame structure.
  375.  *
  376.  * @param frame Frame structure to be initialized.
  377.  * @param zone Host frame zone.
  378.  */
  379. void frame_initialize(frame_t *frame, zone_t *zone)
  380. {
  381.     frame->refcount = 1;
  382.     frame->buddy_order = 0;
  383. }
  384.  
  385.  
  386. /** Buddy system find_buddy implementation
  387.  *
  388.  * @param b Buddy system.
  389.  * @param block Block for which buddy should be found
  390.  *
  391.  * @return Buddy for given block if found
  392.  */
  393. link_t * zone_buddy_find_buddy(buddy_system_t *b, link_t * block) {
  394.     frame_t * frame;
  395.     zone_t * zone;
  396.     count_t index;
  397.     bool is_left, is_right;
  398.  
  399.     frame = list_get_instance(block, frame_t, buddy_link);
  400.     zone = (zone_t *) b->data;
  401.    
  402.     is_left = IS_BUDDY_LEFT_BLOCK(zone, frame);
  403.     is_right = !is_left;
  404.    
  405.     /*
  406.      * test left buddy
  407.      */
  408.     if (is_left) {
  409.         index = (FRAME_INDEX(zone, frame)) + (1 << frame->buddy_order);
  410.     } else if (is_right) {
  411.         index = (FRAME_INDEX(zone, frame)) - (1 << frame->buddy_order);
  412.     }
  413.    
  414.     if (FRAME_INDEX_VALID(zone, index)) {
  415.         if (    zone->frames[index].buddy_order == frame->buddy_order &&
  416.             zone->frames[index].refcount == 0) {
  417.             return &zone->frames[index].buddy_link;
  418.         }
  419.     }
  420.    
  421.     return NULL;   
  422. }
  423.  
  424. /** Buddy system bisect implementation
  425.  *
  426.  * @param b Buddy system.
  427.  * @param block Block to bisect
  428.  *
  429.  * @return right block
  430.  */
  431. link_t * zone_buddy_bisect(buddy_system_t *b, link_t * block) {
  432.     frame_t * frame_l, * frame_r;
  433.     frame_l = list_get_instance(block, frame_t, buddy_link);
  434.     frame_r = (frame_l + (1 << (frame_l->buddy_order - 1)));
  435.     return &frame_r->buddy_link;
  436. }
  437.  
  438. /** Buddy system coalesce implementation
  439.  *
  440.  * @param b Buddy system.
  441.  * @param block_1 First block
  442.  * @param block_2 First block's buddy
  443.  *
  444.  * @return Coalesced block (actually block that represents lower address)
  445.  */
  446. link_t * zone_buddy_coalesce(buddy_system_t *b, link_t * block_1, link_t * block_2) {
  447.     frame_t * frame1, * frame2;
  448.     frame1 = list_get_instance(block_1, frame_t, buddy_link);
  449.     frame2 = list_get_instance(block_2, frame_t, buddy_link);
  450.     return frame1 < frame2 ? block_1 : block_2;
  451. }
  452.  
  453. /** Buddy system set_order implementation
  454.  *
  455.  * @param b Buddy system.
  456.  * @param block Buddy system block
  457.  * @param order Order to set
  458.  */
  459. void zone_buddy_set_order(buddy_system_t *b, link_t * block, __u8 order) {
  460.     frame_t * frame;
  461.     frame = list_get_instance(block, frame_t, buddy_link);
  462.     frame->buddy_order = order;
  463. }
  464.  
  465. /** Buddy system get_order implementation
  466.  *
  467.  * @param b Buddy system.
  468.  * @param block Buddy system block
  469.  *
  470.  * @return Order of block
  471.  */
  472. __u8 zone_buddy_get_order(buddy_system_t *b, link_t * block) {
  473.     frame_t * frame;
  474.     frame = list_get_instance(block, frame_t, buddy_link);
  475.     return frame->buddy_order;
  476. }
  477.  
  478. /** Buddy system mark_busy implementation
  479.  *
  480.  * @param b Buddy system
  481.  * @param block Buddy system block
  482.  *
  483.  */
  484. void zone_buddy_mark_busy(buddy_system_t *b, link_t * block) {
  485.     frame_t * frame;
  486.     frame = list_get_instance(block, frame_t, buddy_link);
  487.     frame->refcount = 1;
  488. }
  489.