blob: 3783518900256a0fb12646da3f30e8b2dd2120c7 [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'Connor59a23bb2008-06-08 23:09:42 -040016// Remove an entry from the e820_list.
17static void
18remove_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.
26static void
27insert_e820(int i, u64 start, u64 size, u32 type)
28{
Kevin O'Connord995b3d2008-11-08 13:05:27 -050029 if (e820_count >= CONFIG_MAX_E820) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -050030 warn_noalloc();
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040031 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
Ian Campbell1f4e8622011-05-13 16:30:55 +010043static const char *
44e820_type_name(u32 type)
45{
Kevin O'Connor7a08ae72012-03-14 21:11:39 -040046 switch (type) {
47 case E820_RAM: return "RAM";
48 case E820_RESERVED: return "RESERVED";
49 case E820_ACPI: return "ACPI";
50 case E820_NVS: return "NVS";
51 case E820_UNUSABLE: return "UNUSABLE";
52 case E820_HOLE: return "HOLE";
53 default: return "UNKNOWN";
54 }
Ian Campbell1f4e8622011-05-13 16:30:55 +010055}
56
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040057// Show the current e820_list.
58static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -050059dump_map(void)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040060{
61 dprintf(1, "e820 map has %d items:\n", e820_count);
62 int i;
63 for (i=0; i<e820_count; i++) {
64 struct e820entry *e = &e820_list[i];
65 u64 e_end = e->start + e->size;
Kevin O'Connorc04090d2012-03-05 10:14:07 -050066 dprintf(1, " %d: %016llx - %016llx = %d %s\n", i
67 , e->start, e_end, e->type, e820_type_name(e->type));
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040068 }
69}
70
71// Add a new entry to the list. This scans for overlaps and keeps the
72// list sorted.
73void
74add_e820(u64 start, u64 size, u32 type)
75{
Kevin O'Connor91b53a72009-05-05 22:52:09 -040076 dprintf(8, "Add to e820 map: %08x %08x %d\n", (u32)start, (u32)size, type);
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040077
78 if (! size)
79 // Huh? Nothing to do.
80 return;
81
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -050082 // Find position of new item (splitting existing item if needed).
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040083 u64 end = start + size;
84 int i;
85 for (i=0; i<e820_count; i++) {
86 struct e820entry *e = &e820_list[i];
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040087 u64 e_end = e->start + e->size;
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -040088 if (start > e_end)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040089 continue;
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -050090 // Found position - check if an existing item needs to be split.
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040091 if (start > e->start) {
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -040092 if (type == e->type) {
93 // Same type - merge them.
94 size += start - e->start;
95 start = e->start;
Kevin O'Connor1bedcc02009-04-26 21:25:53 -040096 } else {
97 // Split existing item.
98 e->size = start - e->start;
99 i++;
100 if (e_end > end)
101 insert_e820(i, end, e_end - end, e->type);
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -0400102 }
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400103 }
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -0500104 break;
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400105 }
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -0500106 // Remove/adjust existing items that are overlapping.
107 while (i<e820_count) {
108 struct e820entry *e = &e820_list[i];
109 if (end < e->start)
110 // No overlap - done.
111 break;
112 u64 e_end = e->start + e->size;
113 if (end >= e_end) {
114 // Existing item completely overlapped - remove it.
115 remove_e820(i);
116 continue;
117 }
118 // Not completely overlapped - adjust its start.
119 e->start = end;
Kevin O'Connor1bedcc02009-04-26 21:25:53 -0400120 e->size = e_end - end;
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -0500121 if (type == e->type) {
122 // Same type - merge them.
Kevin O'Connor1bedcc02009-04-26 21:25:53 -0400123 size += e->size;
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -0500124 remove_e820(i);
125 }
126 break;
127 }
Kevin O'Connor1bedcc02009-04-26 21:25:53 -0400128 // Insert new item.
129 if (type != E820_HOLE)
130 insert_e820(i, start, size, type);
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400131 //dump_map();
132}
133
Kevin O'Connor9649a962008-12-10 20:53:35 -0500134// Report on final memory locations.
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400135void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500136memmap_finalize(void)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400137{
138 dump_map();
Kevin O'Connor2929c352009-07-25 13:48:27 -0400139}