blob: 9b01c4f7f8ebe0451d945762493ccd4738f2ccb8 [file] [log] [blame]
Martin Roth9b1b3352016-02-24 12:27:06 -08001/* memsize.c - MemTest-86 Version 3.3
2 *
3 * Released under version 2 of the Gnu Public License.
4 * By Chris Brady
5 */
6
7#include "test.h"
8#include "defs.h"
9#include "config.h"
10
11short e820_nr;
12short memsz_mode = SZ_MODE_BIOS;
13
14static ulong alt_mem_k;
15static ulong ext_mem_k;
16static struct e820entry e820[E820MAX];
17
18ulong p1, p2;
19ulong *p;
20
21static void sort_pmap(void);
22//static void memsize_bios(void);
23static void memsize_820(void);
24static void memsize_801(void);
25static int sanitize_e820_map(struct e820entry *orig_map,
Ben Gardner90f7d112016-03-15 15:25:22 -050026 struct e820entry *new_bios, short old_nr);
Martin Roth61ea5412016-03-07 20:58:18 -070027static void memsize_coreboot();
Martin Roth9b1b3352016-02-24 12:27:06 -080028
29/*
30 * Find out how much memory there is.
31 */
32void mem_size(void)
33{
34 int i, flag=0;
35 v->test_pages = 0;
36
37 /* Get the memory size from the BIOS */
Ben Gardner90f7d112016-03-15 15:25:22 -050038 /* Determine the memory map */
Martin Roth8cc1aeb2016-02-24 13:03:52 -080039 if (query_multiboot()) {
Ben Gardner90f7d112016-03-15 15:25:22 -050040 flag = 2;
41 } else if (query_coreboot()) {
Martin Roth9b1b3352016-02-24 12:27:06 -080042 flag = 1;
43 } else if (query_pcbios()) {
44 flag = 2;
45 }
46
47 /* On the first time thru only */
48 /* Make a copy of the memory info table so that we can re-evaluate */
49 /* The memory map later */
50 if (e820_nr == 0 && alt_mem_k == 0 && ext_mem_k == 0) {
51 ext_mem_k = mem_info.e88_mem_k;
52 alt_mem_k = mem_info.e801_mem_k;
53 e820_nr = mem_info.e820_nr;
54 for (i=0; i< mem_info.e820_nr; i++) {
55 e820[i].addr = mem_info.e820[i].addr;
56 e820[i].size = mem_info.e820[i].size;
57 e820[i].type = mem_info.e820[i].type;
58 }
59 }
60 if (flag == 1) {
Martin Roth61ea5412016-03-07 20:58:18 -070061 memsize_coreboot();
Martin Roth9b1b3352016-02-24 12:27:06 -080062 } else if (flag == 2) {
63 memsize_820();
64 }
65
66 /* Guarantee that pmap entries are in ascending order */
67 sort_pmap();
68 v->plim_lower = 0;
69 v->plim_upper = v->pmap[v->msegs-1].end;
70
71 adj_mem();
72}
73
74static void sort_pmap(void)
75{
76 int i, j;
77 /* Do an insertion sort on the pmap, on an already sorted
78 * list this should be a O(1) algorithm.
79 */
Ben Gardner90f7d112016-03-15 15:25:22 -050080 for (i = 0; i < v->msegs; i++) {
Martin Roth9b1b3352016-02-24 12:27:06 -080081 /* Find where to insert the current element */
Ben Gardner90f7d112016-03-15 15:25:22 -050082 for (j = i -1; j >= 0; j--) {
Martin Roth9b1b3352016-02-24 12:27:06 -080083 if (v->pmap[i].start > v->pmap[j].start) {
84 j++;
85 break;
86 }
87 }
88 /* Insert the current element */
89 if (i != j) {
90 struct pmap temp;
91 temp = v->pmap[i];
Martin Roth4dcd13d2016-02-24 13:53:07 -080092 memmove(&v->pmap[j], &v->pmap[j+1],
Ben Gardner90f7d112016-03-15 15:25:22 -050093 (i -j)* sizeof(temp));
Martin Roth9b1b3352016-02-24 12:27:06 -080094 v->pmap[j] = temp;
95 }
96 }
97}
Martin Roth61ea5412016-03-07 20:58:18 -070098static void memsize_coreboot(void)
Martin Roth9b1b3352016-02-24 12:27:06 -080099{
100 int i, n;
101 /* Build the memory map for testing */
102 n = 0;
103 for (i=0; i < e820_nr; i++) {
104 unsigned long long end;
105
106 if (e820[i].type != E820_RAM) {
107 continue;
108 }
109 end = e820[i].addr;
110 end += e820[i].size;
111 v->pmap[n].start = (e820[i].addr + 4095) >> 12;
112 v->pmap[n].end = end >> 12;
113 v->test_pages += v->pmap[n].end - v->pmap[n].start;
114 n++;
115 }
116 v->msegs = n;
117}
Martin Roth69593432016-03-27 19:46:03 -0600118static void memsize_820(void)
Martin Roth9b1b3352016-02-24 12:27:06 -0800119{
120 int i, n, nr;
121 struct e820entry nm[E820MAX];
122 unsigned long long start;
123 unsigned long long end;
124
125 /* Clean up, adjust and copy the BIOS-supplied E820-map. */
126 nr = sanitize_e820_map(e820, nm, e820_nr);
127
128 /* If there is not a good 820 map use the BIOS 801/88 info */
129 if (nr < 1 || nr > E820MAX) {
130 memsize_801();
131 return;
132 }
133
134 /* Build the memory map for testing */
135 n = 0;
136 for (i=0; i<nr; i++) {
137 if (nm[i].type == E820_RAM || nm[i].type == E820_ACPI) {
138 start = nm[i].addr;
139 end = start + nm[i].size;
140
141 /* Don't ever use memory between 640 and 1024k */
142 if (start > RES_START && start < RES_END) {
143 if (end < RES_END) {
144 continue;
145 }
146 start = RES_END;
147 }
148 if (end > RES_START && end < RES_END) {
149 end = RES_START;
150 }
151 v->pmap[n].start = (start + 4095) >> 12;
152 v->pmap[n].end = end >> 12;
153 v->test_pages += v->pmap[n].end - v->pmap[n].start;
154 n++;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800155#if 0
Ben Gardner90f7d112016-03-15 15:25:22 -0500156 int epmap = 0;
157 int lpmap = 0;
158 if (n > 12) { epmap = 34; lpmap = -12; }
159 hprint (11+n+lpmap, 0+epmap, v->pmap[n-1].start);
160 hprint (11+n+lpmap, 10+epmap, v->pmap[n-1].end);
161 hprint (11+n+lpmap, 20+epmap, v->pmap[n-1].end - v->pmap[n-1].start);
162 dprint (11+n+lpmap, 30+epmap, nm[i].type, 0, 0);
Martin Roth4dcd13d2016-02-24 13:53:07 -0800163#endif
Martin Roth9b1b3352016-02-24 12:27:06 -0800164 }
165 }
166 v->msegs = n;
167}
Martin Roth4dcd13d2016-02-24 13:53:07 -0800168
Martin Roth9b1b3352016-02-24 12:27:06 -0800169static void memsize_801(void)
170{
171 ulong mem_size;
172
173 /* compare results from 88 and 801 methods and take the greater */
174 /* These sizes are for extended memory in 1k units. */
175
176 if (alt_mem_k < ext_mem_k) {
177 mem_size = ext_mem_k;
178 } else {
179 mem_size = alt_mem_k;
180 }
181 /* First we map in the first 640k */
182 v->pmap[0].start = 0;
183 v->pmap[0].end = RES_START >> 12;
184 v->test_pages = RES_START >> 12;
185
186 /* Now the extended memory */
187 v->pmap[1].start = (RES_END + 4095) >> 12;
188 v->pmap[1].end = (mem_size + 1024) >> 2;
189 v->test_pages += mem_size >> 2;
190 v->msegs = 2;
191}
192
193/*
194 * Sanitize the BIOS e820 map.
195 *
Martin Roth4dcd13d2016-02-24 13:53:07 -0800196 * Some e820 responses include overlapping entries. The following
Martin Roth9b1b3352016-02-24 12:27:06 -0800197 * replaces the original e820 map with a new one, removing overlaps.
198 *
199 */
200static int sanitize_e820_map(struct e820entry *orig_map, struct e820entry *new_bios,
Ben Gardner90f7d112016-03-15 15:25:22 -0500201 short old_nr)
Martin Roth9b1b3352016-02-24 12:27:06 -0800202{
203 struct change_member {
Ben Gardner90f7d112016-03-15 15:25:22 -0500204 struct e820entry *pbios; /* pointer to original bios entry */
Martin Roth9b1b3352016-02-24 12:27:06 -0800205 unsigned long long addr; /* address for this change point */
206 };
207 struct change_member change_point_list[2*E820MAX];
208 struct change_member *change_point[2*E820MAX];
209 struct e820entry *overlap_list[E820MAX];
210 struct e820entry biosmap[E820MAX];
211 struct change_member *change_tmp;
212 ulong current_type, last_type;
213 unsigned long long last_addr;
214 int chgidx, still_changing;
215 int overlap_entries;
216 int new_bios_entry;
217 int i;
218
219 /*
220 Visually we're performing the following (1,2,3,4 = memory types)...
221 Sample memory map (w/overlaps):
222 ____22__________________
223 ______________________4_
224 ____1111________________
225 _44_____________________
226 11111111________________
227 ____________________33__
228 ___________44___________
229 __________33333_________
230 ______________22________
231 ___________________2222_
232 _________111111111______
233 _____________________11_
234 _________________4______
235
236 Sanitized equivalent (no overlap):
237 1_______________________
238 _44_____________________
239 ___1____________________
240 ____22__________________
241 ______11________________
242 _________1______________
243 __________3_____________
244 ___________44___________
245 _____________33_________
246 _______________2________
247 ________________1_______
248 _________________4______
249 ___________________2____
250 ____________________33__
251 ______________________4_
252 */
253 /* First make a copy of the map */
254 for (i=0; i<old_nr; i++) {
255 biosmap[i].addr = orig_map[i].addr;
256 biosmap[i].size = orig_map[i].size;
257 biosmap[i].type = orig_map[i].type;
258 }
259
260 /* bail out if we find any unreasonable addresses in bios map */
261 for (i=0; i<old_nr; i++) {
262 if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)
263 return 0;
264 }
265
266 /* create pointers for initial change-point information (for sorting) */
267 for (i=0; i < 2*old_nr; i++)
268 change_point[i] = &change_point_list[i];
269
270 /* record all known change-points (starting and ending addresses) */
271 chgidx = 0;
Ben Gardner90f7d112016-03-15 15:25:22 -0500272 for (i=0; i < old_nr; i++) {
Martin Roth9b1b3352016-02-24 12:27:06 -0800273 change_point[chgidx]->addr = biosmap[i].addr;
274 change_point[chgidx++]->pbios = &biosmap[i];
275 change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
276 change_point[chgidx++]->pbios = &biosmap[i];
277 }
278
279 /* sort change-point list by memory addresses (low -> high) */
280 still_changing = 1;
Ben Gardner90f7d112016-03-15 15:25:22 -0500281 while (still_changing) {
Martin Roth9b1b3352016-02-24 12:27:06 -0800282 still_changing = 0;
Ben Gardner90f7d112016-03-15 15:25:22 -0500283 for (i=1; i < 2*old_nr; i++) {
Martin Roth9b1b3352016-02-24 12:27:06 -0800284 /* if <current_addr> > <last_addr>, swap */
285 /* or, if current=<start_addr> & last=<end_addr>, swap */
286 if ((change_point[i]->addr < change_point[i-1]->addr) ||
Ben Gardner90f7d112016-03-15 15:25:22 -0500287 ((change_point[i]->addr == change_point[i-1]->addr) &&
288 (change_point[i]->addr == change_point[i]->pbios->addr) &&
289 (change_point[i-1]->addr != change_point[i-1]->pbios->addr))
290 ) {
Martin Roth9b1b3352016-02-24 12:27:06 -0800291 change_tmp = change_point[i];
292 change_point[i] = change_point[i-1];
293 change_point[i-1] = change_tmp;
294 still_changing=1;
295 }
296 }
297 }
298
299 /* create a new bios memory map, removing overlaps */
Ben Gardner90f7d112016-03-15 15:25:22 -0500300 overlap_entries=0; /* number of entries in the overlap table */
301 new_bios_entry=0; /* index for creating new bios map entries */
302 last_type = 0; /* start with undefined memory type */
303 last_addr = 0; /* start with 0 as last starting address */
Martin Roth9b1b3352016-02-24 12:27:06 -0800304 /* loop through change-points, determining affect on the new bios map */
305 for (chgidx=0; chgidx < 2*old_nr; chgidx++)
306 {
307 /* keep track of all overlapping bios entries */
Ben Gardner90f7d112016-03-15 15:25:22 -0500308 if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr) {
Martin Roth9b1b3352016-02-24 12:27:06 -0800309 /* add map entry to overlap list (> 1 entry implies an overlap) */
310 overlap_list[overlap_entries++]=change_point[chgidx]->pbios;
Ben Gardner90f7d112016-03-15 15:25:22 -0500311 } else {
Martin Roth9b1b3352016-02-24 12:27:06 -0800312 /* remove entry from list (order independent, so swap with last) */
313 for (i=0; i<overlap_entries; i++)
314 {
315 if (overlap_list[i] == change_point[chgidx]->pbios)
316 overlap_list[i] = overlap_list[overlap_entries-1];
317 }
318 overlap_entries--;
319 }
320 /* if there are overlapping entries, decide which "type" to use */
321 /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */
322 current_type = 0;
323 for (i=0; i<overlap_entries; i++)
324 if (overlap_list[i]->type > current_type)
325 current_type = overlap_list[i]->type;
326 /* continue building up new bios map based on this information */
Ben Gardner90f7d112016-03-15 15:25:22 -0500327 if (current_type != last_type) {
328 if (last_type != 0) {
Martin Roth9b1b3352016-02-24 12:27:06 -0800329 new_bios[new_bios_entry].size =
330 change_point[chgidx]->addr - last_addr;
331 /* move forward only if the new size was non-zero */
332 if (new_bios[new_bios_entry].size != 0)
333 if (++new_bios_entry >= E820MAX)
Ben Gardner90f7d112016-03-15 15:25:22 -0500334 break; /* no more space left for new bios entries */
Martin Roth9b1b3352016-02-24 12:27:06 -0800335 }
Ben Gardner90f7d112016-03-15 15:25:22 -0500336 if (current_type != 0) {
Martin Roth9b1b3352016-02-24 12:27:06 -0800337 new_bios[new_bios_entry].addr = change_point[chgidx]->addr;
338 new_bios[new_bios_entry].type = current_type;
339 last_addr=change_point[chgidx]->addr;
340 }
341 last_type = current_type;
342 }
343 }
344 return(new_bios_entry);
345}