/*
 * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Created in Samsung Ukraine R&D Center (SRK) under a contract between
 * LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine)
 * and "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
 */

/**
 * @file TzwSerialNumber.c
 * @brief Functionality to get public chip serial number, defined by each silicon provider.
 * @author Konstyantyn Volobuyev <k.volobuyev@samsung.com>
 * @date Created Jun 26, 2017
 */

#include "TzwSerialNumber.h"

#include "TigerMacroses.h"
#include "TzwString.h"

#if defined(TIGER_TZ_MODEL_BLOWFISH)
#include <driver/mem/phys.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#endif

#if defined(TIGER_TZ_MODEL_QCOM)
#include <qsee_core.h>
#endif

#define SIZE_4KB (4*1024)

extern const uint32_t PHY_ADDR;

TzwErrorCode_t tzwReadSerialNumber(TzwSerialNumber_t* apSerialNumber) {
    TIGER_CHECK_FUNCTION_ARGUMENT_RETURN(apSerialNumber != NULL);

#if TIGER_TZ_MODEL_BLOWFISH
    uint32_t offset = PHY_ADDR & (SIZE_4KB - 1);
    const size_t regionSize = sizeof(TzwSerialNumber_t); // SFR region size

    int physFd = open(PHYS_DEV_NAME, O_RDWR);
    if (-1 == physFd) {
        LOG_E("open() failed, err = %d \n", errno);
        return TEE_ERROR_GENERIC;
    }

    void* vaddr = mmap(NULL, regionSize, PROT_READ | PROT_WRITE,
                       MAP_SHARED | MAP_PHYS_NON_CACHED,
                       physFd, PHY_ADDR & ~(SIZE_4KB - 1));
    if (vaddr == MAP_FAILED) {
        LOG_E("mmap() failed, err = %d\n", errno);
        return TEE_ERROR_GENERIC;
    }

    vaddr = (void*) (((unsigned long) vaddr) | offset);

    tzwMemMove(apSerialNumber, vaddr, regionSize);

    return TEE_SUCCESS;
#else
        *apSerialNumber = (TzwSerialNumber_t) qsee_read_serial_num();
#endif
    logByteArrayHex((uint8_t*) apSerialNumber, sizeof(TzwSerialNumber_t), "Serial Number");
    return TEE_SUCCESS;
}
