Hi,
Does anyone know how can I determine the gcc compiler not to insert
any code before my function's prologue?
This is how the function begins, I am interested if I can determine
the compiler to generate code after the last instruction, the mov
instruction should be after the stmdb instruction.
604: e1a05000 mov r5, r0
608: ef0000d3 svc 0x000000d3
60c: e96d50ff stmdb sp!, {r0, r1, r2, r3, r4, r5, r6, r7, ip, lr}^
Thank you!
Lucian
It might help if you could describe what you want to achieve, to avoid
getting the right answer to the wrong question. Also you should show the
significant part of the source code and a little more of the resulting
code.
Hi,
I'm writing some system calls for a custom OS, just my free time
project and for fun.
UINT8 LRTOS_u8MutexRelease(tstMutex *pMutex)
{
604: e1a05000 mov r5, r0
UINT8 u8ReturnValue = nE_N_OK;
UINT8 u8TaskPrio = 0;
/* Switch to SVC mode and disable interrupts */
CPU_vSwitchToSvc();
608: ef0000d3 svc 0x000000d3
/* Storing the USR context used to execute the current system call */
CPU_vStoreUsrContext();
60c: e96d50ff stmdb sp!, {r0, r1, r2, r3, r4, r5, r6, r7, ip,
lr}^
The idea is that the last 2 instructions are the prologue of my system
calls, a task switch can occur inside this naked function or system
call. I need the compiler to recognize the first 2 functions as being
the prologue of the naked function so that it never places anything
before the last 2 instructions.
Thank you!
Lucian
If you want to avoid having code placed before your manually generated
prologue, then do not place any code there yourself. And be sure to make
the asm statement(s) in the prologue "volatile".
So move the variables initialization beyond the prologue. And in C99
mode you can use:
UINT8 LRTOS_u8MutexRelease(tstMutex *pMutex)
{
/* Switch to SVC mode and disable interrupts */
CPU_vSwitchToSvc();
/* Storing the USR context used to execute the current system call */
CPU_vStoreUsrContext();
UINT8 u8ReturnValue = nE_N_OK;
UINT8 u8TaskPrio = 0;
... body ...
}
Hi,
The assembler instructions are all volatile ;-). The problem persists
after reordering. It seems I can't make the compiler recognize my
prologue, would have helped a #pragma or something.
Thank you!
Lucian
IMHO there is no way to declare code as prologue, other than hacking
GCC. Since the compiler choses to move the parameter into some different
register before your asms, you may have the redesign the way you are
dealing with the OS functions. The way you are doing it is asking for
trouble. Even when when you find a way to get the right code tomorrow,
the next compiler release could break your concept again.
I'd guess that there is no safe way to implement parameterized "naked"
functions having a nontrivial body and your prologue/epilogue.
Yeah, the way I handle the functios is a little over the hand but I
don't want to have too much overhead, that is why I use this method.
Another solution is to build another function vHack and do something
like this
UINT8 LRTOS_u8MutexRelease(tstMutex *pMutex)
{
/* Switch to SVC mode and disable interrupts */
CPU_vSwitchToSvc();
6f8: ef0000d3 svc 0x000000d3
/* Storing the USR context used to execute the current system call */
CPU_vStoreUsrContext();
6fc: e96d50ff stmdb sp!, {r0, r1, r2, r3, r4, r5, r6, r7, ip,
lr}^
/* Prepare the scheduler call, since it will be called after the task
is set in sleep mode */
CPU_vPrepareSchedulerCall();
700: e59f3010 ldr r3, [pc, #16] ; 718
<LRTOS_u8MutexRelease+0x20>
704: e583d000 str sp, [r3]
vHack(pMutex);
708: ebffffbd bl 604 <vHack>
/* Restoring the USR context used to execute the current system call
*/
CPU_vRestoreUsrContext();
70c: e8fd50ff ldm sp!, {r0, r1, r2, r3, r4, r5, r6, r7, ip,
lr}^
/* Switch back to USR mode */
CPU_vSwitchToUsr();
710: ef000010 svc 0x00000010
/* Function return, since it is a naked function it has no return */
CPU_vFuncReturn();
714: e1a0f00e mov pc, lr
This will add additional stack operations and I don't like it that
much.
P.S. The concept will not be broken as long as acps is implemented and
the naked attribute is kept, hopefully it won't be broken.
This is only version likely to survive compiler upgrades, although you
still could face a surprise someday. "naked" functions are a hack,
implemented for very rare situations, so you are very much on your own
when using them.
The problem is that I can't really build my sys calls so easy without
having the naked attribute since I need to know where the user context
is saved before entering the system function.
If I let the compiler build it's own prologue I endup with system
calls that save 4 registers, system calls that save 5 and so on, it
would not be so easy to do a task(process) switch.
If I go on the aproach with system calls called like the switch SVC
with each system call and it's ID I get into trouble since I have to go
in a very switch instruction to search for the system call.
What's the reason for all this? Why do you switch to SVC mode instead of
SYS mode? SVC mode has it's own R13/SP, so unless you copy the caller's
SP you likely need a separate kernel stack for each task. Unless all
those kernel functions are non-blocking. And if the kernel runs on the
caller's stack, why in SVC mode?
BTW: Disabling interrupts as part of each and every kernel function this
early makes interrupt latency suffer quite a bit.
Ar Lc wrote:
> since I need to know where the user context
> is saved before entering the system function.
Why?
While this is the approach of big operating systems like Unix having
separate kernel stacks, the much simpler RTOS kernels usually run the
kernel functions on the application stack and defer saving full register
context to the time a context switch is actually done. This is also
quite a bit faster, since in most occurrences of OS calls a context
switch is not actually done.
Each task has it's own stack and one SVC stack, I can acces the stack
pointer of the USR mode and I can use it when I need to switch tasks.
I do have to rethink a little bit the structure and the idea, maybe I
need to change some parts, normally the interrupt latency is not that
affected since the functions are really short(including the scheduler).
I will have to rethink some things ;-).
P.S. You are right, I'll have to rethink the system calls, the problem
is that in my case if I release the mutex and there is a higher priority
task waiting for the mutex I'll have to do the context switch and place
the lower priority task in the ready table.
Ar Lc wrote:
> Each task has it's own stack and one SVC stack
Vague language warning. One SVC stack for each task or one SVC stack
common to all tasks?
In the case of one SVC (kernel) stack for each task: Where exactly do
you need to know the exakt USR context? The context switch needs the
kernel context at time of switch, to know where to continue when
switching back.
In the case of one common SVC stack: IMHO this only works when each and
every kernel function is nonblocking. A rare design decision nowadays.
Sorry was not my intention(I'm not really an english native speaker, my
apologies),
Yes, one common SVC stack in the entire system, one IRQ stack(since the
controller I work on is an ARM9), one FIQ stack, one ABT stack, and as
many USR stacks as needed(dependeing on the number of tasks).
At the moment I have to know the contex before the system call, it's not
a good idea at the moment. I'll need to rethink some things, it's just a
weekend learning experience.
Thanks for the constructive discussion. I analyzed the situation and I
will start adapting the OS to what you said.
Thank you!
Lucian
Reply
Entering an e-mail address is optional. If you want to receive reply notifications by e-mail, please log in.
Rules — please read before posting
- Post long source code as attachment, not in the text
- Posting advertisements is forbidden.
Formatting options
- [c]C code[/c]
- [code]code in other languages, ASCII drawings[/code]
- [math]formula (LaTeX syntax)[/math]
|