/*
* UCW Library -- Allocation of Large Aligned Buffers
*
- * (c) 2006 Martin Mares <mj@ucw.cz>
+ * (c) 2006--2007 Martin Mares <mj@ucw.cz>
+ * (c) 2007 Pavel Charvat <char@ucw.cz>
*
* This software may be freely distributed and used according to the terms
* of the GNU Lesser General Public License.
#include "lib/lib.h"
#include <sys/mman.h>
-#include <sys/user.h>
+#include <string.h>
+#include <limits.h>
-static unsigned int
-big_round(unsigned int len)
+void *
+page_alloc(u64 len)
+{
+ if (len > SIZE_MAX)
+ die("page_alloc: Size %llu is too large for the current architecture", (long long) len);
+ ASSERT(!(len & (CPU_PAGE_SIZE-1)));
+ byte *p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+ if (p == (byte*) MAP_FAILED)
+ die("Cannot mmap %llu bytes of memory: %m", (long long)len);
+ return p;
+}
+
+void *
+page_alloc_zero(u64 len)
+{
+ void *p = page_alloc(len);
+ bzero(p, len);
+ return p;
+}
+
+void
+page_free(void *start, u64 len)
+{
+ ASSERT(!(len & (CPU_PAGE_SIZE-1)));
+ ASSERT(!((uintptr_t) start & (CPU_PAGE_SIZE-1)));
+ munmap(start, len);
+}
+
+void *
+page_realloc(void *start, u64 old_len, u64 new_len)
+{
+ void *p = page_alloc(new_len);
+ memcpy(p, start, MIN(old_len, new_len));
+ page_free(start, old_len);
+ return p;
+}
+
+static u64
+big_round(u64 len)
{
- return ALIGN_TO(len, PAGE_SIZE);
+ return ALIGN_TO(len, (u64)CPU_PAGE_SIZE);
}
void *
-big_alloc(unsigned int len)
+big_alloc(u64 len)
{
- len = big_round(len);
+ u64 l = big_round(len);
+ if (l > SIZE_MAX - 2*CPU_PAGE_SIZE)
+ die("big_alloc: Size %llu is too large for the current architecture", (long long) len);
#ifdef CONFIG_DEBUG
- len += 2*PAGE_SIZE;
+ l += 2*CPU_PAGE_SIZE;
#endif
- byte *p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
- if (p == (byte*) MAP_FAILED)
- die("Cannot mmap %d bytes of memory: %m", len);
+ byte *p = page_alloc(l);
#ifdef CONFIG_DEBUG
- mprotect(p, PAGE_SIZE, PROT_NONE);
- mprotect(p+len-PAGE_SIZE, PAGE_SIZE, PROT_NONE);
- p += PAGE_SIZE;
+ *(u64*)p = len;
+ mprotect(p, CPU_PAGE_SIZE, PROT_NONE);
+ mprotect(p+l-CPU_PAGE_SIZE, CPU_PAGE_SIZE, PROT_NONE);
+ p += CPU_PAGE_SIZE;
#endif
return p;
}
+void *
+big_alloc_zero(u64 len)
+{
+ void *p = big_alloc(len);
+ bzero(p, big_round(len));
+ return p;
+}
+
void
-big_free(void *start, unsigned int len)
+big_free(void *start, u64 len)
{
byte *p = start;
- ASSERT(!((addr_int_t) p & (PAGE_SIZE-1)));
- len = big_round(len);
+ u64 l = big_round(len);
#ifdef CONFIG_DEBUG
- p -= PAGE_SIZE;
- len += 2*PAGE_SIZE;
+ p -= CPU_PAGE_SIZE;
+ mprotect(p, CPU_PAGE_SIZE, PROT_READ);
+ ASSERT(*(u64*)p == len);
+ l += 2*CPU_PAGE_SIZE;
#endif
- munmap(p, len);
+ page_free(p, l);
}
#ifdef TEST