/*
 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 *    conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 *    of conditions and the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _LOS_PROCESS_PRI_H
#define _LOS_PROCESS_PRI_H

#include "los_task_pri.h"
#include "los_sem_pri.h"
#include "los_process.h"
#include "los_vm_map.h"
#if (LOSCFG_KERNEL_LITEIPC == YES)
#include "hm_liteipc.h"
#endif
#ifdef LOSCFG_SECURITY_CAPABILITY
#include "capability_type.h"
#endif
#ifdef LOSCFG_SECURITY_VID
#include "vid_type.h"
#endif

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */

#define OS_PCB_NAME_LEN OS_TCB_NAME_LEN

#ifdef LOSCFG_SECURITY_CAPABILITY
#define OS_GROUPS_NUMBER_MAX 256

typedef struct {
    UINT32  userID;
    UINT32  effUserID;
    UINT32  gid;
    UINT32  effGid;
    UINT32  groupNumber;
    UINT32  groups[1];
} User;
#endif

typedef struct {
    UINT32      groupID;         /**< Process group ID is the PID of the process that created the group */
    LOS_DL_LIST processList;     /**< List of processes under this process group */
    LOS_DL_LIST exitProcessList; /**< List of closed processes (zombie processes) under this group */
    LOS_DL_LIST groupList;       /**< Process group list */
} ProcessGroup;

typedef struct ProcessCB {
    CHAR                 processName[OS_PCB_NAME_LEN]; /**< Process name */
    UINT32               processID;                    /**< Process ID */
    UINT16               processStatus;                /**< [15:4] Process Status; [3:0] The number of threads currently
                                                            running in the process */
    UINT16               priority;                     /**< Process priority */
    UINT16               consoleID;                    /**< The console id of task belongs  */
    UINT16               processMode;                  /**< Kernel Mode:0; User Mode:1; */
    UINT16               readyTaskNum;                 /**< The number of ready tasks in the current process */
    UINT32               parentProcessID;              /**< Parent process ID */
    UINT32               exitCode;                     /**< Process exit status */
    LOS_DL_LIST          pendList;                     /**< Block list to which the process belongs */
    LOS_DL_LIST          childrenList;                 /**< Children process list */
    LOS_DL_LIST          exitChildList;                /**< Exit children process list */
    LOS_DL_LIST          siblingList;                  /**< Linkage in parent's children list */
    ProcessGroup         *group;                       /**< Process group to which a process belongs */
    LOS_DL_LIST          subordinateGroupList;         /**< Linkage in group list */
    UINT32               threadGroupID;                /**< Which thread group , is the main thread ID of the process */
    LOS_DL_LIST          threadSiblingList;            /**< List of threads under this process */
    volatile UINT32      threadNumber; /**< Number of threads alive under this process */
    UINT32               threadCount;  /**< Total number of threads created under this process */
    LOS_DL_LIST          waitList;     /**< The process holds the waitLits to support wait/waitpid */
#if (LOSCFG_KERNEL_SMP == YES)
    UINT32               timerCpu;     /**< CPU core number of this task is delayed or pended */
#endif
    UINTPTR              sigHandler;   /**< Signal handler */
    sigset_t             sigShare;     /**< Signal share bit */
#if (LOSCFG_KERNEL_LITEIPC == YES)
    ProcIpcInfo          ipcInfo;      /**< Memory pool for lite ipc */
#endif
    LosVmSpace           *vmSpace;     /**< VMM space for processes */
#ifdef LOSCFG_FS_VFS
    struct files_struct  *files;       /**< Files held by the process */
#endif
    timer_t              timerID;      /**< ITimer */

#ifdef LOSCFG_SECURITY_CAPABILITY
    User                *user;
    UINT32              capability;
#endif
#ifdef LOSCFG_SECURITY_VID
    TimerIdMap           timerIdMap;
#endif
#ifdef LOSCFG_DRIVERS_TZDRIVER
    struct file          *execFile;   /**< Exec bin of the process */
#endif
    mode_t               umask;
#ifdef LOSCFG_KERNEL_CPUP
    OsCpupBase           processCpup; /**< Process cpu usage */
#endif
} LosProcessCB;

#define CLONE_VM       0x00000100
#define CLONE_FS       0x00000200
#define CLONE_FILES    0x00000400
#define CLONE_SIGHAND  0x00000800
#define CLONE_PTRACE   0x00002000
#define CLONE_VFORK    0x00004000
#define CLONE_PARENT   0x00008000
#define CLONE_THREAD   0x00010000

#define OS_PCB_FROM_PID(processID) (((LosProcessCB *)g_processCBArray) + (processID))
#define OS_PCB_FROM_SIBLIST(ptr)   LOS_DL_LIST_ENTRY((ptr), LosProcessCB, siblingList)
#define OS_PCB_FROM_PENDLIST(ptr)  LOS_DL_LIST_ENTRY((ptr), LosProcessCB, pendList)

/**
 * @ingroup los_process
 * Flag that indicates the process or process control block status.
 *
 * The process is created but does not participate in scheduling.
 */
#define OS_PROCESS_STATUS_INIT           0x0010U

/**
 * @ingroup los_process
 * Flag that indicates the process or process control block status.
 *
 * The process is ready.
 */
#define OS_PROCESS_STATUS_READY          0x0020U

/**
 * @ingroup los_process
 * Flag that indicates the process or process control block status.
 *
 * The process is running.
 */
#define OS_PROCESS_STATUS_RUNNING        0x0040U

/**
 * @ingroup los_process
 * Flag that indicates the process or process control block status.
 *
 * The process is pending
 */
#define OS_PROCESS_STATUS_PENDING       0x0080U

/**
 * @ingroup los_process
 * Flag that indicates the process or process control block status.
 *
 * The process is run out but the resources occupied by the process are not recovered.
 */
#define OS_PROCESS_STATUS_ZOMBIES        0x100U

/**
 * @ingroup los_process
 * Flag that indicates the process or process control block status.
 *
 * The number of task currently running under the process, it only works with multiple cores.
 */
#define OS_PROCESS_RUNTASK_COUNT_MASK    0x000FU

/**
 * @ingroup los_process
 * Flag that indicates the process or process control block status.
 *
 * The process status mask.
 */
#define OS_PROCESS_STATUS_MASK           0xFFF0U

/**
 * @ingroup los_process
 * Flag that indicates the process or process control block status.
 *
 * The process status equal this is process control block unused,
 * coexisting with OS_PROCESS_STATUS_ZOMBIES means that the control block is not recovered.
 */
#define OS_PROCESS_FLAG_UNUSED            0x0200U

/**
 * @ingroup los_process
 * Flag that indicates the process or process control block status.
 *
 * The process has been call exit, it only works with multiple cores.
 */
#define OS_PROCESS_FLAG_EXIT              0x0400U

/**
 * @ingroup los_process
 * Flag that indicates the process or process control block status.
 *
 * The process is the leader of the process group.
 */
#define OS_PROCESS_FLAG_GROUP_LEADER      0x0800U

/**
 * @ingroup los_process
 * Flag that indicates the process or process control block status.
 *
 * The process has performed the exec operation.
 */
#define OS_PROCESS_FLAG_ALREADY_EXEC      0x1000U

/**
 * @ingroup los_process
 * Flag that indicates the process or process control block status.
 *
 * The process is dying or already dying.
 */
#define OS_PROCESS_STATUS_INACTIVE       (OS_PROCESS_FLAG_EXIT | OS_PROCESS_STATUS_ZOMBIES)

/**
 * @ingroup los_process
 * Used to check if the process control block is unused.
 */
STATIC INLINE BOOL OsProcessIsUnused(const LosProcessCB *processCB)
{
    return ((processCB->processStatus & OS_PROCESS_FLAG_UNUSED) != 0);
}

/**
 * @ingroup los_process
 * Used to check if the process is inactive.
 */
STATIC INLINE BOOL OsProcessIsInactive(const LosProcessCB *processCB)
{
    return ((processCB->processStatus & (OS_PROCESS_FLAG_UNUSED | OS_PROCESS_STATUS_INACTIVE)) != 0);
}

/**
 * @ingroup los_process
 * Used to check if the process is dead.
 */
STATIC INLINE BOOL OsProcessIsDead(const LosProcessCB *processCB)
{
    return ((processCB->processStatus & (OS_PROCESS_FLAG_UNUSED | OS_PROCESS_STATUS_ZOMBIES)) != 0);
}

/**
 * @ingroup los_process
 * The highest priority of a kernel mode process.
 */
#define OS_PROCESS_PRIORITY_HIGHEST      0

/**
 * @ingroup los_process
 * The lowest priority of a kernel mode process
 */
#define OS_PROCESS_PRIORITY_LOWEST       31

/**
 * @ingroup los_process
 * The highest priority of a user mode process.
 */
#define OS_USER_PROCESS_PRIORITY_HIGHEST 10

/**
 * @ingroup los_process
 * The lowest priority of a user mode process
 */
#define OS_USER_PROCESS_PRIORITY_LOWEST  OS_PROCESS_PRIORITY_LOWEST

/**
 * @ingroup los_process
 * User state root process default priority
 */
#define OS_PROCESS_USERINIT_PRIORITY     28

#define OS_GET_PROCESS_STATUS(status) ((UINT16)((UINT16)(status) & OS_PROCESS_STATUS_MASK))
#define OS_PROCESS_GET_RUNTASK_COUNT(status) ((UINT16)(((UINT16)(status)) & OS_PROCESS_RUNTASK_COUNT_MASK))
#define OS_PROCESS_RUNTASK_COUNT_ADD(status) ((UINT16)(((UINT16)(status)) & OS_PROCESS_STATUS_MASK) | \
        ((OS_PROCESS_GET_RUNTASK_COUNT(status) + 1) & OS_PROCESS_RUNTASK_COUNT_MASK))
#define OS_PROCESS_RUNTASK_COUNT_DEC(status) ((UINT16)(((UINT16)(status)) & OS_PROCESS_STATUS_MASK) | \
        ((OS_PROCESS_GET_RUNTASK_COUNT(status) - 1) & OS_PROCESS_RUNTASK_COUNT_MASK))

#define OS_TASK_DEFAULT_STACK_SIZE      0x2000
#define OS_USER_TASK_SYSCALL_SATCK_SIZE 0x3000
#define OS_USER_TASK_STACK_SIZE         0x100000

#define OS_KERNEL_MODE 0x0U
#define OS_USER_MODE   0x1U
STATIC INLINE BOOL OsProcessIsUserMode(const LosProcessCB *processCB)
{
    return (processCB->processMode == OS_USER_MODE);
}

#define LOS_SCHED_NORMAL  0U
#define LOS_SCHED_FIFO    1U
#define LOS_SCHED_RR      2U
#define LOS_SCHED_IDLE    3U

#define LOS_PRIO_PROCESS  0U
#define LOS_PRIO_PGRP     1U
#define LOS_PRIO_USER     2U

#define OS_USER_PRIVILEGE_PROCESS_GROUP 1U
#define OS_KERNEL_PROCESS_GROUP         2U

/*
 * Process exit code
 * 31    15           8           7        0
 * |     | exit code  | core dump | signal |
 */
#define OS_PRO_EXIT_OK 0

STATIC INLINE VOID OsProcessExitCodeCoreDumpSet(LosProcessCB *processCB)
{
    processCB->exitCode |= 0x80U;
}

STATIC INLINE VOID OsProcessExitCodeSignalSet(LosProcessCB *processCB, UINT32 signal)
{
    processCB->exitCode |= signal & 0x7FU;
}

STATIC INLINE VOID OsProcessExitCodeSignalClear(LosProcessCB *processCB)
{
    processCB->exitCode &= (~0x7FU);
}

STATIC INLINE BOOL OsProcessExitCodeSignalIsSet(LosProcessCB *processCB)
{
    return (processCB->exitCode) & 0x7FU;
}

STATIC INLINE VOID OsProcessExitCodeSet(LosProcessCB *processCB, UINT32 code)
{
    processCB->exitCode |= ((code & 0x000000FFU) << 8U) & 0x0000FF00U; /* 8: Move 8 bits to the left, exitCode */
}

extern LosProcessCB *g_processCBArray;
extern UINT32 g_processMaxNum;

#define OS_PID_CHECK_INVALID(pid) (((UINT32)(pid)) >= g_processMaxNum)

STATIC INLINE BOOL OsProcessIDUserCheckInvalid(UINT32 pid)
{
    return ((pid >= g_processMaxNum) || (pid == 0));
}

STATIC INLINE LosProcessCB *OsCurrProcessGet(VOID)
{
    UINT32 intSave;

    intSave = LOS_IntLock();
    LosProcessCB *runProcess = (LosProcessCB *)OsPercpuGet()->runProcess;
    LOS_IntRestore(intSave);
    return runProcess;
}

STATIC INLINE VOID OsCurrProcessSet(const LosProcessCB *process)
{
    OsPercpuGet()->runProcess = (UINTPTR)process;
}

#ifdef LOSCFG_SECURITY_CAPABILITY
STATIC INLINE User *OsCurrUserGet(VOID)
{
    User *user = NULL;
    UINT32 intSave;

    intSave = LOS_IntLock();
    user = OsCurrProcessGet()->user;
    LOS_IntRestore(intSave);
    return user;
}
#endif

/*
 * return immediately if no child has exited.
 */
#define LOS_WAIT_WNOHANG   (1 << 0U)

/*
 * return if a child has stopped (but not traced via ptrace(2)).
 * Status for traced children which have stopped is provided even
 * if this option is not specified.
 */
#define LOS_WAIT_WUNTRACED (1 << 1U)

/*
 * return if a stopped child has been resumed by delivery of SIGCONT.
 * (For Linux-only options, see below.)
 */
#define LOS_WAIT_WCONTINUED (1 << 3U)

/*
 * Indicates that you are already in a wait state
 */
#define OS_PROCESS_WAIT     (1 << 15U)

/*
 * Wait for any child process to finish
 */
#define OS_PROCESS_WAIT_ANY OS_TASK_WAIT_ANYPROCESS

/*
 * Wait for the child process specified by the pid to finish
 */
#define OS_PROCESS_WAIT_PRO OS_TASK_WAIT_PROCESS

/*
 * Waits for any child process in the specified process group to finish.
 */
#define OS_PROCESS_WAIT_GID OS_TASK_WAIT_GID

#define OS_PROCESS_INFO_ALL 1
#define OS_PROCESS_DEFAULT_UMASK 0022

extern UINTPTR __user_init_entry;
extern UINTPTR __user_init_bss;
extern UINTPTR __user_init_end;
extern UINTPTR __user_init_load_addr;
extern UINT32 OsSystemProcessCreate(VOID);
extern VOID OsProcessCBRecyleToFree(VOID);
extern VOID OsProcessResourcesToFree(LosProcessCB *processCB);
extern VOID OsProcessExit(LosTaskCB *runTask, INT32 status);
extern UINT32 OsUserInitProcess(VOID);
extern VOID OsTaskSchedQueueDequeue(LosTaskCB *taskCB, UINT16 status);
extern VOID OsTaskSchedQueueEnqueue(LosTaskCB *taskCB, UINT16 status);
extern INT32 OsClone(UINT32 flags, UINTPTR sp, UINT32 size);
extern VOID OsWaitSignalToWakeProcess(LosProcessCB *processCB);
extern UINT32 OsExecRecycleAndInit(LosProcessCB *processCB, const CHAR *name,
                                   LosVmSpace *oldAspace, UINTPTR oldFiles);
extern UINT32 OsExecStart(const TSK_ENTRY_FUNC entry, UINTPTR sp, UINTPTR mapBase, UINT32 mapSize);
extern UINT32 OsSetProcessName(LosProcessCB *processCB, const CHAR *name);
extern INT32 OsSetProcessScheduler(INT32 which, INT32 pid, UINT16 prio, UINT16 policy);
extern INT32 OsGetProcessPriority(INT32 which, INT32 pid);
extern VOID *OsUserStackAlloc(UINT32 processID, UINT32 *size);
extern UINT32 OsGetUserInitProcessID(VOID);
extern UINT32 OsGetIdleProcessID(VOID);
extern INT32 OsSetProcessGroupID(UINT32 pid, UINT32 gid);
extern INT32 OsSetCurrProcessGroupID(UINT32 gid);
extern UINT32 OsGetKernelInitProcessID(VOID);
extern VOID OsSetSigHandler(UINTPTR addr);
extern UINTPTR OsGetSigHandler(VOID);
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */

#endif
