blob: a02d02ab026139f41ded68737ad1e99a67c16ded [file]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2021 MediaTek Inc.
*/
#include "tz_playready.h"
#ifdef TZ_PLAYREADY_SECURETIME_SUPPORT
uint32_t TEE_update_pr_time_intee(KREE_SESSION_HANDLE session)
{
union MTEEC_PARAM param[4];
uint32_t paramTypes;
int ret = TZ_RESULT_SUCCESS;
uint32_t file_result = PR_TIME_FILE_OK_SIGN;
struct file *file = NULL;
UINT64 u8Offset = 0;
int err = -ENODEV;
struct rtc_time tm;
DRM_UINT64 time_count64;
unsigned long time_count;
struct rtc_device *rtc;
struct TZ_JG_SECURECLOCK_INFO secure_time;
DRM_UINT64 cur_counter;
rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
if (rtc == NULL) {
pr_warn("%s: unable to open rtc device (%s)\n",
__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
goto err_open;
}
paramTypes = TZ_ParamTypes3(TZPT_MEM_INPUT,
TZPT_MEM_INPUT,
TZPT_VALUE_OUTPUT);
param[0].mem.buffer = (void *) &secure_time;
param[0].mem.size = sizeof(struct TZ_JG_SECURECLOCK_INFO);
param[1].mem.buffer = (void *) &cur_counter;
param[1].mem.size = sizeof(DRM_UINT64);
file = FILE_Open(PR_TIME_FILE_SAVE_PATH, O_RDWR, 0700);
if (file) {
FILE_Read(file, (void *) &secure_time,
sizeof(struct TZ_JG_SECURECLOCK_INFO), &u8Offset);
filp_close(file, NULL);
} else {
file_result = NO_SECURETD_FILE;
goto err_read;
}
err = rtc_read_time(rtc, &tm);
if (err) {
dev_err(rtc->dev.parent,
"hctosys: unable to read the hardware clock\n");
goto err_read;
}
err = rtc_valid_tm(&tm);
if (err) {
dev_err(rtc->dev.parent, "hctosys: invalid date/time\n");
goto err_invalid;
}
rtc_tm_to_time(&tm, &time_count);
time_count64 = (DRM_UINT64)time_count;
memcpy((char *) &cur_counter, (char *) &time_count64,
sizeof(DRM_UINT64));
ret = KREE_TeeServiceCall(session, TZCMD_PLAYREADY_SET_CURRENT_COUNTER,
paramTypes, param);
if (ret != TZ_RESULT_SUCCESS)
pr_warn("ServiceCall TZCMD_PLAYREADY_SET_CURRENT_COUNTER error %d\n",
ret);
if (param[2].value.a == PR_TIME_FILE_ERROR_SIGN) {
file_result = PR_TIME_FILE_ERROR_SIGN;
pr_warn("ServiceCall TZCMD_PLAYREADY_SET_CURRENT_COUNTER file_result %d\n",
file_result);
} else if (param[2].value.a == PR_TIME_FILE_OK_SIGN) {
file_result = PR_TIME_FILE_OK_SIGN;
pr_warn("ServiceCall TZCMD_PLAYREADY_SET_CURRENT_COUNTER file_result %d\n",
file_result);
}
err_invalid:
err_read:
rtc_class_close(rtc);
err_open:
if (file_result == PR_TIME_FILE_OK_SIGN)
return ret;
else
return file_result;
}
uint32_t TEE_update_pr_time_infile(KREE_SESSION_HANDLE session)
{
union MTEEC_PARAM param[4];
uint32_t paramTypes;
int ret = TZ_RESULT_SUCCESS;
struct file *file = NULL;
UINT64 u8Offset = 0;
struct TZ_JG_SECURECLOCK_INFO secure_time;
paramTypes = TZ_ParamTypes3(TZPT_MEM_OUTPUT, TZPT_VALUE_INPUT,
TZPT_VALUE_OUTPUT);
param[0].mem.buffer = (void *) &secure_time;
param[0].mem.size = sizeof(struct TZ_JG_SECURECLOCK_INFO);
param[1].value.a = 0;
ret = KREE_TeeServiceCall(session, TZCMD_PLAYREADY_GET_CURRENT_COUNTER,
paramTypes, param);
if (ret != TZ_RESULT_SUCCESS) {
pr_warn("ServiceCall error %d\n", ret);
goto tz_error;
}
file = FILE_Open(PR_TIME_FILE_SAVE_PATH, O_RDWR|O_CREAT, 0700);
if (file) {
FILE_Write(file, (void *) &secure_time,
sizeof(struct TZ_JG_SECURECLOCK_INFO), &u8Offset);
filp_close(file, NULL);
} else {
pr_warn("FILE_Open PR_TIME_FILE_SAVE_PATH return NULL\n");
}
tz_error:
return ret;
}
uint32_t TEE_Icnt_pr_time(KREE_SESSION_HANDLE session)
{
union MTEEC_PARAM param[4];
uint32_t paramTypes;
int ret = TZ_RESULT_SUCCESS;
unsigned long time_count = 1392967151;
struct rtc_device *rtc = NULL;
struct rtc_time tm;
int err = -ENODEV;
struct TM_PR secure_TM;
paramTypes = TZ_ParamTypes2(TZPT_VALUE_INPUT, TZPT_MEM_OUTPUT);
param[1].mem.buffer = (void *) &secure_TM;
param[1].mem.size = sizeof(struct TM_PR);
rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
if (rtc == NULL) {
pr_warn("%s: unable to open rtc device (%s)\n",
__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
goto err_open;
}
err = rtc_read_time(rtc, &tm);
if (err) {
dev_err(rtc->dev.parent,
"hctosys: unable to read the hardware clock\n");
goto err_read;
}
err = rtc_valid_tm(&tm);
if (err) {
dev_err(rtc->dev.parent,
"hctosys: invalid date/time\n");
goto err_invalid;
}
rtc_tm_to_time(&tm, &time_count);
#if 0
pr_debug("securetime increase result: %d %d %d %d %d %d %d\n",
tm.tm_yday, tm.tm_year, tm.tm_mon, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
#endif
param[0].value.a = time_count;
ret = KREE_TeeServiceCall(session, TZCMD_PLAYREADY_INC_CURRENT_COUNTER,
paramTypes, param);
if (ret != TZ_RESULT_SUCCESS)
pr_warn("ServiceCall error %d\n", ret);
#if 0
pr_debug("securetime increase result: %d %d %d %d %d %d %d\n"
, secure_TM.tm_yday
, secure_TM.tm_year, secure_TM.tm_mon, secure_TM.tm_mday
, secure_TM.tm_hour, secure_TM.tm_min, secure_TM.tm_sec);
#endif
err_read:
err_invalid:
rtc_class_close(rtc);
err_open:
return ret;
}
#define THREAD_COUNT_FREQ 10
#define THREAD_SAVEFILE_VALUE (1*60*60)
static int check_count;
static KREE_SESSION_HANDLE icnt_session;
int update_securetime_thread(void *data)
{
int ret;
unsigned int update_ret = 0;
uint32_t nsec = THREAD_COUNT_FREQ;
ret = KREE_CreateSession(TZ_TA_PLAYREADY_UUID, &icnt_session);
if (ret != TZ_RESULT_SUCCESS) {
pr_warn("CreateSession error %d\n", ret);
return 1;
}
set_freezable();
schedule_timeout_interruptible(HZ * nsec);
update_ret = TEE_update_pr_time_intee(icnt_session);
if (update_ret == NO_SECURETD_FILE ||
update_ret == PR_TIME_FILE_ERROR_SIGN) {
TEE_update_pr_time_infile(icnt_session);
TEE_update_pr_time_intee(icnt_session);
}
for (;;) {
if (kthread_should_stop())
break;
if (try_to_freeze())
continue;
schedule_timeout_interruptible(HZ * nsec);
if (icnt_session) {
TEE_Icnt_pr_time(icnt_session);
check_count += THREAD_COUNT_FREQ;
if ((check_count < 0) ||
(check_count > THREAD_SAVEFILE_VALUE)) {
TEE_update_pr_time_infile(icnt_session);
check_count = 0;
}
}
}
ret = KREE_CloseSession(icnt_session);
if (ret != TZ_RESULT_SUCCESS)
pr_warn("CloseSession error %d\n", ret);
return 0;
}
#endif