/*-
* 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
************************************************************************/
#ifdef _IGNORE
static void mergeMemBlocks() {
struct memDescriptor *tmpDesc1 = 0x0;
struct memDescriptor *tmpDesc2 = 0x0;
uInt32 baseAddr = 0x0;
return;
//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;
}
#endif
/************************************************************************
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) {
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
***/