00001 00007 /* Embedded XINU, Copyright (C) 2007. All rights reserved. */ 00008 00009 #include <kernel.h> 00010 #include <memory.h> 00011 00017 void *getmem(ulong nbytes) 00018 { 00019 irqmask ps; 00020 struct memblock *prev, *next, *leftover; 00021 00022 if ( (0 == nbytes) || (NULL == freelist.next) ) 00023 { 00024 return (void *)SYSERR; 00025 } 00026 00027 /* pad nbytes with room for accounting information and */ 00028 /* round to the nearest bytes */ 00029 nbytes = (ulong)roundmb(nbytes + sizeof(struct memblock)); 00030 00031 /* modifying memory layout, do not interrupt */ 00032 ps = disable(); 00033 00034 prev = &freelist; 00035 next = freelist.next; 00036 while ( NULL != next ) 00037 { 00038 /* if the current node has enough room, we'll allocate */ 00039 if (next->length >= nbytes) 00040 { 00041 /* this block is big enough, check if it can hold nbytes */ 00042 /* and still have room for the leftover block's acct. info */ 00043 if ( next->length < (nbytes + sizeof(struct memblock)) ) 00044 { 00045 /* there was not enough room for nbytes and the new */ 00046 /* block's accounting information, so allocate block */ 00047 prev->next = next->next; 00048 next->next = next; 00049 00050 /* maintain freelist length */ 00051 freelist.length -= next->length; 00052 00053 restore(ps); 00054 return (void *)(next + 1); /* + 1 to skip acct. data */ 00055 } 00056 else 00057 { 00058 /* block is big enough to split in two relevant blocks */ 00059 leftover = (struct memblock *)((ulong)next + nbytes); 00060 prev->next = leftover; 00061 00062 /* set up data for the new (smaller) node */ 00063 leftover->next = next->next; 00064 leftover->length = next->length - nbytes; 00065 00066 /* prepare block for checks in freemem */ 00067 /* a memory location pointing to itself is unlikely */ 00068 next->next = next; 00069 next->length = nbytes; 00070 00071 /* maintain freelist length */ 00072 freelist.length -= next->length; 00073 00074 restore(ps); 00075 return (void *)(next + 1); /* + 1 to skip acct. data */ 00076 } 00077 } 00078 00079 /* iterate to next pointer, this node was too small */ 00080 prev = next; 00081 next = next->next; 00082 } 00083 00084 restore(ps); 00085 return (void *)SYSERR; 00086 }