Subversion Repositories HelenOS

Rev

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