📄 pagetab.c
字号:
/* pagetab.c - Module to provide page tables for MMU and PU based processors
* Copyright (C) Advanced RISC Machines Limited, 1998-1999.
* Copyright (C) ARM Limited, 1999-2001. All rights reserved.
*
* RCS $Revision: 1.10.2.11.18.6 $
* Checkin $Date: 2004/10/28 15:25:48 $
* Revising $Author: ljameson $
*/
#define MODEL_NAME Pagetab
#include <string.h>
#include "minperip.h"
#include "armul_cnf.h"
#ifndef NDEBUG
# if 1
# else
# define VERBOSE_RESET
# define VERBOSE
# endif
#endif
enum PT_CP15TypeE {
PT_UNKNOWN, PT_PU, PT_MMU, PT_TCRAM, PT_OTHER
};
char const *const PT_CP15TypeNames[1+PT_OTHER] =
{
"UNKNOWN", "PU", "MMU", "TCRAM", "OTHER"
};
enum access {
NO_ACCESS,
NO_USR_W,
SVC_RW,
ALL_ACCESS
};
enum entrytype {
INVALID,
PAGE,
SECTION
};
/* The U_BIT is implementation defined.
* On ARMV6 it SBZ, and is XN if subpages enabled.
* On ARM720T it SBO, and is Updateable on older MMU's.
*/
#define U_BIT 16
#define C_BIT 8
#define B_BIT 4
#define L1Entry(type,addr,dom,ucb,acc) \
((type==SECTION) ? (((addr)&0xfff00000)|((acc)<<10)| \
((dom)<<5)|(ucb)|(type)) : \
(type==PAGE) ? (((addr)&0xfffffc00)|((dom)<<5)| \
((ucb)&U_BIT)|(type)) : \
0)
static struct {
tag_t option;
ARMword bit;
int def;
} ctl_flags[] = {
ARMulCnf_MMU, ARM_MMU_M, TRUE,
ARMulCnf_AlignFaults, ARM_MMU_A, FALSE,
ARMulCnf_Cache, ARM_MMU_C, TRUE,
ARMulCnf_WriteBuffer, ARM_MMU_W, TRUE,
ARMulCnf_Prog32, ARM_MMU_P, TRUE,
ARMulCnf_Data32, ARM_MMU_D, TRUE,
ARMulCnf_LateAbort, ARM_MMU_L, TRUE,
/* - most users of page-tables will allow the debugger to choose ByteSex. */
/* ARMulCnf_BigEnd, ARM_MMU_B, FALSE, */
ARMulCnf_SystemProt, ARM_MMU_S, FALSE,
ARMulCnf_ROMProt, ARM_MMU_R, FALSE,
ARMulCnf_BranchPredict, ARM_MMU_Z, TRUE,
ARMulCnf_ICache, ARM_MMU_I, TRUE,
ARMulCnf_HighExceptionVectors, ARM_MMU_V, FALSE
};
BEGIN_STATE_DECL(Pagetab)
toolconf clone;
/* GenericAccessCallback *ih_gac; */
bool hasMMU, hasPU, hasTCRAM, hasV6MPU;
bool Set_Endian,
sh_Bigend32;
bool_int sh_Bigend8, Set_Endian8;
bool_int Set_Unaligned, sh_Unaligned;
bool_int pt_verbose;
enum PT_CP15TypeE pt_CP15TYPE;
ARMword pt_arch;
END_STATE_DECL(Pagetab)
static void
bitAssignWM(ARMword *d, ARMword mask /* e.g. ARM_MMU_B */, bool_int s)
{
if (s)
*d |= mask;
else
*d &= ~mask;
}
static void disable_MMU(PagetabState *tab)
{
ARMword cp15ctrl[8]; /* Reg1 can have 2 words in XScale */
/* Read what's there already. */
ARMulif_CPRead(&tab->coredesc,15,1,&cp15ctrl[0]);
cp15ctrl[0] &= ~ARM_MMU_M;
ARMulif_CPWrite(&tab->coredesc,15,1,&cp15ctrl[0]);
#ifdef VERBOSE_RESET
printf("Pagetab.c:disable_MMU write %08lx to CP15 reg1.\n",
(unsigned long)cp15ctrl[0]);
#endif
}
/* !!! NB pagetab->clone doesn't allow us to read the
* Architecture from the Processor, so +++ we do this earlier. */
static void pagetab_MMU(PagetabState *tab)
{
toolconf config = tab->clone;
const char *option;
/* ARMword value; */
ARMword PTBase=ToolConf_DLookupUInt(config, ARMulCnf_PageTableBase,
0x40000000) & 0xffffc000; /* align */
ARMword page;
ARMword entry;
unsigned int i;
ARMword arch = tab->pt_arch;
#if 0
Hostif_ConsolePrint(tab->hostif,"\nPagetab MMU for Architecture %u\n",
(unsigned)arch);
#endif
disable_MMU(tab);
{
ARMWord DACvalue=ToolConf_DLookupUInt(config, ARMulCnf_DAC, 0x3);
ARMulif_CPWrite(&tab->coredesc,15,3,&DACvalue);
}
{
/* ARMV6 has > 1 words here. We choose to only write the first TTB. */
ARMword data[16];
memset(data,0,sizeof(data));
ARMulif_CPRead(&tab->coredesc,15,2,&data[0]);
data[0]=PTBase;
ARMulif_CPWrite(&tab->coredesc,15,2,&data[0]);
}
/* start with all pages flat, cacheable, bufferable.
* -- formerly claimed to be uncacheable, read/write, unbufferable */
{
unsigned main_ucb = (arch < 5) ? (U_BIT|C_BIT|B_BIT) : (C_BIT|B_BIT);
entry=L1Entry(SECTION,0,0,main_ucb,ALL_ACCESS);
}
for (i=0, page=PTBase; i<4096; i++, page+=4) {
if (ARMulif_WriteWord(&tab->coredesc, page, entry | (i<<20)))
{
Hostif_ConsolePrint(tab->hostif,"\nPagetab failed to write memory "
"at %08lx\n",
(unsigned long)page);
return;
};
}
for (i=0; i<100; i++) {
char buffer[32];
ARMword low,physical,mask;
ARMword page;
toolconf region;
int j,n;
sprintf(buffer,"REGION[%d]",i);
region=ToolConf_FlatChild(config,(tag_t)buffer);
if (region==NULL) break; /* stop */
option=ToolConf_Lookup(region,ARMulCnf_VirtualBase);
if (option) {
low=option ? strtoul(option,NULL,0) : 0;
physical=ToolConf_DLookupUInt(region, ARMulCnf_PhysicalBase, low);
} else {
low=physical=ToolConf_DLookupUInt(region, ARMulCnf_PhysicalBase,0);
}
option = ToolConf_Lookup(region, ARMulCnf_Size);
if (option != NULL) {
unsigned long size = ToolConf_Power(option, TRUE);
if (size == 0) { /* assume 4GB */
n = 4096;
} else {
n = size >> 20;
}
} else {
/* backwards compatability */
n = ToolConf_DLookupUInt(region, ARMulCnf_Pages, 4096);
}
mask=0;
option=ToolConf_Lookup(region,ARMulCnf_Cacheable);
mask=ToolConf_AddFlag(option,mask,C_BIT,TRUE);
option=ToolConf_Lookup(region,ARMulCnf_Bufferable);
mask=ToolConf_AddFlag(option,mask,B_BIT,TRUE);
if (arch < 5) {
option=ToolConf_Lookup(region,ARMulCnf_Updateable);
mask=ToolConf_AddFlag(option,mask,U_BIT,TRUE);
}
/* Support V6TEX in 1MB sections to enable AllocateOnWrite in ARMV6
* and test that ARM1136 doesn't do allocate-on-write! */
if (arch > 5) {
ARMword tex = ToolConf_DLookupUInt(region, ARMulCnf_V6TEX, 0) & 0x7;
#if 0
Hostif_ConsolePrint(tab->hostif,"\nPagetab MMU has TEX:0x%x\n",
(unsigned)tex);
#endif
mask |= (tex) << 12;
}
mask |= (ToolConf_DLookupUInt(region, ARMulCnf_Domain, 0) & 0xf) << 5;
mask |= (ToolConf_DLookupUInt(region, ARMulCnf_AccessPermissions,
ALL_ACCESS) & 3) << 10;
/* set TRANSLATE=NO to generate translation faults */
if (ToolConf_DLookupBool(region, ARMulCnf_Translate, TRUE))
mask |= SECTION;
low&=0xfff00000;
if (arch < 6)
mask=(physical & 0xfff00000) | (mask & 0xdfe);
else
mask=(physical & 0xfff00000) | (mask & 0x7dfe); /* Allow TEX */
j=low>>20; /* index of first section */
n+=j; if (n>4096) n=4096;
for (page=(PTBase+j*4); j<n; j++, mask+=0x100000, page+=4) {
ARMulif_WriteWord(&tab->coredesc,page,mask);
}
}
/* now enable the caches, etc. */
{
ARMword cp15ctrl[16]; /* Reg1 can have 2 words in XScale */
/* Read what's there already. */
ARMulif_CPRead(&tab->coredesc,15,1,&cp15ctrl[0]);
#ifdef VERBOSE_RESET
printf("Pagetab.c:pagetab_MMU reads %08lx from CP15 reg1.\n",
(unsigned long)cp15ctrl[0]);
#endif
for (i=0;i<sizeof(ctl_flags)/sizeof(ctl_flags[0]);i++)
{
bool b =
ToolConf_DLookupBool(config,ctl_flags[i].option,BOOLIFY(ctl_flags[i].def));
#ifdef VERBOSE_RESET
printf("Pagetab.c:pagetab_MMU, %08lx in CP15 reg1, "
"bool=%u, bit = %08lx.\n",
(unsigned long)cp15ctrl[0], (unsigned)b,
(unsigned long)ctl_flags[i].bit
);
#endif
if (b)
cp15ctrl[0]|=ctl_flags[i].bit;
else
cp15ctrl[0]&= ~(ctl_flags[i].bit);
}
/* !Todo: This should only apply to processors which support FastBus, e.g. by
* checking for HAS_FASTBUS=True. For now, it does no harm!
*/
if (!(ToolConf_DLookupBool(config, ARMulCnf_FastBus, FALSE)))
cp15ctrl[0] |= 0x40000000;
else
cp15ctrl[0] &= ~0x40000000;
if(tab->hasTCRAM)
{
if ((ToolConf_DLookupBool(config, ARMulCnf_TCIRAM, FALSE)))
{
ARMWord value[4];
ARMulif_CPRead(&tab->coredesc,15,9,&value[0]);
value[3] |= 1;
ARMulif_CPWrite(&tab->coredesc,15,9,&value[0]);
}
if ((ToolConf_DLookupBool(config, ARMulCnf_TCDRAM, FALSE))) {
ARMWord value[4];
ARMulif_CPRead(&tab->coredesc,15,9,&value[0]);
value[2] |= 1;
ARMulif_CPWrite(&tab->coredesc,15,9,&value[0]);
}
}
#ifdef VERBOSE_RESET
printf("Pagetab.c:pagetab_MMU before setting endian, %08lx for CP15 reg1.\n",
(unsigned long)cp15ctrl[0]);
#endif
if (tab->Set_Endian)
{
#ifdef VERBOSE_RESET
printf("Setting endian to %u\n",tab->sh_Bigend32);
#endif
bitAssignWM(&cp15ctrl[0], ARM_MMU_B, tab->sh_Bigend32);
}
if (tab->Set_Endian8)
{
bitAssignWM(&cp15ctrl[0],(1<<ARM_MMU_EE_pos), tab->sh_Bigend8);
bitAssignWM(&cp15ctrl[0],(1<<ARM_MMU_U_pos), tab->sh_Unaligned);
{
ARMword psr = ARMulif_GetCPSR(&tab->coredesc);
if (tab->sh_Bigend8)
{
psr |= (1 << ARM_PSR_E_pos);
}
else
{
psr &= ~(1 << ARM_PSR_E_pos);
}
ARMulif_SetCPSR(&tab->coredesc, psr);
}
}
if (tab->Set_Unaligned)
{
bitAssignWM(&cp15ctrl[0], (1<<ARM_MMU_U_pos), tab->sh_Unaligned);
}
#ifdef VERBOSE_RESET
printf("Pagetab.c:pagetab_MMU writes %08lx to CP15 reg1.\n",
(unsigned long)cp15ctrl[0]);
#endif
ARMulif_CPWrite(&tab->coredesc,15,1,&cp15ctrl[0]);
}
}
static void pagetab_ProtectionUnit(PagetabState *tab)
{
toolconf config = tab->clone;
const char *option;
/* Variables to hold the values eventually sent to copro 15.
They are all different sizes, but for simplicity's sake they
are stored as longs.
*/
unsigned long Config_reg=0;
unsigned long Cacheable_reg=0;
unsigned long WriteBuffer_reg=0;
unsigned long Protection_reg=0;
unsigned long Region_regs[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
ARMword start;
ARMword size;
toolconf region;
char buffer[32];
int i, j, x;
disable_MMU(tab); /* Disables the PU. */
for (i = 1; i < 4; i++) { /* a bitmask, 'DI' */
/* For each type of region. Highest priority comes last and ovewrites */
for (j = 0; j < 8; j++) {
switch (i) {
case 1:
sprintf(buffer,"IREGION[%d]",j);
break;
case 2:
sprintf(buffer,"DREGION[%d]",j);
break;
case 3:
sprintf(buffer,"REGION[%d]",j);
break;
}
region = ToolConf_Child(config,(tag_t)buffer);
if (region != NULL) {
start = ToolConf_DLookupUInt(region, ARMulCnf_PhysicalBase, 0);
option = ToolConf_Lookup(region, ARMulCnf_Size);
if (option != NULL) {
size = ToolConf_Power(option, TRUE);
} else {
int n = ToolConf_DLookupUInt(region, ARMulCnf_Pages, 4096);
size = n << 20;
}
/* to get the 5 bit size value from the actual size,
* we have to do a linear search, to find the most
* significant bit set.(Any other bit is ignored)
*/
for (x = 31; x >= 12; x--) {
/* Any value for size less than 0x1000 is considered 0 i.e. 4G */
if (size & (1 << x)) break;
}
size = (x < 12) ? 0x1f : x-1;
/* for the moment I am assuming if we get this far we want the region enabled */
option = ToolConf_Lookup(region, ARMulCnf_Translate);
if (i & 2) { /* D side */
Region_regs[j] = ToolConf_AddFlag(option, (size << 1) | (start << 12), 1, TRUE);
}
if (i & 1) { /* I side */
Region_regs[j+8] = ToolConf_AddFlag(option, (size << 1) | (start << 12), 1, TRUE);
}
option = ToolConf_Lookup(region, ARMulCnf_Cacheable);
if (i & 2) { /* D side */
Cacheable_reg |= ToolConf_AddFlag(option, Cacheable_reg, 1<<j, TRUE);
}
if (i & 1) { /* I side */
Cacheable_reg |= ToolConf_AddFlag(option, Cacheable_reg, 1<<(j+8), TRUE);/* I side */
}
if (i & 2) { /* D side */
option = ToolConf_Lookup(region, ARMulCnf_Bufferable);
WriteBuffer_reg = ToolConf_AddFlag(option, WriteBuffer_reg, 1<<j, TRUE);
}
if (i & 1) { /* I side */
Protection_reg |= (ToolConf_DLookupUInt(region, ARMulCnf_AccessPermissions, ALL_ACCESS) & 3) << (j*2);
}
if (i & 2) { /* D side */
Protection_reg |= (ToolConf_DLookupUInt(region, ARMulCnf_AccessPermissions, ALL_ACCESS) & 3) << ((j*2) + 16);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -