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

📄 mmu405cmd.c

📁 umon bootloader source code, support mips cpu.
💻 C
字号:
/* tlbcmd405.c:

    General notice:
    This code is part of a boot-monitor package developed as a generic base
    platform for embedded system designs.  As such, it is likely to be
    distributed to various projects beyond the control of the original
    author.  Please notify the author of any enhancements made or bugs found
    so that all may benefit from the changes.  In addition, notification back
    to the author will allow the new user to pick up changes that may have
    been made by other users after this version of the code was distributed.

    Author: Ed Sutter
    email:  esutter@lucent.com  (home: lesutter@worldnet.att.net)
    phone:  908-582-2351        (home: 908-889-5161)
*/
#include "config.h"

#if INCLUDE_MMUCMD
#include "cpu.h"
#include "cpuio.h"
#include "genlib.h"
#include "stddefs.h"
#include "cli.h"
#include "arch_ppc.h"

/* Externs from tlb405.s...
 */
extern void ppctlbia(void);
extern unsigned long ppcMftlblo(int);
extern unsigned long ppcMftlbhi(int);
extern unsigned long ppcMfpid(void);
extern unsigned long ppcMfzpr(void);
extern void ppcMttlblo(int,unsigned long);
extern void ppcMttlbhi(int,unsigned long);
extern void ppcMtpid(unsigned long);
extern void ppcMtzpr(unsigned long);

#define PID_SPRNUM	945

/* Bit Fields in TLB entries...
 */
#define PID_MASK			0x000000ff
#define TLBHI_TID			0x0000000f
#define TLBHI_U0			0x00000010
#define TLBHI_ENDIAN		0x00000020
#define TLBHI_VALID			0x00000040
#define TLBHI_PGSIZE		0x00000380
#define TLBHI_EPN			0xfffffc00
#define TLBLO_RPN			0xfffffc00
#define TLBLO_EXECUTEABLE	0x00000200
#define TLBLO_WRITEABLE		0x00000100
#define TLBLO_ZONESELECT	0x000000f0
#define TLBLO_WRITETHRU		0x00000008
#define TLBLO_INHIBITCACHE	0x00000004
#define TLBLO_MEMCOHERENT	0x00000002
#define TLBLO_GUARDED		0x00000001

/* Notes regarding MMU and cache...
 * When MMU is fully enabled (MSR[IR & DR] == 11), the TLB entries
 * control the cacheability of a page.  There are three possibilities
 * for a given page I THINK!!! :-(  ...
 *
 *  MODE                  TLBLO_WRITETHRU     TLBLO_INHIBITCACHE
 *
 *  Dcache enabled             0                   0
 *  Icache enabled
 * ---------------------------------------------------------------
 *  Dcache disabled            1                   0
 *  Icache enabled
 * ---------------------------------------------------------------
 *  Dcache disabled            0                   1
 *  Icache disabled
 * ---------------------------------------------------------------
 *  Illegal State              1                   1
 */

struct pagesizeinfo {
	char *name;
	unsigned long size;
	unsigned long sizebits;
	unsigned long rpnmask;
};

static struct pagesizeinfo pagesizetbl[] = {
	{ "1K",		0x400,			(0<<7),		0xfffffc00 },
	{ "4K",		0x1000,			(1<<7),		0xfffff000 },
	{ "16K",	0x4000,			(2<<7),		0xffffc000 },
	{ "64K",	0x10000,		(3<<7),		0xffff0000 },
	{ "256K",	0x40000,		(4<<7),		0xfffc0000 },
	{ "1M",		0x100000,		(5<<7),		0xfff00000 },
	{ "4M",		0x400000,		(6<<7),		0xffc00000 },
	{ "16M",	0x1000000,		(7<<7),		0xff000000 },
	{ 0,0,0 }
};

static char *
yesorno(ulong  val)
{
	return(val == 0 ? "N" : "Y");
}

static unsigned long
getpagesize(char *name)
{
	struct pagesizeinfo *psi;

	psi = pagesizetbl;
	while(psi->name) {
		if (!strcmp(psi->name,name))
			return(psi->sizebits);
		psi++;
	}
	printf(" Invalid page size: %s\n",name);
	return(0xffffffff);
}

/* printpagesize():
 * Verbosely converts an incoming size entry.
 */
static void
printpagesize(ulong sizebits)
{
	struct pagesizeinfo *psi;

	psi = pagesizetbl;
	while(psi->name) {
		if (psi->sizebits == sizebits) {
			printf("%4s",psi->name);
			return;
		}
		psi++;
	}
	printf("???");
}

/* printtlb():
 * Dump a verbose description of the incoming hi & lo portions of
 * a TLB entry...
 */
static void
printtlb(int idx, ulong hi, ulong lo, int hdr)
{
	if (hdr) {
		printf("Idx  Effective  Real      Page  Vld End ");
		printf("U0 TID Ex Wr Zone WrThru Inhib Mem   Grd\n");
		printf("     PgNum      PgNum     Size          ");
		printf("          En      Cache  Cache Cohrnt\n");
	}
	printf("%2d: x%08lx  x%08lx  ",idx,(hi & TLBHI_EPN),(lo & TLBLO_RPN));
	printpagesize(hi & TLBHI_PGSIZE);
	printf("   %s  %s  %d %3d  %s  %s  %3d   %s      %s     %s    %s\n",
		yesorno(hi & TLBHI_VALID),(hi & TLBHI_ENDIAN) ? "lit" : "big",
		(int)((hi & TLBHI_U0) >> 4),(int)(hi & TLBHI_TID),
		yesorno(lo & TLBLO_EXECUTEABLE),yesorno(lo & TLBLO_WRITEABLE),
		(int)((lo & TLBLO_ZONESELECT) >> 4),yesorno(lo & TLBLO_WRITETHRU),
		yesorno(lo & TLBLO_INHIBITCACHE),yesorno(lo & TLBLO_MEMCOHERENT),
		yesorno(lo & TLBLO_GUARDED));
}


/* checktlb():
 * There are a few rules (according to the PPC405GP users's manual) that
 * must be followed by software when configuring the TLB.  This function
 * makes sure those rules are not violated by the incoming TLB entry.
 *
 * 1: Software must set all unused bits (as determined by page size) of
 *    the RPN (Real Page Number) field to zero.
 *
 * 2: The PowerPC architecture does not support memory models in which
 *    write-thru is enabled and caching is inhibited.
 */
static void
checktlb(int index,ulong hi,ulong lo)
{
	ulong sizebits, rpn;
	struct pagesizeinfo *psi;

	/* If the entry isn't valid, then don't bother checking the RPN...
	 */
	if ((hi & TLBHI_VALID) == 0)
		return;


	sizebits = hi & TLBHI_PGSIZE;

	psi = pagesizetbl;
	while(psi->name) {
		if (psi->sizebits == sizebits)
			break;
		psi++;
	}
	if (psi->name == 0) {
		printf("checktlb() error\n");
		return;
	}

	rpn = lo & TLBLO_RPN;
	if (rpn & ~psi->rpnmask)
		printf("TLB %d: RPN <-> PageSize conflict\n",index);

	if ((lo & TLBLO_WRITETHRU) && (lo & TLBLO_INHIBITCACHE))
		printf("TLB %d: WriteThru <-> CacheInhibit conflict\n",index);
}

char *MmuHelp[] = {
    "MMU-Specific Operations",
    " [-v] {cmd} [params]",
    " Where {cmd} is: ir, dr, tlb, tlbinv, pid, tlbrd, tlbwl, or tlbwh...",
    "   ir [1|0]     instruction relocation {set|clr}",
    "   dr [1|0]     data relocation {set|clr}",
    "   tlb [#]      dump all valid (or specified) tlb entries",
    "   tlbinv       invalidate all tlb entries",
    "   pid [value]  read or write the PID (spr 945)",
    "   zpr [value]  read or write the ZPR (spr 944)",
    "   tlbwh # EPN PgSize Valid Endian U0 TID",
    "   tlbwl # RPN Exec Writeable Zone WriteThru InhibCache MemCohrnt Guarded",
    0,
};

/* MmuCmd():
 * This command allows the user to play around with the MMU-related
 * facilities of the PPC405GP.  
 */
int
MmuCmd(int argc,char *argv[])
{
	int verbose = 0;
    int opt, index, hdr;
	ulong value, hi, lo, mmupid;

    while ((opt=getopt(argc,argv,"v")) != -1) {
	    switch(opt) {
	        case 'v':
	            verbose = 1;
	            break;
	        default:
	            return(CMD_PARAM_ERROR);
	    }
    }

	if (argc < optind+1)
		return(CMD_PARAM_ERROR);

	if (!strcmp(argv[optind],"tlbinv")) {
		if (argc != optind+1)
			return(CMD_PARAM_ERROR);

		ppctlbia();
	}
	else if (!strcmp(argv[optind],"ir")) {
		if (argc == optind+1) {
			printf("Instruction relocation: %sabled\n",
				ppcMfmsr() & MSR_IR ? "en" : "dis");
    		return(CMD_SUCCESS);
		}
		else if (argc != optind+2)
			return(CMD_PARAM_ERROR);

		if (!strcmp(argv[optind+1],"0")) {
			ppcMtmsr(ppcMfmsr() & ~MSR_IR);
		}
		else if (!strcmp(argv[optind+1],"1")) {
			ppcMtmsr(ppcMfmsr() | MSR_IR);
		}
		else
			return(CMD_PARAM_ERROR);
	}
	else if (!strcmp(argv[optind],"dr")) {
		if (argc == optind+1) {
			printf("Data relocation: %sabled\n",
				ppcMfmsr() & MSR_DR ? "en" : "dis");
    		return(CMD_SUCCESS);
		}
		else if (argc != optind+2)
			return(CMD_PARAM_ERROR);

		if (!strcmp(argv[optind+1],"0")) {
			ppcMtmsr(ppcMfmsr() & ~MSR_DR);
		}
		else if (!strcmp(argv[optind+1],"1")) {
			ppcMtmsr(ppcMfmsr() | MSR_DR);
		}
		else
			return(CMD_PARAM_ERROR);
	}
	else if (!strcmp(argv[optind],"pid")) {
		if (argc == optind+1)
			printf("PID: 0x%lx\n",ppcMfpid());
		else if (argc == optind+2)
			ppcMtpid(strtoul(argv[optind+1],0,0));
		else
			return(CMD_PARAM_ERROR);
	}
	else if (!strcmp(argv[optind],"zpr")) {
		if (argc == optind+1)
			printf("ZPR: 0x%lx\n",ppcMfzpr());
		else if (argc == optind+2)
			ppcMtzpr(strtoul(argv[optind+1],0,0));
		else
			return(CMD_PARAM_ERROR);
	}
	else if (!strcmp(argv[optind],"tlb")) {
		hdr = 1;

		/* The tlbre instruction modifies the PID, so we save it here
		 * so that it can be restored later...
		 */
		mmupid = ppcMfpid();
		for(index=0;index<64;index++) {
			hi = ppcMftlbhi(index);
			lo = ppcMftlblo(index);
			if (argc == optind+1) {
				if (hi & TLBHI_VALID) {
					printtlb(index,hi,lo,hdr);
					hdr = 0;
				}
			}
			else if (argc == optind+2) {
				if (inRange(argv[optind+1],index)) {
					printtlb(index,hi,lo,hdr);
					hdr = 0;
				}
			}
			else
				return(CMD_PARAM_ERROR);

			checktlb(index,hi,lo);
		}
		/* Restore PID...
		 */
		ppcMtpid(mmupid);
	}
	else if (!strcmp(argv[optind],"tlbwl")) {
		if (argc == optind+3) {
			index = atoi(argv[optind+1]);
			value = strtoul(argv[optind+2],0,0);
		}
		else if (argc == optind+10) {
			unsigned long rpn, ex, wr, zsel, w, i, m, g;
			
			index = atoi(argv[optind+1]);
			rpn = strtoul(argv[optind+2],0,0);
			ex = strtoul(argv[optind+3],0,0);
			wr = strtoul(argv[optind+4],0,0);
			zsel = strtoul(argv[optind+5],0,0);
			w = strtoul(argv[optind+6],0,0);
			i = strtoul(argv[optind+7],0,0);
			m = strtoul(argv[optind+8],0,0);
			g = strtoul(argv[optind+9],0,0);
			value = (rpn | ((ex & 1) << 9) | ((wr & 1) << 8) |
						((zsel & 0xf) << 4) | ((w & 1) << 3) |
						((i & 1) << 2) | ((m & 1) << 1) | (g & 1));
		}
		else
			return(CMD_PARAM_ERROR);

		if (verbose)
			printf("tlblo[%d] = 0x%08lx\n", index,value);
		ppcMttlblo(index,value);
	}
	else if (!strcmp(argv[optind],"tlbwh")) {
		if (argc == optind+3) {
			index = atoi(argv[optind+1]);
			value = strtoul(argv[optind+2],0,0);
		}
		else if (argc == optind+8) {
			unsigned long epn, sizebits, v, e, u0, tid;

			index = atoi(argv[optind+1]);
			epn = strtoul(argv[optind+2],0,0);
			if ((sizebits = getpagesize(argv[optind+3])) == 0xffffffff)
				return(CMD_FAILURE);
			v = strtoul(argv[optind+4],0,0);
			e = strtoul(argv[optind+5],0,0);
			u0 = strtoul(argv[optind+6],0,0);
			tid = strtoul(argv[optind+7],0,0);
			value = (epn | (sizebits) | ((v & 1) << 6) |
						((e & 0xf) << 5) | ((u0 & 1) << 4) | ((tid & 0xf)));
		}
		else
			return(CMD_PARAM_ERROR);

		if (verbose)
			printf("tlbhi[%d] = 0x%08lx\n", index,value);
		ppcMttlbhi(index,value);
	}
	else
		return(CMD_PARAM_ERROR);
		
    return(CMD_SUCCESS);
}

#endif

⌨️ 快捷键说明

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