blob: 67f10e89db10b8864022c2d034c7e14add023225 [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
Kevin O'Connor9521e262008-07-04 13:04:29 -04009#include "biosvar.h" // SET_EBDA
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040010
11// Temporary storage used during map building.
12static struct e820entry e820_list[64];
13static int e820_count;
14
15// Remove an entry from the e820_list.
16static void
17remove_e820(int i)
18{
19 e820_count--;
20 memmove(&e820_list[i], &e820_list[i+1]
21 , sizeof(e820_list[0]) * (e820_count - i));
22}
23
24// Insert an entry in the e820_list at the given position.
25static void
26insert_e820(int i, u64 start, u64 size, u32 type)
27{
28 if (e820_count >= ARRAY_SIZE(e820_list)) {
29 dprintf(1, "Overflowed e820 list!\n");
30 return;
31 }
32
33 memmove(&e820_list[i+1], &e820_list[i]
34 , sizeof(e820_list[0]) * (e820_count - i));
35 e820_count++;
36 struct e820entry *e = &e820_list[i];
37 e->start = start;
38 e->size = size;
39 e->type = type;
40}
41
42// Show the current e820_list.
43static void
44dump_map()
45{
46 dprintf(1, "e820 map has %d items:\n", e820_count);
47 int i;
48 for (i=0; i<e820_count; i++) {
49 struct e820entry *e = &e820_list[i];
50 u64 e_end = e->start + e->size;
51 dprintf(1, " %d: %x%x - %x%x = %d\n", i
52 , (u32)(e->start >> 32), (u32)e->start
53 , (u32)(e_end >> 32), (u32)e_end
54 , e->type);
55 }
56}
57
58// Add a new entry to the list. This scans for overlaps and keeps the
59// list sorted.
60void
61add_e820(u64 start, u64 size, u32 type)
62{
63 dprintf(8, "Add to e820 map: %x %x %d\n", (u32)start, (u32)size, type);
64
65 if (! size)
66 // Huh? Nothing to do.
67 return;
68
69 u64 end = start + size;
70 int i;
71 for (i=0; i<e820_count; i++) {
72 struct e820entry *e = &e820_list[i];
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -040073 if (end < e->start)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040074 // Simple insertion point.
75 break;
76 u64 e_end = e->start + e->size;
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -040077 if (start > e_end)
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040078 // No overlap.
79 continue;
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -040080 // New item overlaps (or borders) an existing one.
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040081 if (start > e->start) {
82 e->size = start - e->start;
83 i++;
84 if (end < e_end)
85 // Need to split existing item
86 insert_e820(i, end, e_end - end, e->type);
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -040087 if (type == e->type) {
88 // Same type - merge them.
89 size += start - e->start;
90 start = e->start;
91 i--;
92 remove_e820(i);
93 }
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040094 }
Kevin O'Connorb8d7a472008-06-21 11:43:32 -040095 if (type != E820_HOLE) {
96 insert_e820(i, start, size, type);
97 i++;
98 }
Kevin O'Connor59a23bb2008-06-08 23:09:42 -040099 // Remove all existing items that are completely overlapped.
100 while (i<e820_count) {
101 e = &e820_list[i];
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -0400102 if (end < e->start)
103 // No overlap - done.
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400104 break;
105 e_end = e->start + e->size;
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -0400106 if (end >= e_end) {
107 // Existing item completely overlapped - remove it.
108 remove_e820(i);
109 continue;
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400110 }
Kevin O'Connoraa0c66d2008-06-11 21:23:24 -0400111 // Not completely overlapped - adjust its start.
112 e->start = end;
113 e->size = e_end - e->start;
114 if (type == e->type) {
115 // Same type - merge them.
116 (e-1)->size += e->size;
117 remove_e820(i);
118 }
119 break;
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400120 }
121 //dump_map();
122 return;
123 }
124 // Just insert item.
125 insert_e820(i, start, size, type);
126 //dump_map();
127}
128
129u32 bios_table_cur_addr, bios_table_end_addr;
130
131// Prep for memmap stuff - init bios table locations.
132void
133memmap_setup()
134{
135 bios_table_cur_addr = 0xf0000 | OFFSET_freespace2_start;
136 bios_table_end_addr = 0xf0000 | OFFSET_freespace2_end;
137 dprintf(1, "bios_table_addr: 0x%08x end=0x%08x\n",
138 bios_table_cur_addr, bios_table_end_addr);
139}
140
141// Copy the temporary e820 map info to its permanent location.
142void
143memmap_finalize()
144{
145 dump_map();
146
147 u32 msize = e820_count * sizeof(e820_list[0]);
148 if (bios_table_cur_addr + msize > bios_table_end_addr) {
149 dprintf(1, "No room for e820 map!\n");
150 return;
151 }
152 memcpy((void*)bios_table_cur_addr, e820_list, msize);
153 SET_EBDA(e820_loc, bios_table_cur_addr);
154 SET_EBDA(e820_count, e820_count);
155 bios_table_cur_addr += msize;
Kevin O'Connor0525d292008-07-04 06:18:30 -0400156
157 dprintf(1, "bios_table_cur_addr: 0x%08x\n", bios_table_cur_addr);
158 if (bios_table_cur_addr > bios_table_end_addr)
159 BX_PANIC("bios_table_end_addr overflow!\n");
Kevin O'Connor59a23bb2008-06-08 23:09:42 -0400160}