/*- * Copyright (c) 2002-2018 The UbixOS Project. * All rights reserved. * * This was developed by Christopher W. Olsen for the UbixOS Project. * * Redistribution and use in source and binary forms, with or without modification, are permitted * provided that the following conditions are met: * * 1) Redistributions of source code must retain the above copyright notice, this list of * conditions, the following disclaimer and the list of authors. * 2) Redistributions in binary form must reproduce the above copyright notice, this list of * conditions, the following disclaimer and the list of authors in the documentation and/or * other materials provided with the distribution. * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to * endorse or promote products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <lib/kmalloc.h> #include <lib/kprintf.h> #include <ubixos/kpanic.h> #include <ubixos/sched.h> #include <ubixos/spinlock.h> #include <vmm/vmm.h> #include <string.h> #include <assert.h> #include <sys/types.h> /* Set up three descriptor tables: kernDesc - The inuse descriptor table freeKernDesc - The free descriptor table (descriptors with memory backing just not in use) emptyKernDesc - The empty descriptor table (descriptors with out a memory backing) */ static struct memDescriptor *usedKernDesc = 0x0; static struct memDescriptor *freeKernDesc = 0x0; static struct memDescriptor *emptyKernDesc = 0x0; /* Set up our spinlocks so we do not corrupt linked lists if we have re-entrancy */ static struct spinLock mallocSpinLock = SPIN_LOCK_INITIALIZER ; static struct spinLock emptyDescSpinLock = SPIN_LOCK_INITIALIZER ; /************************************************************************ Function: void *getEmptyDesc() Description: Find An Empty Descriptor Notes: 02/17/03 - Is This Efficient? ************************************************************************/ static void* getEmptyDesc() { int i = 0x0; struct memDescriptor *tmpDesc = 0x0; spinLock(&emptyDescSpinLock); tmpDesc = emptyKernDesc; if (tmpDesc != 0x0) { emptyKernDesc = tmpDesc->next; if (emptyKernDesc != 0x0) emptyKernDesc->prev = 0x0; tmpDesc->next = 0x0; tmpDesc->prev = 0x0; spinUnlock(&emptyDescSpinLock); return (tmpDesc); } if ((emptyKernDesc = (struct memDescriptor*) vmm_getFreeMallocPage(4)) == 0x0) kpanic("Error: vmmGetFreeKernelPage returned NULL\n"); /* zero out the memory so we know there is no garbage */ memset(emptyKernDesc, 0x0, 0x4000); emptyKernDesc[0].next = &emptyKernDesc[1]; for (i = 0x1; i < ((0x4000 / sizeof(struct memDescriptor))); i++) { if (i + 1 < (0x4000 / sizeof(struct memDescriptor))) emptyKernDesc[i].next = &emptyKernDesc[i + 1]; else emptyKernDesc[i].next = 0x0; emptyKernDesc[i].prev = &emptyKernDesc[i - 1]; } tmpDesc = &emptyKernDesc[0]; emptyKernDesc = tmpDesc->next; emptyKernDesc->prev = 0x0; tmpDesc->next = 0x0; tmpDesc->prev = 0x0; spinUnlock(&emptyDescSpinLock); return (tmpDesc); } /************************************************************************ Function: void insertFreeDesc(struct memDescriptor *freeDesc) Description: This Function Inserts A Free Descriptor On The List Which Is Kept In Size Order Notes: 02/17/03 - This Was Inspired By TCA's Great Wisdom - "[20:20:59] <TCA> You should just insert it in order" ************************************************************************/ static int insertFreeDesc(struct memDescriptor *freeDesc) { struct memDescriptor *tmpDesc = 0x0; assert(freeDesc); if (freeDesc->limit <= 0x0) kpanic("Inserting Descriptor with no limit\n"); if (freeKernDesc != 0x0) { #if 0 freeDesc->next = freeKernDesc; freeDesc->prev = 0x0; freeKernDesc->prev = freeDesc; freeKernDesc = freeDesc; #endif for (tmpDesc = freeKernDesc; tmpDesc != 0x0; tmpDesc = tmpDesc->next) { if (freeDesc->limit <= tmpDesc->limit) { freeDesc->prev = tmpDesc->prev; if (tmpDesc->prev != 0x0) tmpDesc->prev->next = freeDesc; tmpDesc->prev = freeDesc; freeDesc->next = tmpDesc; if (tmpDesc == freeKernDesc) freeKernDesc = freeDesc; return (0x0); } if (tmpDesc->next == 0x0) { tmpDesc->next = freeDesc; freeDesc->prev = tmpDesc; freeDesc->next = 0x0; return (0x0); } } kpanic("didnt Insert\n"); return (0x0); } else { freeDesc->prev = 0x0; freeDesc->next = 0x0; freeKernDesc = freeDesc; return (0x0); } return (0x1); } /************************************************************************ Function: void mergeMemBlocks() Description: This Function Will Merge Free Blocks And Free Pages Notes: 03/05/03 - We Have A Problem It Seems The First Block Is Limit 0x0 ************************************************************************/ static void mergeMemBlocks() { struct memDescriptor *tmpDesc1 = 0x0; struct memDescriptor *tmpDesc2 = 0x0; u_int32_t baseAddr = 0x0; kprintf("[%s:%i] MMB", __FILE__, __LINE__); //Loop The Free Descriptors See If We Can Merge Them mergeStart: for (tmpDesc1 = freeKernDesc; tmpDesc1 != 0x0; tmpDesc1 = tmpDesc1->next) { /* Compare The Base Addr With The Other Descriptors If You Find The One That You Are Looking For Lets Merge Them */ if (tmpDesc1->limit != 0x0) { baseAddr = (uInt32) tmpDesc1->baseAddr + (uInt32) tmpDesc1->limit; for (tmpDesc2 = freeKernDesc; tmpDesc2; tmpDesc2 = tmpDesc2->next) { if ((uInt32) tmpDesc2->baseAddr == baseAddr) { tmpDesc1->limit += tmpDesc2->limit; tmpDesc2->baseAddr = 0x0; tmpDesc2->limit = 0x0; if (tmpDesc2->prev) { tmpDesc2->prev->next = tmpDesc2->next; } if (tmpDesc2->next) { tmpDesc2->next->prev = tmpDesc2->prev; } tmpDesc2->prev = 0x0; tmpDesc2->next = emptyKernDesc; emptyKernDesc->prev = tmpDesc2; emptyKernDesc = tmpDesc2; if (tmpDesc1->prev) { tmpDesc1->prev->next = tmpDesc1->next; } if (tmpDesc1->next) { tmpDesc1->next->prev = tmpDesc1->prev; } tmpDesc1->prev = 0x0; tmpDesc1->next = 0x0; kprintf("mergememBlocks: [%i]\n", tmpDesc1->limit); insertFreeDesc(tmpDesc1); //tmpDesc1 = freeKernDesc; goto mergeStart; break; } } } } return; } /************************************************************************ Function: void *kmalloc(uInt32 len) Description: Allocate Kernel Memory Notes: 02/17/03 - Do I Still Need To Pass In The Pid? ************************************************************************/ void* kmalloc(uInt32 len) { struct memDescriptor *tmpDesc1 = 0x0; struct memDescriptor *tmpDesc2 = 0x0; char *buf = 0x0; int i = 0x0; uInt16 pages = 0x0; spinLock(&mallocSpinLock); len = MALLOC_ALIGN(len); if (len == 0x0) { spinUnlock(&mallocSpinLock); kprintf("kmalloc: len = 0!\n"); return (0x0); } for (tmpDesc1 = freeKernDesc; tmpDesc1 != 0x0; tmpDesc1 = tmpDesc1->next) { assert(tmpDesc1); if (tmpDesc1->limit >= len) { if (tmpDesc1->prev != 0x0) tmpDesc1->prev->next = tmpDesc1->next; if (tmpDesc1->next != 0x0) tmpDesc1->next->prev = tmpDesc1->prev; if (tmpDesc1 == freeKernDesc) freeKernDesc = tmpDesc1->next; tmpDesc1->prev = 0x0; tmpDesc1->next = usedKernDesc; if (usedKernDesc != 0x0) usedKernDesc->prev = tmpDesc1; usedKernDesc = tmpDesc1; if (tmpDesc1->limit > len) { tmpDesc2 = getEmptyDesc(); assert(tmpDesc2); tmpDesc2->limit = tmpDesc1->limit - len; tmpDesc1->limit = len; tmpDesc2->baseAddr = tmpDesc1->baseAddr + len; tmpDesc2->next = 0x0; tmpDesc2->prev = 0x0; insertFreeDesc(tmpDesc2); } buf = (char*) tmpDesc1->baseAddr; for (i = 0; i < tmpDesc1->limit; i++) { buf[i] = (char) 0x0; } spinUnlock(&mallocSpinLock); //kprintf("m1[%i:%i:0x%X]",tmpDesc1->limit,len,tmpDesc1->baseAddr); assert(tmpDesc1->baseAddr); return (tmpDesc1->baseAddr); } } tmpDesc1 = getEmptyDesc(); //kprintf("no empty desc\n"); if (tmpDesc1 != 0x0) { pages = ((len + 4095) / 4096); tmpDesc1->baseAddr = (struct memDescriptor*) vmm_getFreeMallocPage(pages); tmpDesc1->limit = len; tmpDesc1->next = usedKernDesc; tmpDesc1->prev = 0x0; if (usedKernDesc != 0x0) usedKernDesc->prev = tmpDesc1; usedKernDesc = tmpDesc1; if (((pages * 4096) - len) > 0x0) { tmpDesc2 = getEmptyDesc(); assert(tmpDesc2); tmpDesc2->baseAddr = tmpDesc1->baseAddr + tmpDesc1->limit; tmpDesc2->limit = ((pages * 4096) - len); tmpDesc2->prev = 0x0; tmpDesc2->next = 0x0; if (tmpDesc2->limit <= 0x0) kprintf("kmalloc-2 tmpDesc2: [%i]\n", tmpDesc2->limit); insertFreeDesc(tmpDesc2); } buf = (char*) tmpDesc1->baseAddr; for (i = 0; i < tmpDesc1->limit; i++) { buf[i] = (char) 0x0; } spinUnlock(&mallocSpinLock); //kprintf("baseAddr2[0x%X:0x%X]",tmpDesc1,tmpDesc1->baseAddr); //kprintf("m2[%i:%i:0x%X]",tmpDesc1->limit,len,tmpDesc1->baseAddr); assert(tmpDesc1->baseAddr); return (tmpDesc1->baseAddr); } //Return Null If Unable To Malloc spinUnlock(&mallocSpinLock); //kprintf("baseAddr3[0x0]"); return (0x0); } /************************************************************************ Function: void kfree(void *baseAddr) Description: This Will Find The Descriptor And Free It Notes: 02/17/03 - I need To Make It Join Descriptors ************************************************************************/ void kfree(void *baseAddr) { struct memDescriptor *tmpDesc = 0x0; if (baseAddr == 0x0) return; assert(baseAddr); assert(usedKernDesc); spinLock(&mallocSpinLock); for (tmpDesc = usedKernDesc; tmpDesc != 0x0; tmpDesc = tmpDesc->next) { if (tmpDesc->baseAddr == baseAddr) { //kprintf("[bA: 0x%X]", tmpDesc->baseAddr); memset(tmpDesc->baseAddr, 0xBE, tmpDesc->limit); if (usedKernDesc == tmpDesc) usedKernDesc = tmpDesc->next; if (tmpDesc->prev != 0x0) tmpDesc->prev->next = tmpDesc->next; if (tmpDesc->next != 0x0) tmpDesc->next->prev = tmpDesc->prev; tmpDesc->next = 0x0; tmpDesc->prev = 0x0; if (tmpDesc->limit <= 0x0) kprintf("kfree tmpDesc1: [%i]\n", tmpDesc->limit); //kprintf("{0x%X}",tmpDesc->baseAddr); insertFreeDesc(tmpDesc); // mergeMemBlocks(); spinUnlock(&mallocSpinLock); return; } } spinUnlock(&mallocSpinLock); kprintf("Kernel: Error Freeing Descriptor! [0x%X]\n", (uInt32) baseAddr); return; } /*** $Log: kmalloc.c,v $ Revision 1.3 2006/12/05 14:10:21 reddawg Workign Distro Revision 1.2 2006/10/06 15:48:01 reddawg Starting to make ubixos work with UFS2 Revision 1.1.1.1 2006/06/01 12:46:16 reddawg ubix2 Revision 1.4 2006/06/01 12:42:09 reddawg Getting back to the basics Revision 1.3 2006/06/01 03:58:33 reddawg wondering about this stuff here Revision 1.2 2005/10/12 00:13:37 reddawg Removed Revision 1.1.1.1 2005/09/26 17:24:11 reddawg no message Revision 1.35 2005/08/04 18:32:59 fsdfs added error reporting Revision 1.34 2005/08/04 18:23:41 reddawg BUG: Assert has issues that must be looked into Revision 1.33 2005/08/04 17:11:11 fsdfs ---------------------------------------- ------------------- Revision 1.32 2004/09/28 21:50:04 reddawg kmalloc: now when we kfree memory is filled with 0xBE so it is easy to debug if we continue to use free'd memory Revision 1.31 2004/09/19 16:17:25 reddawg fixed memory leak we now lose no memory.... Revision 1.30 2004/09/14 21:51:24 reddawg Debug info Revision 1.29 2004/09/11 23:39:31 reddawg ok time for bed Revision 1.28 2004/09/11 23:21:26 reddawg run now do you get fegfaults with BB? Revision 1.27 2004/09/11 22:49:28 reddawg pat look at lines 276-285 does the math seem right? Revision 1.26 2004/09/11 22:33:13 reddawg minor changes Revision 1.25 2004/09/11 12:11:11 reddawg Cleaning up the VFS more changes to follow... Revision 1.24 2004/09/08 23:19:58 reddawg hmm Revision 1.23 2004/09/06 15:13:25 reddawg Last commit before FreeBSD 6.0 Revision 1.22 2004/08/26 22:51:18 reddawg TCA touched me :( i think he likes men.... sched.h: kTask_t added parentPid endtask.c: fixed term back to parentPid exec.c: cleaned warnings fork.c: fixed term to childPid sched.c: clean up for dead tasks systemtask.c: clean up dead tasks kmalloc.c: cleaned up warnings udp.c: cleaned up warnings bot.c: cleaned up warnings shell.c: cleaned up warnings tcpdump.c: took a dump hd.c: cleaned up warnings ubixfs.c: stopped prning debug info Revision 1.21 2004/07/28 15:05:43 reddawg Major: Pages now have strict security enforcement. Many null dereferences have been resolved. When apps loaded permissions set for pages rw and ro Revision 1.20 2004/07/28 00:17:05 reddawg Major: Disconnected page 0x0 from the system... Unfortunately this broke many things all of which have been fixed. This was good because nothing deferences NULL any more. Things affected: malloc,kmalloc,getfreepage,getfreevirtualpage,pagefault,fork,exec,ld,ld.so,exec,file Revision 1.19 2004/07/26 19:15:49 reddawg test code, fixes and the like Revision 1.18 2004/07/26 16:52:45 reddawg here we go Revision 1.17 2004/07/24 23:04:44 reddawg Changes... mark let me know if you fault at pid 185 when you type stress Revision 1.16 2004/07/21 10:02:09 reddawg devfs: renamed functions device system: renamed functions fdc: fixed a few potential bugs and cleaned up some unused variables strol: fixed definition endtask: made it print out freepage debug info kmalloc: fixed a huge memory leak we had some unhandled descriptor insertion so some descriptors were lost ld: fixed a pointer conversion file: cleaned up a few unused variables sched: broke task deletion kprintf: fixed ogPrintf definition Revision 1.15 2004/07/20 23:20:50 reddawg kmalloc: forgot to remove an assert Revision 1.14 2004/07/20 23:18:11 reddawg Made malloc a little more robust but we have a serious memory leak somewhere Revision 1.13 2004/07/20 22:29:55 reddawg assert: remade assert Revision 1.12 2004/07/20 18:58:24 reddawg Few fixes Revision 1.11 2004/07/18 05:24:15 reddawg Fixens Revision 1.10 2004/07/17 18:00:47 reddawg kmalloc: added assert() Revision 1.9 2004/07/17 15:54:52 reddawg kmalloc: added assert() bioscall: fixed some potential problem by not making 16bit code paging: added assert() Revision 1.8 2004/06/17 14:50:32 reddawg kmalloc: converted some variables to static Revision 1.7 2004/06/17 02:54:54 flameshadow chg: fixed cast Revision 1.6 2004/05/26 11:56:51 reddawg kmalloc: fixed memrgeMemBlocks hopefully it will prevent future segfault issues by not having any more overlapping blocks Revision 1.5 2004/05/25 14:01:14 reddawg Implimented Better Spinlocking No More Issues With KMALLOC which actually was causing bizzare problems END ***/