/* * Copyright 2010 Steffen Vogel, Chair for Operating Systems, * RWTH Aachen University * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * This file is part of MetalSVM. */ #include #include #include #include /// A linked list for each binary size exponent static buddy_t* buddy_lists[BUDDY_LISTS] = { NULL }; /// Lock for the buddy lists static spinlock_t buddy_lock = SPINLOCK_INIT; /** @brief Check if larger free buddies are available */ static inline int buddy_large_avail(uint8_t exp) { while (exp BUDDY_MAX) return 0; else if (exp < BUDDY_MIN) return BUDDY_MIN; else return exp; } /** @brief Get a free buddy by potentially splitting a larger one */ static buddy_t* buddy_get(int exp) { spinlock_lock(&buddy_lock); buddy_t** list = &buddy_lists[exp-BUDDY_MIN]; buddy_t* buddy = *list; buddy_t* split; if (buddy) // there is already a free buddy => // we remove it from the list *list = buddy->next; else if (exp >= BUDDY_ALLOC && !buddy_large_avail(exp)) // theres no free buddy larger than exp => // we can allocate new memory buddy = (buddy_t*) palloc(1<next = *list; *list = split; } out: spinlock_unlock(&buddy_lock); return buddy; } /** @brief Put a buddy back to its free list * * TODO: merge adjacent buddies (memory compaction) */ static void buddy_put(buddy_t* buddy) { spinlock_lock(&buddy_lock); buddy_t** list = &buddy_lists[buddy->prefix.exponent-BUDDY_MIN]; buddy->next = *list; *list = buddy; spinlock_unlock(&buddy_lock); } void buddy_dump() { size_t free = 0; int i; for (i=0; inext) { kprintf(" %p -> %p \n", buddy, buddy->next); free += 1<> PAGE_SHIFT; kprintf("palloc(%lu) (%lu pages)\n", sz, npages); // TODO: remove // get free virtual address space viraddr = vma_alloc(npages*PAGE_SIZE, VMA_HEAP); if (BUILTIN_EXPECT(!viraddr, 0)) return NULL; // get continous physical pages phyaddr = get_pages(npages); if (BUILTIN_EXPECT(!phyaddr, 0)) { vma_free(viraddr, viraddr+npages*PAGE_SIZE); return NULL; } // map physical pages to VMA viraddr = map_region(viraddr, phyaddr, npages, flags); if (BUILTIN_EXPECT(!viraddr, 0)) { vma_free(viraddr, viraddr+npages*PAGE_SIZE); put_pages(phyaddr, npages); return NULL; } return (void*) viraddr; } void pfree(void* addr, size_t sz) { if (BUILTIN_EXPECT(!addr || !sz, 0)) return; size_t i; size_t phyaddr; size_t viraddr = (size_t) addr & PAGE_MASK; uint32_t npages = PAGE_ALIGN(sz) >> PAGE_SHIFT; // memory is propably not continously mapped! for (i=0; iprefix.magic = BUDDY_MAGIC; buddy->prefix.exponent = exp; // pointer arithmetic: we hide the prefix return buddy+1; } void kfree(void *addr) { if (BUILTIN_EXPECT(!addr, 0)) return; buddy_t* buddy = (buddy_t*) addr - 1; // get prefix // check magic if (BUILTIN_EXPECT(buddy->prefix.magic != BUDDY_MAGIC, 0)) return; buddy_put(buddy); }