Subversion Repositories Kolibri OS

Rev

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

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