Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / lib / libc / stdlib / malloc.c
diff --git a/qemu/roms/SLOF/lib/libc/stdlib/malloc.c b/qemu/roms/SLOF/lib/libc/stdlib/malloc.c
new file mode 100644 (file)
index 0000000..b2a3138
--- /dev/null
@@ -0,0 +1,157 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "stddef.h"
+#include "stdlib.h"
+#include "unistd.h"
+#include "malloc_defs.h"
+
+
+static int clean(void);
+
+
+/* act points to the end of the initialized heap and the start of uninitialized heap */
+static char *act;
+
+/* Pointers to start and end of heap: */
+static char *heap_start, *heap_end;
+
+
+/*
+ * Standard malloc function
+ */
+void *
+malloc(size_t size)
+{
+       char *header;
+       void *data;
+       size_t blksize;         /* size of memory block including the chunk */
+
+       blksize = size + sizeof(struct chunk);
+
+       /* has malloc been called for the first time? */
+       if (act == 0) {
+               size_t initsize;
+               /* add some space so we have a good initial playground */
+               initsize = (blksize + 0x1000) & ~0x0fff;
+               /* get initial memory region with sbrk() */
+               heap_start = sbrk(initsize);
+               if (heap_start == (void*)-1)
+                       return NULL;
+               heap_end = heap_start + initsize;
+               act = heap_start;
+       }
+
+       header = act;
+       data = act + sizeof(struct chunk);
+
+       /* Check if there is space left in the uninitialized part of the heap */
+       if (act + blksize > heap_end) {
+               //search at begin of heap
+               header = heap_start;
+
+               while ((((struct chunk *) header)->inuse != 0
+                       || ((struct chunk *) header)->length < size)
+                      && header < act) {
+                       header = header + sizeof(struct chunk)
+                                + ((struct chunk *) header)->length;
+               }
+
+               // check if heap is full
+               if (header >= act) {
+                       if (clean()) {
+                               // merging of free blocks succeeded, so try again
+                               return malloc(size);
+                       } else if (sbrk(blksize) == heap_end) {
+                               // succeeded to get more memory, so try again
+                               heap_end += blksize;
+                               return malloc(size);
+                       } else {
+                               // No more memory available
+                               return 0;
+                       }
+               }
+
+               // Check if we need to split this memory block into two
+               if (((struct chunk *) header)->length > blksize) {
+                       //available memory is too big
+                       int alt;
+
+                       alt = ((struct chunk *) header)->length;
+                       ((struct chunk *) header)->inuse = 1;
+                       ((struct chunk *) header)->length = size;
+                       data = header + sizeof(struct chunk);
+
+                       //mark the rest of the heap
+                       header = data + size;
+                       ((struct chunk *) header)->inuse = 0;
+                       ((struct chunk *) header)->length =
+                           alt - blksize;
+               } else {
+                       //new memory matched exactly in available memory
+                       ((struct chunk *) header)->inuse = 1;
+                       data = header + sizeof(struct chunk);
+               }
+
+       } else {
+
+               ((struct chunk *) header)->inuse = 1;
+               ((struct chunk *) header)->length = size;
+
+               act += blksize;
+       }
+
+       return data;
+}
+
+
+/*
+ * Merge free memory blocks in initialized heap if possible
+ */
+static int
+clean(void)
+{
+       char *header;
+       char *firstfree = 0;
+       char check = 0;
+
+       header = heap_start;
+       //if (act == 0)         // This should never happen
+       //      act = heap_end;
+
+       while (header < act) {
+
+               if (((struct chunk *) header)->inuse == 0) {
+                       if (firstfree == 0) {
+                               /* First free block in a row, only save address */
+                               firstfree = header;
+
+                       } else {
+                               /* more than one free block in a row, merge them! */
+                               ((struct chunk *) firstfree)->length +=
+                                   ((struct chunk *) header)->length +
+                                   sizeof(struct chunk);
+                               check = 1;
+                       }
+               } else {
+                       firstfree = 0;
+
+               }
+
+               header = header + sizeof(struct chunk)
+                        + ((struct chunk *) header)->length;
+
+       }
+
+       return check;
+}