diff --git a/Android.mk b/Android.mk index 4b76f6fe3d..6a97a75490 100644 --- a/Android.mk +++ b/Android.mk @@ -23,7 +23,7 @@ SSG_SRC_FILES := \ $(wildcard $(LOCAL_PATH)/*/*) \ $(wildcard $(LOCAL_PATH)/*/*/*) \ $(wildcard $(LOCAL_PATH)/*/*/*/*) - +LOCAL_MODULE_DDK_BUILD := true # This is set once per LOCAL_PATH, not per (kernel) module KBUILD_OPTIONS := SSG_ROOT=$(SEC_KERNEL_DIR) KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) diff --git a/BUILD.bazel b/BUILD.bazel index 641ae44bd8..57070d82f1 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -14,28 +14,41 @@ ddk_headers( "include/linux/ITrustedCameraDriver.h", "include/linux/CTrustedCameraDriver.h", "linux/misc/qseecom_kernel.h", - "linux/misc/qseecom_priv.h" + "linux/misc/qseecom_priv.h", ]), - includes = ["include/linux", "linux", "include"] + includes = [ + "include", + "include/linux", + "linux", + ], ) ddk_headers( name = "securemsm_kernel_headers", hdrs = [ "linux/misc/qseecom_kernel.h", - "linux/misc/qseecom_priv.h" + "linux/misc/qseecom_priv.h", ], - includes = ["linux"] + includes = ["linux"], ) + ddk_headers( name = "hdcp_qseecom_dlkm", hdrs = glob([ + ":smcinvoke_kernel_headers", "linux/*.h", - "linux/misc/qseecom_kernel.h", - "hdcp_qseecom/*.h", - "config/*.h" + "include/linux/*h", + "include/smci/uid/*h", + "include/smci/interface/*h", + "linux/misc/*.h", + "config/*.h", ]), - includes = [".","linux","config"] + includes = [ + ".", + "config", + "include", + "linux", + ], ) ddk_headers( diff --git a/Kbuild b/Kbuild index aebc072887..b9375a36ce 100644 --- a/Kbuild +++ b/Kbuild @@ -35,7 +35,7 @@ obj-$(CONFIG_CRYPTO_DEV_QCRYPTO) += qcrypto-msm_dlkm.o qcrypto-msm_dlkm-objs := crypto-qti/qcrypto.o obj-$(CONFIG_HDCP_QSEECOM) += hdcp_qseecom_dlkm.o -hdcp_qseecom_dlkm-objs := hdcp/hdcp_qseecom.o +hdcp_qseecom_dlkm-objs := hdcp/hdcp_main.o hdcp/hdcp_smcinvoke.o hdcp/hdcp_qseecom.o obj-$(CONFIG_HW_RANDOM_MSM_LEGACY) += qrng_dlkm.o qrng_dlkm-objs := qrng/msm_rng.o diff --git a/hdcp/hdcp1.h b/hdcp/hdcp1.h new file mode 100644 index 0000000000..03addb36bd --- /dev/null +++ b/hdcp/hdcp1.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#pragma once +// AUTOGENERATED FILE: DO NOT EDIT + +#include +#include "smcinvoke_object.h" + +#define HDCP1_PROVISION 0 +#define HDCP1_VERIFY 1 +#define HDCP1_SET_ENCRYPTION 2 +#define HDCP1_SET_ENCRYPTION_V2 3 +#define HDCP1_SET_KEY 4 +#define HDCP1_SET_KEY_V2 5 +#define HDCP1_SET_MODE 6 + +static inline int32_t hdcp1_release(struct Object self) +{ + return Object_invoke(self, Object_OP_release, 0, 0); +} + +static inline int32_t hdcp1_retain(struct Object self) +{ + return Object_invoke(self, Object_OP_retain, 0, 0); +} + +static inline int32_t hdcp1_provision(struct Object self, uint32_t keyFormat_val, + const void *key_ptr, size_t key_len, + const void *dps_ptr, size_t dps_len) +{ + union ObjectArg a[3] = {{{0, 0}}}; + + a[0].b = (struct ObjectBuf) {&keyFormat_val, sizeof(uint32_t)}; + a[1].bi = (struct ObjectBufIn) {key_ptr, key_len * 1}; + a[2].bi = (struct ObjectBufIn) {dps_ptr, dps_len * 1}; + + return Object_invoke(self, HDCP1_PROVISION, a, + ObjectCounts_pack(3, 0, 0, 0)); +} + +static inline int32_t hdcp1_verify(struct Object self, uint32_t deviceType_val) +{ + union ObjectArg a[1] = {{{0, 0}}}; + + a[0].b = (struct ObjectBuf) {&deviceType_val, sizeof(uint32_t)}; + + return Object_invoke(self, HDCP1_VERIFY, a, + ObjectCounts_pack(1, 0, 0, 0)); +} + +static inline int32_t hdcp1_set_encryption(struct Object self, uint32_t enable_val) +{ + union ObjectArg a[1] = {{{0, 0}}}; + + a[0].b = (struct ObjectBuf) {&enable_val, sizeof(uint32_t)}; + + return Object_invoke(self, HDCP1_SET_ENCRYPTION, a, + ObjectCounts_pack(1, 0, 0, 0)); +} + +static inline int32_t hdcp1_set_encryption_v2(struct Object self, uint32_t enable_val, + uint32_t deviceType_val) +{ + union ObjectArg a[1] = {{{0, 0}}}; + struct { + uint32_t m_enable; + uint32_t m_deviceType; + } i; + + a[0].b = (struct ObjectBuf) {&i, 8}; + i.m_enable = enable_val; + i.m_deviceType = deviceType_val; + + return Object_invoke(self, HDCP1_SET_ENCRYPTION_V2, a, + ObjectCounts_pack(1, 0, 0, 0)); +} + +static inline int32_t hdcp1_set_key(struct Object self, void *ksv_ptr, size_t ksv_len, + size_t *ksv_lenout) +{ + union ObjectArg a[1] = {{{0, 0}}}; + int32_t result = 0; + + a[0].b = (struct ObjectBuf) {ksv_ptr, ksv_len * 1}; + + result = Object_invoke(self, HDCP1_SET_KEY, a, + ObjectCounts_pack(0, 1, 0, 0)); + + *ksv_lenout = a[0].b.size / 1; + + return result; +} + +static inline int32_t hdcp1_set_key_v2(struct Object self, void *ksv_ptr, + size_t ksv_len, size_t *ksv_lenout, + uint32_t deviceType_val) +{ + union ObjectArg a[2] = {{{0, 0}}}; + int32_t result = 0; + + a[1].b = (struct ObjectBuf) {ksv_ptr, ksv_len * 1}; + a[0].b = (struct ObjectBuf) {&deviceType_val, sizeof(uint32_t)}; + + result = Object_invoke(self, HDCP1_SET_KEY_V2, a, + ObjectCounts_pack(1, 1, 0, 0)); + + *ksv_lenout = a[1].b.size / 1; + + return result; +} + +static inline int32_t hdcp1_set_mode(struct Object self, int32_t mode_val) +{ + union ObjectArg a[1] = {{{0, 0}}}; + + a[0].b = (struct ObjectBuf) {&mode_val, sizeof(int32_t)}; + + return Object_invoke(self, HDCP1_SET_MODE, a, + ObjectCounts_pack(1, 0, 0, 0)); +} diff --git a/hdcp/hdcp1_ops.h b/hdcp/hdcp1_ops.h new file mode 100644 index 0000000000..fb311a7ca8 --- /dev/null +++ b/hdcp/hdcp1_ops.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#pragma once +// AUTOGENERATED FILE: DO NOT EDIT + +#include +#include "smcinvoke_object.h" + +#define IHDCP1OPS_NOTIFY_TOPOLOGY_CHANGE 0 + +static inline int32_t hdcp1_ops_release(struct Object self) +{ + return Object_invoke(self, Object_OP_release, 0, 0); +} + +static inline int32_t hdcp1_ops_retain(struct Object self) +{ + return Object_invoke(self, Object_OP_retain, 0, 0); +} + +static inline int32_t hdcp1_ops_notify_topology_change(struct Object self) +{ + return Object_invoke(self, IHDCP1OPS_NOTIFY_TOPOLOGY_CHANGE, 0, 0); +} diff --git a/hdcp/hdcp2p2.h b/hdcp/hdcp2p2.h new file mode 100644 index 0000000000..71400f076a --- /dev/null +++ b/hdcp/hdcp2p2.h @@ -0,0 +1,303 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#pragma once +// AUTOGENERATED FILE: DO NOT EDIT + +#include +#include "smcinvoke_object.h" + +#define HDCP2P2_PROVISION_KEY 0 +#define HDCP2P2_VERIFY_KEY 1 +#define HDCP2P2_TX_INIT 2 +#define HDCP2P2_TX_DEINIT 3 +#define HDCP2P2_RCVD_MSG 4 +#define HDCP2P2_SEND_TIMEOUT 5 +#define HDCP2P2_SET_HW_KEY 6 +#define HDCP2P2_QUERY_STREAM_TYPE 7 +#define HDCP2P2_INIT 8 +#define HDCP2P2_DEINIT 9 +#define HDCP2P2_VERSION 10 +#define HDCP2P2_SESSION_INIT 11 +#define HDCP2P2_SESSION_DEINIT 12 +#define HDCP2P2_START_AUTH 13 +#define HDCP2P2_SESSION_OPEN_STREAM 14 +#define HDCP2P2_SESSION_CLOSE_STREAM 15 +#define HDCP2P2_FORCE_ENCRYPTION 16 +#define HDCP2P2_DELETE_PAIRING_INFO 17 + +static inline int32_t hdcp2p2_release(struct Object self) +{ + return Object_invoke(self, Object_OP_release, 0, 0); +} + +static inline int32_t hdcp2p2_retain(struct Object self) +{ + return Object_invoke(self, Object_OP_retain, 0, 0); +} + +static inline int32_t hdcp2p2_provision_key(struct Object self, const void *key_ptr, + size_t key_len, + const void *dps_ptr, + size_t dps_len) +{ + union ObjectArg a[2] = {{{0, 0}}}; + + a[0].bi = (struct ObjectBufIn) {key_ptr, key_len * 1}; + a[1].bi = (struct ObjectBufIn) {dps_ptr, dps_len * 1}; + + return Object_invoke(self, HDCP2P2_PROVISION_KEY, a, + ObjectCounts_pack(2, 0, 0, 0)); +} + +static inline int32_t hdcp2p2_verify_key(struct Object self) +{ + return Object_invoke(self, HDCP2P2_VERIFY_KEY, 0, 0); +} + +static inline int32_t hdcp2p2_tx_init(struct Object self, uint32_t sessionid_val, + uint32_t *ctxhandle_ptr) +{ + union ObjectArg a[2] = {{{0, 0}}}; + + a[0].b = (struct ObjectBuf) {&sessionid_val, sizeof(uint32_t)}; + a[1].b = (struct ObjectBuf) {ctxhandle_ptr, sizeof(uint32_t)}; + + return Object_invoke(self, HDCP2P2_TX_INIT, a, + ObjectCounts_pack(1, 1, 0, 0)); +} + +static inline int32_t hdcp2p2_tx_deinit(struct Object self, uint32_t ctxhandle_val) +{ + union ObjectArg a[1] = {{{0, 0}}}; + + a[0].b = (struct ObjectBuf) {&ctxhandle_val, sizeof(uint32_t)}; + + return Object_invoke(self, HDCP2P2_TX_DEINIT, a, + ObjectCounts_pack(1, 0, 0, 0)); +} + +static inline int32_t hdcp2p2_rcvd_msg( + struct Object self, const void *reqMsg_ptr, size_t reqMsg_len, + uint32_t ctxhandle_val, void *resMsg_ptr, size_t resMsg_len, + size_t *resMsg_lenout, uint32_t *timeout_ptr, uint32_t *flag_ptr) +{ + union ObjectArg a[4] = {{{0, 0}}}; + int32_t result = 0; + struct { + uint32_t m_timeout; + uint32_t m_flag; + } o; + + a[2].b = (struct ObjectBuf) {&o, 8}; + a[0].bi = (struct ObjectBufIn) {reqMsg_ptr, reqMsg_len * 1}; + a[1].b = (struct ObjectBuf) {&ctxhandle_val, sizeof(uint32_t)}; + a[3].b = (struct ObjectBuf) {resMsg_ptr, resMsg_len * 1}; + + result = Object_invoke(self, HDCP2P2_RCVD_MSG, a, + ObjectCounts_pack(2, 2, 0, 0)); + + *resMsg_lenout = a[3].b.size / 1; + *timeout_ptr = o.m_timeout; + *flag_ptr = o.m_flag; + + return result; +} + +static inline int32_t hdcp2p2_send_timeout(struct Object self, uint32_t ctxhandle_val, + void *resMsg_ptr, size_t resMsg_len, + size_t *resMsg_lenout, + uint32_t *timeout_ptr) +{ + union ObjectArg a[3] = {{{0, 0}}}; + int32_t result = 0; + + a[0].b = (struct ObjectBuf) {&ctxhandle_val, sizeof(uint32_t)}; + a[1].b = (struct ObjectBuf) {resMsg_ptr, resMsg_len * 1}; + a[2].b = (struct ObjectBuf) {timeout_ptr, sizeof(uint32_t)}; + + result = Object_invoke(self, HDCP2P2_SEND_TIMEOUT, a, + ObjectCounts_pack(1, 2, 0, 0)); + + *resMsg_lenout = a[1].b.size / 1; + + return result; +} + +static inline int32_t hdcp2p2_set_hw_key(struct Object self, uint32_t ctxhandle_val) +{ + union ObjectArg a[1] = {{{0, 0}}}; + + a[0].b = (struct ObjectBuf) {&ctxhandle_val, sizeof(uint32_t)}; + + return Object_invoke(self, HDCP2P2_SET_HW_KEY, a, + ObjectCounts_pack(1, 0, 0, 0)); +} + +static inline int32_t hdcp2p2_query_stream_type( + struct Object self, uint32_t ctxhandle_val, void *resMsg_ptr, size_t resMsg_len, + size_t *resMsg_lenout, uint32_t *timeout_ptr) +{ + union ObjectArg a[3] = {{{0, 0}}}; + int32_t result = 0; + + a[0].b = (struct ObjectBuf) {&ctxhandle_val, sizeof(uint32_t)}; + a[1].b = (struct ObjectBuf) {resMsg_ptr, resMsg_len * 1}; + a[2].b = (struct ObjectBuf) {timeout_ptr, sizeof(uint32_t)}; + + result = Object_invoke(self, HDCP2P2_QUERY_STREAM_TYPE, a, + ObjectCounts_pack(1, 2, 0, 0)); + + *resMsg_lenout = a[1].b.size / 1; + + return result; +} + +static inline int32_t hdcp2p2_init(struct Object self, uint32_t clientVersion_val, + uint32_t *appversion_ptr) +{ + union ObjectArg a[2] = {{{0, 0}}}; + + a[0].b = (struct ObjectBuf) {&clientVersion_val, sizeof(uint32_t)}; + a[1].b = (struct ObjectBuf) {appversion_ptr, sizeof(uint32_t)}; + + return Object_invoke(self, HDCP2P2_INIT, a, + ObjectCounts_pack(1, 1, 0, 0)); +} + +static inline int32_t hdcp2p2_deinit(struct Object self) +{ + return Object_invoke(self, HDCP2P2_DEINIT, 0, 0); +} + +static inline int32_t hdcp2p2_version(struct Object self, uint32_t *appversion_ptr) +{ + union ObjectArg a[1] = {{{0, 0}}}; + + a[0].b = (struct ObjectBuf) {appversion_ptr, sizeof(uint32_t)}; + + return Object_invoke(self, HDCP2P2_VERSION, a, + ObjectCounts_pack(0, 1, 0, 0)); +} + +static inline int32_t hdcp2p2_session_init(struct Object self, uint32_t deviceId_val, + uint32_t *sessionId_ptr) +{ + union ObjectArg a[2] = {{{0, 0}}}; + + a[0].b = (struct ObjectBuf) {&deviceId_val, sizeof(uint32_t)}; + a[1].b = (struct ObjectBuf) {sessionId_ptr, sizeof(uint32_t)}; + + return Object_invoke(self, HDCP2P2_SESSION_INIT, a, + ObjectCounts_pack(1, 1, 0, 0)); +} + +static inline int32_t hdcp2p2_session_deinit(struct Object self, + uint32_t sessionId_val) +{ + union ObjectArg a[1] = {{{0, 0}}}; + + a[0].b = (struct ObjectBuf) {&sessionId_val, sizeof(uint32_t)}; + + return Object_invoke(self, HDCP2P2_SESSION_DEINIT, a, + ObjectCounts_pack(1, 0, 0, 0)); +} + +static inline int32_t hdcp2p2_start_auth(struct Object self, uint32_t ctxhandle_val, + void *resMsg_ptr, size_t resMsg_len, + size_t *resMsg_lenout, + uint32_t *timeout_ptr, + uint32_t *flag_ptr, + uint32_t *tzctxhandle_ptr) +{ + union ObjectArg a[3] = {{{0, 0}}}; + int32_t result = 0; + struct { + uint32_t m_timeout; + uint32_t m_flag; + uint32_t m_tzctxhandle; + } o; + + a[1].b = (struct ObjectBuf) {&o, 12}; + a[0].b = (struct ObjectBuf) {&ctxhandle_val, sizeof(uint32_t)}; + a[2].b = (struct ObjectBuf) {resMsg_ptr, resMsg_len * 1}; + + result = Object_invoke(self, HDCP2P2_START_AUTH, a, + ObjectCounts_pack(1, 2, 0, 0)); + + *resMsg_lenout = a[2].b.size / 1; + *timeout_ptr = o.m_timeout; + *flag_ptr = o.m_flag; + *tzctxhandle_ptr = o.m_tzctxhandle; + + return result; +} + +static inline int32_t hdcp2p2_session_open_stream(struct Object self, + uint32_t sessionid_val, + uint32_t vcpayloadid_val, + uint32_t stream_number_val, + uint32_t streamMediaType_val, + uint32_t *resStreamId_ptr) +{ + union ObjectArg a[2] = {{{0, 0}}}; + struct { + uint32_t m_sessionid; + uint32_t m_vcpayloadid; + uint32_t m_stream_number; + uint32_t m_streamMediaType; + } i; + + a[0].b = (struct ObjectBuf) {&i, 16}; + i.m_sessionid = sessionid_val; + i.m_vcpayloadid = vcpayloadid_val; + i.m_stream_number = stream_number_val; + i.m_streamMediaType = streamMediaType_val; + a[1].b = (struct ObjectBuf) {resStreamId_ptr, sizeof(uint32_t)}; + + return Object_invoke(self, HDCP2P2_SESSION_OPEN_STREAM, a, + ObjectCounts_pack(1, 1, 0, 0)); +} + +static inline int32_t hdcp2p2_session_close_stream(struct Object self, + uint32_t sessionid_val, + uint32_t streamId_val) +{ + union ObjectArg a[1] = {{{0, 0}}}; + struct { + uint32_t m_sessionid; + uint32_t m_streamId; + } i; + + a[0].b = (struct ObjectBuf) {&i, 8}; + i.m_sessionid = sessionid_val; + i.m_streamId = streamId_val; + + return Object_invoke(self, HDCP2P2_SESSION_CLOSE_STREAM, a, + ObjectCounts_pack(1, 0, 0, 0)); +} + +static inline int32_t hdcp2p2_force_encryption(struct Object self, + uint32_t ctxhandle_val, + uint32_t enable_val) +{ + union ObjectArg a[1] = {{{0, 0}}}; + struct { + uint32_t m_ctxhandle; + uint32_t m_enable; + } i; + + a[0].b = (struct ObjectBuf) {&i, 8}; + i.m_ctxhandle = ctxhandle_val; + i.m_enable = enable_val; + + return Object_invoke(self, HDCP2P2_FORCE_ENCRYPTION, a, + ObjectCounts_pack(1, 0, 0, 0)); +} + +static inline int32_t hdcp2p2_delete_pairing_info(struct Object self) +{ + return Object_invoke(self, HDCP2P2_DELETE_PAIRING_INFO, 0, 0); +} diff --git a/hdcp/hdcp_main.c b/hdcp/hdcp_main.c new file mode 100644 index 0000000000..0fb781982c --- /dev/null +++ b/hdcp/hdcp_main.c @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "hdcp_main.h" +#include "hdcp_qseecom.h" +#include "hdcp_smcinvoke.h" + +struct hdcp_ta_interface ta_interface; +static DEFINE_MUTEX(hdcp1_mutex_g); +static DEFINE_MUTEX(hdcp2_mutex_g); + +void select_interface(bool use_smcinvoke) +{ + if (use_smcinvoke) { + ta_interface.trusted_app_hdcp1_init = &hdcp1_init_smcinvoke; + ta_interface.trusted_app_hdcp1_feature_supported = &hdcp1_feature_supported_smcinvoke; + ta_interface.trusted_app_hdcp1_set_enc = &hdcp1_set_enc_smcinvoke; + ta_interface.trusted_app_hdcp1_ops_notify = &hdcp1_ops_notify_smcinvoke; + ta_interface.trusted_app_hdcp1_start = &hdcp1_start_smcinvoke; + ta_interface.trusted_app_hdcp1_stop = &hdcp1_stop_smcinvoke; + ta_interface.trusted_app_hdcp2_init = &hdcp2_init_smcinvoke; + ta_interface.trusted_app_hdcp2_deinit = &hdcp2_deinit_smcinvoke; + ta_interface.trusted_app_hdcp2_app_start = &hdcp2_app_start_smcinvoke; + ta_interface.trusted_app_hdcp2_app_start_auth = &hdcp2_app_start_auth_smcinvoke; + ta_interface.trusted_app_hdcp2_app_process_msg = &hdcp2_app_process_msg_smcinvoke; + ta_interface.trusted_app_hdcp2_app_enable_encryption = &hdcp2_app_enable_encryption_smcinvoke; + ta_interface.trusted_app_hdcp2_app_query_stream = &hdcp2_app_query_stream_smcinvoke; + ta_interface.trusted_app_hdcp2_app_stop = &hdcp2_app_stop_smcinvoke; + ta_interface.trusted_app_hdcp2_feature_supported = &hdcp2_feature_supported_smcinvoke; + ta_interface.trusted_app_hdcp2_force_encryption = &hdcp2_force_encryption_smcinvoke; + ta_interface.trusted_app_hdcp2_open_stream = &hdcp2_open_stream_smcinvoke; + ta_interface.trusted_app_hdcp2_close_stream = &hdcp2_close_stream_smcinvoke; + ta_interface.trusted_app_hdcp2_update_app_data = &hdcp2_update_app_data_smcinvoke; + } else { + ta_interface.trusted_app_hdcp1_init = &hdcp1_init_qseecom; + ta_interface.trusted_app_hdcp1_feature_supported = &hdcp1_feature_supported_qseecom; + ta_interface.trusted_app_hdcp1_set_enc = &hdcp1_set_enc_qseecom; + ta_interface.trusted_app_hdcp1_ops_notify = &hdcp1_ops_notify_qseecom; + ta_interface.trusted_app_hdcp1_start = &hdcp1_start_qseecom; + ta_interface.trusted_app_hdcp1_stop = &hdcp1_stop_qseecom; + ta_interface.trusted_app_hdcp2_init = &hdcp2_init_qseecom; + ta_interface.trusted_app_hdcp2_deinit = &hdcp2_deinit_qseecom; + ta_interface.trusted_app_hdcp2_app_start = &hdcp2_app_start_qseecom; + ta_interface.trusted_app_hdcp2_app_start_auth = &hdcp2_app_start_auth_qseecom; + ta_interface.trusted_app_hdcp2_app_process_msg = &hdcp2_app_process_msg_qseecom; + ta_interface.trusted_app_hdcp2_app_enable_encryption = &hdcp2_app_enable_encryption_qseecom; + ta_interface.trusted_app_hdcp2_app_query_stream = &hdcp2_app_query_stream_qseecom; + ta_interface.trusted_app_hdcp2_app_stop = &hdcp2_app_stop_qseecom; + ta_interface.trusted_app_hdcp2_feature_supported = &hdcp2_feature_supported_qseecom; + ta_interface.trusted_app_hdcp2_force_encryption = &hdcp2_force_encryption_qseecom; + ta_interface.trusted_app_hdcp2_open_stream = &hdcp2_open_stream_qseecom; + ta_interface.trusted_app_hdcp2_close_stream = &hdcp2_close_stream_qseecom; + ta_interface.trusted_app_hdcp2_update_app_data = &hdcp2_update_app_data_qseecom; + } +} + +int hdcp1_count_ones(u8 *array, u8 len) +{ + int i, j, count = 0; + + for (i = 0; i < len; i++) + for (j = 0; j < 8; j++) + count += (((array[i] >> j) & 0x1) ? 1 : 0); + + return count; +} + + + +int hdcp1_validate_aksv(u32 aksv_msb, u32 aksv_lsb) +{ + int const number_of_ones = 20; + u8 aksv[5] = {0}; + + pr_debug("AKSV=%02x%08x\n", aksv_msb, aksv_lsb); + + aksv[0] = aksv_lsb & 0xFF; + aksv[1] = (aksv_lsb >> 8) & 0xFF; + aksv[2] = (aksv_lsb >> 16) & 0xFF; + aksv[3] = (aksv_lsb >> 24) & 0xFF; + aksv[4] = aksv_msb & 0xFF; + + /* check there are 20 ones in AKSV */ + if (hdcp1_count_ones(aksv, 5) != number_of_ones) { + pr_err("AKSV bit count failed\n"); + return -EINVAL; + } + + return 0; +} + + + +bool hdcp2_feature_supported(void *data) +{ + int ret = 0; + + mutex_lock(&hdcp2_mutex_g); + ret = ta_interface.trusted_app_hdcp2_feature_supported(data); + mutex_unlock(&hdcp2_mutex_g); + + return ret; +} +EXPORT_SYMBOL(hdcp2_feature_supported); + +int hdcp2_force_encryption(void *ctx, uint32_t enable) +{ + int ret = 0; + + mutex_lock(&hdcp2_mutex_g); + ret = ta_interface.trusted_app_hdcp2_force_encryption(ctx, enable); + mutex_unlock(&hdcp2_mutex_g); + + return ret; +} +EXPORT_SYMBOL(hdcp2_force_encryption); + +int hdcp2_app_comm(void *ctx, enum hdcp2_app_cmd cmd, + struct hdcp2_app_data *app_data) +{ + int ret = 0; + uint32_t req_len = 0; + + if (!ctx || !app_data) { + pr_err("invalid input\n"); + return -EINVAL; + } + + req_len = app_data->request.length; + + mutex_lock(&hdcp2_mutex_g); + switch (cmd) { + case HDCP2_CMD_START: + ret = ta_interface.trusted_app_hdcp2_app_start(ctx, req_len); + break; + case HDCP2_CMD_START_AUTH: + ret = ta_interface.trusted_app_hdcp2_app_start_auth(ctx, req_len); + break; + case HDCP2_CMD_PROCESS_MSG: + ret = ta_interface.trusted_app_hdcp2_app_process_msg(ctx, req_len); + break; + case HDCP2_CMD_TIMEOUT: + ret = ta_interface.trusted_app_hdcp2_app_timeout(ctx, req_len); + break; + case HDCP2_CMD_EN_ENCRYPTION: + ret = ta_interface.trusted_app_hdcp2_app_enable_encryption(ctx, req_len); + break; + case HDCP2_CMD_QUERY_STREAM: + ret = ta_interface.trusted_app_hdcp2_app_query_stream(ctx, req_len); + break; + case HDCP2_CMD_STOP: + ret = ta_interface.trusted_app_hdcp2_app_stop(ctx); + break; + default: + goto error; + } + + if (ret) + goto error; + + ret = ta_interface.trusted_app_hdcp2_update_app_data(ctx, app_data); + +error: + mutex_unlock(&hdcp2_mutex_g); + return ret; +} +EXPORT_SYMBOL(hdcp2_app_comm); + +int hdcp2_open_stream(void *ctx, uint8_t vc_payload_id, uint8_t stream_number, + uint32_t *stream_id) +{ + int ret = 0; + + mutex_lock(&hdcp2_mutex_g); + ret = ta_interface.trusted_app_hdcp2_open_stream(ctx, vc_payload_id, stream_number, + stream_id); + mutex_unlock(&hdcp2_mutex_g); + + return ret; +} +EXPORT_SYMBOL(hdcp2_open_stream); + +int hdcp2_close_stream(void *ctx, uint32_t stream_id) +{ + int ret = 0; + + mutex_lock(&hdcp2_mutex_g); + ret = ta_interface.trusted_app_hdcp2_close_stream(ctx, stream_id); + mutex_unlock(&hdcp2_mutex_g); + + return ret; +} +EXPORT_SYMBOL(hdcp2_close_stream); + +void *hdcp2_init(u32 device_type) +{ + void *data = NULL; + + mutex_lock(&hdcp2_mutex_g); + data = ta_interface.trusted_app_hdcp2_init(device_type); + mutex_unlock(&hdcp2_mutex_g); + + return data; +} +EXPORT_SYMBOL(hdcp2_init); + +void hdcp2_deinit(void *ctx) +{ + ta_interface.trusted_app_hdcp2_deinit(ctx); +} +EXPORT_SYMBOL(hdcp2_deinit); + +void *hdcp1_init(void) +{ + void *data = NULL; + + mutex_lock(&hdcp1_mutex_g); + data = ta_interface.trusted_app_hdcp1_init(); + mutex_unlock(&hdcp1_mutex_g); + + return data; +} +EXPORT_SYMBOL(hdcp1_init); + +void hdcp1_deinit(void *data) +{ + kfree(data); +} +EXPORT_SYMBOL(hdcp1_deinit); + +bool hdcp1_feature_supported(void *data) +{ + bool supported = false; + + mutex_lock(&hdcp1_mutex_g); + supported = ta_interface.trusted_app_hdcp1_feature_supported(data); + mutex_unlock(&hdcp1_mutex_g); + + return supported; +} +EXPORT_SYMBOL(hdcp1_feature_supported); + +int hdcp1_set_enc(void *data, bool enable) +{ + int ret = 0; + + mutex_lock(&hdcp1_mutex_g); + ret = ta_interface.trusted_app_hdcp1_set_enc(data, enable); + mutex_unlock(&hdcp1_mutex_g); + + return ret; +} +EXPORT_SYMBOL(hdcp1_set_enc); + +int hdcp1_ops_notify(void *data, void *topo, bool is_authenticated) +{ + int ret = 0; + + ret = ta_interface.trusted_app_hdcp1_ops_notify(data, topo, is_authenticated); + + return ret; +} +EXPORT_SYMBOL(hdcp1_ops_notify); + +int hdcp1_start(void *data, u32 *aksv_msb, u32 *aksv_lsb) +{ + int ret = 0; + + mutex_lock(&hdcp1_mutex_g); + ret = ta_interface.trusted_app_hdcp1_start(data, aksv_msb, aksv_lsb); + mutex_unlock(&hdcp1_mutex_g); + + return ret; +} +EXPORT_SYMBOL(hdcp1_start); + +void hdcp1_stop(void *data) +{ + mutex_lock(&hdcp1_mutex_g); + ta_interface.trusted_app_hdcp1_stop(data); + mutex_unlock(&hdcp1_mutex_g); +} +EXPORT_SYMBOL(hdcp1_stop); + +static int __init hdcp_module_init(void) +{ + struct device_node *np = NULL; + bool use_smcinvoke = false; + + np = of_find_compatible_node(NULL, NULL, "qcom,hdcp"); + if (!np) { + /*select qseecom interface as default if hdcp node + *is not present in dtsi + */ + select_interface(use_smcinvoke); + return 0; + } + + use_smcinvoke = of_property_read_bool(np, "qcom,use-smcinvoke"); + + select_interface(use_smcinvoke); + + return 0; +} + +static void __exit hdcp_module_exit(void) +{ +} + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("HDCP driver"); + +module_init(hdcp_module_init); +module_exit(hdcp_module_exit); diff --git a/hdcp/hdcp_main.h b/hdcp/hdcp_main.h new file mode 100644 index 0000000000..018444556b --- /dev/null +++ b/hdcp/hdcp_main.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __HDCP_MAIN_H__ +#define __HDCP_MAIN_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HDCP2P2_APP_NAME "hdcp2p2" +#define HDCP1_APP_NAME "hdcp1" +#define HDCP1OPS_APP_NAME "ops" +#define HDCPSRM_APP_NAME "hdcpsrm" +#define QSEECOM_SBUFF_SIZE 0x1000 + +#define MAX_REC_ID_LIST_SIZE 160 +#define MAX_TX_MESSAGE_SIZE 129 +#define MAX_RX_MESSAGE_SIZE 534 +#define MAX_TOPOLOGY_ELEMS 32 +#define HDCP1_NOTIFY_TOPOLOGY 1 +#define HDCP1_AKSV_SIZE 8 + +#define HDCP_CLIENT_MAKE_VERSION(maj, min, patch) \ + ((((maj)&0xFF) << 16) | (((min)&0xFF) << 8) | ((patch)&0xFF)) + +#define HCDP_TXMTR_GET_MAJOR_VERSION(v) (((v) >> 16) & 0xFF) +#define HCDP_TXMTR_GET_MINOR_VERSION(v) (((v) >> 8) & 0xFF) +#define HCDP_TXMTR_GET_PATCH_VERSION(v) ((v)&0xFF) + +#define HDCP_CLIENT_MAJOR_VERSION 2 +#define HDCP_CLIENT_MINOR_VERSION 1 +#define HDCP_CLIENT_PATCH_VERSION 0 + +#define HDCP_SUCCESS 0 + +/* Wait 200ms after authentication */ +#define SLEEP_FORCE_ENCRYPTION_MS 200 + +#define SLEEP_SET_HW_KEY_MS 300 + +/* flags set by tz in response message */ +#define HDCP_TXMTR_SUBSTATE_INIT 0 +#define HDCP_TXMTR_SUBSTATE_WAITING_FOR_RECIEVERID_LIST 1 +#define HDCP_TXMTR_SUBSTATE_PROCESSED_RECIEVERID_LIST 2 +#define HDCP_TXMTR_SUBSTATE_WAITING_FOR_STREAM_READY_MESSAGE 3 +#define HDCP_TXMTR_SUBSTATE_REPEATER_AUTH_COMPLETE 4 + +enum hdcp_state { + HDCP_STATE_INIT = 0x00, + HDCP_STATE_APP_LOADED = 0x01, + HDCP_STATE_SESSION_INIT = 0x02, + HDCP_STATE_TXMTR_INIT = 0x04, + HDCP_STATE_AUTHENTICATED = 0x08, + HDCP_STATE_ERROR = 0x10 +}; + +struct hdcp_ta_interface +{ + void *(*trusted_app_hdcp1_init)(void); + bool (*trusted_app_hdcp1_feature_supported)(void *data); + int (*trusted_app_hdcp1_set_enc)(void *data,bool enable); + int (*trusted_app_hdcp1_ops_notify)(void *data, void *topo, + bool is_authenticated); + int (*trusted_app_hdcp1_start)(void *data, u32 *aksv_msb, + u32 *aksv_lsb); + void (*trusted_app_hdcp1_stop)(void *data); + void *(*trusted_app_hdcp2_init)(u32 device_type); + void (*trusted_app_hdcp2_deinit)(void *ctx); + int (*trusted_app_hdcp2_app_start)(void *ctx, uint32_t req_len); + int (*trusted_app_hdcp2_app_start_auth)(void *ctx, uint32_t req_len); + int (*trusted_app_hdcp2_app_process_msg)(void *ctx, uint32_t req_len); + int (*trusted_app_hdcp2_app_timeout)(void *ctx, uint32_t req_len); + int (*trusted_app_hdcp2_app_enable_encryption)(void *ctx, uint32_t req_len); + int (*trusted_app_hdcp2_app_query_stream)(void *ctx, uint32_t req_len); + int (*trusted_app_hdcp2_app_stop)(void *ctx); + bool (*trusted_app_hdcp2_feature_supported)(void *ctx); + int (*trusted_app_hdcp2_force_encryption)(void *ctx, uint32_t enable); + int (*trusted_app_hdcp2_open_stream)(void *ctx, uint8_t vc_payload_id, + uint8_t stream_number, uint32_t *stream_id); + int (*trusted_app_hdcp2_close_stream)(void *ctx, uint32_t stream_id); + int (*trusted_app_hdcp2_update_app_data)(void *ctx, + struct hdcp2_app_data *app_data); +}; + +int hdcp1_validate_aksv(u32 aksv_msb, u32 aksv_lsb); + +#endif /* __HDCP_MAIN_H__ */ diff --git a/hdcp/hdcp_qseecom.c b/hdcp/hdcp_qseecom.c index 2bd4f3111c..56852819f4 100644 --- a/hdcp/hdcp_qseecom.c +++ b/hdcp/hdcp_qseecom.c @@ -1,181 +1,21 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2022, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2015-2022 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ -#define pr_fmt(fmt) "[hdcp-qseecom] %s: " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include #include -#if IS_ENABLED(CONFIG_QSEECOM_PROXY) -#include -#else -#include "misc/qseecom_kernel.h" -#endif +#include +#include +#include +#include +#include -#define HDCP2P2_APP_NAME "hdcp2p2" -#define HDCP1_APP_NAME "hdcp1" -#define HDCP1OPS_APP_NAME "ops" -#define HDCPSRM_APP_NAME "hdcpsrm" -#define QSEECOM_SBUFF_SIZE 0x1000 +#include "hdcp_qseecom.h" +#include "hdcp_main.h" -#define MAX_REC_ID_LIST_SIZE 160 -#define MAX_TX_MESSAGE_SIZE 129 -#define MAX_RX_MESSAGE_SIZE 534 -#define MAX_TOPOLOGY_ELEMS 32 -#define HDCP1_NOTIFY_TOPOLOGY 1 -#define HDCP1_AKSV_SIZE 8 - -#define HDCP1_SET_KEY 202 -#define HDCP1_KEY_VERIFY 204 -#define HDCP1_SET_ENC 205 - -#define BITS_8_IN_BYTES 1 -#define BITS_16_IN_BYTES 2 -#define BITS_24_IN_BYTES 3 -#define BITS_32_IN_BYTES 4 -#define BITS_40_IN_BYTES 5 -#define BITS_64_IN_BYTES 8 -#define BITS_128_IN_BYTES 16 -#define BITS_160_IN_BYTES 20 -#define BITS_256_IN_BYTES 32 -#define BITS_1024_IN_BYTES 128 -#define BITS_3072_IN_BYTES 384 -#define TXCAPS_SIZE 3 -#define RXCAPS_SIZE 3 -#define RXINFO_SIZE 2 -#define SEQ_NUM_V_SIZE 3 - -#define RCVR_ID_SIZE BITS_40_IN_BYTES -#define MAX_RCVR_IDS_ALLOWED_IN_LIST 31 -#define MAX_RCVR_ID_LIST_SIZE \ - (RCVR_ID_SIZE*MAX_RCVR_IDS_ALLOWED_IN_LIST) -/* - * minimum wait as per standard is 200 ms. keep it 300 ms - * to be on safe side. - */ -#define SLEEP_SET_HW_KEY_MS 300 - -/* Wait 200ms after authentication */ -#define SLEEP_FORCE_ENCRYPTION_MS 200 - -/* hdcp command status */ -#define HDCP_SUCCESS 0 - -/* DP device type */ -#define DEVICE_TYPE_DP 0x8002 - -const char *HdcpErrors[] = { - "HDCP_SUCCESS", - "HDCP_FAIL", - "HDCP_BAD_PARAM", - "HDCP_DEVICE_TYPE_UNSUPPORTED", - "HDCP_INVALID_COMMAND", - "HDCP_INVALID_COMMAND_HANDLE", - "HDCP_ERROR_SIZE_IN", - "HDCP_ERROR_SIZE_OUT", - "HDCP_DATA_SIZE_INSUFFICIENT", - "HDCP_UNSUPPORTED_RX_VERSION", - "HDCP_WRONG_RX_CAPAB_MASK", - "HDCP_WRONG_RX_RSVD", - "HDCP_WRONG_RX_HDCP_CAPABLE", - "HDCP_RSA_SIGNATURE_VERIFY_FAILED", - "HDCP_VERIFY_H_PRIME_FAILED", - "HDCP_LC_FAILED", - "HDCP_MESSAGE_TIMEOUT", - "HDCP_COUNTER_ROLL_OVER", - "HDCP_WRONG_RXINFO_RSVD", - "HDCP_RXINFO_MAX_DEVS", - "HDCP_RXINFO_MAX_CASCADE", - "HDCP_WRONG_INITIAL_SEQ_NUM_V", - "HDCP_SEQ_NUM_V_ROLL_OVER", - "HDCP_WRONG_SEQ_NUM_V", - "HDCP_VERIFY_V_FAILED", - "HDCP_RPT_METHOD_INVOKED", - "HDCP_RPT_STRM_LEN_WRONG", - "HDCP_VERIFY_STRM_M_FAILED", - "HDCP_TRANSMITTER_NOT_FOUND", - "HDCP_SESSION_NOT_FOUND", - "HDCP_MAX_SESSION_EXCEEDED", - "HDCP_MAX_CONNECTION_EXCEEDED", - "HDCP_MAX_STREAMS_EXCEEDED", - "HDCP_MAX_DEVICES", - "HDCP_ALLOC_FAILED", - "HDCP_CONNECTION_NOT_FOUND", - "HDCP_HASH_FAILED", - "HDCP_BN_FAILED", - "HDCP_ENCRYPT_KM_FAILED", - "HDCP_DECRYPT_KM_FAILED", - "HDCP_HMAC_FAILED", - "HDCP_GET_RANDOM_FAILED", - "HDCP_INVALID_KEY_HEADER", - "HDCP_INVALID_KEY_LC_HASH", - "HDCP_INVALID_KEY_HASH", - "HDCP_KEY_WRITE_FAILED", - "HDCP_KEY_READ_FAILED", - "HDCP_KEY_DECRYPT_FAILED", - "HDCP_TEST_KEY_ON_SECURE_DEVICE", - "HDCP_KEY_VERSION_UNSUPPORTED", - "HDCP_RXID_NOT_FOUND", - "HDCP_STORAGE_INIT_FAILED", - "HDCP_STORAGE_FILE_OPEN_FAILED", - "HDCP_STORAGE_FILE_READ_FAILED", - "HDCP_STORAGE_FILE_WRITE_FAILED", - "HDCP_STORAGE_ID_UNSUPPORTED", - "HDCP_MUTUAL_EXCLUSIVE_DEVICE_PRESENT", - "HDCP_INVALID_STATE", - "HDCP_CONFIG_READ_FAILED", - "HDCP_OPEN_TZ_SERVICE_FAILED", - "HDCP_HW_CLOCK_OFF", - "HDCP_SET_HW_KEY_FAILED", - "HDCP_CLEAR_HW_KEY_FAILED", - "HDCP_GET_CONTENT_LEVEL_FAILED", - "HDCP_STREAMID_INUSE", - "HDCP_STREAM_NOT_FOUND", - "HDCP_FORCE_ENCRYPTION_FAILED", - "HDCP_STREAMNUMBER_INUSE" -}; - -/* flags set by tz in response message */ -#define HDCP_TXMTR_SUBSTATE_INIT 0 -#define HDCP_TXMTR_SUBSTATE_WAITING_FOR_RECIEVERID_LIST 1 -#define HDCP_TXMTR_SUBSTATE_PROCESSED_RECIEVERID_LIST 2 -#define HDCP_TXMTR_SUBSTATE_WAITING_FOR_STREAM_READY_MESSAGE 3 -#define HDCP_TXMTR_SUBSTATE_REPEATER_AUTH_COMPLETE 4 - -#define HDCP_DEVICE_ID 0x0008000 -#define HDCP_CREATE_DEVICE_ID(x) (HDCP_DEVICE_ID | (x)) - -#define HDCP_TXMTR_HDMI HDCP_CREATE_DEVICE_ID(1) - -#define HDCP_TXMTR_SERVICE_ID 0x0001000 -#define SERVICE_CREATE_CMD(x) (HDCP_TXMTR_SERVICE_ID | x) - -#define HCDP_TXMTR_GET_MAJOR_VERSION(v) (((v) >> 16) & 0xFF) -#define HCDP_TXMTR_GET_MINOR_VERSION(v) (((v) >> 8) & 0xFF) -#define HCDP_TXMTR_GET_PATCH_VERSION(v) ((v) & 0xFF) - -#define HDCP_CLIENT_MAJOR_VERSION 2 -#define HDCP_CLIENT_MINOR_VERSION 1 -#define HDCP_CLIENT_PATCH_VERSION 0 -#define HDCP_CLIENT_MAKE_VERSION(maj, min, patch) \ - ((((maj) & 0xFF) << 16) | (((min) & 0xFF) << 8) | ((patch) & 0xFF)) +#define HDCP_CMD_STATUS_TO_STR(x) #x #define hdcp2_app_init_var(x) \ struct hdcp_##x##_req *req_buf = NULL; \ @@ -185,456 +25,651 @@ const char *HdcpErrors[] = { rc = -EINVAL; \ goto error; \ } \ - req_buf = (struct hdcp_##x##_req *) handle->qseecom_handle->sbuf; \ - rsp_buf = (struct hdcp_##x##_rsp *) (handle->qseecom_handle->sbuf + \ - QSEECOM_ALIGN(sizeof(struct hdcp_##x##_req))); \ + req_buf = (struct hdcp_##x##_req *)handle->qseecom_handle->sbuf; \ + rsp_buf = (struct hdcp_##x##_rsp *)(handle->qseecom_handle->sbuf + \ + QSEECOM_ALIGN(sizeof(struct hdcp_##x##_req))); \ req_buf->commandid = hdcp_cmd_##x - #define hdcp2_app_process_cmd(x) \ -({ \ - int rc = qseecom_send_command(handle->qseecom_handle, \ - req_buf, QSEECOM_ALIGN(sizeof(struct hdcp_##x##_req)), \ - rsp_buf, QSEECOM_ALIGN(sizeof(struct hdcp_##x##_rsp))); \ - if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS)) { \ - pr_err("qseecom cmd %s failed with err = %d, status = %d:%s\n" \ - , #x, rc, rsp_buf->status, \ - hdcp_cmd_status_to_str(rsp_buf->status)); \ - rc = -EINVAL; \ - } \ - rc; \ -}) + ({ \ + int rc = qseecom_send_command( \ + handle->qseecom_handle, req_buf, \ + QSEECOM_ALIGN(sizeof(struct hdcp_##x##_req)), rsp_buf, \ + QSEECOM_ALIGN(sizeof(struct hdcp_##x##_rsp))); \ + if ((rc < 0) || (rsp_buf->status != HDCP_SUCCESS)) { \ + pr_err("qseecom cmd %s failed with err = %d, status = %d:%s\n", \ + #x, rc, rsp_buf->status, \ + hdcp_cmd_status_to_str(rsp_buf->status)); \ + rc = -EINVAL; \ + } \ + rc; \ + }) -enum { - hdcp_cmd_tx_init = SERVICE_CREATE_CMD(1), - hdcp_cmd_tx_init_v1 = SERVICE_CREATE_CMD(1), - hdcp_cmd_tx_deinit = SERVICE_CREATE_CMD(2), - hdcp_cmd_rcvd_msg = SERVICE_CREATE_CMD(3), - hdcp_cmd_send_timeout = SERVICE_CREATE_CMD(4), - hdcp_cmd_set_hw_key = SERVICE_CREATE_CMD(5), - hdcp_cmd_query_stream_type = SERVICE_CREATE_CMD(6), - hdcp_cmd_init_v1 = SERVICE_CREATE_CMD(11), - hdcp_cmd_init = SERVICE_CREATE_CMD(11), - hdcp_cmd_deinit = SERVICE_CREATE_CMD(12), - hdcp_cmd_version = SERVICE_CREATE_CMD(14), - hdcp_cmd_verify_key = SERVICE_CREATE_CMD(15), - hdcp_cmd_session_init = SERVICE_CREATE_CMD(16), - hdcp_cmd_session_deinit = SERVICE_CREATE_CMD(17), - hdcp_cmd_start_auth = SERVICE_CREATE_CMD(18), - hdcp_cmd_session_open_stream = SERVICE_CREATE_CMD(20), - hdcp_cmd_session_close_stream = SERVICE_CREATE_CMD(21), - hdcp_cmd_force_encryption = SERVICE_CREATE_CMD(22), -}; +const char *hdcp_errors[] = {"HDCP_SUCCESS", + "HDCP_FAIL", + "HDCP_BAD_PARAM", + "HDCP_DEVICE_TYPE_UNSUPPORTED", + "HDCP_INVALID_COMMAND", + "HDCP_INVALID_COMMAND_HANDLE", + "HDCP_ERROR_SIZE_IN", + "HDCP_ERROR_SIZE_OUT", + "HDCP_DATA_SIZE_INSUFFICIENT", + "HDCP_UNSUPPORTED_RX_VERSION", + "HDCP_WRONG_RX_CAPAB_MASK", + "HDCP_WRONG_RX_RSVD", + "HDCP_WRONG_RX_HDCP_CAPABLE", + "HDCP_RSA_SIGNATURE_VERIFY_FAILED", + "HDCP_VERIFY_H_PRIME_FAILED", + "HDCP_LC_FAILED", + "HDCP_MESSAGE_TIMEOUT", + "HDCP_COUNTER_ROLL_OVER", + "HDCP_WRONG_RXINFO_RSVD", + "HDCP_RXINFO_MAX_DEVS", + "HDCP_RXINFO_MAX_CASCADE", + "HDCP_WRONG_INITIAL_SEQ_NUM_V", + "HDCP_SEQ_NUM_V_ROLL_OVER", + "HDCP_WRONG_SEQ_NUM_V", + "HDCP_VERIFY_V_FAILED", + "HDCP_RPT_METHOD_INVOKED", + "HDCP_RPT_STRM_LEN_WRONG", + "HDCP_VERIFY_STRM_M_FAILED", + "HDCP_TRANSMITTER_NOT_FOUND", + "HDCP_SESSION_NOT_FOUND", + "HDCP_MAX_SESSION_EXCEEDED", + "HDCP_MAX_CONNECTION_EXCEEDED", + "HDCP_MAX_STREAMS_EXCEEDED", + "HDCP_MAX_DEVICES", + "HDCP_ALLOC_FAILED", + "HDCP_CONNECTION_NOT_FOUND", + "HDCP_HASH_FAILED", + "HDCP_BN_FAILED", + "HDCP_ENCRYPT_KM_FAILED", + "HDCP_DECRYPT_KM_FAILED", + "HDCP_HMAC_FAILED", + "HDCP_GET_RANDOM_FAILED", + "HDCP_INVALID_KEY_HEADER", + "HDCP_INVALID_KEY_LC_HASH", + "HDCP_INVALID_KEY_HASH", + "HDCP_KEY_WRITE_FAILED", + "HDCP_KEY_READ_FAILED", + "HDCP_KEY_DECRYPT_FAILED", + "HDCP_TEST_KEY_ON_SECURE_DEVICE", + "HDCP_KEY_VERSION_UNSUPPORTED", + "HDCP_RXID_NOT_FOUND", + "HDCP_STORAGE_INIT_FAILED", + "HDCP_STORAGE_FILE_OPEN_FAILED", + "HDCP_STORAGE_FILE_READ_FAILED", + "HDCP_STORAGE_FILE_WRITE_FAILED", + "HDCP_STORAGE_ID_UNSUPPORTED", + "HDCP_MUTUAL_EXCLUSIVE_DEVICE_PRESENT", + "HDCP_INVALID_STATE", + "HDCP_CONFIG_READ_FAILED", + "HDCP_OPEN_TZ_SERVICE_FAILED", + "HDCP_HW_CLOCK_OFF", + "HDCP_SET_HW_KEY_FAILED", + "HDCP_CLEAR_HW_KEY_FAILED", + "HDCP_GET_CONTENT_LEVEL_FAILED", + "HDCP_STREAMID_INUSE", + "HDCP_STREAM_NOT_FOUND", + "HDCP_FORCE_ENCRYPTION_FAILED", + "HDCP_STREAMNUMBER_INUSE"}; -enum hdcp_state { - HDCP_STATE_INIT = 0x00, - HDCP_STATE_APP_LOADED = 0x01, - HDCP_STATE_SESSION_INIT = 0x02, - HDCP_STATE_TXMTR_INIT = 0x04, - HDCP_STATE_AUTHENTICATED = 0x08, - HDCP_STATE_ERROR = 0x10 -}; - -enum hdcp_element { - HDCP_TYPE_UNKNOWN, - HDCP_TYPE_RECEIVER, - HDCP_TYPE_REPEATER, -}; - -enum hdcp_version { - HDCP_VERSION_UNKNOWN, - HDCP_VERSION_2_2, - HDCP_VERSION_1_4 -}; - -struct receiver_info { - unsigned char rcvrInfo[RCVR_ID_SIZE]; - enum hdcp_element elem_type; - enum hdcp_version hdcp_version; -}; - -struct topology_info { - unsigned int nNumRcvrs; - struct receiver_info rcvinfo[MAX_TOPOLOGY_ELEMS]; -}; - -struct __attribute__ ((__packed__)) hdcp1_key_set_req { - uint32_t commandid; -}; - -struct __attribute__ ((__packed__)) hdcp1_key_set_rsp { - uint32_t commandid; - uint32_t ret; - uint8_t ksv[HDCP1_AKSV_SIZE]; -}; - -struct __attribute__ ((__packed__)) hdcp_version_req { - uint32_t commandid; -}; - -struct __attribute__ ((__packed__)) hdcp_version_rsp { - uint32_t status; - uint32_t commandId; - uint32_t appversion; -}; - -struct __attribute__ ((__packed__)) hdcp_verify_key_req { - uint32_t commandid; -}; - -struct __attribute__ ((__packed__)) hdcp_verify_key_rsp { - uint32_t status; - uint32_t commandId; -}; - -struct __attribute__ ((__packed__)) hdcp1_key_verify_req { - uint32_t commandid; - uint32_t key_type; -}; - -struct __attribute__ ((__packed__)) hdcp1_key_verify_rsp { - uint32_t commandId; - uint32_t ret; -}; - -struct __attribute__ ((__packed__)) hdcp_init_v1_req { - uint32_t commandid; -}; - -struct __attribute__ ((__packed__)) hdcp_init_v1_rsp { - uint32_t status; - uint32_t commandid; - uint32_t ctxhandle; - uint32_t timeout; - uint32_t msglen; - uint8_t message[MAX_TX_MESSAGE_SIZE]; -}; - -struct __attribute__ ((__packed__)) hdcp_init_req { - uint32_t commandid; - uint32_t clientversion; -}; - -struct __attribute__ ((__packed__)) hdcp_init_rsp { - uint32_t status; - uint32_t commandid; - uint32_t appversion; -}; - -struct __attribute__ ((__packed__)) hdcp_deinit_req { - uint32_t commandid; -}; - -struct __attribute__ ((__packed__)) hdcp_deinit_rsp { - uint32_t status; - uint32_t commandid; -}; - -struct __attribute__ ((__packed__)) hdcp_session_init_req { - uint32_t commandid; - uint32_t deviceid; -}; - -struct __attribute__ ((__packed__)) hdcp_session_init_rsp { - uint32_t status; - uint32_t commandid; - uint32_t sessionid; -}; - -struct __attribute__ ((__packed__)) hdcp_session_deinit_req { - uint32_t commandid; - uint32_t sessionid; -}; - -struct __attribute__ ((__packed__)) hdcp_session_deinit_rsp { - uint32_t status; - uint32_t commandid; -}; - -struct __attribute__ ((__packed__)) hdcp_tx_init_v1_req { - uint32_t commandid; -}; - -struct __attribute__ ((__packed__)) hdcp_tx_init_v1_rsp { - uint32_t status; - uint32_t commandid; - uint32_t ctxhandle; - uint32_t timeout; - uint32_t msglen; - uint8_t message[MAX_TX_MESSAGE_SIZE]; -}; - -struct __attribute__ ((__packed__)) hdcp_tx_init_req { - uint32_t commandid; - uint32_t sessionid; -}; - -struct __attribute__ ((__packed__)) hdcp_tx_init_rsp { - uint32_t status; - uint32_t commandid; - uint32_t ctxhandle; -}; - -struct __attribute__ ((__packed__)) hdcp_tx_deinit_req { - uint32_t commandid; - uint32_t ctxhandle; -}; - -struct __attribute__ ((__packed__)) hdcp_tx_deinit_rsp { - uint32_t status; - uint32_t commandid; -}; - -struct __attribute__ ((__packed__)) hdcp_rcvd_msg_req { - uint32_t commandid; - uint32_t ctxhandle; - uint32_t msglen; - uint8_t msg[MAX_RX_MESSAGE_SIZE]; -}; - -struct __attribute__ ((__packed__)) hdcp_rcvd_msg_rsp { - uint32_t status; - uint32_t commandid; - uint32_t state; - uint32_t timeout; - uint32_t flag; - uint32_t msglen; - uint8_t msg[MAX_TX_MESSAGE_SIZE]; -}; - -struct __attribute__ ((__packed__)) hdcp_set_hw_key_req { - uint32_t commandid; - uint32_t ctxhandle; -}; - -struct __attribute__ ((__packed__)) hdcp_set_hw_key_rsp { - uint32_t status; - uint32_t commandid; -}; - -struct __attribute__ ((__packed__)) hdcp_send_timeout_req { - uint32_t commandid; - uint32_t ctxhandle; -}; - -struct __attribute__ ((__packed__)) hdcp_send_timeout_rsp { - uint32_t status; - uint32_t commandid; - uint32_t timeout; - uint32_t msglen; - uint8_t message[MAX_TX_MESSAGE_SIZE]; -}; - -struct __attribute__ ((__packed__)) hdcp_query_stream_type_req { - uint32_t commandid; - uint32_t ctxhandle; -}; - -struct __attribute__ ((__packed__)) hdcp_query_stream_type_rsp { - uint32_t status; - uint32_t commandid; - uint32_t timeout; - uint32_t msglen; - uint8_t msg[MAX_TX_MESSAGE_SIZE]; -}; - -struct __attribute__ ((__packed__)) hdcp_set_stream_type_req { - uint32_t commandid; - uint32_t ctxhandle; - uint8_t streamtype; -}; - -struct __attribute__ ((__packed__)) hdcp_set_stream_type_rsp { - uint32_t status; - uint32_t commandid; - uint32_t timeout; - uint32_t msglen; - uint8_t message[MAX_TX_MESSAGE_SIZE]; -}; - -struct __attribute__ ((__packed__)) hdcp_update_srm_req { - uint32_t commandid; - uint32_t ctxhandle; - uint32_t srmoffset; - uint32_t srmlength; -}; - -struct __attribute__ ((__packed__)) hdcp_update_srm_rsp { - uint32_t status; - uint32_t commandid; -}; - -struct __attribute__ ((__packed__)) hdcp_get_topology_req { - uint32_t commandid; - uint32_t ctxhandle; -}; - -struct __attribute__ ((__packed__)) hdcp_get_topology_rsp { - uint32_t status; - uint32_t commandid; - struct topology_info topologyinfo; -}; - -struct __attribute__ ((__packed__)) rxvr_info_struct { - uint8_t rcvrCert[522]; - uint8_t rrx[BITS_64_IN_BYTES]; - uint8_t rxcaps[RXCAPS_SIZE]; - bool repeater; -}; - -struct __attribute__ ((__packed__)) repeater_info_struct { - uint8_t RxInfo[RXINFO_SIZE]; - uint8_t seq_num_V[SEQ_NUM_V_SIZE]; - bool seq_num_V_Rollover_flag; - uint8_t ReceiverIDList[MAX_RCVR_ID_LIST_SIZE]; - uint32_t ReceiverIDListLen; -}; - -struct __attribute__ ((__packed__)) hdcp1_set_enc_req { - uint32_t commandid; - uint32_t enable; -}; - -struct __attribute__ ((__packed__)) hdcp1_set_enc_rsp { - uint32_t commandid; - uint32_t ret; -}; - -struct __attribute__ ((__packed__)) hdcp1_ops_notify_req { - uint32_t commandid; - uint32_t device_type; - uint8_t recv_id_list[MAX_REC_ID_LIST_SIZE]; - int32_t recv_id_len; - struct hdcp1_topology topology; - bool is_authenticated; -}; - -struct __attribute__ ((__packed__)) hdcp1_ops_notify_rsp { - uint32_t commandid; - uint32_t ret; -}; - -struct __attribute__ ((__packed__)) hdcp_start_auth_req { - uint32_t commandid; - uint32_t ctxHandle; -}; - -struct __attribute__ ((__packed__)) hdcp_start_auth_rsp { - uint32_t status; - uint32_t commandid; - uint32_t ctxhandle; - uint32_t timeout; - uint32_t msglen; - uint8_t message[MAX_TX_MESSAGE_SIZE]; -}; - -struct __attribute__((__packed__)) hdcp_session_open_stream_req { - uint32_t commandid; - uint32_t sessionid; - uint32_t vcpayloadid; - uint32_t stream_number; - uint32_t streamMediaType; -}; - -struct __attribute__((__packed__)) hdcp_session_open_stream_rsp { - uint32_t status; - uint32_t commandid; - uint32_t streamid; -}; - -struct __attribute__((__packed__)) hdcp_session_close_stream_req { - uint32_t commandid; - uint32_t sessionid; - uint32_t streamid; -}; - -struct __attribute__((__packed__)) hdcp_session_close_stream_rsp { - uint32_t status; - uint32_t commandid; -}; - -struct __attribute__((__packed__)) hdcp_force_encryption_req { - uint32_t commandid; - uint32_t ctxhandle; - uint32_t enable; -}; - -struct __attribute__ ((__packed__)) hdcp_force_encryption_rsp { - uint32_t status; - uint32_t commandid; -}; - -struct hdcp2_handle { - struct hdcp2_app_data app_data; - uint32_t tz_ctxhandle; - bool feature_supported; - enum hdcp_state hdcp_state; - struct qseecom_handle *qseecom_handle; - struct qseecom_handle *hdcpsrm_qseecom_handle; - uint32_t session_id; - bool legacy_app; - uint32_t device_type; - char *app_name; - - int (*app_init)(struct hdcp2_handle *handle); - int (*tx_init)(struct hdcp2_handle *handle); -}; - -/* - * struct hdcp1_handle - handle for HDCP 1.x client - * @qseecom_handle - for sending commands to qseecom - * @hdcpops_handle - for sending commands to ops TA - * @feature_supported - set to true if the platform supports HDCP 1.x - * @device_type - the interface type (HDMI or DisplayPort) - */ -struct hdcp1_handle { - struct qseecom_handle *qseecom_handle; - struct qseecom_handle *hdcpops_handle; - bool feature_supported; - uint32_t device_type; - enum hdcp_state hdcp_state; - char *app_name; -}; +#define HDCP_TXMTR_SERVICE_ID 0x0001000 +#define SERVICE_CREATE_CMD(x) (HDCP_TXMTR_SERVICE_ID | x) #define HDCP_CMD_STATUS_TO_STR(x) #x + +enum { + hdcp_cmd_tx_init = SERVICE_CREATE_CMD(1), + hdcp_cmd_tx_init_v1 = SERVICE_CREATE_CMD(1), + hdcp_cmd_tx_deinit = SERVICE_CREATE_CMD(2), + hdcp_cmd_rcvd_msg = SERVICE_CREATE_CMD(3), + hdcp_cmd_send_timeout = SERVICE_CREATE_CMD(4), + hdcp_cmd_set_hw_key = SERVICE_CREATE_CMD(5), + hdcp_cmd_query_stream_type = SERVICE_CREATE_CMD(6), + hdcp_cmd_init_v1 = SERVICE_CREATE_CMD(11), + hdcp_cmd_init = SERVICE_CREATE_CMD(11), + hdcp_cmd_deinit = SERVICE_CREATE_CMD(12), + hdcp_cmd_version = SERVICE_CREATE_CMD(14), + hdcp_cmd_verify_key = SERVICE_CREATE_CMD(15), + hdcp_cmd_session_init = SERVICE_CREATE_CMD(16), + hdcp_cmd_session_deinit = SERVICE_CREATE_CMD(17), + hdcp_cmd_start_auth = SERVICE_CREATE_CMD(18), + hdcp_cmd_session_open_stream = SERVICE_CREATE_CMD(20), + hdcp_cmd_session_close_stream = SERVICE_CREATE_CMD(21), + hdcp_cmd_force_encryption = SERVICE_CREATE_CMD(22), +}; + +static struct qseecom_handle *qseecom_handle_g; +static struct qseecom_handle *hdcpsrm_qseecom_handle_g; +static int hdcp2_app_started; + +static struct qseecom_handle *hdcp1_qseecom_handle_g; +static int hdcp1_app_started; + static const char *hdcp_cmd_status_to_str(uint32_t err) { - int len = ARRAY_SIZE(HdcpErrors); + int len = ARRAY_SIZE(hdcp_errors); if (err >= 0 && err < len) - return HdcpErrors[err]; + return hdcp_errors[err]; else return ""; } -static int hdcp_get_version(struct hdcp2_handle *handle) +static int hdcp1_app_load(struct hdcp1_qsee_handle *handle) { int rc = 0; - uint32_t app_major_version = 0; - hdcp2_app_init_var(version); - - if (handle->hdcp_state & HDCP_STATE_APP_LOADED) { - pr_err("library already loaded\n"); + if (!handle) { + pr_err("invalid handle\n"); goto error; } - rc = hdcp2_app_process_cmd(version); - if (rc) - goto error; + if (!hdcp1_qseecom_handle_g) { + rc = qseecom_start_app(&hdcp1_qseecom_handle_g, handle->app_name, + QSEECOM_SBUFF_SIZE); + if (rc) { + pr_err("%s app load failed (%d)\n", handle->app_name, rc); + goto error; + } + } + handle->qseecom_handle = hdcp1_qseecom_handle_g; + hdcp1_app_started++; - app_major_version = HCDP_TXMTR_GET_MAJOR_VERSION(rsp_buf->appversion); + rc = qseecom_start_app(&handle->hdcpops_handle, HDCP1OPS_APP_NAME, + QSEECOM_SBUFF_SIZE); + if (rc) { + pr_warn("%s app load failed (%d)\n", HDCP1OPS_APP_NAME, rc); + handle->hdcpops_handle = NULL; + } - pr_debug("hdp2p2 app major version %d, app version %d\n", - app_major_version, rsp_buf->appversion); + handle->hdcp_state |= HDCP_STATE_APP_LOADED; + pr_debug("%s app loaded\n", handle->app_name); - if (app_major_version == 1) - handle->legacy_app = true; error: return rc; } -static int hdcp2_app_init_legacy(struct hdcp2_handle *handle) +static void hdcp1_app_unload(struct hdcp1_qsee_handle *handle) +{ + int rc = 0; + + if (!handle || !handle->qseecom_handle) { + pr_err("invalid handle\n"); + return; + } + + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_warn("%s app not loaded\n", handle->app_name); + return; + } + + if (handle->hdcpops_handle) { + /* deallocate the resources for HDCP 1.x ops handle */ + rc = qseecom_shutdown_app(&handle->hdcpops_handle); + if (rc) + pr_warn("%s app unload failed (%d)\n", HDCP1OPS_APP_NAME, rc); + } + + /* deallocate the resources for qseecom HDCP 1.x handle */ + rc = qseecom_shutdown_app(&handle->qseecom_handle); + if (rc) { + pr_err("%s app unload failed (%d)\n", handle->app_name, rc); + return; + } + + handle->hdcp_state &= ~HDCP_STATE_APP_LOADED; + pr_debug("%s app unloaded\n", handle->app_name); +} + +static int hdcp1_set_key(struct hdcp1_qsee_handle *hdcp1_handle, u32 *aksv_msb, + u32 *aksv_lsb) +{ + int rc = 0; + struct hdcp1_key_set_req *key_set_req; + struct hdcp1_key_set_rsp *key_set_rsp; + struct qseecom_handle *handle = NULL; + + if (aksv_msb == NULL || aksv_lsb == NULL) { + pr_err("invalid aksv\n"); + return -EINVAL; + } + + if (!hdcp1_handle || !hdcp1_handle->qseecom_handle) { + pr_err("invalid HDCP 1.x handle\n"); + return -EINVAL; + } + + if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("%s app not loaded\n", hdcp1_handle->app_name); + return -EINVAL; + } + + handle = hdcp1_handle->qseecom_handle; + + /* set keys and request aksv */ + key_set_req = (struct hdcp1_key_set_req *)handle->sbuf; + key_set_req->commandid = HDCP1_SET_KEY; + key_set_rsp = (struct hdcp1_key_set_rsp *)(handle->sbuf + + QSEECOM_ALIGN(sizeof(struct hdcp1_key_set_req))); + rc = qseecom_send_command( + handle, key_set_req, QSEECOM_ALIGN(sizeof(struct hdcp1_key_set_req)), + key_set_rsp, QSEECOM_ALIGN(sizeof(struct hdcp1_key_set_rsp))); + + if (rc < 0) { + pr_err("qseecom cmd failed err=%d\n", rc); + return -ENOKEY; + } + + rc = key_set_rsp->ret; + if (rc) { + pr_err("set key cmd failed, rsp=%d\n", key_set_rsp->ret); + return -ENOKEY; + } + + /* copy bytes into msb and lsb */ + *aksv_msb = key_set_rsp->ksv[0] << 24 | key_set_rsp->ksv[1] << 16 | + key_set_rsp->ksv[2] << 8 | key_set_rsp->ksv[3]; + *aksv_lsb = key_set_rsp->ksv[4] << 24 | key_set_rsp->ksv[5] << 16 | + key_set_rsp->ksv[6] << 8 | key_set_rsp->ksv[7]; + + rc = hdcp1_validate_aksv(*aksv_msb, *aksv_lsb); + if (rc) { + pr_err("aksv validation failed (%d)\n", rc); + return rc; + } + + return 0; +} + +static int hdcp1_verify_key(struct hdcp1_qsee_handle *hdcp1_handle) +{ + int rc = 0; + struct hdcp1_key_verify_req *key_verify_req; + struct hdcp1_key_verify_rsp *key_verify_rsp; + struct qseecom_handle *handle = NULL; + + if (!hdcp1_handle || !hdcp1_handle->qseecom_handle) { + pr_err("invalid HDCP 1.x handle\n"); + return -EINVAL; + } + + if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("%s app not loaded\n", hdcp1_handle->app_name); + return -EINVAL; + } + + handle = hdcp1_handle->qseecom_handle; + + key_verify_req = (struct hdcp1_key_verify_req *)handle->sbuf; + key_verify_req->commandid = HDCP1_KEY_VERIFY; + key_verify_rsp = + (struct hdcp1_key_verify_rsp *)(handle->sbuf + + QSEECOM_ALIGN(sizeof(struct hdcp1_key_verify_req))); + rc = qseecom_send_command( + handle, key_verify_req, + QSEECOM_ALIGN(sizeof(struct hdcp1_key_verify_req)), key_verify_rsp, + QSEECOM_ALIGN(sizeof(struct hdcp1_key_set_rsp))); + + if (rc < 0) { + pr_err("command HDCP1_KEY_VERIFY failed (%d)\n", rc); + return -EINVAL; + } + + rc = key_verify_rsp->ret; + if (rc) { + pr_err("key_verify failed, rsp=%d\n", key_verify_rsp->ret); + return -EINVAL; + } + + pr_debug("success\n"); + + return 0; +} + +static int hdcp2_app_unload(struct hdcp2_qsee_handle *handle) +{ + int rc = 0; + + hdcp2_app_init_var(deinit); + + hdcp2_app_started--; + if (!hdcp2_app_started) { + + hdcp2_app_process_cmd(deinit); + /* deallocate the resources for qseecom HDCPSRM handle */ + rc = qseecom_shutdown_app(&handle->hdcpsrm_qseecom_handle); + if (rc) + pr_err("qseecom_shutdown_app failed for HDCPSRM (%d)\n", rc); + + hdcpsrm_qseecom_handle_g = NULL; + /* deallocate the resources for qseecom HDCP2P2 handle */ + rc = qseecom_shutdown_app(&handle->qseecom_handle); + if (rc) { + pr_err("qseecom_shutdown_app failed for HDCP2P2 (%d)\n", rc); + return rc; + } + qseecom_handle_g = NULL; + } + handle->qseecom_handle = NULL; + handle->hdcpsrm_qseecom_handle = NULL; + + handle->hdcp_state &= ~HDCP_STATE_APP_LOADED; + pr_debug("%s app unloaded\n", handle->app_name); + + return rc; +error: + if (!hdcp2_app_started) + qseecom_shutdown_app(&handle->hdcpsrm_qseecom_handle); + return rc; +} + +static int hdcp2_verify_key(struct hdcp2_qsee_handle *handle) +{ + int rc = 0; + + hdcp2_app_init_var(verify_key); + + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("%s app not loaded\n", handle->app_name); + rc = -EINVAL; + goto error; + } + + rc = hdcp2_app_process_cmd(verify_key); + pr_debug("verify_key = %d\n", rc); + +error: + return rc; +} + +static int hdcp2_app_tx_deinit(struct hdcp2_qsee_handle *handle) +{ + int rc = 0; + + hdcp2_app_init_var(tx_deinit); + + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("%s app not loaded\n", handle->app_name); + rc = -EINVAL; + goto error; + } + + if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) { + pr_err("txmtr not initialized\n"); + rc = -EINVAL; + goto error; + } + + req_buf->ctxhandle = handle->tz_ctxhandle; + + rc = hdcp2_app_process_cmd(tx_deinit); + if (rc) + goto error; + + handle->hdcp_state &= ~HDCP_STATE_TXMTR_INIT; + pr_debug("success\n"); +error: + return rc; +} + +static int hdcp2_app_session_deinit(struct hdcp2_qsee_handle *handle) +{ + int rc = 0; + + hdcp2_app_init_var(session_deinit); + + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("%s app not loaded\n", handle->app_name); + rc = -EINVAL; + goto error; + } + + if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) { + pr_err("session not initialized\n"); + rc = -EINVAL; + goto error; + } + + req_buf->sessionid = handle->session_id; + + rc = hdcp2_app_process_cmd(session_deinit); + if (rc) + goto error; + + handle->hdcp_state &= ~HDCP_STATE_SESSION_INIT; + pr_debug("success\n"); +error: + return rc; +} + +void *hdcp1_init_qseecom(void) +{ + struct hdcp1_qsee_handle *handle = + kzalloc(sizeof(struct hdcp1_qsee_handle), GFP_KERNEL); + + if (!handle) + goto error; + + handle->app_name = HDCP1_APP_NAME; + +error: + return handle; +} + +bool hdcp1_feature_supported_qseecom(void *data) +{ + bool supported = false; + struct hdcp1_qsee_handle *handle = data; + int rc = 0; + + if (!handle) { + pr_err("invalid handle\n"); + goto error; + } + + if (handle->feature_supported) { + supported = true; + goto error; + } + + rc = hdcp1_app_load(handle); + if (!rc && (handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + if (!hdcp1_verify_key(handle)) { + pr_debug("HDCP 1.x supported\n"); + handle->feature_supported = true; + supported = true; + } + hdcp1_app_unload(handle); + } +error: + return supported; +} + +int hdcp1_set_enc_qseecom(void *data, bool enable) +{ + int rc = 0; + struct hdcp1_set_enc_req *set_enc_req; + struct hdcp1_set_enc_rsp *set_enc_rsp; + struct hdcp1_qsee_handle *hdcp1_handle = data; + struct qseecom_handle *handle = NULL; + + if (!hdcp1_handle || !hdcp1_handle->qseecom_handle) { + pr_err("invalid HDCP 1.x handle\n"); + return -EINVAL; + } + + if (!hdcp1_handle->feature_supported) { + pr_err("HDCP 1.x not supported\n"); + return -EINVAL; + } + + if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("%s app not loaded\n", hdcp1_handle->app_name); + return -EINVAL; + } + + handle = hdcp1_handle->qseecom_handle; + + /* set keys and request aksv */ + set_enc_req = (struct hdcp1_set_enc_req *)handle->sbuf; + set_enc_req->commandid = HDCP1_SET_ENC; + set_enc_req->enable = enable; + set_enc_rsp = (struct hdcp1_set_enc_rsp *)(handle->sbuf + + QSEECOM_ALIGN(sizeof(struct hdcp1_set_enc_req))); + rc = qseecom_send_command( + handle, set_enc_req, QSEECOM_ALIGN(sizeof(struct hdcp1_set_enc_req)), + set_enc_rsp, QSEECOM_ALIGN(sizeof(struct hdcp1_set_enc_rsp))); + + if (rc < 0) { + pr_err("qseecom cmd failed err=%d\n", rc); + return -EINVAL; + } + + rc = set_enc_rsp->ret; + if (rc) { + pr_err("enc cmd failed, rsp=%d\n", set_enc_rsp->ret); + return -EINVAL; + } + + pr_debug("success\n"); + return 0; +} + +int hdcp1_ops_notify_qseecom(void *data, void *topo, bool is_authenticated) +{ + int rc = 0; + struct hdcp1_ops_notify_req *ops_notify_req; + struct hdcp1_ops_notify_rsp *ops_notify_rsp; + struct hdcp1_qsee_handle *hdcp1_handle = data; + struct qseecom_handle *handle = NULL; + struct hdcp1_topology *topology = NULL; + + if (!hdcp1_handle || !hdcp1_handle->hdcpops_handle) { + pr_err("invalid HDCP 1.x ops handle\n"); + return -EINVAL; + } + + if (!hdcp1_handle->feature_supported) { + pr_err("HDCP 1.x not supported\n"); + return -EINVAL; + } + + if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("%s app not loaded\n", HDCP1OPS_APP_NAME); + return -EINVAL; + } + + handle = hdcp1_handle->hdcpops_handle; + topology = (struct hdcp1_topology *)topo; + + /* set keys and request aksv */ + ops_notify_req = (struct hdcp1_ops_notify_req *)handle->sbuf; + ops_notify_req->commandid = HDCP1_NOTIFY_TOPOLOGY; + ops_notify_req->device_type = DEVICE_TYPE_DP; + ops_notify_req->is_authenticated = is_authenticated; + ops_notify_req->topology.depth = topology->depth; + ops_notify_req->topology.device_count = topology->device_count; + ops_notify_req->topology.max_devices_exceeded = + topology->max_devices_exceeded; + ops_notify_req->topology.max_cascade_exceeded = + topology->max_cascade_exceeded; + + /* + * For hdcp1.4 below two nodes are not applicable but as + * TZ ops ta talks with other drivers with same structure + * and want to maintain same interface across hdcp versions, + * we are setting the values to 0. + */ + ops_notify_req->topology.hdcp2LegacyDeviceDownstream = 0; + ops_notify_req->topology.hdcp1DeviceDownstream = 0; + + memset(ops_notify_req->recv_id_list, 0, + sizeof(uint8_t) * MAX_REC_ID_LIST_SIZE); + + ops_notify_rsp = + (struct hdcp1_ops_notify_rsp *)(handle->sbuf + + QSEECOM_ALIGN(sizeof(struct hdcp1_ops_notify_req))); + rc = qseecom_send_command( + handle, ops_notify_req, + QSEECOM_ALIGN(sizeof(struct hdcp1_ops_notify_req)), ops_notify_rsp, + QSEECOM_ALIGN(sizeof(struct hdcp1_ops_notify_rsp))); + + rc = ops_notify_rsp->ret; + if (rc < 0) { + pr_warn("Ops notify cmd failed, rsp=%d\n", ops_notify_rsp->ret); + return -EINVAL; + } + + pr_debug("ops notify success\n"); + return 0; +} + +int hdcp1_start_qseecom(void *data, u32 *aksv_msb, u32 *aksv_lsb) +{ + int rc = 0; + struct hdcp1_qsee_handle *handle = data; + + if (!aksv_msb || !aksv_lsb) { + pr_err("invalid aksv output buffer\n"); + rc = -EINVAL; + goto error; + } + + if (!handle) { + pr_err("invalid handle\n"); + rc = -EINVAL; + goto error; + } + + if (!handle->feature_supported) { + pr_err("feature not supported\n"); + rc = -EINVAL; + goto error; + } + + if (handle->hdcp_state & HDCP_STATE_APP_LOADED) { + pr_debug("%s app already loaded\n", handle->app_name); + goto error; + } + + rc = hdcp1_app_load(handle); + if (rc) + goto error; + + rc = hdcp1_set_key(handle, aksv_msb, aksv_lsb); + if (rc) + goto key_error; + + pr_debug("success\n"); + return rc; + +key_error: + hdcp1_app_unload(handle); +error: + return rc; +} + +void hdcp1_stop_qseecom(void *data) +{ + struct hdcp1_qsee_handle *hdcp1_handle = data; + + if (!hdcp1_handle || !hdcp1_handle->qseecom_handle || + !hdcp1_handle->hdcpops_handle) { + pr_err("invalid handle\n"); + return; + } + + if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_debug("%s app not loaded\n", hdcp1_handle->app_name); + return; + } + + hdcp1_app_unload(hdcp1_handle); +} + +static int hdcp2_app_init_legacy(struct hdcp2_qsee_handle *handle) { int rc = 0; @@ -660,88 +695,7 @@ error: return rc; } -static int hdcp2_app_init(struct hdcp2_handle *handle) -{ - int rc = 0; - uint32_t app_minor_version = 0; - - hdcp2_app_init_var(init); - - if (handle->legacy_app) { - pr_err("wrong init function\n"); - rc = -EINVAL; - goto error; - } - - if (handle->hdcp_state & HDCP_STATE_APP_LOADED) { - pr_err("library already loaded\n"); - goto error; - } - - req_buf->clientversion = - HDCP_CLIENT_MAKE_VERSION(HDCP_CLIENT_MAJOR_VERSION, - HDCP_CLIENT_MINOR_VERSION, - HDCP_CLIENT_PATCH_VERSION); - - rc = hdcp2_app_process_cmd(init); - if (rc) - goto error; - - app_minor_version = HCDP_TXMTR_GET_MINOR_VERSION(rsp_buf->appversion); - if (app_minor_version != HDCP_CLIENT_MINOR_VERSION) { - pr_err - ("client-app minor version mismatch app(%d), client(%d)\n", - app_minor_version, HDCP_CLIENT_MINOR_VERSION); - rc = -1; - goto error; - } - - pr_debug("success\n"); - - pr_debug("client version major(%d), minor(%d), patch(%d)\n", - HDCP_CLIENT_MAJOR_VERSION, HDCP_CLIENT_MINOR_VERSION, - HDCP_CLIENT_PATCH_VERSION); - - pr_debug("app version major(%d), minor(%d), patch(%d)\n", - HCDP_TXMTR_GET_MAJOR_VERSION(rsp_buf->appversion), - HCDP_TXMTR_GET_MINOR_VERSION(rsp_buf->appversion), - HCDP_TXMTR_GET_PATCH_VERSION(rsp_buf->appversion)); -error: - return rc; -} - -static int hdcp2_app_tx_init(struct hdcp2_handle *handle) -{ - int rc = 0; - - hdcp2_app_init_var(tx_init); - - if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) { - pr_err("session not initialized\n"); - rc = -EINVAL; - goto error; - } - - if (handle->hdcp_state & HDCP_STATE_TXMTR_INIT) { - pr_err("txmtr already initialized\n"); - goto error; - } - - req_buf->sessionid = handle->session_id; - - rc = hdcp2_app_process_cmd(tx_init); - if (rc) - goto error; - - handle->tz_ctxhandle = rsp_buf->ctxhandle; - handle->hdcp_state |= HDCP_STATE_TXMTR_INIT; - - pr_debug("success\n"); -error: - return rc; -} - -static int hdcp2_app_tx_init_legacy(struct hdcp2_handle *handle) +static int hdcp2_app_tx_init_legacy(struct hdcp2_qsee_handle *handle) { int rc = 0; @@ -774,7 +728,114 @@ error: return rc; } -static int hdcp2_app_load(struct hdcp2_handle *handle) +static int hdcp2_app_init(struct hdcp2_qsee_handle *handle) +{ + int rc = 0; + uint32_t app_minor_version = 0; + + hdcp2_app_init_var(init); + + if (handle->legacy_app) { + pr_err("wrong init function\n"); + rc = -EINVAL; + goto error; + } + + if (handle->hdcp_state & HDCP_STATE_APP_LOADED) { + pr_err("library already loaded\n"); + goto error; + } + + req_buf->clientversion = HDCP_CLIENT_MAKE_VERSION( + HDCP_CLIENT_MAJOR_VERSION, HDCP_CLIENT_MINOR_VERSION, + HDCP_CLIENT_PATCH_VERSION); + + rc = hdcp2_app_process_cmd(init); + if (rc) + goto error; + + app_minor_version = HCDP_TXMTR_GET_MINOR_VERSION(rsp_buf->appversion); + if (app_minor_version != HDCP_CLIENT_MINOR_VERSION) { + pr_err("client-app minor version mismatch app(%d), client(%d)\n", + app_minor_version, HDCP_CLIENT_MINOR_VERSION); + rc = -1; + goto error; + } + + pr_debug("success\n"); + + pr_debug("client version major(%d), minor(%d), patch(%d)\n", + HDCP_CLIENT_MAJOR_VERSION, HDCP_CLIENT_MINOR_VERSION, + HDCP_CLIENT_PATCH_VERSION); + + pr_debug("app version major(%d), minor(%d), patch(%d)\n", + HCDP_TXMTR_GET_MAJOR_VERSION(rsp_buf->appversion), + HCDP_TXMTR_GET_MINOR_VERSION(rsp_buf->appversion), + HCDP_TXMTR_GET_PATCH_VERSION(rsp_buf->appversion)); +error: + return rc; +} + +static int hdcp2_app_tx_init(struct hdcp2_qsee_handle *handle) +{ + int rc = 0; + + hdcp2_app_init_var(tx_init); + + if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) { + pr_err("session not initialized\n"); + rc = -EINVAL; + goto error; + } + + if (handle->hdcp_state & HDCP_STATE_TXMTR_INIT) { + pr_err("txmtr already initialized\n"); + goto error; + } + + req_buf->sessionid = handle->session_id; + + rc = hdcp2_app_process_cmd(tx_init); + if (rc) + goto error; + + handle->tz_ctxhandle = rsp_buf->ctxhandle; + handle->hdcp_state |= HDCP_STATE_TXMTR_INIT; + + pr_debug("success\n"); +error: + return rc; +} + +static int hdcp_get_version(struct hdcp2_qsee_handle *handle) +{ + int rc = 0; + uint32_t app_major_version = 0; + + hdcp2_app_init_var(version); + + if (handle->hdcp_state & HDCP_STATE_APP_LOADED) { + pr_err("library already loaded\n"); + goto error; + } + + rc = hdcp2_app_process_cmd(version); + if (rc) + goto error; + + app_major_version = HCDP_TXMTR_GET_MAJOR_VERSION(rsp_buf->appversion); + + pr_debug("hdp2p2 app major version %d, app version %d\n", app_major_version, + rsp_buf->appversion); + + if (app_major_version == 1) + handle->legacy_app = true; + +error: + return rc; +} + +static int hdcp2_app_load(struct hdcp2_qsee_handle *handle) { int rc = 0; @@ -789,20 +850,27 @@ static int hdcp2_app_load(struct hdcp2_handle *handle) goto error; } - rc = qseecom_start_app(&handle->qseecom_handle, - handle->app_name, QSEECOM_SBUFF_SIZE); - if (rc) { - pr_err("qseecom_start_app failed for HDCP2P2 (%d)\n", rc); - goto error; + if (!qseecom_handle_g) { + rc = qseecom_start_app(&qseecom_handle_g, + handle->app_name, QSEECOM_SBUFF_SIZE); + if (rc) { + pr_err("qseecom_start_app failed for HDCP2P2 (%d)\n", rc); + goto error; + } } - rc = qseecom_start_app(&handle->hdcpsrm_qseecom_handle, - HDCPSRM_APP_NAME, QSEECOM_SBUFF_SIZE); - if (rc) { - pr_err("qseecom_start_app failed for HDCPSRM (%d)\n", rc); - goto hdcpsrm_error; + handle->qseecom_handle = qseecom_handle_g; + + if (!hdcpsrm_qseecom_handle_g) { + rc = qseecom_start_app(&hdcpsrm_qseecom_handle_g, + HDCPSRM_APP_NAME, QSEECOM_SBUFF_SIZE); + if (rc) { + pr_err("qseecom_start_app failed for HDCPSRM (%d)\n", rc); + goto hdcpsrm_error; + } } + handle->hdcpsrm_qseecom_handle = hdcpsrm_qseecom_handle_g; pr_debug("qseecom_start_app success\n"); rc = hdcp_get_version(handle); @@ -819,103 +887,35 @@ static int hdcp2_app_load(struct hdcp2_handle *handle) handle->tx_init = hdcp2_app_tx_init; } - rc = handle->app_init(handle); - if (rc) { - pr_err("app init failed\n"); - goto get_version_error; + if (!hdcp2_app_started) { + rc = handle->app_init(handle); + if (rc) { + pr_err("app init failed\n"); + goto get_version_error; + } } + hdcp2_app_started++; + handle->hdcp_state |= HDCP_STATE_APP_LOADED; - return rc; get_version_error: - qseecom_shutdown_app(&handle->hdcpsrm_qseecom_handle); + if (!hdcp2_app_started) { + qseecom_shutdown_app(&hdcpsrm_qseecom_handle_g); + hdcpsrm_qseecom_handle_g = NULL; + } + handle->hdcpsrm_qseecom_handle = NULL; hdcpsrm_error: - qseecom_shutdown_app(&handle->qseecom_handle); + if (!hdcp2_app_started) { + qseecom_shutdown_app(&qseecom_handle_g); + qseecom_handle_g = NULL; + } + handle->qseecom_handle = NULL; error: return rc; } -static int hdcp2_app_unload(struct hdcp2_handle *handle) -{ - int rc = 0; - - hdcp2_app_init_var(deinit); - - hdcp2_app_process_cmd(deinit); - - /* deallocate the resources for qseecom HDCPSRM handle */ - rc = qseecom_shutdown_app(&handle->hdcpsrm_qseecom_handle); - if (rc) - pr_err("qseecom_shutdown_app failed for HDCPSRM (%d)\n", rc); - - /* deallocate the resources for qseecom HDCP2P2 handle */ - rc = qseecom_shutdown_app(&handle->qseecom_handle); - if (rc) { - pr_err("qseecom_shutdown_app failed for HDCP2P2 (%d)\n", rc); - return rc; - } - - handle->hdcp_state &= ~HDCP_STATE_APP_LOADED; - pr_debug("%s app unloaded\n", handle->app_name); - - return rc; -error: - qseecom_shutdown_app(&handle->hdcpsrm_qseecom_handle); - return rc; -} - -static int hdcp2_verify_key(struct hdcp2_handle *handle) -{ - int rc = 0; - - hdcp2_app_init_var(verify_key); - - if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { - pr_err("%s app not loaded\n", handle->app_name); - rc = -EINVAL; - goto error; - } - - rc = hdcp2_app_process_cmd(verify_key); - pr_debug("verify_key = %d\n", rc); - -error: - return rc; -} - -bool hdcp2_feature_supported(void *data) -{ - int rc = 0; - bool supported = false; - struct hdcp2_handle *handle = data; - - if (!handle) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto error; - } - - if (handle->feature_supported) { - supported = true; - goto error; - } - - rc = hdcp2_app_load(handle); - if (!rc) { - if (!hdcp2_verify_key(handle)) { - pr_debug("HDCP 2.2 supported\n"); - handle->feature_supported = true; - supported = true; - } - hdcp2_app_unload(handle); - } -error: - return supported; -} -EXPORT_SYMBOL(hdcp2_feature_supported); - -static int hdcp2_app_session_init(struct hdcp2_handle *handle) +static int hdcp2_app_session_init(struct hdcp2_qsee_handle *handle) { int rc = 0; @@ -954,105 +954,70 @@ error: return rc; } -static int hdcp2_app_session_deinit(struct hdcp2_handle *handle) +void *hdcp2_init_qseecom(u32 device_type) { - int rc = 0; + struct hdcp2_qsee_handle *handle = + kzalloc(sizeof(struct hdcp2_qsee_handle), GFP_KERNEL); - hdcp2_app_init_var(session_deinit); - - if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { - pr_err("%s app not loaded\n", handle->app_name); - rc = -EINVAL; + if (!handle) goto error; + + handle->device_type = device_type; + handle->app_name = HDCP2P2_APP_NAME; + + handle->res_buf = kmalloc(QSEECOM_SBUFF_SIZE, GFP_KERNEL); + if (!handle->res_buf) { + kfree_sensitive(handle); + return NULL; } - if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) { - pr_err("session not initialized\n"); - rc = -EINVAL; - goto error; + handle->req_buf = kmalloc(QSEECOM_SBUFF_SIZE, GFP_KERNEL); + if (!handle->req_buf) { + kfree_sensitive(handle->res_buf); + kfree_sensitive(handle); + return NULL; } - req_buf->sessionid = handle->session_id; - - rc = hdcp2_app_process_cmd(session_deinit); - if (rc) - goto error; - - handle->hdcp_state &= ~HDCP_STATE_SESSION_INIT; - pr_debug("success\n"); + handle->app_data.request.data = handle->req_buf; + handle->app_data.response.data = handle->res_buf; error: - return rc; + return handle; } -static int hdcp2_app_tx_deinit(struct hdcp2_handle *handle) +void hdcp2_deinit_qseecom(void *ctx) { + struct hdcp2_qsee_handle *handle = NULL; int rc = 0; - hdcp2_app_init_var(tx_deinit); + handle = ctx; - if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { - pr_err("%s app not loaded\n", handle->app_name); + if (!handle) { + pr_err("invalid handle\n"); rc = -EINVAL; goto error; } - if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) { - pr_err("txmtr not initialized\n"); - rc = -EINVAL; - goto error; - } + kfree_sensitive(handle->res_buf); + kfree_sensitive(handle->req_buf); - req_buf->ctxhandle = handle->tz_ctxhandle; - - rc = hdcp2_app_process_cmd(tx_deinit); - if (rc) - goto error; - - handle->hdcp_state &= ~HDCP_STATE_TXMTR_INIT; - pr_debug("success\n"); error: - return rc; + kfree_sensitive(ctx); } -static int hdcp2_app_start_auth(struct hdcp2_handle *handle) +int hdcp2_app_start_qseecom(void *ctx, uint32_t req_len) { + struct hdcp2_qsee_handle *handle = NULL; int rc = 0; - hdcp2_app_init_var(start_auth); + handle = ctx; - if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) { - pr_err("session not initialized\n"); + if (!handle) { + pr_err("invalid handle\n"); rc = -EINVAL; goto error; } - if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) { - pr_err("txmtr not initialized\n"); - rc = -EINVAL; - goto error; - } - - req_buf->ctxHandle = handle->tz_ctxhandle; - - rc = hdcp2_app_process_cmd(start_auth); - if (rc) - goto error; - - handle->app_data.response.data = rsp_buf->message; - handle->app_data.response.length = rsp_buf->msglen; - handle->app_data.timeout = rsp_buf->timeout; - handle->app_data.repeater_flag = false; - - handle->tz_ctxhandle = rsp_buf->ctxhandle; - - pr_debug("success\n"); -error: - return rc; -} - -static int hdcp2_app_start(struct hdcp2_handle *handle) -{ - int rc = 0; + handle->app_data.request.length = req_len; rc = hdcp2_app_load(handle); if (rc) @@ -1076,31 +1041,67 @@ error: return rc; } -static int hdcp2_app_stop(struct hdcp2_handle *handle) +int hdcp2_app_start_auth_qseecom(void *ctx, uint32_t req_len) { int rc = 0; + struct hdcp2_qsee_handle *handle = (struct hdcp2_qsee_handle *)ctx; - rc = hdcp2_app_tx_deinit(handle); - if (rc) - goto end; + hdcp2_app_init_var(start_auth); - if (!handle->legacy_app) { - rc = hdcp2_app_session_deinit(handle); - if (rc) - goto end; + if (!handle) { + pr_err("invalid handle\n"); + rc = -EINVAL; + goto error; } - rc = hdcp2_app_unload(handle); -end: + handle->app_data.request.length = req_len; + + if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) { + pr_err("session not initialized\n"); + rc = -EINVAL; + goto error; + } + + if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) { + pr_err("txmtr not initialized\n"); + rc = -EINVAL; + goto error; + } + + req_buf->ctxHandle = handle->tz_ctxhandle; + + rc = hdcp2_app_process_cmd(start_auth); + if (rc) + goto error; + + memcpy(handle->res_buf, rsp_buf->message, rsp_buf->msglen); + + handle->app_data.response.length = rsp_buf->msglen; + handle->app_data.timeout = rsp_buf->timeout; + handle->app_data.repeater_flag = false; + + handle->tz_ctxhandle = rsp_buf->ctxhandle; + + pr_debug("success\n"); +error: return rc; } -static int hdcp2_app_process_msg(struct hdcp2_handle *handle) +int hdcp2_app_process_msg_qseecom(void *ctx, uint32_t req_len) { int rc = 0; + struct hdcp2_qsee_handle *handle = (struct hdcp2_qsee_handle *)ctx; hdcp2_app_init_var(rcvd_msg); + if (!handle) { + pr_err("invalid handle\n"); + rc = -EINVAL; + goto error; + } + + handle->app_data.request.length = req_len; + if (!handle->app_data.request.data) { pr_err("invalid request buffer\n"); rc = -EINVAL; @@ -1110,6 +1111,8 @@ static int hdcp2_app_process_msg(struct hdcp2_handle *handle) req_buf->msglen = handle->app_data.request.length; req_buf->ctxhandle = handle->tz_ctxhandle; + memcpy(req_buf->msg, handle->req_buf, handle->app_data.request.length); + rc = hdcp2_app_process_cmd(rcvd_msg); if (rc) goto error; @@ -1118,36 +1121,57 @@ static int hdcp2_app_process_msg(struct hdcp2_handle *handle) if (rsp_buf->flag == HDCP_TXMTR_SUBSTATE_WAITING_FOR_RECIEVERID_LIST) handle->app_data.repeater_flag = true; - handle->app_data.response.data = rsp_buf->msg; + memcpy(handle->res_buf, rsp_buf->msg, rsp_buf->msglen); + handle->app_data.response.length = rsp_buf->msglen; handle->app_data.timeout = rsp_buf->timeout; + error: return rc; } -static int hdcp2_app_timeout(struct hdcp2_handle *handle) +int hdcp2_app_timeout_qseecom(void *ctx, uint32_t req_len) { int rc = 0; + struct hdcp2_qsee_handle *handle = (struct hdcp2_qsee_handle *)ctx; hdcp2_app_init_var(send_timeout); + if (!handle) { + pr_err("invalid handle\n"); + rc = -EINVAL; + goto error; + } + + handle->app_data.request.length = req_len; + rc = hdcp2_app_process_cmd(send_timeout); if (rc) goto error; - handle->app_data.response.data = rsp_buf->message; + memcpy(handle->res_buf, rsp_buf->message, rsp_buf->msglen); + handle->app_data.response.length = rsp_buf->msglen; handle->app_data.timeout = rsp_buf->timeout; error: return rc; } -static int hdcp2_app_enable_encryption(struct hdcp2_handle *handle) +int hdcp2_app_enable_encryption_qseecom(void *ctx, uint32_t req_len) { int rc = 0; + struct hdcp2_qsee_handle *handle = (struct hdcp2_qsee_handle *)ctx; hdcp2_app_init_var(set_hw_key); + if (!handle) { + pr_err("Invalid handle\n"); + rc = -EINVAL; + goto error; + } + + handle->app_data.request.length = req_len; + /* * wait at least 200ms before enabling encryption * as per hdcp2p2 specifications. @@ -1161,19 +1185,108 @@ static int hdcp2_app_enable_encryption(struct hdcp2_handle *handle) goto error; handle->hdcp_state |= HDCP_STATE_AUTHENTICATED; - - pr_debug("success\n"); - return rc; error: return rc; } -static int hdcp2_force_encryption_utility(struct hdcp2_handle *handle, - uint32_t enable) +int hdcp2_app_query_stream_qseecom(void *ctx, uint32_t req_len) { int rc = 0; + struct hdcp2_qsee_handle *handle = (struct hdcp2_qsee_handle *)ctx; + + hdcp2_app_init_var(query_stream_type); + + if (!handle) { + pr_err("Invalid handle\n"); + rc = -EINVAL; + goto error; + } + + handle->app_data.request.length = req_len; + + req_buf->ctxhandle = handle->tz_ctxhandle; + + rc = hdcp2_app_process_cmd(query_stream_type); + if (rc) + goto error; + + memcpy(handle->res_buf, rsp_buf->msg, rsp_buf->msglen); + + handle->app_data.response.length = rsp_buf->msglen; + handle->app_data.timeout = rsp_buf->timeout; +error: + return rc; +} + +int hdcp2_app_stop_qseecom(void *ctx) +{ + int rc = 0; + struct hdcp2_qsee_handle *handle = (struct hdcp2_qsee_handle *)ctx; + + if (!handle) { + pr_err("Invalid handle\n"); + rc = -EINVAL; + goto error; + } + + rc = hdcp2_app_tx_deinit(handle); + if (rc) + goto error; + + if (!handle->legacy_app) { + rc = hdcp2_app_session_deinit(handle); + if (rc) + goto error; + } + + rc = hdcp2_app_unload(handle); +error: + return rc; +} + +bool hdcp2_feature_supported_qseecom(void *ctx) +{ + int rc = 0; + bool supported = false; + struct hdcp2_qsee_handle *handle = (struct hdcp2_qsee_handle *)ctx; + + if (!handle) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto error; + } + + if (handle->feature_supported) { + supported = true; + goto error; + } + + rc = hdcp2_app_load(handle); + if (!rc) { + if (!hdcp2_verify_key(handle)) { + pr_debug("HDCP 2.2 supported\n"); + handle->feature_supported = true; + supported = true; + } + hdcp2_app_unload(handle); + } +error: + return supported; +} + +int hdcp2_force_encryption_qseecom(void *ctx, uint32_t enable) +{ + int rc = 0; + struct hdcp2_qsee_handle *handle = (struct hdcp2_qsee_handle *)ctx; hdcp2_app_init_var(force_encryption); + + if (!handle) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto error; + } + if (handle->hdcp_state == HDCP_STATE_AUTHENTICATED) msleep(SLEEP_FORCE_ENCRYPTION_MS); @@ -1184,129 +1297,24 @@ static int hdcp2_force_encryption_utility(struct hdcp2_handle *handle, if (rc || (rsp_buf->commandid != hdcp_cmd_force_encryption)) goto error; - return 0; error: return rc; } -int hdcp2_force_encryption(void *ctx, uint32_t enable) -{ - int rc = 0; - struct hdcp2_handle *handle = NULL; - - if (!ctx) { - pr_err("invalid input\n"); - return -EINVAL; - } - - handle = ctx; - rc = hdcp2_force_encryption_utility(handle, enable); - if (rc) - goto error; - - pr_debug("success\n"); - return 0; -error: - pr_err("failed, rc=%d\n", rc); - return rc; -} -EXPORT_SYMBOL(hdcp2_force_encryption); - -static int hdcp2_app_query_stream(struct hdcp2_handle *handle) -{ - int rc = 0; - - hdcp2_app_init_var(query_stream_type); - - req_buf->ctxhandle = handle->tz_ctxhandle; - - rc = hdcp2_app_process_cmd(query_stream_type); - if (rc) - goto error; - - handle->app_data.response.data = rsp_buf->msg; - handle->app_data.response.length = rsp_buf->msglen; - handle->app_data.timeout = rsp_buf->timeout; -error: - return rc; -} - -static unsigned char *hdcp2_get_recv_buf(struct hdcp2_handle *handle) -{ - struct hdcp_rcvd_msg_req *req_buf; - - req_buf = (struct hdcp_rcvd_msg_req *)(handle->qseecom_handle->sbuf); - return req_buf->msg; -} - -int hdcp2_app_comm(void *ctx, enum hdcp2_app_cmd cmd, - struct hdcp2_app_data *app_data) -{ - struct hdcp2_handle *handle = NULL; - int rc = 0; - - if (!ctx || !app_data) { - pr_err("invalid input\n"); - return -EINVAL; - } - - handle = ctx; - handle->app_data.request.length = app_data->request.length; - - pr_debug("command %s\n", hdcp2_app_cmd_str(cmd)); - - switch (cmd) { - case HDCP2_CMD_START: - rc = hdcp2_app_start(handle); - break; - case HDCP2_CMD_START_AUTH: - rc = hdcp2_app_start_auth(handle); - break; - case HDCP2_CMD_PROCESS_MSG: - rc = hdcp2_app_process_msg(handle); - break; - case HDCP2_CMD_TIMEOUT: - rc = hdcp2_app_timeout(handle); - break; - case HDCP2_CMD_EN_ENCRYPTION: - rc = hdcp2_app_enable_encryption(handle); - break; - case HDCP2_CMD_QUERY_STREAM: - rc = hdcp2_app_query_stream(handle); - break; - case HDCP2_CMD_STOP: - rc = hdcp2_app_stop(handle); - goto error; - default: - rc = -EINVAL; - break; - } - - if (rc) - goto error; - - handle->app_data.request.data = hdcp2_get_recv_buf(handle); - - app_data->request.data = handle->app_data.request.data; - app_data->request.length = handle->app_data.request.length; - app_data->response.data = handle->app_data.response.data; - app_data->response.length = handle->app_data.response.length; - app_data->timeout = handle->app_data.timeout; - app_data->repeater_flag = handle->app_data.repeater_flag; -error: - return rc; -} -EXPORT_SYMBOL(hdcp2_app_comm); - -static int hdcp2_open_stream_helper(struct hdcp2_handle *handle, - uint8_t vc_payload_id, - uint8_t stream_number, - uint32_t *stream_id) +int hdcp2_open_stream_qseecom(void *ctx, uint8_t vc_payload_id, + uint8_t stream_number, uint32_t *stream_id) { + struct hdcp2_qsee_handle *handle = (struct hdcp2_qsee_handle *)ctx; int rc = 0; hdcp2_app_init_var(session_open_stream); + if (!handle) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto error; + } + if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) { pr_err("session not initialized\n"); rc = -EINVAL; @@ -1336,30 +1344,19 @@ error: return rc; } -int hdcp2_open_stream(void *ctx, uint8_t vc_payload_id, uint8_t stream_number, - uint32_t *stream_id) -{ - struct hdcp2_handle *handle = NULL; - - if (!ctx) { - pr_err("invalid input\n"); - return -EINVAL; - } - - handle = ctx; - - return hdcp2_open_stream_helper(handle, vc_payload_id, stream_number, - stream_id); -} -EXPORT_SYMBOL(hdcp2_open_stream); - -static int hdcp2_close_stream_helper(struct hdcp2_handle *handle, - uint32_t stream_id) +int hdcp2_close_stream_qseecom(void *ctx, uint32_t stream_id) { + struct hdcp2_qsee_handle *handle = (struct hdcp2_qsee_handle *)ctx; int rc = 0; hdcp2_app_init_var(session_close_stream); + if (!handle) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto error; + } + if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) { pr_err("session not initialized\n"); rc = -EINVAL; @@ -1376,7 +1373,6 @@ static int hdcp2_close_stream_helper(struct hdcp2_handle *handle, req_buf->streamid = stream_id; rc = hdcp2_app_process_cmd(session_close_stream); - if (rc) goto error; @@ -1385,485 +1381,24 @@ error: return rc; } -int hdcp2_close_stream(void *ctx, uint32_t stream_id) +int hdcp2_update_app_data_qseecom(void *ctx, struct hdcp2_app_data *app_data) { - struct hdcp2_handle *handle = NULL; + int rc = 0; + struct hdcp2_qsee_handle *handle = (struct hdcp2_qsee_handle *)ctx; - if (!ctx) { + if (!handle) { pr_err("invalid input\n"); - return -EINVAL; - } - - handle = ctx; - - return hdcp2_close_stream_helper(handle, stream_id); -} -EXPORT_SYMBOL(hdcp2_close_stream); - -void *hdcp2_init(u32 device_type) -{ - struct hdcp2_handle *handle = NULL; - - handle = kzalloc(sizeof(struct hdcp2_handle), GFP_KERNEL); - if (!handle) - goto error; - - handle->device_type = device_type; - handle->app_name = HDCP2P2_APP_NAME; -error: - return handle; -} -EXPORT_SYMBOL(hdcp2_init); - -void hdcp2_deinit(void *ctx) -{ - kfree_sensitive(ctx); -} -EXPORT_SYMBOL(hdcp2_deinit); - -void *hdcp1_init(void) -{ - struct hdcp1_handle *handle = - kzalloc(sizeof(struct hdcp1_handle), GFP_KERNEL); - - if (!handle) - goto error; - - handle->app_name = HDCP1_APP_NAME; -error: - return handle; -} -EXPORT_SYMBOL(hdcp1_init); - -void hdcp1_deinit(void *data) -{ - kfree(data); -} -EXPORT_SYMBOL(hdcp1_deinit); - -static int hdcp1_count_ones(u8 *array, u8 len) -{ - int i, j, count = 0; - - for (i = 0; i < len; i++) - for (j = 0; j < 8; j++) - count += (((array[i] >> j) & 0x1) ? 1 : 0); - return count; -} - -static int hdcp1_validate_aksv(u32 aksv_msb, u32 aksv_lsb) -{ - int const number_of_ones = 20; - u8 aksv[5]; - - pr_debug("AKSV=%02x%08x\n", aksv_msb, aksv_lsb); - - aksv[0] = aksv_lsb & 0xFF; - aksv[1] = (aksv_lsb >> 8) & 0xFF; - aksv[2] = (aksv_lsb >> 16) & 0xFF; - aksv[3] = (aksv_lsb >> 24) & 0xFF; - aksv[4] = aksv_msb & 0xFF; - - /* check there are 20 ones in AKSV */ - if (hdcp1_count_ones(aksv, 5) != number_of_ones) { - pr_err("AKSV bit count failed\n"); - return -EINVAL; - } - - return 0; -} - - -static int hdcp1_set_key(struct hdcp1_handle *hdcp1_handle, u32 *aksv_msb, - u32 *aksv_lsb) -{ - int rc = 0; - struct hdcp1_key_set_req *key_set_req; - struct hdcp1_key_set_rsp *key_set_rsp; - struct qseecom_handle *handle = NULL; - - if (aksv_msb == NULL || aksv_lsb == NULL) { - pr_err("invalid aksv\n"); - return -EINVAL; - } - - if (!hdcp1_handle || !hdcp1_handle->qseecom_handle) { - pr_err("invalid HDCP 1.x handle\n"); - return -EINVAL; - } - - if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { - pr_err("%s app not loaded\n", hdcp1_handle->app_name); - return -EINVAL; - } - - handle = hdcp1_handle->qseecom_handle; - - /* set keys and request aksv */ - key_set_req = (struct hdcp1_key_set_req *)handle->sbuf; - key_set_req->commandid = HDCP1_SET_KEY; - key_set_rsp = (struct hdcp1_key_set_rsp *)(handle->sbuf + - QSEECOM_ALIGN(sizeof(struct hdcp1_key_set_req))); - rc = qseecom_send_command(handle, key_set_req, - QSEECOM_ALIGN(sizeof - (struct hdcp1_key_set_req)), - key_set_rsp, - QSEECOM_ALIGN(sizeof - (struct hdcp1_key_set_rsp))); - - if (rc < 0) { - pr_err("qseecom cmd failed err=%d\n", rc); - return -ENOKEY; - } - - rc = key_set_rsp->ret; - if (rc) { - pr_err("set key cmd failed, rsp=%d\n", key_set_rsp->ret); - return -ENOKEY; - } - - /* copy bytes into msb and lsb */ - *aksv_msb = key_set_rsp->ksv[0] << 24 | key_set_rsp->ksv[1] << 16 | - key_set_rsp->ksv[2] << 8 | key_set_rsp->ksv[3]; - *aksv_lsb = key_set_rsp->ksv[4] << 24 | key_set_rsp->ksv[5] << 16 | - key_set_rsp->ksv[6] << 8 | key_set_rsp->ksv[7]; - - rc = hdcp1_validate_aksv(*aksv_msb, *aksv_lsb); - if (rc) { - pr_err("aksv validation failed (%d)\n", rc); - return rc; - } - - return 0; -} - -static int hdcp1_app_load(struct hdcp1_handle *handle) -{ - int rc = 0; - - if (!handle) { - pr_err("invalid handle\n"); - goto error; - } - - rc = qseecom_start_app(&handle->qseecom_handle, handle->app_name, - QSEECOM_SBUFF_SIZE); - if (rc) { - pr_err("%s app load failed (%d)\n", handle->app_name, rc); - goto error; - } - - rc = qseecom_start_app(&handle->hdcpops_handle, HDCP1OPS_APP_NAME, - QSEECOM_SBUFF_SIZE); - if (rc) { - pr_warn("%s app load failed (%d)\n", HDCP1OPS_APP_NAME, rc); - handle->hdcpops_handle = NULL; - } - - handle->hdcp_state |= HDCP_STATE_APP_LOADED; - pr_debug("%s app loaded\n", handle->app_name); - -error: - return rc; -} - -static void hdcp1_app_unload(struct hdcp1_handle *handle) -{ - int rc = 0; - - if (!handle || !handle->qseecom_handle) { - pr_err("invalid handle\n"); - return; - } - - if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { - pr_warn("%s app not loaded\n", handle->app_name); - return; - } - - if (handle->hdcpops_handle) { - /* deallocate the resources for HDCP 1.x ops handle */ - rc = qseecom_shutdown_app(&handle->hdcpops_handle); - if (rc) - pr_warn("%s app unload failed (%d)\n", HDCP1OPS_APP_NAME, rc); - } - - /* deallocate the resources for qseecom HDCP 1.x handle */ - rc = qseecom_shutdown_app(&handle->qseecom_handle); - if (rc) { - pr_err("%s app unload failed (%d)\n", handle->app_name, rc); - return; - } - - handle->hdcp_state &= ~HDCP_STATE_APP_LOADED; - pr_debug("%s app unloaded\n", handle->app_name); -} - -static int hdcp1_verify_key(struct hdcp1_handle *hdcp1_handle) -{ - int rc = 0; - struct hdcp1_key_verify_req *key_verify_req; - struct hdcp1_key_verify_rsp *key_verify_rsp; - struct qseecom_handle *handle = NULL; - - if (!hdcp1_handle || !hdcp1_handle->qseecom_handle) { - pr_err("invalid HDCP 1.x handle\n"); - return -EINVAL; - } - - if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { - pr_err("%s app not loaded\n", hdcp1_handle->app_name); - return -EINVAL; - } - - handle = hdcp1_handle->qseecom_handle; - - key_verify_req = (struct hdcp1_key_verify_req *)handle->sbuf; - key_verify_req->commandid = HDCP1_KEY_VERIFY; - key_verify_rsp = (struct hdcp1_key_verify_rsp *)(handle->sbuf + - QSEECOM_ALIGN(sizeof(struct hdcp1_key_verify_req))); - rc = qseecom_send_command(handle, key_verify_req, - QSEECOM_ALIGN(sizeof - (struct hdcp1_key_verify_req)), - key_verify_rsp, - QSEECOM_ALIGN(sizeof - (struct hdcp1_key_set_rsp))); - - if (rc < 0) { - pr_err("command HDCP1_KEY_VERIFY failed (%d)\n", rc); - return -EINVAL; - } - - rc = key_verify_rsp->ret; - if (rc) { - pr_err("key_verify failed, rsp=%d\n", key_verify_rsp->ret); - return -EINVAL; - } - - pr_debug("success\n"); - - return 0; -} - -bool hdcp1_feature_supported(void *data) -{ - bool supported = false; - struct hdcp1_handle *handle = data; - int rc = 0; - - if (!handle) { - pr_err("invalid handle\n"); - goto error; - } - - if (handle->feature_supported) { - supported = true; - goto error; - } - - rc = hdcp1_app_load(handle); - if (!rc && (handle->hdcp_state & HDCP_STATE_APP_LOADED)) { - if (!hdcp1_verify_key(handle)) { - pr_debug("HDCP 1.x supported\n"); - handle->feature_supported = true; - supported = true; - } - hdcp1_app_unload(handle); - } -error: - return supported; -} -EXPORT_SYMBOL(hdcp1_feature_supported); - -int hdcp1_set_enc(void *data, bool enable) -{ - int rc = 0; - struct hdcp1_set_enc_req *set_enc_req; - struct hdcp1_set_enc_rsp *set_enc_rsp; - struct hdcp1_handle *hdcp1_handle = data; - struct qseecom_handle *handle = NULL; - - if (!hdcp1_handle || !hdcp1_handle->qseecom_handle) { - pr_err("invalid HDCP 1.x handle\n"); - return -EINVAL; - } - - if (!hdcp1_handle->feature_supported) { - pr_err("HDCP 1.x not supported\n"); - return -EINVAL; - } - - if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { - pr_err("%s app not loaded\n", hdcp1_handle->app_name); - return -EINVAL; - } - - handle = hdcp1_handle->qseecom_handle; - - /* set keys and request aksv */ - set_enc_req = (struct hdcp1_set_enc_req *)handle->sbuf; - set_enc_req->commandid = HDCP1_SET_ENC; - set_enc_req->enable = enable; - set_enc_rsp = (struct hdcp1_set_enc_rsp *)(handle->sbuf + - QSEECOM_ALIGN(sizeof(struct hdcp1_set_enc_req))); - rc = qseecom_send_command(handle, set_enc_req, - QSEECOM_ALIGN(sizeof - (struct hdcp1_set_enc_req)), - set_enc_rsp, - QSEECOM_ALIGN(sizeof - (struct hdcp1_set_enc_rsp))); - - if (rc < 0) { - pr_err("qseecom cmd failed err=%d\n", rc); - return -EINVAL; - } - - rc = set_enc_rsp->ret; - if (rc) { - pr_err("enc cmd failed, rsp=%d\n", set_enc_rsp->ret); - return -EINVAL; - } - - pr_debug("success\n"); - return 0; -} -EXPORT_SYMBOL(hdcp1_set_enc); - -int hdcp1_ops_notify(void *data, void *topo, bool is_authenticated) -{ - int rc = 0; - struct hdcp1_ops_notify_req *ops_notify_req; - struct hdcp1_ops_notify_rsp *ops_notify_rsp; - struct hdcp1_handle *hdcp1_handle = data; - struct qseecom_handle *handle = NULL; - struct hdcp1_topology *topology = NULL; - - if (!hdcp1_handle || !hdcp1_handle->hdcpops_handle) { - pr_err("invalid HDCP 1.x ops handle\n"); - return -EINVAL; - } - - if (!hdcp1_handle->feature_supported) { - pr_err("HDCP 1.x not supported\n"); - return -EINVAL; - } - - if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { - pr_err("%s app not loaded\n", HDCP1OPS_APP_NAME); - return -EINVAL; - } - - handle = hdcp1_handle->hdcpops_handle; - topology = (struct hdcp1_topology *)topo; - - /* set keys and request aksv */ - ops_notify_req = (struct hdcp1_ops_notify_req *)handle->sbuf; - ops_notify_req->commandid = HDCP1_NOTIFY_TOPOLOGY; - ops_notify_req->device_type = DEVICE_TYPE_DP; - ops_notify_req->is_authenticated = is_authenticated; - ops_notify_req->topology.depth = topology->depth; - ops_notify_req->topology.device_count = topology->device_count; - ops_notify_req->topology.max_devices_exceeded = topology->max_devices_exceeded; - ops_notify_req->topology.max_cascade_exceeded = topology->max_cascade_exceeded; - - /* - * For hdcp1.4 below two nodes are not applicable but as - * TZ ops ta talks with other drivers with same structure - * and want to maintain same interface across hdcp versions, - * we are setting the values to 0. - */ - ops_notify_req->topology.hdcp2LegacyDeviceDownstream = 0; - ops_notify_req->topology.hdcp1DeviceDownstream = 0; - - memset(ops_notify_req->recv_id_list, 0, sizeof(uint8_t) * MAX_REC_ID_LIST_SIZE); - - ops_notify_rsp = (struct hdcp1_ops_notify_rsp *)(handle->sbuf + - QSEECOM_ALIGN(sizeof(struct hdcp1_ops_notify_req))); - rc = qseecom_send_command(handle, ops_notify_req, - QSEECOM_ALIGN(sizeof(struct hdcp1_ops_notify_req)), - ops_notify_rsp, - QSEECOM_ALIGN(sizeof(struct hdcp1_ops_notify_rsp))); - - rc = ops_notify_rsp->ret; - if (rc < 0) { - pr_warn("Ops notify cmd failed, rsp=%d\n", ops_notify_rsp->ret); - return -EINVAL; - } - - pr_debug("ops notify success\n"); - return 0; -} -EXPORT_SYMBOL(hdcp1_ops_notify); - -int hdcp1_start(void *data, u32 *aksv_msb, u32 *aksv_lsb) -{ - int rc = 0; - struct hdcp1_handle *hdcp1_handle = data; - - if (!aksv_msb || !aksv_lsb) { - pr_err("invalid aksv output buffer\n"); rc = -EINVAL; goto error; } - if (!hdcp1_handle) { - pr_err("invalid handle\n"); - rc = -EINVAL; - goto error; - } + app_data->request.data = handle->app_data.request.data; + app_data->request.length = handle->app_data.request.length; + app_data->response.data = handle->app_data.response.data; + app_data->response.length = handle->app_data.response.length; + app_data->timeout = handle->app_data.timeout; + app_data->repeater_flag = handle->app_data.repeater_flag; - if (!hdcp1_handle->feature_supported) { - pr_err("feature not supported\n"); - rc = -EINVAL; - goto error; - } - - if (hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED) { - pr_debug("%s app already loaded\n", hdcp1_handle->app_name); - goto error; - } - - rc = hdcp1_app_load(hdcp1_handle); - if (rc) - goto error; - - rc = hdcp1_set_key(hdcp1_handle, aksv_msb, aksv_lsb); - if (rc) - goto key_error; - - pr_debug("success\n"); - return rc; - -key_error: - hdcp1_app_unload(hdcp1_handle); error: return rc; } -EXPORT_SYMBOL(hdcp1_start); - -void hdcp1_stop(void *data) -{ - struct hdcp1_handle *hdcp1_handle = data; - - if (!hdcp1_handle || !hdcp1_handle->qseecom_handle || !hdcp1_handle->hdcpops_handle) { - pr_err("invalid handle\n"); - return; - } - - if (!(hdcp1_handle->hdcp_state & HDCP_STATE_APP_LOADED)) { - pr_debug("%s app not loaded\n", hdcp1_handle->app_name); - return; - } - - hdcp1_app_unload(hdcp1_handle); -} -EXPORT_SYMBOL(hdcp1_stop); - -static int __init hdcp_module_init(void){ return 0; } -static void __exit hdcp_module_exit(void){ return; } - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("HDCP driver"); - -module_init(hdcp_module_init); -module_exit(hdcp_module_exit); diff --git a/hdcp/hdcp_qseecom.h b/hdcp/hdcp_qseecom.h new file mode 100644 index 0000000000..dfa74b2c3a --- /dev/null +++ b/hdcp/hdcp_qseecom.h @@ -0,0 +1,326 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __HDCP_QSEECOM_H__ +#define __HDCP_QSEECOM_H__ + +#include +#include +#include +#include + +#include "hdcp_main.h" + +struct hdcp1_qsee_handle { + struct qseecom_handle *qseecom_handle; + struct qseecom_handle *hdcpops_handle; + bool feature_supported; + uint32_t device_type; + enum hdcp_state hdcp_state; + char *app_name; +}; + +struct hdcp2_qsee_handle { + struct hdcp2_app_data app_data; + uint32_t tz_ctxhandle; + bool feature_supported; + enum hdcp_state hdcp_state; + struct qseecom_handle *qseecom_handle; + struct qseecom_handle *hdcpsrm_qseecom_handle; + uint32_t session_id; + bool legacy_app; + uint32_t device_type; + char *app_name; + unsigned char *req_buf; + unsigned char *res_buf; + int (*app_init)(struct hdcp2_qsee_handle *handle); + int (*tx_init)(struct hdcp2_qsee_handle *handle); +}; + +struct hdcp1_key_set_req { + uint32_t commandid; +} __packed; + +struct hdcp1_key_set_rsp { + uint32_t commandid; + uint32_t ret; + uint8_t ksv[HDCP1_AKSV_SIZE]; +} __packed; + +struct hdcp1_ops_notify_req { + uint32_t commandid; + uint32_t device_type; + uint8_t recv_id_list[MAX_REC_ID_LIST_SIZE]; + int32_t recv_id_len; + struct hdcp1_topology topology; + bool is_authenticated; +} __packed; + +struct hdcp1_ops_notify_rsp { + uint32_t commandid; + uint32_t ret; +} __packed; + +struct hdcp1_set_enc_req { + uint32_t commandid; + uint32_t enable; +} __packed; + +struct hdcp1_set_enc_rsp { + uint32_t commandid; + uint32_t ret; +} __packed; + +struct hdcp1_key_verify_req { + uint32_t commandid; + uint32_t key_type; +} __packed; + +struct hdcp1_key_verify_rsp { + uint32_t commandId; + uint32_t ret; +} __packed; + +struct hdcp_init_v1_req { + uint32_t commandid; +} __packed; + +struct hdcp_init_v1_rsp { + uint32_t status; + uint32_t commandid; + uint32_t ctxhandle; + uint32_t timeout; + uint32_t msglen; + uint8_t message[MAX_TX_MESSAGE_SIZE]; +} __packed; + +struct hdcp_init_req { + uint32_t commandid; + uint32_t clientversion; +} __packed; + +struct hdcp_init_rsp { + uint32_t status; + uint32_t commandid; + uint32_t appversion; +} __packed; + +struct hdcp_session_init_req { + uint32_t commandid; + uint32_t deviceid; +} __packed; + +struct hdcp_session_init_rsp { + uint32_t status; + uint32_t commandid; + uint32_t sessionid; +} __packed; + +struct hdcp_tx_init_v1_req { + uint32_t commandid; +} __packed; + +struct hdcp_tx_init_v1_rsp { + uint32_t status; + uint32_t commandid; + uint32_t ctxhandle; + uint32_t timeout; + uint32_t msglen; + uint8_t message[MAX_TX_MESSAGE_SIZE]; +} __packed; + +struct hdcp_tx_init_req { + uint32_t commandid; + uint32_t sessionid; +} __packed; + +struct hdcp_tx_init_rsp { + uint32_t status; + uint32_t commandid; + uint32_t ctxhandle; +} __packed; + +struct hdcp_version_req { + uint32_t commandid; +} __packed; + +struct hdcp_version_rsp { + uint32_t status; + uint32_t commandId; + uint32_t appversion; +} __packed; + +struct hdcp_session_open_stream_req { + uint32_t commandid; + uint32_t sessionid; + uint32_t vcpayloadid; + uint32_t stream_number; + uint32_t streamMediaType; +} __packed; + +struct hdcp_session_open_stream_rsp { + uint32_t status; + uint32_t commandid; + uint32_t streamid; +} __packed; + +struct hdcp_session_close_stream_req { + uint32_t commandid; + uint32_t sessionid; + uint32_t streamid; +} __packed; + +struct hdcp_session_close_stream_rsp { + uint32_t status; + uint32_t commandid; +} __packed; + +struct hdcp_force_encryption_req { + uint32_t commandid; + uint32_t ctxhandle; + uint32_t enable; +} __packed; + +struct hdcp_force_encryption_rsp { + uint32_t status; + uint32_t commandid; +} __packed; + +struct hdcp_tx_deinit_req { + uint32_t commandid; + uint32_t ctxhandle; +} __packed; + +struct hdcp_tx_deinit_rsp { + uint32_t status; + uint32_t commandid; +} __packed; + +struct hdcp_session_deinit_req { + uint32_t commandid; + uint32_t sessionid; +} __packed; + +struct hdcp_session_deinit_rsp { + uint32_t status; + uint32_t commandid; +} __packed; + +struct hdcp_deinit_req { + uint32_t commandid; +} __packed; + +struct hdcp_deinit_rsp { + uint32_t status; + uint32_t commandid; +} __packed; + +struct hdcp_query_stream_type_req { + uint32_t commandid; + uint32_t ctxhandle; +} __packed; + +struct hdcp_query_stream_type_rsp { + uint32_t status; + uint32_t commandid; + uint32_t timeout; + uint32_t msglen; + uint8_t msg[MAX_TX_MESSAGE_SIZE]; +} __packed; + +struct hdcp_set_hw_key_req { + uint32_t commandid; + uint32_t ctxhandle; +} __packed; + +struct hdcp_set_hw_key_rsp { + uint32_t status; + uint32_t commandid; +} __packed; + +struct hdcp_send_timeout_req { + uint32_t commandid; + uint32_t ctxhandle; +} __packed; + +struct hdcp_send_timeout_rsp { + uint32_t status; + uint32_t commandid; + uint32_t timeout; + uint32_t msglen; + uint8_t message[MAX_TX_MESSAGE_SIZE]; +} __packed; + +struct hdcp_start_auth_req { + uint32_t commandid; + uint32_t ctxHandle; +} __packed; + +struct hdcp_start_auth_rsp { + uint32_t status; + uint32_t commandid; + uint32_t ctxhandle; + uint32_t timeout; + uint32_t msglen; + uint8_t message[MAX_TX_MESSAGE_SIZE]; +} __packed; + +struct hdcp_rcvd_msg_req { + uint32_t commandid; + uint32_t ctxhandle; + uint32_t msglen; + uint8_t msg[MAX_RX_MESSAGE_SIZE]; +} __packed; + +struct hdcp_rcvd_msg_rsp { + uint32_t status; + uint32_t commandid; + uint32_t state; + uint32_t timeout; + uint32_t flag; + uint32_t msglen; + uint8_t msg[MAX_TX_MESSAGE_SIZE]; +} __packed; + +struct hdcp_verify_key_req { + uint32_t commandid; +} __packed; + +struct hdcp_verify_key_rsp { + uint32_t status; + uint32_t commandId; +} __packed; + +#define HDCP1_SET_KEY 202 +#define HDCP1_KEY_VERIFY 204 +#define HDCP1_SET_ENC 205 + +/* DP device type */ +#define DEVICE_TYPE_DP 0x8002 + +void *hdcp1_init_qseecom(void); +bool hdcp1_feature_supported_qseecom(void *data); +int hdcp1_set_enc_qseecom(void *data, bool enable); +int hdcp1_ops_notify_qseecom(void *data, void *topo, bool is_authenticated); +int hdcp1_start_qseecom(void *data, u32 *aksv_msb, u32 *aksv_lsb); +void hdcp1_stop_qseecom(void *data); + +void *hdcp2_init_qseecom(u32 device_type); +void hdcp2_deinit_qseecom(void *ctx); +int hdcp2_app_start_qseecom(void *ctx, uint32_t req_len); +int hdcp2_app_start_auth_qseecom(void *ctx, uint32_t req_len); +int hdcp2_app_process_msg_qseecom(void *ctx, uint32_t req_len); +int hdcp2_app_timeout_qseecom(void *ctx, uint32_t req_len); +int hdcp2_app_enable_encryption_qseecom(void *ctx, uint32_t req_len); +int hdcp2_app_query_stream_qseecom(void *ctx, uint32_t req_len); +int hdcp2_app_stop_qseecom(void *ctx); +bool hdcp2_feature_supported_qseecom(void *ctx); +int hdcp2_force_encryption_qseecom(void *ctx, uint32_t enable); +int hdcp2_open_stream_qseecom(void *ctx, uint8_t vc_payload_id, + uint8_t stream_number, uint32_t *stream_id); +int hdcp2_close_stream_qseecom(void *ctx, uint32_t stream_id); +int hdcp2_update_app_data_qseecom(void *ctx, struct hdcp2_app_data *app_data); + +#endif /* __HDCP_QSEECOM_H__ */ diff --git a/hdcp/hdcp_smcinvoke.c b/hdcp/hdcp_smcinvoke.c new file mode 100644 index 0000000000..32c37af715 --- /dev/null +++ b/hdcp/hdcp_smcinvoke.c @@ -0,0 +1,1090 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hdcp_main.h" +#include "hdcp_smcinvoke.h" +#include "hdcp1.h" +#include "hdcp1_ops.h" +#include "hdcp2p2.h" + +static int hdcp1_verify_key(struct hdcp1_smcinvoke_handle *handle) +{ + int ret = 0; + + if (!handle) { + pr_err("invalid HDCP 1.x handle\n"); + return -EINVAL; + } + + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("%s app not loaded\n", HDCP1_APP_NAME); + return -EINVAL; + } + + ret = hdcp1_verify(handle->hdcp1_app_obj, 1); + if (ret) + pr_err("hdcp1_verify failed error:%d\n", ret); + + return ret; +} + +static int hdcp1_key_set(struct hdcp1_smcinvoke_handle *handle, + uint32_t *aksv_msb, uint32_t *aksv_lsb) +{ + int ret = 0; + uint8_t *ksvRes = NULL; + size_t ksvResLen = 0; + + ksvRes = kmalloc(HDCP1_AKSV_SIZE, GFP_KERNEL); + if (!ksvRes) + return -EINVAL; + + if (aksv_msb == NULL || aksv_lsb == NULL) { + pr_err("invalid aksv\n"); + return -EINVAL; + } + + if (!handle) { + pr_err("invalid HDCP 1.x handle\n"); + return -EINVAL; + } + + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("hdcp1 app not loaded\n"); + return -EINVAL; + } + + ret = hdcp1_set_key(handle->hdcp1_app_obj, ksvRes, HDCP1_AKSV_SIZE, + &ksvResLen); + if (ret) { + pr_err("hdcp1_set_key failed ret=%d\n", ret); + return -ENOKEY; + } + + /* copy bytes into msb and lsb */ + *aksv_msb = ksvRes[0] << 24 | ksvRes[1] << 16 | ksvRes[2] << 8 | ksvRes[3]; + *aksv_lsb = ksvRes[4] << 24 | ksvRes[5] << 16 | ksvRes[6] << 8 | ksvRes[7]; + + ret = hdcp1_validate_aksv(*aksv_msb, *aksv_lsb); + if (ret) + pr_err("aksv validation failed (%d)\n", ret); + + return ret; +} + +int load_app(char *app_name, struct Object *app_obj, + struct Object *app_controller_obj) +{ + int ret = 0; + uint8_t *buffer = NULL; + struct qtee_shm shm = {0}; + size_t size = 0; + struct Object client_env = {NULL, NULL}; + struct Object app_loader = {NULL, NULL}; + + ret = get_client_env_object(&client_env); + if (ret) { + pr_err("get_client_env_object failed :%d\n", ret); + client_env.invoke = NULL; + client_env.context = NULL; + goto error; + } + + ret = IClientEnv_open(client_env, CAppLoader_UID, &app_loader); + if (ret) { + pr_err("IClientEnv_open failed :%d\n", ret); + app_loader.invoke = NULL; + app_loader.context = NULL; + goto error; + } + + buffer = firmware_request_from_smcinvoke(app_name, &size, &shm); + if (buffer == NULL) { + pr_err("firmware_request_from_smcinvoke failed\n"); + ret = -EINVAL; + goto error; + } + + ret = IAppLoader_loadFromBuffer(app_loader, (const void *)buffer, size, + app_controller_obj); + if (ret) { + pr_err("IAppLoader_loadFromBuffer failed :%d\n", ret); + app_controller_obj->invoke = NULL; + app_controller_obj->context = NULL; + goto error; + } + + ret = IAppController_getAppObject(*app_controller_obj, app_obj); + if (ret) { + pr_err("IAppController_getAppObject failed :%d\n", ret); + goto error; + } + +error: + qtee_shmbridge_free_shm(&shm); + Object_ASSIGN_NULL(app_loader); + Object_ASSIGN_NULL(client_env); + return ret; +} + +static int hdcp1_app_load(struct hdcp1_smcinvoke_handle *handle) +{ + int ret = 0; + + if (!handle) { + pr_err("invalid input\n"); + ret = -EINVAL; + goto error; + } + + if (handle->hdcp_state & HDCP_STATE_APP_LOADED) + goto error; + + ret = load_app(HDCP1_APP_NAME, &(handle->hdcp1_app_obj), + &(handle->hdcp1_appcontroller_obj)); + if (ret) { + pr_err("hdcp1 TA load failed :%d\n", ret); + goto error; + } + + if (Object_isNull(handle->hdcp1_app_obj)) { + pr_err("hdcp1_app_obj is NULL\n"); + ret = -EINVAL; + goto error; + } + + ret = load_app(HDCP1OPS_APP_NAME, &(handle->hdcp1ops_app_obj), + &(handle->hdcp1ops_appcontroller_obj)); + if (ret) { + pr_err("hdcp1ops TA load failed :%d\n", ret); + goto error; + } + + if (Object_isNull(handle->hdcp1ops_app_obj)) { + pr_err("hdcp1ops_app_obj is NULL\n"); + ret = -EINVAL; + goto error; + } + + handle->hdcp_state |= HDCP_STATE_APP_LOADED; + +error: + return ret; +} + +static void hdcp1_app_unload(struct hdcp1_smcinvoke_handle *handle) +{ + if (!handle || !!handle->hdcp1_app_obj.context) { + pr_err("invalid handle\n"); + return; + } + + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_warn("hdcp1 app not loaded\n"); + return; + } + + Object_ASSIGN_NULL(handle->hdcp1_app_obj); + Object_ASSIGN_NULL(handle->hdcp1_appcontroller_obj); + Object_ASSIGN_NULL(handle->hdcp1ops_app_obj); + Object_ASSIGN_NULL(handle->hdcp1ops_appcontroller_obj); + + handle->hdcp_state &= ~HDCP_STATE_APP_LOADED; + pr_debug("%s app unloaded\n", HDCP1_APP_NAME); +} + +void *hdcp1_init_smcinvoke(void) +{ + struct hdcp1_smcinvoke_handle *handle = + kzalloc(sizeof(struct hdcp1_smcinvoke_handle), GFP_KERNEL); + + if (!handle) + goto error; + +error: + return handle; +} + +bool hdcp1_feature_supported_smcinvoke(void *data) +{ + int ret = 0; + bool supported = false; + struct hdcp1_smcinvoke_handle *handle = data; + + if (!handle) { + pr_err("invalid handle\n"); + goto error; + } + + if (handle->feature_supported) { + supported = true; + goto error; + } + + ret = hdcp1_app_load(handle); + if (!ret && (handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + if (!hdcp1_verify_key(handle)) { + pr_debug("HDCP 1.x supported\n"); + handle->feature_supported = true; + supported = true; + } + hdcp1_app_unload(handle); + } +error: + return supported; +} + +int hdcp1_set_enc_smcinvoke(void *data, bool enable) +{ + int ret = 0; + struct hdcp1_smcinvoke_handle *handle = data; + + if (!handle || !handle->hdcp1_app_obj.context) { + pr_err("invalid HDCP 1.x handle\n"); + return -EINVAL; + } + + if (!handle->feature_supported) { + pr_err("HDCP 1.x not supported\n"); + return -EINVAL; + } + + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("%s app not loaded\n", HDCP1_APP_NAME); + return -EINVAL; + } + + ret = hdcp1_set_encryption(handle->hdcp1_app_obj, enable); + if (ret) + pr_err("hdcp1_set_encryption failed :%d\n", ret); + + return ret; +} + +int hdcp1_ops_notify_smcinvoke(void *data, void *topo, bool is_authenticated) +{ + int ret = 0; + struct hdcp1_smcinvoke_handle *handle = data; + + if (!handle || !handle->hdcp1ops_app_obj.context) { + pr_err("invalid HDCP 1.x ops handle\n"); + return -EINVAL; + } + + if (!handle->feature_supported) { + pr_err("HDCP 1.x not supported\n"); + return -EINVAL; + } + + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("%s app not loaded\n", HDCP1OPS_APP_NAME); + return -EINVAL; + } + + ret = hdcp1_ops_notify_topology_change(handle->hdcp1ops_app_obj); + if (ret) + pr_err("hdcp1_ops_notify_topology_change failed, ret=%d\n", ret); + + return ret; +} + +int hdcp1_start_smcinvoke(void *data, u32 *aksv_msb, u32 *aksv_lsb) +{ + int ret = 0; + struct hdcp1_smcinvoke_handle *handle = data; + + if (!aksv_msb || !aksv_lsb) { + pr_err("invalid aksv output buffer\n"); + ret = -EINVAL; + goto error; + } + + if (!handle) { + pr_err("invalid handle\n"); + ret = -EINVAL; + goto error; + } + + if (!handle->feature_supported) { + pr_err("feature not supported\n"); + ret = -EINVAL; + goto error; + } + + if (handle->hdcp_state & HDCP_STATE_APP_LOADED) { + pr_debug("%s app already loaded\n", HDCP1_APP_NAME); + goto error; + } + + ret = hdcp1_app_load(handle); + if (ret) + goto error; + + ret = hdcp1_key_set(handle, aksv_msb, aksv_lsb); + if (ret) + goto key_error; + + pr_debug("success\n"); + return ret; + +key_error: + hdcp1_app_unload(handle); +error: + return ret; +} + +void hdcp1_stop_smcinvoke(void *data) +{ + struct hdcp1_smcinvoke_handle *hdcp1_handle = data; + + Object_ASSIGN_NULL(hdcp1_handle->hdcp1_app_obj); + Object_ASSIGN_NULL(hdcp1_handle->hdcp1_appcontroller_obj); + Object_ASSIGN_NULL(hdcp1_handle->hdcp1ops_app_obj); + Object_ASSIGN_NULL(hdcp1_handle->hdcp1ops_appcontroller_obj); +} + +void *hdcp2_init_smcinvoke(u32 device_type) +{ + struct hdcp2_smcinvoke_handle *handle = + kzalloc(sizeof(struct hdcp2_smcinvoke_handle), GFP_KERNEL); + + if (!handle) + goto error; + + handle->device_type = device_type; + +error: + return handle; +} + +void hdcp2_deinit_smcinvoke(void *ctx) +{ + kfree_sensitive(ctx); +} + +int hdcp_get_version(struct hdcp2_smcinvoke_handle *handle) +{ + int ret = 0; + uint32_t app_major_version = 0; + uint32_t appversion = 0; + + if (handle->hdcp_state & HDCP_STATE_APP_LOADED) { + pr_err("hdcp2p2 TA already loaded\n"); + goto error; + } + + ret = hdcp2p2_version(handle->hdcp2_app_obj, &appversion); + if (ret) { + pr_err("hdcp2p2_version failed :%d\n", ret); + goto error; + } + app_major_version = HCDP_TXMTR_GET_MAJOR_VERSION(appversion); + + pr_debug("hdp2p2 app major version %d, app version %d\n", app_major_version, + appversion); +error: + return ret; +} + +int hdcp2_app_init(struct hdcp2_smcinvoke_handle *handle) +{ + int ret = 0; + uint32_t app_minor_version = 0; + uint32_t clientversion = 0; + uint32_t appversion = 0; + + if (handle->hdcp_state & HDCP_STATE_APP_LOADED) { + pr_err("hdcp2p2 TA already loaded\n"); + goto error; + } + + clientversion = HDCP_CLIENT_MAKE_VERSION(HDCP_CLIENT_MAJOR_VERSION, + HDCP_CLIENT_MINOR_VERSION, + HDCP_CLIENT_PATCH_VERSION); + + ret = hdcp2p2_init(handle->hdcp2_app_obj, clientversion, &appversion); + if (ret) { + pr_err("hdcp2p2_init failed:%d\n", ret); + goto error; + } + + app_minor_version = HCDP_TXMTR_GET_MINOR_VERSION(appversion); + if (app_minor_version != HDCP_CLIENT_MINOR_VERSION) { + pr_err("client-app minor version mismatch app(%d), client(%d)\n", + app_minor_version, HDCP_CLIENT_MINOR_VERSION); + ret = -1; + goto error; + } + + pr_err("client version major(%d), minor(%d), patch(%d)\n", + HDCP_CLIENT_MAJOR_VERSION, HDCP_CLIENT_MINOR_VERSION, + HDCP_CLIENT_PATCH_VERSION); + + pr_err("app version major(%d), minor(%d), patch(%d)\n", + HCDP_TXMTR_GET_MAJOR_VERSION(appversion), + HCDP_TXMTR_GET_MINOR_VERSION(appversion), + HCDP_TXMTR_GET_PATCH_VERSION(appversion)); +error: + return ret; +} + +int hdcp2_app_tx_init(struct hdcp2_smcinvoke_handle *handle) +{ + int ret = 0; + uint32_t ctxhandle = 0; + + if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) { + pr_err("session not initialized\n"); + ret = -EINVAL; + goto error; + } + + if (handle->hdcp_state & HDCP_STATE_TXMTR_INIT) { + pr_err("txmtr already initialized\n"); + goto error; + } + + ret = hdcp2p2_tx_init(handle->hdcp2_app_obj, handle->session_id, &ctxhandle); + if (ret) { + pr_err("hdcp2p2_tx_init failed :%d\n", ret); + goto error; + } + + handle->tz_ctxhandle = ctxhandle; + handle->hdcp_state |= HDCP_STATE_TXMTR_INIT; + +error: + return ret; +} + +int hdcp2_app_tx_deinit(struct hdcp2_smcinvoke_handle *handle) +{ + int ret = 0; + + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("hdcp2p2 TA not loaded\n"); + ret = -EINVAL; + goto error; + } + + if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) { + pr_err("txmtr not initialized\n"); + ret = -EINVAL; + goto error; + } + + ret = hdcp2p2_tx_deinit(handle->hdcp2_app_obj, handle->tz_ctxhandle); + if (ret) { + pr_err("hdcp2p2_tx_deinit failed :%d\n", ret); + goto error; + } + handle->hdcp_state &= ~HDCP_STATE_TXMTR_INIT; + +error: + return ret; +} + +static int hdcp2_app_load(struct hdcp2_smcinvoke_handle *handle) +{ + int ret = 0; + + if (!handle) { + pr_err("invalid input\n"); + ret = -EINVAL; + goto error; + } + + if (handle->hdcp_state & HDCP_STATE_APP_LOADED) { + pr_err("hdcp2p2 TA already loaded\n"); + goto error; + } + + ret = load_app(HDCP2P2_APP_NAME, &(handle->hdcp2_app_obj), + &(handle->hdcp2_appcontroller_obj)); + if (ret) { + pr_err("hdcp2p2 TA load_app failed :%d\n", ret); + goto error; + } + + if (Object_isNull(handle->hdcp2_app_obj)) { + pr_err("hdcp2p2 app object is NULL\n"); + ret = -EINVAL; + goto error; + } + + ret = load_app(HDCPSRM_APP_NAME, &(handle->hdcpsrm_app_obj), + &(handle->hdcpsrm_appcontroller_obj)); + if (ret) { + pr_err("hdcpsrm TA load failed :%d\n", ret); + goto error; + } + + if (Object_isNull(handle->hdcpsrm_app_obj)) { + pr_err("hdcpsrm app object is NULL\n"); + ret = -EINVAL; + goto error; + } + + ret = hdcp_get_version(handle); + if (ret) { + pr_err("library get version failed\n"); + goto error; + } + + ret = hdcp2_app_init(handle); + if (ret) { + pr_err("app init failed\n"); + goto error; + } + + handle->hdcp_state |= HDCP_STATE_APP_LOADED; + +error: + return ret; +} + +static int hdcp2_app_unload(struct hdcp2_smcinvoke_handle *handle) +{ + int ret = 0; + + ret = hdcp2p2_deinit(handle->hdcp2_app_obj); + if (ret) { + pr_err("hdcp2p2_deinit failed:%d\n", ret); + goto error; + } + + Object_ASSIGN_NULL(handle->hdcp2_app_obj); + Object_ASSIGN_NULL(handle->hdcp2_appcontroller_obj); + Object_ASSIGN_NULL(handle->hdcpsrm_app_obj); + Object_ASSIGN_NULL(handle->hdcpsrm_appcontroller_obj); + + handle->hdcp_state &= ~HDCP_STATE_APP_LOADED; + +error: + return ret; +} + +static int hdcp2_verify_key(struct hdcp2_smcinvoke_handle *handle) +{ + int ret = 0; + + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("%s app not loaded\n", HDCP2P2_APP_NAME); + ret = -EINVAL; + goto error; + } + + ret = hdcp2p2_verify_key(handle->hdcp2_app_obj); + if (ret) { + pr_err("hdcp2p2_verify_key failed:%d\n", ret); + goto error; + } + +error: + return ret; +} + +static int hdcp2_app_session_init(struct hdcp2_smcinvoke_handle *handle) +{ + int ret = 0; + uint32_t sessionId = 0; + + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("hdcp2p2 app not loaded\n"); + ret = -EINVAL; + goto error; + } + + if (handle->hdcp_state & HDCP_STATE_SESSION_INIT) { + pr_err("session already initialized\n"); + goto error; + } + + if (Object_isNull(handle->hdcp2_app_obj)) { + pr_err("hdcp2_app_obj is NULL\n"); + goto error; + } + + ret = hdcp2p2_session_init(handle->hdcp2_app_obj, handle->device_type, + &sessionId); + if (ret) { + pr_err("hdcp2p2_session_init failed ret:%d\n", ret); + goto error; + } + + handle->session_id = sessionId; + handle->hdcp_state |= HDCP_STATE_SESSION_INIT; +error: + return ret; +} + +static int hdcp2_app_session_deinit(struct hdcp2_smcinvoke_handle *handle) +{ + int ret = 0; + + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("hdcp2p2 app not loaded\n"); + ret = -EINVAL; + goto error; + } + + if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) { + pr_err("session not initialized\n"); + ret = -EINVAL; + goto error; + } + + ret = hdcp2p2_session_deinit(handle->hdcp2_app_obj, handle->session_id); + if (ret) { + pr_err("hdcp2p2_session_deinit failed:%d\n", ret); + goto error; + } + + handle->hdcp_state &= ~HDCP_STATE_SESSION_INIT; +error: + return ret; +} + +int hdcp2_app_start_smcinvoke(void *ctx, uint32_t req_len) +{ + struct hdcp2_smcinvoke_handle *handle = NULL; + int ret = 0; + + handle = (struct hdcp2_smcinvoke_handle *)ctx; + + if (!handle) { + pr_err("Invalid handle\n"); + ret = -EINVAL; + goto error; + } + + handle->app_data.request.data = kmalloc(MAX_RX_MESSAGE_SIZE, GFP_KERNEL); + if (!handle->app_data.request.data) { + ret = -EINVAL; + goto error; + } + + handle->app_data.response.data = kmalloc(MAX_TX_MESSAGE_SIZE, GFP_KERNEL); + if (!handle->app_data.response.data) { + ret = -EINVAL; + goto error; + } + + ret = hdcp2_app_load(handle); + if (ret) + goto error; + + ret = hdcp2_app_session_init(handle); + if (ret) + goto error; + + ret = hdcp2_app_tx_init(handle); + if (ret) + goto error; + +error: + return ret; +} + +int hdcp2_app_start_auth_smcinvoke(void *ctx, uint32_t req_len) +{ + struct hdcp2_smcinvoke_handle *handle = NULL; + int ret = 0; + size_t resMsgOut = 0; + uint32_t timeout = 0; + uint32_t flag = 0; + uint32_t ctxhandle = 0; + + uint8_t resMsg[MAX_TX_MESSAGE_SIZE] = {0}; + + handle = ctx; + + if (!handle) { + pr_err("Invalid handle\n"); + ret = -EINVAL; + goto error; + } + + handle->app_data.request.length = req_len; + + if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) { + pr_err("session not initialized\n"); + ret = -EINVAL; + goto error; + } + + if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) { + pr_err("txmtr not initialized\n"); + ret = -EINVAL; + goto error; + } + + ret = hdcp2p2_start_auth(handle->hdcp2_app_obj, handle->tz_ctxhandle, + resMsg, MAX_TX_MESSAGE_SIZE, &resMsgOut, &timeout, + &flag, &ctxhandle); + if (ret) { + pr_err("hdcp2p2_start_auth failed :%d\n", ret); + goto error; + } + + memcpy(handle->app_data.response.data, resMsg, resMsgOut); + + handle->app_data.response.length = resMsgOut; + handle->app_data.timeout = timeout; + handle->app_data.repeater_flag = false; + + handle->tz_ctxhandle = ctxhandle; + +error: + return ret; +} + +int hdcp2_app_process_msg_smcinvoke(void *ctx, uint32_t req_len) +{ + struct hdcp2_smcinvoke_handle *handle = NULL; + int ret = 0; + size_t resMsgLen = 0; + uint32_t timeout = 0; + uint32_t flag = 0; + + uint8_t resMsg[MAX_TX_MESSAGE_SIZE] = {0}; + + handle = ctx; + + if (!handle) { + pr_err("Invalid handle\n"); + ret = -EINVAL; + goto error; + } + + handle->app_data.request.length = req_len; + + if (!handle->app_data.request.data) { + pr_err("invalid request buffer\n"); + ret = -EINVAL; + goto error; + } + + ret = hdcp2p2_rcvd_msg( + handle->hdcp2_app_obj, handle->app_data.request.data, + handle->app_data.request.length, handle->tz_ctxhandle, resMsg, + MAX_TX_MESSAGE_SIZE, &resMsgLen, &timeout, &flag); + if (ret) { + pr_err("hdcp2p2_rcvd_msg failed :%d\n", ret); + goto error; + } + + memcpy(handle->app_data.response.data, resMsg, resMsgLen); + + /* check if it's a repeater */ + if (flag == HDCP_TXMTR_SUBSTATE_WAITING_FOR_RECIEVERID_LIST) + handle->app_data.repeater_flag = true; + + handle->app_data.response.length = resMsgLen; + handle->app_data.timeout = timeout; + +error: + return ret; +} + +int hdcp2_app_timeout_smcinvoke(void *ctx, uint32_t req_len) +{ + struct hdcp2_smcinvoke_handle *handle = NULL; + int ret = 0; + uint32_t timeout = 0; + size_t resMsgLenOut = 0; + + uint8_t resMsg[MAX_TX_MESSAGE_SIZE] = {0}; + + handle = ctx; + + if (!handle) { + pr_err("Invalid handle\n"); + ret = -EINVAL; + goto error; + } + + handle->app_data.request.length = req_len; + + ret = hdcp2p2_send_timeout(handle->hdcp2_app_obj, handle->tz_ctxhandle, + resMsg, MAX_TX_MESSAGE_SIZE, &resMsgLenOut, + &timeout); + if (ret) { + pr_err("hdcp2p2_send_timeout failed :%d\n", ret); + goto error; + } + + memcpy(handle->app_data.response.data, resMsg, resMsgLenOut); + + handle->app_data.response.length = resMsgLenOut; + handle->app_data.timeout = timeout; + +error: + return ret; +} + +int hdcp2_app_enable_encryption_smcinvoke(void *ctx, uint32_t req_len) +{ + struct hdcp2_smcinvoke_handle *handle = NULL; + int ret = 0; + + handle = ctx; + + if (!handle) { + pr_err("Invalid handle\n"); + ret = -EINVAL; + goto error; + } + + handle->app_data.request.length = req_len; + + /* + * wait at least 200ms before enabling encryption + * as per hdcp2p2 specifications. + */ + msleep(SLEEP_SET_HW_KEY_MS); + + ret = hdcp2p2_set_hw_key(handle->hdcp2_app_obj, handle->tz_ctxhandle); + if (ret) { + pr_err("hdcp2p2_set_hw_key failed:%d\n", ret); + goto error; + } + + handle->hdcp_state |= HDCP_STATE_AUTHENTICATED; +error: + return ret; +} + +int hdcp2_app_query_stream_smcinvoke(void *ctx, uint32_t req_len) +{ + struct hdcp2_smcinvoke_handle *handle = NULL; + int ret = 0; + + uint32_t timeout = 0; + size_t resMsgLenOut = 0; + + uint8_t resMsg[MAX_TX_MESSAGE_SIZE] = {0}; + + handle = ctx; + + if (!handle) { + pr_err("Invalid handle\n"); + ret = -EINVAL; + goto error; + } + + handle->app_data.request.length = req_len; + + ret = hdcp2p2_query_stream_type( + handle->hdcp2_app_obj, handle->tz_ctxhandle, resMsg, + MAX_TX_MESSAGE_SIZE, &resMsgLenOut, &timeout); + if (ret) { + pr_err("hdcp2p2_query_stream_type failed :%d\n", ret); + goto error; + } + + memcpy(handle->app_data.response.data, resMsg, resMsgLenOut); + + handle->app_data.response.length = resMsgLenOut; + handle->app_data.timeout = timeout; +error: + return ret; +} + +int hdcp2_app_stop_smcinvoke(void *ctx) +{ + struct hdcp2_smcinvoke_handle *handle = NULL; + int ret = 0; + + handle = ctx; + + if (!handle) { + pr_err("Invalid handle\n"); + ret = -EINVAL; + goto end; + } + + ret = hdcp2_app_tx_deinit(handle); + if (ret) + goto end; + + ret = hdcp2_app_session_deinit(handle); + if (ret) + goto end; + + ret = hdcp2_app_unload(handle); + + kfree(handle->app_data.request.data); + kfree(handle->app_data.response.data); + +end: + return ret; +} + +bool hdcp2_feature_supported_smcinvoke(void *ctx) +{ + struct hdcp2_smcinvoke_handle *handle = NULL; + int ret = 0; + bool supported = false; + + handle = ctx; + + if (!handle) { + pr_err("invalid input\n"); + ret = -EINVAL; + goto error; + } + + if (handle->feature_supported) { + supported = true; + goto error; + } + + ret = hdcp2_app_load(handle); + if (!ret) { + if (!hdcp2_verify_key(handle)) { + pr_debug("HDCP 2.2 supported\n"); + handle->feature_supported = true; + supported = true; + } + hdcp2_app_unload(handle); + } +error: + return supported; +} + +int hdcp2_force_encryption_smcinvoke(void *ctx, uint32_t enable) +{ + struct hdcp2_smcinvoke_handle *handle = NULL; + int ret = 0; + + handle = ctx; + + if (!handle) { + pr_err("Invalid handle\n"); + ret = -EINVAL; + goto error; + } + + if (handle->hdcp_state == HDCP_STATE_AUTHENTICATED) + msleep(SLEEP_FORCE_ENCRYPTION_MS); + + ret = hdcp2p2_force_encryption(handle->hdcp2_app_obj, handle->tz_ctxhandle, + enable); + if (ret) { + pr_err("hdcp2p2_force_encryption failed :%d\n", ret); + goto error; + } + +error: + return ret; +} + +int hdcp2_open_stream_smcinvoke(void *ctx, uint8_t vc_payload_id, + uint8_t stream_number, uint32_t *stream_id) +{ + struct hdcp2_smcinvoke_handle *handle = NULL; + int ret = 0; + uint32_t streamid = 0; + + handle = ctx; + + if (!handle) { + pr_err("Invalid handle\n"); + ret = -EINVAL; + goto error; + } + + if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) { + pr_err("session not initialized\n"); + ret = -EINVAL; + goto error; + } + + if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) { + pr_err("txmtr not initialized\n"); + ret = -EINVAL; + goto error; + } + + ret = hdcp2p2_session_open_stream(handle->hdcp2_app_obj, + handle->session_id, vc_payload_id, + stream_number, 0, &streamid); + if (ret) { + pr_err("hdcp2p2_session_open_stream failed :%d\n", ret); + goto error; + } + + *stream_id = streamid; + +error: + return ret; +} + +int hdcp2_close_stream_smcinvoke(void *ctx, uint32_t stream_id) +{ + struct hdcp2_smcinvoke_handle *handle = NULL; + int ret = 0; + + handle = ctx; + + if (!handle) { + pr_err("Invalid handle\n"); + ret = -EINVAL; + goto error; + } + + if (!(handle->hdcp_state & HDCP_STATE_SESSION_INIT)) { + pr_err("session not initialized\n"); + ret = -EINVAL; + goto error; + } + + if (!(handle->hdcp_state & HDCP_STATE_TXMTR_INIT)) { + pr_err("txmtr not initialized\n"); + ret = -EINVAL; + goto error; + } + + ret = hdcp2p2_session_close_stream(handle->hdcp2_app_obj, + handle->session_id, stream_id); + if (ret) { + pr_err("hdcp2p2_session_close_stream failed :%d\n", ret); + goto error; + } + +error: + return ret; +} + +int hdcp2_update_app_data_smcinvoke(void *ctx, struct hdcp2_app_data *app_data) +{ + struct hdcp2_smcinvoke_handle *handle = NULL; + int ret = 0; + + handle = ctx; + + if (!handle || !app_data) { + pr_err("Invalid handle\n"); + return -EINVAL; + } + + app_data->request.data = handle->app_data.request.data; + app_data->request.length = handle->app_data.request.length; + app_data->response.data = handle->app_data.response.data; + app_data->response.length = handle->app_data.response.length; + app_data->timeout = handle->app_data.timeout; + app_data->repeater_flag = handle->app_data.repeater_flag; + return ret; +} diff --git a/hdcp/hdcp_smcinvoke.h b/hdcp/hdcp_smcinvoke.h new file mode 100644 index 0000000000..b155278d1e --- /dev/null +++ b/hdcp/hdcp_smcinvoke.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __HDCP_SMCINVOKE_H__ +#define __HDCP_SMCINVOKE_H__ + +#include +#include +#include +#include + +#include "hdcp_main.h" + +struct hdcp1_smcinvoke_handle { + struct Object hdcp1_app_obj; + struct Object hdcp1_appcontroller_obj; + struct Object hdcp1ops_app_obj; + struct Object hdcp1ops_appcontroller_obj; + bool feature_supported; + uint32_t device_type; + enum hdcp_state hdcp_state; +}; + +struct hdcp2_smcinvoke_handle { + struct hdcp2_app_data app_data; + uint32_t tz_ctxhandle; + bool feature_supported; + enum hdcp_state hdcp_state; + struct Object hdcp2_app_obj; + struct Object hdcp2_appcontroller_obj; + struct Object hdcpsrm_app_obj; + struct Object hdcpsrm_appcontroller_obj; + uint32_t session_id; + uint32_t device_type; +}; + +void *hdcp1_init_smcinvoke(void); +bool hdcp1_feature_supported_smcinvoke(void *data); +int hdcp1_set_enc_smcinvoke(void *data, bool enable); +int hdcp1_ops_notify_smcinvoke(void *data, void *topo, bool is_authenticated); +int hdcp1_start_smcinvoke(void *data, u32 *aksv_msb, u32 *aksv_lsb); +void hdcp1_stop_smcinvoke(void *data); + +void *hdcp2_init_smcinvoke(u32 device_type); +void hdcp2_deinit_smcinvoke(void *ctx); +int hdcp2_app_start_smcinvoke(void *ctx, uint32_t req_len); +int hdcp2_app_start_auth_smcinvoke(void *ctx, uint32_t req_len); +int hdcp2_app_process_msg_smcinvoke(void *ctx, uint32_t req_len); +int hdcp2_app_timeout_smcinvoke(void *ctx, uint32_t req_len); +int hdcp2_app_enable_encryption_smcinvoke(void *ctx, uint32_t req_len); +int hdcp2_app_query_stream_smcinvoke(void *ctx, uint32_t req_len); +int hdcp2_app_stop_smcinvoke(void *ctx); +bool hdcp2_feature_supported_smcinvoke(void *ctx); +int hdcp2_force_encryption_smcinvoke(void *ctx, uint32_t enable); +int hdcp2_open_stream_smcinvoke(void *ctx, uint8_t vc_payload_id, + uint8_t stream_number, uint32_t *stream_id); +int hdcp2_close_stream_smcinvoke(void *ctx, uint32_t stream_id); +int hdcp2_update_app_data_smcinvoke(void *ctx, struct hdcp2_app_data *app_data); + +#endif /* __HDCP_SMCINVOKE_H__ */ diff --git a/include/linux/smcinvoke_object.h b/include/linux/smcinvoke_object.h index 4df7b76b1e..43bcb929e3 100644 --- a/include/linux/smcinvoke_object.h +++ b/include/linux/smcinvoke_object.h @@ -9,6 +9,7 @@ #include #include #include +#include "smcinvoke.h" /* * Method bits are not modified by transport layers. These describe the @@ -190,7 +191,6 @@ static inline void Object_replace(struct Object *loc, struct Object objNew) int smcinvoke_release_from_kernel_client(int fd); int get_root_fd(int *root_fd); - int process_invoke_request_from_kernel_client( int fd, struct smcinvoke_cmd_req *req); diff --git a/include/smci/interface/IAppClient.h b/include/smci/interface/IAppClient.h new file mode 100644 index 0000000000..6336ee57cd --- /dev/null +++ b/include/smci/interface/IAppClient.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ +/** @cond */ + +#pragma once + + +#include "smcinvoke_object.h" + + +#define IAppClient_ERROR_APP_NOT_FOUND INT32_C(10) +#define IAppClient_ERROR_APP_RESTART_FAILED INT32_C(11) +#define IAppClient_ERROR_APP_UNTRUSTED_CLIENT INT32_C(12) +#define IAppClient_ERROR_CLIENT_CRED_PARSING_FAILURE INT32_C(13) +#define IAppClient_ERROR_APP_LOAD_FAILED INT32_C(14) + +#define IAppClient_OP_getAppObject 0 + +static inline int32_t +IAppClient_release(struct Object self) +{ + return Object_invoke(self, Object_OP_release, 0, 0); +} + +static inline int32_t +IAppClient_retain(struct Object self) +{ + return Object_invoke(self, Object_OP_retain, 0, 0); +} + +static inline int32_t +IAppClient_getAppObject(struct Object self, const void *appDistName_ptr, size_t appDistName_len,struct Object *obj_ptr) +{ + int32_t result; + union ObjectArg a[2]; + a[0].bi = (struct ObjectBufIn) { appDistName_ptr, appDistName_len * 1 }; + + result = Object_invoke(self, IAppClient_OP_getAppObject, a, ObjectCounts_pack(1, 0, 0, 1)); + + *obj_ptr = a[1].o; + + return result; +} + + + diff --git a/include/smci/interface/IAppController.h b/include/smci/interface/IAppController.h new file mode 100644 index 0000000000..45166482a3 --- /dev/null +++ b/include/smci/interface/IAppController.h @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/** @cond */ +#pragma once + +#include "smcinvoke_object.h" + + +#define IAppController_CBO_INTERFACE_WAIT UINT32_C(1) + +#define IAppController_ERROR_APP_SUSPENDED INT32_C(10) +#define IAppController_ERROR_APP_BLOCKED_ON_LISTENER INT32_C(11) +#define IAppController_ERROR_APP_UNLOADED INT32_C(12) +#define IAppController_ERROR_APP_IN_USE INT32_C(13) +#define IAppController_ERROR_NOT_SUPPORTED INT32_C(14) +#define IAppController_ERROR_CBO_UNKNOWN INT32_C(15) +#define IAppController_ERROR_APP_UNLOAD_NOT_ALLOWED INT32_C(16) +#define IAppController_ERROR_APP_DISCONNECTED INT32_C(17) +#define IAppController_ERROR_USER_DISCONNECT_REJECTED INT32_C(18) +#define IAppController_ERROR_STILL_RUNNING INT32_C(19) + +#define IAppController_OP_openSession 0 +#define IAppController_OP_unload 1 +#define IAppController_OP_getAppObject 2 +#define IAppController_OP_installCBO 3 +#define IAppController_OP_disconnect 4 +#define IAppController_OP_restart 5 + +static inline int32_t +IAppController_release(struct Object self) +{ + return Object_invoke(self, Object_OP_release, 0, 0); +} + +static inline int32_t +IAppController_retain(struct Object self) +{ + return Object_invoke(self, Object_OP_retain, 0, 0); +} + +static inline int32_t +IAppController_openSession(struct Object self, uint32_t cancelCode_val, uint32_t connectionMethod_val, uint32_t connectionData_val, uint32_t paramTypes_val, uint32_t exParamTypes_val, const void *i1_ptr, size_t i1_len, const void *i2_ptr, size_t i2_len, const void *i3_ptr, size_t i3_len, const void *i4_ptr, size_t i4_len, void *o1_ptr, size_t o1_len, size_t *o1_lenout, void *o2_ptr, size_t o2_len, size_t *o2_lenout, void *o3_ptr, size_t o3_len, size_t *o3_lenout, void *o4_ptr, size_t o4_len, size_t *o4_lenout,struct Object imem1_val,struct Object imem2_val,struct Object imem3_val,struct Object imem4_val, uint32_t *memrefOutSz1_ptr, uint32_t *memrefOutSz2_ptr, uint32_t *memrefOutSz3_ptr, uint32_t *memrefOutSz4_ptr,struct Object *session_ptr, uint32_t *retValue_ptr, uint32_t *retOrigin_ptr) +{ + union ObjectArg a[15]; + struct { + uint32_t m_cancelCode; + uint32_t m_connectionMethod; + uint32_t m_connectionData; + uint32_t m_paramTypes; + uint32_t m_exParamTypes; + } i; + + struct { + uint32_t m_memrefOutSz1; + uint32_t m_memrefOutSz2; + uint32_t m_memrefOutSz3; + uint32_t m_memrefOutSz4; + uint32_t m_retValue; + uint32_t m_retOrigin; + } o; + int32_t result; + + a[0].b = (struct ObjectBuf) { &i, 20 }; + a[5].b = (struct ObjectBuf) { &o, 24 }; + i.m_cancelCode = cancelCode_val; + i.m_connectionMethod = connectionMethod_val; + i.m_connectionData = connectionData_val; + i.m_paramTypes = paramTypes_val; + i.m_exParamTypes = exParamTypes_val; + a[1].bi = (struct ObjectBufIn) { i1_ptr, i1_len * 1 }; + a[2].bi = (struct ObjectBufIn) { i2_ptr, i2_len * 1 }; + a[3].bi = (struct ObjectBufIn) { i3_ptr, i3_len * 1 }; + a[4].bi = (struct ObjectBufIn) { i4_ptr, i4_len * 1 }; + a[6].b = (struct ObjectBuf) { o1_ptr, o1_len * 1 }; + a[7].b = (struct ObjectBuf) { o2_ptr, o2_len * 1 }; + a[8].b = (struct ObjectBuf) { o3_ptr, o3_len * 1 }; + a[9].b = (struct ObjectBuf) { o4_ptr, o4_len * 1 }; + a[10].o = imem1_val; + a[11].o = imem2_val; + a[12].o = imem3_val; + a[13].o = imem4_val; + + result = Object_invoke(self, IAppController_OP_openSession, a, ObjectCounts_pack(5, 5, 4, 1)); + + *o1_lenout = a[6].b.size / 1; + *o2_lenout = a[7].b.size / 1; + *o3_lenout = a[8].b.size / 1; + *o4_lenout = a[9].b.size / 1; + *memrefOutSz1_ptr = o.m_memrefOutSz1; + *memrefOutSz2_ptr = o.m_memrefOutSz2; + *memrefOutSz3_ptr = o.m_memrefOutSz3; + *memrefOutSz4_ptr = o.m_memrefOutSz4; + *session_ptr = a[14].o; + *retValue_ptr = o.m_retValue; + *retOrigin_ptr = o.m_retOrigin; + + return result; +} + +static inline int32_t +IAppController_unload(struct Object self) +{ + return Object_invoke(self, IAppController_OP_unload, 0, 0); +} + +static inline int32_t +IAppController_getAppObject(struct Object self,struct Object *obj_ptr) +{ + union ObjectArg a[1]; + int32_t result = Object_invoke(self, IAppController_OP_getAppObject, a, ObjectCounts_pack(0, 0, 0, 1)); + + *obj_ptr = a[0].o; + + return result; +} + +static inline int32_t +IAppController_installCBO(struct Object self, uint32_t uid_val,struct Object obj_val) +{ + union ObjectArg a[2]; + a[0].b = (struct ObjectBuf) { &uid_val, sizeof(uint32_t) }; + a[1].o = obj_val; + + return Object_invoke(self, IAppController_OP_installCBO, a, ObjectCounts_pack(1, 0, 1, 0)); +} + +static inline int32_t +IAppController_disconnect(struct Object self) +{ + return Object_invoke(self, IAppController_OP_disconnect, 0, 0); +} + +static inline int32_t +IAppController_restart(struct Object self) +{ + return Object_invoke(self, IAppController_OP_restart, 0, 0); +} + + + diff --git a/include/smci/interface/IAppLoader.h b/include/smci/interface/IAppLoader.h new file mode 100644 index 0000000000..f91307d78a --- /dev/null +++ b/include/smci/interface/IAppLoader.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#pragma once + + +#include "smcinvoke_object.h" +#include "IAppController.h" + +#define IAppLoader_ERROR_INVALID_BUFFER INT32_C(10) +#define IAppLoader_ERROR_PIL_ROLLBACK_FAILURE INT32_C(11) +#define IAppLoader_ERROR_ELF_SIGNATURE_ERROR INT32_C(12) +#define IAppLoader_ERROR_METADATA_INVALID INT32_C(13) +#define IAppLoader_ERROR_MAX_NUM_APPS INT32_C(14) +#define IAppLoader_ERROR_NO_NAME_IN_METADATA INT32_C(15) +#define IAppLoader_ERROR_ALREADY_LOADED INT32_C(16) +#define IAppLoader_ERROR_EMBEDDED_IMAGE_NOT_FOUND INT32_C(17) +#define IAppLoader_ERROR_TZ_HEAP_MALLOC_FAILURE INT32_C(18) +#define IAppLoader_ERROR_TA_APP_REGION_MALLOC_FAILURE INT32_C(19) +#define IAppLoader_ERROR_CLIENT_CRED_PARSING_FAILURE INT32_C(20) +#define IAppLoader_ERROR_APP_UNTRUSTED_CLIENT INT32_C(21) +#define IAppLoader_ERROR_APP_NOT_LOADED INT32_C(22) +#define IAppLoader_ERROR_APP_MAX_CLIENT_CONNECTIONS INT32_C(23) +#define IAppLoader_ERROR_APP_BLACKLISTED INT32_C(24) + +#define IAppLoader_OP_loadFromBuffer 0 +#define IAppLoader_OP_loadFromRegion 1 +#define IAppLoader_OP_loadEmbedded 2 +#define IAppLoader_OP_connect 3 + +static inline int32_t +IAppLoader_release(struct Object self) +{ + return Object_invoke(self, Object_OP_release, 0, 0); +} + +static inline int32_t +IAppLoader_retain(struct Object self) +{ + return Object_invoke(self, Object_OP_retain, 0, 0); +} + +static inline int32_t +IAppLoader_loadFromBuffer(struct Object self, const void *appElf_ptr, size_t appElf_len,struct Object *appController_ptr) +{ + union ObjectArg a[2]; + int32_t result; + a[0].bi = (struct ObjectBufIn) { appElf_ptr, appElf_len * 1 }; + + + result = Object_invoke(self, IAppLoader_OP_loadFromBuffer, a, ObjectCounts_pack(1, 0, 0, 1)); + + *appController_ptr = a[1].o; + + return result; +} + +static inline int32_t +IAppLoader_loadFromRegion(struct Object self,struct Object appElf_val,struct Object *appController_ptr) +{ + union ObjectArg a[2]; + int32_t result; + a[0].o = appElf_val; + + result = Object_invoke(self, IAppLoader_OP_loadFromRegion, a, ObjectCounts_pack(0, 0, 1, 1)); + + *appController_ptr = a[1].o; + + return result; +} + +static inline int32_t +IAppLoader_loadEmbedded(struct Object self, const void *appName_ptr, size_t appName_len,struct Object *appController_ptr) +{ + union ObjectArg a[2]; + int32_t result; + a[0].bi = (struct ObjectBufIn) { appName_ptr, appName_len * 1 }; + + result = Object_invoke(self, IAppLoader_OP_loadEmbedded, a, ObjectCounts_pack(1, 0, 0, 1)); + + *appController_ptr = a[1].o; + + return result; +} + +static inline int32_t +IAppLoader_connect(struct Object self, const void *appName_ptr, size_t appName_len,struct Object *appController_ptr) +{ + union ObjectArg a[2]; + + int32_t result; + a[0].bi = (struct ObjectBufIn) { appName_ptr, appName_len * 1 }; + + + result = Object_invoke(self, IAppLoader_OP_connect, a, ObjectCounts_pack(1, 0, 0, 1)); + + *appController_ptr = a[1].o; + + return result; +} + + + diff --git a/include/smci/interface/IOpener.h b/include/smci/interface/IOpener.h new file mode 100644 index 0000000000..d77368e374 --- /dev/null +++ b/include/smci/interface/IOpener.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/** @cond */ +#pragma once + + +#include "smcinvoke_object.h" + +/** 0 is not a valid service ID. */ +#define IOpener_INVALID_ID UINT32_C(0) + +#define IOpener_ERROR_NOT_FOUND INT32_C(10) +#define IOpener_ERROR_PRIVILEGE INT32_C(11) +#define IOpener_ERROR_NOT_SUPPORTED INT32_C(12) + +#define IOpener_OP_open 0 + +static inline int32_t +IOpener_release(struct Object self) +{ + return Object_invoke(self, Object_OP_release, 0, 0); +} + +static inline int32_t +IOpener_retain(struct Object self) +{ + return Object_invoke(self, Object_OP_retain, 0, 0); +} + +static inline int32_t +IOpener_open(struct Object self, uint32_t id_val,struct Object *obj_ptr) +{ + union ObjectArg a[2]; + int32_t result; + a[0].b = (struct ObjectBuf) { &id_val, sizeof(uint32_t) }; + + result = Object_invoke(self, IOpener_OP_open, a, ObjectCounts_pack(1, 0, 0, 1)); + + *obj_ptr = a[1].o; + + return result; +} + + + diff --git a/include/smci/uid/CAppClient.h b/include/smci/uid/CAppClient.h new file mode 100644 index 0000000000..6cb6e9a60c --- /dev/null +++ b/include/smci/uid/CAppClient.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/** +* @addtogroup CAppClient +* @{ + Class CAppClient implements \link IAppClient \endlink interface. + This class provides an interface to obtain app-provided functionalities. + + The class ID `AppClient` is not included in the default privilege set. +*/ +#pragma once + +#include + +#define CAppClient_UID (0x97) + + diff --git a/include/smci/uid/CAppLoader.h b/include/smci/uid/CAppLoader.h new file mode 100644 index 0000000000..8f84d8fb5a --- /dev/null +++ b/include/smci/uid/CAppLoader.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#pragma once + +#include + + +// This class provides an interface to load Secure Applications in QSEE +#define CAppLoader_UID (3) diff --git a/pineapple.bzl b/pineapple.bzl index 42d48166f6..5a45c5eeb2 100644 --- a/pineapple.bzl +++ b/pineapple.bzl @@ -14,5 +14,6 @@ def define_pineapple(): "smmu_proxy_dlkm" ], extra_options = [ - "CONFIG_QCOM_SMCINVOKE"] + "CONFIG_QCOM_SMCINVOKE", + ], ) diff --git a/securemsm_kernel.bzl b/securemsm_kernel.bzl index 2168fe0d68..8f8c1701ee 100644 --- a/securemsm_kernel.bzl +++ b/securemsm_kernel.bzl @@ -1,7 +1,13 @@ -load("//build/kernel/kleaf:kernel.bzl", "kernel_modules_install", - "ddk_module") -load(":securemsm_modules.bzl", "securemsm_modules", - "securemsm_modules_by_config") +load( + "//build/kernel/kleaf:kernel.bzl", + "ddk_module", + "kernel_modules_install", +) +load( + ":securemsm_modules.bzl", + "securemsm_modules", + "securemsm_modules_by_config", +) load("//build/bazel_common_rules/dist:dist.bzl", "copy_to_dist_dir") def _replace_formatting_codes(target, variant, s): @@ -11,9 +17,9 @@ def _replace_formatting_codes(target, variant, s): def _console_print(target, variant, module, message): if module: - print('{}: {}: securemsm-kernel: {}: {}'.format(target, variant, module, message)) + print("{}: {}: securemsm-kernel: {}: {}".format(target, variant, module, message)) else: - print('{}: {}: securemsm-kernel: {} '.format(target, variant, message)) + print("{}: {}: securemsm-kernel: {} ".format(target, variant, message)) def _get_options(target, variant, target_config_option, modules, extra_options): all_options = {option: True for option in extra_options} @@ -37,7 +43,7 @@ def _get_options(target, variant, target_config_option, modules, extra_options): all_options[target_config_option] = True if redundant_options: - _console_print(target, variant, None, 'INFO: The following options are already declared either by a module or the target, no need to redeclare: \n{}'.format('\n'.join(redundant_options))) + _console_print(target, variant, None, "INFO: The following options are already declared either by a module or the target, no need to redeclare: \n{}".format("\n".join(redundant_options))) return all_options @@ -51,7 +57,7 @@ def _get_module_srcs(target, variant, module, options): globbed_srcs = native.glob(["{}{}".format(module_path, _replace_formatting_codes(target, variant, src)) for src in srcs]) if not globbed_srcs: - _console_print(target, variant, module["name"], 'WARNING: Module has no sources attached!') + _console_print(target, variant, module["name"], "WARNING: Module has no sources attached!") return globbed_srcs @@ -79,27 +85,25 @@ def define_target_variant_modules(target, variant, modules, extra_options = [], deps = ["//msm-kernel:all_headers"] + [_replace_formatting_codes(target, variant, dep) for dep in module["deps"]], hdrs = module["hdrs"], local_defines = target_local_defines, - copts = module["copts"] - + copts = module["copts"], ) module_rules.append(rule_name) copy_to_dist_dir( - name = "{}_securemsm-kernel_dist".format(kernel_build_variant), - data = module_rules, - dist_dir = "out/target/product/{}/dlkm/lib/modules/".format(target), - flat = True, - wipe_dist_dir = False, - allow_duplicate_filenames = False, - mode_overrides = {"**/*": "644"}, - log = "info", + name = "{}_securemsm-kernel_dist".format(kernel_build_variant), + data = module_rules, + dist_dir = "out/target/product/{}/dlkm/lib/modules/".format(target), + flat = True, + wipe_dist_dir = False, + allow_duplicate_filenames = False, + mode_overrides = {"**/*": "644"}, + log = "info", ) - kernel_modules_install( name = "{}_modules_install".format(kernel_build_variant), kernel_build = "//msm-kernel:{}".format(kernel_build_variant), - kernel_modules = module_rules + kernel_modules = module_rules, ) def define_consolidate_gki_modules(target, modules, extra_options = [], config_option = None): diff --git a/securemsm_modules.bzl b/securemsm_modules.bzl index f72f021f82..389f117275 100644 --- a/securemsm_modules.bzl +++ b/securemsm_modules.bzl @@ -22,12 +22,11 @@ securemsm_modules_by_config = {} def register_securemsm_module(name, path = None, config_option = None, default_srcs = [], config_srcs = {}, deps = [], srcs = [], copts = [], hdrs = []): processed_config_srcs = {} - for config_src_name in config_srcs: config_src = config_srcs[config_src_name] if type(config_src) == "list": - processed_config_srcs[config_src_name] = { True: config_src } + processed_config_srcs[config_src_name] = {True: config_src} else: processed_config_srcs[config_src_name] = config_src @@ -48,18 +47,16 @@ def register_securemsm_module(name, path = None, config_option = None, default_s if config_option: securemsm_modules_by_config[config_option] = name - # ------------------------------------ SECUREMSM MODULE DEFINITIONS --------------------------------- register_securemsm_module( name = "smcinvoke_dlkm", path = SMCINVOKE_PATH, default_srcs = [ - "smcinvoke.c", - "smcinvoke_kernel.c", - "trace_smcinvoke.h", - "IQSEEComCompat.h", - "IQSEEComCompatAppLoader.h", - + "smcinvoke.c", + "smcinvoke_kernel.c", + "trace_smcinvoke.h", + "IQSEEComCompat.h", + "IQSEEComCompatAppLoader.h", ], deps = [":smcinvoke_kernel_headers"], hdrs = [":smcinvoke_kernel_headers"], @@ -68,8 +65,10 @@ register_securemsm_module( register_securemsm_module( name = "qseecom_dlkm", path = QSEECOM_PATH, - default_srcs = ["qseecom.c", - "ice.h"], + default_srcs = [ + "qseecom.c", + "ice.h", + ], deps = [":securemsm_kernel_headers"], srcs = ["config/sec-kernel_defconfig_qseecom.h"], copts = ["-include", "config/sec-kernel_defconfig_qseecom.h"], @@ -84,10 +83,31 @@ register_securemsm_module( register_securemsm_module( name = "hdcp_qseecom_dlkm", path = HDCP_PATH, - default_srcs = ["hdcp_qseecom.c"], - deps = [":hdcp_qseecom_dlkm","%b_smcinvoke_dlkm"], + default_srcs = [ + "hdcp_qseecom.c", + "hdcp_qseecom.h", + "hdcp_main.c", + "smcinvoke_object.h", + "hdcp_main.h", + "hdcp_smcinvoke.c", + "hdcp_smcinvoke.h", + "CAppClient.h", + "CAppLoader.h", + "IAppClient.h", + "IAppController.h", + "IAppLoader.h", + "IClientEnv.h", + "IOpener.h", + "hdcp1.h", + "hdcp1_ops.h", + "hdcp2p2.h", + ], + deps = [":hdcp_qseecom_dlkm", "%b_smcinvoke_dlkm"], srcs = ["config/sec-kernel_defconfig.h"], - copts = ["-include", "config/sec-kernel_defconfig.h"], + copts = [ + "-include", + "config/sec-kernel_defconfig.h", + ], ) register_securemsm_module(