Subversion Repositories Kolibri OS

Rev

Rev 889 | Rev 908 | 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. #include <slab.h>
  8.  
  9. #define page_tabs 0xDF800000
  10.  
  11.  
  12. #define  MD_FREE    1
  13. #define  MD_USED    2
  14.  
  15. typedef struct {
  16.     u32_t  av_mapped;
  17.     u32_t  av_unmapped;
  18.  
  19.     link_t mapped[32];
  20.     link_t unmapped[32];
  21.  
  22.     link_t used;
  23.  
  24.     SPINLOCK_DECLARE(lock);   /**< this lock protects everything below */
  25. }heap_t;
  26.  
  27.  
  28. slab_cache_t *md_slab;
  29. slab_cache_t *phm_slab;
  30.  
  31.  
  32. heap_t        lheap;
  33. heap_t        sheap;
  34.  
  35.  
  36. static inline void _set_lavu(count_t idx)
  37. { asm volatile ("bts %0, _lheap+4"::"r"(idx):"cc"); }
  38.  
  39. static inline void _reset_lavu(count_t idx)
  40. { asm volatile ("btr %0, _lheap+4"::"r"(idx):"cc"); }
  41.  
  42. static inline void _set_savm(count_t idx)
  43. { asm volatile ("bts %0, _sheap"::"r"(idx):"cc"); }
  44.  
  45. static inline void _reset_savm(count_t idx)
  46. { asm volatile ("btr %0, _sheap"::"r"(idx):"cc"); }
  47.  
  48. static inline void _set_savu(count_t idx)
  49. { asm volatile ("bts %0, _sheap+4"::"r"(idx):"cc"); }
  50.  
  51. static inline void _reset_savu(count_t idx)
  52. { asm volatile ("btr %0, _sheap+4"::"r"(idx):"cc"); }
  53.  
  54.  
  55. int __fastcall init_heap(addr_t base, size_t size)
  56. {
  57.     md_t *md;
  58.     u32_t i;
  59.  
  60.     ASSERT(base != 0);
  61.     ASSERT(size != 0)
  62.     ASSERT((base & 0x3FFFFF) == 0);
  63.     ASSERT((size & 0x3FFFFF) == 0);
  64.  
  65.     for (i = 0; i < 32; i++)
  66.     {
  67.         list_initialize(&lheap.mapped[i]);
  68.         list_initialize(&lheap.unmapped[i]);
  69.  
  70.         list_initialize(&sheap.mapped[i]);
  71.         list_initialize(&sheap.unmapped[i]);
  72.     };
  73.  
  74.     list_initialize(&lheap.used);
  75.     list_initialize(&sheap.used);
  76.  
  77.     md_slab = slab_cache_create(sizeof(md_t), 32,NULL,NULL,SLAB_CACHE_MAGDEFERRED);
  78.  
  79.     md = (md_t*)slab_alloc(md_slab,0);
  80.  
  81.     list_initialize(&md->adj);
  82.     md->base = base;
  83.     md->size = size;
  84.     md->parent = NULL;
  85.     md->state = MD_FREE;
  86.  
  87.     list_prepend(&md->link, &lheap.unmapped[31]);
  88.     lheap.av_mapped    = 0x00000000;
  89.     lheap.av_unmapped  = 0x80000000;
  90.     sheap.av_mapped    = 0x00000000;
  91.     sheap.av_unmapped  = 0x00000000;
  92.  
  93.     return 1;
  94. };
  95.  
  96. md_t* __fastcall find_large_md(size_t size)
  97. {
  98.     md_t *md = NULL;
  99.  
  100.     count_t idx0;
  101.     u32_t mask;
  102.  
  103.     ASSERT((size & 0x3FFFFF) == 0);
  104.  
  105.     idx0 = (size>>22) - 1 < 32 ? (size>>22) - 1 : 31;
  106.     mask = lheap.av_unmapped & ( -1<<idx0 );
  107.  
  108.     if(mask)
  109.     {
  110.         if(idx0 == 31)
  111.         {
  112.             md_t *tmp = (md_t*)lheap.unmapped[31].next;
  113.             while(&tmp->link != &lheap.unmapped[31])
  114.             {
  115.                 if(tmp->size >= size)
  116.                 {
  117.                     DBG("remove large tmp %x\n", tmp);
  118.  
  119.                     md = tmp;
  120.                     break;
  121.                 };
  122.             };
  123.             tmp = (md_t*)tmp->link.next;
  124.         }
  125.         else
  126.         {
  127.             idx0 = _bsf(mask);
  128.  
  129.             ASSERT( !list_empty(&lheap.unmapped[idx0]))
  130.  
  131.             md = (md_t*)lheap.unmapped[idx0].next;
  132.         };
  133.     }
  134.     else
  135.         return NULL;
  136.  
  137.     ASSERT(md->state == MD_FREE);
  138.  
  139.     list_remove((link_t*)md);
  140.     if(list_empty(&lheap.unmapped[idx0]))
  141.         _reset_lavu(idx0);
  142.  
  143.     if(md->size > size)
  144.     {
  145.         count_t idx1;
  146.         md_t *new_md = (md_t*)slab_alloc(md_slab,0);         /* FIXME check */
  147.  
  148.         link_initialize(&new_md->link);
  149.         list_insert(&new_md->adj, &md->adj);
  150.  
  151.         new_md->base   = md->base;
  152.         new_md->size   = size;
  153.         new_md->parent = NULL;
  154.         new_md->state  = MD_USED;
  155.  
  156.         md->base+= size;
  157.         md->size-= size;
  158.  
  159.         idx1 = (md->size>>22) - 1 < 32 ? (md->size>>22) - 1 : 31;
  160.  
  161.         list_prepend(&md->link, &lheap.unmapped[idx1]);
  162.         _set_lavu(idx1);
  163.  
  164.         return new_md;
  165.     };
  166.     md->state = MD_USED;
  167.  
  168.     return md;
  169. }
  170.  
  171. md_t* __fastcall find_unmapped_md(size_t size)
  172. {
  173.     eflags_t efl;
  174.  
  175.     md_t *md = NULL;
  176.  
  177.     count_t idx0;
  178.     u32_t mask;
  179.  
  180.     ASSERT((size & 0xFFF) == 0);
  181.  
  182.     efl = safe_cli();
  183.  
  184.     idx0 = (size>>12) - 1 < 32 ? (size>>12) - 1 : 31;
  185.     mask = sheap.av_unmapped & ( -1<<idx0 );
  186.  
  187.     DBG("smask %x size %x idx0 %x mask %x\n",sheap.av_unmapped, size, idx0, mask);
  188.  
  189.     if(mask)
  190.     {
  191.         if(idx0 == 31)
  192.         {
  193.             ASSERT( !list_empty(&sheap.unmapped[31]));
  194.  
  195.             md_t *tmp = (md_t*)sheap.unmapped[31].next;
  196.             while( &tmp->link != &sheap.unmapped[31])
  197.             {
  198.                 if(tmp->size >= size)
  199.                 {
  200.                     md = tmp;
  201.                     break;
  202.                 };
  203.                 tmp = (md_t*)tmp->link.next;
  204.             };
  205.         }
  206.         else
  207.         {
  208.             idx0 = _bsf(mask);
  209.  
  210.             ASSERT( !list_empty(&sheap.unmapped[idx0]));
  211.  
  212.             md = (md_t*)sheap.unmapped[idx0].next;
  213.         }
  214.     };
  215.  
  216.     if(md)
  217.     {
  218.         DBG("remove md %x\n", md);
  219.  
  220.         ASSERT(md->state==MD_FREE);
  221.         ASSERT(md->parent != NULL);
  222.  
  223.         list_remove((link_t*)md);
  224.         if(list_empty(&sheap.unmapped[idx0]))
  225.             _reset_savu(idx0);
  226.     }
  227.     else
  228.     {
  229.         md_t *lmd;
  230.         lmd = find_large_md((size+0x3FFFFF)&~0x3FFFFF);
  231.  
  232.         DBG("get large md %x\n", lmd);
  233.  
  234.         if( !lmd)
  235.         {
  236.             safe_sti(efl);
  237.             return NULL;
  238.         };
  239.  
  240.         ASSERT(lmd->size != 0);
  241.         ASSERT(lmd->base != 0);
  242.         ASSERT((lmd->base & 0x3FFFFF) == 0);
  243.         ASSERT(lmd->parent == NULL);
  244.  
  245.         md = (md_t*)slab_alloc(md_slab,0);    /* FIXME check */
  246.  
  247.         link_initialize(&md->link);
  248.         list_initialize(&md->adj);
  249.         md->base = lmd->base;
  250.         md->size = lmd->size;
  251.         md->parent  = lmd;
  252.         md->state = MD_USED;
  253.     };
  254.  
  255.     if(md->size > size)
  256.     {
  257.         count_t idx1;
  258.         md_t *new_md = (md_t*)slab_alloc(md_slab,0);    /* FIXME check */
  259.  
  260.         link_initialize(&new_md->link);
  261.         list_insert(&new_md->adj, &md->adj);
  262.  
  263.         new_md->base = md->base;
  264.         new_md->size = size;
  265.         new_md->parent = md->parent;
  266.         new_md->state = MD_USED;
  267.  
  268.         md->base+= size;
  269.         md->size-= size;
  270.         md->state = MD_FREE;
  271.  
  272.         idx1 = (md->size>>12) - 1 < 32 ? (md->size>>12) - 1 : 31;
  273.  
  274.         DBG("insert md %x, base %x size %x idx %x\n", md,md->base, md->size,idx1);
  275.  
  276.         if( idx1 < 31)
  277.           list_prepend(&md->link, &sheap.unmapped[idx1]);
  278.         else
  279.         {
  280.             if( list_empty(&sheap.unmapped[31]))
  281.                 list_prepend(&md->link, &sheap.unmapped[31]);
  282.             else
  283.             {
  284.                 md_t *tmp = (md_t*)sheap.unmapped[31].next;
  285.  
  286.                 while( &tmp->link != &sheap.unmapped[31])
  287.                 {
  288.                     if(md->base < tmp->base)
  289.                         break;
  290.                     tmp = (md_t*)tmp->link.next;
  291.                 }
  292.                 list_insert(&md->link, &tmp->link);
  293.             };
  294.         };
  295.  
  296.         _set_savu(idx1);
  297.  
  298.         safe_sti(efl);
  299.  
  300.         return new_md;
  301.     };
  302.  
  303.     md->state = MD_USED;
  304.  
  305.     safe_sti(efl);
  306.  
  307.     return md;
  308. }
  309.  
  310. md_t* __fastcall find_mapped_md(size_t size)
  311. {
  312.     eflags_t efl;
  313.  
  314.     md_t *md = NULL;
  315.  
  316.     count_t idx0;
  317.     u32_t mask;
  318.  
  319.     ASSERT((size & 0xFFF) == 0);
  320.  
  321.     efl = safe_cli();
  322.  
  323.     idx0 = (size>>12) - 1 < 32 ? (size>>12) - 1 : 31;
  324.     mask = sheap.av_mapped & ( -1<<idx0 );
  325.  
  326.     DBG("small av_mapped %x size %x idx0 %x mask %x\n",sheap.av_mapped, size,
  327.          idx0, mask);
  328.  
  329.     if(mask)
  330.     {
  331.         if(idx0 == 31)
  332.         {
  333.             ASSERT( !list_empty(&sheap.mapped[31]));
  334.  
  335.             md_t *tmp = (md_t*)sheap.mapped[31].next;
  336.             while( &tmp->link != &sheap.mapped[31])
  337.             {
  338.                 if(tmp->size >= size)
  339.                 {
  340.                     md = tmp;
  341.                     break;
  342.                 };
  343.                 tmp = (md_t*)tmp->link.next;
  344.             };
  345.         }
  346.         else
  347.         {
  348.             idx0 = _bsf(mask);
  349.  
  350.             ASSERT( !list_empty(&sheap.mapped[idx0]));
  351.  
  352.             md = (md_t*)sheap.mapped[idx0].next;
  353.         }
  354.     };
  355.  
  356.     if(md)
  357.     {
  358.         DBG("remove md %x\n", md);
  359.  
  360.         ASSERT(md->state==MD_FREE);
  361.  
  362.         list_remove((link_t*)md);
  363.         if(list_empty(&sheap.mapped[idx0]))
  364.             _reset_savm(idx0);
  365.     }
  366.     else
  367.     {
  368.         md_t    *lmd;
  369.         addr_t  frame;
  370.         addr_t  *pte;
  371.         int i;
  372.  
  373.         lmd = find_large_md((size+0x3FFFFF)&~0x3FFFFF);
  374.  
  375.         DBG("get large md %x\n", lmd);
  376.  
  377.         if( !lmd)
  378.         {
  379.             safe_sti(efl);
  380.             return NULL;
  381.         };
  382.  
  383.         ASSERT(lmd->size != 0);
  384.         ASSERT(lmd->base != 0);
  385.         ASSERT((lmd->base & 0x3FFFFF) == 0);
  386.         ASSERT(lmd->parent == NULL);
  387.  
  388.         frame = core_alloc(10);                        /* FIXME check */
  389.  
  390.         lmd->parent = (void*)frame;
  391.  
  392.         pte = &((addr_t*)page_tabs)[lmd->base>>12];    /* FIXME remove */
  393.  
  394.         for(i = 0; i<1024; i++)
  395.         {
  396.            *pte++ = frame;
  397.            frame+= 4096;
  398.         }
  399.  
  400.         md = (md_t*)slab_alloc(md_slab,0);             /* FIXME check */
  401.  
  402.         link_initialize(&md->link);
  403.         list_initialize(&md->adj);
  404.         md->base = lmd->base;
  405.         md->size = lmd->size;
  406.         md->parent  = lmd;
  407.         md->state = MD_USED;
  408.     };
  409.  
  410.     if(md->size > size)
  411.     {
  412.         count_t idx1;
  413.         md_t *new_md = (md_t*)slab_alloc(md_slab,0);    /* FIXME check */
  414.  
  415.         link_initialize(&new_md->link);
  416.         list_insert(&new_md->adj, &md->adj);
  417.  
  418.         new_md->base = md->base;
  419.         new_md->size = size;
  420.         new_md->parent = md->parent;
  421.  
  422.         md->base+= size;
  423.         md->size-= size;
  424.         md->state = MD_FREE;
  425.  
  426.         idx1 = (md->size>>12) - 1 < 32 ? (md->size>>12) - 1 : 31;
  427.  
  428.         DBG("insert md %x, base %x size %x idx %x\n", md,md->base, md->size,idx1);
  429.  
  430.         if( idx1 < 31)
  431.           list_prepend(&md->link, &sheap.mapped[idx1]);
  432.         else
  433.         {
  434.             if( list_empty(&sheap.mapped[31]))
  435.                 list_prepend(&md->link, &sheap.mapped[31]);
  436.             else
  437.             {
  438.                 md_t *tmp = (md_t*)sheap.mapped[31].next;
  439.  
  440.                 while( &tmp->link != &sheap.mapped[31])
  441.                 {
  442.                     if(md->base < tmp->base)
  443.                         break;
  444.                     tmp = (md_t*)tmp->link.next;
  445.                 }
  446.                 list_insert(&md->link, &tmp->link);
  447.             };
  448.         };
  449.  
  450.         _set_savm(idx1);
  451.  
  452.         md = new_md;
  453.     };
  454.  
  455.     md->state = MD_USED;
  456.  
  457.     safe_sti(efl);
  458.  
  459.     return md;
  460. }
  461.  
  462. void __fastcall free_unmapped_md(md_t *md)
  463. {
  464.     eflags_t  efl ;
  465.     md_t     *fd;
  466.     md_t     *bk;
  467.     count_t   idx;
  468.  
  469.     ASSERT(md->parent != NULL);
  470.  
  471.     efl = safe_cli();
  472.     spinlock_lock(&sheap.lock);
  473.  
  474.     if( !list_empty(&md->adj))
  475.     {
  476.         bk = (md_t*)md->adj.prev;
  477.         fd = (md_t*)md->adj.next;
  478.  
  479.         if(fd->state == MD_FREE)
  480.         {
  481.             idx = (fd->size>>12) - 1 < 32 ? (fd->size>>12) - 1 : 31;
  482.  
  483.             list_remove((link_t*)fd);
  484.             if(list_empty(&sheap.unmapped[idx]))
  485.                 _reset_savu(idx);
  486.  
  487.             md->size+= fd->size;
  488.             md->adj.next = fd->adj.next;
  489.             md->adj.next->prev = (link_t*)md;
  490.             slab_free(md_slab, fd);
  491.         };
  492.         if(bk->state == MD_FREE)
  493.         {
  494.             idx = (bk->size>>12) - 1 < 32 ? (bk->size>>12) - 1 : 31;
  495.  
  496.             list_remove((link_t*)bk);
  497.             if(list_empty(&sheap.unmapped[idx]))
  498.                 _reset_savu(idx);
  499.  
  500.             bk->size+= md->size;
  501.             bk->adj.next = md->adj.next;
  502.             bk->adj.next->prev = (link_t*)bk;
  503.             slab_free(md_slab, md);
  504.             md = fd;
  505.         };
  506.     };
  507.  
  508.     md->state = MD_FREE;
  509.  
  510.     idx = (md->size>>12) - 1 < 32 ? (md->size>>12) - 1 : 31;
  511.  
  512.     _set_savu(idx);
  513.  
  514.     if( idx < 31)
  515.         list_prepend(&md->link, &sheap.unmapped[idx]);
  516.     else
  517.     {
  518.         if( list_empty(&sheap.unmapped[31]))
  519.             list_prepend(&md->link, &sheap.unmapped[31]);
  520.         else
  521.         {
  522.             md_t *tmp = (md_t*)sheap.unmapped[31].next;
  523.  
  524.             while( &tmp->link != &sheap.unmapped[31])
  525.             {
  526.                 if(md->base < tmp->base)
  527.                     break;
  528.                 tmp = (md_t*)tmp->link.next;
  529.             }
  530.             list_insert(&md->link, &tmp->link);
  531.         };
  532.     };
  533.     spinlock_unlock(&sheap.lock);
  534.     safe_sti(efl);
  535.  
  536. };
  537.  
  538. void __fastcall free_mapped_md(md_t *md)
  539. {
  540.     eflags_t  efl ;
  541.     md_t     *fd;
  542.     md_t     *bk;
  543.     count_t   idx;
  544.  
  545.     ASSERT(md->parent != NULL);
  546.     ASSERT( ((md_t*)(md->parent))->parent != NULL);
  547.  
  548.     efl = safe_cli();
  549.     spinlock_lock(&sheap.lock);
  550.  
  551.     if( !list_empty(&md->adj))
  552.     {
  553.         bk = (md_t*)md->adj.prev;
  554.         fd = (md_t*)md->adj.next;
  555.  
  556.         if(fd->state == MD_FREE)
  557.         {
  558.             idx = (fd->size>>12) - 1 < 32 ? (fd->size>>12) - 1 : 31;
  559.  
  560.             list_remove((link_t*)fd);
  561.             if(list_empty(&sheap.mapped[idx]))
  562.                 _reset_savm(idx);
  563.  
  564.             md->size+= fd->size;
  565.             md->adj.next = fd->adj.next;
  566.             md->adj.next->prev = (link_t*)md;
  567.             slab_free(md_slab, fd);
  568.         };
  569.         if(bk->state == MD_FREE)
  570.         {
  571.             idx = (bk->size>>12) - 1 < 32 ? (bk->size>>12) - 1 : 31;
  572.  
  573.             list_remove((link_t*)bk);
  574.             if(list_empty(&sheap.mapped[idx]))
  575.                 _reset_savm(idx);
  576.  
  577.             bk->size+= md->size;
  578.             bk->adj.next = md->adj.next;
  579.             bk->adj.next->prev = (link_t*)bk;
  580.             slab_free(md_slab, md);
  581.             md = fd;
  582.         };
  583.     };
  584.  
  585.     md->state = MD_FREE;
  586.  
  587.     idx = (md->size>>12) - 1 < 32 ? (md->size>>12) - 1 : 31;
  588.  
  589.     _set_savm(idx);
  590.  
  591.     if( idx < 31)
  592.         list_prepend(&md->link, &sheap.mapped[idx]);
  593.     else
  594.     {
  595.         if( list_empty(&sheap.mapped[31]))
  596.             list_prepend(&md->link, &sheap.mapped[31]);
  597.         else
  598.         {
  599.             md_t *tmp = (md_t*)sheap.mapped[31].next;
  600.  
  601.             while( &tmp->link != &sheap.mapped[31])
  602.             {
  603.                 if(md->base < tmp->base)
  604.                     break;
  605.                 tmp = (md_t*)tmp->link.next;
  606.             }
  607.             list_insert(&md->link, &tmp->link);
  608.         };
  609.     };
  610.     spinlock_unlock(&sheap.lock);
  611.     safe_sti(efl);
  612. };
  613.  
  614.  
  615. md_t* __fastcall  md_alloc(size_t size, u32_t flags)
  616. {
  617.     eflags_t efl;
  618.  
  619.     md_t *md;
  620.  
  621.     size = (size+4095)&~4095;
  622.  
  623.     if( flags & PG_MAP )
  624.     {
  625.         md = find_mapped_md(size);
  626.  
  627.         if( !md )
  628.             return NULL;
  629.  
  630.         ASSERT(md->state == MD_USED);
  631.         ASSERT(md->parent != NULL);
  632.  
  633.         md_t *lmd = (md_t*)md->parent;
  634.  
  635.         ASSERT( lmd != NULL);
  636.         ASSERT( lmd->parent != NULL);
  637.  
  638.         addr_t  frame  = (md->base - lmd->base + (addr_t)lmd->parent)|
  639.                          (flags & 0xFFF);
  640.         DBG("frame %x\n", frame);
  641.         ASSERT(frame != 0);
  642.  
  643.         count_t  tmp = size >> 12;
  644.         addr_t  *pte = &((addr_t*)page_tabs)[md->base>>12];
  645.  
  646.         while(tmp--)
  647.         {
  648.             *pte++ = frame;
  649.             frame+= 4096;
  650.         };
  651.     }
  652.     else
  653.     {
  654.         md = find_unmapped_md(size);
  655.         if( !md )
  656.             return NULL;
  657.  
  658.         ASSERT(md->parent != NULL);
  659.         ASSERT(md->state == MD_USED);
  660.     }
  661.  
  662.     return md;
  663. };
  664.  
  665.  
  666. void __fastcall md_free(md_t *md)
  667. {
  668.  
  669.     if( md )
  670.     {
  671.         md_t *lmd;
  672.  
  673.         DBG("free md: %x base: %x size: %x\n",md, md->base, md->size);
  674.  
  675.         ASSERT(md->state == MD_USED);
  676.  
  677.         list_remove((link_t*)md);
  678.  
  679.         lmd = (md_t*)md->parent;
  680.  
  681.         ASSERT(lmd != 0);
  682.  
  683.         if(lmd->parent != 0)
  684.         {
  685.             addr_t   mem = md->base;
  686.             addr_t  *pte = &((addr_t*)page_tabs)[md->base>>12];
  687.             count_t  tmp  = md->size >> 12;
  688.  
  689.             while(tmp--)
  690.             {
  691.                 *pte++ = 0;
  692.                 asm volatile ( "invlpg (%0)" ::"r" (mem) );
  693.                 mem+= 4096;
  694.             };
  695.             free_mapped_md( md );
  696.         }
  697.         else
  698.             free_unmapped_md( md );
  699.     }
  700.  
  701.     return;
  702. };
  703.  
  704. void * __fastcall mem_alloc(size_t size, u32_t flags)
  705. {
  706.     eflags_t efl;
  707.  
  708.     md_t *md;
  709.  
  710.     DBG("\nmem_alloc: %x bytes\n", size);
  711.  
  712.     ASSERT(size != 0);
  713.  
  714.     md = md_alloc(size, flags);
  715.  
  716.     if( !md )
  717.         return NULL;
  718.  
  719.     efl = safe_cli();
  720.     spinlock_lock(&sheap.lock);
  721.  
  722.     if( list_empty(&sheap.used) )
  723.         list_prepend(&md->link, &sheap.used);
  724.     else
  725.     {
  726.         md_t *tmp = (md_t*)sheap.used.next;
  727.  
  728.         while( &tmp->link != &sheap.used)
  729.         {
  730.             if(md->base < tmp->base)
  731.                 break;
  732.             tmp = (md_t*)tmp->link.next;
  733.         }
  734.         list_insert(&md->link, &tmp->link);
  735.     };
  736.  
  737.     spinlock_unlock(&sheap.lock);
  738.     safe_sti(efl);
  739.  
  740.     DBG("allocate: %x size %x\n\n",md->base, size);
  741.     return (void*)md->base;
  742. };
  743.  
  744. void __fastcall mem_free(void *mem)
  745. {
  746.     eflags_t efl;
  747.  
  748.     md_t *tmp;
  749.     md_t *md = NULL;
  750.  
  751.     DBG("mem_free: %x\n",mem);
  752.  
  753.     ASSERT( mem != 0 );
  754.     ASSERT( ((addr_t)mem & 0xFFF) == 0 );
  755.     ASSERT( ! list_empty(&sheap.used));
  756.  
  757.     efl = safe_cli();
  758.  
  759.     tmp = (md_t*)sheap.used.next;
  760.  
  761.     while( &tmp->link != &sheap.used)
  762.     {
  763.         if( tmp->base == (addr_t)mem )
  764.         {
  765.             md = tmp;
  766.             break;
  767.         };
  768.         tmp = (md_t*)tmp->link.next;
  769.     }
  770.  
  771.     if( md )
  772.     {
  773.         md_free( md );
  774.  
  775.     }
  776.     else
  777.         DBG("\tERROR: invalid base address: %x\n", mem);
  778.  
  779.     safe_sti(efl);
  780. };
  781.