📄 setup.c
字号:
} } 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) && (change_point[i]->addr == change_point[i]->pbios->addr) && (change_point[i-1]->addr != change_point[i-1]->pbios->addr)) ) { change_tmp = change_point[i]; change_point[i] = change_point[i-1]; change_point[i-1] = change_tmp; still_changing=1; } } } /* create a new bios memory map, removing overlaps */ overlap_entries=0; /* number of entries in the overlap table */ new_bios_entry=0; /* index for creating new bios map entries */ last_type = 0; /* start with undefined memory type */ last_addr = 0; /* start with 0 as last starting address */ /* loop through change-points, determining affect on the new bios map */ for (chgidx=0; chgidx < chg_nr; chgidx++) { /* keep track of all overlapping bios entries */ if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr) { /* add map entry to overlap list (> 1 entry implies an overlap) */ overlap_list[overlap_entries++]=change_point[chgidx]->pbios; } else { /* remove entry from list (order independent, so swap with last) */ for (i=0; i<overlap_entries; i++) { if (overlap_list[i] == change_point[chgidx]->pbios) overlap_list[i] = overlap_list[overlap_entries-1]; } overlap_entries--; } /* if there are overlapping entries, decide which "type" to use */ /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ current_type = 0; for (i=0; i<overlap_entries; i++) if (overlap_list[i]->type > current_type) current_type = overlap_list[i]->type; /* continue building up new bios map based on this information */ if (current_type != last_type) { if (last_type != 0) { new_bios[new_bios_entry].size = change_point[chgidx]->addr - last_addr; /* move forward only if the new size was non-zero */ if (new_bios[new_bios_entry].size != 0) if (++new_bios_entry >= E820MAX) break; /* no more space left for new bios entries */ } if (current_type != 0) { new_bios[new_bios_entry].addr = change_point[chgidx]->addr; new_bios[new_bios_entry].type = current_type; last_addr=change_point[chgidx]->addr; } last_type = current_type; } } new_nr = new_bios_entry; /* retain count for new bios entries */ /* copy new bios mapping into original location */ memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry)); *pnr_map = new_nr; return 0;}/* * Copy the BIOS e820 map into a safe place. * * Sanity-check it while we're at it.. * * If we're lucky and live on a modern system, the setup code * will have given us a memory map that we can use to properly * set up memory. If we aren't, we'll fake a memory map. * * We check to see that the memory map contains at least 2 elements * before we'll use it, because the detection code in setup.S may * not be perfect and most every PC known to man has two memory * regions: one from 0 to 640k, and one from 1mb up. (The IBM * thinkpad 560x, for example, does not cooperate with the memory * detection code.) */static int __init copy_e820_map(struct e820entry * biosmap, int nr_map){ /* Only one memory region (or negative)? Ignore it */ if (nr_map < 2) return -1; do { unsigned long long start = biosmap->addr; unsigned long long size = biosmap->size; unsigned long long end = start + size; unsigned long type = biosmap->type; /* Overflow in 64 bits? Ignore the memory map. */ if (start > end) return -1; /* * Some BIOSes claim RAM in the 640k - 1M region. * Not right. Fix it up. */ if (type == E820_RAM) { if (start < 0x100000ULL && end > 0xA0000ULL) { if (start < 0xA0000ULL) add_memory_region(start, 0xA0000ULL-start, type); if (end <= 0x100000ULL) continue; start = 0x100000ULL; size = end - start; } } add_memory_region(start, size, type); } while (biosmap++,--nr_map); return 0;}#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)struct edd edd;#ifdef CONFIG_EDD_MODULEEXPORT_SYMBOL(edd);#endif/** * copy_edd() - Copy the BIOS EDD information * from boot_params into a safe place. * */static inline void copy_edd(void){ memcpy(edd.mbr_signature, EDD_MBR_SIGNATURE, sizeof(edd.mbr_signature)); memcpy(edd.edd_info, EDD_BUF, sizeof(edd.edd_info)); edd.mbr_signature_nr = EDD_MBR_SIG_NR; edd.edd_info_nr = EDD_NR;}#elsestatic inline void copy_edd(void){}#endif/* * Do NOT EVER look at the BIOS memory size location. * It does not work on many machines. */#define LOWMEMSIZE() (0x9f000)static void __init parse_cmdline_early (char ** cmdline_p){ char c = ' ', *to = command_line, *from = saved_command_line; int len = 0; int userdef = 0; /* Save unparsed command line copy for /proc/cmdline */ saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; for (;;) { if (c != ' ') goto next_char; /* * "mem=nopentium" disables the 4MB page tables. * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM * to <mem>, overriding the bios size. * "memmap=XXX[KkmM]@XXX[KkmM]" defines a memory region from * <start> to <start>+<mem>, overriding the bios size. * * HPA tells me bootloaders need to parse mem=, so no new * option should be mem= [also see Documentation/i386/boot.txt] */ if (!memcmp(from, "mem=", 4)) { if (to != command_line) to--; if (!memcmp(from+4, "nopentium", 9)) { from += 9+4; clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability); disable_pse = 1; } else { /* If the user specifies memory size, we * limit the BIOS-provided memory map to * that size. exactmap can be used to specify * the exact map. mem=number can be used to * trim the existing memory map. */ unsigned long long mem_size; mem_size = memparse(from+4, &from); limit_regions(mem_size); userdef=1; } } else if (!memcmp(from, "memmap=", 7)) { if (to != command_line) to--; if (!memcmp(from+7, "exactmap", 8)) {#ifdef CONFIG_CRASH_DUMP /* If we are doing a crash dump, we * still need to know the real mem * size before original memory map is * reset. */ find_max_pfn(); saved_max_pfn = max_pfn;#endif from += 8+7; e820.nr_map = 0; userdef = 1; } else { /* If the user specifies memory size, we * limit the BIOS-provided memory map to * that size. exactmap can be used to specify * the exact map. mem=number can be used to * trim the existing memory map. */ unsigned long long start_at, mem_size; mem_size = memparse(from+7, &from); if (*from == '@') { start_at = memparse(from+1, &from); add_memory_region(start_at, mem_size, E820_RAM); } else if (*from == '#') { start_at = memparse(from+1, &from); add_memory_region(start_at, mem_size, E820_ACPI); } else if (*from == '$') { start_at = memparse(from+1, &from); add_memory_region(start_at, mem_size, E820_RESERVED); } else { limit_regions(mem_size); userdef=1; } } } else if (!memcmp(from, "noexec=", 7)) noexec_setup(from + 7);#ifdef CONFIG_X86_SMP /* * If the BIOS enumerates physical processors before logical, * maxcpus=N at enumeration-time can be used to disable HT. */ else if (!memcmp(from, "maxcpus=", 8)) { extern unsigned int maxcpus; maxcpus = simple_strtoul(from + 8, NULL, 0); }#endif#ifdef CONFIG_ACPI /* "acpi=off" disables both ACPI table parsing and interpreter */ else if (!memcmp(from, "acpi=off", 8)) { disable_acpi(); } /* acpi=force to over-ride black-list */ else if (!memcmp(from, "acpi=force", 10)) { acpi_force = 1; acpi_ht = 1; acpi_disabled = 0; } /* acpi=strict disables out-of-spec workarounds */ else if (!memcmp(from, "acpi=strict", 11)) { acpi_strict = 1; } /* Limit ACPI just to boot-time to enable HT */ else if (!memcmp(from, "acpi=ht", 7)) { if (!acpi_force) disable_acpi(); acpi_ht = 1; } /* "pci=noacpi" disable ACPI IRQ routing and PCI scan */ else if (!memcmp(from, "pci=noacpi", 10)) { acpi_disable_pci(); } /* "acpi=noirq" disables ACPI interrupt routing */ else if (!memcmp(from, "acpi=noirq", 10)) { acpi_noirq_set(); } else if (!memcmp(from, "acpi_sci=edge", 13)) acpi_sci_flags.trigger = 1; else if (!memcmp(from, "acpi_sci=level", 14)) acpi_sci_flags.trigger = 3; else if (!memcmp(from, "acpi_sci=high", 13)) acpi_sci_flags.polarity = 1; else if (!memcmp(from, "acpi_sci=low", 12)) acpi_sci_flags.polarity = 3;#ifdef CONFIG_X86_IO_APIC else if (!memcmp(from, "acpi_skip_timer_override", 24)) acpi_skip_timer_override = 1; if (!memcmp(from, "disable_timer_pin_1", 19)) disable_timer_pin_1 = 1; if (!memcmp(from, "enable_timer_pin_1", 18)) disable_timer_pin_1 = -1; /* disable IO-APIC */ else if (!memcmp(from, "noapic", 6)) disable_ioapic_setup();#endif /* CONFIG_X86_IO_APIC */#endif /* CONFIG_ACPI */#ifdef CONFIG_X86_LOCAL_APIC /* enable local APIC */ else if (!memcmp(from, "lapic", 5)) lapic_enable(); /* disable local APIC */ else if (!memcmp(from, "nolapic", 6)) lapic_disable();#endif /* CONFIG_X86_LOCAL_APIC */#ifdef CONFIG_KEXEC /* crashkernel=size@addr specifies the location to reserve for * a crash kernel. By reserving this memory we guarantee * that linux never set's it up as a DMA target. * Useful for holding code to do something appropriate * after a kernel panic. */ else if (!memcmp(from, "crashkernel=", 12)) { unsigned long size, base; size = memparse(from+12, &from); if (*from == '@') { base = memparse(from+1, &from); /* FIXME: Do I want a sanity check * to validate the memory range? */ crashk_res.start = base; crashk_res.end = base + size - 1; } }#endif#ifdef CONFIG_CRASH_DUMP /* elfcorehdr= specifies the location of elf core header * stored by the crashed kernel. */ else if (!memcmp(from, "elfcorehdr=", 11)) elfcorehdr_addr = memparse(from+11, &from);#endif /* * highmem=size forces highmem to be exactly 'size' bytes. * This works even on boxes that have no highmem otherwise. * This also works to reduce highmem size on bigger boxes. */ else if (!memcmp(from, "highmem=", 8)) highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT; /* * vmalloc=size forces the vmalloc area to be exactly 'size' * bytes. This can be used to increase (or decrease) the * vmalloc area - the default is 128m. */ else if (!memcmp(from, "vmalloc=", 8)) __VMALLOC_RESERVE = memparse(from+8, &from); next_char: c = *(from++); if (!c) break; if (COMMAND_LINE_SIZE <= ++len) break; *(to++) = c; } *to = '\0'; *cmdline_p = command_line; if (userdef) { printk(KERN_INFO "user-defined physical RAM map:\n"); print_memory_map("user"); }}/* * Callback for efi_memory_walk. */static int __initefi_find_max_pfn(unsigned long start, unsigned long end, void *arg){ unsigned long *max_pfn = arg, pfn; if (start < end) { pfn = PFN_UP(end -1); if (pfn > *max_pfn) *max_pfn = pfn; } return 0;}/* * Find the highest page frame number we have available */void __init find_max_pfn(void){ int i; max_pfn = 0; if (efi_enabled) { efi_memmap_walk(efi_find_max_pfn, &max_pfn); return; } for (i = 0; i < e820.nr_map; i++) { unsigned long start, end; /* RAM? */ if (e820.map[i].type != E820_RAM) continue; start = PFN_UP(e820.map[i].addr); end = PFN_DOWN(e820.map[i].addr + e820.map[i].size); if (start >= end) continue; if (end > max_pfn) max_pfn = end; }}/* * Determine low and high memory ranges: */unsigned long __init find_max_low_pfn(void){ unsigned long max_low_pfn; max_low_pfn = max_pfn; if (max_low_pfn > MAXMEM_PFN) { if (highmem_pages == -1) highmem_pages = max_pfn - MAXMEM_PFN; if (highmem_pages + MAXMEM_PFN < max_pfn) max_pfn = MAXMEM_PFN + highmem_pages; if (highmem_pages + MAXMEM_PFN > max_pfn) { printk("only %luMB highmem pages available, ignoring highmem size of %uMB.\n", pages_to_mb(max_pfn - MAXMEM_PFN), pages_to_mb(highmem_pages)); highmem_pages = 0; } max_low_pfn = MAXMEM_PFN;#ifndef CONFIG_HIGHMEM /* Maximum memory usable is what is directly addressable */ printk(KERN_WARNING "Warning only %ldMB will be used.\n", MAXMEM>>20); if (max_pfn > MAX_NONPAE_PFN) printk(KERN_WARNING "Use a PAE enabled kernel.\n"); else printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); max_pfn = MAXMEM_PFN;#else /* !CONFIG_HIGHMEM */#ifndef CONFIG_X86_PAE if (max_pfn > MAX_NONPAE_PFN) { max_pfn = MAX_NONPAE_PFN; printk(KERN_WARNING "Warning only 4GB will be used.\n"); printk(KERN_WARNING "Use a PAE enabled kernel.\n"); }#endif /* !CONFIG_X86_PAE */#endif /* !CONFIG_HIGHMEM */ } else { if (highmem_pages == -1) highmem_pages = 0;#ifdef CONFIG_HIGHMEM if (highmem_pages >= max_pfn) { printk(KERN_ERR "highmem size specified (%uMB) is bigger than pages available (%luMB)!.\n", pages_to_mb(highmem_pages), pages_to_mb(max_pfn)); highmem_pages = 0; } if (highmem_pages) { if (max_low_pfn-highmem_pages < 64*1024*1024/PAGE_SIZE){ printk(KERN_ERR "highmem size %uMB results in smaller than 64MB lowmem, ignoring it.\n", pages_to_mb(highmem_pages)); highmem_pages = 0; } max_low_pfn -= highmem_pages; }#else if (highmem_pages) printk(KERN_ERR "ignoring highmem size on non-highmem kernel!\n");#endif } return max_low_pfn;}/* * Free all available memory for boot time allocation. Used * as a callback function by efi_memory_walk() */static int __initfree_available_memory(unsigned long start, unsigned long end, void *arg){ /* check max_low_pfn */ if (start >= ((max_low_pfn + 1) << PAGE_SHIFT)) return 0; if (end >= ((max_low_pfn + 1) << PAGE_SHIFT)) end = (max_low_pfn + 1) << PAGE_SHIFT; if (start < end) free_bootmem(start, end - start); return 0;}/* * Register fully available low RAM pages with the bootmem allocator. */static void __init register_bootmem_low_pages(unsigned long max_low_pfn){ int i; if (efi_enabled) { efi_memmap_walk(free_available_memory, NULL); return; } for (i = 0; i < e820.nr_map; i++) { unsigned long curr_pfn, last_pfn, size; /* * Reserve usable low memory */ if (e820.map[i].type != E820_RAM) continue; /* * We are rounding up the start address of usable memory: */ curr_pfn = PFN_UP(e820.map[i].addr); if (curr_pfn >= max_low_pfn) continue; /* * ... and at the end of the usable range downwards: */ last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -