hdmitx: adjust hdmitx related code [1/2]

PD#173252: hdmitx: adjust hdmitx related code

Change-Id: Ie8dfd4b21055b9ab34b50efca65dfafa78f2254d
Signed-off-by: Zongdong Jiao <zongdong.jiao@amlogic.com>
This commit is contained in:
Zongdong Jiao
2018-09-05 17:12:53 +08:00
committed by Jianxin Pan
parent 00ff0c7669
commit ee2c15ae28
8 changed files with 279 additions and 759 deletions

View File

@@ -13538,9 +13538,9 @@ M: Tao Zeng <tao.zeng@amlogic.com>
F: arch/arm/mach-meson/Makefile.boot
HDMITX OUTPUT DRIVER
M: Zongdong Jiao <zongdong.jiao@amlogic.com>
M: Yi Zhou <yi.zhou@amlogic.com>
M: Kaifu Hu <kaifu.hu@amlogic.com>
M: Zongdong Jiao <zongdong.jiao@amlogic.com>
S: Maintained
F: drivers/amlogic/media/vout/hdmitx/*
F: drivers/amlogic/media/vout/hdmitx/hdcp/*

View File

@@ -1,2 +1,2 @@
obj-y += hdmi_tx_hw.o reg_ops.o enc_cfg_hw.o hdmi_tx_ddc.o hdcpVerify.o
obj-y += hdmi_tx_hw.o reg_ops.o enc_cfg_hw.o hdmi_tx_ddc.o checksha.o
obj-y += hw_gxbb.o hw_gxtvbb.o hw_gxl.o hw_txlx.o hw_clk.o hw_g12a.o

View File

@@ -0,0 +1,200 @@
/*
* drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/checksha.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/types.h>
#include <linux/printk.h>
#include <linux/string.h>
#include "checksha.h"
static void shamsg_reset(struct shamsg_t *msg)
{
int i = 0;
msg->shamsg_idx = 0;
msg->shamsg_cmp = FALSE;
msg->shamsg_crp = FALSE;
for (i = 0; i < sizeof(msg->shamsg_len); i++)
msg->shamsg_len[i] = 0;
msg->shamsg_dgt[0] = SHA_CONST_VAL0;
msg->shamsg_dgt[1] = SHA_CONST_VAL1;
msg->shamsg_dgt[2] = SHA_CONST_VAL2;
msg->shamsg_dgt[3] = SHA_CONST_VAL3;
msg->shamsg_dgt[4] = SHA_CONST_VAL4;
}
static void shamsg_calcblock(struct shamsg_t *msg)
{
const unsigned int K[] = {
SHA_CONST_K0,
SHA_CONST_K1,
SHA_CONST_K2,
SHA_CONST_K3
};
unsigned int W[80];
unsigned int A, B, C, D, E;
unsigned int temp = 0;
int t = 0;
#define SHIFT_DAT(idx, off) \
(((unsigned int)msg->shamsg_blk[t * 4 + idx]) << off)
for (t = 0; t < 80; t++) {
if (t < 16) {
W[t] = SHIFT_DAT(0, 24);
W[t] |= SHIFT_DAT(1, 16);
W[t] |= SHIFT_DAT(2, 8);
W[t] |= SHIFT_DAT(3, 0);
} else
W[t] = SHAMSG_SHIFT(1, W[t-3]^W[t-8]^W[t-14]^W[t-16]);
}
A = msg->shamsg_dgt[0];
B = msg->shamsg_dgt[1];
C = msg->shamsg_dgt[2];
D = msg->shamsg_dgt[3];
E = msg->shamsg_dgt[4];
for (t = 0; t < 80; t++) {
temp = SHAMSG_SHIFT(5, A);
if (t < 20)
temp += ((B & C) | ((~B) & D)) + E + W[t] + K[0];
else if (t < 40)
temp += (B ^ C ^ D) + E + W[t] + K[1];
else if (t < 60)
temp += ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
else
temp += (B ^ C ^ D) + E + W[t] + K[3];
E = D;
D = C;
C = SHAMSG_SHIFT(30, B);
B = A;
A = (temp & MAX_VAL_MASK);
}
msg->shamsg_dgt[0] = (msg->shamsg_dgt[0] + A) & MAX_VAL_MASK;
msg->shamsg_dgt[1] = (msg->shamsg_dgt[1] + B) & MAX_VAL_MASK;
msg->shamsg_dgt[2] = (msg->shamsg_dgt[2] + C) & MAX_VAL_MASK;
msg->shamsg_dgt[3] = (msg->shamsg_dgt[3] + D) & MAX_VAL_MASK;
msg->shamsg_dgt[4] = (msg->shamsg_dgt[4] + E) & MAX_VAL_MASK;
msg->shamsg_idx = 0;
}
static void shamsg_init(struct shamsg_t *msg,
const unsigned char *data, int size)
{
int i = 0;
unsigned int j = 0;
int rc = TRUE;
if (data == NULL || size == 0) {
pr_info("invalid parameters\n");
return;
}
if (msg->shamsg_cmp == TRUE || msg->shamsg_crp == TRUE) {
msg->shamsg_crp = TRUE;
return;
}
while (size-- && msg->shamsg_crp == FALSE) {
msg->shamsg_blk[msg->shamsg_idx++] = *data;
for (i = 0; i < 8; i++) {
rc = TRUE;
for (j = 0; j < sizeof(msg->shamsg_len); j++) {
msg->shamsg_len[j]++;
if (msg->shamsg_len[j] != 0) {
rc = FALSE;
break;
}
}
msg->shamsg_crp = (msg->shamsg_crp == TRUE ||
rc == TRUE) ? TRUE : FALSE;
}
if (msg->shamsg_idx == 64)
shamsg_calcblock(msg);
data++;
}
}
static void shamsg_padmsg(struct shamsg_t *msg)
{
if (msg->shamsg_idx > 55) {
msg->shamsg_blk[msg->shamsg_idx++] = 0x80;
while (msg->shamsg_idx < 64)
msg->shamsg_blk[msg->shamsg_idx++] = 0;
shamsg_calcblock(msg);
while (msg->shamsg_idx < 56)
msg->shamsg_blk[msg->shamsg_idx++] = 0;
} else {
msg->shamsg_blk[msg->shamsg_idx++] = 0x80;
while (msg->shamsg_idx < 56)
msg->shamsg_blk[msg->shamsg_idx++] = 0;
}
msg->shamsg_blk[56] = msg->shamsg_len[7];
msg->shamsg_blk[57] = msg->shamsg_len[6];
msg->shamsg_blk[58] = msg->shamsg_len[5];
msg->shamsg_blk[59] = msg->shamsg_len[4];
msg->shamsg_blk[60] = msg->shamsg_len[3];
msg->shamsg_blk[61] = msg->shamsg_len[2];
msg->shamsg_blk[62] = msg->shamsg_len[1];
msg->shamsg_blk[63] = msg->shamsg_len[0];
shamsg_calcblock(msg);
}
static int get_shamsg_result(struct shamsg_t *msg)
{
if (msg->shamsg_crp == TRUE)
return FALSE;
if (msg->shamsg_crp == FALSE) {
shamsg_padmsg(msg);
msg->shamsg_crp = TRUE;
}
return TRUE;
}
int calc_hdcp_ksv_valid(const unsigned char *data, int size)
{
int i = 0;
struct shamsg_t shamsg;
memset(&shamsg, 0, sizeof(struct shamsg_t));
if (data == NULL || size < (HDCP_HEAD + SHA_MAX_SIZE)) {
pr_info("invalid parameters\n");
return FALSE;
}
shamsg_reset(&shamsg);
shamsg_init(&shamsg, data, size - SHA_MAX_SIZE);
if (get_shamsg_result(&shamsg) == FALSE) {
pr_info("hdcp invalid ksv/sha message\n");
return FALSE;
}
for (i = 0; i < SHA_MAX_SIZE; i++) {
if (data[size - SHA_MAX_SIZE + i] !=
(uint8_t)(shamsg.shamsg_dgt[i / 4]
>> ((i % 4) * 8))) {
pr_info("hdcp ksv/sha not match\n");
return FALSE;
}
}
return TRUE;
}

View File

@@ -0,0 +1,59 @@
/*
* drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/checksha.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef __CHECKSHA_H__
#define __CHECKSHA_H__
#define FALSE 0
#define TRUE 1
#define HDCP_NULL 0
#define HDCP_KSVLIST_VALID 1
#define HDCP_KSVLIST_INVALID 2
#define KSV_SIZE 5
#define HDCP_HEAD 10
#define SHA_MAX_SIZE 20
#define KSV_MASK 0x7F
#define MAX_VAL_MASK 0xFFFFFFFF
#define SHA_CONST_VAL0 0x67452301
#define SHA_CONST_VAL1 0xEFCDAB89
#define SHA_CONST_VAL2 0x98BADCFE
#define SHA_CONST_VAL3 0x10325476
#define SHA_CONST_VAL4 0xC3D2E1F0
#define SHA_CONST_K0 0x5A827999
#define SHA_CONST_K1 0x6ED9EBA1
#define SHA_CONST_K2 0x8F1BBCDC
#define SHA_CONST_K3 0xCA62C1D6
struct shamsg_t {
unsigned char shamsg_len[8];
unsigned char shamsg_blk[64];
int shamsg_idx;
int shamsg_cmp;
int shamsg_crp;
unsigned int shamsg_dgt[5];
};
#define SHAMSG_SHIFT(bit, val) \
((((val) << (bit)) & 0xFFFFFFFF) | ((val) >> (32-(bit))))
int calc_hdcp_ksv_valid(const unsigned char *dat, int size);
#endif /* __CHECKSHA_H__ */

View File

@@ -1,45 +0,0 @@
/*
* drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/hdcp.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef HDCP_H_
#define HDCP_H_
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
enum hdcp_status_t {
HDCP_IDLE = 0,
HDCP_KSV_LIST_READY,
HDCP_ERR_KSV_LIST_NOT_VALID,
HDCP_KSV_LIST_ERR_DEPTH_EXCEEDED,
HDCP_KSV_LIST_ERR_MEM_ACCESS,
HDCP_ENGAGED,
HDCP_FAILED
};
/* HDCP Interrupt bit fields */
#define INT_KSV_ACCESS (0)
#define INT_KSV_SHA1 (1)
#define INT_HDCP_FAIL (6)
#define INT_HDCP_ENGAGED (7)
#endif /* HDCP_H_ */

View File

@@ -1,600 +0,0 @@
/*
* drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/hdcpVerify.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include "hdcpVerify.h"
#define SIZE (160/8)
#define KSIZE (1024/8)
void sha_Reset(struct sha_t *sha)
{
size_t i = 0;
sha->mIndex = 0;
sha->mComputed = FALSE;
sha->mCorrupted = FALSE;
for (i = 0; i < sizeof(sha->mLength); i++)
sha->mLength[i] = 0;
sha->mDigest[0] = 0x67452301;
sha->mDigest[1] = 0xEFCDAB89;
sha->mDigest[2] = 0x98BADCFE;
sha->mDigest[3] = 0x10325476;
sha->mDigest[4] = 0xC3D2E1F0;
}
int sha_Result(struct sha_t *sha)
{
if (sha->mCorrupted == TRUE)
return FALSE;
if (sha->mComputed == FALSE) {
sha_PadMessage(sha);
sha->mComputed = TRUE;
}
return TRUE;
}
void sha_Input(struct sha_t *sha, const uint8_t *data, size_t size)
{
int i = 0;
unsigned int j = 0;
int rc = TRUE;
if (data == 0 || size == 0) {
pr_info("invalid input data");
return;
}
if (sha->mComputed == TRUE || sha->mCorrupted == TRUE) {
sha->mCorrupted = TRUE;
return;
}
while (size-- && sha->mCorrupted == FALSE) {
sha->mBlock[sha->mIndex++] = *data;
for (i = 0; i < 8; i++) {
rc = TRUE;
for (j = 0; j < sizeof(sha->mLength); j++) {
sha->mLength[j]++;
if (sha->mLength[j] != 0) {
rc = FALSE;
break;
}
}
sha->mCorrupted = (sha->mCorrupted == TRUE ||
rc == TRUE) ? TRUE : FALSE;
}
/* if corrupted then message is too long */
if (sha->mIndex == 64)
sha_ProcessBlock(sha);
data++;
}
}
void sha_ProcessBlock(struct sha_t *sha)
{
#define shaCircularShift(bits, word) \
((((word) << (bits)) & 0xFFFFFFFF) | ((word) >> (32-(bits))))
const unsigned int K[] = {
/* constants defined in SHA-1 */
0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };
unsigned int W[80]; /* word sequence */
unsigned int A, B, C, D, E; /* word buffers */
unsigned int temp = 0;
int t = 0;
/* Initialize the first 16 words in the array W */
for (t = 0; t < 80; t++) {
if (t < 16) {
W[t] = ((unsigned int) sha->mBlock[t * 4 + 0]) << 24;
W[t] |= ((unsigned int) sha->mBlock[t * 4 + 1]) << 16;
W[t] |= ((unsigned int) sha->mBlock[t * 4 + 2]) << 8;
W[t] |= ((unsigned int) sha->mBlock[t * 4 + 3]) << 0;
} else
W[t] = shaCircularShift(1,
W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
}
A = sha->mDigest[0];
B = sha->mDigest[1];
C = sha->mDigest[2];
D = sha->mDigest[3];
E = sha->mDigest[4];
for (t = 0; t < 80; t++) {
temp = shaCircularShift(5, A);
if (t < 20)
temp += ((B & C) | ((~B) & D)) + E + W[t] + K[0];
else if (t < 40)
temp += (B ^ C ^ D) + E + W[t] + K[1];
else if (t < 60)
temp += ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
else
temp += (B ^ C ^ D) + E + W[t] + K[3];
E = D;
D = C;
C = shaCircularShift(30, B);
B = A;
A = (temp & 0xFFFFFFFF);
}
sha->mDigest[0] = (sha->mDigest[0] + A) & 0xFFFFFFFF;
sha->mDigest[1] = (sha->mDigest[1] + B) & 0xFFFFFFFF;
sha->mDigest[2] = (sha->mDigest[2] + C) & 0xFFFFFFFF;
sha->mDigest[3] = (sha->mDigest[3] + D) & 0xFFFFFFFF;
sha->mDigest[4] = (sha->mDigest[4] + E) & 0xFFFFFFFF;
sha->mIndex = 0;
}
void sha_PadMessage(struct sha_t *sha)
{
/*
* Check to see if the current message block is too small to hold
* the initial padding bits and length. If so, we will pad the
* block, process it, and then continue padding into a second
* block.
*/
if (sha->mIndex > 55) {
sha->mBlock[sha->mIndex++] = 0x80;
while (sha->mIndex < 64)
sha->mBlock[sha->mIndex++] = 0;
sha_ProcessBlock(sha);
while (sha->mIndex < 56)
sha->mBlock[sha->mIndex++] = 0;
} else {
sha->mBlock[sha->mIndex++] = 0x80;
while (sha->mIndex < 56)
sha->mBlock[sha->mIndex++] = 0;
}
/* Store the message length as the last 8 octets */
sha->mBlock[56] = sha->mLength[7];
sha->mBlock[57] = sha->mLength[6];
sha->mBlock[58] = sha->mLength[5];
sha->mBlock[59] = sha->mLength[4];
sha->mBlock[60] = sha->mLength[3];
sha->mBlock[61] = sha->mLength[2];
sha->mBlock[62] = sha->mLength[1];
sha->mBlock[63] = sha->mLength[0];
sha_ProcessBlock(sha);
}
int hdcpVerify_DSA(const uint8_t *M, size_t n, const uint8_t *r,
const uint8_t *s)
{
int i = 0;
struct sha_t sha;
static const uint8_t q[] = {
0xE7, 0x08, 0xC7, 0xF9, 0x4D, 0x3F, 0xEF, 0x97,
0xE2, 0x14, 0x6D, 0xCD, 0x6A, 0xB5, 0x6D, 0x5E,
0xCE, 0xF2, 0x8A, 0xEE };
static const uint8_t p[] = {
0x27, 0x75, 0x28, 0xF3, 0x2B, 0x80, 0x59, 0x8C,
0x11, 0xC2, 0xED, 0x46, 0x1C, 0x95, 0x39, 0x2A,
0x54, 0x19, 0x89, 0x96, 0xFD, 0x49, 0x8A, 0x02,
0x3B, 0x73, 0x75, 0x32, 0x14, 0x9C, 0x7B, 0x5C,
0x49, 0x20, 0x98, 0xB9, 0x07, 0x32, 0x3F, 0xA7,
0x30, 0x15, 0x72, 0xB3, 0x09, 0x55, 0x71, 0x10,
0x3A, 0x4C, 0x97, 0xD1, 0xBC, 0xA0, 0x04, 0xF4,
0x35, 0xCF, 0x47, 0x54, 0x0E, 0xA7, 0x2B, 0xE5,
0x83, 0xB9, 0xC6, 0xD4, 0x47, 0xC7, 0x44, 0xB8,
0x67, 0x76, 0x7C, 0xAE, 0x0C, 0xDC, 0x34, 0x4F,
0x4B, 0x9E, 0x96, 0x1D, 0x82, 0x84, 0xD2, 0xA0,
0xDC, 0xE0, 0x00, 0xF5, 0x64, 0xA1, 0x7F, 0x8E,
0xFF, 0x58, 0x70, 0x6A, 0xC3, 0x4F, 0xA2, 0xA1,
0xB8, 0xC7, 0x52, 0x5A, 0x35, 0x5B, 0x39, 0x17,
0x6B, 0x78, 0x43, 0x93, 0xF7, 0x75, 0x8D, 0x01,
0xB7, 0x61, 0x17, 0xFD, 0xB2, 0xF5, 0xC3, 0xD3 };
static const uint8_t g[] = {
0xD9, 0x0B, 0xBA, 0xC2, 0x42, 0x24, 0x46, 0x69,
0x5B, 0x40, 0x67, 0x2F, 0x5B, 0x18, 0x3F, 0xB9,
0xE8, 0x6F, 0x21, 0x29, 0xAC, 0x7D, 0xFA, 0x51,
0xC2, 0x9D, 0x4A, 0xAB, 0x8A, 0x9B, 0x8E, 0xC9,
0x42, 0x42, 0xA5, 0x1D, 0xB2, 0x69, 0xAB, 0xC8,
0xE3, 0xA5, 0xC8, 0x81, 0xBE, 0xB6, 0xA0, 0xB1,
0x7F, 0xBA, 0x21, 0x2C, 0x64, 0x35, 0xC8, 0xF7,
0x5F, 0x58, 0x78, 0xF7, 0x45, 0x29, 0xDD, 0x92,
0x9E, 0x79, 0x3D, 0xA0, 0x0C, 0xCD, 0x29, 0x0E,
0xA9, 0xE1, 0x37, 0xEB, 0xBF, 0xC6, 0xED, 0x8E,
0xA8, 0xFF, 0x3E, 0xA8, 0x7D, 0x97, 0x62, 0x51,
0xD2, 0xA9, 0xEC, 0xBD, 0x4A, 0xB1, 0x5D, 0x8F,
0x11, 0x86, 0x27, 0xCD, 0x66, 0xD7, 0x56, 0x5D,
0x31, 0xD7, 0xBE, 0xA9, 0xAC, 0xDE, 0xAF, 0x02,
0xB5, 0x1A, 0xDE, 0x45, 0x24, 0x3E, 0xE4, 0x1A,
0x13, 0x52, 0x4D, 0x6A, 0x1B, 0x5D, 0xF8, 0x92 };
static const uint8_t y[] = {
0x99, 0x37, 0xE5, 0x36, 0xFA, 0xF7, 0xA9, 0x62,
0x83, 0xFB, 0xB3, 0xE9, 0xF7, 0x9D, 0x8F, 0xD8,
0xCB, 0x62, 0xF6, 0x66, 0x8D, 0xDC, 0xC8, 0x95,
0x10, 0x24, 0x6C, 0x88, 0xBD, 0xFF, 0xB7, 0x7B,
0xE2, 0x06, 0x52, 0xFD, 0xF7, 0x5F, 0x43, 0x62,
0xE6, 0x53, 0x65, 0xB1, 0x38, 0x90, 0x25, 0x87,
0x8D, 0xA4, 0x9E, 0xFE, 0x56, 0x08, 0xA7, 0xA2,
0x0D, 0x4E, 0xD8, 0x43, 0x3C, 0x97, 0xBA, 0x27,
0x6C, 0x56, 0xC4, 0x17, 0xA4, 0xB2, 0x5C, 0x8D,
0xDB, 0x04, 0x17, 0x03, 0x4F, 0xE1, 0x22, 0xDB,
0x74, 0x18, 0x54, 0x1B, 0xDE, 0x04, 0x68, 0xE1,
0xBD, 0x0B, 0x4F, 0x65, 0x48, 0x0E, 0x95, 0x56,
0x8D, 0xA7, 0x5B, 0xF1, 0x55, 0x47, 0x65, 0xE7,
0xA8, 0x54, 0x17, 0x8A, 0x65, 0x76, 0x0D, 0x4F,
0x0D, 0xFF, 0xAC, 0xA3, 0xE0, 0xFB, 0x80, 0x3A,
0x86, 0xB0, 0xA0, 0x6B, 0x52, 0x00, 0x06, 0xC7 };
uint8_t w[SIZE];
uint8_t z[SIZE];
uint8_t u1[SIZE];
uint8_t u2[SIZE];
uint8_t gu1[KSIZE];
uint8_t yu2[KSIZE];
uint8_t pro[KSIZE];
uint8_t v[SIZE];
/* adapt to the expected format by arithmetic functions */
uint8_t r1[SIZE];
uint8_t s1[SIZE];
sha_Reset(&sha);
hdcpVerify_ArrayCPY(r1, r, sizeof(r1));
hdcpVerify_ArrayCPY(s1, s, sizeof(s1));
hdcpVerify_ArraySWP(r1, sizeof(r1));
hdcpVerify_ArraySWP(s1, sizeof(s1));
hdcpVerify_ComputeINV(w, s1, q, sizeof(w));
sha_Input(&sha, M, n);
if (sha_Result(&sha) == TRUE) {
for (i = 0; i < 5; i++) {
z[i * 4 + 0] = sha.mDigest[i] >> 24;
z[i * 4 + 1] = sha.mDigest[i] >> 16;
z[i * 4 + 2] = sha.mDigest[i] >> 8;
z[i * 4 + 3] = sha.mDigest[i] >> 0;
}
hdcpVerify_ArraySWP(z, sizeof(z));
} else {
pr_info("cannot digest message");
return FALSE;
}
if (hdcpVerify_ComputeMUL(u1, z, w, q, sizeof(u1)) == FALSE)
return FALSE;
if (hdcpVerify_ComputeMUL(u2, r1, w, q, sizeof(u2)) == FALSE)
return FALSE;
if (hdcpVerify_ComputeEXP(gu1, g, u1, p, sizeof(gu1), sizeof(u1))
== FALSE)
return FALSE;
if (hdcpVerify_ComputeEXP(yu2, y, u2, p, sizeof(yu2), sizeof(u2))
== FALSE)
return FALSE;
if (hdcpVerify_ComputeMUL(pro, gu1, yu2, p, sizeof(pro)) == FALSE)
return FALSE;
if (hdcpVerify_ComputeMOD(v, pro, q, sizeof(v)) == FALSE)
return FALSE;
return hdcpVerify_ArrayCMP(v, r1, sizeof(v)) == 0;
}
int hdcpVerify_ArrayADD(uint8_t *r, const uint8_t *a, const uint8_t *b,
size_t n)
{
uint8_t c = 0;
size_t i = 0;
for (i = 0; i < n; i++) {
u16 s = a[i] + b[i] + c;
c = (uint8_t) (s >> 8);
r[i] = (uint8_t) s;
}
return c;
}
int hdcpVerify_ArrayCMP(const uint8_t *a, const uint8_t *b, size_t n)
{
int i = 0;
for (i = n; i > 0; i--) {
if (a[i - 1] > b[i - 1])
return 1;
else if (a[i - 1] < b[i - 1])
return -1;
}
return 0;
}
void hdcpVerify_ArrayCPY(uint8_t *dst, const uint8_t *src, size_t n)
{
size_t i = 0;
for (i = 0; i < n; i++)
dst[i] = src[i];
}
int hdcpVerify_ArrayDIV(uint8_t *r, const uint8_t *D, const uint8_t *d,
size_t n)
{
int i = 0;
if (r == D || r == d || (!hdcpVerify_ArrayTST(d, 0, n)) == TRUE) {
pr_info("invalid input data");
return FALSE;
}
hdcpVerify_ArraySET(&r[n], 0, n);
hdcpVerify_ArrayCPY(r, D, n);
for (i = n; i > 0; i--) {
r[i - 1 + n] = 0;
while (hdcpVerify_ArrayCMP(&r[i - 1], d, n) >= 0) {
hdcpVerify_ArraySUB(&r[i - 1], &r[i - 1], d, n);
r[i - 1 + n] += 1;
}
}
return TRUE;
}
int hdcpVerify_ArrayMAC(uint8_t *r, const uint8_t *M, const uint8_t m, size_t n)
{
u16 c = 0;
size_t i = 0;
for (i = 0; i < n; i++) {
u16 p = (M[i] * m) + c + r[i];
c = p >> 8;
r[i] = (uint8_t) p;
}
return (uint8_t) c;
}
int hdcpVerify_ArrayMUL(uint8_t *r, const uint8_t *M, const uint8_t *m,
size_t n)
{
size_t i = 0;
if (r == M || r == m) {
pr_info("invalid input data");
return FALSE;
}
hdcpVerify_ArraySET(r, 0, n);
for (i = 0; i < n; i++) {
if (m[i] == 0)
continue;
else if (m[i] == 1)
hdcpVerify_ArrayADD(&r[i], &r[i], M, n - i);
else
hdcpVerify_ArrayMAC(&r[i], M, m[i], n - i);
}
return TRUE;
}
void hdcpVerify_ArraySET(uint8_t *dst, const uint8_t src, size_t n)
{
size_t i = 0;
for (i = 0; i < n; i++)
dst[i] = src;
}
int hdcpVerify_ArraySUB(uint8_t *r, const uint8_t *a, const uint8_t *b,
size_t n)
{
uint8_t c = 1;
size_t i = 0;
for (i = 0; i < n; i++) {
u16 s = ((uint8_t) a[i] + (uint8_t) (~b[i])) + c;
c = (uint8_t) (s >> 8);
r[i] = (uint8_t) s;
}
return c;
}
void hdcpVerify_ArraySWP(uint8_t *r, size_t n)
{
size_t i = 0;
for (i = 0; i < (n / 2); i++) {
uint8_t tmp = r[i];
r[i] = r[n - 1 - i];
r[n - 1 - i] = tmp;
}
}
int hdcpVerify_ArrayTST(const uint8_t *a, const uint8_t b, size_t n)
{
size_t i = 0;
for (i = 0; i < n; i++) {
if (a[i] != b)
return FALSE;
}
return TRUE;
}
int hdcpVerify_ComputeEXP(uint8_t *c, const uint8_t *M, const uint8_t *e,
const uint8_t *p, size_t n, size_t nE)
{
int i = 8 * nE - 1;
int rc = TRUE;
/* LR Binary Method */
if ((e[i / 8] & (1 << (i % 8))) != 0)
hdcpVerify_ArrayCPY(c, M, n);
else {
hdcpVerify_ArraySET(c, 0, n);
c[0] = 1;
}
for (i -= 1; i >= 0; i--) {
rc |= hdcpVerify_ComputeMUL(c, c, c, p, n);
if ((e[i / 8] & (1 << (i % 8))) != 0)
rc &= hdcpVerify_ComputeMUL(c, c, M, p, n);
}
return rc;
}
int hdcpVerify_ComputeINV(uint8_t *out, const uint8_t *z, const uint8_t *a,
size_t n)
{
uint8_t w[2][SIZE];
uint8_t x[2][SIZE];
uint8_t y[2][SIZE];
uint8_t r[2*SIZE];
uint8_t *i, *j, *q, *t;
uint8_t *x1, *x2;
uint8_t *y1, *y2;
if ((n > SIZE) || (hdcpVerify_ArrayTST(z, 0, n) == TRUE)
|| (hdcpVerify_ArrayTST(a, 0, n) == TRUE)
|| (hdcpVerify_ArrayCMP(z, a, n) >= 0)) {
pr_info("invalid input data");
return FALSE;
}
hdcpVerify_ArrayCPY(w[0], a, n);
hdcpVerify_ArrayCPY(w[1], z, n);
i = w[0];
j = w[1];
hdcpVerify_ArraySET(x[1], 0, n);
x[1][0] = 1;
hdcpVerify_ArraySET(x[0], 0, n);
x2 = x[1];
x1 = x[0];
hdcpVerify_ArraySET(y[1], 0, n);
hdcpVerify_ArraySET(y[0], 0, n);
y[0][0] = 1;
y2 = y[1];
y1 = y[0];
do {
hdcpVerify_ArrayDIV(r, i, j, n);
hdcpVerify_ArrayCPY(i, r, n);
q = &r[n];
t = i; /* swap i <-> j */
i = j;
j = t;
hdcpVerify_ArrayMUL(r, x1, q, n);
hdcpVerify_ArraySUB(x2, x2, r, n);
t = x2; /* swap x1 <-> x2 */
x2 = x1;
x1 = t;
hdcpVerify_ArrayMUL(r, y1, q, n);
hdcpVerify_ArraySUB(y2, y2, r, n);
t = y2; /* swap y1 <-> y2 */
y2 = y1;
y1 = t;
} while (hdcpVerify_ArrayTST(j, 0, n) == FALSE);
j[0] = 1;
if (hdcpVerify_ArrayCMP(i, j, n) != 0) {
pr_info("i != 1");
return FALSE;
}
hdcpVerify_ArrayCPY(out, y2, n);
return TRUE;
}
int hdcpVerify_ComputeMOD(uint8_t *dst, const uint8_t *src, const uint8_t *p,
size_t n)
{
uint8_t aux[KSIZE];
uint8_t ext[SIZE + 1];
uint8_t tmp[2 * (KSIZE + 1)];
int i = 0;
if (n > SIZE) {
pr_info("invalid input data");
return FALSE;
}
hdcpVerify_ArrayCPY(aux, src, sizeof(aux));
/* TODO: remove extension */
hdcpVerify_ArrayCPY(ext, p, n);
ext[n] = 0;
for (i = sizeof(aux)-n-1; i >= 0; i--) {
hdcpVerify_ArrayDIV(tmp, &aux[i], ext, n+1);
hdcpVerify_ArrayCPY(&aux[i], tmp, n+1);
}
hdcpVerify_ArrayCPY(dst, aux, n);
return TRUE;
}
int hdcpVerify_ComputeMUL(uint8_t *p, const uint8_t *a, const uint8_t *b,
const uint8_t *m, size_t n)
{
uint8_t aux[2 * KSIZE + 1];
uint8_t ext[KSIZE + 1];
uint8_t tmp[2 * (KSIZE + 1)];
size_t i = 0;
int j = 0;
if (n > KSIZE) {
pr_info("invalid input data");
return FALSE;
}
hdcpVerify_ArraySET(aux, 0, sizeof(aux));
for (i = 0; i < n; i++) {
/* TODO: extension was faster */
aux[n+i] = hdcpVerify_ArrayMAC(&aux[i], a, b[i], n);
}
/* TODO: reuse ComputeMOD */
hdcpVerify_ArrayCPY(ext, m, n);
ext[n] = 0;
for (j = n; j >= 0; j--) {
hdcpVerify_ArrayDIV(tmp, &aux[j], ext, n+1);
hdcpVerify_ArrayCPY(&aux[j], tmp, n+1);
}
hdcpVerify_ArrayCPY(p, aux, n);
return TRUE;
}
int hdcpVerify_KSV(const uint8_t *data, size_t size)
{
size_t i = 0;
struct sha_t sha;
if (data == 0 || size < (HEADER + SHAMAX)) {
pr_info("invalid input data");
return FALSE;
}
sha_Reset(&sha);
sha_Input(&sha, data, size - SHAMAX);
if (sha_Result(&sha) == FALSE) {
pr_info("cannot process SHA digest");
return FALSE;
}
for (i = 0; i < SHAMAX; i++) {
if (data[size - SHAMAX + i] != (uint8_t) (sha.mDigest[i / 4]
>> ((i % 4) * 8))) {
pr_info("SHA digest does not match");
return FALSE;
}
}
return TRUE;
}
int hdcpVerify_SRM(const uint8_t *data, size_t size)
{
if (data == 0 || size < (VRL_HEADER + VRL_NUMBER + 2 * DSAMAX)) {
pr_info("invalid input data");
return FALSE;
}
/* M, n, r, s */
return hdcpVerify_DSA(data, size - 2 * DSAMAX, &data[size - 2 * DSAMAX],
&data[size - DSAMAX]);
}

View File

@@ -1,97 +0,0 @@
/*
* drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hw/hdcpVerify.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef HDCPVERIFY_H_
#define HDCPVERIFY_H_
#include <linux/types.h>
#include <linux/printk.h>
#include "hdcp.h"
struct sha_t {
uint8_t mLength[8];
uint8_t mBlock[64];
int mIndex;
int mComputed;
int mCorrupted;
unsigned int mDigest[5];
};
#define KSV_LEN 5
#define KSV_MSK 0x7F
#define VRL_LENGTH 0x05
#define VRL_HEADER 5
#define VRL_NUMBER 3
#define HEADER 10
#define SHAMAX 20
#define DSAMAX 20
void sha_Reset(struct sha_t *sha);
int sha_Result(struct sha_t *sha);
void sha_Input(struct sha_t *sha, const uint8_t *data, size_t size);
void sha_ProcessBlock(struct sha_t *sha);
void sha_PadMessage(struct sha_t *sha);
int hdcpVerify_DSA(const uint8_t *M, size_t n, const uint8_t *r,
const uint8_t *s);
int hdcpVerify_ArrayADD(uint8_t *r, const uint8_t *a, const uint8_t *b,
size_t n);
int hdcpVerify_ArrayCMP(const uint8_t *a, const uint8_t *b, size_t n);
void hdcpVerify_ArrayCPY(uint8_t *dst, const uint8_t *src, size_t n);
int hdcpVerify_ArrayDIV(uint8_t *r, const uint8_t *D, const uint8_t *d,
size_t n);
int hdcpVerify_ArrayMAC(uint8_t *r, const uint8_t *M, const uint8_t m,
size_t n);
int hdcpVerify_ArrayMUL(uint8_t *r, const uint8_t *M, const uint8_t *m,
size_t n);
void hdcpVerify_ArraySET(uint8_t *dst, const uint8_t src, size_t n);
int hdcpVerify_ArraySUB(uint8_t *r, const uint8_t *a, const uint8_t *b,
size_t n);
void hdcpVerify_ArraySWP(uint8_t *r, size_t n);
int hdcpVerify_ArrayTST(const uint8_t *a, const uint8_t b, size_t n);
int hdcpVerify_ComputeEXP(uint8_t *c, const uint8_t *M, const uint8_t *e,
const uint8_t *p, size_t n, size_t nE);
int hdcpVerify_ComputeINV(uint8_t *out, const uint8_t *z, const uint8_t *a,
size_t n);
int hdcpVerify_ComputeMOD(uint8_t *dst, const uint8_t *src, const uint8_t *p,
size_t n);
int hdcpVerify_ComputeMUL(uint8_t *p, const uint8_t *a, const uint8_t *b,
const uint8_t *m, size_t n);
int hdcpVerify_KSV(const uint8_t *data, size_t size);
int hdcpVerify_SRM(const uint8_t *data, size_t size);
#endif /* HDCPVERIFY_H_ */

View File

@@ -44,9 +44,9 @@
#include "hdmi_tx_reg.h"
#include "tvenc_conf.h"
#include "common.h"
#include "hdcpVerify.h"
#include "hw_clk.h"
#include <linux/arm-smccc.h>
#include "checksha.h"
static void mode420_half_horizontal_para(void);
static void hdmi_phy_suspend(void);
@@ -4192,42 +4192,45 @@ static void hdcp_ksv_sha1_calc(struct hdmitx_dev *hdev)
size_t list = 0;
size_t size = 0;
size_t i = 0;
int valid = HDCP_IDLE;
int valid = HDCP_NULL;
unsigned char ksvs[635] = {0}; /* Max 127 * 5 */
int j = 0;
/* 0x165e: Page 95 */
hdcp_mKsvListBuf = kmalloc(0x1660, GFP_ATOMIC);
if (hdcp_mKsvListBuf) {
/* KSV_LEN; */
list = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_0) & KSV_MSK;
/* KSV_SIZE; */
list = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_0) & KSV_MASK;
if (list <= HDCP_NMOOFDEVICES) {
size = (list * KSV_LEN) + HEADER + SHAMAX;
size = (list * KSV_SIZE) + HDCP_HEAD + SHA_MAX_SIZE;
for (i = 0; i < size; i++) {
if (i < HEADER) { /* BSTATUS & M0 */
hdcp_mKsvListBuf[(list * KSV_LEN) + i]
if (i < HDCP_HEAD) { /* BSTATUS & M0 */
hdcp_mKsvListBuf[(list * KSV_SIZE) + i]
= hdmitx_rd_reg(
HDMITX_DWC_HDCP_BSTATUS_0 + i);
} else if (i < (HEADER + (list * KSV_LEN))) {
} else if (i < (HDCP_HEAD +
(list * KSV_SIZE))) {
/* KSV list */
hdcp_mKsvListBuf[i - HEADER] =
hdcp_mKsvListBuf[i - HDCP_HEAD] =
hdmitx_rd_reg(
HDMITX_DWC_HDCP_BSTATUS_0 + i);
ksvs[j] = hdcp_mKsvListBuf[i - HEADER];
ksvs[j] =
hdcp_mKsvListBuf[i - HDCP_HEAD];
j++;
} else { /* SHA */
hdcp_mKsvListBuf[i] = hdmitx_rd_reg(
HDMITX_DWC_HDCP_BSTATUS_0 + i);
}
}
valid = hdcpVerify_KSV(hdcp_mKsvListBuf, size)
== TRUE ? HDCP_KSV_LIST_READY :
HDCP_ERR_KSV_LIST_NOT_VALID;
if (calc_hdcp_ksv_valid(hdcp_mKsvListBuf, size) == TRUE)
valid = HDCP_KSVLIST_VALID;
else
valid = HDCP_KSVLIST_INVALID;
}
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 0, 1);
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL,
(valid == HDCP_KSV_LIST_READY) ? 0 : 1, 3, 1);
if (valid == HDCP_KSV_LIST_READY)
(valid == HDCP_KSVLIST_VALID) ? 0 : 1, 3, 1);
if (valid == HDCP_KSVLIST_VALID)
hdcp_ksv_store(ksvs, j);
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 1, 2, 1);
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 2, 1);