/*
* Low level x86 E820 memory map handling functions.
*
* The firmware and bootloader passes us the "E820 table", which is the primary
* physical memory layout description available about x86 systems.
*
* The kernel takes the E820 memory layout and optionally modifies it with
* quirks and other tweaks, and feeds that into the generic Linux memory
* allocation code routines via a platform independent interface (memblock, etc.).
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/crash_dump.h>
#include <linux/export.h>
#include <linux/bootmem.h>
#include <linux/pfn.h>
#include <linux/suspend.h>
#include <linux/acpi.h>
#include <linux/firmware-map.h>
#include <linux/memblock.h>
#include <linux/sort.h>
#include <asm/e820/api.h>
#include <asm/proto.h>
#include <asm/setup.h>
#include <asm/cpufeature.h>
/*
* We organize the E820 table into two main data structures:
*
* - 'e820_table_firmware': the original firmware version passed to us by the
* bootloader - not modified by the kernel. We use this to:
*
* - inform the user about the firmware's notion of memory layout
* via /sys/firmware/memmap
*
* - the hibernation code uses it to generate a kernel-independent MD5
* fingerprint of the physical memory layout of a system.
*
* - kexec, which is a bootloader in disguise, uses the original E820
* layout to pass to the kexec-ed kernel. This way the original kernel
* can have a restricted E820 map while the kexec()-ed kexec-kernel
* can have access to full memory - etc.
*
* - 'e820_table': this is the main E820 table that is massaged by the
* low level x86 platform code, or modified by boot parameters, before
* passed on to higher level MM layers.
*
* Once the E820 map has been converted to the standard Linux memory layout
* information its role stops - modifying it has no effect and does not get
* re-propagated. So itsmain role is a temporary bootstrap storage of firmware
* specific memory layout data during early bootup.
*/
static struct e820_table e820_table_init __initdata;
static struct e820_table e820_table_firmware_init __initdata;
struct e820_table *e820_table __refdata = &e820_table_init;
struct e820_table *e820_table_firmware __refdata = &e820_table_firmware_init;
/* For PCI or other memory-mapped resources */
unsigned long pci_mem_start = 0xaeedbabe;
#ifdef CONFIG_PCI
EXPORT_SYMBOL(pci_mem_start);
#endif
/*
* This function checks if any part of the range <start,end> is mapped
* with type.
*/
int e820_any_mapped(u64 start, u64 end, unsigned type)
{
int i;
for (i = 0; i < e820_table->nr_entries; i++) {
struct e820_entry *ei = &e820_table->entries[i];
if (type && ei->type != type)
continue;
if (ei->addr >= end || ei->addr + ei->size <= start)
continue;
return 1;
}
return 0;
}
EXPORT_SYMBOL_GPL(e820_any_mapped);
/*
* This function checks if the entire <start,end> range is mapped with 'type'.
*
* Note: this function only works correctly once the E820 table is sorted and
* not-overlapping (at least for the range specified), which is the case normally.
*/
int __init e820_all_mapped(u64 start, u64 end, unsigned type)
{
int i;
for (i = 0; i < e820_table->nr_entries; i++) {
struct e820_entry *ei = &e820_table->entries[i];
if (type && ei->type != type)
continue;
/* Is the region (part) in overlap with the current region? */
if (ei->addr >= end || ei->addr + ei->size <= start)
continue;
/*
* If the region is at the beginning of <start,end> we move
* 'start' to the end of the region since it's ok until there
*/
if (ei->addr <= start)
start = ei->addr + ei->size;
/*
* If 'start' is now at or beyond 'end', we're done, full
* coverage of the desired range exists:
*/
if (start >= end)
return 1;
}
return 0;
}
/*
* Add a memory region to the kernel E820 map.
*/
static void __init __e820_add_region(struct