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.
I have been struggling with a prefetch abort for several days now. According to documentation, a prefetch abort is associated with an instruction fetch as opposed to a data access. When a prefetch abort occurs, the processor marks the prefetched instruction as invalid, but does not take the exception until it executes the instruction.
We have a TMS570 bootloader application installed. The booloading process works great when we install baremetal user applications, but all hell breaks loose when we install a SafeRTOS user application. The SafeRTOS user application works as expected when it doesn't use the bootolader (e.g. when we start the program at 0000_0000).
This is the memory map for my bootloader program:
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 }
And this is my bootloader vector table (sys_intvecs.asm) file:
.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] ;-------------------------------------------------------------------------------
On my bootloadable SafeRTOS user application, I have the following memory map:
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 }
And here is my vector table:
.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]
When the user application runs, and the prefecth abort occurs the relevant CP15 become:
Cp15_CP15_AUX_INSTRUCTION_FAULT_STATUS = 0x00400000
Cp15_CP15_INSTRUCTION_FAULT_ADDRESS = 0x0005409C
This fault address is inside the vPortIdleHook function:
I believe the issue occurs when the application calls service call instruction (svc #4) on flash address 0005_4098. This instruction will branch to 0000_0008 (software interrupt), and my booloader vector table will issue an immediate jump to 0002_0008. This is all legit, and I see the jump being made.
0002_0008 contains the SafeRTOS SVC Handler, and when I step through it, I can see that the correct service number (#4) has been read and dispatched.
Right as the SVC is exiting, there is an instruction and it's upon its execution that we get the prefetch abort.
_vPortSVC_exit: LDMFD SP!, { R4, R5, PC }^ ; Pop saved R4 and R5, and the LR into the PC to return
Before executing this line, here is my complete register export:
After executing this line, here is my complete register export:
In these two files, we can clearly see the Cp15_CP15_AUX_INSTRUCTION_FAULT_STATUS and Cp15_CP15_INSTRUCTION_FAULT_ADDRESS change.
Stepping through the code, we can clearly see the flow going from 0002_71cc to 0000_000c and then to 0002_000c when this prefetch abort occurs.
As stated earlier, there is absolutely no issue when the user application starts at 0000_0000.
I would be grateful for insights on how to fix this issue and why this prefetch abort is occuring.
Hi Nuno,
We started to work on your issue, and we will provide an update soon.
--
Thanks & regards,
Jagadish.
Another piece of the puzzle that points out to a MPU issue.
The SVC #4 puts the device into user mode, whereas SVC #3 puts the device into privileged mode.
If I set the SVC #4 on the dispatch table to put the device into privileged mode, the application no longer enters a prefetch abort. Obviously, this is a hack but gives a clue to what is going on.
Still looking for suggestions.
Hi Nuno,
If you modify the dispatch table to handle the SVC #4 request by putting the device into privileged mode, it may prevent the application from entering prefetch abort because the device is now running in privileged mode, which has access to all system resources, including the memory regions that caused the prefetch abort.
--
Thanks & regards,
Jagadish.
In a sense that defeats the purpose of having a MPU protection and SafeRTOS.
I got in touch with the SafeRTOS fellows, and they explained that the issue, at base, is that SAFERTOS places stuff, including the vector table, in a region that is protected by the MPU from unprivileged access. Potential problems are that if you place the bootloader in low memory near the vector table(s), the kernel region base address (possibly) and end address (definitely) move up somewhat, and the region size calculated then is bigger. This will cause all sorts of problems.
To work around this, I moved the bootloader code towards the end of the flash and adjusted the linker files for my bootloader application and my user application. It works great. SafeRTOS, MPU, peripherals, ethernet... everything.
To help out the next fellow that will surely also have this issue in the future... Here is my memory map for the bootloader:
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 }
Here is my memory map for the user application:
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 }
Here is my 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] ;-------------------------------------------------------------------------------
I had to start my user application at 0x0000_4000 instead of something like 0x0000_0080, because I couldn't find a good way to partially delete the contents of a region.