从引导程序跳转会生成异常

时间:2013-08-13 20:13:40

标签: c bootloader

我为我的SAM4S编写了一个引导加载程序,它位于扇区0并在扇区1中加载一个应用程序。然而问题是,当我尝试跳转到新函数时,它似乎生成一个异常(调试器转到Dummy_Handler ())。

Bootloader在地图中包含以下条目:

.application    0x00410000        0x0
                0x00410000                . = ALIGN (0x4)
                0x00410000                _sappl = .
                0x00410004                _sjump = (. + 0x4)

应用程序图像映射文件具有:

.vectors       0x00410000       0xd0 src/ASF/sam/utils/cmsis/sam4s/source/templates/gcc/startup_sam4s.o
                0x00410000                exception_table
…
.text.Reset_Handler
                0x0041569c      0x100 src/ASF/sam/utils/cmsis/sam4s/source/templates/gcc/startup_sam4s.o
                0x0041569c                Reset_Handler

异常表定义如下:

const DeviceVectors exception_table = {

        /* Configure Initial Stack Pointer, using linker-generated symbols */
        .pvStack = (void*) (&_estack),

        .pfnReset_Handler      = (void*) Reset_Handler,

引导加载程序将应用程序跳转点声明为:

extern void (*_sjump) ();

然后拨打以下电话:

_sjump();

0x00410004处的存储器内容为0x0041569d,我注意到这不是字对齐的。这是因为我们使用Thumb指令吗?无论哪种方式,为什么它不是0x0041569c?或者更重要的是为什么会出现异常?

谢谢,

德万

更新 找到this但它似乎对我不起作用:

void (*user_code_entry)(void);
unsigned *p; 
p = (uint32_t)&_sappl + 4;
user_code_entry = (void (*)(void))(*p - 1);

if(applGood && tempGood) {
    SCB->VTOR = &_sappl;

    PrintHex(p);
    PrintHex(*p);
    PrintHex(user_code_entry);

    user_code_entry();

}

代码打印: 00410004 0041569D 0041569C

更新更新 尝试使用C函数指针跳转的代码生成了以下反汇编:

--- D:\Zebra\PSPT_SAM4S\PSPT_SAM4S\SAM4S_PSPT\BOOTLOADER\Debug/.././BOOTLOADER.c 
user_code_entry(); 
004005BA ldr    r3, [r7, #4]     
004005BC blx    r3

我能够使用以下程序集进行此操作:

"mov   r1, r0        \n"
"ldr   r0, [r1, #4]  \n"
"ldr   sp, [r1]      \n"
"blx   r0"

基于此,我想知道是否需要堆栈重置,如果是这样,是否可以在C中完成?

2 个答案:

答案 0 :(得分:3)

我遇到了与SAM4E相同的问题。我猜不出你的问题是什么,但我可以指出我遇到的困难和我使用的信息。

我的bootloader没有在固件的几个部分存储在正确的内存位置。这导致了dummy_handler异常。当我在地址计算中修复错误时,引导程序工作得很好。

我的建议:

  • 关注ATMEL的示例:DocumentExample Code应该足够了。 main.c足以理解引导程序应该如何工作。没有必要在开始时进入分区细节。
  • 您可能想了解如何execute functions/ISRs from RAM
  • This webpage解释了英特尔HEX格式。
  • 最后,在引导加载程序完成升级后,您可以读取闪存并将其发送回主机。然后将其与原始图像进行比较(使用脚本)。这就是我调试引导加载程序的方式。

其他可能有用的想法:

  • 在你写这篇文章之前你会删除每一页吗?
  • 在删除/写入之前,您是否解锁了每个内存空间?
  • 您可以锁定Bootloader的部分以避免错误地覆盖它
  • 您可以锁定已升级固件的部分。

您必须指向的地址是0x00410000而不是0x00410004。 Atmel的示例代码(请参阅函数binary_exec)结合Intel Hex格式(记录类型05)应该可以解决这个问题。

我希望这条信息会有所帮助!

答案 1 :(得分:2)

我在SAM4S上遇到了同样的问题,这让我想到了这个问题。所以,如果有人再次来到这里,我就找到了。 正如ChrisB提到的那样,遵循Atmel示例代码是一个良好的开端,但我发现问题是请求跳转的实际代码对SAM4S不起作用。 缺少的是在向量表之前重新设置堆栈指针,然后加载重置处理程序地址。 尝试这样的事情:

static void ExecuteApp(void)
{
    uint32_t i;

   // Pointer to the Application Section
   void (*application_code_entry)(void);

   // -- Disable interrupts and system timer

    __disable_irq();
    SysTick->CTRL = 0; // Disable System timer

    // disable and clear pending IRQs
    for (i = 0; i < 8; i++) 
    {
        NVIC->ICER[i] = 0xFFFFFFFF; // disable IRQ
        NVIC->ICPR[i] = 0xFFFFFFFF; // clear pending IRQ
    }


    // Barriers
    __DSB();    // data synchronization barrier
    __ISB();    // instruction synchronization barrier

    // Rebase the Stack Pointer
     __set_MSP(*(uint32_t *) APPCODE_START_ADDR);

     // Rebase the vector table base address
     SCB->VTOR = ((uint32_t) APPCODE_START_ADDR & SCB_VTOR_TBLOFF_Msk);

     // Load the Reset Handler address of the application
     application_code_entry = (void (*)(void))(unsigned *)(*(unsigned *)
                              (APP_START_RESET_VEC_ADDRESS));

    __DSB();
    __ISB();

    // -- Enable interrupts
    __enable_irq();

     // Jump to user Reset Handler in the application
     application_code_entry();

}