Subversion Repositories HelenOS-historic

Rev

Rev 724 | Rev 759 | 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/as.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_INITIALIZE(zone_head_lock);    /**< this lock protects zone_head list */
  45. LIST_INITIALIZE(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.         frame_region_not_free(KA2PA(config.base), config.kernel_size);
  72.         if (config.init_size > 0)
  73.             frame_region_not_free(KA2PA(config.init_addr), config.init_size);
  74.     }
  75.  
  76.     frame_arch_init();
  77. }
  78.  
  79. /** Allocate power-of-two frames of physical memory.
  80.  *
  81.  * @param flags Flags for host zone selection and address processing.
  82.  * @param order Allocate exactly 2^order frames.
  83.  *
  84.  * @return Allocated frame.
  85.  */
  86. __address frame_alloc(int flags, __u8 order, int * status)
  87. {
  88.     ipl_t ipl;
  89.     link_t *cur, *tmp;
  90.     zone_t *z;
  91.     zone_t *zone = NULL;
  92.     frame_t *frame = NULL;
  93.     __address v;
  94.    
  95. loop:
  96.     ipl = interrupts_disable();
  97.     spinlock_lock(&zone_head_lock);
  98.  
  99.     /*
  100.      * First, find suitable frame zone.
  101.      */
  102.     for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
  103.         z = list_get_instance(cur, zone_t, link);
  104.        
  105.         spinlock_lock(&z->lock);
  106.  
  107.         /* Check if the zone has 2^order frames area available  */
  108.         if (buddy_system_can_alloc(z->buddy_system, order)) {
  109.             zone = z;
  110.             break;
  111.         }
  112.        
  113.         spinlock_unlock(&z->lock);
  114.     }
  115.    
  116.     if (!zone) {
  117.         if (flags & FRAME_PANIC)
  118.             panic("Can't allocate frame.\n");
  119.        
  120.         /*
  121.          * TODO: Sleep until frames are available again.
  122.          */
  123.         spinlock_unlock(&zone_head_lock);
  124.         interrupts_restore(ipl);
  125.  
  126.         if (flags & FRAME_NON_BLOCKING) {
  127.             ASSERT(status != NULL);
  128.             *status = FRAME_NO_MEMORY;
  129.             return NULL;
  130.         }
  131.        
  132.         panic("Sleep not implemented.\n");
  133.         goto loop;
  134.     }
  135.        
  136.     /* Allocate frames from zone buddy system */
  137.     tmp = buddy_system_alloc(zone->buddy_system, order);
  138.    
  139.     ASSERT(tmp);
  140.    
  141.     /* Update zone information. */
  142.     zone->free_count -= (1 << order);
  143.     zone->busy_count += (1 << order);
  144.  
  145.     /* Frame will be actually a first frame of the block. */
  146.     frame = list_get_instance(tmp, frame_t, buddy_link);
  147.    
  148.     /* get frame address */
  149.     v = FRAME2ADDR(zone, frame);
  150.  
  151.     spinlock_unlock(&zone->lock);
  152.     spinlock_unlock(&zone_head_lock);
  153.     interrupts_restore(ipl);
  154.  
  155.     ASSERT(v == ALIGN_UP(v, FRAME_SIZE << order));
  156.  
  157.     if (flags & FRAME_KA)
  158.         v = PA2KA(v);
  159.    
  160.     if (flags & FRAME_NON_BLOCKING) {
  161.         ASSERT(status != NULL);
  162.         *status = FRAME_OK;
  163.     }
  164.     return v;
  165. }
  166.  
  167. /** Free a frame.
  168.  *
  169.  * Find respective frame structrue for supplied addr.
  170.  * Decrement frame reference count.
  171.  * If it drops to zero, move the frame structure to free list.
  172.  *
  173.  * @param addr Address of the frame to be freed. It must be a multiple of FRAME_SIZE.
  174.  */
  175. void frame_free(__address addr)
  176. {
  177.     ipl_t ipl;
  178.     link_t *cur;
  179.     zone_t *z;
  180.     zone_t *zone = NULL;
  181.     frame_t *frame;
  182.     int order;
  183.    
  184.     ASSERT(addr % FRAME_SIZE == 0);
  185.    
  186.     ipl = interrupts_disable();
  187.     spinlock_lock(&zone_head_lock);
  188.    
  189.     /*
  190.      * First, find host frame zone for addr.
  191.      */
  192.     for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
  193.         z = list_get_instance(cur, zone_t, link);
  194.        
  195.         spinlock_lock(&z->lock);
  196.        
  197.         if (IS_KA(addr))
  198.             addr = KA2PA(addr);
  199.        
  200.         /*
  201.          * Check if addr belongs to z.
  202.          */
  203.         if ((addr >= z->base) && (addr <= z->base + (z->free_count + z->busy_count) * FRAME_SIZE)) {
  204.             zone = z;
  205.             break;
  206.         }
  207.  
  208.         spinlock_unlock(&z->lock);
  209.     }
  210.    
  211.     ASSERT(zone != NULL);
  212.    
  213.     frame = ADDR2FRAME(zone, addr);
  214.    
  215.     /* remember frame order */
  216.     order = frame->buddy_order;
  217.  
  218.     ASSERT(frame->refcount);
  219.  
  220.     if (!--frame->refcount) {
  221.         buddy_system_free(zone->buddy_system, &frame->buddy_link);
  222.     }
  223.  
  224.     /* Update zone information. */
  225.     zone->free_count += (1 << order);
  226.     zone->busy_count -= (1 << order);
  227.    
  228.     spinlock_unlock(&zone->lock);
  229.     spinlock_unlock(&zone_head_lock);
  230.     interrupts_restore(ipl);
  231. }
  232.  
  233. /** Mark frame region not free.
  234.  *
  235.  * Mark frame region not free.
  236.  *
  237.  * @param base Base address of non-available region.
  238.  * @param size Size of non-available region.
  239.  */
  240. void frame_region_not_free(__address base, size_t size)
  241. {
  242.     index_t index;
  243.     index = zone_blacklist_count++;
  244.  
  245.     /* Force base to the nearest lower address frame boundary. */
  246.     base = ALIGN_DOWN(base, FRAME_SIZE);
  247.     /* Align size to frame boundary. */
  248.     size = ALIGN_UP(size, FRAME_SIZE);
  249.  
  250.     ASSERT(index < ZONE_BLACKLIST_SIZE);
  251.     zone_blacklist[index].base = base;
  252.     zone_blacklist[index].size = size;
  253. }
  254.  
  255. /** Create frame zones in region of available memory.
  256.  *
  257.  * Avoid any black listed areas of non-available memory.
  258.  * Assume that the black listed areas cannot overlap
  259.  * one another or cross available memory region boundaries.
  260.  *
  261.  * @param base Base address of available memory region.
  262.  * @param size Size of the region.
  263.  */
  264. void zone_create_in_region(__address base, size_t size) {
  265.     int i;
  266.     zone_t * z;
  267.     __address s;
  268.     size_t sz;
  269.    
  270.     ASSERT(base % FRAME_SIZE == 0);
  271.     ASSERT(size % FRAME_SIZE == 0);
  272.    
  273.     if (!size)
  274.         return;
  275.  
  276.     for (i = 0; i < zone_blacklist_count; i++) {
  277.         if (zone_blacklist[i].base >= base && zone_blacklist[i].base < base + size) {
  278.             s = base; sz = zone_blacklist[i].base - base;
  279.             ASSERT(base != s || sz != size);
  280.             zone_create_in_region(s, sz);
  281.            
  282.             s = zone_blacklist[i].base + zone_blacklist[i].size;
  283.             sz = (base + size) - (zone_blacklist[i].base + zone_blacklist[i].size);
  284.             ASSERT(base != s || sz != size);
  285.             zone_create_in_region(s, sz);
  286.             return;
  287.        
  288.         }
  289.     }
  290.    
  291.     z = zone_create(base, size, 0);
  292.  
  293.     if (!z) {
  294.         panic("Cannot allocate zone (base=%P, size=%d).\n", base, size);
  295.     }
  296.    
  297.     zone_attach(z);
  298. }
  299.  
  300.  
  301. /** Create frame zone
  302.  *
  303.  * Create new frame zone.
  304.  *
  305.  * @param start Physical address of the first frame within the zone.
  306.  * @param size Size of the zone. Must be a multiple of FRAME_SIZE.
  307.  * @param flags Zone flags.
  308.  *
  309.  * @return Initialized zone.
  310.  */
  311. zone_t * zone_create(__address start, size_t size, int flags)
  312. {
  313.     zone_t *z;
  314.     count_t cnt;
  315.     int i;
  316.     __u8 max_order;
  317.  
  318.     ASSERT(start % FRAME_SIZE == 0);
  319.     ASSERT(size % FRAME_SIZE == 0);
  320.    
  321.     cnt = size / FRAME_SIZE;
  322.    
  323.     z = (zone_t *) early_malloc(sizeof(zone_t));
  324.     if (z) {
  325.         link_initialize(&z->link);
  326.         spinlock_initialize(&z->lock, "zone_lock");
  327.    
  328.         z->base = start;
  329.         z->base_index = start / FRAME_SIZE;
  330.        
  331.         z->flags = flags;
  332.  
  333.         z->free_count = cnt;
  334.         z->busy_count = 0;
  335.        
  336.         z->frames = (frame_t *) early_malloc(cnt * sizeof(frame_t));
  337.         if (!z->frames) {
  338.             early_free(z);
  339.             return NULL;
  340.         }
  341.        
  342.         for (i = 0; i<cnt; i++) {
  343.             frame_initialize(&z->frames[i], z);
  344.         }
  345.        
  346.         /*
  347.          * Create buddy system for the zone
  348.          */
  349.         for (max_order = 0; cnt >> max_order; max_order++)
  350.             ;
  351.         z->buddy_system = buddy_system_create(max_order, &zone_buddy_system_operations, (void *) z);
  352.        
  353.         /* Stuffing frames */
  354.         for (i = 0; i<cnt; i++) {
  355.             z->frames[i].refcount = 0;
  356.             buddy_system_free(z->buddy_system, &z->frames[i].buddy_link);  
  357.         }
  358.        
  359.     }
  360.     return z;
  361. }
  362.  
  363. /** Attach frame zone
  364.  *
  365.  * Attach frame zone to zone list.
  366.  *
  367.  * @param zone Zone to be attached.
  368.  */
  369. void zone_attach(zone_t *zone)
  370. {
  371.     ipl_t ipl;
  372.    
  373.     ipl = interrupts_disable();
  374.     spinlock_lock(&zone_head_lock);
  375.    
  376.     list_append(&zone->link, &zone_head);
  377.    
  378.     spinlock_unlock(&zone_head_lock);
  379.     interrupts_restore(ipl);
  380. }
  381.  
  382. /** Initialize frame structure
  383.  *
  384.  * Initialize frame structure.
  385.  *
  386.  * @param frame Frame structure to be initialized.
  387.  * @param zone Host frame zone.
  388.  */
  389. void frame_initialize(frame_t *frame, zone_t *zone)
  390. {
  391.     frame->refcount = 1;
  392.     frame->buddy_order = 0;
  393. }
  394.  
  395.  
  396. /** Buddy system find_buddy implementation
  397.  *
  398.  * @param b Buddy system.
  399.  * @param block Block for which buddy should be found
  400.  *
  401.  * @return Buddy for given block if found
  402.  */
  403. link_t * zone_buddy_find_buddy(buddy_system_t *b, link_t * block) {
  404.     frame_t * frame;
  405.     zone_t * zone;
  406.     index_t index;
  407.     bool is_left, is_right;
  408.  
  409.     frame = list_get_instance(block, frame_t, buddy_link);
  410.     zone = (zone_t *) b->data;
  411.     ASSERT(IS_BUDDY_ORDER_OK(FRAME_INDEX_ABS(zone, frame), frame->buddy_order));
  412.    
  413.    
  414.     is_left = IS_BUDDY_LEFT_BLOCK_ABS(zone, frame);
  415.     is_right = IS_BUDDY_RIGHT_BLOCK_ABS(zone, frame);
  416.    
  417.     ASSERT(is_left ^ is_right);
  418.    
  419.     if (is_left) {
  420.         index = (FRAME_INDEX(zone, frame)) + (1 << frame->buddy_order);
  421.     } else { // if (is_right)
  422.         index = (FRAME_INDEX(zone, frame)) - (1 << frame->buddy_order);
  423.     }
  424.    
  425.     if (FRAME_INDEX_VALID(zone, index)) {
  426.         if (    zone->frames[index].buddy_order == frame->buddy_order &&
  427.             zone->frames[index].refcount == 0) {
  428.             return &zone->frames[index].buddy_link;
  429.         }
  430.     }
  431.    
  432.     return NULL;   
  433. }
  434.  
  435. /** Buddy system bisect implementation
  436.  *
  437.  * @param b Buddy system.
  438.  * @param block Block to bisect
  439.  *
  440.  * @return right block
  441.  */
  442. link_t * zone_buddy_bisect(buddy_system_t *b, link_t * block) {
  443.     frame_t * frame_l, * frame_r;
  444.  
  445.     frame_l = list_get_instance(block, frame_t, buddy_link);
  446.     frame_r = (frame_l + (1 << (frame_l->buddy_order - 1)));
  447.    
  448.     return &frame_r->buddy_link;
  449. }
  450.  
  451. /** Buddy system coalesce implementation
  452.  *
  453.  * @param b Buddy system.
  454.  * @param block_1 First block
  455.  * @param block_2 First block's buddy
  456.  *
  457.  * @return Coalesced block (actually block that represents lower address)
  458.  */
  459. link_t * zone_buddy_coalesce(buddy_system_t *b, link_t * block_1, link_t * block_2) {
  460.     frame_t * frame1, * frame2;
  461.    
  462.     frame1 = list_get_instance(block_1, frame_t, buddy_link);
  463.     frame2 = list_get_instance(block_2, frame_t, buddy_link);
  464.    
  465.     return frame1 < frame2 ? block_1 : block_2;
  466. }
  467.  
  468. /** Buddy system set_order implementation
  469.  *
  470.  * @param b Buddy system.
  471.  * @param block Buddy system block
  472.  * @param order Order to set
  473.  */
  474. void zone_buddy_set_order(buddy_system_t *b, link_t * block, __u8 order) {
  475.     frame_t * frame;
  476.     frame = list_get_instance(block, frame_t, buddy_link);
  477.     frame->buddy_order = order;
  478. }
  479.  
  480. /** Buddy system get_order implementation
  481.  *
  482.  * @param b Buddy system.
  483.  * @param block Buddy system block
  484.  *
  485.  * @return Order of block
  486.  */
  487. __u8 zone_buddy_get_order(buddy_system_t *b, link_t * block) {
  488.     frame_t * frame;
  489.     frame = list_get_instance(block, frame_t, buddy_link);
  490.     return frame->buddy_order;
  491. }
  492.  
  493. /** Buddy system mark_busy implementation
  494.  *
  495.  * @param b Buddy system
  496.  * @param block Buddy system block
  497.  *
  498.  */
  499. void zone_buddy_mark_busy(buddy_system_t *b, link_t * block) {
  500.     frame_t * frame;
  501.     frame = list_get_instance(block, frame_t, buddy_link);
  502.     frame->refcount = 1;
  503. }
  504.  
  505. /** Prints list of zones
  506.  *
  507.  */
  508. void zone_print_list(void) {
  509.     zone_t *zone = NULL;
  510.     link_t *cur;
  511.     ipl_t ipl;
  512.  
  513.     ipl = interrupts_disable();
  514.     spinlock_lock(&zone_head_lock);
  515.     printf("Base address\tFree Frames\tBusy Frames\n");
  516.     printf("------------\t-----------\t-----------\n");
  517.     for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
  518.         zone = list_get_instance(cur, zone_t, link);
  519.         spinlock_lock(&zone->lock);
  520.         printf("%L\t%d\t\t%d\n",zone->base, zone->free_count, zone->busy_count);
  521.         spinlock_unlock(&zone->lock);
  522.     }
  523.     spinlock_unlock(&zone_head_lock);
  524.     interrupts_restore(ipl);
  525. }
  526.  
  527. /** Prints zone details
  528.  *
  529.  * @param base Zone base address
  530.  */
  531. void zone_print_one(__address base) {
  532.     zone_t *zone = NULL, *z ;
  533.     link_t *cur;
  534.     ipl_t ipl;
  535.  
  536.     ipl = interrupts_disable();
  537.     spinlock_lock(&zone_head_lock);
  538.    
  539.     for (cur = zone_head.next; cur != &zone_head; cur = cur->next) {
  540.         z = list_get_instance(cur, zone_t, link);
  541.         if (base == z->base) {
  542.             zone = z;
  543.             break;
  544.         }
  545.     }
  546.    
  547.     if (!zone) {
  548.         spinlock_unlock(&zone_head_lock);
  549.         interrupts_restore(ipl);
  550.         printf("No zone with address %X\n", base);
  551.         return;
  552.     }
  553.    
  554.     spinlock_lock(&zone->lock);
  555.     printf("Memory zone information\n\n");
  556.     printf("Zone base address: %P\n", zone->base);
  557.     printf("Zone size: %d frames (%dK)\n", zone->free_count + zone->busy_count, ((zone->free_count + zone->busy_count) * FRAME_SIZE) >> 10);
  558.     printf("Allocated space: %d frames (%dK)\n", zone->busy_count, (zone->busy_count * FRAME_SIZE) >> 10);
  559.     printf("Available space: %d (%dK)\n", zone->free_count, (zone->free_count * FRAME_SIZE) >> 10);
  560.    
  561.     printf("\nBuddy allocator structures:\n\n");
  562.     buddy_system_structure_print(zone->buddy_system, FRAME_SIZE);
  563.    
  564.     spinlock_unlock(&zone->lock);
  565.     spinlock_unlock(&zone_head_lock);
  566.     interrupts_restore(ipl);
  567. }
  568.  
  569.