+
+#define MIN_MEMRANGE 8
+
+void *mem_alloc(unsigned int sz, unsigned int attr)
+{
+ int i;
+ struct memrange *mr, *prev, dummy;
+ struct memrange *mem = 0;
+
+ if(!(attr & MEM_ANY)) {
+ attr |= MEM_ANY;
+ }
+
+ for(i=0; i<NUM_POOLS; i++) {
+ if(!(attr & (1 << i))) continue;
+
+ dummy.next = pool[i];
+ prev = &dummy;
+ mr = dummy.next;
+ while(mr) {
+ if(mr->size >= sz) {
+ if(mr->size >= sz + sizeof *mr + MIN_MEMRANGE) {
+ /* we have enough space for a leftover piece */
+ mem = mr;
+
+ mr = (struct memrange*)(mem->start + sz);
+ *mr = *mem;
+ mr->size -= sz + sizeof *mr;
+ prev->next = mr;
+
+ mem->size = sz;
+ mem->attr |= MEM_USED;
+ mem->next = 0;
+ } else {
+ /* not enough leftover space, just allocate the whole range */
+ mem = mr;
+ mr->attr |= MEM_USED;
+ prev->next = mr->next;
+ mr->next = 0;
+ }
+ break;
+ }
+ prev = mr;
+ mr = mr->next;
+ }
+ pool[i] = dummy.next;
+
+ if(mem) {
+ return mem->start;
+ }
+ }
+
+ return 0;
+}
+
+void mem_free(void *ptr)
+{
+ struct memrange *mr = (struct memrange*)ptr - 1;
+ int pidx = 0;
+
+ if(mr->magic != MAGIC || !(mr->attr & MEM_ANY)) {
+ goto fail;
+ }
+
+ if(mr->attr & MEM_FAST) {
+ pidx = 0;
+ } else if(mr->attr & MEM_SLOW) {
+ pidx = 1;
+ } else if(mr->attr & MEM_CHIP) {
+ pidx = 2;
+ } else {
+ goto fail;
+ }
+
+ add_range(pidx, mr);
+ return;
+
+fail:
+ printf("mem_free(%p): invalid pointer or magic corrupted\n", ptr);
+ memdump(mr, sizeof *mr);
+ panic("");
+}
+
+static void add_range(int pidx, struct memrange *mr)
+{
+ struct memrange *prev, *next, dummy;
+
+ printf("DBG adding free range: %06lx - %06lx to pool %d\n", (unsigned long)mr,
+ (unsigned long)(mr->start + mr->size - (unsigned char*)mr), pidx);
+
+ dummy.next = pool[pidx];
+ prev = &dummy;
+
+ while(prev->next && prev->next < mr) {
+ prev = prev->next;
+ }
+
+ mr->next = prev->next;
+ prev->next = mr;
+
+ /* coalesce */
+ if((next = mr->next) && mr->start + mr->size >= (unsigned char*)mr->next) {
+ mr->size = next->start + next->size - mr->start;
+ mr->next = next->next;
+ next->magic = 0;
+ printf(" DBG coalescing up\n");
+ }
+ if(prev != &dummy && prev->start + prev->size >= (unsigned char*)mr) {
+ prev->size = mr->start + mr->size - prev->start;
+ prev->next = mr->next;
+ mr->magic = 0;
+ printf(" DBG coalescing down\n");
+ }
+
+ pool[pidx] = dummy.next;
+}