Subversion Repositories Kolibri OS

Rev

Rev 1313 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1.  
  2. #define ALLOC_FAST
  3.  
  4. #include <types.h>
  5. #include <core.h>
  6. #include <spinlock.h>
  7. #include <link.h>
  8. #include <mm.h>
  9.  
  10. #define PG_DEMAND   0x400
  11.  
  12. #define HF_WIDTH    16
  13. #define HF_SIZE     (1 << HF_WIDTH)
  14.  
  15. #define BUDDY_SYSTEM_INNER_BLOCK  0xff
  16.  
  17. static zone_t z_heap;
  18.  
  19. static link_t  shared_mmap;
  20.  
  21.  
  22. #define heap_index( frame ) \
  23.           (index_t)( (frame) - z_heap.frames)
  24.  
  25. #define heap_index_abs( frame ) \
  26.           (index_t)( (frame) - z_heap.frames)
  27.  
  28.  
  29. static __inline void frame_initialize(frame_t *frame)
  30. {
  31.         frame->refcount = 1;
  32.         frame->buddy_order = 0;
  33. }
  34.  
  35. #define buddy_get_order( block) \
  36.     ((frame_t*)(block))->buddy_order
  37.  
  38.  
  39. #define buddy_set_order( block, order) \
  40.      ((frame_t*)(block))->buddy_order = (order)
  41.  
  42. #define buddy_mark_busy( block ) \
  43.     ((frame_t*)(block))->refcount = 1
  44.  
  45.  
  46. static __inline link_t * buddy_bisect(link_t *block)
  47. {
  48.     frame_t *frame_l, *frame_r;
  49.  
  50.     frame_l = (frame_t*)block;
  51.         frame_r = (frame_l + (1 << (frame_l->buddy_order - 1)));
  52.  
  53.         return &frame_r->buddy_link;
  54. }
  55.  
  56. static __inline link_t *buddy_coalesce(link_t *block_1, link_t *block_2)
  57. {
  58.         frame_t *frame1, *frame2;
  59.  
  60.     frame1 = (frame_t*)block_1;
  61.     frame2 = (frame_t*)block_2;
  62.  
  63.         return frame1 < frame2 ? block_1 : block_2;
  64. }
  65.  
  66.  
  67. #define IS_BUDDY_LEFT_BLOCK_ABS(frame)  \
  68.   (((heap_index_abs((frame)) >> (frame)->buddy_order) & 0x1) == 0)
  69.  
  70. #define IS_BUDDY_RIGHT_BLOCK_ABS(frame) \
  71.         (((heap_index_abs((frame)) >> (frame)->buddy_order) & 0x1) == 1)
  72.  
  73.  
  74. static link_t *find_buddy(link_t *block)
  75. {
  76.         frame_t *frame;
  77.         index_t index;
  78.     u32_t is_left, is_right;
  79.  
  80.     frame = (frame_t*)block;
  81.  //   ASSERT(IS_BUDDY_ORDER_OK(frame_index_abs(zone, frame),frame->buddy_order));
  82.  
  83.         is_left = IS_BUDDY_LEFT_BLOCK_ABS( frame);
  84.         is_right = IS_BUDDY_RIGHT_BLOCK_ABS( frame);
  85.  
  86.  //   ASSERT(is_left ^ is_right);
  87.  
  88.     if (is_left) {
  89.         index = (heap_index(frame)) + (1 << frame->buddy_order);
  90.     }
  91.     else {    /* if (is_right) */
  92.         index = (heap_index(frame)) - (1 << frame->buddy_order);
  93.     };
  94.  
  95.  
  96.         if ( index < z_heap.count)
  97.         {
  98.                 if (z_heap.frames[index].buddy_order == frame->buddy_order &&
  99.                     z_heap.frames[index].refcount == 0) {
  100.                         return &z_heap.frames[index].buddy_link;
  101.                 }
  102.         }
  103.  
  104.         return NULL;
  105. }
  106.  
  107.  
  108. static void buddy_system_free(link_t *block)
  109. {
  110.     link_t *buddy, *hlp;
  111.     u32_t i;
  112.  
  113.     /*
  114.          * Determine block's order.
  115.          */
  116.     i = buddy_get_order(block);
  117.  
  118.     ASSERT(i <= z_heap.max_order);
  119.  
  120.     if (i != z_heap.max_order)
  121.     {
  122.                 /*
  123.                  * See if there is any buddy in the list of order i.
  124.                  */
  125.         buddy = find_buddy( block );
  126.                 if (buddy)
  127.                 {
  128.  
  129.             ASSERT(buddy_get_order(buddy) == i);
  130.                         /*
  131.                          * Remove buddy from the list of order i.
  132.                          */
  133.                         list_remove(buddy);
  134.  
  135.                         /*
  136.                          * Invalidate order of both block and buddy.
  137.                          */
  138.             buddy_set_order(block, BUDDY_SYSTEM_INNER_BLOCK);
  139.             buddy_set_order(buddy, BUDDY_SYSTEM_INNER_BLOCK);
  140.  
  141.                         /*
  142.                          * Coalesce block and buddy into one block.
  143.                          */
  144.             hlp = buddy_coalesce( block, buddy );
  145.  
  146.                         /*
  147.                          * Set order of the coalesced block to i + 1.
  148.                          */
  149.             buddy_set_order(hlp, i + 1);
  150.  
  151.                         /*
  152.                          * Recursively add the coalesced block to the list of order i + 1.
  153.                          */
  154.             buddy_system_free( hlp );
  155.                         return;
  156.                 }
  157.         }
  158.         /*
  159.          * Insert block into the list of order i.
  160.          */
  161.     list_append(block, &z_heap.order[i]);
  162. }
  163.  
  164.  
  165. static link_t* buddy_system_alloc( u32_t i)
  166. {
  167.         link_t *res, *hlp;
  168.  
  169.     ASSERT(i <= z_heap.max_order);
  170.  
  171.         /*
  172.          * If the list of order i is not empty,
  173.          * the request can be immediatelly satisfied.
  174.          */
  175.         if (!list_empty(&z_heap.order[i])) {
  176.                 res = z_heap.order[i].next;
  177.                 list_remove(res);
  178.                 buddy_mark_busy(res);
  179.                 return res;
  180.         }
  181.         /*
  182.          * If order i is already the maximal order,
  183.          * the request cannot be satisfied.
  184.          */
  185.         if (i == z_heap.max_order)
  186.                 return NULL;
  187.  
  188.         /*
  189.          * Try to recursively satisfy the request from higher order lists.
  190.          */
  191.         hlp = buddy_system_alloc( i + 1 );
  192.  
  193.         /*
  194.          * The request could not be satisfied
  195.          * from higher order lists.
  196.          */
  197.         if (!hlp)
  198.                 return NULL;
  199.  
  200.         res = hlp;
  201.  
  202.         /*
  203.          * Bisect the block and set order of both of its parts to i.
  204.          */
  205.         hlp = buddy_bisect( res );
  206.  
  207.         buddy_set_order(res, i);
  208.         buddy_set_order(hlp, i);
  209.  
  210.         /*
  211.          * Return the other half to buddy system. Mark the first part
  212.          * full, so that it won't coalesce again.
  213.          */
  214.         buddy_mark_busy(res);
  215.         buddy_system_free( hlp );
  216.  
  217.         return res;
  218. }
  219.  
  220.  
  221. int __fastcall init_heap(addr_t start, size_t size)
  222. {
  223.         count_t i;
  224.     count_t count;
  225.  
  226.     count = size >> HF_WIDTH;
  227.  
  228.     ASSERT( start != 0);
  229.     ASSERT( count != 0);
  230.  
  231.     spinlock_initialize(&z_heap.lock);
  232.  
  233.     z_heap.base = start >> HF_WIDTH;
  234.         z_heap.count = count;
  235.         z_heap.free_count = count;
  236.         z_heap.busy_count = 0;
  237.  
  238.     z_heap.max_order = fnzb(count);
  239.  
  240.     DBG("create heap zone: base %x count %x\n", start, count);
  241.  
  242.     ASSERT(z_heap.max_order < BUDDY_SYSTEM_INNER_BLOCK);
  243.  
  244.     for (i = 0; i <= z_heap.max_order; i++)
  245.         list_initialize(&z_heap.order[i]);
  246.  
  247.  
  248.     DBG("count %d frame_t %d page_size %d\n",
  249.                count, sizeof(frame_t), PAGE_SIZE);
  250.  
  251.     z_heap.frames = (frame_t *)PA2KA(frame_alloc( (count*sizeof(frame_t)) >> PAGE_WIDTH ));
  252.  
  253.  
  254.     if( z_heap.frames == 0 )
  255.         return 0;
  256.  
  257.  
  258.         for (i = 0; i < count; i++) {
  259.                 z_heap.frames[i].buddy_order=0;
  260.                 z_heap.frames[i].parent = NULL;
  261.                 z_heap.frames[i].refcount=1;
  262.         }
  263.  
  264.     for (i = 0; i < count; i++)
  265.     {
  266.         z_heap.frames[i].refcount = 0;
  267.         buddy_system_free(&z_heap.frames[i].buddy_link);
  268.     }
  269.  
  270.     list_initialize(&shared_mmap);
  271.  
  272.         return 1;
  273. }
  274.  
  275. addr_t  __fastcall mem_alloc(size_t size, u32_t flags)
  276. {
  277.     eflags_t  efl;
  278.     addr_t    heap = 0;
  279.  
  280.     count_t   order;
  281.     frame_t  *frame;
  282.     index_t   v;
  283.     int i;
  284.     mmap_t   *map;
  285.     count_t   pages;
  286.  
  287.  //   __asm__ __volatile__ ("xchgw %bx, %bx");
  288.  
  289.     size = (size + 4095) & ~4095;
  290.  
  291.     pages = size >> PAGE_WIDTH;
  292.  
  293. //    map = (mmap_t*)malloc( sizeof(mmap_t) +
  294. //                           sizeof(addr_t) * pages);
  295.  
  296.     map = (mmap_t*)PA2KA(frame_alloc( (sizeof(mmap_t) +
  297.                            sizeof(addr_t) * pages) >> PAGE_WIDTH));
  298.  
  299.     if ( map )
  300.     {
  301.     map->size = size;
  302.  
  303.         order = size >> HF_WIDTH;
  304.  
  305.         if( order )
  306.             order = fnzb(order - 1) + 1;
  307.  
  308.         efl = safe_cli();
  309.  
  310.         spinlock_lock(&z_heap.lock);
  311.  
  312.         frame = (frame_t*)buddy_system_alloc(order);
  313.  
  314.         ASSERT( frame );
  315.  
  316.         if( frame )
  317.         {
  318.             addr_t  mem;
  319.  
  320.             z_heap.free_count -= (1 << order);
  321.             z_heap.busy_count += (1 << order);
  322.  
  323. /* get frame address */
  324.  
  325.             v = z_heap.base + (index_t)(frame - z_heap.frames);
  326.  
  327.             heap = v << HF_WIDTH;
  328.  
  329.             map->base = heap;
  330.  
  331.             for(i = 0; i < (1 << order); i++)
  332.                 frame[i].parent = map;
  333.  
  334.             spinlock_unlock(&z_heap.lock);
  335.  
  336.             safe_sti(efl);
  337.  
  338.  
  339.             addr_t  *pte = &((addr_t*)page_tabs)[heap >> PAGE_WIDTH];
  340.             addr_t  *mpte = &map->pte[0];
  341.  
  342.             mem = heap;
  343.  
  344.             if( flags & PG_MAP )
  345.             {
  346.                 addr_t  page_frame;
  347.  
  348. #ifdef  ALLOC_FAST
  349.  
  350.                 while( pages )
  351.                 {
  352.                     u32_t   order;
  353.  
  354.                     asm volatile ("bsrl %1, %0":"=&r"(order):"r"(pages):"cc");
  355.                     asm volatile ("btrl %1, %0" :"=&r"(pages):"r"(order):"cc");
  356.  
  357.                     page_frame = frame_alloc(1 << order) | (flags & 0xFFF);    /* FIXME check */
  358.  
  359.                     for(i = 0; i < 1 << order; i++)
  360.                     {
  361.                         *pte++  = 0;
  362.                         *mpte++ = page_frame;
  363.  
  364.                         asm volatile ( "invlpg (%0)" ::"r" (mem) );
  365.                         mem+=  4096;
  366.                         page_frame+= 4096;
  367.                     };
  368.                 }
  369. #else
  370.  
  371.                 page_frame = PG_DEMAND | (flags & 0xFFF);
  372.  
  373.                 while(pages--)
  374.                 {
  375.                     *pte++  = 0;
  376.                     *mpte++ = page_frame;
  377.                     asm volatile ( "invlpg (%0)" ::"r" (mem) );
  378.                     mem+=  4096;
  379.                 };
  380. #endif
  381.             }
  382.             else
  383.             {
  384.                 while(pages--)
  385.                 {
  386.                     *pte++  = 0;
  387.                     *mpte++ = 0;
  388.  
  389.                     asm volatile ( "invlpg (%0)" ::"r" (mem) );
  390.                     mem+=  4096;
  391.                 };
  392.             }
  393.  
  394.             DBG("%s %x size %d order %d\n", __FUNCTION__, heap, size, order);
  395.  
  396.             return heap;
  397.         }
  398.  
  399.         spinlock_unlock(&z_heap.lock);
  400.  
  401.         safe_sti(efl);
  402.  
  403.         frame_free( KA2PA(map) );
  404.     };
  405.  
  406.     return 0;
  407. }
  408.  
  409. void __fastcall mem_free(addr_t addr)
  410. {
  411.     eflags_t     efl;
  412.     frame_t     *frame;
  413.     count_t      idx;
  414.  
  415.     idx = (addr >> HF_WIDTH);
  416.  
  417.     if( (idx < z_heap.base) ||
  418.         (idx >= z_heap.base+z_heap.count)) {
  419.         DBG("invalid address %x\n", addr);
  420.         return;
  421.     }
  422.  
  423.     efl = safe_cli();
  424.  
  425.     frame = &z_heap.frames[idx-z_heap.base];
  426.  
  427.     u32_t order = frame->buddy_order;
  428.  
  429.     DBG("%s %x order %d\n", __FUNCTION__, addr, order);
  430.  
  431.     ASSERT(frame->refcount);
  432.  
  433.     spinlock_lock(&z_heap.lock);
  434.  
  435.     if (!--frame->refcount)
  436.     {
  437.         mmap_t  *map;
  438.         count_t  i;
  439.  
  440.         map = frame->parent;
  441.  
  442.         for(i = 0; i < (1 << order); i++)
  443.                 frame[i].parent = NULL;
  444.  
  445.         buddy_system_free(&frame->buddy_link);
  446.  
  447.                 /* Update zone information. */
  448.         z_heap.free_count += (1 << order);
  449.         z_heap.busy_count -= (1 << order);
  450.  
  451.         spinlock_unlock(&z_heap.lock);
  452.         safe_sti(efl);
  453.  
  454.         for( i = 0; i < (map->size >> PAGE_WIDTH); )
  455.         {
  456.            i+= frame_free(map->pte[i]);
  457.         }
  458.  
  459.         frame_free( KA2PA(map) );
  460.     }
  461.     else
  462.     {
  463.         spinlock_unlock(&z_heap.lock);
  464.         safe_sti(efl);
  465.     };
  466. };
  467.  
  468. void __fastcall heap_fault(addr_t faddr, u32_t code)
  469. {
  470.     index_t   idx;
  471.     frame_t  *frame;
  472.     mmap_t   *map;
  473.  
  474.     idx = faddr >> HF_WIDTH;
  475.  
  476.     frame = &z_heap.frames[idx-z_heap.base];
  477.  
  478.     map = frame->parent;
  479.  
  480.     ASSERT( faddr >= map->base);
  481.  
  482.     if( faddr < map->base + map->size)
  483.     {
  484.         addr_t page;
  485.  
  486.         idx = (faddr - map->base) >> PAGE_WIDTH;
  487.  
  488.         page = map->pte[idx];
  489.  
  490.         if( page != 0)
  491.         {
  492.             if( page & PG_DEMAND)
  493.             {
  494.                 page &= ~PG_DEMAND;
  495.                 page = alloc_page() | (page & 0xFFF);
  496.  
  497.                 map->pte[idx] = page;
  498.             };
  499.             ((addr_t*)page_tabs)[faddr >> PAGE_WIDTH] = page;
  500.         };
  501.     };
  502. };
  503.  
  504. //#include "mmap.inc"
  505.  
  506.