blob: f029ce2496ac16670bbee3affc71fd9a7b05f73d [file] [log] [blame]
Kevin O'Connor59a23bb2008-06-08 23:09:42 -04001// Support for building memory maps suitable for int 15 e820 calls.
2//
Kevin O'Connor2929c352009-07-25 13:48:27 -04003// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
Kevin O'Connor59a23bb2008-06-08 23:09:42 -04004//
Kevin O'Connorb1b7c2a2009-01-15 20:52:58 -05005// This file may be distributed under the terms of the GNU LGPLv3 license.
Kevin O'Connor59a23bb2008-06-08 23:09:42 -04006
7#include "memmap.h" // struct e820entry
Kevin O'Connor4bc49972012-05-13 22:58:08 -04008#include "config.h" // CONFIG_*
Kevin O'Connor59a23bb2008-06-08 23:09:42 -04009#include "util.h" // dprintf.h
10
Kevin O'Connor2929c352009-07-25 13:48:27 -040011
12/****************************************************************
13 * e820 memory map
14 ****************************************************************/
15
Kevin O'Connor89a2f962013-02-18 23:36:03 -050016// Info on e820 map location and size.
17struct e820entry e820_list[CONFIG_MAX_E820] VARFSEG;
18int e820_count VARFSEG;
19
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040020// Remove an entry from the e820_list.
21static void
22remove_e820(int i)
23{
24 e820_count--;
25 memmove(&e820_list[i], &e820_list[i+1]
26 , sizeof(e820_list[0]) * (e820_count - i));
27}
28
29// Insert an entry in the e820_list at the given position.
30static void
31insert_e820(int i, u64 start, u64 size, u32 type)
32{
Kevin O'Connord995b3d2008-11-08 13:05:27 -050033 if (e820_count >= CONFIG_MAX_E820) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -050034 warn_noalloc();
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040035 return;
36 }
37
38 memmove(&e820_list[i+1], &e820_list[i]
39 , sizeof(e820_list[0]) * (e820_count - i));
40 e820_count++;
41 struct e820entry *e = &e820_list[i];
42 e->start = start;
43 e->size = size;
44 e->type = type;
45}
46
Ian Campbell1f4e8622011-05-13 16:30:55 +010047static const char *
48e820_type_name(u32 type)
49{
Kevin O'Connor7a08ae72012-03-14 21:11:39 -040050 switch (type) {
51 case E820_RAM: return "RAM";
52 case E820_RESERVED: return "RESERVED";
53 case E820_ACPI: return "ACPI";
54 case E820_NVS: return "NVS";
55 case E820_UNUSABLE: return "UNUSABLE";
56 case E820_HOLE: return "HOLE";
57 default: return "UNKNOWN";
58 }
Ian Campbell1f4e8622011-05-13 16:30:55 +010059}
60
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040061// Show the current e820_list.
62static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -050063dump_map(void)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040064{
65 dprintf(1, "e820 map has %d items:\n", e820_count);
66 int i;
67 for (i=0; i<e820_count; i++) {
68 struct e820entry *e = &e820_list[i];
69 u64 e_end = e->start + e->size;
Kevin O'Connorc04090d2012-03-05 10:14:07 -050070 dprintf(1, " %d: %016llx - %016llx = %d %s\n", i
71 , e->start, e_end, e->type, e820_type_name(e->type));
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040072 }
73}
74
75// Add a new entry to the list. This scans for overlaps and keeps the
76// list sorted.
77void
78add_e820(u64 start, u64 size, u32 type)
79{
Kevin O'Connor91b53a72009-05-05 22:52:09 -040080 dprintf(8, "Add to e820 map: %08x %08x %d\n", (u32)start, (u32)size, type);
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040081
82 if (! size)
83 // Huh? Nothing to do.
84 return;
85
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -050086 // Find position of new item (splitting existing item if needed).
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040087 u64 end = start + size;
88 int i;
89 for (i=0; i<e820_count; i++) {
90 struct e820entry *e = &e820_list[i];
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040091 u64 e_end = e->start + e->size;
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -040092 if (start > e_end)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040093 continue;
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -050094 // Found position - check if an existing item needs to be split.
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040095 if (start > e->start) {
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -040096 if (type == e->type) {
97 // Same type - merge them.
98 size += start - e->start;
99 start = e->start;
Kevin O'Connor1bedcc02009-04-26 21:25:53 -0400100 } else {
101 // Split existing item.
102 e->size = start - e->start;
103 i++;
104 if (e_end > end)
105 insert_e820(i, end, e_end - end, e->type);
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -0400106 }
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400107 }
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -0500108 break;
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400109 }
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -0500110 // Remove/adjust existing items that are overlapping.
111 while (i<e820_count) {
112 struct e820entry *e = &e820_list[i];
113 if (end < e->start)
114 // No overlap - done.
115 break;
116 u64 e_end = e->start + e->size;
117 if (end >= e_end) {
118 // Existing item completely overlapped - remove it.
119 remove_e820(i);
120 continue;
121 }
122 // Not completely overlapped - adjust its start.
123 e->start = end;
Kevin O'Connor1bedcc02009-04-26 21:25:53 -0400124 e->size = e_end - end;
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -0500125 if (type == e->type) {
126 // Same type - merge them.
Kevin O'Connor1bedcc02009-04-26 21:25:53 -0400127 size += e->size;
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -0500128 remove_e820(i);
129 }
130 break;
131 }
Kevin O'Connor1bedcc02009-04-26 21:25:53 -0400132 // Insert new item.
133 if (type != E820_HOLE)
134 insert_e820(i, start, size, type);
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400135 //dump_map();
136}
137
Kevin O'Connor9649a962008-12-10 20:53:35 -0500138// Report on final memory locations.
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400139void
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500140memmap_prepboot(void)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400141{
142 dump_map();
Kevin O'Connor2929c352009-07-25 13:48:27 -0400143}