Subversion Repositories HelenOS-historic

Rev

Rev 487 | Rev 489 | 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.  
  41. spinlock_t zone_head_lock;       /**< this lock protects zone_head list */
  42. link_t zone_head;                /**< list of all zones in the system */
  43.  
  44. static 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.  */
  56. void 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.    
  86. loop:
  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.  */
  151. void 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.  */
  210. void 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.  */
  270. void 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.  */
  285. void 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.  */
  301. zone_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.  */
  353. void 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.  */
  373. void 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.    
  398. loop:
  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.  */
  460. void 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.  */
  516. zone_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.  */
  550. link_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.  */
  602. link_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.  */
  620. link_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.  */
  633. void 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. }
  649.