/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*        http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/

#include <xs_base.h>
#include <stdint.h>
#include "svc_handle.h"
#include <xs_service.h>
#include <xs_ktask.h>

static void SvcDispatch(void) __attribute__ ((naked, no_instrument_function));
static void SvcDispatch(void)
{
  __asm__ __volatile__
    (
        " mov r12, sp\n"
        " sub r12, r12, #36\n"
        " and r12, r12, #7\n"
        " add r12, r12, #36\n"
        " sub sp,  sp, r12\n"
        " str r0,  [sp, #0]\n" 
        " str r1,  [sp, #4]\n" 
        " str r2,  [sp, #8]\n" 
        " str r3,  [sp, #12]\n"
        " str r4,  [sp, #16]\n"          
        " str r5,  [sp, #20]\n"
        " str r6,  [sp, #24]\n"
        " str lr,  [sp, #28]\n"
        " str r12, [sp, #32]\n"
        " mov r0,  sp\n"
        " ldr r12, =SvcHandle\n"
        " blx r12\n"
        " ldr lr,  [sp, #28]\n"
        " ldr r2,  [sp, #32]\n"
        " add sp, sp, r2\n"
        " svc 1"
    );
}


void _svcall(uintptr_t* contex)
{
    uint32_t svc_number;
    KTaskDescriptorType tid;

    tid = GetKTaskDescriptor();
    svc_number = ((char *)contex[REG_INT_PC ])[-2];
    switch (svc_number) {
    case 0:  //svc handler 
        tid->task_dync_sched_member.svc_return = contex[REG_INT_PC];
        tid->task_dync_sched_member.isolation_status = 1;
        contex[REG_INT_PC] = (uint32_t)SvcDispatch & ~1;
        break;
    case 1:   // svc return 
        contex[REG_INT_PC] = tid->task_dync_sched_member.svc_return;
        tid->task_dync_sched_member.isolation_status = 0;
        break;
    default:
        KPrintf("unsurport svc call number :%d\n",svc_number);
        break;
    }
}

uintptr_t SvcHandle(uintptr_t *sp)
{
    uint32_t service_num = 0;
    service_num = ((uint32_t) sp[0]);  //r0 
    uint8_t param_num =  g_service_table[service_num].param_num;
    uintptr_t *param = sp + 1;
    return g_service_table[service_num].fun(service_num,param,param_num) ;
}


uint32_t GetTaskPrivilege(void){
    uint32_t unprivileg = 0;
    struct TaskDescriptor *task = GetKTaskDescriptor();
    if (task->task_dync_sched_member.isolation_flag == 1 && task->task_dync_sched_member.isolation_status == 0) {
       unprivileg = 1;
    } else {
       unprivileg = 0;
    }

    return unprivileg;
}
