kmalloc.c

Go to the documentation of this file.
00001 /*****************************************************************************************
00002  Copyright (c) 2002-2004 The UbixOS Project
00003  All rights reserved.
00004 
00005  Redistribution and use in source and binary forms, with or without modification, are
00006  permitted provided that the following conditions are met:
00007 
00008  Redistributions of source code must retain the above copyright notice, this list of
00009  conditions, the following disclaimer and the list of authors.  Redistributions in binary
00010  form must reproduce the above copyright notice, this list of conditions, the following
00011  disclaimer and the list of authors in the documentation and/or other materials provided
00012  with the distribution. Neither the name of the UbixOS Project nor the names of its
00013  contributors may be used to endorse or promote products derived from this software
00014  without specific prior written permission.
00015 
00016  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
00017  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00018  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
00019  THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00020  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00021  OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00022  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
00023  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00024  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00025 
00026  $Id$
00027 
00028 *****************************************************************************************/
00029 
00030 #include <lib/kmalloc.h>
00031 #include <lib/kprintf.h>
00032 #include <ubixos/kpanic.h>
00033 #include <ubixos/sched.h>
00034 #include <ubixos/spinlock.h>
00035 #include <vmm/vmm.h>
00036 #include <string.h>
00037 #include <assert.h>
00038 
00039 /*
00040  Set up three descriptor tables:
00041  
00042  kernDesc      - The inuse descriptor table 
00043  freeKernDesc  - The free descriptor table (descriptors with memory backing just not in use)
00044  emptyKernDesc - The empty descriptor table (descriptors with out a memory backing)
00045  
00046 */
00047 static struct memDescriptor *usedKernDesc  = 0x0;
00048 static struct memDescriptor *freeKernDesc  = 0x0;
00049 static struct memDescriptor *emptyKernDesc = 0x0;
00050 
00051 /*
00052  Set up our spinlocks so we do not corrupt linked lists if we have re-entrancy
00053 */
00054 static spinLock_t mallocSpinLock    = SPIN_LOCK_INITIALIZER;
00055 static spinLock_t emptyDescSpinLock = SPIN_LOCK_INITIALIZER;
00056 
00057 /************************************************************************
00058 
00059 Function: void *getEmptyDesc()
00060 Description: Find An Empty Descriptor
00061 
00062 Notes:
00063 
00064 02/17/03 - Is This Efficient?
00065 
00066 ************************************************************************/    
00067 static void *getEmptyDesc() {
00068   int i = 0x0;
00069   struct memDescriptor *tmpDesc = 0x0;
00070 
00071   spinLock(&emptyDescSpinLock);
00072   
00073   tmpDesc = emptyKernDesc;
00074   
00075   if (tmpDesc != 0x0) {
00076     emptyKernDesc       = tmpDesc->next;
00077     if (emptyKernDesc != 0x0) 
00078       emptyKernDesc->prev = 0x0;
00079       
00080      
00081     tmpDesc->next       = 0x0;
00082     tmpDesc->prev       = 0x0;
00083     spinUnlock(&emptyDescSpinLock);
00084     return(tmpDesc);
00085     }
00086 
00087   if ((emptyKernDesc = (struct memDescriptor *)vmm_getFreeMallocPage(4)) == 0x0)
00088     kpanic("Error: vmmGetFreeKernelPage returned NULL\n");
00089     
00090   /* zero out the memory so we know there is no garbage */
00091   memset(emptyKernDesc,0x0,0x4000);
00092 
00093   emptyKernDesc[0].next = &emptyKernDesc[1];
00094 
00095   for (i = 0x1;i < ((0x4000/sizeof(struct memDescriptor)));i++) {
00096     if (i+1 < (0x4000/sizeof(struct memDescriptor)))
00097       emptyKernDesc[i].next = &emptyKernDesc[i+1];
00098     else
00099       emptyKernDesc[i].next = 0x0;
00100     emptyKernDesc[i].prev = &emptyKernDesc[i-1];
00101     }
00102 
00103   tmpDesc = &emptyKernDesc[0];
00104 
00105   emptyKernDesc       = tmpDesc->next;
00106   emptyKernDesc->prev = 0x0;
00107   tmpDesc->next       = 0x0;
00108   tmpDesc->prev       = 0x0;
00109   spinUnlock(&emptyDescSpinLock);
00110   return(tmpDesc);
00111   }
00112 
00113 /************************************************************************
00114 
00115 Function: void insertFreeDesc(struct memDescriptor *freeDesc)
00116 Description: This Function Inserts A Free Descriptor On The List Which Is
00117              Kept In Size Order
00118 
00119 Notes:
00120 
00121 02/17/03 - This Was Inspired By TCA's Great Wisdom -
00122            "[20:20:59] <TCA> You should just insert it in order"
00123 
00124 ************************************************************************/
00125 static int insertFreeDesc(struct memDescriptor *freeDesc) {
00126   struct memDescriptor *tmpDesc = 0x0;
00127   assert(freeDesc);
00128   
00129   if (freeDesc->limit <= 0x0)
00130     kpanic("Inserting Descriptor with no limit\n");
00131   
00132   if (freeKernDesc != 0x0) {
00133  
00134     #if 0
00135     freeDesc->next = freeKernDesc;
00136     freeDesc->prev = 0x0;
00137     freeKernDesc->prev = freeDesc;
00138     freeKernDesc = freeDesc;
00139     #endif 
00140     
00141     for (tmpDesc = freeKernDesc;tmpDesc != 0x0;tmpDesc = tmpDesc->next) {
00142       if (freeDesc->limit <= tmpDesc->limit) {
00143       
00144         freeDesc->prev = tmpDesc->prev;
00145         if (tmpDesc->prev != 0x0)
00146           tmpDesc->prev->next = freeDesc;
00147 
00148         
00149         tmpDesc->prev  = freeDesc;
00150         freeDesc->next = tmpDesc;
00151         
00152         if (tmpDesc == freeKernDesc)
00153           freeKernDesc = freeDesc;
00154         return(0x0);
00155         }
00156        if (tmpDesc->next == 0x0) {
00157          tmpDesc->next = freeDesc;
00158          freeDesc->prev = tmpDesc;
00159          freeDesc->next = 0x0;
00160          return(0x0);
00161          }
00162       }
00163     kpanic("didnt Insert\n");
00164     return(0x0);
00165     }
00166   else {
00167     freeDesc->prev = 0x0;
00168     freeDesc->next = 0x0;
00169     freeKernDesc = freeDesc;
00170     return(0x0);
00171     }
00172 
00173   return(0x1);
00174   }
00175 
00176 /************************************************************************
00177 
00178 Function: void mergeMemBlocks()
00179 Description: This Function Will Merge Free Blocks And Free Pages
00180 
00181 Notes:
00182 
00183 03/05/03 - We Have A Problem It Seems The First Block Is Limit 0x0
00184 
00185 ************************************************************************/
00186 static void mergeMemBlocks() {
00187   struct memDescriptor *tmpDesc1 = 0x0;
00188   struct memDescriptor *tmpDesc2 = 0x0;
00189   uInt32               baseAddr  = 0x0;
00190 
00191   return;
00192 
00193   //Loop The Free Descriptors See If We Can Merge Them
00194   mergeStart:
00195   for (tmpDesc1=freeKernDesc;tmpDesc1 != 0x0;tmpDesc1=tmpDesc1->next) {
00196     /*
00197      Compare The Base Addr With The Other Descriptors If You Find The One
00198      That You Are Looking For Lets Merge Them
00199     */
00200     if (tmpDesc1->limit != 0x0) {
00201       baseAddr = (uInt32)tmpDesc1->baseAddr + (uInt32)tmpDesc1->limit;
00202       for (tmpDesc2=freeKernDesc;tmpDesc2;tmpDesc2=tmpDesc2->next) {
00203         if ((uInt32)tmpDesc2->baseAddr == baseAddr) {
00204           tmpDesc1->limit += tmpDesc2->limit;
00205           tmpDesc2->baseAddr = 0x0;
00206           tmpDesc2->limit    = 0x0;
00207           if (tmpDesc2->prev) {
00208             tmpDesc2->prev->next = tmpDesc2->next;
00209             }
00210           if (tmpDesc2->next) {
00211             tmpDesc2->next->prev = tmpDesc2->prev;
00212             }
00213           tmpDesc2->prev      = 0x0;
00214           tmpDesc2->next      = emptyKernDesc;
00215           emptyKernDesc->prev = tmpDesc2;
00216           emptyKernDesc       = tmpDesc2;
00217           if (tmpDesc1->prev) {
00218             tmpDesc1->prev->next = tmpDesc1->next;
00219             }
00220           if (tmpDesc1->next) {
00221             tmpDesc1->next->prev = tmpDesc1->prev;
00222             }
00223           tmpDesc1->prev = 0x0;
00224           tmpDesc1->next = 0x0;
00225           kprintf("mergememBlocks: [%i]\n",tmpDesc1->limit);
00226           insertFreeDesc(tmpDesc1);
00227           //tmpDesc1 = freeKernDesc;
00228           goto mergeStart;
00229           break;
00230           }
00231         }
00232       }
00233     }
00234   return;
00235   }
00236 
00237 
00238 /************************************************************************
00239 
00240 Function: void *kmalloc(uInt32 len)
00241 Description: Allocate Kernel Memory
00242 
00243 Notes:
00244 
00245 02/17/03 - Do I Still Need To Pass In The Pid?
00246 
00247 ************************************************************************/    
00248 void *kmalloc(uInt32 len) {
00249   struct memDescriptor *tmpDesc1 = 0x0;
00250   struct memDescriptor *tmpDesc2 = 0x0;
00251   char                 *buf      = 0x0;
00252   int                   i        = 0x0;
00253   uInt16                pages    = 0x0;
00254 
00255   spinLock(&mallocSpinLock);
00256   
00257   len = MALLOC_ALIGN(len);
00258   
00259   if (len == 0x0) {
00260     spinUnlock(&mallocSpinLock);
00261         kprintf("kmalloc: len = 0!\n");
00262     return(0x0);
00263     }
00264   for (tmpDesc1 = freeKernDesc;tmpDesc1 != 0x0;tmpDesc1=tmpDesc1->next) {
00265     assert(tmpDesc1);
00266     if (tmpDesc1->limit >= len) {
00267       if (tmpDesc1->prev != 0x0)
00268         tmpDesc1->prev->next = tmpDesc1->next;
00269       if (tmpDesc1->next != 0x0)
00270         tmpDesc1->next->prev = tmpDesc1->prev;
00271 
00272       if (tmpDesc1 == freeKernDesc)
00273         freeKernDesc = tmpDesc1->next;
00274 
00275       tmpDesc1->prev = 0x0;
00276       tmpDesc1->next = usedKernDesc;
00277       if (usedKernDesc != 0x0)
00278         usedKernDesc->prev = tmpDesc1;
00279       usedKernDesc = tmpDesc1; 
00280       if (tmpDesc1->limit > len) {
00281         tmpDesc2 = getEmptyDesc();
00282         assert(tmpDesc2);
00283         tmpDesc2->limit = tmpDesc1->limit - len;
00284         tmpDesc1->limit = len;
00285         tmpDesc2->baseAddr = tmpDesc1->baseAddr + len;
00286         tmpDesc2->next = 0x0;
00287         tmpDesc2->prev = 0x0;
00288         insertFreeDesc(tmpDesc2);
00289         }
00290       buf = (char *)tmpDesc1->baseAddr;
00291       for (i=0;i<tmpDesc1->limit;i++) {
00292         (char)buf[i] = (char)0x0;
00293         }
00294       spinUnlock(&mallocSpinLock);
00295       //kprintf("m1[%i:%i:0x%X]",tmpDesc1->limit,len,tmpDesc1->baseAddr);
00296         assert(tmpDesc1->baseAddr);
00297       return(tmpDesc1->baseAddr);
00298       }
00299     }
00300   tmpDesc1 = getEmptyDesc();
00301   //kprintf("no empty desc\n");
00302   if (tmpDesc1 != 0x0) {
00303     pages = ((len + 4095)/4096);
00304     tmpDesc1->baseAddr = (struct memDescriptor *)vmm_getFreeMallocPage(pages);
00305     tmpDesc1->limit    = len;
00306     tmpDesc1->next     = usedKernDesc;
00307     tmpDesc1->prev     = 0x0;
00308     if (usedKernDesc != 0x0)
00309       usedKernDesc->prev       = tmpDesc1;
00310     usedKernDesc             = tmpDesc1;
00311 
00312     if (((pages * 4096)-len) > 0x0) {
00313       tmpDesc2           = getEmptyDesc();
00314       assert(tmpDesc2);
00315       tmpDesc2->baseAddr = tmpDesc1->baseAddr + tmpDesc1->limit;
00316       tmpDesc2->limit    = ((pages * 4096)-len);
00317       tmpDesc2->prev     = 0x0;
00318       tmpDesc2->next     = 0x0;
00319       if (tmpDesc2->limit <= 0x0)
00320         kprintf("kmalloc-2 tmpDesc2: [%i]\n",tmpDesc2->limit);
00321       insertFreeDesc(tmpDesc2);
00322       }
00323 
00324       buf = (char *)tmpDesc1->baseAddr;
00325       for (i=0;i<tmpDesc1->limit;i++) {
00326         (char)buf[i] = (char)0x0;
00327         }
00328     spinUnlock(&mallocSpinLock);
00329     //kprintf("baseAddr2[0x%X:0x%X]",tmpDesc1,tmpDesc1->baseAddr);
00330     //kprintf("m2[%i:%i:0x%X]",tmpDesc1->limit,len,tmpDesc1->baseAddr);
00331         assert(tmpDesc1->baseAddr);
00332     return(tmpDesc1->baseAddr);
00333     }
00334   //Return Null If Unable To Malloc
00335   spinUnlock(&mallocSpinLock);
00336   //kprintf("baseAddr3[0x0]");
00337   return(0x0);
00338   }
00339   
00340 /************************************************************************
00341 
00342 Function: void kfree(void *baseAddr)
00343 Description: This Will Find The Descriptor And Free It
00344 
00345 Notes:
00346 
00347 02/17/03 - I need To Make It Join Descriptors
00348 
00349 ************************************************************************/
00350 void kfree(void *baseAddr) {
00351   struct memDescriptor *tmpDesc = 0x0;
00352 
00353   if (baseAddr == 0x0) return; 
00354   assert(baseAddr);
00355 
00356   assert(usedKernDesc);
00357   spinLock(&mallocSpinLock);
00358   
00359   for (tmpDesc = usedKernDesc;tmpDesc != 0x0;tmpDesc = tmpDesc->next) {
00360     
00361     if (tmpDesc->baseAddr == baseAddr) {
00362       memset(tmpDesc->baseAddr,0xBE,tmpDesc->limit);
00363     
00364       if (usedKernDesc == tmpDesc)
00365         usedKernDesc = tmpDesc->next;
00366 
00367       if (tmpDesc->prev != 0x0)
00368         tmpDesc->prev->next = tmpDesc->next;
00369 
00370       if (tmpDesc->next != 0x0)
00371         tmpDesc->next->prev = tmpDesc->prev;
00372 
00373 
00374       tmpDesc->next = 0x0;
00375       tmpDesc->prev = 0x0;
00376       
00377       if (tmpDesc->limit <= 0x0)
00378         kprintf("kfree tmpDesc1: [%i]\n",tmpDesc->limit);
00379       //kprintf("{0x%X}",tmpDesc->baseAddr);
00380       insertFreeDesc(tmpDesc);
00381 
00382      // mergeMemBlocks();
00383       spinUnlock(&mallocSpinLock);
00384       return;
00385       }
00386     }
00387   spinUnlock(&mallocSpinLock);
00388   kprintf("Kernel: Error Freeing Descriptor! [0x%X]\n",(uInt32)baseAddr);
00389   return;
00390   }
00391 
00392 /***
00393  $Log$
00394  Revision 1.2  2006/10/06 15:48:01  reddawg
00395  Starting to make ubixos work with UFS2
00396 
00397  Revision 1.1.1.1  2006/06/01 12:46:16  reddawg
00398  ubix2
00399 
00400  Revision 1.4  2006/06/01 12:42:09  reddawg
00401  Getting back to the basics
00402 
00403  Revision 1.3  2006/06/01 03:58:33  reddawg
00404  wondering about this stuff here
00405 
00406  Revision 1.2  2005/10/12 00:13:37  reddawg
00407  Removed
00408 
00409  Revision 1.1.1.1  2005/09/26 17:24:11  reddawg
00410  no message
00411 
00412  Revision 1.35  2005/08/04 18:32:59  fsdfs
00413 
00414  added error reporting
00415 
00416  Revision 1.34  2005/08/04 18:23:41  reddawg
00417  BUG: Assert has issues that must be looked into
00418 
00419  Revision 1.33  2005/08/04 17:11:11  fsdfs
00420 
00421  ----------------------------------------
00422 
00423  -------------------
00424 
00425  Revision 1.32  2004/09/28 21:50:04  reddawg
00426  kmalloc: now when we kfree memory is filled with 0xBE so it is easy to debug if we continue to use free'd memory
00427 
00428  Revision 1.31  2004/09/19 16:17:25  reddawg
00429  fixed memory leak we now lose no memory....
00430 
00431  Revision 1.30  2004/09/14 21:51:24  reddawg
00432  Debug info
00433 
00434  Revision 1.29  2004/09/11 23:39:31  reddawg
00435  ok time for bed
00436 
00437  Revision 1.28  2004/09/11 23:21:26  reddawg
00438  run now do you get fegfaults with BB?
00439 
00440  Revision 1.27  2004/09/11 22:49:28  reddawg
00441  pat look at lines 276-285  does the math seem right?
00442 
00443  Revision 1.26  2004/09/11 22:33:13  reddawg
00444  minor changes
00445 
00446  Revision 1.25  2004/09/11 12:11:11  reddawg
00447  Cleaning up the VFS more changes to follow...
00448 
00449  Revision 1.24  2004/09/08 23:19:58  reddawg
00450  hmm
00451 
00452  Revision 1.23  2004/09/06 15:13:25  reddawg
00453  Last commit before FreeBSD 6.0
00454 
00455  Revision 1.22  2004/08/26 22:51:18  reddawg
00456  TCA touched me :( i think he likes men....
00457 
00458 
00459  sched.h:        kTask_t added parentPid
00460  endtask.c:     fixed term back to parentPid
00461  exec.c:          cleaned warnings
00462  fork.c:            fixed term to childPid
00463  sched.c:         clean up for dead tasks
00464  systemtask.c: clean up dead tasks
00465  kmalloc.c:       cleaned up warnings
00466  udp.c:            cleaned up warnings
00467  bot.c:             cleaned up warnings
00468  shell.c:           cleaned up warnings
00469  tcpdump.c:     took a dump
00470  hd.c:             cleaned up warnings
00471  ubixfs.c:        stopped prning debug info
00472 
00473  Revision 1.21  2004/07/28 15:05:43  reddawg
00474  Major:
00475    Pages now have strict security enforcement.
00476    Many null dereferences have been resolved.
00477    When apps loaded permissions set for pages rw and ro
00478 
00479  Revision 1.20  2004/07/28 00:17:05  reddawg
00480  Major:
00481    Disconnected page 0x0 from the system... Unfortunately this broke many things
00482    all of which have been fixed. This was good because nothing deferences NULL
00483    any more.
00484 
00485  Things affected:
00486    malloc,kmalloc,getfreepage,getfreevirtualpage,pagefault,fork,exec,ld,ld.so,exec,file
00487 
00488  Revision 1.19  2004/07/26 19:15:49  reddawg
00489  test code, fixes and the like
00490 
00491  Revision 1.18  2004/07/26 16:52:45  reddawg
00492  here we go
00493 
00494  Revision 1.17  2004/07/24 23:04:44  reddawg
00495  Changes... mark let me know if you fault at pid 185 when you type stress
00496 
00497  Revision 1.16  2004/07/21 10:02:09  reddawg
00498  devfs: renamed functions
00499  device system: renamed functions
00500  fdc: fixed a few potential bugs and cleaned up some unused variables
00501  strol: fixed definition
00502  endtask: made it print out freepage debug info
00503  kmalloc: fixed a huge memory leak we had some unhandled descriptor insertion so some descriptors were lost
00504  ld: fixed a pointer conversion
00505  file: cleaned up a few unused variables
00506  sched: broke task deletion
00507  kprintf: fixed ogPrintf definition
00508 
00509  Revision 1.15  2004/07/20 23:20:50  reddawg
00510  kmalloc: forgot to remove an assert
00511 
00512  Revision 1.14  2004/07/20 23:18:11  reddawg
00513  Made malloc a little more robust but we have a serious memory leak somewhere
00514 
00515  Revision 1.13  2004/07/20 22:29:55  reddawg
00516  assert: remade assert
00517 
00518  Revision 1.12  2004/07/20 18:58:24  reddawg
00519  Few fixes
00520 
00521  Revision 1.11  2004/07/18 05:24:15  reddawg
00522  Fixens
00523 
00524  Revision 1.10  2004/07/17 18:00:47  reddawg
00525  kmalloc: added assert()
00526 
00527  Revision 1.9  2004/07/17 15:54:52  reddawg
00528  kmalloc: added assert()
00529  bioscall: fixed some potential problem by not making 16bit code
00530  paging: added assert()
00531 
00532  Revision 1.8  2004/06/17 14:50:32  reddawg
00533  kmalloc: converted some variables to static
00534 
00535  Revision 1.7  2004/06/17 02:54:54  flameshadow
00536  chg: fixed cast
00537 
00538  Revision 1.6  2004/05/26 11:56:51  reddawg
00539  kmalloc: fixed memrgeMemBlocks hopefully it will prevent future segfault issues
00540           by not having any more overlapping blocks
00541 
00542  Revision 1.5  2004/05/25 14:01:14  reddawg
00543  Implimented Better Spinlocking No More Issues With KMALLOC which actually
00544  was causing bizzare problems
00545 
00546  END
00547  ***/
00548 

Generated on Sun Dec 3 02:38:04 2006 for UbixOS V2 by  doxygen 1.4.7