📄 hal_if.c
字号:
//=============================================================================
//
// hal_if.c
//
// ROM/RAM interfacing functions
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
// Copyright (C) 2002, 2003 Gary Thomas
// Copyright (C) 2003 Nick Garnett <nickg@calivar.com>
// Copyright (C) 2003 Jonathan Larmour <jlarmour@eCosCentric.com>
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting the copyright
// holders.
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): jskov
// Contributors:jskov, woehler
// Date: 2000-06-07
//
//####DESCRIPTIONEND####
//
//=============================================================================
#include <pkgconf/hal.h>
#ifdef CYGPKG_KERNEL
# include <pkgconf/kernel.h>
#endif
#include <cyg/infra/cyg_ass.h> // assertions
#include <cyg/hal/hal_arch.h> // set/restore GP
#include <cyg/hal/hal_io.h> // IO macros
#include <cyg/hal/hal_if.h> // our interface
#include <cyg/hal/hal_diag.h> // Diag IO
#include <cyg/hal/hal_misc.h> // User break
#include <cyg/hal/hal_stub.h> // stub functionality
#include <cyg/hal/hal_intr.h> // hal_vsr_table and others
#ifdef CYGPKG_REDBOOT
#include <pkgconf/redboot.h>
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
#include <redboot.h>
#include <flash_config.h>
#endif
#ifdef CYGOPT_REDBOOT_FIS
#include <fis.h>
#endif
#endif
//--------------------------------------------------------------------------
externC void patch_dbg_syscalls(void * vector);
externC void init_thread_syscall(void * vector);
//--------------------------------------------------------------------------
// Implementations and function wrappers for monitor services
// flash config state queries
#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
static __call_if_flash_cfg_op_fn_t flash_config_op;
static cyg_bool
flash_config_op(int op, struct cyg_fconfig *fc)
{
cyg_bool res = false;
CYGARC_HAL_SAVE_GP();
switch (op) {
case CYGNUM_CALL_IF_FLASH_CFG_GET:
res = flash_get_config(fc->key, fc->val, fc->type);
break;
case CYGNUM_CALL_IF_FLASH_CFG_NEXT:
res = flash_next_key(fc->key, fc->keylen, &fc->type, &fc->offset);
break;
case CYGNUM_CALL_IF_FLASH_CFG_SET:
res = flash_set_config(fc->key, fc->val, fc->type);
break;
default:
// nothing else supported yet - though it is expected that "set"
// will fit the same set of arguments, potentially.
break;
}
CYGARC_HAL_RESTORE_GP();
return res;
}
#endif
#ifdef CYGOPT_REDBOOT_FIS
static __call_if_flash_fis_op_fn_t flash_fis_op;
static cyg_bool
flash_fis_op( int op, char *name, void *val)
{
cyg_bool res = false;
struct fis_image_desc *fis;
int num;
CYGARC_HAL_SAVE_GP();
fis = fis_lookup(name, &num);
if(fis != NULL)
{
switch ( op ) {
case CYGNUM_CALL_IF_FLASH_FIS_GET_FLASH_BASE:
*(CYG_ADDRESS *)val = fis->flash_base;
res = true;
break;
case CYGNUM_CALL_IF_FLASH_FIS_GET_SIZE:
*(unsigned long *)val = fis->size;
res = true;
break;
case CYGNUM_CALL_IF_FLASH_FIS_GET_MEM_BASE:
*(CYG_ADDRESS *)val = fis->mem_base;
res = true;
break;
case CYGNUM_CALL_IF_FLASH_FIS_GET_ENTRY_POINT:
*(CYG_ADDRESS *)val = fis->entry_point;
res = true;
break;
case CYGNUM_CALL_IF_FLASH_FIS_GET_DATA_LENGTH:
*(unsigned long *)val = fis->data_length;
res = true;
break;
case CYGNUM_CALL_IF_FLASH_FIS_GET_DESC_CKSUM:
*(unsigned long *)val = fis->desc_cksum;
res = true;
break;
case CYGNUM_CALL_IF_FLASH_FIS_GET_FILE_CKSUM:
*(unsigned long *)val = fis->file_cksum;
res = true;
break;
default:
break;
}
}
CYGARC_HAL_RESTORE_GP();
return res;
}
#include <cyg/io/flash.h>
extern int __flash_init;
extern int fisdir_size;
extern int flash_block_size;
extern void* fis_addr;
#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
extern void* redundant_fis_addr;
#endif
extern void* fis_work_block;
extern int do_flash_init(void);
extern int fis_start_update_directory(int autolock);
extern int fis_update_directory(int autolock, int error);
static __call_if_flash_fis_op2_fn_t flash_fis_op2;
static int
flash_fis_op2( int op, unsigned int index, struct fis_table_entry *entry)
{
int res=0;
CYGARC_HAL_SAVE_GP();
switch ( op ) {
case CYGNUM_CALL_IF_FLASH_FIS_GET_VERSION:
res=CYG_REDBOOT_FIS_VERSION;
break;
case CYGNUM_CALL_IF_FLASH_FIS_INIT:
__flash_init=0; //force reinitialization
res=do_flash_init();
break;
case CYGNUM_CALL_IF_FLASH_FIS_GET_ENTRY_COUNT:
res=fisdir_size / sizeof(struct fis_image_desc);
break;
case CYGNUM_CALL_IF_FLASH_FIS_GET_ENTRY:
{
struct fis_image_desc* img = (struct fis_image_desc *)fis_work_block;
CYG_ASSERT(entry!=0, "fis_table_entry == 0 !");
memcpy(entry->name, img[index].u.name, 16);
entry->flash_base=img[index].flash_base;
entry->mem_base=img[index].mem_base;
entry->size=img[index].size;
entry->entry_point=img[index].entry_point;
entry->data_length=img[index].data_length;
entry->desc_cksum=img[index].desc_cksum;
entry->file_cksum=img[index].file_cksum;
res=0;
}
break;
case CYGNUM_CALL_IF_FLASH_FIS_START_UPDATE:
fis_start_update_directory(1);
break;
case CYGNUM_CALL_IF_FLASH_FIS_FINISH_UPDATE:
fis_update_directory(1, index);
break;
case CYGNUM_CALL_IF_FLASH_FIS_MODIFY_ENTRY:
{
res=0;
if (entry->name[0]!=0xff)
{
if ((entry->size==0)
|| ((entry->size % flash_block_size) !=0)
|| (flash_verify_addr((void*)entry->flash_base)!=0)
|| (flash_verify_addr((void*)(entry->flash_base+entry->size-1))!=0)
|| (entry->size < entry->data_length))
res=-1;
}
if (res==0)
{
struct fis_image_desc* img = (struct fis_image_desc *)fis_work_block;
memcpy(img[index].u.name, entry->name, 16);
img[index].flash_base=entry->flash_base;
img[index].mem_base=entry->mem_base;
img[index].size=entry->size;
img[index].entry_point=entry->entry_point;
img[index].data_length=entry->data_length;
img[index].desc_cksum=entry->desc_cksum;
img[index].file_cksum=entry->file_cksum;
}
}
break;
default:
break;
}
CYGARC_HAL_RESTORE_GP();
return res;
}
#endif
//----------------------------
// Delay uS
#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_DELAY_US
static __call_if_delay_us_t delay_us;
static void
delay_us(cyg_int32 usecs)
{
CYGARC_HAL_SAVE_GP();
#ifdef CYGPKG_KERNEL
{
cyg_int32 start, elapsed, elapsed_usec;
cyg_int32 slice;
cyg_int32 usec_per_period = CYGNUM_HAL_RTC_NUMERATOR/CYGNUM_HAL_RTC_DENOMINATOR/1000;
cyg_int32 ticks_per_usec = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD/usec_per_period;
do {
// Spin in slices of 1/2 the RTC period. Allows interrupts
// time to run without messing up the algorithm. If we
// spun for 1 period (or more) of the RTC, there would also
// be problems figuring out when the timer wrapped. We
// may lose a tick or two for each cycle but it shouldn't
// matter much.
// The tests against CYGNUM_KERNEL_COUNTERS_RTC_PERIOD
// check for a value that would cause a 32 bit signed
// multiply to overflow. But this also implies that just
// multiplying by ticks_per_usec will yield a good
// approximation. Otherwise we need to do the full
// multiply+divide to get sufficient accuracy. Note that
// this test is actually constant, so the compiler will
// eliminate it and only compile the branch that is
// selected.
if( usecs > usec_per_period/2 )
slice = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD/2;
else if( CYGNUM_KERNEL_COUNTERS_RTC_PERIOD/2 >= 0x7FFFFFFF/usec_per_period )
slice = usecs * ticks_per_usec;
else
{
slice = usecs*CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
slice /= usec_per_period;
}
HAL_CLOCK_READ(&start);
do {
HAL_CLOCK_READ(&elapsed);
elapsed = (elapsed - start); // counts up!
if (elapsed < 0)
elapsed += CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
} while (elapsed < slice);
// Adjust by elapsed, not slice, since an interrupt may
// have been stalling us for some time.
if( CYGNUM_KERNEL_COUNTERS_RTC_PERIOD >= 0x7FFFFFFF/usec_per_period )
elapsed_usec = elapsed / ticks_per_usec;
else
{
elapsed_usec = elapsed * usec_per_period;
elapsed_usec = elapsed_usec / CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
}
// It is possible for elapsed_usec to end up zero in some
// circumstances and we could end up looping indefinitely.
// Avoid that by ensuring that we always decrement usec by
// at least 1 each time.
usecs -= elapsed_usec ? elapsed_usec : 1;
} while (usecs > 0);
}
#else // CYGPKG_KERNEL
#ifdef HAL_DELAY_US
// Use a HAL feature if defined
HAL_DELAY_US(usecs);
#else
// If no accurate delay mechanism, just spin for a while. Having
// an inaccurate delay is much better than no delay at all. The
// count of 10 should mean the loop takes something resembling
// 1us on most CPUs running between 30-100MHz [depends on how many
// instructions this compiles to, how many dispatch units can be
// used for the simple loop, actual CPU frequency, etc]
while (usecs-- > 0) {
int i;
for (i = 0; i < 10; i++);
}
#endif // HAL_DELAY_US
#endif // CYGPKG_KERNEL
CYGARC_HAL_RESTORE_GP();
}
#endif // CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_DELAY_US
// Reset functions
#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_RESET
static __call_if_reset_t reset;
static void
reset(void)
{
CYGARC_HAL_SAVE_GP();
// With luck, the platform defines some magic that will cause a hardware
// reset.
#ifdef HAL_PLATFORM_RESET
HAL_PLATFORM_RESET();
#endif
#ifdef HAL_PLATFORM_RESET_ENTRY
// If that's not the case (above is an empty statement) there may
// be defined an address we can jump to - and effectively
// reinitialize the system. Not quite as good as a reset, but it
// is often enough.
goto *HAL_PLATFORM_RESET_ENTRY;
#else
#error " no RESET_ENTRY"
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -