// Support for building memory maps suitable for int 15 e820 calls. // // Copyright (C) 2008,2009 Kevin O'Connor // // This file may be distributed under the terms of the GNU LGPLv3 license. #include "config.h" // BUILD_MAX_E820 #include "e820map.h" // struct e820entry #include "output.h" // dprintf #include "string.h" // memmove /**************************************************************** * e820 memory map ****************************************************************/ // Info on e820 map location and size. struct e820entry e820_list[BUILD_MAX_E820] VARFSEG; int e820_count VARFSEG; // Remove an entry from the e820_list. static void remove_e820(int i) { e820_count--; memmove(&e820_list[i], &e820_list[i+1] , sizeof(e820_list[0]) * (e820_count - i)); } // Insert an entry in the e820_list at the given position. static void insert_e820(int i, u64 start, u64 size, u32 type) { if (e820_count >= BUILD_MAX_E820) { warn_noalloc(); return; } memmove(&e820_list[i+1], &e820_list[i] , sizeof(e820_list[0]) * (e820_count - i)); e820_count++; struct e820entry *e = &e820_list[i]; e->start = start; e->size = size; e->type = type; } static const char * e820_type_name(u32 type) { switch (type) { case E820_RAM: return "RAM"; case E820_RESERVED: return "RESERVED"; case E820_ACPI: return "ACPI"; case E820_NVS: return "NVS"; case E820_UNUSABLE: return "UNUSABLE"; default: return "UNKNOWN"; } } // Show the current e820_list. static void dump_map(void) { dprintf(1, "e820 map has %d items:\n", e820_count); int i; for (i=0; istart + e->size; dprintf(1, " %d: %016llx - %016llx = %d %s\n", i , e->start, e_end, e->type, e820_type_name(e->type)); } } #define E820_HOLE ((u32)-1) // Used internally to remove entries // Add a new entry to the list. This scans for overlaps and keeps the // list sorted. void e820_add(u64 start, u64 size, u32 type) { dprintf(8, "Add to e820 map: %08llx %08llx %d\n", start, size, type); if (! size) // Huh? Nothing to do. return; // Find position of new item (splitting existing item if needed). u64 end = start + size; int i; for (i=0; istart + e->size; if (start > e_end) continue; // Found position - check if an existing item needs to be split. if (start > e->start) { if (type == e->type) { // Same type - merge them. size += start - e->start; start = e->start; } else { // Split existing item. e->size = start - e->start; i++; if (e_end > end) insert_e820(i, end, e_end - end, e->type); } } break; } // Remove/adjust existing items that are overlapping. while (istart) // No overlap - done. break; u64 e_end = e->start + e->size; if (end >= e_end) { // Existing item completely overlapped - remove it. remove_e820(i); continue; } // Not completely overlapped - adjust its start. e->start = end; e->size = e_end - end; if (type == e->type) { // Same type - merge them. size += e->size; remove_e820(i); } break; } // Insert new item. if (type != E820_HOLE) insert_e820(i, start, size, type); //dump_map(); } // Remove any definitions in a memory range (make a memory hole). void e820_remove(u64 start, u64 size) { e820_add(start, size, E820_HOLE); } // Report on final memory locations. void e820_prepboot(void) { dump_map(); } int e820_is_used(u64 start, u64 size) { int i; for (i=0; istart) continue; if (start >= e->start + e->size) continue; return 1; } return 0; }