blob: eaa6142f0d79f66344691acde89b1bfb2328ff28 [file] [log] [blame]
/* exc-syscall-c-handler.c - SYSCALL instruction XTOS handler in C */
/*
* Copyright (c) 1999-2006 Tensilica Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <xtensa/config/core.h>
#include "xtos-internal.h"
UserFrame* _xtos_p_syscall_handler( UserFrame *uf /*, int cause */ );
/*
* User vector mode exception handler for the SYSCALL cause.
*
* NOTE: This function is NOT used by default. The assembly-level
* handler version of this function is normally used instead.
* This function is provided as an example only.
* To use it instead of the default assembly-level version,
* you can register it using _xtos_set_exception_handler().
* For example:
*
* #include <xtensa/xtruntime.h>
* #include <xtensa/corebits.h>
* _xtos_set_exception_handler( EXCCAUSE_SYSCALL,
* (_xtos_handler)_xtos_p_syscall_handler );
*/
UserFrame* _xtos_p_syscall_handler( UserFrame *uf /*, int cause */ )
{
uf->pc += 3; /* skip SYSCALL instruction */
#if XCHAL_HAVE_LOOPS
/*
* If the SYSCALL instruction was the last instruction in the body
* of a zero-overhead loop, then we should decrement the loop count
* and resume execution at the head of the loop.
*/
if( uf->pc == uf->lend && uf->lcount != 0 )
{
uf->lcount--;
uf->pc = uf->lbeg;
}
#endif /*XCHAL_HAVE_LOOP*/
/*
* Handle the system call.
*
* A typical SYSCALL handler uses code such as this to handle
* the system call, where the operation to be done is determined
* by the a2 register. Parameters to the operation are typically
* passed in address registers a3 and up. Results are typically
* returned in a2. (See Linux source code for example.)
*/
switch( uf->a2 ) {
case 0:
/* Spill register windows to the stack. */
/*
* The Xtensa architecture reserves the a2==0 condition as a request
* to flush (spill) register windows to the stack. The current exception
* handling implementation never spills windows to the stack (it used
* to always spill, not true anymore), so we have to spill windows
* explicitly here. (Note that xthal_window_spill() spills windows
* that are part of the interrupt handling context, that don't
* really need to be spilled, but that's harmless other than being
* less than optimally efficient.)
*
* Also, be nice to programmers here. If they're
* building for Call0 ABI, silently do nothing for
* syscall a2==0.
*/
#ifdef __XTENSA_WINDOWED_ABI__
xthal_window_spill();
#endif
break;
default:
uf->a2 = -1 /*ENOSYS*/; /* system call not supported */
break;
}
return( uf );
}