This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TMS570LS1227:使用引导加载程序和 SAFERTOS 时的预取中止

Guru**** 2382630 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1205464/tms570ls1227-prefetch-abort-when-using-a-bootloader-and-safertos

器件型号:TMS570LS1227

我已经为预取中止操作困扰了几天了。 根据文档、 预取中止与指令提取而非数据访问相关联。 当发生预取中止时、处理器将预取指令标记为无效、但在执行该指令之前不会接收到异常。

我们已安装 TMS570引导加载程序应用。 当我们安装 BareMetal 用户应用程序时、加载过程非常有效、但当我们安装 SafeRTOS 用户应用程序时、所有这些都会松散。 当 SAFERTOS 用户应用程序未使用引导程序时(例如、我们在0000_0000处启动程序时)、它会按预期工作。  

这是我的 bootloader  程序的内存映射:

MEMORY
{
    VECTORS 	(X)  	: origin=0x00000000 length=0x00000080
    FLASH_API  	(RX)  	: origin=0x00000080 length=0x000014E0
    FLASHBOOT  	(RX) 	: origin=0x00001560 length=0x0007EB00
    STACKS  	(RW) 	: origin=0x08000000 length=0x00002000
    RAM     	(RW) 	: origin=0x08002000 length=0x0003E000
}

这是我的引导加载程序 矢量表(sys_intvecs.asm)文件:

   .sect ".intvecs"
    .arm

;-------------------------------------------------------------------------------
; import reference for interrupt routines

    .ref _c_int00
    .ref _dabort

    .def resetEntry

;-------------------------------------------------------------------------------
resetEntry
		; Since the user application starts @ 0x00020000, so each interrupt
		; entry needs to be set to 0x1FFF8 which is 0x00020000 - 0x8. Basically
		; when an interrupt occurs, the interrupt vector table will force the
		; PC to jump to the appropriate location in flash that was set by the
		; user application.
        b   _c_int00               ;0x00
        b   #0x1FFF8               ;0x04 ;  ; vUndefAbort on User Application
        b   #0x1FFF8               ;0x08, Software interrupt ; vSafeRTOSSVCHandler  on User Application
        b   #0x1FFF8               ;0x0C, Abort (prefetch) ; vPrefetchAbort  on User Application
        b   #0x1FFF8               ;0x10, Abort (data) ; vDataAbort  on User Application    
reservedEntry
        b   #0x1FFF8               ;phantomInterrupt on User Application
        ldr pc,[pc,#-0x1b0]
        ldr pc,[pc,#-0x1b0]
    
;-------------------------------------------------------------------------------

在我的可引导式 SAFERTOS 用户应用程序中、有以下存储器映射:

MEMORY
{
    VECTORS (X)     : origin=0x00020000 length=0x00000080
    KERN_FUNC (RX)  : origin=0x00020080 length=0x0000FF80
    FLASH0  (RX)    : origin=0x00030000 length=0x0010FFFF
    STACKS  (RW)    : origin=0x08000000 length=0x00001800
    KERN_DATA (RW)  : origin=0x08001800 length=0x00000800
    RAM     (RW)    : origin=0x08002000 length=0x0002C000
}

这是我的矢量表:

    .sect ".intvecs"
    .arm

;-------------------------------------------------------------------------------
; import reference for interrupt routines

    .ref _c_int00
    .ref vUndefAbort
    .ref vSafeRTOSSVCHandler
    .ref vPrefetchAbort
    .ref vDataAbort
    .ref phantomInterrupt
    .def resetEntry

;-------------------------------------------------------------------------------
; interrupt vectors

resetEntry
        b   _c_int00
        b   vUndefAbort
        b   vSafeRTOSSVCHandler
        b   vPrefetchAbort
        b   vDataAbort
        b   phantomInterrupt
        ldr pc,[pc,#-0x1b0]
        ldr pc,[pc,#-0x1b0]

当用户应用程序运行且发生预取中止时、相关 CP15将变为:

Cp15_CP15_AUX_DIRECTOR_FAULT_STATUS = 0x00400000

Cp15_CP15_instruction_fault_address = 0x0005409C

此故障地址位于 vPortIdleHook 函数中:

  

我认为、当应用程序调用闪存地址0005_4098上的服务调用指令(SVC #4)时会出现此问题。 该指令将分支到0000_0008 (软件中断)、我的引导加载程序矢量表将立即发出到0002_0008的跳转。 这一切都是合法的,我看到正在跳。  

0002_0008包含 SafeRTOS SVC 处理程序、当我逐步执行它时、我可以看到已读取并发送了正确的服务编号(#4)。

SVC 正在退出、有一条指令在执行时获得预取中止。

_vPortSVC_exit:
        LDMFD   SP!, { R4, R5, PC }^        ; Pop saved R4 and R5, and the LR into the PC to return

在执行该行之前、以下是我的完整寄存器导出:

执行该行后、以下是我的完整寄存器导出:

在这两个文件中、我们可以清楚地看到 Cp15_CP15_AUX_DIAG_FAULT_STATUS 和 Cp15_CP15_DIRECTOR_FAULT_ADDRESS 更改。

通过单步执行代码、我们可以清楚地看到从0002_71cc 到0000_000c、然后在发生该预取中止时变为0002_000c 的流程。

如前所述、当 用户应用程序从0000_0000开始时、绝对没有问题。

如果能 深入了解如何解决此问题以及发生预取中止的原因、我将非常感激。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Nuno:

    我们已着手解决您的问题、我们将很快提供更新。

    --

    谢谢。此致、
    Jagadish。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    指出 MPU 问题的另一个拼图。  

    SVC #4将设备置于用户模式,而 SVC #3将设备置于特权模式。  

     

    如果我在调度表中将 SVC #4设置为将设备置于 特权 模式、应用程序将不再进入预取中止。 很显然、 这是一个黑客攻击、但可为正在发生的事情提供线索。

    还在寻找建议。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Nuno:

    如果通过将设备置于特权模式来修改调度表以处理 SVC #4请求、则可能会由于设备现在正在特权模式下运行、而阻止应用程序进入预取中止。 该 MCU 具有对所有系统资源的访问权限、包括导致预取中止的内存区域。

    --

    谢谢。此致、
    Jagadish。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    但从某种意义上来说、它无法实现具有 MPU 保护和 SAFERTOS 的目的。

    我和 SAFERTOS 的研究员取得了联系,他们解释说,问题是 SAFERTOS 将包括向量表在内的东西放置在一个 MPU 保护的区域,不允许非特权访问。 潜在的问题是、如果您将引导加载程序放置在向量表附近的低内存中、内核区域基地址(可能)和结束地址(肯定)会有所上移、然后计算出的区域大小会更大。 这将导致各种问题。  

    为了解决此问题、我将引导加载程序代码移到了闪存的末尾、并调整了引导加载程序和用户应用程序的链接器文件。 工作得很好。 SafeRTOS、MPU、外设、以太网…… 一切。

    为了帮助下一个 肯定 也会有这个问题在未来的人... 以下是引导加载程序的存储器映射:

    MEMORY
    {
    
    /* Bootloader: Due to SafeRTOS MPU interface, we had to bring the user
     * application to a staring address of 0x000_4000, and we had to push the
     * bootloader code towards the end of the flash.  Since, the flash has
     * size of 0x0013_FFFF, and since the bootloader code starts at 0x0012_0000,
     * the maximum bootloader size is 0x0001_FFFF bytes, or 128 KiB (kibibytes).
     *
     */
        VECTORS 	(X)  	: origin=0x00000000 length=0x00000080
        FLASH_API  	(RX)  	: origin=0x00120000 length=0x000014E0
        FLASHBOOT  	(RX) 	: origin=0x001214E0 length=0x0001EB1F
        STACKS  	(RW) 	: origin=0x08000000 length=0x00002000
        RAM     	(RW) 	: origin=0x08002000 length=0x0003E000
    }
    

    以下是针对用户应用程序的存储器映射:

    MEMORY
    {
        // Bootloader where APP_START_ADDRESS is 0x0000_4000
        VECTORS (X)     : origin=0x00004000 length=0x00000080
        KERN_FUNC (RX)  : origin=0x00004080 length=0x0000FF80
        FLASH0  (RX)    : origin=0x00014000 length=0x000F0000
        STACKS  (RW)    : origin=0x08000000 length=0x00001800
        KERN_DATA (RW)  : origin=0x08001800 length=0x00000800
        RAM     (RW)    : origin=0x08002000 length=0x0002C000
    
    }

    这是我的 sys_intvecs.asm

        .sect ".intvecs"
        .arm
    
    ;-------------------------------------------------------------------------------
    ; import reference for interrupt routines
    
        .ref _c_int00
        .ref _dabort
    
        .def resetEntry
    
    ;-------------------------------------------------------------------------------
    resetEntry
    
    		; Since the user application starts @ 0x0000_4000, each interrupt
    		; entry needs to be set to 0x3FF8 which is 0x0000_4000 - 0x0000_008.
    		; Basically when an interrupt occurs, the interrupt vector table will
    		; force the PC to jump to the appropriate location in flash in the
    		; user application.
            b   _c_int00 ;0x00
            b   #0x3FF8  ;0x04 ; vUndefAbort on User Application
            b   #0x3FF8  ;0x08, Software interrupt; vSafeRTOSSVCHandler on User Application
            b   #0x3FF8  ;0x0C, Abort (prefetch); vPrefetchAbort on User Application
            b   #0x3FF8  ;0x10, Abort (data); vDataAbort on User Application
    reservedEntry
            b   #0x3FF8  ;phantomInterrupt on User Application
            ldr pc,[pc,#-0x1b0]
            ldr pc,[pc,#-0x1b0]
        
    ;-------------------------------------------------------------------------------

    我必须在0x0000_4000处启动用户应用程序、而不是像0x0000_0080这样的东西、因为我找不到一个好方法来部分删除某个区域的内容。