Fix coreboot bios table copying by delaying to after memory scan.
[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 ((s32)(newpos - zone->bottom) < 0)
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     dprintf(3, "malloc setup\n");
178
179     // Memory in 0xf0000 area.
180     memset(BiosTableSpace, 0, CONFIG_MAX_BIOSTABLE);
181     ZoneFSeg.bottom = (u32)BiosTableSpace;
182     ZoneFSeg.top = ZoneFSeg.cur = ZoneFSeg.bottom + CONFIG_MAX_BIOSTABLE;
183
184     // Find memory at the top of ram.
185     u32 top = 0;
186     int i;
187     for (i=e820_count-1; i>=0; i--) {
188         struct e820entry *e = &e820_list[i];
189         u64 end = e->start + e->size;
190         if (e->type != E820_RAM || end > 0xffffffff
191             || e->size < CONFIG_MAX_HIGHTABLE)
192             continue;
193         top = end;
194         break;
195     }
196     if (top < 1024*1024 + CONFIG_MAX_HIGHTABLE) {
197         // No memory above 1Meg
198         memset(&ZoneHigh, 0, sizeof(ZoneHigh));
199         return;
200     }
201     ZoneHigh.bottom = top - CONFIG_MAX_HIGHTABLE;
202     ZoneHigh.top = ZoneHigh.cur = ZoneHigh.bottom + CONFIG_MAX_HIGHTABLE;
203     add_e820(ZoneHigh.bottom, CONFIG_MAX_HIGHTABLE, E820_RESERVED);
204 }
205
206 void
207 malloc_finalize()
208 {
209     dprintf(3, "malloc finalize\n");
210
211     // Give back unused high ram.
212     u32 giveback = (ZoneHigh.cur - ZoneHigh.bottom) / 4096 * 4096;
213     add_e820(ZoneHigh.bottom, giveback, E820_RAM);
214
215     // Report statistics
216     u32 used = ZoneFSeg.top - ZoneFSeg.cur;
217     u32 avail = ZoneFSeg.top - ZoneFSeg.bottom;
218     dprintf(1, "malloc_fseg used=%d (%d%%)\n"
219             , used, (100 * used) / avail);
220     used = ZoneHigh.top - ZoneHigh.cur;
221     avail = ZoneHigh.top - ZoneHigh.bottom;
222     dprintf(1, "malloc_high used=%d (%d%%) (returned %d)\n"
223             , used, (100 * used) / avail, giveback);
224 }