Update TODO items.
[seabios.git] / src / memmap.c
1 // Support for building memory maps suitable for int 15 e820 calls.
2 //
3 // Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
4 //
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
6
7 #include "memmap.h" // struct e820entry
8 #include "util.h" // dprintf.h
9 #include "biosvar.h" // SET_EBDA
10
11
12 /****************************************************************
13  * e820 memory map
14  ****************************************************************/
15
16 // Remove an entry from the e820_list.
17 static void
18 remove_e820(int i)
19 {
20     e820_count--;
21     memmove(&e820_list[i], &e820_list[i+1]
22             , sizeof(e820_list[0]) * (e820_count - i));
23 }
24
25 // Insert an entry in the e820_list at the given position.
26 static void
27 insert_e820(int i, u64 start, u64 size, u32 type)
28 {
29     if (e820_count >= CONFIG_MAX_E820) {
30         dprintf(1, "Overflowed e820 list!\n");
31         return;
32     }
33
34     memmove(&e820_list[i+1], &e820_list[i]
35             , sizeof(e820_list[0]) * (e820_count - i));
36     e820_count++;
37     struct e820entry *e = &e820_list[i];
38     e->start = start;
39     e->size = size;
40     e->type = type;
41 }
42
43 // Show the current e820_list.
44 static void
45 dump_map()
46 {
47     dprintf(1, "e820 map has %d items:\n", e820_count);
48     int i;
49     for (i=0; i<e820_count; i++) {
50         struct e820entry *e = &e820_list[i];
51         u64 e_end = e->start + e->size;
52         dprintf(1, "  %d: %08x%08x - %08x%08x = %d\n", i
53                 , (u32)(e->start >> 32), (u32)e->start
54                 , (u32)(e_end >> 32), (u32)e_end
55                 , e->type);
56     }
57 }
58
59 // Add a new entry to the list.  This scans for overlaps and keeps the
60 // list sorted.
61 void
62 add_e820(u64 start, u64 size, u32 type)
63 {
64     dprintf(8, "Add to e820 map: %08x %08x %d\n", (u32)start, (u32)size, type);
65
66     if (! size)
67         // Huh?  Nothing to do.
68         return;
69
70     // Find position of new item (splitting existing item if needed).
71     u64 end = start + size;
72     int i;
73     for (i=0; i<e820_count; i++) {
74         struct e820entry *e = &e820_list[i];
75         u64 e_end = e->start + e->size;
76         if (start > e_end)
77             continue;
78         // Found position - check if an existing item needs to be split.
79         if (start > e->start) {
80             if (type == e->type) {
81                 // Same type - merge them.
82                 size += start - e->start;
83                 start = e->start;
84             } else {
85                 // Split existing item.
86                 e->size = start - e->start;
87                 i++;
88                 if (e_end > end)
89                     insert_e820(i, end, e_end - end, e->type);
90             }
91         }
92         break;
93     }
94     // Remove/adjust existing items that are overlapping.
95     while (i<e820_count) {
96         struct e820entry *e = &e820_list[i];
97         if (end < e->start)
98             // No overlap - done.
99             break;
100         u64 e_end = e->start + e->size;
101         if (end >= e_end) {
102             // Existing item completely overlapped - remove it.
103             remove_e820(i);
104             continue;
105         }
106         // Not completely overlapped - adjust its start.
107         e->start = end;
108         e->size = e_end - end;
109         if (type == e->type) {
110             // Same type - merge them.
111             size += e->size;
112             remove_e820(i);
113         }
114         break;
115     }
116     // Insert new item.
117     if (type != E820_HOLE)
118         insert_e820(i, start, size, type);
119     //dump_map();
120 }
121
122 // Prep for memmap stuff - init bios table locations.
123 void
124 memmap_setup()
125 {
126     e820_count = 0;
127 }
128
129 // Report on final memory locations.
130 void
131 memmap_finalize()
132 {
133     dump_map();
134 }
135
136
137 /****************************************************************
138  * malloc
139  ****************************************************************/
140
141 #define MINALIGN 16
142
143 struct zone_s {
144     u32 top, bottom, cur;
145 };
146
147 static struct zone_s ZoneHigh, ZoneFSeg;
148
149 static void *
150 __malloc(struct zone_s *zone, u32 size)
151 {
152     u32 newpos = (zone->cur - size) / MINALIGN * MINALIGN;
153     if (newpos < zone->bottom)
154         // No space
155         return NULL;
156     zone->cur = newpos;
157     return (void*)newpos;
158 }
159
160 // Allocate memory at the top of 32bit ram.
161 void *
162 malloc_high(u32 size)
163 {
164     return __malloc(&ZoneHigh, size);
165 }
166
167 // Allocate memory in the 0xf0000-0x100000 area of ram.
168 void *
169 malloc_fseg(u32 size)
170 {
171     return __malloc(&ZoneFSeg, size);
172 }
173
174 void
175 malloc_setup()
176 {
177     // Memory in 0xf0000 area.
178     memset(BiosTableSpace, 0, CONFIG_MAX_BIOSTABLE);
179     ZoneFSeg.bottom = (u32)BiosTableSpace;
180     ZoneFSeg.top = ZoneFSeg.cur = ZoneFSeg.bottom + CONFIG_MAX_BIOSTABLE;
181
182     // Find memory at the top of ram.
183     u32 top = 0;
184     int i;
185     for (i=e820_count-1; i>=0; i--) {
186         struct e820entry *e = &e820_list[i];
187         u64 end = e->start + e->size;
188         if (e->type != E820_RAM || end > 0xffffffff)
189             continue;
190         top = end;
191         break;
192     }
193     if (top < 1024*1024 + CONFIG_MAX_HIGHTABLE) {
194         // No memory above 1Meg
195         memset(&ZoneHigh, 0, sizeof(ZoneHigh));
196         return;
197     }
198     ZoneHigh.bottom = top - CONFIG_MAX_HIGHTABLE;
199     ZoneHigh.top = ZoneHigh.cur = ZoneHigh.bottom + CONFIG_MAX_HIGHTABLE;
200     add_e820(ZoneHigh.bottom, CONFIG_MAX_HIGHTABLE, E820_RESERVED);
201 }
202
203 void
204 malloc_finalize()
205 {
206     // Give back unused high ram.
207     u32 giveback = (ZoneHigh.cur - ZoneHigh.bottom) / 4096 * 4096;
208     add_e820(ZoneHigh.bottom, giveback, E820_RAM);
209
210     // Report statistics
211     u32 used = ZoneFSeg.top - ZoneFSeg.cur;
212     u32 avail = ZoneFSeg.top - ZoneFSeg.bottom;
213     dprintf(1, "malloc_fseg used=%d (%d%%)\n"
214             , used, (100 * used) / avail);
215     used = ZoneHigh.top - ZoneHigh.cur;
216     avail = ZoneHigh.top - ZoneHigh.bottom;
217     dprintf(1, "malloc_high used=%d (%d%%) (returned %d)\n"
218             , used, (100 * used) / avail, giveback);
219 }