Browse Source

kmalloc: initial implementation

Aaron Lindsay 7 years ago
parent
commit
ccbee1d142
3 changed files with 226 additions and 1 deletions
  1. 27 0
      include/kmalloc.h
  2. 155 0
      kernel/kmalloc.c
  3. 44 1
      kernel/start_kernel.c

+ 27 - 0
include/kmalloc.h

@@ -0,0 +1,27 @@
1
+/*
2
+    Copyright (C) 2012, Aaron Lindsay <aaron@aclindsay.com>
3
+
4
+    This file is part of Aedrix.
5
+
6
+    This program is free software; you can redistribute it and/or modify
7
+    it under the terms of the GNU General Public License as published by
8
+    the Free Software Foundation; either version 2 of the License, or
9
+    (at your option) any later version.
10
+
11
+    This program is distributed in the hope that it will be useful,
12
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+    GNU General Public License for more details.
15
+
16
+    You should have received a copy of the GNU General Public License along
17
+    with this program; if not, write to the Free Software Foundation, Inc.,
18
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
+ */
20
+
21
+#ifndef KMALLOC_H
22
+#define KMALLOC_H
23
+
24
+void* kmalloc(unsigned int bytes);
25
+void kfree(void *p);
26
+
27
+#endif /* KMALLOC_H */

+ 155 - 0
kernel/kmalloc.c

@@ -0,0 +1,155 @@
1
+/*
2
+    Copyright (C) 2012, Aaron Lindsay <aaron@aclindsay.com>
3
+
4
+    This file is part of Aedrix.
5
+
6
+    This program is free software; you can redistribute it and/or modify
7
+    it under the terms of the GNU General Public License as published by
8
+    the Free Software Foundation; either version 2 of the License, or
9
+    (at your option) any later version.
10
+
11
+    This program is distributed in the hope that it will be useful,
12
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+    GNU General Public License for more details.
15
+
16
+    You should have received a copy of the GNU General Public License along
17
+    with this program; if not, write to the Free Software Foundation, Inc.,
18
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
+ */
20
+
21
+#include <kmalloc.h>
22
+#include <mm.h>
23
+#include <list.h>
24
+#include <print.h>
25
+
26
+struct kmalloc_region {
27
+	struct dlist_node list;
28
+	void *end;
29
+};
30
+
31
+#define KMALLOC_MIN_ALIGNMENT 4
32
+#define KMALLOC_REGION_SIZE (sizeof(struct kmalloc_region) + (sizeof(struct kmalloc_region) % KMALLOC_MIN_ALIGNMENT ? KMALLOC_MIN_ALIGNMENT - sizeof(struct kmalloc_region) % KMALLOC_MIN_ALIGNMENT : 0)) //round actual struct size up so its aligned 
33
+#define KMALLOC_MAX_TRIES 3 //Max number of times the heap can be grown for a single request
34
+
35
+
36
+int curr_page_power = 0;
37
+struct dlist_node kmalloc_free_regions;
38
+
39
+void kmalloc_init() {
40
+	init_list(&kmalloc_free_regions);
41
+}
42
+
43
+struct kmalloc_region *find_free_region(unsigned int bytes) {
44
+	struct kmalloc_region *it;
45
+	for_each_list(it, &kmalloc_free_regions, struct kmalloc_region, list) {
46
+		unsigned int size = (char *)it->end - (char*)it + 1;
47
+		if (size >= KMALLOC_REGION_SIZE + bytes) {
48
+			return it;
49
+		}
50
+	}
51
+	return (struct kmalloc_region *)0;
52
+}
53
+
54
+struct kmalloc_region *join_regions(struct kmalloc_region *first, struct kmalloc_region *second) {
55
+	first->end = second->end;
56
+	remove(&second->list);
57
+
58
+	//TODO free pages here if we get a big enough free space
59
+	return first;
60
+}
61
+
62
+void coalesce(struct kmalloc_region *region) {
63
+	struct kmalloc_region *prev = 0, *next = 0;
64
+
65
+	if (region->list.next != &kmalloc_free_regions)
66
+		next = container(region->list.next, struct kmalloc_region, list);
67
+	if (region->list.prev != &kmalloc_free_regions)
68
+		prev = container(region->list.prev, struct kmalloc_region, list);
69
+
70
+	if (next && (char *)next == (char *)region->end + 1) {
71
+		region = join_regions(region, next);
72
+		coalesce(region);
73
+	}
74
+	if (prev && (char *)region == (char *)prev->end + 1) {
75
+		region = join_regions(prev, region);
76
+		coalesce(region);
77
+	}
78
+}
79
+
80
+void add_region(struct kmalloc_region *region) {
81
+	struct kmalloc_region *it;
82
+	for_each_list(it, &kmalloc_free_regions, struct kmalloc_region, list) {
83
+		if (region < it) {
84
+			insert_before(&it->list, &region->list);
85
+			goto coalesce;
86
+		}
87
+	}
88
+
89
+	insert_before(&kmalloc_free_regions, &region->list);
90
+
91
+coalesce:
92
+	coalesce(region);
93
+}
94
+
95
+void *_kmalloc(unsigned int bytes, unsigned int tries);
96
+
97
+void *grow_and_retry(unsigned int bytes, unsigned int tries) {
98
+	struct page *p;
99
+
100
+	if ((p = mm_get_free_pages(curr_page_power))) {
101
+		struct kmalloc_region *region = (struct kmalloc_region *)p->address;
102
+		//TODO don't throw away p, but keep it in a list (allocate a little at the beginning of this chunk for a list element), so we can free pages later if we want to
103
+		region->end = (char *)region + MM_PAGE_SIZE * (1 << curr_page_power) - 1;
104
+		add_region(region);
105
+		curr_page_power++;
106
+		return _kmalloc(bytes, tries);
107
+	}
108
+
109
+	return 0;
110
+}
111
+
112
+void *_kmalloc(unsigned int bytes, unsigned int tries) {
113
+	struct kmalloc_region *region;
114
+
115
+	if (tries > KMALLOC_MAX_TRIES)
116
+		return 0;
117
+
118
+	if (bytes % KMALLOC_MIN_ALIGNMENT)
119
+		bytes += KMALLOC_MIN_ALIGNMENT - (bytes % KMALLOC_MIN_ALIGNMENT);
120
+	
121
+	if ((region = find_free_region(bytes))) {
122
+		//if there's enough space leftover in the region after this allocation
123
+		//for another, split the region.
124
+		if ((unsigned int)((char *)region->end - (char *)region)
125
+				>= 2*KMALLOC_REGION_SIZE + KMALLOC_MIN_ALIGNMENT + bytes) {
126
+			struct kmalloc_region *leftovers;
127
+			leftovers = (struct kmalloc_region *)((char *)region + KMALLOC_REGION_SIZE + bytes);
128
+			leftovers->end = region->end;
129
+			region->end = (char *)leftovers - 1;
130
+			insert_after(&region->list, &leftovers->list);
131
+		}
132
+
133
+		remove(&region->list);
134
+		return (char *)region + KMALLOC_REGION_SIZE;
135
+
136
+	} else {
137
+		return grow_and_retry(bytes, tries + 1);
138
+	}
139
+}
140
+
141
+void *kmalloc(unsigned int bytes) {
142
+	return _kmalloc(bytes, 1);
143
+}
144
+
145
+void kfree(void *p) {
146
+	struct kmalloc_region *region;
147
+
148
+	if (!p) {
149
+		print("Error: kfree was passed a null pointer. Ignoring. This indicates a possible memory leak.\n");
150
+		return;
151
+	}
152
+
153
+	region = (struct kmalloc_region *)((char *)p - KMALLOC_REGION_SIZE);
154
+	add_region(region);
155
+}

+ 44 - 1
kernel/start_kernel.c

@@ -19,6 +19,7 @@
19 19
  */
20 20
 
21 21
 #include <atags.h>
22
+#include <kmalloc.h>
22 23
 #include <mmu.h>
23 24
 #include <mm.h>
24 25
 #include <print.h>
@@ -41,8 +42,11 @@ void video(void) {
41 42
 	console_init(&myfb);
42 43
 }
43 44
 
44
-void test_memory() {
45
+void test_mm() {
45 46
 	struct page *p, *q;
47
+
48
+	print("\ntest_mm():\n");
49
+
46 50
 	p = mm_get_free_pages(0);
47 51
 	if (p)
48 52
 		print("%x, %x\n", p, p->address);
@@ -69,8 +73,46 @@ void test_memory() {
69 73
 		print("%x, %x\n", p, p->address);
70 74
 	else
71 75
 		print("Error: failed to allocate memory for p\n");
76
+	mm_put_free_pages(p);
77
+	mm_put_free_pages(q);
72 78
 
73 79
 }
80
+
81
+void test_kmalloc() {
82
+	void *a, *b, *c, *d;
83
+
84
+	print("\ntest_kmalloc():\n");
85
+
86
+	a = kmalloc(4);
87
+	print("a: %x\n", a);
88
+	b = kmalloc(13);
89
+	print("b: %x\n", b);
90
+	c = kmalloc(4);
91
+	print("c: %x\n", c);
92
+	d = kmalloc(25);
93
+	print("d: %x\n", d);
94
+
95
+	kfree(c);
96
+	kfree(b);
97
+	kfree(a);
98
+	kfree(d);
99
+
100
+	a = kmalloc(13);
101
+	print("a: %x\n", a);
102
+	b = kmalloc(4);
103
+	print("b: %x\n", b);
104
+	c = kmalloc(25);
105
+	print("c: %x\n", c);
106
+	d = kmalloc(7);
107
+	print("d: %x\n", d);
108
+}
109
+
110
+void test_memory() {
111
+	test_mm();
112
+	test_kmalloc();
113
+}
114
+
115
+void kmalloc_init();
74 116
  
75 117
 int main(void) {
76 118
 	char *lower, *upper;
@@ -84,6 +126,7 @@ int main(void) {
84 126
 
85 127
 	//setup memory
86 128
 	mm_init();
129
+	kmalloc_init();
87 130
 
88 131
 	if (atags_first_mem_region(&atags)) {
89 132
 		print("Error: atags must contain at least one memory region\n");