Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

kmalloc.c

Go to the documentation of this file.
00001 /*!     \file kernel/kmalloc.c
00002  *      \brief Memory Allocator.
00003  *      \author Andrea Righi <drizzt@inwind.it>
00004  *      \date Last update: 2004-01-01
00005  *      \note Copyright (&copy;) 2003 Andrea Righi
00006  */
00007 
00008 #include <const.h>
00009 
00010 #include <arch/i386.h>
00011 #include <arch/mem.h>
00012 #include <arch/paging.h>
00013 
00014 #include <kernel/console.h>
00015 #include <kernel/kernel_map.h>
00016 #include <kernel/keyboard.h>
00017 #include <kernel/task.h>
00018 
00019 #include <kernel/kmalloc.h>
00020 
00021 //! \brief Initialize the kernel virtual memory area.
00022 void kmalloc_init()
00023 {
00024         mem_block_t *p;
00025 
00026         // Create only one hudge block                                  //
00027         p = (mem_block_t *)K_HEAP_START;
00028         p->magic = M_MAGIC;
00029         p->flags = M_FREE;
00030         p->size = K_HEAP_END - K_HEAP_START - sizeof(mem_block_t);
00031         p->owner = NULL;
00032 }
00033 
00034 //! \brief
00035 //!     Allocate a memory block from the kernel memory area.
00036 //!     This is a best-fit like allocator.
00037 //! \param size The size of the block you want to allocate.
00038 //! \exception NULL Out-of-memory.
00039 //! \return A pointer to a memory area.
00040 //! \note The memory area is not initialized when it's just allocated.
00041 
00042 // NOTE!!! IF YOU WANT TO USE A FIRST-FIT LIKE ALLOCATOR FOR THE KERNEL //
00043 // MEMORY AREA, YOU MUST CHANGE THE kmalloc(size_t size) FUNCTION WITH  //
00044 // THIS ONE AND RECOMPILE THE KERNEL.
00045 void *kmalloc(size_t size)
00046 {
00047         mem_block_t *p, *p_best=NULL;
00048         dword IF = GET_IF();
00049 
00050         if (!size) return NULL; // Is the process crazy?! :-) //
00051 
00052         disable();
00053 
00054         // Round the size up to sizeof(mem_block_t); the        //
00055         // sizeof(mem_block_t) is the unit of allocation.       //
00056         size = ( size & -((uint32_t)sizeof(mem_block_t)) ) + sizeof(mem_block_t);
00057 
00058         // Explore the heap for the best-fit hole //
00059         p=(mem_block_t *)K_HEAP_START;
00060         while(p < (mem_block_t *)K_HEAP_END)
00061         {
00062                 // Find a free block //
00063                 if (p->flags == M_FREE)
00064                 {
00065                         // This block is free... let's proceed //
00066                         if (p->size == size)
00067                         {
00068                                 // Best fit block found! You're lucky! //
00069                                 p_best = p;
00070                                 break;
00071                         }
00072                         if (p->size > size)
00073                         {
00074                                 // The hole is bigger than size...      //
00075                                 // ...check if it's the best-fit hole!  //
00076                                 if (p_best==NULL)
00077                                         p_best = p;
00078                                 else
00079                                         if (p_best->size > p->size)
00080                                                 p_best = p;
00081                         }
00082                 }
00083                 // Examine the next memory block //
00084                 p = (void *)p+p->size+sizeof(mem_block_t);
00085         }
00086 
00087         // Have you found a free block?! //
00088         if (p_best == NULL)
00089         {
00090                 // No free memory :( //
00091                 SET_IF(IF);
00092                 return NULL;
00093         }
00094 
00095         // Found, now allocate it! //
00096         p_best->magic = M_MAGIC;
00097         p_best->flags = M_ALLOC;
00098         p_best->owner = get_pid();
00099 
00100         if (p_best->size == size)
00101         {
00102                 p_best = (void *)p_best + sizeof(mem_block_t);
00103                 SET_IF(IF);
00104                 // The block cover the size perfectly //
00105                 return ((void *)p_best);
00106         }
00107 
00108         // Otherwise split the hole in two blocks //
00109         p = (void *)p_best + sizeof(mem_block_t) + size;
00110         p->magic = M_MAGIC;
00111         p->flags = M_FREE;
00112         p->size = p_best->size - size - sizeof(mem_block_t);
00113         p->owner = NULL;
00114 
00115         p_best->size = size;
00116         p_best = (void *)p_best + sizeof(mem_block_t);
00117 
00118         SET_IF(IF);
00119         // Return the best-fit pointer //
00120         return ((void *)p_best);
00121 }
00122 
00123 /*
00124 //! \brief
00125 //!     Allocate a memory block from the kernel memory area.
00126 //!     This is a first-fit like allocator.
00127 //! \param size The size of the block you want to allocate.
00128 //! \exception NULL Out-of-memory.
00129 //! \return A pointer to a memory area.
00130 //! \note The memory area is not initialized when it's just allocated.
00131 
00132 // NOTE!!! IF YOU WANT TO USE A FIRST-FIT LIKE ALLOCATOR FOR THE KERNEL //
00133 // MEMORY AREA, YOU MUST CHANGE THE kmalloc(size_t size) FUNCTION WITH  //
00134 // THIS ONE AND RECOMPILE THE KERNEL.
00135 void *kmalloc(size_t size)
00136 {
00137 // This is a first-fit allocator for the kernel memory area.            //
00138 // This function allocates size bytes and returns a pointer to the      //
00139 // allocated memory. The memory is not cleaned.                         //
00140 
00141         mem_block_t *p, *p2;
00142         dword IF = GET_IF();
00143 
00144         if (!size) return NULL; // Is the process crazy?! :-)           //
00145 
00146         // Round the size up to sizeof(mem_block_t); the                //
00147         // sizeof(mem_block_t) is the unit of allocation.               //
00148         size = ( size & -((uint32_t)sizeof(mem_block_t)) ) + sizeof(mem_block_t);
00149 
00150         disable();
00151 
00152         // Let's start!                                                 //
00153         p = (mem_block_t *)K_HEAP_START;
00154         while(p < (mem_block_t *)K_HEAP_END)
00155         {
00156                 if (p->flags == M_FREE)
00157                 {
00158                         // We found a free block, now allocate it!      //
00159                         p->magic = M_MAGIC;
00160                         p->flags = M_ALLOC;
00161                         p->owner = get_pid();
00162 
00163                         if (p->size == size)
00164                         {
00165                                 // The block cover the size perfectly,  //
00166                                 // splitting is not required            //
00167                                 p = (void *)p + sizeof(mem_block_t);
00168 
00169                                 SET_IF(IF);
00170 
00171                                 // Return the pointer                   //
00172                                 return ((void *)p);
00173                         }
00174 
00175                         // Otherwise split the hole in two blocks       //
00176                         p2 = (void *)p + sizeof(mem_block_t) + size;
00177                         p2->magic = M_MAGIC;
00178                         p2->flags = M_FREE;
00179                         p2->size = p->size - size - sizeof(mem_block_t);
00180                         p2->owner = NULL;
00181 
00182                         p->size = size;
00183                         p = (void *)p + sizeof(mem_block_t);
00184 
00185                         SET_IF(IF);
00186 
00187                         // Return the pointer                           //
00188                         return ((void *)p);
00189                 }
00190 
00191                 // Examine the next memory block                        //
00192                 p = (void *)p + p->size + sizeof(mem_block_t);
00193         }
00194 
00195         // Out of memory! Return 0...                                   //
00196         return(0);
00197 }
00198 */
00199 
00200 //! \brief Try to release physical frames occupied by the freed block.
00201 //! \param ptr The pointer to deallocate.
00202 static void deallocate(mem_block_t *ptr)
00203 {
00204         dword start = PAGE_ALIGN_UP((dword)((void *)ptr + sizeof(mem_block_t)));
00205         dword end = PAGE_ALIGN((dword)((void *)ptr + sizeof(mem_block_t) + ptr->size));
00206 
00207         while(start < end)
00208         {
00209                 if (*ADDR_TO_PDE(start) != NULL)
00210                 {
00211                         delete_page(start);
00212                         start += PAGE_SIZE;
00213                 }
00214                 else
00215                         start = PAGE_DIR_ALIGN_UP(start);
00216         }
00217 }
00218 
00219 //! \brief
00220 //!     Frees the memory space pointed by ptr, which must have
00221 //!     been returned by a previous call to kmalloc(size_t size).
00222 //! \param ptr The pointer you want to free.
00223 void kfree(void *ptr)
00224 {
00225         mem_block_t *p, *p2;
00226         dword IF = GET_IF();
00227 
00228         if (ptr == NULL) return;
00229 
00230         disable();
00231 
00232         // Point to the header                                          //
00233         p = (void *)ptr - sizeof(mem_block_t);
00234 
00235         if (p->magic != M_MAGIC) return; // Is the process crazy?! :)   //
00236         if (p->flags != M_ALLOC) return; // Crazy again?! :)            //
00237 
00238         // Free the block                                               //
00239         p->flags = M_FREE;
00240         p->owner = NULL;
00241 
00242         // Try to combine the block wih the next one...                 //
00243         p2 = (void *)p + p->size + sizeof(mem_block_t);
00244 
00245         if (p2 < (mem_block_t *)K_HEAP_END)
00246                 if (p2->flags == M_FREE)
00247                 {
00248                         // Let's merge the two blocks!                  //
00249                         p->size += p2->size + sizeof(mem_block_t);
00250                         p2->magic = NULL;
00251                 }
00252 
00253         // Try to combine the block with the previous one...            //
00254         if (p != (mem_block_t *)K_HEAP_START)
00255         {
00256                 // Find the previous block                              //
00257                 p2 = (void *)K_HEAP_START;
00258                 for(;;)
00259                 {
00260                         if (((void *)p2 + p2->size + sizeof(mem_block_t)) == p)
00261                         {
00262                                 // Block found!                         //
00263                                 // Check if it's a free block           //
00264                                 if (p2->flags == M_FREE)
00265                                 {
00266                                         // Let's merge the two blocks!  //
00267                                         p2->size += (p->size + sizeof(mem_block_t));
00268                                         p->magic = NULL;
00269                                         p = p2;
00270                                 }
00271                                 break;
00272                         }
00273                         p2 = (void *)p2 + p2->size + sizeof(mem_block_t);
00274                 }
00275         }
00276         // Release the physical space occupied by the block             //
00277         deallocate(p);
00278 
00279         SET_IF(IF);
00280 }
00281 
00282 //! \brief
00283 //!     Return the size of the pointer \a ptr passed as argument.
00284 //! \param ptr The pointer you want to know the size.
00285 //! \exception NULL Invalid pointer \a ptr.
00286 //! \return The size of the pointer \a ptr passed as argument.
00287 int mem_sizeof(void *ptr)
00288 {
00289 // Return the size of the pointer "ptr", or NULL if an error occurs     //
00290         mem_block_t *p = ((mem_block_t *)ptr-1);
00291 
00292         if ( (p->magic == M_MAGIC) && (p->flags == M_ALLOC) )
00293                 return( p->size );
00294         else
00295                 return(NULL);
00296 }
00297 
00298 //! \brief Allocate some memory aligned to a boundary.
00299 //! \param alignment The boundary.
00300 //! \param size The size you want to allocate.
00301 //! \exception NULL Out-of-memory.
00302 //! \return
00303 //!     A pointer to a memory area aligned to the boundary.
00304 //!     The pointer is a \c aligned_mem_block_t pointer, so if you
00305 //!     want to access to the data area of this pointer you must
00306 //!     specify the \c p->start filed.
00307 //! \note Use kfree(void *ptr) to free the allocated block.
00308 void *kmemalign(size_t alignment, size_t size)
00309 {
00310         mem_block_t *p, *p2;
00311         dword IF = GET_IF();
00312 
00313         // Cannot allocate memory with a size of zero                   //
00314         if ( !size )
00315                 return(NULL);
00316 
00317         // Allocate the pointer                                         //
00318         p = kmalloc(size + alignment + 2*sizeof(mem_block_t));
00319         if ( p == NULL )
00320                 return(NULL);
00321 
00322         // An alignment of zero is intended as a simple kmalloc(size)   //
00323         if ( alignment == 0 )
00324         {
00325                 return(p);
00326         }
00327 
00328         // Check if the pointer is correcly aligned                     //
00329         if ( (size_t)(p) % alignment )
00330         {
00331                 // Align the pointer p to the boundary.                 //
00332                 disable();
00333 
00334                 // Allocate the new block                               //
00335                 p2 = p + 2;
00336                 p2 = (mem_block_t *)ALIGN_UP((size_t)p2, alignment)  - 1;
00337                 p2->magic = M_MAGIC;
00338                 p2->flags = (p-1)->flags;
00339                 p2->owner = (p-1)->owner;
00340                 p2->size = mem_sizeof(p) - ((size_t)(p2+1) - (size_t)p);
00341 
00342                 // Free the unused space                                //
00343                 (p-1)->size = (size_t)p2 - (size_t)p;
00344                 kfree(p);
00345 
00346                 SET_IF(IF);
00347 
00348                 return(p2+1);
00349         }
00350         else
00351                 // The pointer p is already aligned to the boudary      //
00352                 return(p);
00353 }
00354 
00355 //! \brief This is a routine for debug only.
00356 //! It prints all the memory block headers.
00357 //! \note Prints the result to the current console.
00358 void dump_memory_map()
00359 {
00360         mem_block_t *p = (mem_block_t *)K_HEAP_START;
00361 
00362         for(;;)
00363         {
00364                 kprintf(
00365                         "\n\rp        = %#010x"
00366                         "\n\rp->magic = %s"
00367                         "\n\rp->flags = %#010x"
00368                         "\n\rp->size  = %u"
00369                         "\n\rp->owner = %i\n\r",
00370                         (dword)p + sizeof(mem_block_t),
00371                         (byte *)p->magic,
00372                         p->flags,
00373                         p->size,
00374                         p->owner);
00375 
00376                 p = (void *)p + p->size + sizeof(mem_block_t);
00377 
00378                 if (p >= (mem_block_t *)K_HEAP_END) break;
00379 
00380                 // Wait for a key... //
00381                 if (kgetchar() == CTRL_C) break;
00382         }
00383 }

Generated on Fri Feb 20 15:32:16 2004 for Minirighi by doxygen1.2.18