Subversion Repositories Kolibri OS

Rev

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