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

📄 sun4c.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (ctxp != &ctx_free) {		remove_from_ctx_list(ctxp);		add_to_used_ctxlist(ctxp);		mm->context = ctxp->ctx_number;		ctxp->ctx_mm = mm;		return;	}	ctxp = ctx_used.next;	if(ctxp->ctx_mm == old_mm)		ctxp = ctxp->next;	remove_from_ctx_list(ctxp);	add_to_used_ctxlist(ctxp);	ctxp->ctx_mm->context = NO_CONTEXT;	ctxp->ctx_mm = mm;	mm->context = ctxp->ctx_number;	sun4c_demap_context_sw(&sun4c_context_ring[ctxp->ctx_number],			       ctxp->ctx_number);}/* Switch the current MM context. */static void sun4c_switch_mm_sw(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu){	struct ctx_list *ctx;	int dirty = 0;	if (mm->context == NO_CONTEXT) {		dirty = 1;		sun4c_alloc_context_sw(old_mm, mm);	} else {		/* Update the LRU ring of contexts. */		ctx = ctx_list_pool + mm->context;		remove_from_ctx_list(ctx);		add_to_used_ctxlist(ctx);	}	if (dirty || old_mm != mm)		sun4c_set_context(mm->context);}static void sun4c_destroy_context_sw(struct mm_struct *mm){	struct ctx_list *ctx_old;	if (mm->context != NO_CONTEXT) {		sun4c_demap_context_sw(&sun4c_context_ring[mm->context], mm->context);		ctx_old = ctx_list_pool + mm->context;		remove_from_ctx_list(ctx_old);		add_to_free_ctxlist(ctx_old);		mm->context = NO_CONTEXT;	}}static int sun4c_mmu_info(char *buf){	int used_user_entries, i;	int len;	used_user_entries = 0;	for (i = 0; i < num_contexts; i++)		used_user_entries += sun4c_context_ring[i].num_entries;	len = sprintf(buf, 		"vacsize\t\t: %d bytes\n"		"vachwflush\t: %s\n"		"vaclinesize\t: %d bytes\n"		"mmuctxs\t\t: %d\n"		"mmupsegs\t: %d\n"		"kernelpsegs\t: %d\n"		"kfreepsegs\t: %d\n"		"usedpsegs\t: %d\n"		"ufreepsegs\t: %d\n"		"user_taken\t: %d\n"		"max_taken\t: %d\n",		sun4c_vacinfo.num_bytes,		(sun4c_vacinfo.do_hwflushes ? "yes" : "no"),		sun4c_vacinfo.linesize,		num_contexts,		(invalid_segment + 1),		sun4c_kernel_ring.num_entries,		sun4c_kfree_ring.num_entries,		used_user_entries,		sun4c_ufree_ring.num_entries,		sun4c_user_taken_entries,		max_user_taken_entries);	return len;}/* Nothing below here should touch the mmu hardware nor the mmu_entry * data structures. *//* First the functions which the mid-level code uses to directly * manipulate the software page tables.  Some defines since we are * emulating the i386 page directory layout. */#define PGD_PRESENT  0x001#define PGD_RW       0x002#define PGD_USER     0x004#define PGD_ACCESSED 0x020#define PGD_DIRTY    0x040#define PGD_TABLE    (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY)static int sun4c_pte_present(pte_t pte){	return ((pte_val(pte) & (_SUN4C_PAGE_PRESENT | _SUN4C_PAGE_PRIV)) != 0);}static void sun4c_pte_clear(pte_t *ptep)	{ *ptep = __pte(0); }static int sun4c_pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }static int sun4c_pmd_bad(pmd_t pmd){	return (((pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE) ||		(!VALID_PAGE(virt_to_page(pmd_val(pmd)))));}static int sun4c_pmd_present(pmd_t pmd){	return ((pmd_val(pmd) & PGD_PRESENT) != 0);}static void sun4c_pmd_clear(pmd_t *pmdp)	{ *pmdp = __pmd(0); }static int sun4c_pgd_none(pgd_t pgd)		{ return 0; }static int sun4c_pgd_bad(pgd_t pgd)		{ return 0; }static int sun4c_pgd_present(pgd_t pgd)	        { return 1; }static void sun4c_pgd_clear(pgd_t * pgdp)	{ }/* * The following only work if pte_present() is true. * Undefined behaviour if not.. */static pte_t sun4c_pte_mkwrite(pte_t pte){	pte = __pte(pte_val(pte) | _SUN4C_PAGE_WRITE);	if (pte_val(pte) & _SUN4C_PAGE_MODIFIED)		pte = __pte(pte_val(pte) | _SUN4C_PAGE_SILENT_WRITE);	return pte;}static pte_t sun4c_pte_mkdirty(pte_t pte){	pte = __pte(pte_val(pte) | _SUN4C_PAGE_MODIFIED);	if (pte_val(pte) & _SUN4C_PAGE_WRITE)		pte = __pte(pte_val(pte) | _SUN4C_PAGE_SILENT_WRITE);	return pte;}static pte_t sun4c_pte_mkyoung(pte_t pte){	pte = __pte(pte_val(pte) | _SUN4C_PAGE_ACCESSED);	if (pte_val(pte) & _SUN4C_PAGE_READ)		pte = __pte(pte_val(pte) | _SUN4C_PAGE_SILENT_READ);	return pte;}/* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. */static pte_t sun4c_mk_pte(struct page *page, pgprot_t pgprot){	return __pte((page - mem_map) | pgprot_val(pgprot));}static pte_t sun4c_mk_pte_phys(unsigned long phys_page, pgprot_t pgprot){	return __pte((phys_page >> PAGE_SHIFT) | pgprot_val(pgprot));}static pte_t sun4c_mk_pte_io(unsigned long page, pgprot_t pgprot, int space){	return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));}static struct page *sun4c_pte_page(pte_t pte){	return (mem_map + (unsigned long)(pte_val(pte) & SUN4C_PFN_MASK));}static inline unsigned long sun4c_pmd_page(pmd_t pmd){	return (pmd_val(pmd) & PAGE_MASK);}static unsigned long sun4c_pgd_page(pgd_t pgd){	return 0;}/* to find an entry in a page-table-directory */extern inline pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address){	return mm->pgd + (address >> SUN4C_PGDIR_SHIFT);}/* Find an entry in the second-level page table.. */static pmd_t *sun4c_pmd_offset(pgd_t * dir, unsigned long address){	return (pmd_t *) dir;}/* Find an entry in the third-level page table.. */ pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address){	return (pte_t *) sun4c_pmd_page(*dir) +	((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1));}/* Please take special note on the foo_kernel() routines below, our * fast in window fault handler wants to get at the pte's for vmalloc * area with traps off, therefore they _MUST_ be locked down to prevent * a watchdog from happening.  It only takes 4 pages of pte's to lock * down the maximum vmalloc space possible on sun4c so we statically * allocate these page table pieces in the kernel image.  Therefore * we should never have to really allocate or free any kernel page * table information. *//* Allocate and free page tables. The xxx_kernel() versions are * used to allocate a kernel page table - this turns on ASN bits * if any, and marks the page tables reserved. */static void sun4c_pte_free_kernel(pte_t *pte){	/* This should never get called. */	panic("sun4c_pte_free_kernel called, can't happen...");}static pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address){	if (address >= SUN4C_LOCK_VADDR)		return NULL;	address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);	if (sun4c_pmd_none(*pmd))		panic("sun4c_pmd_none for kernel pmd, can't happen...");	if (sun4c_pmd_bad(*pmd)) {		printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));		*pmd = __pmd(PGD_TABLE | (unsigned long) BAD_PAGETABLE);		return NULL;	}	return (pte_t *) sun4c_pmd_page(*pmd) + address;}static void sun4c_free_pte_slow(pte_t *pte){	free_page((unsigned long)pte);}static void sun4c_free_pgd_slow(pgd_t *pgd){	free_page((unsigned long)pgd);}/* * allocating and freeing a pmd is trivial: the 1-entry pmd is * inside the pgd, so has no extra memory associated with it. */static void sun4c_pmd_free_kernel(pmd_t *pmd){}static pmd_t *sun4c_pmd_alloc_kernel(pgd_t *pgd, unsigned long address){	return (pmd_t *) pgd;}extern __inline__ pgd_t *sun4c_get_pgd_fast(void){	unsigned long *ret;	if ((ret = pgd_quicklist) != NULL) {		pgd_quicklist = (unsigned long *)(*ret);		ret[0] = ret[1];		pgtable_cache_size--;	} else {		pgd_t *init;				ret = (unsigned long *)__get_free_page(GFP_KERNEL);		memset (ret, 0, (KERNBASE / SUN4C_PGDIR_SIZE) * sizeof(pgd_t));		init = sun4c_pgd_offset(&init_mm, 0);		memcpy (((pgd_t *)ret) + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));	}	return (pgd_t *)ret;}extern __inline__ void sun4c_free_pgd_fast(pgd_t *pgd){	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;	pgd_quicklist = (unsigned long *) pgd;	pgtable_cache_size++;}extern __inline__ pte_t *sun4c_get_pte_fast(void){	unsigned long *ret;	if ((ret = (unsigned long *)pte_quicklist) != NULL) {		pte_quicklist = (unsigned long *)(*ret);		ret[0] = ret[1];		pgtable_cache_size--;	}	return (pte_t *)ret;}extern __inline__ void sun4c_free_pte_fast(pte_t *pte){	*(unsigned long *)pte = (unsigned long) pte_quicklist;	pte_quicklist = (unsigned long *) pte;	pgtable_cache_size++;}static void sun4c_pte_free(pte_t *pte){	sun4c_free_pte_fast(pte);}static pte_t *sun4c_pte_alloc(pmd_t * pmd, unsigned long address){	address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);	if (sun4c_pmd_none(*pmd)) {		pte_t *page = (pte_t *) sun4c_get_pte_fast();				if (page) {			*pmd = __pmd(PGD_TABLE | (unsigned long) page);			return page + address;		}		page = (pte_t *) get_free_page(GFP_KERNEL);		if (sun4c_pmd_none(*pmd)) {			if (page) {				*pmd = __pmd(PGD_TABLE | (unsigned long) page);				return page + address;			}			*pmd = __pmd(PGD_TABLE | (unsigned long) BAD_PAGETABLE);			return NULL;		}		free_page((unsigned long) page);	}	if (sun4c_pmd_bad(*pmd)) {		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));		*pmd = __pmd(PGD_TABLE | (unsigned long) BAD_PAGETABLE);		return NULL;	}	return (pte_t *) sun4c_pmd_page(*pmd) + address;}/* * allocating and freeing a pmd is trivial: the 1-entry pmd is * inside the pgd, so has no extra memory associated with it. */static void sun4c_pmd_free(pmd_t * pmd){}static pmd_t *sun4c_pmd_alloc(pgd_t * pgd, unsigned long address){	return (pmd_t *) pgd;}static void sun4c_pgd_free(pgd_t *pgd){	sun4c_free_pgd_fast(pgd);}static pgd_t *sun4c_pgd_alloc(void){	return sun4c_get_pgd_fast();}static int sun4c_check_pgt_cache(int low, int high){	int freed = 0;	if (pgtable_cache_size > high) {		do {			if (pgd_quicklist)				sun4c_free_pgd_slow(sun4c_get_pgd_fast()), freed++;	/* Only two level page tables at the moment, sun4 3 level mmu is not supported - Anton */#if 0			if (pmd_quicklist)				sun4c_free_pmd_slow(sun4c_get_pmd_fast()), freed++;#endif			if (pte_quicklist)				sun4c_free_pte_slow(sun4c_get_pte_fast()), freed++;		} while (pgtable_cache_size > low);	}	return freed;}/* An experiment, turn off by default for now... -DaveM */#define SUN4C_PRELOAD_PSEGvoid sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte){	unsigned long flags;	int pseg;	save_and_cli(flags);	address &= PAGE_MASK;	if ((pseg = sun4c_get_segmap(address)) == invalid_segment) {		struct sun4c_mmu_entry *entry = sun4c_user_strategy();		struct mm_struct *mm = vma->vm_mm;		unsigned long start, end;		entry->vaddr = start = (address & SUN4C_REAL_PGDIR_MASK);		entry->ctx = mm->context;		add_ring_ordered(sun4c_context_ring + mm->context, entry);		sun4c_put_segmap(entry->vaddr, entry->pseg);		end = start + SUN4C_REAL_PGDIR_SIZE;		while (start < end) {#ifdef SUN4C_PRELOAD_PSEG			pgd_t *pgdp = sun4c_pgd_offset(mm, start);			pte_t *ptep;			if (!pgdp)				goto no_mapping;			ptep = sun4c_pte_offset((pmd_t *) pgdp, start);			if (!ptep || !(pte_val(*ptep) & _SUN4C_PAGE_PRESENT))				goto no_mapping;			sun4c_put_pte(start, pte_val(*ptep));			goto next;		no_mapping:#endif			sun4c_put_pte(start, 0);#ifdef SUN4C_PRELOAD_PSEG		next:#endif			start += PAGE_SIZE;		}#ifndef SUN4C_PRELOAD_PSEG		sun4c_put_pte(address, pte_val(pte));#endif		restore_flags(flags);		return;	} else {		struct sun4c_mmu_entry *entry = &mmu_entry_pool[pseg];		remove_lru(entry);		add_lru(entry);	}	sun4c_put_pte(address, pte_val(pte));	restore_flags(flags);}extern void sparc_context_init(int);extern unsigned long end;extern void bootmem_init(void);extern unsigned long last_valid_pfn;extern void sun_serial_setup(void);void __init sun4c_paging_init(void){	int i, cnt;	unsigned long kernel_end, vaddr;	extern struct resource sparc_iomap;	unsigned long end_pfn;	kernel_end = (unsigned long) &end;	kernel_end += (SUN4C_REAL_PGDIR_SIZE * 4);	kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);	bootmem_init();	end_pfn = last_valid_pfn;	/* This does not logically belong here, but we need to	 * call it at the moment we are able to use the bootmem	 * allocator.	 */	sun_serial_setup();	sun4c_probe_mmu();	invalid_segment = (num_segmaps - 1);	sun4c_init_mmu_entry_pool();	sun4c_init_rings();	sun4c_init_map_kernelprom(kernel_end);	sun4c_init_clean_mmu(kernel_end);	sun4c_init_fill_kernel_ring(SUN4C_KERNEL_BUCKETS);	sun4c_init_lock_area(sparc_iomap.start, IOBASE_END);	sun4c_init_lock_area(DVMA_VADDR, DVMA_END);	sun4c_init_lock_areas();	sun4c_init_fill_user_ring();	sun4c_set_context(0);	memset(swapper_pg_dir, 0, PAGE_SIZE);	memset(pg0, 0, PAGE_SIZE);	memset(pg1, 0, PAGE_SIZE);	memset(pg2, 0, PAGE_SIZE);	memset(pg3, 0, PAGE_SIZE);	/* Save work later. */	vaddr = VMALLOC_START;	swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg0);

⌨️ 快捷键说明

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