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

📄 pte121.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: pte121.c,v 1.3.2.1 2003/02/20 22:06:46 joel Exp $ *//* Trivial page table setup for RTEMS * Purpose: allow write protection of text/ro-data * * Author: Till Straumann <strauman@slac.stanford.edu>, 4/2002 *//* Chose debugging options */#undef  DEBUG_MAIN	/* create a standalone (host) program for basic testing */#undef  DEBUG		/* target debugging and consistency checking */#undef  DEBUG_EXC	/* add exception handler which reenables BAT0 and recovers from a page fault */#ifdef	DEBUG_MAIN#undef	DEBUG		/* must not use these together with DEBUG_MAIN */#undef	DEBUG_EXC#endif/***************************** INCLUDE HEADERS ****************************/#ifndef DEBUG_MAIN#include <rtems.h>#include <rtems/bspIo.h>#include <libcpu/cpuIdent.h>#ifdef	DEBUG_EXC#include <bsp.h>#include <bsp/vectors.h>#include <libcpu/raw_exception.h>#endif#endif#include <stdio.h>#include <assert.h>#include <string.h>#include "pte121.h"/************************** CONSTANT DEFINITIONS **************************//* Base 2 logs of some sizes */#ifndef DEBUG_MAIN#define	LD_PHYS_SIZE	32		/* physical address space */#define LD_PG_SIZE		12		/* page size */#define LD_PTEG_SIZE	6		/* PTEG size */#define LD_PTE_SIZE		3		/* PTE size  */#define LD_SEG_SIZE		28		/* segment size */#define LD_MIN_PT_SIZE	16		/* minimal size of a page table */#define LD_HASH_SIZE	19		/* lengh of a hash */#else /* DEBUG_MAIN *//* Reduced 'fantasy' sizes for testing */#define	LD_PHYS_SIZE	32		/* physical address space */#define LD_PG_SIZE		6		/* page size */#define LD_PTEG_SIZE	5		/* PTEG size */#define LD_PTE_SIZE		3		/* PTE size  */#define LD_SEG_SIZE		28		/* segment size */#define LD_MIN_PT_SIZE	7		/* minimal size of a page table */#define LD_HASH_SIZE	19		/* lengh of a hash */#endif /* DEBUG_MAIN *//* Derived sizes *//* Size of a page index */#define LD_PI_SIZE		((LD_SEG_SIZE) - (LD_PG_SIZE)) /* Number of PTEs in a PTEG */#define PTE_PER_PTEG	(1<<((LD_PTEG_SIZE)-(LD_PTE_SIZE)))/* Segment register bits */#define KEY_SUP			(1<<30)	/* supervisor mode key */#define KEY_USR			(1<<29)	/* user mode key *//* The range of effective addresses to scan with 'tlbie' * instructions in order to flush all TLBs. * On the 750 and 7400, there are 128 two way I and D TLBs, * indexed by EA[14:19]. Hence calling *	  tlbie rx * where rx scans 0x00000, 0x01000, 0x02000, ... 0x3f000 * is sufficient to do the job */#define NUM_TLB_PER_WAY 64 /* 750 and 7400 have 128 two way TLBs */#define FLUSH_EA_RANGE	(NUM_TLB_PER_WAY<<LD_PG_SIZE)/*************************** MACRO DEFINITIONS ****************************//* Macros to split a (32bit) 'effective' address into * VSID (virtual segment id) and PI (page index) * using a 1:1 mapping of 'effective' to 'virtual' * addresses. * * For 32bit addresses this looks like follows * (each 'x' or '0' stands for a 'nibble' [4bits]): * *         32bit effective address (EA) * *              x x x x x x x x *               |       | *    0 0 0 0 0 x|x x x x|x x x *       VSID    |  PI   |  PO (page offset) *               |       | *//* 1:1 VSID of an EA  */#define VSID121(ea) (((ea)>>LD_SEG_SIZE) & ((1<<(LD_PHYS_SIZE-LD_SEG_SIZE))-1))/* page index of an EA */#define PI121(ea)	(((ea)>>LD_PG_SIZE) & ((1<<LD_PI_SIZE)-1))/* Primary and secondary PTE hash functions *//* Compute the primary hash from a VSID and a PI */#define PTE_HASH1(vsid, pi) (((vsid)^(pi))&((1<<LD_HASH_SIZE)-1))/* Compute the secondary hash from a primary hash */#define PTE_HASH2(hash1) ((~(hash1))&((1<<LD_HASH_SIZE)-1))/* Extract the abbreviated page index (which is the * part of the PI which does not go into the hash * under all circumstances [10 bits to -> 6bit API]) */#define API(pi)	((pi)>>((LD_MIN_PT_SIZE)-(LD_PTEG_SIZE)))/* Horrible Macros */#ifdef __rtems__/* must not use printf until multitasking is up */typedef void (*PrintF)(char *,...);static PrintF whatPrintf(void){		return _Thread_Executing ?				(PrintF)printf :				printk;}#define PRINTF(args...) ((void)(whatPrintf())(args))#else#define PRINTF(args...) printf(args)#endif#ifdef DEBUGunsigned longtriv121PgTblConsistency(Triv121PgTbl pt, int pass, int expect);static int consistencyPass=0;#define CONSCHECK(expect) triv121PgTblConsistency(&pgTbl,consistencyPass++,(expect))#else#define CONSCHECK(expect) do {} while (0)#endif/**************************** TYPE DEFINITIONS ****************************//* A PTE entry */typedef struct PTERec_ {		unsigned long v:1,    vsid:24, h:1, api: 6;		unsigned long rpn:20, pad: 3, r:1, c:1, wimg:4, marked:1, pp:2;} PTERec, *PTE;/* internal description of a trivial page table */typedef struct Triv121PgTblRec_ {		PTE				base;		unsigned long	size;		int				active;} Triv121PgTblRec;/************************** FORWARD DECLARATIONS *************************/#ifdef DEBUG_EXCstatic voidmyhdl(BSP_Exception_frame* excPtr);#endif#if defined(DEBUG_MAIN) || defined(DEBUG)static voiddumpPte(PTE pte);#endif#ifdef DEBUGstatic voiddumpPteg(unsigned long vsid, unsigned long pi, unsigned long hash);unsigned longtriv121IsRangeMapped(unsigned long start, unsigned long end);#endif/**************************** STATIC VARIABLES ****************************//* dont malloc - we might have to use this before * we have malloc or even RTEMS workspace available */static Triv121PgTblRec pgTbl={0};#ifdef DEBUG_EXCstatic void *ohdl;			/* keep a pointer to the original handler */#endif/*********************** INLINES & PRIVATE ROUTINES ***********************//* compute the page table entry group (PTEG) of a hash */static inline PTEptegOf(Triv121PgTbl pt, unsigned long hash){	hash &= ((1<<LD_HASH_SIZE)-1);	return (PTE)(((unsigned long)pt->base) | ((hash<<LD_PTEG_SIZE) & (pt->size-1)));}/* see if a vsid/pi combination is already mapped * * RETURNS: PTE of mapping / NULL if none exists * * NOTE: a vsid<0 is legal and will tell this *       routine that 'pi' is actually an EA to *       be split into vsid and pi... */static PTEalreadyMapped(Triv121PgTbl pt, long vsid, unsigned long pi){int				i;unsigned long	hash,api;PTE				pte;	if (!pt->size)		return 0;	if (vsid<0) {		vsid=VSID121(pi);		pi=PI121(pi);	}	hash = PTE_HASH1(vsid,pi);	api=API(pi);	for (i=0, pte=ptegOf(pt,hash); i<PTE_PER_PTEG; i++,pte++)		if (pte->v && pte->vsid==vsid && pte->api==api && 0==pte->h)			return pte;	/* try the secondary hash table */	hash = PTE_HASH2(hash);	for (i=0, pte=ptegOf(pt,hash); i<PTE_PER_PTEG; i++,pte++)		if (pte->v && pte->vsid==vsid && pte->api==api && 1==pte->h)			return pte;	return 0;}/* find the first available slot for  vsid/pi * * NOTE: it is NOT legal to pass a vsid<0 / EA combination. * * RETURNS free slot with the 'marked' field set. The 'h' *         field is set to 0 or one, depending on whether *         the slot was allocated by using the primary or *         the secondary hash, respectively. */static PTEslotFor(Triv121PgTbl pt, unsigned long vsid, unsigned long pi){int				i;unsigned long	hash,api;PTE				pte;	/* primary hash */	hash = PTE_HASH1(vsid,pi);	api=API(pi);	/* linear search thru all buckets for this hash */	for (i=0, pte=ptegOf(pt,hash); i<PTE_PER_PTEG; i++,pte++) {		if (!pte->v && !pte->marked) {			/* found a free PTE; mark it as potentially used and return */			pte->h=0;	/* found by the primary hash fn */			pte->marked=1;			return pte;		}	}#ifdef DEBUG	/* Strange: if the hash table was allocated big enough,	 *          this should not happen (when using a 1:1 mapping)	 *          Give them some information...	 */	PRINTF("## First hash bucket full - ");	dumpPteg(vsid,pi,hash);#endif	hash = PTE_HASH2(hash);#ifdef DEBUG	PRINTF("   Secondary pteg is 0x%08x\n", (unsigned)ptegOf(pt,hash));#endif	for (i=0, pte=ptegOf(pt,hash); i<PTE_PER_PTEG; i++,pte++) {		if (!pte->v && !pte->marked) {			/* mark this pte as potentially used */			pte->marked=1;			pte->h=1;			return pte;		}	}#ifdef DEBUG	/* Even more strange - most likely, something is REALLY messed up */	PRINTF("## Second hash bucket full - ");	dumpPteg(vsid,pi,hash);#endif	return 0;}/* unmark all entries */static voidunmarkAll(Triv121PgTbl pt){unsigned long	n=pt->size / sizeof(PTERec);unsigned long	i;PTE				pte;	for (i=0,pte=pt->base; i<n; i++,pte++)		pte->marked=0;}/* calculate the minimal size of a page/hash table * to map a range of 'size' bytes in EA space. * * RETURNS: size in 'number of bits', i.e. the *          integer part of LOGbase2(minsize) *          is returned. * NOTE:	G3/G4 machines need at least 16 bits *          (64k). */unsigned longtriv121PgTblLdMinSize(unsigned long size){unsigned long i;	/* round 'size' up to the next page boundary */	size += (1<<LD_PG_SIZE)-1;	size &= ~((1<<LD_PG_SIZE)-1);	/* divide by number of PTEs  and multiply	 * by the size of a PTE.	 */	size >>= LD_PG_SIZE - LD_PTE_SIZE;	/* find the next power of 2 >= size */	for (i=0; i<LD_PHYS_SIZE; i++) {		if ((1<<i) >= size)			break;	}	/* pop up to the allowed minimum, if necessary */	if (i<LD_MIN_PT_SIZE)			i=LD_MIN_PT_SIZE;	return i;}/* initialize a trivial page table of 2^ldSize bytes * at 'base' in memory. * * RETURNS:	OPAQUE HANDLE (not the hash table address) *          or NULL on failure. */Triv121PgTbltriv121PgTblInit(unsigned long base, unsigned ldSize){	if (pgTbl.size) {		/* already initialized */		return 0;	}	if (ldSize < LD_MIN_PT_SIZE)		return 0; /* too small */	if (base & ((1<<ldSize)-1))		return 0; /* misaligned */	/* This was tested on 604r, 750 and 7400.	 * On other CPUs, verify that the TLB invalidation works	 * for a new CPU variant and that it has hardware PTE lookup/	 * TLB replacement before adding it to this list.	 *	 * NOTE: The 603 features no hardware PTE lookup - and 	 *       hence the page tables should NOT be used.	 *		 Although lookup could be implemented in	 *		 software this is probably not desirable	 *		 as it could have an impact on hard realtime	 *		 performance, screwing deterministic latency!	 *		 (Could still be useful for debugging, though)	 */	if	(	PPC_604		!=current_ppc_cpu &&  			PPC_604e	!=current_ppc_cpu &&  			PPC_604r	!=current_ppc_cpu &&  			PPC_750		!=current_ppc_cpu &&  			PPC_7400	!=current_ppc_cpu )		return 0;	/* unsupported by this CPU */	pgTbl.base=(PTE)base;	pgTbl.size=1<<ldSize;	/* clear all page table entries */	memset(pgTbl.base, 0, pgTbl.size);	CONSCHECK(0);	/* map the page table itself 'm' and 'readonly' */	if (triv121PgTblMap(&pgTbl,						TRIV121_121_VSID,						base,						(pgTbl.size >> LD_PG_SIZE),						TRIV121_ATTR_M,						TRIV121_PP_RO_PAGE) >= 0)		return 0;	CONSCHECK((pgTbl.size>>LD_PG_SIZE));	return &pgTbl;}/* return the handle of the (one and only) page table * or NULL if none has been initialized yet. */Triv121PgTbltriv121PgTblGet(void){	return pgTbl.size ? &pgTbl : 0;}/* NOTE: this routine returns -1 on success; *       on failure, the page table index for *       which no PTE could be allocated is returned * * (Consult header about argument/return value * description) */longtriv121PgTblMap(				Triv121PgTbl	pt,				long			vsid,				unsigned long	start,				unsigned long	numPages,				unsigned		attributes,				unsigned		protection				){int				i,pass;unsigned long	pi;PTE				pte;	/* already activated - no change allowed */	if (pt->active)			return -1;	if (vsid < 0) {

⌨️ 快捷键说明

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