blob: 66fba097c5dac2a3e0ca5e8636bcae9829b52272 [file] [log] [blame]
Kevin O'Connor59a23bb2008-06-08 23:09:42 -04001// Support for building memory maps suitable for int 15 e820 calls.
2//
3// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
4//
5// This file may be distributed under the terms of the GNU GPLv3 license.
6
7#include "memmap.h" // struct e820entry
8#include "util.h" // dprintf.h
9
10// Temporary storage used during map building.
11static struct e820entry e820_list[64];
12static int e820_count;
13
14// Remove an entry from the e820_list.
15static void
16remove_e820(int i)
17{
18 e820_count--;
19 memmove(&e820_list[i], &e820_list[i+1]
20 , sizeof(e820_list[0]) * (e820_count - i));
21}
22
23// Insert an entry in the e820_list at the given position.
24static void
25insert_e820(int i, u64 start, u64 size, u32 type)
26{
27 if (e820_count >= ARRAY_SIZE(e820_list)) {
28 dprintf(1, "Overflowed e820 list!\n");
29 return;
30 }
31
32 memmove(&e820_list[i+1], &e820_list[i]
33 , sizeof(e820_list[0]) * (e820_count - i));
34 e820_count++;
35 struct e820entry *e = &e820_list[i];
36 e->start = start;
37 e->size = size;
38 e->type = type;
39}
40
41// Show the current e820_list.
42static void
43dump_map()
44{
45 dprintf(1, "e820 map has %d items:\n", e820_count);
46 int i;
47 for (i=0; i<e820_count; i++) {
48 struct e820entry *e = &e820_list[i];
49 u64 e_end = e->start + e->size;
50 dprintf(1, " %d: %x%x - %x%x = %d\n", i
51 , (u32)(e->start >> 32), (u32)e->start
52 , (u32)(e_end >> 32), (u32)e_end
53 , e->type);
54 }
55}
56
57// Add a new entry to the list. This scans for overlaps and keeps the
58// list sorted.
59void
60add_e820(u64 start, u64 size, u32 type)
61{
62 dprintf(8, "Add to e820 map: %x %x %d\n", (u32)start, (u32)size, type);
63
64 if (! size)
65 // Huh? Nothing to do.
66 return;
67
68 u64 end = start + size;
69 int i;
70 for (i=0; i<e820_count; i++) {
71 struct e820entry *e = &e820_list[i];
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -040072 if (end < e->start)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040073 // Simple insertion point.
74 break;
75 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 // No overlap.
78 continue;
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -040079 // New item overlaps (or borders) an existing one.
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040080 if (start > e->start) {
81 e->size = start - e->start;
82 i++;
83 if (end < e_end)
84 // Need to split existing item
85 insert_e820(i, end, e_end - end, e->type);
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -040086 if (type == e->type) {
87 // Same type - merge them.
88 size += start - e->start;
89 start = e->start;
90 i--;
91 remove_e820(i);
92 }
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040093 }
94 insert_e820(i, start, size, type);
95 i++;
96 // Remove all existing items that are completely overlapped.
97 while (i<e820_count) {
98 e = &e820_list[i];
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -040099 if (end < e->start)
100 // No overlap - done.
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400101 break;
102 e_end = e->start + e->size;
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -0400103 if (end >= e_end) {
104 // Existing item completely overlapped - remove it.
105 remove_e820(i);
106 continue;
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400107 }
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -0400108 // Not completely overlapped - adjust its start.
109 e->start = end;
110 e->size = e_end - e->start;
111 if (type == e->type) {
112 // Same type - merge them.
113 (e-1)->size += e->size;
114 remove_e820(i);
115 }
116 break;
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400117 }
118 //dump_map();
119 return;
120 }
121 // Just insert item.
122 insert_e820(i, start, size, type);
123 //dump_map();
124}
125
126u32 bios_table_cur_addr, bios_table_end_addr;
127
128// Prep for memmap stuff - init bios table locations.
129void
130memmap_setup()
131{
132 bios_table_cur_addr = 0xf0000 | OFFSET_freespace2_start;
133 bios_table_end_addr = 0xf0000 | OFFSET_freespace2_end;
134 dprintf(1, "bios_table_addr: 0x%08x end=0x%08x\n",
135 bios_table_cur_addr, bios_table_end_addr);
136}
137
138// Copy the temporary e820 map info to its permanent location.
139void
140memmap_finalize()
141{
142 dump_map();
143
144 u32 msize = e820_count * sizeof(e820_list[0]);
145 if (bios_table_cur_addr + msize > bios_table_end_addr) {
146 dprintf(1, "No room for e820 map!\n");
147 return;
148 }
149 memcpy((void*)bios_table_cur_addr, e820_list, msize);
150 SET_EBDA(e820_loc, bios_table_cur_addr);
151 SET_EBDA(e820_count, e820_count);
152 bios_table_cur_addr += msize;
153}