/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed 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.
 */

#ifndef _NANOHUB_NANOHUB_H_
#define _NANOHUB_NANOHUB_H_

#include <inttypes.h>
#include <nanohub/aes.h>

/* this file is collection of nanohub-related definitions shared between multiple parties,
 * including but not limited to: HAL, Kernel, utilities, nanohub FW
 * it provides minimum details on nanohub implementation, necessary to reliably identify it, and
 * generate/parse compatible images
 */

#define NANOHUB_OS_PATCH_LEVEL  0x0000

#define NANOHUB_VENDOR_GOOGLE      UINT64_C(0x476F6F676C) // "Googl"
#define NANOHUB_VENDOR_STMICRO     UINT64_C(0x53544d6963) // "STMic"
#define NANOHUB_VENDOR_INVENSENSE  UINT64_C(0x496E76656E) // "Inven"

#define NANOAPP_SIGNED_FLAG    0x1  // contents is signed with one or more signature block(s)
#define NANOAPP_ENCRYPTED_FLAG 0x2  // contents is encrypted with exactly one encryption key

#define NANOAPP_AOSP_MAGIC (((uint32_t)'N' <<  0) | ((uint32_t)'A' <<  8) | ((uint32_t)'N' << 16) | ((uint32_t)'O' << 24))
#define NANOAPP_FW_MAGIC (((uint32_t)'N' <<  0) | ((uint32_t)'B' <<  8) | ((uint32_t)'I' << 16) | ((uint32_t)'N' << 24))
#define GOOGLE_LAYOUT_MAGIC (((uint32_t)'G' <<  0) | ((uint32_t)'o' <<  8) | ((uint32_t)'o' << 16) | ((uint32_t)'g' << 24))

#define APP_ID_ANY                 UINT64_C(0xFFFFFFFFFFFFFFFF)
#define APP_VENDOR_ANY             UINT64_C(0xFFFFFFFFFF)
#define APP_VENDOR_SHF             (24)
#define APP_SEQ_ID_ANY             UINT32_C(0xFFFFFF)
#define APP_ID_GET_VENDOR(appid)   ((appid) >> APP_VENDOR_SHF)
#define APP_ID_GET_SEQ_ID(appid)   ((appid) & APP_SEQ_ID_ANY)
#define APP_ID_MAKE(vendor, app)   ((((uint64_t)(vendor)) << APP_VENDOR_SHF) | ((app) & APP_SEQ_ID_ANY))

#ifndef CONTEXT_HUB_H
// The binary format below is in little endian format; borrowed from CONTEXT_HUB_H
struct nano_app_binary_t {
    uint32_t header_version;       // 0x1 for this version
    uint32_t magic;                // "NANO"
    uint64_t app_id;               // App Id contains vendor id
    uint32_t app_version;          // Version of the app
    uint32_t flags;                // Signed, encrypted
    uint64_t hw_hub_type;          // which hub type is this compiled for
    uint8_t  chre_api_major;       // Which CHRE API version this is compiled for
    uint8_t  chre_api_minor;
    uint8_t  reserved[6];          // Should be all zeroes
    uint8_t  custom_binary[0];     // start of custom binary data
};

#endif

struct HostMsgHdr {
    uint32_t eventId;
    uint64_t appId;
    uint8_t len;
} __attribute__((packed));

struct HostMsgHdrChreV10 {
    uint32_t eventId;
    uint64_t appId;
    uint8_t len;
    uint32_t appEventId;
} __attribute__((packed));

struct HostMsgHdrChre {
    uint32_t eventId;
    uint64_t appId;
    uint8_t len;
    uint32_t appEventId;
    uint16_t endpoint;
} __attribute__((packed));

// we translate AOSP header into FW header: this header is in LE format
// please maintain natural alignment for every field (matters to Intel; otherwise is has to be declared as packed)
struct FwCommonHdr {
    uint32_t magic;         // external & internal: NANOAPP_FW_MAGIC
    uint16_t fwVer;         // external & internal: set to 1; header version
    uint16_t fwFlags;       // external & internal: class : EXTERNAL/INTERNAL, EXEC/NOEXEC, APP/KERNEL/EEDATA/...
    uint64_t appId;         // external: copy from AOSP header; internal: defined locally
    uint32_t appVer;        // external: copy from AOSP header; internal: defined locally
    uint8_t  payInfoType;   // external: copy ImageLayout::payload; internal: LAYOUT_APP
    uint8_t  payInfoSize;   // sizeof(PayloadInfo) for this payload type
    uint8_t  chreApiMajor;  // Chre Api Major Version (or 0xFF for non-chre nanoapps)
    uint8_t  chreApiMinor;  // Chre Api Minor Version (or 0xFF for non-chre nanoapps)
};

struct SectInfo {
    uint32_t data_start;
    uint32_t data_end;
    uint32_t data_data;

    uint32_t bss_start;
    uint32_t bss_end;

    uint32_t got_start;
    uint32_t got_end;
    uint32_t rel_start;
    uint32_t rel_end;
};

// this is platform-invariant version of struct TaskFuncs (from seos.h)
struct AppVectors {
    uint32_t init;
    uint32_t end;
    uint32_t handle;
};

#define FLASH_RELOC_OFFSET offsetof(struct AppHdr, sect)        // used by appSupport.c at run time
#define BINARY_RELOC_OFFSET offsetof(struct BinHdr, sect)       // used by postprocess at build time

struct BinCommonHdr {
    uint32_t magic;
    uint32_t appVer;
};

// binary nanoapp image (.bin) produced by objcopy starts with this binary header (LE)
struct BinHdr {
    struct BinCommonHdr hdr;
    struct SectInfo     sect;
    struct AppVectors   vec;
};

// FW nanoapp image starts with this binary header (LE) in flash
struct AppHdr {
    struct FwCommonHdr hdr;
    struct SectInfo    sect;
    struct AppVectors  vec;
};

struct AppSecSignHdr {
    uint32_t appDataLen;
};

struct AppSecEncrHdr {
    uint64_t keyID;
    uint32_t dataLen;
    uint32_t IV[AES_BLOCK_WORDS];
};

#define LAYOUT_APP  1
#define LAYOUT_KEY  2
#define LAYOUT_OS   3
#define LAYOUT_DATA 4

struct ImageLayout {
    uint32_t magic;     // Layout ID: (GOOGLE_LAYOUT_MAGIC for this implementation)
    uint8_t  version;   // layout version
    uint8_t  payload;   // type of payload: APP, SECRET KEY, OS IMAGE, USER DATA, ...
    uint16_t flags;     // layout flags: extra options for certain payload types; payload-specific
};

// .napp image starts with this binary header (LE)
// it is optionally followed by AppSecSignHdr and/or AppSecEncrHdr
// all of the above are included in signing hash, but never encrypted
// encryption (if enabled) starts immediately after those
struct ImageHeader {
    struct nano_app_binary_t aosp;
    struct ImageLayout   layout;
};

#define CKK_RSA 0x00
#define CKK_AES 0x1F

#define CKO_PUBLIC_KEY  0x02
#define CKO_PRIVATE_KEY 0x03
#define CKO_SECRET_KEY  0x04

// flags
#define FL_KI_ENFORCE_ID 0x0001  // if set, size, key_type, obj_type must be valid

// payload header format: LAYOUT_KEY
struct KeyInfo {
    union {
        struct {
            uint16_t id;        // arbitrary number, != 0, equivalent of PKCS#11 name
            uint16_t flags;     // key flags (additional PKCS#11 attrs, unused for now; must be 0)
            uint16_t size;      // key size in bits
            uint8_t  key_type;  // 8 LSB of PKCS-11 CKK_<KEY TYPE>
            uint8_t  obj_type;  // 8 LSB of PKCS-11 CKO_<OBJ TYPE>
        };
        uint64_t data;          // complete 64-bit key-id, unique within this APP namespace (complete id is <APP_ID | KEY_INFO> 128 bits)
    };
};

#define AES_KEY_ID(_id) (((struct KeyInfo){ .key_type = CKK_AES, .obj_type = CKO_SECRET_KEY, .size = 256, .id = (_id) }).data)

// payload header format: LAYOUT_APP
struct AppInfo {
    struct SectInfo   sect;
    struct AppVectors vec;
};

#define OS_UPDT_MARKER_INPROGRESS     0xFF
#define OS_UPDT_MARKER_DOWNLOADED     0xFE
#define OS_UPDT_MARKER_VERIFIED       0xF0
#define OS_UPDT_MARKER_INVALID        0x00
#define OS_UPDT_MAGIC                 "Nanohub OS" //11 bytes incl terminator

// payload header format: LAYOUT_OS
struct OsUpdateHdr {
    char magic[11];
    uint8_t marker; //OS_UPDT_MARKER_INPROGRESS -> OS_UPDT_MARKER_DOWNLOADED -> OS_UPDT_MARKER_VERIFIED / OS_UPDT_INVALID
    uint32_t size;  //does not include the mandatory signature (using device key) that follows
};

// payload header format: LAYOUT_DATA
struct DataInfo {
    uint32_t id;
    uint32_t size;
};

#endif // _NANOHUB_NANOHUB_H_