📄 abl_arm922t_cp15_driver.c
字号:
/***********************************************************************
* $Workfile: abl_arm922t_cp15_driver.c $
* $Revision: 1.10 $
* $Author: WellsK $
* $Date: May 27 2005 14:21:36 $
*
* Project: ARM922T Coprocessor 15 driver
*
* Description:
* This file contains driver support for the MMU and cache
* coprocessor (15) of the ARM922T.
*
* Revision History:
* $Log: //smaicnt2/pvcs/VM/sharpmcu/archives/sharpmcu/software/abl/source/abl_arm922t_cp15_driver.c-arc $
*
* Rev 1.10 May 27 2005 14:21:36 WellsK
* Fix a compilation issue with inline assembly instructions for
* GNU when performing a load immediate (MOV r0, 0).
*
* Rev 1.9 May 12 2005 12:48:28 PattamattaD
* Added some more utility functions
*
* Rev 1.8 Oct 04 2004 15:01:38 WellsK
* Added ARM ADS versions of the cache adn write buffer
* flush functions. GNU, GHS, and IAR are pending.
*
* Rev 1.7 Apr 15 2004 15:20:14 WellsK
* Added IAR intrinsic functions for NOPs.
*
* Rev 1.6 Mar 29 2004 12:09:26 WellsK
* Fixed/improved support for IAR toolchain.
*
* Rev 1.5 Dec 02 2003 10:12:28 WellsK
* Corrected mask value in void cp15_force_cache_coherence
* function.
*
* Rev 1.4 Oct 01 2003 12:06:28 WellsK
* Added cp15_get_ttb function.
*
* Rev 1.3 Sep 30 2003 17:01:42 WellsK
* Corrected __ARM_CC define. Used __arm instead.
*
* Rev 1.2 Sep 25 2003 15:13:52 WellsK
* Added support for IAR environment.
*
* Rev 1.1 Sep 10 2003 11:27:10 WellsK
* Added a function for setting the virtual address of where the
* MMU table is located.
*
* Rev 1.0 Jun 09 2003 12:06:26 WellsK
* Initial revision.
*
*
***********************************************************************
* SHARP MICROELECTRONICS OF THE AMERICAS MAKES NO REPRESENTATION
* OR WARRANTIES WITH RESPECT TO THE PERFORMANCE OF THIS SOFTWARE,
* AND SPECIFICALLY DISCLAIMS ANY RESPONSIBILITY FOR ANY DAMAGES,
* SPECIAL OR CONSEQUENTIAL, CONNECTED WITH THE USE OF THIS SOFTWARE.
*
* SHARP MICROELECTRONICS OF THE AMERICAS PROVIDES THIS SOFTWARE SOLELY
* FOR THE PURPOSE OF SOFTWARE DEVELOPMENT INCORPORATING THE USE OF A
* SHARP MICROCONTROLLER OR SYSTEM-ON-CHIP PRODUCT. USE OF THIS SOURCE
* FILE IMPLIES ACCEPTANCE OF THESE CONDITIONS.
*
* COPYRIGHT (C) 2001 SHARP MICROELECTRONICS OF THE AMERICAS, INC.
* CAMAS, WA
**********************************************************************/
#include "abl_arm922t_cp15_driver.h"
#ifdef __ICCARM__
#include "inarm.h"
#endif
/***********************************************************************
* CP15 driver private data
**********************************************************************/
/* The address translation functions of this driver require a saved
pointer to the virtual base address of the MMU table. */
UNS_32 *virtual_tlb_addr;
/***********************************************************************
* CP15 driver private functions and macros
**********************************************************************/
#ifdef __ghs__
/* Simple GHS function returning the TTB register */
asm UNS_32 getttb (void)
{
%reg ttb
MRC p15, 0, r0, c2, c0, 0
}
/* Simple GHS function returning the MMU control register */
asm UNS_32 getstatus (void)
{
%reg status
MRC p15, 0, r0, c1, c0, 0
}
/* Simple GHS function used to support cache invalidation */
asm void invalcache (UNS_32 *adr)
{
%reg adr
MCR p15, 0, adr, c7, c14, 1
MCR p15, 0, adr, c7, c5, 1
%con adr
MOV r0, adr
MCR p15, 0, r0, c7, c14, 1
MCR p15, 0, r0, c7, c5, 1
}
/* Simple GHS function used to support cache invalidation */
asm void inval_all_cache(void)
{
MOV r0, 0
MCR p15, 0, r0, c7, c7, 0
}
/* Simple GHS function used to support translation table base
register invalidation */
asm void invaltlb (UNS_32 *adr)
{
%reg adr
MCR p15, 0, adr, c8, c5, 1
NOP
NOP
%con adr
MOV r0, adr
MCR p15, 0, r0, c8, c5, 1
NOP
NOP
}
/* Simple GHS function used to invalidate all TLB entries */
asm void inval_all_tlb(void)
{
MOV r0, 0
MCR p15, 0, r0, c8, c7, 0
}
/* Simple GHS function used to enable/disable MMU */
asm void set_mmu (UNS_32 val)
{
%reg val
MRC p15, 0, val, c1, c0, 0
}
/* Simple GHS function used to set TTB address */
asm void set_ttb (UNS_32 addr)
{
%reg addr
MCR p15, 0, addr, c2, c5, 0
}
/* Simple GHS function used to set domain access control */
asm void set_dac (UNS_32 reg_val)
{
%reg reg_val
MCR p15, 0, reg_val, c3, c0, 0
}
#endif
/***********************************************************************
* CP15 driver public functions
**********************************************************************/
/***********************************************************************
*
* Function: cp15_decode_level2
*
* Purpose:
* Given a level2 descriptor and a physical address, return
* the virtual address if the level2 descriptor can map the
* physical address.
*
* Processing:
* Translate and return the level 2 virtual address for
* the given physical address.
*
* Parameters:
* level2: MMU level 2 table value
* addr: Physical address to be converted
*
* Outputs: None
*
* Returns:
* The virtual address or 0 if the address does not translate.
*
* Notes: None
*
**********************************************************************/
static UNS_32 cp15_decode_level2(UNS_32 level2,
UNS_32 addr)
{
UNS_32 dcd = 0;
switch (level2 & ARM922T_L2D_TYPE_PAGE_MASK)
{
case ARM922T_L2D_TYPE_LARGE_PAGE:
/* Large page table */
if ((level2 & ARM922T_L2D_LPAGE_MASK) ==
(addr & ARM922T_L2D_LPAGE_MASK))
{
dcd = (level2 & ARM922T_L2D_LPAGE_MASK) |
(addr & (~ARM922T_L2D_LPAGE_MASK));
}
break;
case ARM922T_L2D_TYPE_SMALL_PAGE:
/* Small page table */
if ((level2 & ARM922T_L2D_SPAGE_MASK) ==
(addr & ARM922T_L2D_SPAGE_MASK))
{
dcd = (level2 & ARM922T_L2D_SPAGE_MASK) |
(addr & (~ARM922T_L2D_SPAGE_MASK));
}
break;
case ARM922T_L2D_TYPE_TINY_PAGE:
/* Tiny page table */
if ((level2 & ARM922T_L2D_TPAGE_MASK) ==
(addr & ARM922T_L2D_TPAGE_MASK))
{
dcd = (level2 & ARM922T_L2D_TPAGE_MASK) |
(addr & (~ARM922T_L2D_TPAGE_MASK));
}
default:
break;
}
return dcd;
}
/***********************************************************************
* CP15 driver public functions
**********************************************************************/
/***********************************************************************
*
* Function: cp15_map_virtual_to_physical
*
* Purpose: Return a physical address for a passed virtual address
*
* Processing:
* Return (UNS_32)addr if MMU is turned off. Otherwise, read the
* address of the translation table from the translation table base
* address register. Use the upper 12 bits of the addr to index the
* translation table and read out the descriptor. If the descriptor
* is invalid, return 0. If the descriptor is for a 1 Meg section,
* read back the upper 12 bits of the physical address. The lower
* 20 bits of the physical address is the lower 20 bits of the
* virtual address. If the descriptor is for a coarse page table,
* read the coarse page table descriptor and use the most
* significant 22 bits as the base address of the page table. If
* the descriptor is for a fine page table, read the fine page
* table descriptor and use the most significant 20 bits as the
* base address of the page table.
*
* If not a section base, read the level 2 page descriptor from the
* page table. If bits 1..0 of the level2 descriptor are 01, then
* it is a large page table descriptor. The most significant 16
* bits of the descriptor are the most significant 16 bits of the
* physical address; the least significant 16-bits of the virtual
* address are the least significant 16-bits of the address. If
* bits 1..0 of the level2 descriptor are 10, then it is a small
* page table descriptor. The most significant 20 bits of the
* level2 descriptor are the most significant 20 bits of the
* physical address; the least significant 12 bits are the least
* significant 12 bits of the physical address. If bits 1..0 of
* the level2 descriptor are 11, then it is a tiny page table
* descriptor. The most significant 22 bits of the level2
* descriptor are the most significant 22 bits of the physical
* address; the least significant 10 bits are the least
* significant 10 bits of the physical address. If bits 1..0
* of the level2 descriptor are 0, return 0 (invalid).
*
* Parameters:
* addr: The virtual address to be converted
*
* Outputs: None
*
* Returns:
* The physical address or 0 if the address does not translate.
*
* Notes: None
*
**********************************************************************/
UNS_32 cp15_map_virtual_to_physical(void *addr)
{
register UNS_32 status;
UNS_32 *tlb, tlb_entry, index, virtual_addr;
UNS_32 *page_table, level2;
virtual_addr = (UNS_32) addr;
/* Read the MMU control register */
#ifdef __GNUC__
asm ("MRC p15, 0, %0, c1, c0, 0" : "=r" (status));
#endif
#ifdef __ghs__
status = getstatus();
#endif
#ifdef __arm
__asm
{
MRC p15, 0, status, c1, c0, 0;
}
#endif
#ifdef __ICCARM__
/* IAR CC includes some "intrinsic" functions to access ARM CP regs */
status = __MRC(15, 0, 1, 0, 0);
#endif
/* Is MMU enabled? */
if ((status & ARM922T_MMU_CONTROL_M) == 0)
{
/* MMU is off; virtual address is physical address */
return virtual_addr;
}
/* Get TLB base address */
tlb = virtual_tlb_addr;
/*******************************************************************
* Get the level 1 translation table entry
* indexed by bits 31:20 of the address
******************************************************************/
index = virtual_addr;
index >>= 20;
tlb_entry = tlb[index];
/* Perform function based on level 1 page type or section */
switch (tlb_entry & ARM922T_L1D_TYPE_PG_SN_MASK)
{
case ARM922T_L1D_TYPE_FAULT:
/* Invalid section or page, fault */
return 0;
case ARM922T_L1D_TYPE_CPAGE:
/* Coarse page tables */
index = (virtual_addr >> 12) & ARM922T_CPT_INDEX_MASK;
page_table = (UNS_32 *)(tlb_entry &
ARM922T_L2D_CP_BASE_MASK);
level2 = page_table[index];
break;
case ARM922T_L1D_TYPE_SECTION:
/* Section type */
/***********************************************************
* Section base -- upper 12 bits of entry is physical
* memory base lower 20 bits of virtual address is offset
* rom that base
**********************************************************/
return ((tlb_entry & ARM922T_L2D_SN_BASE_MASK) |
(virtual_addr & ~(ARM922T_L2D_SN_BASE_MASK)));
case ARM922T_L1D_TYPE_FPAGE:
/* Fine page tables */
index = (virtual_addr >> 10) & ARM922T_FPT_INDEX_MASK;
page_table = (UNS_32 *)(tlb_entry &
ARM922T_L2D_FP_BASE_MASK);
level2 = page_table[index];
break;
default:
/* This should never happen */
return 0;
}
switch (level2 & ARM922T_L2D_TYPE_PAGE_MASK)
{
case ARM922T_L2D_TYPE_LARGE_PAGE:
/* Large page table */
return ((level2 & ARM922T_L2D_LPAGE_MASK) |
(virtual_addr & ~(ARM922T_L2D_LPAGE_MASK)));
case ARM922T_L2D_TYPE_SMALL_PAGE:
/* Small page table */
return ((level2 & ARM922T_L2D_SPAGE_MASK) |
(virtual_addr & ~(ARM922T_L2D_SPAGE_MASK)));
case ARM922T_L2D_TYPE_TINY_PAGE:
/* Tiny page table */
return ((level2 & ARM922T_L2D_TPAGE_MASK) |
(virtual_addr & ~(ARM922T_L2D_TPAGE_MASK)));
default:
break;
}
return 0;
}
/***********************************************************************
*
* Function: cp15_map_physical_to_virtual
*
* Purpose: Return a virtual address for a passed physical address
*
* Processing:
* Test if MMU is on, return if not. Search for the virtual
* address of the provided physical address. If found, return a
* void pointer to virtual address.
*
* Parameters:
* addr: The physical address to be converted
*
* Outputs: None
*
* Returns:
* The virtual address or 0 if the address does not translate.
*
* Notes: None
*
**********************************************************************/
void * cp15_map_physical_to_virtual(UNS_32 addr)
{
register UNS_32 status;
UNS_32 *tlb, tlb_entry, index;
UNS_32 *page_table, level2, index2;
void *virtual_addr;
/*******************************************************************
* Do a linear search of the translation table until the level 1
* descriptor corresponding to the physical address is found
******************************************************************/
/* Read the control register */
#ifdef __GNUC__
asm ("MRC p15, 0, %0, c1, c0, 0" : "=r" (status));
#endif
#ifdef __ghs__
status = getstatus ();
#endif
#ifdef __arm
__asm
{
MRC p15, 0, status, c1, c0, 0;
}
#endif
#ifdef __ICCARM__
/* IAR CC includes some "intrinsic" functions to access ARM CP regs */
status = __MRC(15, 0, 1, 0, 0);
#endif
/* Is MMU enabled? */
if ((status & ARM922T_MMU_CONTROL_M) == 0)
{
/* MMU is off; physical address is virtual address */
return (void *)addr;
}
/* Get TLB base address */
tlb = virtual_tlb_addr;
/*******************************************************************
* Search until found or all 4096 translation
* table entries are examined.
******************************************************************/
for (index = 0; index < ARM922T_TT_ENTRIES; index ++)
{
tlb_entry = tlb[index];
switch (tlb_entry & ARM922T_L1D_TYPE_PG_SN_MASK)
{
case ARM922T_L1D_TYPE_FAULT:
/* Invalid section or page, fault */
break;
case ARM922T_L1D_TYPE_CPAGE:
/* Course page tables, loop through all entries */
page_table = (UNS_32 *)(tlb_entry &
ARM922T_L2D_CP_BASE_MASK);
for (index2 = 0; index2 < ARM922T_CPT_ENTRIES; index2++)
{
level2 = page_table[index2];
if (level2)
{
virtual_addr = (void *)
cp15_decode_level2(level2, addr);
if (virtual_addr)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -