blob: 84bc4faa94650db92a1d03fc964d38e0dd6424f1 [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
8#include "util.h" // dprintf.h
Kevin O'Connor9521e262008-07-04 13:04:29 -04009#include "biosvar.h" // SET_EBDA
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040010
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
43// Show the current e820_list.
44static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -050045dump_map(void)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040046{
47 dprintf(1, "e820 map has %d items:\n", e820_count);
48 int i;
49 for (i=0; i<e820_count; i++) {
50 struct e820entry *e = &e820_list[i];
51 u64 e_end = e->start + e->size;
Kevin O'Connor91b53a72009-05-05 22:52:09 -040052 dprintf(1, " %d: %08x%08x - %08x%08x = %d\n", i
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040053 , (u32)(e->start >> 32), (u32)e->start
54 , (u32)(e_end >> 32), (u32)e_end
55 , e->type);
56 }
57}
58
59// Add a new entry to the list. This scans for overlaps and keeps the
60// list sorted.
61void
62add_e820(u64 start, u64 size, u32 type)
63{
Kevin O'Connor91b53a72009-05-05 22:52:09 -040064 dprintf(8, "Add to e820 map: %08x %08x %d\n", (u32)start, (u32)size, type);
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040065
66 if (! size)
67 // Huh? Nothing to do.
68 return;
69
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -050070 // Find position of new item (splitting existing item if needed).
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040071 u64 end = start + size;
72 int i;
73 for (i=0; i<e820_count; i++) {
74 struct e820entry *e = &e820_list[i];
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040075 u64 e_end = e->start + e->size;
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -040076 if (start > e_end)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040077 continue;
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -050078 // Found position - check if an existing item needs to be split.
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040079 if (start > e->start) {
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -040080 if (type == e->type) {
81 // Same type - merge them.
82 size += start - e->start;
83 start = e->start;
Kevin O'Connor1bedcc02009-04-26 21:25:53 -040084 } else {
85 // Split existing item.
86 e->size = start - e->start;
87 i++;
88 if (e_end > end)
89 insert_e820(i, end, e_end - end, e->type);
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -040090 }
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040091 }
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -050092 break;
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040093 }
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -050094 // Remove/adjust existing items that are overlapping.
95 while (i<e820_count) {
96 struct e820entry *e = &e820_list[i];
97 if (end < e->start)
98 // No overlap - done.
99 break;
100 u64 e_end = e->start + e->size;
101 if (end >= e_end) {
102 // Existing item completely overlapped - remove it.
103 remove_e820(i);
104 continue;
105 }
106 // Not completely overlapped - adjust its start.
107 e->start = end;
Kevin O'Connor1bedcc02009-04-26 21:25:53 -0400108 e->size = e_end - end;
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -0500109 if (type == e->type) {
110 // Same type - merge them.
Kevin O'Connor1bedcc02009-04-26 21:25:53 -0400111 size += e->size;
Kevin O'Connor5d8ec3e2009-02-27 20:19:27 -0500112 remove_e820(i);
113 }
114 break;
115 }
Kevin O'Connor1bedcc02009-04-26 21:25:53 -0400116 // Insert new item.
117 if (type != E820_HOLE)
118 insert_e820(i, start, size, type);
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400119 //dump_map();
120}
121
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400122// Prep for memmap stuff - init bios table locations.
123void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500124memmap_setup(void)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400125{
Kevin O'Connoracf13742008-11-29 11:19:19 -0500126 e820_count = 0;
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400127}
128
Kevin O'Connor9649a962008-12-10 20:53:35 -0500129// Report on final memory locations.
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400130void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500131memmap_finalize(void)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400132{
133 dump_map();
Kevin O'Connor2929c352009-07-25 13:48:27 -0400134}