Subversion Repositories Kolibri OS

Rev

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