📄 sun4c.c
字号:
/* 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_hw(struct mm_struct *mm){ struct ctx_list *ctx_old; if (mm->context != NO_CONTEXT) { sun4c_demap_context_hw(&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 void sun4c_alloc_context_sw(struct mm_struct *old_mm, struct mm_struct *mm){ struct ctx_list *ctxp; ctxp = ctx_free.next; 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 void sun4c_mmu_info(struct seq_file *m){ int used_user_entries, i; used_user_entries = 0; for (i = 0; i < num_contexts; i++) used_user_entries += sun4c_context_ring[i].num_entries; seq_printf(m, "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);}/* 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_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 */static 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));}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);}static 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;}static void sun4c_free_pgd_fast(pgd_t *pgd){ *(unsigned long *)pgd = (unsigned long) pgd_quicklist; pgd_quicklist = (unsigned long *) pgd; pgtable_cache_size++;}static pte_t *sun4c_pte_alloc_one(struct mm_struct *mm, unsigned long address){ pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL); if (pte) memset(pte, 0, PAGE_SIZE); return pte;}pte_t *sun4c_pte_alloc_one_fast(struct mm_struct *mm, unsigned long address){ 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;}static __inline__ void sun4c_free_pte_fast(pte_t *pte){ *(unsigned long *)pte = (unsigned long) pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++;}/* * allocating and freeing a pmd is trivial: the 1-entry pmd is * inside the pgd, so has no extra memory associated with it. */static pmd_t *sun4c_pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address){ BUG(); return NULL;}static void sun4c_free_pmd_fast(pmd_t * pmd){}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++; if (pte_quicklist) sun4c_free_pte_slow(sun4c_pte_alloc_one_fast(NULL, 0)), 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 unsigned long bootmem_init(unsigned long *pages_avail);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, pages_avail; kernel_end = (unsigned long) &end; kernel_end += (SUN4C_REAL_PGDIR_SIZE * 4); kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end); pages_avail = 0; last_valid_pfn = bootmem_init(&pages_avail); 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); vaddr += SUN4C_PGDIR_SIZE; swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg1); vaddr += SUN4C_PGDIR_SIZE; swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg2); vaddr += SUN4C_PGDIR_SIZE; swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg3); sun4c_init_ss2_cache_bug(); sparc_context_init(num_contexts); { unsigned long zones_size[MAX_NR_ZONES]; unsigned long zholes_size[MAX_NR_ZONES]; unsigned long npages; int znum; for (znum = 0; znum < MAX_NR_ZONES; znum++) zones_size[znum] = zholes_size[znum] = 0; npages = max_low_pfn - (phys_base >> PAGE_SHIFT); zones_size[ZONE_DMA] = npages; zholes_size[ZONE_DMA] = npages - pages_avail; npages = highend_pfn - max_low_pfn; zones_size[ZONE_HIGHMEM] = npages; zholes_size[ZONE_HIGHMEM] = npages - calc_highpages(); free_area_init_node(0, NULL, NULL, zones_size, phys_base, zholes_size); } cnt = 0; for (i = 0; i < num_segmaps; i++) if (mmu_entry_pool[i].locked) cnt++; max_user_taken_entries = num_segmaps - cnt - 40 - 1; printk("SUN4C: %d mmu entries for the kernel\n", cnt);}/* Load up routines and constants for sun4c mmu */void __init ld_mmu_sun4c(void){ extern void ___xchg32_sun4c(void); printk("Loading sun4c MMU routines\n"); /* First the constants */ BTFIXUPSET_SIMM13(pmd_shift, SUN4C_PMD_SHIFT); BTFIXUPSET_SETHI(pmd_size, SUN4C_PMD_SIZE); BTFIXUPSET_SETHI(pmd_mask, SUN4C_PMD_MASK); BTFIXUPSET_SIMM13(pgdir_shift, SUN4C_PGDIR_SHIFT); BTFIXUPSET_SETHI(pgdir_size, SUN4C_PGDIR_SIZE); BTFIXUPSET_SETHI(pgdir_mask, SUN4C_PGDIR_MASK); BTFIXUPSET_SIMM13(ptrs_per_pte, SUN4C_PTRS_PER_PTE); BTFIXUPSET_SIMM13(ptrs_per_pmd, SUN4C_PTRS_PER_PMD); BTFIXUPSET_SIMM13(ptrs_per_pgd, SUN4C_PTRS_PER_PGD); BTFIXUPSET_SIMM13(user_ptrs_per_pgd, KERNBASE / SUN4C_PGDIR_SIZE); BTFIXUPSET_INT(page_none, pgpr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -