Add support for field width argument to %x (eg, %08x).
[seabios.git] / src / memmap.c
1 // 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 LGPLv3 license.
6
7 #include "memmap.h" // struct e820entry
8 #include "util.h" // dprintf.h
9 #include "biosvar.h" // SET_EBDA
10
11 // Remove an entry from the e820_list.
12 static void
13 remove_e820(int i)
14 {
15     e820_count--;
16     memmove(&e820_list[i], &e820_list[i+1]
17             , sizeof(e820_list[0]) * (e820_count - i));
18 }
19
20 // Insert an entry in the e820_list at the given position.
21 static void
22 insert_e820(int i, u64 start, u64 size, u32 type)
23 {
24     if (e820_count >= CONFIG_MAX_E820) {
25         dprintf(1, "Overflowed e820 list!\n");
26         return;
27     }
28
29     memmove(&e820_list[i+1], &e820_list[i]
30             , sizeof(e820_list[0]) * (e820_count - i));
31     e820_count++;
32     struct e820entry *e = &e820_list[i];
33     e->start = start;
34     e->size = size;
35     e->type = type;
36 }
37
38 // Show the current e820_list.
39 static void
40 dump_map()
41 {
42     dprintf(1, "e820 map has %d items:\n", e820_count);
43     int i;
44     for (i=0; i<e820_count; i++) {
45         struct e820entry *e = &e820_list[i];
46         u64 e_end = e->start + e->size;
47         dprintf(1, "  %d: %08x%08x - %08x%08x = %d\n", i
48                 , (u32)(e->start >> 32), (u32)e->start
49                 , (u32)(e_end >> 32), (u32)e_end
50                 , e->type);
51     }
52 }
53
54 // Add a new entry to the list.  This scans for overlaps and keeps the
55 // list sorted.
56 void
57 add_e820(u64 start, u64 size, u32 type)
58 {
59     dprintf(8, "Add to e820 map: %08x %08x %d\n", (u32)start, (u32)size, type);
60
61     if (! size)
62         // Huh?  Nothing to do.
63         return;
64
65     // Find position of new item (splitting existing item if needed).
66     u64 end = start + size;
67     int i;
68     for (i=0; i<e820_count; i++) {
69         struct e820entry *e = &e820_list[i];
70         u64 e_end = e->start + e->size;
71         if (start > e_end)
72             continue;
73         // Found position - check if an existing item needs to be split.
74         if (start > e->start) {
75             if (type == e->type) {
76                 // Same type - merge them.
77                 size += start - e->start;
78                 start = e->start;
79             } else {
80                 // Split existing item.
81                 e->size = start - e->start;
82                 i++;
83                 if (e_end > end)
84                     insert_e820(i, end, e_end - end, e->type);
85             }
86         }
87         break;
88     }
89     // Remove/adjust existing items that are overlapping.
90     while (i<e820_count) {
91         struct e820entry *e = &e820_list[i];
92         if (end < e->start)
93             // No overlap - done.
94             break;
95         u64 e_end = e->start + e->size;
96         if (end >= e_end) {
97             // Existing item completely overlapped - remove it.
98             remove_e820(i);
99             continue;
100         }
101         // Not completely overlapped - adjust its start.
102         e->start = end;
103         e->size = e_end - end;
104         if (type == e->type) {
105             // Same type - merge them.
106             size += e->size;
107             remove_e820(i);
108         }
109         break;
110     }
111     // Insert new item.
112     if (type != E820_HOLE)
113         insert_e820(i, start, size, type);
114     //dump_map();
115 }
116
117 // Prep for memmap stuff - init bios table locations.
118 void
119 memmap_setup()
120 {
121     memset(BiosTableSpace, 0, CONFIG_MAX_BIOSTABLE);
122     bios_table_cur_addr = (u32)BiosTableSpace;
123     bios_table_end_addr = bios_table_cur_addr + CONFIG_MAX_BIOSTABLE;
124     dprintf(1, "bios_table_addr: 0x%08x end=0x%08x\n",
125             bios_table_cur_addr, bios_table_end_addr);
126
127     e820_count = 0;
128 }
129
130 // Report on final memory locations.
131 void
132 memmap_finalize()
133 {
134     dump_map();
135
136     dprintf(1, "final bios_table_addr: 0x%08x (used %d%%)\n"
137             , bios_table_cur_addr
138             , (100 * (bios_table_cur_addr - (u32)&BiosTableSpace)
139                / CONFIG_MAX_BIOSTABLE));
140     if (bios_table_cur_addr > bios_table_end_addr)
141         panic("bios_table_end_addr overflow!\n");
142 }