/**
 * @file       task.h
 * @brief      Find by task structure using forensic GAF in kernel space for driver
 * @author     Viacheslav Vovchenko (v.vovchenko@samsung.com)
 * @version    1.0
 * @date       Created Jun 30, 2016
 * @copyright  In Samsung Ukraine R&D Center (SURC) under a contract between
 * @copyright  LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine) and
 * @copyright  "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
 * @copyright  Copyright: (c) Samsung Electronics Co, Ltd 2016. All rights reserved.
**/

#ifndef PA_TZ_DRV_SRC_TASK_H_
#define PA_TZ_DRV_SRC_TASK_H_

#include "memory.h"
#include "pa_certificate.h"

/**
 * @brief state in task_struct, see sched.h.
 */
#define TASK_RUNNING          0x0000
#define TASK_INTERRUPTIBLE    0x0001
#define TASK_UNINTERRUPTIBLE  0x0002

enum {
  kMaxPaSignatureLength = PAGE_SIZE //!< Maximal PA signature length
};

/**
 * @brief Kernel structure for RbNode
 */
typedef struct {
#if defined(CONFIG_KERNEL_32)
  uint32_t  __rb_parent_color; //!< Color
#else
  uint64_t  __rb_parent_color; //!< Color
#endif
  KernelAddress rb_right;      //!< Right child
  KernelAddress rb_left;       //!< Left child
} RbNode;

/**
 * @brief Kernel structure for RbRoot
 */
typedef struct {
  KernelAddress rb_node;       //!< Root node
} RbRoot;

/**
 * @brief Kernel values for Task Integrity
 */
enum IntegrityValues {
  kIntegrityNone             = 0x00000000, //!< not authenticated
  kIntegrityPreload          = 0x33333333, //!< FIVE RSA
  kIntegrityPreloadWithSign  = 0xcccccccc, //!< FIVE RSA + trusted app (apk_signer or dex2oat)
  kIntegrityMixed            = 0x55555555, //!< FIVE HMAC
  kIntegrityMixedWithSign    = 0x5a5a5a5a, //!< FIVE HMAC + trusted app
  kIntegrityDmVerity         = 0xaaaaaaaa, //!< DMVERITY verified
  kIntegrityDmVerityWithSign = 0x3c3c3c3c, //!< DMVERITY verified + trusted app
  kIntegrityPending          = 0xffffffff  //!< Pending status from FIVE (response's not been obtained)
};

/**
 * @brief Structure to hold NWd view of proca certificate
 */
typedef struct {
  KernelAddress app_name; //!< Parsed application name for signature
  size_t app_name_size;   //!< Application name length
} KernelProcaCertificate;

/**
 * @brief PROCA identity structure
 */
typedef struct {
  size_t          certificate_size; //!< Size of certificate buffer
  KernelAddress   certificate;      //!< File certificate buffer
  KernelAddress   file;          //!< Kernel executable file struct ref
  KernelProcaCertificate parsed_cert; //!< Parsed certificate
} PaIdentity;

/**
 * @brief Common task structure
 */
typedef struct {
  KernelAddress virt;       //!< Start kernel virtual address
  unsigned int state;       //!< Process state
  unsigned int pid;         //!< Process ID
  KernelAddress mm;         //!< Memory management
  KernelAddress pgd;        //!< Page global directory
  KernelAddress mmap;       //!< Memory mapping
  uint32_t integrity;       //!< Flag integrity from FIVE (see IntegrityValues)
  PaCertificate_t *certificate;  //!< Certificate data is provided by PA signature
                                 //!< (must be free using FreeTaskInfo function)
  RbRoot mm_rb;             //!< Root node of VMA RbTree
  ProcessAddress vma_address;  //!< Vma address of mapped file which provided by PA certificate

  PaIdentity pa_identity;      //!< PROCA identity struct from task descriptor
} TaskInfo;

/**
 * @brief Free allocated resources
 * @details It must be call after using for to free previously allocated resources
 * @param [in] task Pointer to task structure
 */
void FreeTaskInfo(TaskInfo *task);

/**
 * @brief vm_flags in vm_area_struct, see mm_types.h.
 */
#define VM_NONE   (0x00000000)
#define VM_READ   (0x00000001)  /* currently active flags */
#define VM_WRITE  (0x00000002)
#define VM_EXEC   (0x00000004)
#define VM_SHARED (0x00000008)

/**
 * @brief Memory vma structure
 */
typedef struct vma_area {
  ProcessAddress vm_start; //!< Our start address within vm_mm
  ProcessAddress vm_end;   //!< The first byte after our end address within vm_mm
  KernelAddress vm_next;   //!< Next vma in list
  uint64_t vm_flags;       //!< Flags mapping
  KernelAddress vm_file;   //!< File we map to (can be NULL)
  RbNode vm_rb;            //!< RbNode of this VMA
} VmaInfo;

typedef enum {
  kEqual,
  kSmaller,
  kBigger,
  kNonEqual
} FindResult;

/**
 * @brief The signature type describes a common type of finding function inside VMA structure
 * @param [in] task Pointer to task structure
 * @param [in] vma Pointer to VMA structure
 * @param [in] param Pointer to param
 * @return ::FindResult
 */
typedef FindResult (*CustomFind)(const TaskInfo *task, const VmaInfo *vma,
                                 const void* param);

/**
 * @brief Check VMA contains the physical address of command buffer
 * @param [in] task Pointer to task structure
 * @param [in] vma Pointer to VMA structure
 * @param [in] param Pointer to physical address
 * @return ::FindResult
 */
FindResult CheckPhysicalCommandBuffer(const TaskInfo *task, const VmaInfo *vma,
                                      const void* param);

/**
 * @brief Find task with given PID
 * @param [in]  pid PID of needed task
 * @param [out] out_task Pointer to task struct which was found
 * @return ::PA_TZ_SUCCESS in case of success
 */
PaTzResult TaskFindByPid(uint32_t pid, TaskInfo *out_task);

/**
 * @brief Find task with given application name
 * @param [in]  app_name Application name of needed task (not null terminated)
 * @param [in]  app_name_len Application name length
 * @param [out] out_task Pointer to task struct which was found
 * @return ::PA_TZ_SUCCESS in case of success
 */
PaTzResult TaskFindByAppName(const char *app_name,
                             const size_t app_name_len,
                             TaskInfo *out_task);

/**
 * @brief Find VMA by condition which is set in overriding function.
 * Walking over all VMAs is linear (one by one).
 * It is applicable if we don't know user space virtual address.
 * @param [in] task Pointer to task structure
 * @param [in] custom_find Pointer to the overriding function
 * @param [in] param Pointer to input parameters for ptr_compare
 * @param [out] out_vma Pointer to vma structure which it was found in list vma
 * @return ::PA_TZ_SUCCESS in case of success, ::PA_TZ_GENERAL_ERROR
 */
PaTzResult TaskFindVmaLinear(const TaskInfo *task, const CustomFind custom_find,
                             const void *param, VmaInfo *out_vma);

/**
 * @brief Find VMA by condition which is set in overriding function.
 * Walking over all VMAs using RbTree. We should know user space virtual address
 * to use this method.
 * @param [in] task Pointer to task structure
 * @param [in] custom_find Pointer to the overriding function
 * @param [in] param Pointer to input parameters for ptr_compare
 * @param [out] out_vma Pointer to vma structure which it was found in list vma
 * @return ::PA_TZ_SUCCESS in case of success, ::PA_TZ_GENERAL_ERROR
 */
PaTzResult TaskFindVmaRbTree(const TaskInfo *task, const CustomFind custom_find,
                             const void *param, VmaInfo *out_vma);

/**
 * @brief Find VMA that has physical address region
 * @param [in] task Task structure
 * @param [in] address,size Physical address region
 * @param [out] out_vma Pointer to vma structure which it was found
 * @return ::PA_TZ_SUCCESS in case of success, ::PA_TZ_GENERAL_ERROR
 */
PaTzResult TaskFindVmaWithPhysicalMemory(const TaskInfo *task,
    PhysicalAddress address, size_t size, VmaInfo *out_vma);

/**
 * @brief Find VMA that has process virtual address
 * @param [in] task Task structure
 * @param [in] address Process virtual address
 * @param [out] out_vma Pointer to vma structure which it was found
 * @return ::PA_TZ_SUCCESS in case of success, ::PA_TZ_GENERAL_ERROR
 */
PaTzResult TaskFindVmaWithProcessAddress(const TaskInfo *task,
    ProcessAddress address, VmaInfo *out_vma);

#endif  // PA_TZ_DRV_SRC_TASK_H_
