debuggers.hg

view xen/arch/x86/e820.c @ 3674:fb875591fd72

bitkeeper revision 1.1159.223.63 (42028527-fv-d9BM0_LRp8UKGP19gQ)

Fix NMI deferral.
Signed-off-by: keir.fraser@cl.cam.ac.uk
author kaf24@scramble.cl.cam.ac.uk
date Thu Feb 03 20:10:15 2005 +0000 (2005-02-03)
parents af362b7301a0
children 023c30e91254 0dc3b8b8c298
line source
1 #include <xen/config.h>
2 #include <xen/init.h>
3 #include <xen/lib.h>
4 #include <asm/e820.h>
6 struct e820map e820;
8 static void __init add_memory_region(unsigned long long start,
9 unsigned long long size, int type)
10 {
11 int x;
13 /*if (!efi_enabled)*/ {
14 x = e820.nr_map;
16 if (x == E820MAX) {
17 printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
18 return;
19 }
21 e820.map[x].addr = start;
22 e820.map[x].size = size;
23 e820.map[x].type = type;
24 e820.nr_map++;
25 }
26 } /* add_memory_region */
28 #define E820_DEBUG 1
30 static void __init print_memory_map(void)
31 {
32 int i;
34 for (i = 0; i < e820.nr_map; i++) {
35 printk(" %016Lx - %016Lx ",
36 e820.map[i].addr,
37 e820.map[i].addr + e820.map[i].size);
38 switch (e820.map[i].type) {
39 case E820_RAM: printk("(usable)\n");
40 break;
41 case E820_RESERVED:
42 printk("(reserved)\n");
43 break;
44 case E820_ACPI:
45 printk("(ACPI data)\n");
46 break;
47 case E820_NVS:
48 printk("(ACPI NVS)\n");
49 break;
50 default: printk("type %u\n", e820.map[i].type);
51 break;
52 }
53 }
54 }
56 /*
57 * Sanitize the BIOS e820 map.
58 *
59 * Some e820 responses include overlapping entries. The following
60 * replaces the original e820 map with a new one, removing overlaps.
61 *
62 */
63 struct change_member {
64 struct e820entry *pbios; /* pointer to original bios entry */
65 unsigned long long addr; /* address for this change point */
66 };
67 static struct change_member change_point_list[2*E820MAX] __initdata;
68 static struct change_member *change_point[2*E820MAX] __initdata;
69 static struct e820entry *overlap_list[E820MAX] __initdata;
70 static struct e820entry new_bios[E820MAX] __initdata;
72 static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
73 {
74 struct change_member *change_tmp;
75 unsigned long current_type, last_type;
76 unsigned long long last_addr;
77 int chgidx, still_changing;
78 int overlap_entries;
79 int new_bios_entry;
80 int old_nr, new_nr, chg_nr;
81 int i;
83 /*
84 Visually we're performing the following (1,2,3,4 = memory types)...
86 Sample memory map (w/overlaps):
87 ____22__________________
88 ______________________4_
89 ____1111________________
90 _44_____________________
91 11111111________________
92 ____________________33__
93 ___________44___________
94 __________33333_________
95 ______________22________
96 ___________________2222_
97 _________111111111______
98 _____________________11_
99 _________________4______
101 Sanitized equivalent (no overlap):
102 1_______________________
103 _44_____________________
104 ___1____________________
105 ____22__________________
106 ______11________________
107 _________1______________
108 __________3_____________
109 ___________44___________
110 _____________33_________
111 _______________2________
112 ________________1_______
113 _________________4______
114 ___________________2____
115 ____________________33__
116 ______________________4_
117 */
119 /* if there's only one memory region, don't bother */
120 if (*pnr_map < 2)
121 return -1;
123 old_nr = *pnr_map;
125 /* bail out if we find any unreasonable addresses in bios map */
126 for (i=0; i<old_nr; i++)
127 if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)
128 return -1;
130 /* create pointers for initial change-point information (for sorting) */
131 for (i=0; i < 2*old_nr; i++)
132 change_point[i] = &change_point_list[i];
134 /* record all known change-points (starting and ending addresses),
135 omitting those that are for empty memory regions */
136 chgidx = 0;
137 for (i=0; i < old_nr; i++) {
138 if (biosmap[i].size != 0) {
139 change_point[chgidx]->addr = biosmap[i].addr;
140 change_point[chgidx++]->pbios = &biosmap[i];
141 change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
142 change_point[chgidx++]->pbios = &biosmap[i];
143 }
144 }
145 chg_nr = chgidx; /* true number of change-points */
147 /* sort change-point list by memory addresses (low -> high) */
148 still_changing = 1;
149 while (still_changing) {
150 still_changing = 0;
151 for (i=1; i < chg_nr; i++) {
152 /* if <current_addr> > <last_addr>, swap */
153 /* or, if current=<start_addr> & last=<end_addr>, swap */
154 if ((change_point[i]->addr < change_point[i-1]->addr) ||
155 ((change_point[i]->addr == change_point[i-1]->addr) &&
156 (change_point[i]->addr == change_point[i]->pbios->addr) &&
157 (change_point[i-1]->addr != change_point[i-1]->pbios->addr))
158 )
159 {
160 change_tmp = change_point[i];
161 change_point[i] = change_point[i-1];
162 change_point[i-1] = change_tmp;
163 still_changing=1;
164 }
165 }
166 }
168 /* create a new bios memory map, removing overlaps */
169 overlap_entries=0; /* number of entries in the overlap table */
170 new_bios_entry=0; /* index for creating new bios map entries */
171 last_type = 0; /* start with undefined memory type */
172 last_addr = 0; /* start with 0 as last starting address */
173 /* loop through change-points, determining affect on the new bios map */
174 for (chgidx=0; chgidx < chg_nr; chgidx++)
175 {
176 /* keep track of all overlapping bios entries */
177 if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
178 {
179 /* add map entry to overlap list (> 1 entry implies an overlap) */
180 overlap_list[overlap_entries++]=change_point[chgidx]->pbios;
181 }
182 else
183 {
184 /* remove entry from list (order independent, so swap with last) */
185 for (i=0; i<overlap_entries; i++)
186 {
187 if (overlap_list[i] == change_point[chgidx]->pbios)
188 overlap_list[i] = overlap_list[overlap_entries-1];
189 }
190 overlap_entries--;
191 }
192 /* if there are overlapping entries, decide which "type" to use */
193 /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */
194 current_type = 0;
195 for (i=0; i<overlap_entries; i++)
196 if (overlap_list[i]->type > current_type)
197 current_type = overlap_list[i]->type;
198 /* continue building up new bios map based on this information */
199 if (current_type != last_type) {
200 if (last_type != 0) {
201 new_bios[new_bios_entry].size =
202 change_point[chgidx]->addr - last_addr;
203 /* move forward only if the new size was non-zero */
204 if (new_bios[new_bios_entry].size != 0)
205 if (++new_bios_entry >= E820MAX)
206 break; /* no more space left for new bios entries */
207 }
208 if (current_type != 0) {
209 new_bios[new_bios_entry].addr = change_point[chgidx]->addr;
210 new_bios[new_bios_entry].type = current_type;
211 last_addr=change_point[chgidx]->addr;
212 }
213 last_type = current_type;
214 }
215 }
216 new_nr = new_bios_entry; /* retain count for new bios entries */
218 /* copy new bios mapping into original location */
219 memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
220 *pnr_map = new_nr;
222 return 0;
223 }
225 /*
226 * Copy the BIOS e820 map into a safe place.
227 *
228 * Sanity-check it while we're at it..
229 *
230 * If we're lucky and live on a modern system, the setup code
231 * will have given us a memory map that we can use to properly
232 * set up memory. If we aren't, we'll fake a memory map.
233 *
234 * We check to see that the memory map contains at least 2 elements
235 * before we'll use it, because the detection code in setup.S may
236 * not be perfect and most every PC known to man has two memory
237 * regions: one from 0 to 640k, and one from 1mb up. (The IBM
238 * thinkpad 560x, for example, does not cooperate with the memory
239 * detection code.)
240 */
241 static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
242 {
243 /* Only one memory region (or negative)? Ignore it */
244 if (nr_map < 2)
245 return -1;
247 do {
248 unsigned long long start = biosmap->addr;
249 unsigned long long size = biosmap->size;
250 unsigned long long end = start + size;
251 unsigned long type = biosmap->type;
253 /* Overflow in 64 bits? Ignore the memory map. */
254 if (start > end)
255 return -1;
257 /*
258 * Some BIOSes claim RAM in the 640k - 1M region.
259 * Not right. Fix it up.
260 */
261 if (type == E820_RAM) {
262 if (start < 0x100000ULL && end > 0xA0000ULL) {
263 if (start < 0xA0000ULL)
264 add_memory_region(start, 0xA0000ULL-start, type);
265 if (end <= 0x100000ULL)
266 continue;
267 start = 0x100000ULL;
268 size = end - start;
269 }
270 }
271 add_memory_region(start, size, type);
272 } while (biosmap++,--nr_map);
273 return 0;
274 }
277 /*
278 * Find the highest page frame number we have available
279 */
280 static unsigned long __init find_max_pfn(void)
281 {
282 int i;
283 unsigned long max_pfn = 0;
285 #if 0
286 if (efi_enabled) {
287 efi_memmap_walk(efi_find_max_pfn, &max_pfn);
288 return;
289 }
290 #endif
292 for (i = 0; i < e820.nr_map; i++) {
293 unsigned long start, end;
294 /* RAM? */
295 if (e820.map[i].type != E820_RAM)
296 continue;
297 start = PFN_UP(e820.map[i].addr);
298 end = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
299 if (start >= end)
300 continue;
301 if (end > max_pfn)
302 max_pfn = end;
303 }
305 return max_pfn;
306 }
308 static void __init machine_specific_memory_setup(
309 struct e820entry *raw, int raw_nr)
310 {
311 char nr = (char)raw_nr;
312 int i;
314 sanitize_e820_map(raw, &nr);
316 (void)copy_e820_map(raw, nr);
318 #ifdef __i386__
319 /* 32-bit systems restricted to a 4GB physical memory map. */
320 for ( i = 0; i < e820.nr_map; i++ )
321 {
322 if ( (e820.map[i].addr + e820.map[i].size) <= 0x100000000ULL )
323 continue;
324 printk("WARNING: Only the first 4GB of the physical memory map "
325 "can be accessed\n"
326 " by Xen in 32-bit mode. "
327 "Truncating the memory map...\n");
328 if ( e820.map[i].addr >= 0x100000000ULL )
329 {
330 e820.nr_map = i;
331 }
332 else
333 {
334 e820.map[i].size = 0x100000000ULL - e820.map[i].addr;
335 e820.nr_map = i + 1;
336 }
337 }
338 #endif
339 }
341 unsigned long init_e820(struct e820entry *raw, int raw_nr)
342 {
343 machine_specific_memory_setup(raw, raw_nr);
344 printk(KERN_INFO "Physical RAM map:\n");
345 print_memory_map();
346 return find_max_pfn();
347 }