📄 sys.c
字号:
* SHELL_ERROR_OVERFLOW : Range overflow
* SHELL_ERROR_TLB : Mapped address with no match in TLB
* SHELL_ERROR_TLB_WP : Write access to mapped write protected address
* SHELL_ERROR_RAM_RANGE : Address in unused RAM space
*
************************************************************************/
UINT32
sys_validate_range(
UINT32 addr, /* Start address */
UINT32 count, /* Byte count */
UINT8 size, /* Access size (number of bytes) */
bool write ) /* Write access */
{
UINT32 last, pagesize;
bool sys_mmu_tlb;
UINT32 phys;
UINT32 rc = OK;
if( !sys_legal_align( addr, size ) )
rc = SHELL_ERROR_ALIGN;
if( (rc == OK) && !sys_legal_align( count, size ) )
rc = SHELL_ERROR_ALIGN;
if( (rc == OK) && (count == 0) )
return OK;
if( rc == OK )
{
last = addr + (count - size);
if( last < addr )
rc = SHELL_ERROR_OVERFLOW;
}
if( rc == OK )
{
/* Determine physical addresses based on MMU and
* validate RAM range.
*/
SYSCON_read( SYSCON_CPU_TLB_AVAIL_ID,
(void *)&sys_mmu_tlb,
sizeof( bool ) );
if( !sys_mmu_tlb )
{
/* Assume Fixed Mapping MMU.
* We check for KSEG0/KSEG1 only (TBD : Could be improved).
*/
if(
((KSEG0( addr ) == addr) && (KSEG0( last ) == last)) ||
((KSEG1( addr ) == addr) && (KSEG1( last ) == last)) )
{
/* Range contained within KSEG0 or KSEG1 */
return sys_validate_ram_range( PHYS(addr),
PHYS(last) );
}
else
return SHELL_ERROR_ADDRESS;
}
else
{
/* MMU = TLB */
while( (rc == OK) && (addr <= last) )
{
if( KSEG0( addr ) == addr )
{
/* KSEG0, check if range leaves KSEG0 */
if( KSEG0( last ) == last )
{
/* Range contained within KSEG0 */
rc = sys_validate_ram_range( PHYS(addr),
PHYS(last) );
if( rc == OK )
return OK;
}
else
{
/* Range overflows KSEG0 */
rc = sys_validate_ram_range( PHYS(addr),
PHYS(KSEG1BASE-size) );
if( rc == OK )
{
/* Continue in KSEG1 */
addr = KSEG1BASE;
}
}
}
else if( KSEG1( addr ) == addr )
{
/* KSEG1, check if range leaves KSEG1 */
if( KSEG1( last ) == last )
{
/* Range contained within KSEG1 */
rc = sys_validate_ram_range( PHYS(addr),
PHYS(last) );
if( rc == OK )
return OK;
}
else
{
/* Range overflows KSEG1 */
rc = sys_validate_ram_range( PHYS(addr),
PHYS(KSSEGBASE-size) );
if( rc == OK )
{
/* Continue in KSSEG */
addr = KSSEGBASE;
}
}
}
else
{
/* KUSEG/KSSEG/KSEG3, i.e. TLB mapped */
switch( sys_tlb_lookup( addr, &phys, &pagesize ) )
{
case SYS_TLB_WP :
if( write )
rc = SHELL_ERROR_TLB_WP;
/* Fallthrough !! */
case SYS_TLB_OK :
if( rc == OK )
{
rc = sys_validate_ram_range( phys,
phys + pagesize - size );
}
if( rc == OK )
{
/* Calc next page start */
addr += pagesize;
}
break;
case SYS_TLB_NOTFOUND :
case SYS_TLB_NOTVALID :
default : /* Should not happen */
rc = SHELL_ERROR_TLB;
break;
}
}
}
}
}
if( (rc == SHELL_ERROR_TLB) ||
(rc == SHELL_ERROR_TLB_WP) )
{
sprintf( msg, "Address = 0x%08x", addr );
shell_error_data = msg;
}
return rc;
}
/************************************************************************
*
* sys_kseg0
* Description :
* -------------
*
* Determine KSEG0 address corresponding to input address.
*
* In case input address is TLB mapped, a lookup is performed in the
* TLB to determine the physical address. Then, the corresponding
* KSEG0 address is calculated.
*
* In case input address is in KSEG1 range, it is converted to KSEG0.
*
* Return values :
* ---------------
*
* TRUE if conversion was successfull, otherwise FALSE
*
************************************************************************/
bool
sys_kseg0(
UINT32 addr, /* Address to be converted */
UINT32 *kseg0addr ) /* OUT : Converted address */
{
UINT32 phys, pagesize;
bool sys_mmu_tlb;
SYSCON_read( SYSCON_CPU_TLB_AVAIL_ID,
(void *)&sys_mmu_tlb,
sizeof( bool ) );
if( sys_mmu_tlb )
{
/* MMU = TLB */
if( (KSEG0( addr ) == addr) || (KSEG1( addr ) == addr) )
{
*kseg0addr = KSEG0(addr);
return TRUE;
}
else
{
if( sys_tlb_lookup( addr, &phys, &pagesize ) == SYS_TLB_OK )
{
*kseg0addr = KSEG0( phys );
return TRUE;
}
else
return FALSE;
}
}
else
{
/* Assume Fixed Mapping MMU */
if( (KSEG0( addr ) == addr) || (KSEG1( addr ) == addr) )
{
*kseg0addr = KSEG0(addr);
return TRUE;
}
else
return FALSE;
}
}
/************************************************************************
*
* sys_legal_align
* Description :
* -------------
*
* Determine if alignment of address is legal
*
* Return values :
* ---------------
*
* TRUE -> Legal alignment, FALSE -> Illegal alignment
*
************************************************************************/
bool
sys_legal_align(
UINT32 address,
UINT32 align )
{
return (address == (address & ~(align - 1))) ? TRUE : FALSE;
}
/************************************************************************
* Implementation : static functions
************************************************************************/
/************************************************************************
* determine_dev
************************************************************************/
static bool
determine_dev(
UINT32 port,
UINT32 *major,
UINT32 *minor )
{
UINT32 id_major, id_minor;
if( port == PORT_TTY0 )
{
id_major = SYSCON_COM_TTY0_MAJOR;
id_minor = SYSCON_COM_TTY0_MINOR;
}
else if( port == PORT_TTY1 )
{
id_major = SYSCON_COM_TTY1_MAJOR;
id_minor = SYSCON_COM_TTY1_MINOR;
}
else
return FALSE;
SYSCON_read( id_major,
(void *)(major),
sizeof(UINT32) );
SYSCON_read( id_minor,
(void *)(minor),
sizeof(UINT32) );
return TRUE;
}
/************************************************************************
*
* sys_validate_ram_range
* Description :
* -------------
*
* Perform range check relating to RAM use.
*
* The range defined by parameters 'start' and 'last' is checked with
* relation to RAM use.
*
* The memory map allocates a range for RAM. In case the RAM
* module does not occupy this entire range, there will be an
* "empty" RAM range. We detect whether the specified range
* hits this empty RAM range. If so, we return an error code.
* Otherwise, OK is returned.
*
* In case of a hit in the unused range, shell_err_data is set to a
* text string stating the illegal address. This may be used by
* error handling.
*
* Return values :
* ---------------
*
* OK : No error
* SHELL_ERROR_RAM_RANGE : Error detected
*
************************************************************************/
static UINT32
sys_validate_ram_range(
UINT32 start, /* Start address (physical) */
UINT32 last ) /* Last address (physical) */
{
static void *ram_base;
static UINT32 ram_actual_size, ram_size;
static UINT32 ram_range_unused_start;
static UINT32 ram_range_unused_last;
static bool first = TRUE;
if( first )
{
/* Self-initialisation */
first = FALSE;
SYSCON_read( SYSCON_BOARD_SYSTEMRAM_ACTUAL_SIZE_ID,
(void *)&ram_actual_size,
sizeof(UINT32) );
SYSCON_read( SYSCON_BOARD_SYSTEMRAM_BASE_ID,
(void *)&ram_base,
sizeof(void *) );
SYSCON_read( SYSCON_BOARD_SYSTEMRAM_SIZE_ID,
(void *)&ram_size,
sizeof(UINT32) );
ram_range_unused_start = (UINT32)ram_base + ram_actual_size;
ram_range_unused_last = (UINT32)ram_base + ram_size - 1;
}
if( ram_actual_size == ram_size )
return OK; /* No unused RAM space */
if( (start >= ram_range_unused_start) &&
(start <= ram_range_unused_last) )
{
sprintf( msg, "Address = 0x%08x", start );
shell_error_data = msg;
return SHELL_ERROR_RAM_RANGE;
}
if( (last >= ram_range_unused_start) &&
(last <= ram_range_unused_last) )
{
sprintf( msg, "Address = 0x%08x", ram_range_unused_start );
shell_error_data = msg;
return SHELL_ERROR_RAM_RANGE;
}
return OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -