⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 init.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  $Id: init.c,v 1.195 1999/10/15 16:39:39 cort Exp $ * *  PowerPC version  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) *  and Cort Dougan (PReP) (cort@cs.nmt.edu) *    Copyright (C) 1996 Paul Mackerras *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). * *  Derived from "arch/i386/mm/init.c" *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds * *  This program is free software; you can redistribute it and/or *  modify it under the terms of the GNU General Public License *  as published by the Free Software Foundation; either version *  2 of the License, or (at your option) any later version. * */#include <linux/config.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/types.h>#include <linux/ptrace.h>#include <linux/mman.h>#include <linux/mm.h>#include <linux/swap.h>#include <linux/stddef.h>#include <linux/vmalloc.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/openpic.h>#include <linux/bootmem.h>#include <linux/highmem.h>#ifdef CONFIG_BLK_DEV_INITRD#include <linux/blk.h>		/* for initrd_* */#endif#include <asm/pgalloc.h>#include <asm/prom.h>#include <asm/io.h>#include <asm/mmu_context.h>#include <asm/pgtable.h>#include <asm/mmu.h>#include <asm/residual.h>#include <asm/uaccess.h>#ifdef CONFIG_8xx#include <asm/8xx_immap.h>#include <asm/mpc8xx.h>#endif#ifdef CONFIG_8260#include <asm/immap_8260.h>#include <asm/mpc8260.h>#endif#include <asm/smp.h>#include <asm/bootx.h>#include <asm/machdep.h>#include <asm/setup.h>#include <asm/amigahw.h>#include <asm/gemini.h>#include "mem_pieces.h"#if defined(CONFIG_4xx)#include "4xx_tlb.h"#endif#define MAX_LOW_MEM	(640 << 20)#define	PGTOKB(pages)	(((pages) * PAGE_SIZE) >> 10)int prom_trashed;atomic_t next_mmu_context;unsigned long *end_of_DRAM;unsigned long total_memory;unsigned long total_lowmem;int mem_init_done;int init_bootmem_done;int boot_mapsize;unsigned long totalram_pages;unsigned long totalhigh_pages;extern pgd_t swapper_pg_dir[];extern char _start[], _end[];extern char etext[], _stext[];extern char __init_begin, __init_end;extern char __prep_begin, __prep_end;extern char __chrp_begin, __chrp_end;extern char __pmac_begin, __pmac_end;extern char __apus_begin, __apus_end;extern char __openfirmware_begin, __openfirmware_end;struct device_node *memory_node;unsigned long ioremap_base;unsigned long ioremap_bot;unsigned long avail_start;extern int num_memory;extern struct mem_info memory[];extern boot_infos_t *boot_infos;extern unsigned int rtas_data, rtas_size;#ifndef CONFIG_SMPstruct pgtable_cache_struct quicklists;#endif#ifdef CONFIG_HIGHMEMpte_t *kmap_pte;pgprot_t kmap_prot;#endifvoid MMU_init(void);static void *MMU_get_page(void);unsigned long prep_find_end_of_memory(void);unsigned long pmac_find_end_of_memory(void);unsigned long apus_find_end_of_memory(void);unsigned long gemini_find_end_of_memory(void);extern unsigned long find_end_of_memory(void);#ifdef CONFIG_8xxunsigned long m8xx_find_end_of_memory(void);#endif /* CONFIG_8xx */#ifdef CONFIG_4xxunsigned long oak_find_end_of_memory(void);#endif#ifdef CONFIG_8260unsigned long m8260_find_end_of_memory(void);#endif /* CONFIG_8260 */static void mapin_ram(void);void map_page(unsigned long va, unsigned long pa, int flags);void set_phys_avail(struct mem_pieces *mp);extern void die_if_kernel(char *,struct pt_regs *,long);extern char _start[], _end[];extern char _stext[], etext[];extern struct task_struct *current_set[NR_CPUS];struct mem_pieces phys_mem;char *klimit = _end;struct mem_pieces phys_avail;PTE *Hash, *Hash_end;unsigned long Hash_size, Hash_mask;#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)unsigned long _SDR1;static void hash_init(void);union ubat {			/* BAT register values to be loaded */	BAT	bat;#ifdef CONFIG_PPC64BRIDGE	u64	word[2];#else	u32	word[2];#endif	} BATS[4][2];			/* 4 pairs of IBAT, DBAT */struct batrange {		/* stores address ranges mapped by BATs */	unsigned long start;	unsigned long limit;	unsigned long phys;} bat_addrs[4];/* * Return PA for this VA if it is mapped by a BAT, or 0 */static inline unsigned long v_mapped_by_bats(unsigned long va){	int b;	for (b = 0; b < 4; ++b)		if (va >= bat_addrs[b].start && va < bat_addrs[b].limit)			return bat_addrs[b].phys + (va - bat_addrs[b].start);	return 0;}/* * Return VA for a given PA or 0 if not mapped */static inline unsigned long p_mapped_by_bats(unsigned long pa){	int b;	for (b = 0; b < 4; ++b)		if (pa >= bat_addrs[b].phys	    	    && pa < (bat_addrs[b].limit-bat_addrs[b].start)		              +bat_addrs[b].phys)			return bat_addrs[b].start+(pa-bat_addrs[b].phys);	return 0;}#else /* CONFIG_4xx || CONFIG_8xx */#define v_mapped_by_bats(x)	(0UL)#define p_mapped_by_bats(x)	(0UL)#endif /* !CONFIG_4xx && !CONFIG_8xx *//* * this tells the system to map all of ram with the segregs * (i.e. page tables) instead of the bats. * -- Cort */int __map_without_bats;/* max amount of RAM to use */unsigned long __max_memory;void __bad_pte(pmd_t *pmd){	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));	pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;}pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset){        pte_t *pte;        if (pmd_none(*pmd)) {		if (!mem_init_done)			pte = (pte_t *) MMU_get_page();		else if ((pte = (pte_t *) __get_free_page(GFP_KERNEL)))			clear_page(pte);                if (pte) {                        pmd_val(*pmd) = (unsigned long)pte;                        return pte + offset;                }		pmd_val(*pmd) = (unsigned long)BAD_PAGETABLE;                return NULL;        }        if (pmd_bad(*pmd)) {                __bad_pte(pmd);                return NULL;        }        return (pte_t *) pmd_page(*pmd) + offset;}int do_check_pgt_cache(int low, int high){	int freed = 0;	if(pgtable_cache_size > high) {		do {			if(pgd_quicklist)				free_pgd_slow(get_pgd_fast()), freed++;			if(pmd_quicklist)				free_pmd_slow(get_pmd_fast()), freed++;			if(pte_quicklist)				free_pte_slow(get_pte_fast()), freed++;		} while(pgtable_cache_size > low);	}	return freed;}/* * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a * do_exit(), but using this instead means there is less risk * for a process dying in kernel mode, possibly leaving a inode * unused etc.. * * BAD_PAGETABLE is the accompanying page-table: it is initialized * to point to BAD_PAGE entries. * * ZERO_PAGE is a special page that is used for zero-initialized * data and COW. */pte_t *empty_bad_page_table;pte_t * __bad_pagetable(void){	clear_page(empty_bad_page_table);	return empty_bad_page_table;}void *empty_bad_page;pte_t __bad_page(void){	clear_page(empty_bad_page);	return pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED));}void show_mem(void){	int i,free = 0,total = 0,reserved = 0;	int shared = 0, cached = 0;	struct task_struct *p;	int highmem = 0;	printk("Mem-info:\n");	show_free_areas();	printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));	i = max_mapnr;	while (i-- > 0) {		total++;		if (PageHighMem(mem_map+i))			highmem++;		if (PageReserved(mem_map+i))			reserved++;		else if (PageSwapCache(mem_map+i))			cached++;		else if (!page_count(mem_map+i))			free++;		else			shared += atomic_read(&mem_map[i].count) - 1;	}	printk("%d pages of RAM\n",total);	printk("%d pages of HIGHMEM\n", highmem);	printk("%d free pages\n",free);	printk("%d reserved pages\n",reserved);	printk("%d pages shared\n",shared);	printk("%d pages swap cached\n",cached);	printk("%d pages in page table cache\n",(int)pgtable_cache_size);	show_buffers();	printk("%-8s %3s %8s %8s %8s %9s %8s", "Process", "Pid",	       "Ctx", "Ctx<<4", "Last Sys", "pc", "task");#ifdef CONFIG_SMP	printk(" %3s", "CPU");#endif /* CONFIG_SMP */	printk("\n");	for_each_task(p)	{		printk("%-8.8s %3d %8ld %8ld %8ld %c%08lx %08lx ",		       p->comm,p->pid,		       (p->mm)?p->mm->context:0,		       (p->mm)?(p->mm->context<<4):0,		       p->thread.last_syscall,		       (p->thread.regs)?user_mode(p->thread.regs) ? 'u' : 'k' : '?',		       (p->thread.regs)?p->thread.regs->nip:0,		       (ulong)p);		{			int iscur = 0;#ifdef CONFIG_SMP			printk("%3d ", p->processor);			if ( (p->processor != NO_PROC_ID) &&			     (p == current_set[p->processor]) )			{				iscur = 1;				printk("current");			}#else			if ( p == current )			{				iscur = 1;				printk("current");			}						if ( p == last_task_used_math )			{				if ( iscur )					printk(",");				printk("last math");			}			#endif /* CONFIG_SMP */			printk("\n");		}	}}void si_meminfo(struct sysinfo *val){	int i;	i = max_mapnr;	val->totalram = 0;	val->sharedram = 0;	val->freeram = nr_free_pages();	val->bufferram = atomic_read(&buffermem_pages);	while (i-- > 0)  {		if (PageReserved(mem_map+i))			continue;		val->totalram++;		if (!atomic_read(&mem_map[i].count))			continue;		val->sharedram += atomic_read(&mem_map[i].count) - 1;	}	val->totalhigh = totalhigh_pages;	val->freehigh = nr_free_highpages();	val->mem_unit = PAGE_SIZE;}void *ioremap(unsigned long addr, unsigned long size){	return __ioremap(addr, size, _PAGE_NO_CACHE);}void *__ioremap(unsigned long addr, unsigned long size, unsigned long flags){	unsigned long p, v, i;	/*	 * Choose an address to map it to.	 * Once the vmalloc system is running, we use it.	 * Before then, we map addresses >= ioremap_base	 * virt == phys; for addresses below this we use	 * space going down from ioremap_base (ioremap_bot	 * records where we're up to).	 */	p = addr & PAGE_MASK;	size = PAGE_ALIGN(addr + size) - p;	/*	 * If the address lies within the first 16 MB, assume it's in ISA	 * memory space	 */	if (p < 16*1024*1024)	    p += _ISA_MEM_BASE;	/*	 * Don't allow anybody to remap normal RAM that we're using.	 * mem_init() sets high_memory so only do the check after that.	 */	if ( mem_init_done && (p < virt_to_phys(high_memory)) )	{		printk("__ioremap(): phys addr %0lx is RAM lr %p\n", p,		       __builtin_return_address(0));		return NULL;	}	if (size == 0)		return NULL;	/*	 * Is it already mapped?  Perhaps overlapped by a previous	 * BAT mapping.  If the whole area is mapped then we're done,	 * otherwise remap it since we want to keep the virt addrs for	 * each request contiguous.	 *	 * We make the assumption here that if the bottom and top	 * of the range we want are mapped then it's mapped to the	 * same virt address (and this is contiguous).	 *  -- Cort	 */	if ((v = p_mapped_by_bats(p)) /*&& p_mapped_by_bats(p+size-1)*/ )		goto out;		if (mem_init_done) {		struct vm_struct *area;		area = get_vm_area(size, VM_IOREMAP);		if (area == 0)			return NULL;		v = VMALLOC_VMADDR(area->addr);	} else {		if (p >= ioremap_base)			v = p;		else			v = (ioremap_bot -= size);	}	if ((flags & _PAGE_PRESENT) == 0)		flags |= pgprot_val(PAGE_KERNEL);	if (flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU))		flags |= _PAGE_GUARDED;	/*	 * Is it a candidate for a BAT mapping?	 */	for (i = 0; i < size; i += PAGE_SIZE)		map_page(v+i, p+i, flags);out:	return (void *) (v + (addr & ~PAGE_MASK));}void iounmap(void *addr){	if (addr > high_memory && (unsigned long) addr < ioremap_bot)		vfree((void *) (PAGE_MASK & (unsigned long) addr));}unsigned long iopa(unsigned long addr){	unsigned long pa;	pmd_t *pd;	pte_t *pg;	/* Check the BATs */	pa = v_mapped_by_bats(addr);	if (pa)		return pa;	/* Do we have a page table? */	if (init_mm.pgd == NULL)		return 0;	/* Use upper 10 bits of addr to index the first level map */	pd = (pmd_t *) (init_mm.pgd + (addr >> PGDIR_SHIFT));	if (pmd_none(*pd))		return 0;	/* Use middle 10 bits of addr to index the second-level map */	pg = pte_offset(pd, addr);	return (pte_val(*pg) & PAGE_MASK) | (addr & ~PAGE_MASK);}voidmap_page(unsigned long va, unsigned long pa, int flags){	pmd_t *pd, oldpd;	pte_t *pg;	/* Use upper 10 bits of VA to index the first level map */	pd = pmd_offset(pgd_offset_k(va), va);	oldpd = *pd;	/* Use middle 10 bits of VA to index the second-level map */	pg = pte_alloc(pd, va);	if (pmd_none(oldpd) && mem_init_done)		set_pgdir(va, *(pgd_t *)pd);	set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags)));	if (mem_init_done)		flush_hash_page(0, va);}#ifndef CONFIG_8xx/* * TLB flushing: * *  - flush_tlb_all() flushes all processes TLBs *  - flush_tlb_mm(mm) flushes the specified mm context TLB's *  - flush_tlb_page(vma, vmaddr) flushes one page *  - flush_tlb_range(mm, start, end) flushes a range of pages * * since the hardware hash table functions as an extension of the * tlb as far as the linux tables are concerned, flush it too. *    -- Cort *//* * Flush all tlb/hash table entries (except perhaps for those * mapping RAM starting at PAGE_OFFSET, since they never change). */voidlocal_flush_tlb_all(void){#ifdef CONFIG_PPC64BRIDGE	/* XXX this assumes that the vmalloc arena starts no lower than	 * 0xd0000000 on 64-bit machines. */	flush_hash_segments(0xd, 0xffffff);#else	__clear_user(Hash, Hash_size);	_tlbia();#ifdef CONFIG_SMP	smp_send_tlb_invalidate(0);#endif /* CONFIG_SMP */#endif /* CONFIG_PPC64BRIDGE */}/* * Flush all the (user) entries for the address space described * by mm.  We can't rely on mm->mmap describing all the entries * that might be in the hash table.

⌨️ 快捷键说明

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