kerneltest/e32test/mmu/t_pages.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 137 8aab599e3476
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// e32test\mmu\t_pages.cpp
// 
//

#include <e32std.h>
#include <e32std_private.h>
#include <e32svr.h>
#include "d_shadow.h"

RShadow Shadow;
LOCAL_D TUint Read(TUint anAddr)
	{
	return Shadow.Read(anAddr);
	}
TUint PageTables = 0;
TCpu  Cpu = ECpuUnknown;
TInt  CpuArc = 0;
TInt  CpuSpecial = 0;
TUint ControlReg = 0;

const TUint KXPbitM = 0x800000;

LOCAL_C void ProcessCBTEX(TDes& aDes, TUint aCb, TUint aTex)
	{
	
	const TPtrC KTEXCB[9] = {_L("StOr"),_L("ShDv"),_L("WTRA"),_L("WBRA"),_L("NoCa"),_L("Resv"),_L("ImpD"),_L("WBWA"),_L("NSDv")};
	const TPtrC KCacheP[4] = {_L("NoCa"),_L("WBWA"),_L("WTRA"),_L("WBRA")};	
	aCb = aCb >> 2;
	
	TUint texCB = aCb | ((aTex&7) << 2);
	
	if ((texCB<9) && (CpuArc>5))
		aDes.Append(KTEXCB[texCB]);
	else if ((aTex&4) && (CpuArc>5))
		{
		aDes.Append(KCacheP[aTex&3]);
		aDes.Append(TChar('/'));
		aDes.Append(KCacheP[aCb]);
		}
	else
		{
		if (CpuArc>5)
			{
			if (aTex&4)
				aDes.Append(TChar('1'));
			else 
				aDes.Append(TChar('0'));
			
			if (aTex&2)
				aDes.Append(TChar('1'));
			else 
				aDes.Append(TChar('0'));	

			if (aTex&1)
				aDes.Append(TChar('1'));
			else 
				aDes.Append(TChar('0'));
			}
		else if (CpuSpecial == 2)
			{
			if (aTex==1)
				aDes.Append(TChar('X'));
			else if (aTex==0)
				aDes.Append(TChar('_'));
			else
				aDes.Append(TChar('?'));

			}
		
		if (aCb & 2)
			aDes.Append(TChar('C'));
		else
			aDes.Append(TChar('_'));
		if (aCb & 1)
			aDes.Append(TChar('B'));
		else
			aDes.Append(TChar('_'));
		}
	}


LOCAL_C void ProcessXNnGS(TDes& aDes, TUint anGS, TUint aXN)
	{
	if ((ControlReg & KXPbitM))
		{
		aDes.Append(TChar(' '));
		if (aXN )
			aDes.Append(_L("XN "));
		else
			aDes.Append(_L("__ "));
		
		if (anGS&2 )
			aDes.Append(_L("nG "));
		else
			aDes.Append(_L("__ "));
		
		if (anGS&1 )
			aDes.Append(TChar('S'));
		else
			aDes.Append(TChar('_'));
		
		}
	}


LOCAL_C void ProcessAP(TDes& aDes, TUint aAp)
	{
	const TPtrC KAccessP[7] = {_L(" RWNO"),_L(" RWRO"),_L(" RWRW"),_L(" Rsv0"),_L(" RONO"),_L(" RORO"),_L(" Rsv1")};
	const TPtrC KAccZrP[4] = {_L(" NONO"), _L(" RONO"), _L(" RORO"), _L(" Rsv2")};
	
	TUint access = aAp & 3;
	TUint apx = (aAp >> 3) & 4;
	
	if (((ControlReg & 0x300) !=0) && apx)
		{
			aDes.Append(_L(" Rsv3"));
		}
	else
		{	
		if ((ControlReg & KXPbitM))
			access |= apx;
		
		if (access==0)
			aDes.Append(KAccZrP[(ControlReg >> 8) & 3]);
		else 
			aDes.Append(KAccessP[access-1]);
		}
	}

LOCAL_C void ProcessPteSE(TUint aPte, TUint anAddr)
	{
	TUint type=aPte&3;
	TBuf<36> buf;
	switch(type)
		{
		case 0:
			// not present
			break;
		case 1:
			{
			// large page
			TUint phys=aPte & 0xffff0000;
			TUint ap0=(aPte>>4)&3;
			TUint ap1=(aPte>>6)&3;
			TUint ap2=(aPte>>8)&3;
			TUint ap3=(aPte>>10)&3;
			TUint tex=(aPte>>12)&0xf;
			ProcessCBTEX(buf,aPte&0xc,tex);
			ProcessAP(buf,ap0);
			ProcessAP(buf,ap1);
			ProcessAP(buf,ap2);
			ProcessAP(buf,ap3);
			RDebug::Print(_L("\t%08x  Lpage: phys=%08x, %S"),anAddr,phys,&buf);
			break;
			}
		case 2:
			{
			// small page
			TUint phys=aPte & 0xfffff000;
			TUint ap0=(aPte>>4)&3;
			TUint ap1=(aPte>>6)&3;
			TUint ap2=(aPte>>8)&3;
			TUint ap3=(aPte>>10)&3;
			ProcessCBTEX(buf,aPte&0xc,0);
			ProcessAP(buf,ap0);
			ProcessAP(buf,ap1);
			ProcessAP(buf,ap2);
			ProcessAP(buf,ap3);
			RDebug::Print(_L("\t%08x  Spage: phys=%08x, %S"),anAddr,phys,&buf);
			break;
			}
		case 3:
			{
			// extended small page
			TUint phys=aPte & 0xfffff000;
			TUint ap=(aPte>>4)&3;
			TUint tex=(aPte>>6)&0xf;
			ProcessCBTEX(buf,aPte&0xc,tex);
			ProcessAP(buf,ap);
			RDebug::Print(_L("\t%08x XSpage: phys=%08x, %S"),anAddr,phys,&buf);
			break;
			}
		}
	}


LOCAL_C void ProcessPteSD(TUint aPte, TUint anAddr)
	{
	if ((aPte&3) != 0)
		{
		
		TBuf<36> buf;
		TUint ap=(aPte>>4)&23;	
		
		if (aPte&2) // XS-Page
			{
			// extended small page
			TUint phys=aPte & 0xfffff000;
			TUint tex=(aPte>>6)&0x7;
			ProcessCBTEX(buf,aPte&0xc,tex);
			ProcessAP(buf,ap);
			ProcessXNnGS(buf, (aPte>>10)&3, aPte &1);
			RDebug::Print(_L("\t%08x XSpage: phys=%08x, %S"),anAddr,phys,&buf);
			}
		else // L-Page
			{
					
			// large page
			TUint phys=aPte & 0xffff0000;
			TUint tex=(aPte>>12)&0x7;
			ProcessCBTEX(buf,aPte&0xc,tex);
			ProcessAP(buf,ap);
			ProcessXNnGS(buf, (aPte>>10)&3, (aPte >> 15) &1);
			RDebug::Print(_L("\t%08x  Lpage: phys=%08x, %S"),anAddr,phys,&buf);
			}		
		
		}// Else "Fault" - Not Present

	}


LOCAL_C void ProcessPde(TUint aPde, TUint anAddr)
	{
	TUint type=aPde&3;
	TBuf<24> buf;
	switch(type)
		{
		case 0:
			// not present
			if (aPde) 
				RDebug::Print(_L(" Not Present\n"));
			break;
		case 1:
			{
			// page table
			TUint ptphys=aPde & 0xfffffc00;
			TUint domain=(aPde>>5)&15;
			TUint P=(aPde&0x200);
			TUint ptpgphys=ptphys & 0xfffff000;
			TUint ptlin=0;
			
			TInt i;
			for (i=0; i<256; i++)
				{
				if ((Read(PageTables+i*4)&0xfffff000)==ptpgphys)
					{
					if (ptlin==0)
						ptlin=PageTables+(i<<12)+(ptphys & 0xc00);
					else
						RDebug::Print(_L("WARNING Multiple page tables found! alt = %08x\n"), PageTables+(i<<12)+(ptphys & 0xc00));
					}
				}
			if (ptlin)
				{
				RDebug::Print(_L("%08x page table: phys=%08x, domain %2d, %s, page table lin=%08x"),anAddr,ptphys,domain,P?L"ECC":L"No ECC",ptlin);
				for (i=0; i<256; i++)
					{
					TUint addr=anAddr+(i<<12);
					TUint pte=Read(ptlin+i*4);
					
					if (ControlReg & KXPbitM)
						ProcessPteSD(pte,addr);
					else
						ProcessPteSE(pte,addr);
					}
				}
			else
				RDebug::Print(_L("%08x page table: phys=%08x, domain %2d, %s, page table not found"),anAddr,ptphys,domain,P?L"ECC":L"No ECC");
				
			break;
			}
		case 2:
			{	
			// section
			TUint phys=aPde & 0xfff00000;
			TUint perm=(aPde>>10)&0x23;
			TUint P=(aPde&0x200);
			TUint domain=(aPde>>5)&15;
			ProcessCBTEX(buf,aPde&0xc,(aPde>>12)&0xf);  // tex is bigger on xscale, but bit is masked off later.
			ProcessAP(buf,perm);
			ProcessXNnGS(buf, (aPde>>16)&3, (aPde>>4)&1);
			
			if ((ControlReg & KXPbitM) && (aPde & 0x40000))
				{
				domain = (domain << 4) | ((aPde >> 20) &15);
				RDebug::Print(_L("%08x Supersectn: phys=%08x, base %4d, %s, %S"),anAddr,phys,domain,P?L"ECC":L"No ECC",&buf);
				}
			else
				{			
				RDebug::Print(_L("%08x section   : phys=%08x, domain %2d, %s, %S"),anAddr,phys,domain,P?L"ECC":L"No ECC",&buf);
				}
			break;
			}
		default:
			// invalid
			RDebug::Print(_L("PDE for %08x invalid, value %08x"),anAddr,aPde);
			break;
		}
	}

const TInt KNotInInvalid = -2;
TInt StartInvalid=KNotInInvalid;
TInt StartInvalidBase=0;
TInt EndInvalidBase=0;

void DisplayNotPresent(TInt aCurrentPd)
	{
	aCurrentPd--;
	if (StartInvalid!=KNotInInvalid) // Display any Invalid ranges.
		{
		if (StartInvalid == aCurrentPd)
			RDebug::Print(_L("\nPage Directory 0x%x:  Base=0x%x - Not Present.\n"), StartInvalid, StartInvalidBase);
		else
			RDebug::Print(_L("\nPage Directorys 0x%x-0x%x:  Bases=0x%x-0x%x - Not Present.\n"), StartInvalid, aCurrentPd, StartInvalidBase, EndInvalidBase);
		
		StartInvalid=KNotInInvalid;
		}
	}

void ProcessPd(TUint aPd)
	{
	TUint i;
	TUint pdSize;
	TUint pdBase;
	TUint offset;
	
	TInt err = Shadow.GetPdInfo(aPd, pdSize, pdBase, offset);
	
	if (err==KErrNone)
		{
		DisplayNotPresent(aPd);
			
		if (aPd==KGlobalPageDirectory)
			RDebug::Print(_L("Global Page Directory: Base=0x%x, Entries=0x%x, Start index=0x%x\n"), pdBase, pdSize, offset);
		else
			RDebug::Print(_L("\nPage Directory 0x%x: Base=0x%x, Entries=0x%x %x\n"), aPd, pdBase, pdSize, offset);
		
		if (Cpu == ECpuArm)
			{		

			for (i=0; i<pdSize; i++)
				{
				TUint addr=(i+offset)<<20;
				TUint pde=Read(pdBase+i*4);
				ProcessPde(pde,addr);
				}
			}
			else
				RDebug::Print(_L("Cannot display pde for this CPU"));
		}
	else
		{ // Dont list all invalid PDs - there are too many.
		if (StartInvalid==KNotInInvalid)
			{
			StartInvalidBase = pdBase;
			StartInvalid = aPd;
			}
		else
			{
			EndInvalidBase=pdBase;
			}
				
		}
	}

GLDEF_C TInt E32Main()
	{
	TUint mmuId=0;
	TUint cacheType=0;

	
	
	TInt r=User::LoadLogicalDevice(_L("D_SHADOW"));
	if ((r!=KErrNone) && (r!=KErrAlreadyExists))
		User::Panic(_L("T_PAGES0"),r);
	r=Shadow.Open();
	if (r!=KErrNone)
		User::Panic(_L("T_PAGES1"),r);

	Shadow.GetMemoryArchitecture(Cpu, ControlReg);
	switch (Cpu)
		{
		case ECpuArm:
			{	
			mmuId=Shadow.MmuId();
			TUint implementor= (mmuId>>24);
			
			if (implementor==0x44)
				CpuSpecial = 1;
			
			switch ((mmuId>>12)&15)
				{
				case 0: // Pre-ARM7
					if ((mmuId>>4)==0x4156030)
						CpuArc = 2;
					else if ((mmuId>>8)==0x415606)
						CpuArc = 3;
					break;
				case 7: // Mid-ARM7
					CpuArc = 3;
				default:// Post-ARM7
					TUint arc = (mmuId >>16) &15;
					if (arc<3)
						{
						CpuArc = 4;
						if ((implementor==0x69) && (arc==4))
							CpuSpecial=1;
						}
					else if (arc<7)
						{
						CpuArc = 5;
						if ((implementor==0x69) && (arc==5))
							CpuSpecial=2;
						}
					else if (arc==7)
						CpuArc = 6;
					else 
						CpuArc = arc;
				}
			
			switch (CpuSpecial)
				{
				case 1:RDebug::Print(_L("\nCPU = ARMv%d (StrongArm), ControlRegister = 0x%x "),CpuArc, ControlReg);
					break;
				case 2:RDebug::Print(_L("\nCPU = ARMv%d (XScale), ControlRegister = 0x%x "),CpuArc, ControlReg);
					break;
				default: 
					if (CpuArc<7)
						RDebug::Print(_L("\nCPU = ARMv%d, ControlRegister = 0x%x "),CpuArc, ControlReg);
					else
						RDebug::Print(_L("\nCPU = ARM (#%d), ControlRegister = 0x%x "),CpuArc, ControlReg);
				}	
			
			RDebug::Print(_L("(MMU=%d, Alignment Checking=%d, Write Buffer=%d, System Protection=%d, "),
				ControlReg & 1,(ControlReg>>1)&1,(ControlReg>>3)&1, (ControlReg>>8)&1);
							
			if (ControlReg & KXPbitM)
				RDebug::Print(_L("ROM Protection=%d, Subpages Disabled, Exception Endian=%d)\n"), (ControlReg>>9)&1, (ControlReg>>25)&1);
			else
				RDebug::Print(_L("ROM Protection=%d, Subpages Enabled, Exception Endian=%d)\n"), (ControlReg>>9)&1, (ControlReg>>25)&1);
			
			RDebug::Print(_L("MMU ID=%08X"),mmuId);
			
			
					
			cacheType=Shadow.CacheType();
			RDebug::Print(_L("CACHE TYPE=%08X"),cacheType);
			break;
			
			}
					
		case ECpuX86:
			RDebug::Print(_L("\nCPU = x86\n"));
			break;
		case ECpuUnknown:
		default:
			RDebug::Print(_L("\nCPU = Unknown, Flags = 0x%x\n"), ControlReg);
		
		}
		
	TUint numPages = 0;
	TMemModel memModel = Shadow.GetMemModelInfo(PageTables, numPages);	
	
	switch (memModel)
		{
		case EMemModelMoving: RDebug::Print(_L("Moving Memory Model.\n"));
			break;
		case EMemModelMultiple : RDebug::Print(_L("Multiple Memory Model.\nMax number of PageDirectorys=0x%x.\n"), numPages);
			break;
		case EMemModelFlexible : RDebug::Print(_L("Flexible Memory Model.\nMax number of PageDirectorys=0x%x.\n"), numPages);
			break;
		default:
			RDebug::Print(_L("Unknown Memory Model.\n"));
			return KErrNone;
		}
	
	ProcessPd(KGlobalPageDirectory);

	if (memModel==2)
		{
		TUint i;
		for (i=0; i<numPages; i++)
			{
				ProcessPd(i);
			}
		DisplayNotPresent(numPages);
		}
	Shadow.Close();
	User::FreeLogicalDevice(_L("Shadow"));
	return KErrNone;
	}