init.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 907 行 · 第 1/2 页

C
907
字号
		((unsigned long)__init_end - (unsigned long)__init_begin) >> 10);}#ifdef CONFIG_BLK_DEV_INITRDvoid free_initrd_mem(unsigned long start, unsigned long end){	if (start < end)		printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);	for (; start < end; start += PAGE_SIZE) {		ClearPageReserved(virt_to_page(start));		set_page_count(virt_to_page(start), 1);		free_page(start);		totalram_pages++;	}}#endifstatic spinlock_t mmu_context_lock = SPIN_LOCK_UNLOCKED;static DEFINE_IDR(mmu_context_idr);int init_new_context(struct task_struct *tsk, struct mm_struct *mm){	int index;	int err;again:	if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL))		return -ENOMEM;	spin_lock(&mmu_context_lock);	err = idr_get_new(&mmu_context_idr, NULL, &index);	spin_unlock(&mmu_context_lock);	if (err == -EAGAIN)		goto again;	else if (err)		return err;	if (index > MAX_CONTEXT) {		idr_remove(&mmu_context_idr, index);		return -ENOMEM;	}	mm->context.id = index;	return 0;}void destroy_context(struct mm_struct *mm){	spin_lock(&mmu_context_lock);	idr_remove(&mmu_context_idr, mm->context.id);	spin_unlock(&mmu_context_lock);	mm->context.id = NO_CONTEXT;}static int __init mmu_context_init(void){	int index;	/* Reserve the first (invalid) context*/	idr_pre_get(&mmu_context_idr, GFP_KERNEL);	idr_get_new(&mmu_context_idr, NULL, &index);	BUG_ON(0 != index);	return 0;}arch_initcall(mmu_context_init);/* * Do very early mm setup. */void __init mm_init_ppc64(void){#ifndef CONFIG_PPC_ISERIES	unsigned long i;#endif	ppc64_boot_msg(0x100, "MM Init");	/* This is the story of the IO hole... please, keep seated,	 * unfortunately, we are out of oxygen masks at the moment.	 * So we need some rough way to tell where your big IO hole	 * is. On pmac, it's between 2G and 4G, on POWER3, it's around	 * that area as well, on POWER4 we don't have one, etc...	 * We need that as a "hint" when sizing the TCE table on POWER3	 * So far, the simplest way that seem work well enough for us it	 * to just assume that the first discontinuity in our physical	 * RAM layout is the IO hole. That may not be correct in the future	 * (and isn't on iSeries but then we don't care ;)	 */#ifndef CONFIG_PPC_ISERIES	for (i = 1; i < lmb.memory.cnt; i++) {		unsigned long base, prevbase, prevsize;		prevbase = lmb.memory.region[i-1].physbase;		prevsize = lmb.memory.region[i-1].size;		base = lmb.memory.region[i].physbase;		if (base > (prevbase + prevsize)) {			io_hole_start = prevbase + prevsize;			io_hole_size = base  - (prevbase + prevsize);			break;		}	}#endif /* CONFIG_PPC_ISERIES */	if (io_hole_start)		printk("IO Hole assumed to be %lx -> %lx\n",		       io_hole_start, io_hole_start + io_hole_size - 1);	ppc64_boot_msg(0x100, "MM Init Done");}/* * This is called by /dev/mem to know if a given address has to * be mapped non-cacheable or not */int page_is_ram(unsigned long pfn){	int i;	unsigned long paddr = (pfn << PAGE_SHIFT);	for (i=0; i < lmb.memory.cnt; i++) {		unsigned long base;#ifdef CONFIG_MSCHUNKS		base = lmb.memory.region[i].physbase;#else		base = lmb.memory.region[i].base;#endif		if ((paddr >= base) &&			(paddr < (base + lmb.memory.region[i].size))) {			return 1;		}	}	return 0;}EXPORT_SYMBOL(page_is_ram);/* * Initialize the bootmem system and give it all the memory we * have available. */#ifndef CONFIG_DISCONTIGMEMvoid __init do_init_bootmem(void){	unsigned long i;	unsigned long start, bootmap_pages;	unsigned long total_pages = lmb_end_of_DRAM() >> PAGE_SHIFT;	int boot_mapsize;	/*	 * Find an area to use for the bootmem bitmap.  Calculate the size of	 * bitmap required as (Total Memory) / PAGE_SIZE / BITS_PER_BYTE.	 * Add 1 additional page in case the address isn't page-aligned.	 */	bootmap_pages = bootmem_bootmap_pages(total_pages);	start = abs_to_phys(lmb_alloc(bootmap_pages<<PAGE_SHIFT, PAGE_SIZE));	BUG_ON(!start);	boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages);	max_pfn = max_low_pfn;	/* add all physical memory to the bootmem map. Also find the first */	for (i=0; i < lmb.memory.cnt; i++) {		unsigned long physbase, size;		physbase = lmb.memory.region[i].physbase;		size = lmb.memory.region[i].size;		free_bootmem(physbase, size);	}	/* reserve the sections we're already using */	for (i=0; i < lmb.reserved.cnt; i++) {		unsigned long physbase = lmb.reserved.region[i].physbase;		unsigned long size = lmb.reserved.region[i].size;		reserve_bootmem(physbase, size);	}}/* * paging_init() sets up the page tables - in fact we've already done this. */void __init paging_init(void){	unsigned long zones_size[MAX_NR_ZONES];	unsigned long zholes_size[MAX_NR_ZONES];	unsigned long total_ram = lmb_phys_mem_size();	unsigned long top_of_ram = lmb_end_of_DRAM();	printk(KERN_INFO "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",	       top_of_ram, total_ram);	printk(KERN_INFO "Memory hole size: %ldMB\n",	       (top_of_ram - total_ram) >> 20);	/*	 * All pages are DMA-able so we put them all in the DMA zone.	 */	memset(zones_size, 0, sizeof(zones_size));	memset(zholes_size, 0, sizeof(zholes_size));	zones_size[ZONE_DMA] = top_of_ram >> PAGE_SHIFT;	zholes_size[ZONE_DMA] = (top_of_ram - total_ram) >> PAGE_SHIFT;	free_area_init_node(0, &contig_page_data, zones_size,			    __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size);	mem_map = contig_page_data.node_mem_map;}#endif /* CONFIG_DISCONTIGMEM */static struct kcore_list kcore_vmem;static int __init setup_kcore(void){	int i;	for (i=0; i < lmb.memory.cnt; i++) {		unsigned long physbase, size;		struct kcore_list *kcore_mem;		physbase = lmb.memory.region[i].physbase;		size = lmb.memory.region[i].size;		/* GFP_ATOMIC to avoid might_sleep warnings during boot */		kcore_mem = kmalloc(sizeof(struct kcore_list), GFP_ATOMIC);		if (!kcore_mem)			panic("mem_init: kmalloc failed\n");		kclist_add(kcore_mem, __va(physbase), size);	}	kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START);	return 0;}module_init(setup_kcore);void __init mem_init(void){#ifdef CONFIG_DISCONTIGMEM	int nid;#endif	pg_data_t *pgdat;	unsigned long i;	struct page *page;	unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize;	num_physpages = max_low_pfn;	/* RAM is assumed contiguous */	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);#ifdef CONFIG_DISCONTIGMEM        for (nid = 0; nid < numnodes; nid++) {		if (NODE_DATA(nid)->node_spanned_pages != 0) {			printk("freeing bootmem node %x\n", nid);			totalram_pages +=				free_all_bootmem_node(NODE_DATA(nid));		}	}#else	max_mapnr = num_physpages;	totalram_pages += free_all_bootmem();#endif	for_each_pgdat(pgdat) {		for (i = 0; i < pgdat->node_spanned_pages; i++) {			page = pgdat->node_mem_map + i;			if (PageReserved(page))				reservedpages++;		}	}	codesize = (unsigned long)&_etext - (unsigned long)&_stext;	initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin;	datasize = (unsigned long)&_edata - (unsigned long)&__init_end;	bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start;	printk(KERN_INFO "Memory: %luk/%luk available (%luk kernel code, "	       "%luk reserved, %luk data, %luk bss, %luk init)\n",		(unsigned long)nr_free_pages() << (PAGE_SHIFT-10),		num_physpages << (PAGE_SHIFT-10),		codesize >> 10,		reservedpages << (PAGE_SHIFT-10),		datasize >> 10,		bsssize >> 10,		initsize >> 10);	mem_init_done = 1;#ifdef CONFIG_PPC_ISERIES	iommu_vio_init();#endif}/* * This is called when a page has been modified by the kernel. * It just marks the page as not i-cache clean.  We do the i-cache * flush later when the page is given to a user process, if necessary. */void flush_dcache_page(struct page *page){	if (cur_cpu_spec->cpu_features & CPU_FTR_COHERENT_ICACHE)		return;	/* avoid an atomic op if possible */	if (test_bit(PG_arch_1, &page->flags))		clear_bit(PG_arch_1, &page->flags);}void clear_user_page(void *page, unsigned long vaddr, struct page *pg){	clear_page(page);	if (cur_cpu_spec->cpu_features & CPU_FTR_COHERENT_ICACHE)		return;	/*	 * We shouldnt have to do this, but some versions of glibc	 * require it (ld.so assumes zero filled pages are icache clean)	 * - Anton	 */	/* avoid an atomic op if possible */	if (test_bit(PG_arch_1, &pg->flags))		clear_bit(PG_arch_1, &pg->flags);}void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,		    struct page *pg){	copy_page(vto, vfrom);	/*	 * We should be able to use the following optimisation, however	 * there are two problems.	 * Firstly a bug in some versions of binutils meant PLT sections	 * were not marked executable.	 * Secondly the first word in the GOT section is blrl, used	 * to establish the GOT address. Until recently the GOT was	 * not marked executable.	 * - Anton	 */#if 0	if (!vma->vm_file && ((vma->vm_flags & VM_EXEC) == 0))		return;#endif	if (cur_cpu_spec->cpu_features & CPU_FTR_COHERENT_ICACHE)		return;	/* avoid an atomic op if possible */	if (test_bit(PG_arch_1, &pg->flags))		clear_bit(PG_arch_1, &pg->flags);}void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,			     unsigned long addr, int len){	unsigned long maddr;	maddr = (unsigned long)page_address(page) + (addr & ~PAGE_MASK);	flush_icache_range(maddr, maddr + len);}/* * This is called at the end of handling a user page fault, when the * fault has been handled by updating a PTE in the linux page tables. * We use it to preload an HPTE into the hash table corresponding to * the updated linux PTE. *  * This must always be called with the mm->page_table_lock held */void update_mmu_cache(struct vm_area_struct *vma, unsigned long ea,		      pte_t pte){	unsigned long vsid;	void *pgdir;	pte_t *ptep;	int local = 0;	cpumask_t tmp;	unsigned long flags;	/* handle i-cache coherency */	if (!(cur_cpu_spec->cpu_features & CPU_FTR_COHERENT_ICACHE) &&	    !(cur_cpu_spec->cpu_features & CPU_FTR_NOEXECUTE)) {		unsigned long pfn = pte_pfn(pte);		if (pfn_valid(pfn)) {			struct page *page = pfn_to_page(pfn);			if (!PageReserved(page)			    && !test_bit(PG_arch_1, &page->flags)) {				__flush_dcache_icache(page_address(page));				set_bit(PG_arch_1, &page->flags);			}		}	}	/* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */	if (!pte_young(pte))		return;	pgdir = vma->vm_mm->pgd;	if (pgdir == NULL)		return;	ptep = find_linux_pte(pgdir, ea);	if (!ptep)		return;	vsid = get_vsid(vma->vm_mm->context.id, ea);	local_irq_save(flags);	tmp = cpumask_of_cpu(smp_processor_id());	if (cpus_equal(vma->vm_mm->cpu_vm_mask, tmp))		local = 1;	__hash_page(ea, pte_val(pte) & (_PAGE_USER|_PAGE_RW), vsid, ptep,		    0x300, local);	local_irq_restore(flags);}void * reserve_phb_iospace(unsigned long size){	void *virt_addr;			if (phbs_io_bot >= IMALLOC_BASE) 		panic("reserve_phb_iospace(): phb io space overflow\n");				virt_addr = (void *) phbs_io_bot;	phbs_io_bot += size;	return virt_addr;}kmem_cache_t *zero_cache;static void zero_ctor(void *pte, kmem_cache_t *cache, unsigned long flags){	memset(pte, 0, PAGE_SIZE);}void pgtable_cache_init(void){	zero_cache = kmem_cache_create("zero",				PAGE_SIZE,				0,				SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN,				zero_ctor,				NULL);	if (!zero_cache)		panic("pgtable_cache_init(): could not create zero_cache!\n");}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?