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

📄 vm_machdep.c

📁 早期freebsd实现
💻 C
字号:
/* * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Computer Consoles Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	@(#)vm_machdep.c	7.10 (Berkeley) 9/23/93 */#include "sys/param.h"#include "sys/systm.h"#include "sys/user.h"#include "sys/proc.h"#include "sys/cmap.h"#include "sys/vm.h"#include "sys/text.h"#include "sys/kernel.h"#include "../include/pte.h"#include "../include/cpu.h"#include "../include/mtpr.h"/* * Set a red zone in the kernel stack after the u. area. */setredzone(pte, vaddr)	register struct pte *pte;	caddr_t vaddr;{	pte += (sizeof (struct user) + NBPG - 1) / NBPG;	*(int *)pte &= ~PG_PROT;	*(int *)pte |= PG_URKR;	if (vaddr)		mtpr(TBIS, vaddr + sizeof (struct user) + NBPG - 1);}/* * Check for valid program size * NB - Check data and data growth separately as they may overflow  * when summed together. */chksize(ts, ids, uds, ss)	register unsigned ts, ids, uds, ss;{	extern unsigned maxtsize;	if (ctob(ts) > maxtsize ||	    ctob(ids) > u.u_rlimit[RLIMIT_DATA].rlim_cur ||	    ctob(uds) > u.u_rlimit[RLIMIT_DATA].rlim_cur ||	    ctob(ids + uds) > u.u_rlimit[RLIMIT_DATA].rlim_cur ||	    ctob(ss) > u.u_rlimit[RLIMIT_STACK].rlim_cur) {		return (ENOMEM);	}	return (0);}/*ARGSUSED*/newptes(pte, v, size)	register struct pte *pte;	u_int v;	register int size;{	register caddr_t a = ptob(v);#ifdef lint	pte = pte;#endif	if (size >= 8) {		mtpr(TBIA, 0);		return;	}	while (size > 0) {		mtpr(TBIS, a);		a += NBPG;		size--;	}}/* * Change protection codes of text segment. * Have to flush translation buffer since this * affect virtual memory mapping of current process. */chgprot(addr, tprot)	caddr_t addr;	long tprot;{	unsigned v;	int tp;	register struct pte *pte;	register struct cmap *c;	v = clbase(btop(addr));	if (!isatsv(u.u_procp, v))		return (EFAULT);	tp = vtotp(u.u_procp, v);	pte = tptopte(u.u_procp, tp);	if (pte->pg_fod == 0 && pte->pg_pfnum) {		c = &cmap[pgtocm(pte->pg_pfnum)];		if (c->c_blkno)			munhash(c->c_vp, (daddr_t)(u_long)c->c_blkno);	}	*(int *)pte &= ~PG_PROT;	*(int *)pte |= tprot;	distcl(pte);	tbiscl(v);	return (0);}settprot(tprot)	long tprot;{	register int *ptaddr, i;	ptaddr = (int *)mfpr(P0BR);	for (i = 0; i < u.u_tsize; i++) {		ptaddr[i] &= ~PG_PROT;		ptaddr[i] |= tprot;	}	mtpr(TBIA, 0);}#ifdef notdef/* * Rest are machine-dependent */getmemc(addr)	caddr_t addr;{	register int c;	struct pte savemap;	savemap = mmap[0];	*(int *)mmap = PG_V | PG_KR | btop(addr);	mtpr(TBIS, vmmap);	uncache(&vmmap[(int)addr & PGOFSET]);	c = *(char *)&vmmap[(int)addr & PGOFSET];	mmap[0] = savemap;	mtpr(TBIS, vmmap);	return (c & 0377);}putmemc(addr, val)	caddr_t addr;{	struct pte savemap;	savemap = mmap[0];	*(int *)mmap = PG_V | PG_KW | btop(addr);	mtpr(TBIS, vmmap);	*(char *)&vmmap[(int)addr & PGOFSET] = val;	mtpr(PADC, 0);	mtpr(PACC, 0);	mmap[0] = savemap;	mtpr(TBIS, vmmap);}#endif/* * Move pages from one kernel virtual address to another. * Both addresses are assumed to reside in the Sysmap, * and size must be a multiple of CLSIZE. */pagemove(from, to, size)	register caddr_t from, to;	int size;{	register struct pte *fpte, *tpte;	if (size % CLBYTES)		panic("pagemove");	fpte = kvtopte(from);	tpte = kvtopte(to);	while (size > 0) {		*tpte++ = *fpte;		*(int *)fpte++ = 0;		mtpr(TBIS, from);		mtpr(TBIS, to);		mtpr(P1DC, to);		/* purge !! */		from += NBPG;		to += NBPG;		size -= NBPG;	}}/* * Code and data key management routines. * * The array ckey_cnt maintains the count of processes currently * sharing each code key.  The array ckey_cache maintains a record * of all code keys used since the last flush of the code cache. * Such keys may not be reused, even if unreferenced, until * the cache is flushed.  The data cache key handling is analogous. * The arrays ckey_cnt and ckey_cache are allways kept in such a way * that the following invariant holds: *	ckey_cnt > 0	=>'s	ckey_cache == 1 * meaning as long as a code key is used by at least one process, it's * marked as being 'in the cache'. Of course, the following invariant * also holds: *	ckey_cache == 0	=>'s	ckey_cnt == 0 * which is just the reciprocal of the 1'st invariant. * Equivalent invariants hold for the data key arrays. */struct	keystats ckeystats = { NCKEY - 1 };struct	keystats dkeystats = { NDKEY - 1 };/*  * Release a code key. */ckeyrelease(key)	int key;{	register int s;	s = spl8();	if (--ckey_cnt[key] < 0) {		printf("ckeyrelease: key = %d\n", key);		ckey_cnt[key] = 0;	}	if (ckey_cnt[key] == 0)		ckeystats.ks_dirty++;	splx(s);}/*  * Release a data key. */dkeyrelease(key)	int key;{	register int s;	s = spl8();	if (--dkey_cnt[key] != 0) {		printf("dkeyrelease: key = %d\n", key);		dkey_cnt[key] = 0;	}	splx(s);		dkeystats.ks_dirty++;}/* * Invalidate the data cache for a process * by exchanging cache keys. */dkeyinval(p)	register struct proc *p;{	int s;	dkeystats.ks_inval++;	s = spl8();	if (--dkey_cnt[p->p_dkey] != 0)		dkey_cnt[p->p_dkey] = 0;	if (p == u.u_procp && !noproc) {		p->p_dkey = getdatakey();		mtpr(DCK, p->p_dkey);	} else		p->p_dkey = 0;	splx(s);	}/*  * Get a code key. * Strategy: try each of the following in turn * until a key is allocated. * * 1) Find an unreferenced key not yet in the cache. *    If this fails, a code cache purge will be necessary. * 2) Find an unreferenced key.  Mark all unreferenced keys *    as available and purge the cache. * 3) Free the keys from all processes not sharing keys. * 4) Free the keys from all processes. */getcodekey(){	register int i, s, freekey;	register struct proc *p;	int desparate = 0;	static int lastkey = MAXCKEY;	ckeystats.ks_allocs++;	s = spl8();	freekey = 0;	for (i = lastkey + 1; ; i++) {		if (i > MAXCKEY)			i = 1;		if ((int)ckey_cache[i] == 0) {	/* free key, take it */			ckey_cache[i] = 1, ckey_cnt[i] = 1;			splx(s);			ckeystats.ks_allocfree++;			ckeystats.ks_avail--;			lastkey = i;			return (i);		}		if (ckey_cnt[i] == 0)		/* save for potential use */			freekey = i;		if (i == lastkey)			break;	}	/*	 * All code keys were marked as being in cache.	 * If a key was in the cache, but not in use, grab it.	 */	if (freekey != 0) {purge:		/*		 * If we've run out of free keys,		 * try and free up some other keys to avoid		 * future cache purges.		 */		ckey_cnt[freekey] = 1, ckey_cache[freekey] = 1;		for (i = 1; i <= MAXCKEY; i++)			if (ckey_cnt[i] == 0) {				ckey_cache[i] = 0;				ckeystats.ks_avail++;			}		mtpr(PACC, 0);		splx(s);		ckeystats.ks_dirty = 0;		ckeystats.ks_norefs++;		return (freekey);	}	/*	 * All keys are marked as in the cache and in use.	 * Release all unshared keys, or, on second pass,	 * release all keys.	 */steal:	for (p = allproc; p; p = p->p_next)		if (p->p_ckey != 0 && (p->p_flag & P_SYSTEM) == 0) {			i = p->p_ckey;			if (ckey_cnt[i] == 1 || desparate) {				p->p_ckey = 0;				if (--ckey_cnt[i] == 0) {					freekey = i;					if (p->p_textp)						p->p_textp->x_ckey = 0;				}			}		}	if (freekey) {		ckeystats.ks_taken++;		goto purge;	} else {		desparate++;		goto steal;	}}/*  * Get a data key. * * General strategy: * 1) Try to find a data key that isn't in the cache. Allocate it. * 2) If all data keys are in the cache, find one which isn't *    allocated.  Mark all unallocated keys as not in cache, *    purge the cache, and allocate this one. * 3) If all of them are allocated, free all process' keys *    and let them reclaim then as they run. */getdatakey(){	register int i, freekey;	register struct proc *p;	int s;	static int lastkey = MAXDKEY;	dkeystats.ks_allocs++;	s = spl8();	freekey = 0;	for (i = lastkey + 1; ; i++) {		if (i > MAXDKEY)			i = 1;		if ((int)dkey_cache[i] == 0) {	/* free key, take it */			dkey_cache[i] = 1, dkey_cnt[i] = 1;			splx(s);			dkeystats.ks_allocfree++;			dkeystats.ks_avail--;			lastkey = i;			return (i);		}		if (dkey_cnt[i] == 0)			freekey = i;		if (i == lastkey)			break;	}purge:	if (freekey) {		/*		 * Try and free up some more keys to avoid		 * future allocations causing a cache purge.		 */		dkey_cnt[freekey] = 1, dkey_cache[freekey] = 1;		for (i = 1; i <= MAXDKEY; i++)			if (dkey_cnt[i] == 0) {				dkey_cache[i] = 0;				dkeystats.ks_avail++;			}		mtpr(PADC, 0);		splx(s);		dkeystats.ks_norefs++;		dkeystats.ks_dirty = 0;		return (freekey);	}	/*	 * Now, we have to take a key from someone.	 * May as well take them all, so we get them	 * from all of the idle procs.	 */	for (p = allproc; p; p = p->p_next)		if (p->p_dkey != 0 && (p->p_flag & P_SYSTEM) == 0) {			freekey = p->p_dkey;			dkey_cnt[freekey] = 0;			p->p_dkey = 0;		}	dkeystats.ks_taken++;	goto purge;}/*VARGARGS1*/vtoph(p, v)	register struct proc *p;	unsigned v;{	register struct pte *pte;	register unsigned pg;	pg = btop(v);	if (pg >= BTOPKERNBASE)		pte = &Sysmap[pg - BTOPKERNBASE];	else		pte = vtopte(p, pg);	return ((pte->pg_pfnum << PGSHIFT) + (v & PGOFSET));}

⌨️ 快捷键说明

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