Subversion Repositories Kolibri OS

Rev

Rev 908 | 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. extern u32_t pg_balloc;
  9.  
  10. extern u32_t mem_amount;
  11.  
  12. void __fastcall *balloc(u32_t size);
  13.  
  14. zone_t z_core;
  15.  
  16.  
  17. static void buddy_system_create(zone_t *z);
  18. static void  __fastcall buddy_system_free(zone_t *z, link_t *block);
  19. static void zone_mark_unavailable(zone_t *zone, index_t frame_idx);
  20.  
  21. static addr_t __fastcall zone_alloc(zone_t *zone, u32_t order);
  22. void __fastcall zone_free(zone_t *zone, pfn_t frame_idx);
  23.  
  24. size_t buddy_conf_size(int max_order);
  25.  
  26. static inline void frame_initialize(frame_t *frame);
  27.  
  28.  
  29. static void zone_create(zone_t *z, pfn_t start, count_t count);
  30. static void zone_reserve(zone_t *z, pfn_t base, count_t count);
  31. static void zone_release(zone_t *z, pfn_t base, count_t count);
  32.  
  33.  
  34. void init_mm()
  35. {
  36.    int i;
  37.  
  38.    u32_t   base;
  39.    u32_t   size;
  40.    count_t pages;
  41.    size_t  conf_size;
  42.    size_t  core_size;
  43.  
  44.    pages = mem_amount >> FRAME_WIDTH;
  45.    DBG("last page = %x total pages =  %x\n",mem_amount, pages);
  46.  
  47.    conf_size = pages*sizeof(frame_t);
  48.    DBG("conf_size = %x  free mem start =%x\n",conf_size, pg_balloc);
  49.  
  50.    zone_create(&z_core, 0, pages);
  51.  
  52.    zone_release(&z_core, 0, pages);
  53.    zone_reserve(&z_core, 0, pg_balloc >> FRAME_WIDTH);
  54.  
  55.  
  56. #if 0
  57.    core_size = (pg_free+conf_size+1024*1024*5)&(-1024*1024*4);
  58. //   printf("core size = %x core heap = %x\n",core_size,core_size-conf_size-pg_free);
  59.  
  60.    u32_t p0, p1;
  61.    u32_t b0, b1;
  62.  
  63.    p0 = core_size>>12;
  64.    p1 = (last_page-core_size)>>12;
  65.  
  66.    b0 = p0*sizeof(frame_t);
  67.    b1 = p1*sizeof(frame_t);
  68.  
  69. //   printf("buddy_0: %x pages  conf_size %x\n", p0, b0);
  70. //   printf("buddy_1: %x pages  conf_size %x\n", p1, b1);
  71.  
  72.    zone_create(&z_core, 0, p0);
  73.    zone_create(&z_user, p0, p1);
  74.  
  75. //   printf("free mem start = %x\n",pg_balloc);
  76.  
  77.    for(i = 0; i < mem_counter; i++)
  78.    {
  79.      u32_t page;
  80.      if( mem_table[i].type != 1)
  81.        continue;
  82.      page = (mem_table[i].base+mem_table[i].size)&(~4095);
  83.      if(page > last_page)
  84.         last_page = page;
  85.  
  86.      zone_release(&z_core,mem_table[i].base>>12, mem_table[i].size>>12);
  87.      zone_release(&z_user,mem_table[i].base>>12, mem_table[i].size>>12);
  88.    };
  89.    zone_reserve(&z_core, 0x100000>>12,(pg_balloc-OS_BASE-0x100000)>>12);
  90. #endif
  91. };
  92.  
  93. static void zone_create(zone_t *z, pfn_t start, count_t count)
  94. {
  95.         unsigned int i;
  96. //  int znum;
  97.  
  98.         /* Theoretically we could have here 0, practically make sure
  99.          * nobody tries to do that. If some platform requires, remove
  100.          * the assert
  101.          */
  102. //  ASSERT(confframe);
  103.         /* If conframe is supposed to be inside our zone, then make sure
  104.          * it does not span kernel & init
  105.          */
  106.  
  107. //  printf("create zone: base %x count %x\n", start, count);
  108.  
  109.   spinlock_initialize(&z->lock);
  110.         z->base = start;
  111.         z->count = count;
  112.         z->free_count = count;
  113.         z->busy_count = 0;
  114.  
  115.   z->max_order = fnzb(count);
  116.  
  117.   ASSERT(z->max_order < BUDDY_SYSTEM_INNER_BLOCK);
  118.  
  119.   for (i = 0; i <= z->max_order; i++)
  120.     list_initialize(&z->order[i]);
  121.  
  122.   z->frames = (frame_t *)balloc(count*sizeof(frame_t));
  123.  
  124.         for (i = 0; i < count; i++) {
  125.                 frame_initialize(&z->frames[i]);
  126.         }
  127. }
  128.  
  129. static void zone_reserve(zone_t *z, pfn_t base, count_t count)
  130. {
  131.   int i;
  132.   pfn_t top = base+count;
  133.  
  134.   if( (base+count < z->base)||(base > z->base+z->count))
  135.     return;
  136.  
  137.   if(base < z->base)
  138.     base = z->base;
  139.  
  140.   if(top > z->base+z->count)
  141.      top = z->base+z->count;
  142.  
  143.   DBG("zone reserve base %x top %x\n", base, top);
  144.  
  145.   for (i = base; i < top; i++)
  146.     zone_mark_unavailable(z, i - z->base);
  147.  
  148. };
  149.  
  150. static void zone_release(zone_t *z, pfn_t base, count_t count)
  151. {
  152.     int i;
  153.     pfn_t top = base+count;
  154.  
  155.     if( (base+count < z->base)||(base > z->base+z->count))
  156.         return;
  157.  
  158.     if(base < z->base)
  159.         base = z->base;
  160.  
  161.     if(top > z->base+z->count)
  162.         top = z->base+z->count;
  163.  
  164.     DBG("zone release base %x top %x\n", base, top);
  165.  
  166.     for (i = base; i < top; i++) {
  167.         z->frames[i-z->base].refcount = 0;
  168.         buddy_system_free(z, &z->frames[i-z->base].buddy_link);
  169.     }
  170. };
  171.  
  172.  
  173. static inline index_t frame_index(zone_t *zone, frame_t *frame)
  174. {
  175.         return (index_t) (frame - zone->frames);
  176. }
  177.  
  178. static inline index_t frame_index_abs(zone_t *zone, frame_t *frame)
  179. {
  180.   return (index_t) (frame - zone->frames);
  181. }
  182.  
  183. static inline int frame_index_valid(zone_t *zone, index_t index)
  184. {
  185.         return (index < zone->count);
  186. }
  187.  
  188. /** Compute pfn_t from frame_t pointer & zone pointer */
  189. static inline index_t make_frame_index(zone_t *zone, frame_t *frame)
  190. {
  191.         return (frame - zone->frames);
  192. }
  193.  
  194. static inline void frame_initialize(frame_t *frame)
  195. {
  196.         frame->refcount = 1;
  197.         frame->buddy_order = 0;
  198. }
  199.  
  200.  
  201. static link_t *buddy_find_block(zone_t *zone, link_t *child,
  202.     u32_t order)
  203. {
  204.         frame_t *frame;
  205.         index_t index;
  206.  
  207.   frame = (frame_t*)child;
  208.  
  209.         index = frame_index(zone, frame);
  210.         do {
  211.                 if (zone->frames[index].buddy_order != order) {
  212.                         return &zone->frames[index].buddy_link;
  213.                 }
  214.         } while(index-- > 0);
  215.         return NULL;
  216. }
  217.  
  218. static inline link_t * buddy_bisect(zone_t *z, link_t *block) {
  219.         frame_t *frame_l, *frame_r;
  220.  
  221.   frame_l = (frame_t*)block;
  222.         frame_r = (frame_l + (1 << (frame_l->buddy_order - 1)));
  223.  
  224.         return &frame_r->buddy_link;
  225. }
  226.  
  227. static inline u32_t buddy_get_order(zone_t *z, link_t *block) {
  228.   frame_t *frame = (frame_t*)block;
  229.         return frame->buddy_order;
  230. }
  231.  
  232. static inline void buddy_set_order(zone_t *z, link_t *block,
  233.     u32_t order) {
  234.   frame_t *frame = (frame_t*)block;
  235.         frame->buddy_order = order;
  236. }
  237.  
  238. static link_t *buddy_coalesce(zone_t *z, link_t *block_1,
  239.     link_t *block_2)
  240. {
  241.         frame_t *frame1, *frame2;
  242.  
  243.   frame1 = (frame_t*)block_1;
  244.   frame2 = (frame_t*)block_2;
  245.  
  246.         return frame1 < frame2 ? block_1 : block_2;
  247. }
  248.  
  249. static inline void buddy_mark_busy(zone_t *z, link_t * block) {
  250.     frame_t * frame = (frame_t*)block;
  251.         frame->refcount = 1;
  252. }
  253.  
  254. static inline void buddy_mark_available(zone_t *z, link_t *block) {
  255.     frame_t *frame = (frame_t*)block;
  256.         frame->refcount = 0;
  257. }
  258.  
  259. #define IS_BUDDY_ORDER_OK(index, order)   \
  260.     ((~(((u32_t) -1) << (order)) & (index)) == 0)
  261. #define IS_BUDDY_LEFT_BLOCK_ABS(zone, frame)  \
  262.   (((frame_index_abs((zone), (frame)) >> (frame)->buddy_order) & 0x1) == 0)
  263.  
  264. #define IS_BUDDY_RIGHT_BLOCK_ABS(zone, frame) \
  265.         (((frame_index_abs((zone), (frame)) >> (frame)->buddy_order) & 0x1) == 1)
  266.  
  267. static link_t *find_buddy(zone_t *zone, link_t *block)
  268. {
  269.         frame_t *frame;
  270.         index_t index;
  271.     u32_t is_left, is_right;
  272.  
  273.     frame = (frame_t*)block;
  274.     ASSERT(IS_BUDDY_ORDER_OK(frame_index_abs(zone, frame),frame->buddy_order));
  275.  
  276.         is_left = IS_BUDDY_LEFT_BLOCK_ABS(zone, frame);
  277.         is_right = IS_BUDDY_RIGHT_BLOCK_ABS(zone, frame);
  278.  
  279.     ASSERT(is_left ^ is_right);
  280.         if (is_left) {
  281.                 index = (frame_index(zone, frame)) + (1 << frame->buddy_order);
  282.         } else {        /* if (is_right) */
  283.                 index = (frame_index(zone, frame)) - (1 << frame->buddy_order);
  284.         }
  285.  
  286.         if (frame_index_valid(zone, index)) {
  287.                 if (zone->frames[index].buddy_order == frame->buddy_order &&
  288.                     zone->frames[index].refcount == 0) {
  289.                         return &zone->frames[index].buddy_link;
  290.                 }
  291.         }
  292.  
  293.         return NULL;
  294. }
  295.  
  296. static link_t* __fastcall buddy_system_alloc_block(zone_t *z, link_t *block)
  297. {
  298.         link_t *left,*right, *tmp;
  299.     u32_t order;
  300.  
  301.     left = buddy_find_block(z, block, BUDDY_SYSTEM_INNER_BLOCK);
  302.     ASSERT(left);
  303.         list_remove(left);
  304.         while (1) {
  305.         if (! buddy_get_order(z,left)) {
  306.             buddy_mark_busy(z, left);
  307.                         return left;
  308.                 }
  309.  
  310.         order = buddy_get_order(z, left);
  311.  
  312.         right = buddy_bisect(z, left);
  313.         buddy_set_order(z, left, order-1);
  314.         buddy_set_order(z, right, order-1);
  315.  
  316.         tmp = buddy_find_block(z, block, BUDDY_SYSTEM_INNER_BLOCK);
  317.  
  318.         if (tmp == right) {
  319.             right = left;
  320.             left = tmp;
  321.         }
  322.         ASSERT(tmp == left);
  323.         buddy_mark_busy(z, left);
  324.         buddy_system_free(z, right);
  325.         buddy_mark_available(z, left);
  326.         }
  327. }
  328.  
  329. static void __fastcall buddy_system_free(zone_t *z, link_t *block)
  330. {
  331.     link_t *buddy, *hlp;
  332.     u8_t i;
  333.  
  334.     /*
  335.          * Determine block's order.
  336.          */
  337.     i = buddy_get_order(z, block);
  338.  
  339.     ASSERT(i <= z->max_order);
  340.  
  341.     if (i != z->max_order) {
  342.                 /*
  343.                  * See if there is any buddy in the list of order i.
  344.                  */
  345.         buddy = find_buddy(z, block);
  346.                 if (buddy) {
  347.  
  348.             ASSERT(buddy_get_order(z, buddy) == i);
  349.                         /*
  350.                          * Remove buddy from the list of order i.
  351.                          */
  352.                         list_remove(buddy);
  353.  
  354.                         /*
  355.                          * Invalidate order of both block and buddy.
  356.                          */
  357.             buddy_set_order(z, block, BUDDY_SYSTEM_INNER_BLOCK);
  358.             buddy_set_order(z, buddy, BUDDY_SYSTEM_INNER_BLOCK);
  359.  
  360.                         /*
  361.                          * Coalesce block and buddy into one block.
  362.                          */
  363.             hlp = buddy_coalesce(z, block, buddy);
  364.  
  365.                         /*
  366.                          * Set order of the coalesced block to i + 1.
  367.                          */
  368.             buddy_set_order(z, hlp, i + 1);
  369.  
  370.                         /*
  371.                          * Recursively add the coalesced block to the list of order i + 1.
  372.                          */
  373.             buddy_system_free(z, hlp);
  374.                         return;
  375.                 }
  376.         }
  377.         /*
  378.          * Insert block into the list of order i.
  379.          */
  380.     list_append(block, &z->order[i]);
  381. }
  382.  
  383. static inline frame_t * zone_get_frame(zone_t *zone, index_t frame_idx)
  384. {
  385.     ASSERT(frame_idx < zone->count);
  386.         return &zone->frames[frame_idx];
  387. }
  388.  
  389. static void zone_mark_unavailable(zone_t *zone, index_t frame_idx)
  390. {
  391.         frame_t *frame;
  392.         link_t *link;
  393.  
  394.         frame = zone_get_frame(zone, frame_idx);
  395.         if (frame->refcount)
  396.                 return;
  397.     link = buddy_system_alloc_block(zone, &frame->buddy_link);
  398.     ASSERT(link);
  399.         zone->free_count--;
  400. }
  401.  
  402. static link_t* __fastcall buddy_system_alloc(zone_t *z, u32_t i)
  403. {
  404.         link_t *res, *hlp;
  405.  
  406.     ASSERT(i <= z->max_order);
  407.  
  408.         /*
  409.          * If the list of order i is not empty,
  410.          * the request can be immediatelly satisfied.
  411.          */
  412.         if (!list_empty(&z->order[i])) {
  413.                 res = z->order[i].next;
  414.                 list_remove(res);
  415.                 buddy_mark_busy(z, res);
  416.                 return res;
  417.         }
  418.         /*
  419.          * If order i is already the maximal order,
  420.          * the request cannot be satisfied.
  421.          */
  422.         if (i == z->max_order)
  423.                 return NULL;
  424.  
  425.         /*
  426.          * Try to recursively satisfy the request from higher order lists.
  427.          */
  428.         hlp = buddy_system_alloc(z, i + 1);
  429.  
  430.         /*
  431.          * The request could not be satisfied
  432.          * from higher order lists.
  433.          */
  434.         if (!hlp)
  435.                 return NULL;
  436.  
  437.         res = hlp;
  438.  
  439.         /*
  440.          * Bisect the block and set order of both of its parts to i.
  441.          */
  442.         hlp = buddy_bisect(z, res);
  443.         buddy_set_order(z, res, i);
  444.         buddy_set_order(z, hlp, i);
  445.  
  446.         /*
  447.          * Return the other half to buddy system. Mark the first part
  448.          * full, so that it won't coalesce again.
  449.          */
  450.         buddy_mark_busy(z, res);
  451.         buddy_system_free(z, hlp);
  452.  
  453.         return res;
  454.  
  455. }
  456.  
  457.  
  458. static __fastcall pfn_t zone_frame_alloc(zone_t *zone, u32_t order)
  459. {
  460.         pfn_t v;
  461.         link_t *tmp;
  462.         frame_t *frame;
  463.  
  464.  
  465.         /* Allocate frames from zone buddy system */
  466.         tmp = buddy_system_alloc(zone, order);
  467.  
  468.     ASSERT(tmp);
  469.  
  470.         /* Update zone information. */
  471.         zone->free_count -= (1 << order);
  472.         zone->busy_count += (1 << order);
  473.  
  474.         /* Frame will be actually a first frame of the block. */
  475.         frame = (frame_t*)tmp;
  476.  
  477.         /* get frame address */
  478.         v = make_frame_index(zone, frame);
  479.  
  480.         return v;
  481. }
  482.  
  483.  
  484. /** Set parent of frame */
  485. void __fastcall frame_set_parent(pfn_t pfn, void *data)
  486. {
  487. /*  zone_t *zone = find_zone_and_lock(pfn, &hint);
  488.   ASSERT(zone);
  489.  */
  490.  
  491.   spinlock_lock(&z_core.lock);
  492.     zone_get_frame(&z_core, pfn-z_core.base)->parent = data;
  493.   spinlock_unlock(&z_core.lock);
  494. }
  495.  
  496. void* __fastcall frame_get_parent(pfn_t pfn)
  497. {
  498. //      zone_t *zone = find_zone_and_lock(pfn, &hint);
  499.         void *res;
  500.  
  501.   spinlock_lock(&z_core.lock);
  502.     res = zone_get_frame(&z_core, pfn)->parent;
  503.   spinlock_unlock(&z_core.lock);
  504.  
  505.         return res;
  506. }
  507.  
  508. static inline int to_order(count_t arg)
  509. {
  510.   int n;
  511.   asm volatile (
  512.                 "xorl %eax, %eax \n\t"
  513.                 "bsr %edx, %eax \n\t"
  514.                 "incl %eax"
  515.                 :"=a" (n)
  516.                 :"d"(arg)
  517.                 );
  518.         return n;
  519. }
  520.  
  521.  
  522. addr_t __fastcall zone_alloc(zone_t *zone, u32_t order)
  523. {
  524.    eflags_t efl;
  525.    pfn_t v;
  526.  
  527.    efl = safe_cli();
  528.      spinlock_lock(&zone->lock);
  529.        v = zone_frame_alloc(zone, order);
  530.        v += zone->base;
  531.      spinlock_unlock(&zone->lock);
  532.    safe_sti(efl);
  533.  
  534.    return (v << FRAME_WIDTH);
  535. }
  536.  
  537. addr_t  __fastcall core_alloc(u32_t order)
  538. {
  539.    eflags_t efl;
  540.    pfn_t v;
  541.  
  542.    efl = safe_cli();
  543.      spinlock_lock(&z_core.lock);
  544.        v = zone_frame_alloc(&z_core, order);
  545.      spinlock_unlock(&z_core.lock);
  546.    safe_sti(efl);
  547.  
  548.    DBG("core alloc at: 0x%x, size 0x%x   remain  %d\n", v << FRAME_WIDTH,
  549.         ((1<<order)<<FRAME_WIDTH), z_core.free_count);
  550.  
  551.    return (v << FRAME_WIDTH);
  552. };
  553.  
  554. void __fastcall core_free(addr_t frame)
  555. {
  556.    eflags_t efl;
  557.  
  558.    DBG("core free  0x%x", frame);
  559.  
  560.    efl = safe_cli();
  561.      spinlock_lock(&z_core.lock);
  562.  //      zone_free(&z_core, frame>>12);
  563.      spinlock_unlock(&z_core.lock);
  564.    safe_sti(efl);
  565.  
  566.    DBG("  remain %d\n", z_core.free_count);
  567.  
  568. }
  569.  
  570. addr_t alloc_page()                                //obsolete
  571. {
  572.    eflags_t efl;
  573.    u32_t    edx;
  574.    pfn_t v;
  575.  
  576.    edx = save_edx();
  577.    efl = safe_cli();
  578.      spinlock_lock(&z_core.lock);
  579.        v = zone_frame_alloc(&z_core, 0);
  580.      spinlock_unlock(&z_core.lock);
  581.    safe_sti(efl);
  582.  
  583.    DBG("alloc_page: %x   remain  %d\n", v << FRAME_WIDTH, z_core.free_count);
  584.  
  585.    restore_edx(edx);
  586.    return (v << FRAME_WIDTH);
  587. };
  588.  
  589. void __fastcall zone_free(zone_t *zone, pfn_t frame_idx)
  590. {
  591.         frame_t *frame;
  592.     u32_t order;
  593.  
  594.         frame = &zone->frames[frame_idx];
  595.  
  596.         /* remember frame order */
  597.         order = frame->buddy_order;
  598.  
  599.     ASSERT(frame->refcount);
  600.  
  601.     if (!--frame->refcount)
  602.     {
  603.                 buddy_system_free(zone, &frame->buddy_link);
  604.  
  605.                 /* Update zone information. */
  606.                 zone->free_count += (1 << order);
  607.                 zone->busy_count -= (1 << order);
  608.         }
  609. }
  610.  
  611. void frame_free(addr_t frame)           //export
  612. {
  613.    eflags_t efl;
  614.    zone_t *zone;
  615.  
  616.    efl = safe_cli();
  617.      spinlock_lock(&z_core.lock);
  618.        zone_free(&z_core, frame>>12);
  619.      spinlock_unlock(&z_core.lock);
  620.   safe_sti(efl);
  621. }
  622.  
  623. count_t get_free_mem()
  624. {
  625.    return z_core.free_count;
  626. }
  627.  
  628.