grml...
[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         warn_noalloc();
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 static const char *
44 e820_type_name(u32 type)
45 {
46         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         }
55 }
56
57 // Show the current e820_list.
58 static void
59 dump_map(void)
60 {
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;
66         dprintf(1, "  %d: %08x%08x - %08x%08x = %d %s\n", i
67                 , (u32)(e->start >> 32), (u32)e->start
68                 , (u32)(e_end >> 32), (u32)e_end
69                 , e->type, e820_type_name(e->type));
70     }
71 }
72
73 // Add a new entry to the list.  This scans for overlaps and keeps the
74 // list sorted.
75 void
76 add_e820(u64 start, u64 size, u32 type)
77 {
78     dprintf(8, "Add to e820 map: %08x %08x %d\n", (u32)start, (u32)size, type);
79
80     if (! size)
81         // Huh?  Nothing to do.
82         return;
83
84     // Find position of new item (splitting existing item if needed).
85     u64 end = start + size;
86     int i;
87     for (i=0; i<e820_count; i++) {
88         struct e820entry *e = &e820_list[i];
89         u64 e_end = e->start + e->size;
90         if (start > e_end)
91             continue;
92         // Found position - check if an existing item needs to be split.
93         if (start > e->start) {
94             if (type == e->type) {
95                 // Same type - merge them.
96                 size += start - e->start;
97                 start = e->start;
98             } else {
99                 // Split existing item.
100                 e->size = start - e->start;
101                 i++;
102                 if (e_end > end)
103                     insert_e820(i, end, e_end - end, e->type);
104             }
105         }
106         break;
107     }
108     // Remove/adjust existing items that are overlapping.
109     while (i<e820_count) {
110         struct e820entry *e = &e820_list[i];
111         if (end < e->start)
112             // No overlap - done.
113             break;
114         u64 e_end = e->start + e->size;
115         if (end >= e_end) {
116             // Existing item completely overlapped - remove it.
117             remove_e820(i);
118             continue;
119         }
120         // Not completely overlapped - adjust its start.
121         e->start = end;
122         e->size = e_end - end;
123         if (type == e->type) {
124             // Same type - merge them.
125             size += e->size;
126             remove_e820(i);
127         }
128         break;
129     }
130     // Insert new item.
131     if (type != E820_HOLE)
132         insert_e820(i, start, size, type);
133     //dump_map();
134 }
135
136 // Report on final memory locations.
137 void
138 memmap_finalize(void)
139 {
140     dump_map();
141 }