📄 init_64.c
字号:
unsigned long max_zone_pfns[MAX_NR_ZONES]; memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN; max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN; max_zone_pfns[ZONE_NORMAL] = end_pfn; memory_present(0, 0, end_pfn); sparse_init(); free_area_init_nodes(max_zone_pfns);}#endif/* Unmap a kernel mapping if it exists. This is useful to avoid prefetches from the CPU leading to inconsistent cache lines. address and size must be aligned to 2MB boundaries. Does nothing when the mapping doesn't exist. */void __init clear_kernel_mapping(unsigned long address, unsigned long size) { unsigned long end = address + size; BUG_ON(address & ~LARGE_PAGE_MASK); BUG_ON(size & ~LARGE_PAGE_MASK); for (; address < end; address += LARGE_PAGE_SIZE) { pgd_t *pgd = pgd_offset_k(address); pud_t *pud; pmd_t *pmd; if (pgd_none(*pgd)) continue; pud = pud_offset(pgd, address); if (pud_none(*pud)) continue; pmd = pmd_offset(pud, address); if (!pmd || pmd_none(*pmd)) continue; if (0 == (pmd_val(*pmd) & _PAGE_PSE)) { /* Could handle this, but it should not happen currently. */ printk(KERN_ERR "clear_kernel_mapping: mapping has been split. will leak memory\n"); pmd_ERROR(*pmd); } set_pmd(pmd, __pmd(0)); } __flush_tlb_all();} /* * Memory hotplug specific functions */void online_page(struct page *page){ ClearPageReserved(page); init_page_count(page); __free_page(page); totalram_pages++; num_physpages++;}#ifdef CONFIG_MEMORY_HOTPLUG/* * Memory is added always to NORMAL zone. This means you will never get * additional DMA/DMA32 memory. */int arch_add_memory(int nid, u64 start, u64 size){ struct pglist_data *pgdat = NODE_DATA(nid); struct zone *zone = pgdat->node_zones + ZONE_NORMAL; unsigned long start_pfn = start >> PAGE_SHIFT; unsigned long nr_pages = size >> PAGE_SHIFT; int ret; init_memory_mapping(start, (start + size -1)); ret = __add_pages(zone, start_pfn, nr_pages); if (ret) goto error; return ret;error: printk("%s: Problem encountered in __add_pages!\n", __func__); return ret;}EXPORT_SYMBOL_GPL(arch_add_memory);#if !defined(CONFIG_ACPI_NUMA) && defined(CONFIG_NUMA)int memory_add_physaddr_to_nid(u64 start){ return 0;}EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);#endif#endif /* CONFIG_MEMORY_HOTPLUG */#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE/* * Memory Hotadd without sparsemem. The mem_maps have been allocated in advance, * just online the pages. */int __add_pages(struct zone *z, unsigned long start_pfn, unsigned long nr_pages){ int err = -EIO; unsigned long pfn; unsigned long total = 0, mem = 0; for (pfn = start_pfn; pfn < start_pfn + nr_pages; pfn++) { if (pfn_valid(pfn)) { online_page(pfn_to_page(pfn)); err = 0; mem++; } total++; } if (!err) { z->spanned_pages += total; z->present_pages += mem; z->zone_pgdat->node_spanned_pages += total; z->zone_pgdat->node_present_pages += mem; } return err;}#endifstatic struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules, kcore_vsyscall;void __init mem_init(void){ long codesize, reservedpages, datasize, initsize; pci_iommu_alloc(); /* clear the zero-page */ memset(empty_zero_page, 0, PAGE_SIZE); reservedpages = 0; /* this will put all low memory onto the freelists */#ifdef CONFIG_NUMA totalram_pages = numa_free_all_bootmem();#else totalram_pages = free_all_bootmem();#endif reservedpages = end_pfn - totalram_pages - absent_pages_in_range(0, end_pfn); after_bootmem = 1; codesize = (unsigned long) &_etext - (unsigned long) &_text; datasize = (unsigned long) &_edata - (unsigned long) &_etext; initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; /* Register memory areas for /proc/kcore */ kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT); kclist_add(&kcore_vmalloc, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START); kclist_add(&kcore_kernel, &_stext, _end - _stext); kclist_add(&kcore_modules, (void *)MODULES_VADDR, MODULES_LEN); kclist_add(&kcore_vsyscall, (void *)VSYSCALL_START, VSYSCALL_END - VSYSCALL_START); printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, %ldk data, %ldk init)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), end_pfn << (PAGE_SHIFT-10), codesize >> 10, reservedpages << (PAGE_SHIFT-10), datasize >> 10, initsize >> 10);}void free_init_pages(char *what, unsigned long begin, unsigned long end){ unsigned long addr; if (begin >= end) return; printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); for (addr = begin; addr < end; addr += PAGE_SIZE) { ClearPageReserved(virt_to_page(addr)); init_page_count(virt_to_page(addr)); memset((void *)(addr & ~(PAGE_SIZE-1)), POISON_FREE_INITMEM, PAGE_SIZE); if (addr >= __START_KERNEL_map) change_page_attr_addr(addr, 1, __pgprot(0)); free_page(addr); totalram_pages++; } if (addr > __START_KERNEL_map) global_flush_tlb();}void free_initmem(void){ free_init_pages("unused kernel memory", (unsigned long)(&__init_begin), (unsigned long)(&__init_end));}#ifdef CONFIG_DEBUG_RODATAvoid mark_rodata_ro(void){ unsigned long start = (unsigned long)_stext, end;#ifdef CONFIG_HOTPLUG_CPU /* It must still be possible to apply SMP alternatives. */ if (num_possible_cpus() > 1) start = (unsigned long)_etext;#endif#ifdef CONFIG_KPROBES start = (unsigned long)__start_rodata;#endif end = (unsigned long)__end_rodata; start = (start + PAGE_SIZE - 1) & PAGE_MASK; end &= PAGE_MASK; if (end <= start) return; change_page_attr_addr(start, (end - start) >> PAGE_SHIFT, PAGE_KERNEL_RO); printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", (end - start) >> 10); /* * change_page_attr_addr() requires a global_flush_tlb() call after it. * We do this after the printk so that if something went wrong in the * change, the printk gets out at least to give a better debug hint * of who is the culprit. */ global_flush_tlb();}#endif#ifdef CONFIG_BLK_DEV_INITRDvoid free_initrd_mem(unsigned long start, unsigned long end){ free_init_pages("initrd memory", start, end);}#endifvoid __init reserve_bootmem_generic(unsigned long phys, unsigned len) { #ifdef CONFIG_NUMA int nid = phys_to_nid(phys);#endif unsigned long pfn = phys >> PAGE_SHIFT; if (pfn >= end_pfn) { /* This can happen with kdump kernels when accessing firmware tables. */ if (pfn < end_pfn_map) return; printk(KERN_ERR "reserve_bootmem: illegal reserve %lx %u\n", phys, len); return; } /* Should check here against the e820 map to avoid double free */#ifdef CONFIG_NUMA reserve_bootmem_node(NODE_DATA(nid), phys, len);#else reserve_bootmem(phys, len); #endif if (phys+len <= MAX_DMA_PFN*PAGE_SIZE) { dma_reserve += len / PAGE_SIZE; set_dma_reserve(dma_reserve); }}int kern_addr_valid(unsigned long addr) { unsigned long above = ((long)addr) >> __VIRTUAL_MASK_SHIFT; pgd_t *pgd; pud_t *pud; pmd_t *pmd; pte_t *pte; if (above != 0 && above != -1UL) return 0; pgd = pgd_offset_k(addr); if (pgd_none(*pgd)) return 0; pud = pud_offset(pgd, addr); if (pud_none(*pud)) return 0; pmd = pmd_offset(pud, addr); if (pmd_none(*pmd)) return 0; if (pmd_large(*pmd)) return pfn_valid(pmd_pfn(*pmd)); pte = pte_offset_kernel(pmd, addr); if (pte_none(*pte)) return 0; return pfn_valid(pte_pfn(*pte));}/* A pseudo VMA to allow ptrace access for the vsyscall page. This only covers the 64bit vsyscall page now. 32bit has a real VMA now and does not need special handling anymore. */static struct vm_area_struct gate_vma = { .vm_start = VSYSCALL_START, .vm_end = VSYSCALL_START + (VSYSCALL_MAPPED_PAGES << PAGE_SHIFT), .vm_page_prot = PAGE_READONLY_EXEC, .vm_flags = VM_READ | VM_EXEC};struct vm_area_struct *get_gate_vma(struct task_struct *tsk){#ifdef CONFIG_IA32_EMULATION if (test_tsk_thread_flag(tsk, TIF_IA32)) return NULL;#endif return &gate_vma;}int in_gate_area(struct task_struct *task, unsigned long addr){ struct vm_area_struct *vma = get_gate_vma(task); if (!vma) return 0; return (addr >= vma->vm_start) && (addr < vma->vm_end);}/* Use this when you have no reliable task/vma, typically from interrupt * context. It is less reliable than using the task's vma and may give * false positives. */int in_gate_area_no_task(unsigned long addr){ return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END);}const char *arch_vma_name(struct vm_area_struct *vma){ if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) return "[vdso]"; if (vma == &gate_vma) return "[vsyscall]"; return NULL;}#ifdef CONFIG_SPARSEMEM_VMEMMAP/* * Initialise the sparsemem vmemmap using huge-pages at the PMD level. */int __meminit vmemmap_populate(struct page *start_page, unsigned long size, int node){ unsigned long addr = (unsigned long)start_page; unsigned long end = (unsigned long)(start_page + size); unsigned long next; pgd_t *pgd; pud_t *pud; pmd_t *pmd; for (; addr < end; addr = next) { next = pmd_addr_end(addr, end); pgd = vmemmap_pgd_populate(addr, node); if (!pgd) return -ENOMEM; pud = vmemmap_pud_populate(pgd, addr, node); if (!pud) return -ENOMEM; pmd = pmd_offset(pud, addr); if (pmd_none(*pmd)) { pte_t entry; void *p = vmemmap_alloc_block(PMD_SIZE, node); if (!p) return -ENOMEM; entry = pfn_pte(__pa(p) >> PAGE_SHIFT, PAGE_KERNEL); mk_pte_huge(entry); set_pmd(pmd, __pmd(pte_val(entry))); printk(KERN_DEBUG " [%lx-%lx] PMD ->%p on node %d\n", addr, addr + PMD_SIZE - 1, p, node); } else vmemmap_verify((pte_t *)pmd, node, addr, next); } return 0;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -