summaryrefslogtreecommitdiff
path: root/kern/kalloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'kern/kalloc.c')
-rw-r--r--kern/kalloc.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/kern/kalloc.c b/kern/kalloc.c
new file mode 100644
index 0000000..5390139
--- /dev/null
+++ b/kern/kalloc.c
@@ -0,0 +1,237 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University.
+ * Copyright (c) 1993,1994 The University of Utah and
+ * the Computer Systems Laboratory (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
+ * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
+ * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
+ * THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * File: kern/kalloc.c
+ * Author: Avadis Tevanian, Jr.
+ * Date: 1985
+ *
+ * General kernel memory allocator. This allocator is designed
+ * to be used by the kernel to manage dynamic memory fast.
+ */
+
+#include <mach/machine/vm_types.h>
+#include <mach/vm_param.h>
+
+#include <kern/zalloc.h>
+#include <kern/kalloc.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_object.h>
+#include <vm/vm_map.h>
+
+
+
+vm_map_t kalloc_map;
+vm_size_t kalloc_map_size = 8 * 1024 * 1024;
+vm_size_t kalloc_max;
+
+/*
+ * All allocations of size less than kalloc_max are rounded to the
+ * next highest power of 2. This allocator is built on top of
+ * the zone allocator. A zone is created for each potential size
+ * that we are willing to get in small blocks.
+ *
+ * We assume that kalloc_max is not greater than 64K;
+ * thus 16 is a safe array size for k_zone and k_zone_name.
+ */
+
+int first_k_zone = -1;
+struct zone *k_zone[16];
+static char *k_zone_name[16] = {
+ "kalloc.1", "kalloc.2",
+ "kalloc.4", "kalloc.8",
+ "kalloc.16", "kalloc.32",
+ "kalloc.64", "kalloc.128",
+ "kalloc.256", "kalloc.512",
+ "kalloc.1024", "kalloc.2048",
+ "kalloc.4096", "kalloc.8192",
+ "kalloc.16384", "kalloc.32768"
+};
+
+/*
+ * Max number of elements per zone. zinit rounds things up correctly
+ * Doing things this way permits each zone to have a different maximum size
+ * based on need, rather than just guessing; it also
+ * means its patchable in case you're wrong!
+ */
+unsigned long k_zone_max[16] = {
+ 1024, /* 1 Byte */
+ 1024, /* 2 Byte */
+ 1024, /* 4 Byte */
+ 1024, /* 8 Byte */
+ 1024, /* 16 Byte */
+ 4096, /* 32 Byte */
+ 4096, /* 64 Byte */
+ 4096, /* 128 Byte */
+ 4096, /* 256 Byte */
+ 1024, /* 512 Byte */
+ 1024, /* 1024 Byte */
+ 1024, /* 2048 Byte */
+ 1024, /* 4096 Byte */
+ 4096, /* 8192 Byte */
+ 64, /* 16384 Byte */
+ 64, /* 32768 Byte */
+};
+
+/*
+ * Initialize the memory allocator. This should be called only
+ * once on a system wide basis (i.e. first processor to get here
+ * does the initialization).
+ *
+ * This initializes all of the zones.
+ */
+
+void kalloc_init()
+{
+ vm_offset_t min, max;
+ vm_size_t size;
+ register int i;
+
+ kalloc_map = kmem_suballoc(kernel_map, &min, &max,
+ kalloc_map_size, FALSE);
+
+ /*
+ * Ensure that zones up to size 8192 bytes exist.
+ * This is desirable because messages are allocated
+ * with kalloc, and messages up through size 8192 are common.
+ */
+
+ if (PAGE_SIZE < 16*1024)
+ kalloc_max = 16*1024;
+ else
+ kalloc_max = PAGE_SIZE;
+
+ /*
+ * Allocate a zone for each size we are going to handle.
+ * We specify non-paged memory.
+ */
+ for (i = 0, size = 1; size < kalloc_max; i++, size <<= 1) {
+ if (size < MINSIZE) {
+ k_zone[i] = 0;
+ continue;
+ }
+ if (size == MINSIZE) {
+ first_k_zone = i;
+ }
+ k_zone[i] = zinit(size, k_zone_max[i] * size, size,
+ size >= PAGE_SIZE ? ZONE_COLLECTABLE : 0,
+ k_zone_name[i]);
+ }
+}
+
+vm_offset_t kalloc(size)
+ vm_size_t size;
+{
+ register int zindex;
+ register vm_size_t allocsize;
+ vm_offset_t addr;
+
+ /* compute the size of the block that we will actually allocate */
+
+ allocsize = size;
+ if (size < kalloc_max) {
+ allocsize = MINSIZE;
+ zindex = first_k_zone;
+ while (allocsize < size) {
+ allocsize <<= 1;
+ zindex++;
+ }
+ }
+
+ /*
+ * If our size is still small enough, check the queue for that size
+ * and allocate.
+ */
+
+ if (allocsize < kalloc_max) {
+ addr = zalloc(k_zone[zindex]);
+ } else {
+ if (kmem_alloc_wired(kalloc_map, &addr, allocsize)
+ != KERN_SUCCESS)
+ addr = 0;
+ }
+ return(addr);
+}
+
+vm_offset_t kget(size)
+ vm_size_t size;
+{
+ register int zindex;
+ register vm_size_t allocsize;
+ vm_offset_t addr;
+
+ /* compute the size of the block that we will actually allocate */
+
+ allocsize = size;
+ if (size < kalloc_max) {
+ allocsize = MINSIZE;
+ zindex = first_k_zone;
+ while (allocsize < size) {
+ allocsize <<= 1;
+ zindex++;
+ }
+ }
+
+ /*
+ * If our size is still small enough, check the queue for that size
+ * and allocate.
+ */
+
+ if (allocsize < kalloc_max) {
+ addr = zget(k_zone[zindex]);
+ } else {
+ /* This will never work, so we might as well panic */
+ panic("kget");
+ }
+ return(addr);
+}
+
+void
+kfree(data, size)
+ vm_offset_t data;
+ vm_size_t size;
+{
+ register int zindex;
+ register vm_size_t freesize;
+
+ freesize = size;
+ if (size < kalloc_max) {
+ freesize = MINSIZE;
+ zindex = first_k_zone;
+ while (freesize < size) {
+ freesize <<= 1;
+ zindex++;
+ }
+ }
+
+ if (freesize < kalloc_max) {
+ zfree(k_zone[zindex], data);
+ } else {
+ kmem_free(kalloc_map, data, freesize);
+ }
+}