📄 e820_32.c
字号:
#include <linux/kernel.h>#include <linux/types.h>#include <linux/init.h>#include <linux/bootmem.h>#include <linux/ioport.h>#include <linux/string.h>#include <linux/kexec.h>#include <linux/module.h>#include <linux/mm.h>#include <linux/efi.h>#include <linux/pfn.h>#include <linux/uaccess.h>#include <linux/suspend.h>#include <asm/pgtable.h>#include <asm/page.h>#include <asm/e820.h>#include <asm/setup.h>#ifdef CONFIG_EFIint efi_enabled = 0;EXPORT_SYMBOL(efi_enabled);#endifstruct e820map e820;struct change_member { struct e820entry *pbios; /* pointer to original bios entry */ unsigned long long addr; /* address for this change point */};static struct change_member change_point_list[2*E820MAX] __initdata;static struct change_member *change_point[2*E820MAX] __initdata;static struct e820entry *overlap_list[E820MAX] __initdata;static struct e820entry new_bios[E820MAX] __initdata;/* For PCI or other memory-mapped resources */unsigned long pci_mem_start = 0x10000000;#ifdef CONFIG_PCIEXPORT_SYMBOL(pci_mem_start);#endifextern int user_defined_memmap;struct resource data_resource = { .name = "Kernel data", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_MEM};struct resource code_resource = { .name = "Kernel code", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_MEM};struct resource bss_resource = { .name = "Kernel bss", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_MEM};static struct resource system_rom_resource = { .name = "System ROM", .start = 0xf0000, .end = 0xfffff, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM};static struct resource extension_rom_resource = { .name = "Extension ROM", .start = 0xe0000, .end = 0xeffff, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM};static struct resource adapter_rom_resources[] = { { .name = "Adapter ROM", .start = 0xc8000, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM}, { .name = "Adapter ROM", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM}, { .name = "Adapter ROM", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM}, { .name = "Adapter ROM", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM}, { .name = "Adapter ROM", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM}, { .name = "Adapter ROM", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM} };static struct resource video_rom_resource = { .name = "Video ROM", .start = 0xc0000, .end = 0xc7fff, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM};static struct resource video_ram_resource = { .name = "Video RAM area", .start = 0xa0000, .end = 0xbffff, .flags = IORESOURCE_BUSY | IORESOURCE_MEM};static struct resource standard_io_resources[] = { { .name = "dma1", .start = 0x0000, .end = 0x001f, .flags = IORESOURCE_BUSY | IORESOURCE_IO}, { .name = "pic1", .start = 0x0020, .end = 0x0021, .flags = IORESOURCE_BUSY | IORESOURCE_IO}, { .name = "timer0", .start = 0x0040, .end = 0x0043, .flags = IORESOURCE_BUSY | IORESOURCE_IO}, { .name = "timer1", .start = 0x0050, .end = 0x0053, .flags = IORESOURCE_BUSY | IORESOURCE_IO}, { .name = "keyboard", .start = 0x0060, .end = 0x006f, .flags = IORESOURCE_BUSY | IORESOURCE_IO}, { .name = "dma page reg", .start = 0x0080, .end = 0x008f, .flags = IORESOURCE_BUSY | IORESOURCE_IO}, { .name = "pic2", .start = 0x00a0, .end = 0x00a1, .flags = IORESOURCE_BUSY | IORESOURCE_IO}, { .name = "dma2", .start = 0x00c0, .end = 0x00df, .flags = IORESOURCE_BUSY | IORESOURCE_IO}, { .name = "fpu", .start = 0x00f0, .end = 0x00ff, .flags = IORESOURCE_BUSY | IORESOURCE_IO} };#define ROMSIGNATURE 0xaa55static int __init romsignature(const unsigned char *rom){ const unsigned short * const ptr = (const unsigned short *)rom; unsigned short sig; return probe_kernel_address(ptr, sig) == 0 && sig == ROMSIGNATURE;}static int __init romchecksum(const unsigned char *rom, unsigned long length){ unsigned char sum, c; for (sum = 0; length && probe_kernel_address(rom++, c) == 0; length--) sum += c; return !length && !sum;}static void __init probe_roms(void){ const unsigned char *rom; unsigned long start, length, upper; unsigned char c; int i; /* video rom */ upper = adapter_rom_resources[0].start; for (start = video_rom_resource.start; start < upper; start += 2048) { rom = isa_bus_to_virt(start); if (!romsignature(rom)) continue; video_rom_resource.start = start; if (probe_kernel_address(rom + 2, c) != 0) continue; /* 0 < length <= 0x7f * 512, historically */ length = c * 512; /* if checksum okay, trust length byte */ if (length && romchecksum(rom, length)) video_rom_resource.end = start + length - 1; request_resource(&iomem_resource, &video_rom_resource); break; } start = (video_rom_resource.end + 1 + 2047) & ~2047UL; if (start < upper) start = upper; /* system rom */ request_resource(&iomem_resource, &system_rom_resource); upper = system_rom_resource.start; /* check for extension rom (ignore length byte!) */ rom = isa_bus_to_virt(extension_rom_resource.start); if (romsignature(rom)) { length = extension_rom_resource.end - extension_rom_resource.start + 1; if (romchecksum(rom, length)) { request_resource(&iomem_resource, &extension_rom_resource); upper = extension_rom_resource.start; } } /* check for adapter roms on 2k boundaries */ for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) { rom = isa_bus_to_virt(start); if (!romsignature(rom)) continue; if (probe_kernel_address(rom + 2, c) != 0) continue; /* 0 < length <= 0x7f * 512, historically */ length = c * 512; /* but accept any length that fits if checksum okay */ if (!length || start + length > upper || !romchecksum(rom, length)) continue; adapter_rom_resources[i].start = start; adapter_rom_resources[i].end = start + length - 1; request_resource(&iomem_resource, &adapter_rom_resources[i]); start = adapter_rom_resources[i++].end & ~2047UL; }}/* * Request address space for all standard RAM and ROM resources * and also for regions reported as reserved by the e820. */static void __initlegacy_init_iomem_resources(struct resource *code_resource, struct resource *data_resource, struct resource *bss_resource){ int i; probe_roms(); for (i = 0; i < e820.nr_map; i++) { struct resource *res;#ifndef CONFIG_RESOURCES_64BIT if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL) continue;#endif res = kzalloc(sizeof(struct resource), GFP_ATOMIC); switch (e820.map[i].type) { case E820_RAM: res->name = "System RAM"; break; case E820_ACPI: res->name = "ACPI Tables"; break; case E820_NVS: res->name = "ACPI Non-volatile Storage"; break; default: res->name = "reserved"; } res->start = e820.map[i].addr; res->end = res->start + e820.map[i].size - 1; res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; if (request_resource(&iomem_resource, res)) { kfree(res); continue; } if (e820.map[i].type == E820_RAM) { /* * We don't know which RAM region contains kernel data, * so we try it repeatedly and let the resource manager * test it. */ request_resource(res, code_resource); request_resource(res, data_resource); request_resource(res, bss_resource);#ifdef CONFIG_KEXEC if (crashk_res.start != crashk_res.end) request_resource(res, &crashk_res);#endif } }}/* * Request address space for all standard resources * * This is called just before pcibios_init(), which is also a * subsys_initcall, but is linked in later (in arch/i386/pci/common.c). */static int __init request_standard_resources(void){ int i; printk("Setting up standard PCI resources\n"); if (efi_enabled) efi_initialize_iomem_resources(&code_resource, &data_resource, &bss_resource); else legacy_init_iomem_resources(&code_resource, &data_resource, &bss_resource); /* EFI systems may still have VGA */ request_resource(&iomem_resource, &video_ram_resource); /* request I/O space for devices used on all i[345]86 PCs */ for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++) request_resource(&ioport_resource, &standard_io_resources[i]); return 0;}subsys_initcall(request_standard_resources);#if defined(CONFIG_PM) && defined(CONFIG_HIBERNATION)/** * e820_mark_nosave_regions - Find the ranges of physical addresses that do not * correspond to e820 RAM areas and mark the corresponding pages as nosave for * hibernation. * * This function requires the e820 map to be sorted and without any * overlapping entries and assumes the first e820 area to be RAM. */void __init e820_mark_nosave_regions(void){ int i; unsigned long pfn; pfn = PFN_DOWN(e820.map[0].addr + e820.map[0].size); for (i = 1; i < e820.nr_map; i++) { struct e820entry *ei = &e820.map[i]; if (pfn < PFN_UP(ei->addr)) register_nosave_region(pfn, PFN_UP(ei->addr)); pfn = PFN_DOWN(ei->addr + ei->size); if (ei->type != E820_RAM) register_nosave_region(PFN_UP(ei->addr), pfn); if (pfn >= max_low_pfn) break; }}#endifvoid __init add_memory_region(unsigned long long start, unsigned long long size, int type){ int x; if (!efi_enabled) { x = e820.nr_map; if (x == E820MAX) { printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); return; } e820.map[x].addr = start; e820.map[x].size = size; e820.map[x].type = type; e820.nr_map++; }} /* add_memory_region *//* * Sanitize the BIOS e820 map. * * Some e820 responses include overlapping entries. The following * replaces the original e820 map with a new one, removing overlaps. * */int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map){ struct change_member *change_tmp; unsigned long current_type, last_type; unsigned long long last_addr; int chgidx, still_changing; int overlap_entries; int new_bios_entry; int old_nr, new_nr, chg_nr; int i; /* Visually we're performing the following (1,2,3,4 = memory types)... Sample memory map (w/overlaps): ____22__________________ ______________________4_ ____1111________________ _44_____________________ 11111111________________ ____________________33__ ___________44___________ __________33333_________ ______________22________ ___________________2222_ _________111111111______ _____________________11_ _________________4______ Sanitized equivalent (no overlap): 1_______________________ _44_____________________ ___1____________________ ____22__________________ ______11________________ _________1______________ __________3_____________ ___________44___________ _____________33_________ _______________2________ ________________1_______ _________________4______ ___________________2____ ____________________33__ ______________________4_ */ /* if there's only one memory region, don't bother */ if (*pnr_map < 2) { return -1; } old_nr = *pnr_map; /* bail out if we find any unreasonable addresses in bios map */ for (i=0; i<old_nr; i++) if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr) { return -1; } /* create pointers for initial change-point information (for sorting) */ for (i=0; i < 2*old_nr; i++) change_point[i] = &change_point_list[i]; /* record all known change-points (starting and ending addresses), omitting those that are for empty memory regions */ chgidx = 0; for (i=0; i < old_nr; i++) { if (biosmap[i].size != 0) { change_point[chgidx]->addr = biosmap[i].addr; change_point[chgidx++]->pbios = &biosmap[i]; change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size; change_point[chgidx++]->pbios = &biosmap[i]; } } chg_nr = chgidx; /* true number of change-points */ /* sort change-point list by memory addresses (low -> high) */ still_changing = 1; while (still_changing) { still_changing = 0; for (i=1; i < chg_nr; i++) { /* if <current_addr> > <last_addr>, swap */ /* or, if current=<start_addr> & last=<end_addr>, swap */ if ((change_point[i]->addr < change_point[i-1]->addr) || ((change_point[i]->addr == change_point[i-1]->addr) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -