Summary of Problem: For TMX320F28069 device, the Device_cal function in Boot ROM does not work if device is secured and Stack is located in L0 DPSARAM.
In our application code, in the file F2806x_SysCtrl.c, we call Device_cal as recommended by TI’s documentation and Control Suite examples. Also, in our application, we have the ‘Stack’ located in L0 DPSARAM (because we needed more than 2Kx16 of stack space).
The call to Device_cal works if we do not have the device secured with a password in the Code Security Module. But, if we have the device secured, then Device_cal does not work.
The problem is that the function Device_cal tries to access the Stack (located in PROTECTED L0 DPSARAM) from its code executing in UNPROTECTED M0 SARAM. This does not work because the device cannot access PROTECTED memory from code executing in UNPROTECTED memory (when the device is secure).
More Details:
Device_cal is located at address 0x03d7c80 in the Boot ROM.
Standard initialization code sets the stack pointer (SP) to point to memory in L0 DPSARAM.
Then, using Code Compose Studio, we step through the Device_cal code in the ‘Disassembly’ view. At address 0x3d7ca7, the code branches (unconditionally) to address 0x3d7db0, which is in a “RESERVED” section of the device’s memory map. Continuing to step through the code in this section, it apparently writes some data/code into M0 SARAM that it is subsequently going to execute. At address 0x3d7dec the program jumps to 0x0001a0 which is located in (unprotected) M0 SARAM and executes 10 instructions, the last instruction being a LRETR instruction, which accesses the Stack. However, if the device is secured, then the LRETR instruction (executing from UNPROTECTED M0 SARAM) cannot access the Stack (located in PROTECTED L0 DPSARAM).
It seems that the problem is in the Device_cal function in the Boot ROM. It should not try to execute an LRETR instruction from UNPROTECTED M0 memory, because this does not work if the Stack is located in PROTECTED L0 memory.
Please advise.
Eric
Eric,we are looking into this. Can you confirm the below things.1.> Revision of boot ROM (value at the locations 0x3FFFBA and 0x3FFFBB) on the device.2.> when you are stepping through Device_cal code are you stepping it by putting a break point at the Device_cal and executing the device after a debug reset or are you stepping through Device_cal function when called from application context.3.> Will it be possible to switch the stacks temporarily in your code, I beleive Device_cal is being executed in your main during the initialization - can you initialize SP to unsecure memory when calling it and initialize it back to what your application needs after Device_cal returns?There is an errata listed for 28069 REV0 devices, I beleive which is what you are observing when you step through the Device_cal code. The work around in Device_Cal is supposed to be working/executing only if Device_cal is called from bootROM - Device_Cal does use stack to do this. Please note that irrespective of this work around being present or not (on REVA devices there is no boot ROM related Work around) Device_cal still uses LRETR to return back to caller. On 28069 device, Device_cal is executed from unsecure memory (just like boot ROM) and any code running from unsecure memories cannot access secure memories. We are looking in to this more. Best RegardsSantosh
Santosh,
Here are answers to your questions:
1. Revision of the Boot ROM: Boot ROM Version: 0x3fffba = 0x0001 Boot ROM Release: 0x3fffbb = 0x1010
2. I am stepping through Device_cal function when called from application context. When Device_cal is called from the application context, the SP has already been set to point to SECURE memory.
3. We could try doing what you suggest. It would look something like this? Saved_IER = IER; IER = Saved_IER & 0x0004; /* save IER and disable interrupts */ Saved_SP = SP; /* not sure about the exact syntax for doing this */ SP = ???; /* needs to be an address in UNSECURE memory; what address should we use? */ Device_cal(); SP = Saved_SP; /* restore SP */ IER = Saved_IER; /* restore IER */
We will have to make sure that the stack area that we choose for Device_cal does not stomp on anything needed by the application context, and make sure it is an area that is not used by Device_cal.
Could you also explain why Device_cal writes data/code to M0 and then jumps to it and executes it? If it did not do this, then it would not have to perform an LRETR instruction from UNSECURE M0 memory.
Thanks for your help. I look forward to additional responses.
My previous post is wrong. I had been single-stepping through the Boot ROM Device_cal function.
I just now single-stepped through Device_cal when called from our application context, and in this case Device_cal does NOT jump to code in the UNSECURE M0.
However, the basic problem still remains (but executing code from M0 has nothing to do with the issue).
In summary, the problem is that our application context has the Stack Pointer (SP) pointing to SECURE L0 memory, and we call Device_cal in the Boot ROM in UNSECURE memory, and Device_cal tries to use the memory pointed to by the SP, which will not work if the device is SECURE.
Eric,
Thanks for the details. This is a REV0 device, so we need to make sure whatever we put in application will also works for REVA devices as well - I don't think it will be a problem because on all these devices Device_Cal is executed from unsecure memory. see if below helps.
Eric R. We could try doing what you suggest. It would look something like this? Saved_IER = IER; IER = Saved_IER & 0x0004; /* save IER and disable interrupts */ Saved_SP = SP; /* not sure about the exact syntax for doing this */ SP = ???; /* needs to be an address in UNSECURE memory; what address should we use? */ Device_cal(); SP = Saved_SP; /* restore SP */ IER = Saved_IER; /* restore IER */ We will have to make sure that the stack area that we choose for Device_cal does not stomp on anything needed by the application context, and make sure it is an area that is not used by Device_cal.
We could try doing what you suggest. It would look something like this? Saved_IER = IER; IER = Saved_IER & 0x0004; /* save IER and disable interrupts */ Saved_SP = SP; /* not sure about the exact syntax for doing this */ SP = ???; /* needs to be an address in UNSECURE memory; what address should we use? */ Device_cal(); SP = Saved_SP; /* restore SP */ IER = Saved_IER; /* restore IER */
Regarding above, you will be calling Device_cal before initializing PIE. Device_cal doesn't touch IER either so you don't have to save/restore it. It doesn't hurt doing that though.
You can point Stack to bootROM default stack - 0x0002. Your application can re-use this memory later on after the job is done.
Eric R.Could you also explain why Device_cal writes data/code to M0 and then jumps to it and executes it? If it did not do this, then it would not have to perform an LRETR instruction from UNSECURE M0 memory.
Regarding above, this is done as part of boot ROM work around function. CSM passwords read instuctions are copied from ROM to M0 RAM (boot ROM reserved memory) and executed from there because CSM has to be unlocked by reading the passowords either from ROM or unsecure RAM. This is done only in stand-alone boot when Device_cal is called from bootROM. It shouldn't be done when Device_cal is called from application. Now, in your case because SP is in secure memory and Device_cal is in OTP memory which is unsecure it is not able to identify from where the function is being called so it is confused. Once you move SP to unsecure memory in your application before calling Device_cal it will not copy those instructions to M0 RAM any more so LRETR will not be executed from M0 RAM any more. But even in this case an LRETR is executed from OTP memory which is again unsecure memory (this is the case on REVA devices). So above solution should work for both REV0 and REVA devices.
Hope above helps and let us know if it works, please let us know if you have more questions.
Best Regards
Santosh
What is the syntax for accessing the stack pointer in C code?
<forums are acting wierd - mail from forum and post to forum are terribly out of sync, atleast for me :-(>
I just read the post where you mention that you were stepping through Device_cal when called from bootROM context. It makes sense, I was assuming the same. and yes the problem still remains because LRETR is executed when SP points to secure memory.
I'm not sure if its possible in a C instruction, you could easily do this in in-line assembly. Experts and Gurus suggest to put a function around it in an assembly file and call that function from C instead of using inline assembly - Its up to you. Below is something I put quickly. I haven't RUN this on board to test as I don't have one at my disposal currently. But you should do something similar, see if below works.
//NOT VERIFIED - JUST COMPILED
.global __get_current_stack_get_current_stack: PUSH SP MOVL ACC, *--SP ; returns current stack in accumulator ? LRETR
.global __set_current_stack_set_current_stack: MOV SP, ACC ; pass stack value in accumulator - which gets set in SP? LRETR.
I don't think _set_current_stack will work because LRETR will not return correctly since the SP was modified in the previous instruction; i.e. the SP is no longer going to be pointing to the correct return-address for the function. Correct?
you are right....you will have to put that in inline assembly. Or I think there is another way of function call which doesn't use stack for returning. I think it is called fast function call procedure. It is documented in C28x assembly reference guide - look for FFC. I'm sure you can use this.
It turns out that _Get_Current_Stack in posting above also has a problem. When the function _Get_Current_Stack is called, the return address is pushed on the stack and the SP is incremented by 2. We need to undo that increment by 2 in order to have the value of the SP that we want to save. I played around a little bit in assembly code, and came up with the following code that works:
Here is the ASSEMBLY code:
.def _DSP28x_GetSP.global __DSP28x_GetSP_DSP28x_GetSP: MOV AL, SP DEC AL ; /* need to decrement by 2 to */ DEC AL ; /* undo the increment by 2 that occurred when this function was called */ LRETR
.def _DSP28x_PutValueInAL.global __DSP28x_PutValueInAL_DSP28x_PutValueInAL: ; /* nothing required, as calling function will put value in accumulator AL */ LRETR
Here is the C code:
static Uint16 S_SavedSP;S_SavedSP = DSP28x_GetSP(); /* save SP; do NOT store this value on the stack, store as a static variable */asm (" MOV AL, #0x0004"); /* the Boot ROM default stack; SP is a 16-bit pointer */asm (" MOV SP, AL"); /* after this instruction, SP will point to UNSECURE M0 memory at address 0x0004 */(*Device_cal)(); /* this function is located in UNSECURE Boot ROM */DSP28x_PutValueInAL (S_SavedSP); /* this puts S_SavedSP in AL */asm (" MOV SP, AL"); /* restore SP; put AL in SP */
awesome. I was assuming that would happen, its tricky to come up with some thing like that without testing.
Does the above fix the problem with Device_cal () call-ability from Secure memory?
Yes, this fixes the problem of calling Device_cal from Secure memory.
Thanks for your help!
Thanks Eric.Appreciate you for sharing the details and the 'stack-switch' code. We will get the documents and collateral updated accordingly.Best RegardsSantosh