* arch/misoc/src/minerva/minerva_swint.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <string.h>
#include <syscall.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/sched.h>
#include <arch/irq.h>
#include "signal/signal.h"
#include "minerva.h"
* Private Functions
****************************************************************************/
* Name: dispatch_syscall
*
* Description:
* Call the stub function corresponding to the system call.
*
****************************************************************************/
#ifdef CONFIG_BUILD_KERNEL
static void dispatch_syscall(void) naked_function;
static void dispatch_syscall(void)
{
#error "Missing logic"
* ARM
*/
}
#endif
* Public Functions
****************************************************************************/
* Name: minerva_swint
*
* Description:
* This is software interrupt exception handler that performs context
* switching and manages system calls
*
****************************************************************************/
int minerva_swint(int irq, void *context, void *arg)
{
uint32_t *regs = (uint32_t *) context;
DEBUGASSERT(regs != NULL && regs == up_current_regs());
* command and REG_A1-6 = variable number of arguments depending on the
* system call.
*/
#ifdef CONFIG_DEBUG_SYSCALL_INFO
svcinfo("Entry: regs: %p cmd: %d\n", regs, regs[REG_A0]);
minerva_registerdump(regs);
#endif
switch (regs[REG_A0])
{
* int up_saveusercontext(void *saveregs);
* At this point, the following values are saved in context: A0 =
* SYS_save_context A1 = saveregs A2 = saveregs. In this case, we
* save the context registers to the save register area referenced by
* the saved contents of R5.
*/
case SYS_save_context:
{
DEBUGASSERT(regs[REG_A1] != 0);
minerva_copystate((uint32_t *) regs[REG_A1], regs);
}
break;
* up_fullcontextrestore(uint32_t *restoreregs) noreturn_function; At
* this point, the following values are saved in context: A0 =
* SYS_restore_context A1 = restoreregs In this case, we simply need to
* set g_current_regs to restore register area referenced in the saved
* R1. context == g_current_regs is the normal exception return. By
* setting g_current_regs = context[R1], we force the return to the
* saved context referenced in $a1.
*/
case SYS_restore_context:
{
DEBUGASSERT(regs[REG_A1] != 0);
up_set_current_regs((uint32_t *)regs[REG_A1]);
}
break;
* misoc_switchcontext(uint32_t *saveregs, uint32_t *restoreregs);
* At this point, the following values are saved in context: A0 =
* SYS_switch_context A1 = saveregs A2 = restoreregs. In this case, we
* save the context registers to the save register area referenced by
* the saved contents of R5 and then set g_current_regs to the save
* register area referenced by the saved contents of R6.
*/
case SYS_switch_context:
{
DEBUGASSERT(regs[REG_A1] != 0 && regs[REG_A2] != 0);
minerva_copystate((uint32_t *) regs[REG_A1], regs);
up_set_current_regs((uint32_t *)regs[REG_A2]);
}
break;
* up_sycall_return(void); At this point, the following values are
* saved in context: A0 = SYS_syscall_return We need to restore the
* saved return address and return in unprivileged thread mode.
*/
#ifdef CONFIG_BUILD_KERNEL
case SYS_syscall_return:
{
struct tcb_s *rtcb = this_task();
int index = (int)rtcb->xcp.nsyscalls - 1;
DEBUGASSERT(index >= 0);
* original mode.
*/
up_current_regs()[REG_CSR_MEPC] =
rtcb->xcp.syscall[index].sysreturn;
#error "Missing logic -- need to restore the original mode"
rtcb->xcp.nsyscalls = index;
* the system call.
*/
atomic_and(&rtcb->flags, ~TCB_FLAG_SYSCALL);
(void)nxsig_unmask_pendingsignal();
}
break;
#endif
case SYS_assert_handler:
{
_assert((const char *)regs[REG_A1], (int)regs[REG_A2],
(const char *)regs[REG_A3], (void *)running_regs(), false);
}
break;
* as a standalone kernel with a system call interface, then all of the
* additional system calls must be handled as in the default case.
*/
default:
{
#ifdef CONFIG_BUILD_KERNEL
struct tcb_s *rtcb = this_task();
int index = rtcb->xcp.nsyscalls;
DEBUGASSERT(up_current_regs()[REG_A0] < SYS_maxsyscall);
* address. We cannot yet handle nested system calls.
*/
DEBUGASSERT(index < CONFIG_SYS_NNEST);
*/
rtcb->xcpsyscall[index].sysreturn = regs[REG_CSR_MEPC];
#error "Missing logic -- Need to save mode"
rtcb->xcp.nsyscalls = index + 1;
regs[REG_CSR_MEPC] = (uint32_t) dispatch_syscall;
#error "Missing logic -- Need to set privileged mode"
up_current_regs()[REG_A0] -= CONFIG_SYS_RESERVED;
atomic_or(&rtcb->flags, TCB_FLAG_SYSCALL);
#else
svcerr("ERROR: Bad SYS call: %d\n", regs[REG_A0]);
#endif
}
break;
}
* switch
*/
#ifdef CONFIG_DEBUG_SYSCALL_INFO
if (regs != up_current_regs())
{
svcinfo("SWInt Return: Context switch!\n");
minerva_registerdump(up_current_regs());
}
else
{
svcinfo("SWInt Return: %d\n", regs[REG_A0]);
}
#endif
return OK;
}