cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hdcp1_transition.c (10655B)


      1/*
      2 * Copyright 2019 Advanced Micro Devices, Inc.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 * OTHER DEALINGS IN THE SOFTWARE.
     21 *
     22 * Authors: AMD
     23 *
     24 */
     25
     26#include "hdcp.h"
     27
     28enum mod_hdcp_status mod_hdcp_hdcp1_transition(struct mod_hdcp *hdcp,
     29		struct mod_hdcp_event_context *event_ctx,
     30		struct mod_hdcp_transition_input_hdcp1 *input,
     31		struct mod_hdcp_output *output)
     32{
     33	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
     34	struct mod_hdcp_connection *conn = &hdcp->connection;
     35	struct mod_hdcp_link_adjustment *adjust = &hdcp->connection.link.adjust;
     36
     37	switch (current_state(hdcp)) {
     38	case H1_A0_WAIT_FOR_ACTIVE_RX:
     39		if (input->bksv_read != PASS || input->bcaps_read != PASS) {
     40			/* 1A-04: repeatedly attempts on port access failure */
     41			callback_in_ms(500, output);
     42			increment_stay_counter(hdcp);
     43			break;
     44		}
     45		callback_in_ms(0, output);
     46		set_state_id(hdcp, output, H1_A1_EXCHANGE_KSVS);
     47		break;
     48	case H1_A1_EXCHANGE_KSVS:
     49		if (input->create_session != PASS) {
     50			/* out of sync with psp state */
     51			adjust->hdcp1.disable = 1;
     52			fail_and_restart_in_ms(0, &status, output);
     53			break;
     54		} else if (input->an_write != PASS ||
     55				input->aksv_write != PASS ||
     56				input->bksv_read != PASS ||
     57				input->bksv_validation != PASS ||
     58				input->ainfo_write == FAIL) {
     59			/* 1A-05: consider invalid bksv a failure */
     60			fail_and_restart_in_ms(0, &status, output);
     61			break;
     62		}
     63		callback_in_ms(300, output);
     64		set_state_id(hdcp, output,
     65			H1_A2_COMPUTATIONS_A3_VALIDATE_RX_A6_TEST_FOR_REPEATER);
     66		break;
     67	case H1_A2_COMPUTATIONS_A3_VALIDATE_RX_A6_TEST_FOR_REPEATER:
     68		if (input->bcaps_read != PASS ||
     69				input->r0p_read != PASS) {
     70			fail_and_restart_in_ms(0, &status, output);
     71			break;
     72		} else if (input->rx_validation != PASS) {
     73			/* 1A-06: consider invalid r0' a failure */
     74			/* 1A-08: consider bksv listed in SRM a failure */
     75			/*
     76			 * some slow RX will fail rx validation when it is
     77			 * not ready. give it more time to react before retry.
     78			 */
     79			fail_and_restart_in_ms(1000, &status, output);
     80			break;
     81		} else if (!conn->is_repeater && input->encryption != PASS) {
     82			fail_and_restart_in_ms(0, &status, output);
     83			break;
     84		}
     85		if (conn->is_repeater) {
     86			callback_in_ms(0, output);
     87			set_watchdog_in_ms(hdcp, 5000, output);
     88			set_state_id(hdcp, output, H1_A8_WAIT_FOR_READY);
     89		} else {
     90			callback_in_ms(0, output);
     91			set_state_id(hdcp, output, H1_A45_AUTHENTICATED);
     92			set_auth_complete(hdcp, output);
     93		}
     94		break;
     95	case H1_A45_AUTHENTICATED:
     96		if (input->link_maintenance == FAIL) {
     97			/* 1A-07: consider invalid ri' a failure */
     98			/* 1A-07a: consider read ri' not returned a failure */
     99			fail_and_restart_in_ms(0, &status, output);
    100			break;
    101		}
    102		callback_in_ms(500, output);
    103		increment_stay_counter(hdcp);
    104		break;
    105	case H1_A8_WAIT_FOR_READY:
    106		if (input->ready_check != PASS) {
    107			if (event_ctx->event ==
    108					MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) {
    109				/* 1B-03: fail hdcp on ksv list READY timeout */
    110				/* prevent black screen in next attempt */
    111				adjust->hdcp1.postpone_encryption = 1;
    112				fail_and_restart_in_ms(0, &status, output);
    113			} else {
    114				/* continue ksv list READY polling*/
    115				callback_in_ms(500, output);
    116				increment_stay_counter(hdcp);
    117			}
    118			break;
    119		}
    120		callback_in_ms(0, output);
    121		set_state_id(hdcp, output, H1_A9_READ_KSV_LIST);
    122		break;
    123	case H1_A9_READ_KSV_LIST:
    124		if (input->bstatus_read != PASS ||
    125				input->max_cascade_check != PASS ||
    126				input->max_devs_check != PASS ||
    127				input->device_count_check != PASS ||
    128				input->ksvlist_read != PASS ||
    129				input->vp_read != PASS ||
    130				input->ksvlist_vp_validation != PASS ||
    131				input->encryption != PASS) {
    132			/* 1B-06: consider MAX_CASCADE_EXCEEDED a failure */
    133			/* 1B-05: consider MAX_DEVS_EXCEEDED a failure */
    134			/* 1B-04: consider invalid v' a failure */
    135			fail_and_restart_in_ms(0, &status, output);
    136			break;
    137		}
    138		callback_in_ms(0, output);
    139		set_state_id(hdcp, output, H1_A45_AUTHENTICATED);
    140		set_auth_complete(hdcp, output);
    141		break;
    142	default:
    143		status = MOD_HDCP_STATUS_INVALID_STATE;
    144		fail_and_restart_in_ms(0, &status, output);
    145		break;
    146	}
    147
    148	return status;
    149}
    150
    151enum mod_hdcp_status mod_hdcp_hdcp1_dp_transition(struct mod_hdcp *hdcp,
    152		struct mod_hdcp_event_context *event_ctx,
    153		struct mod_hdcp_transition_input_hdcp1 *input,
    154		struct mod_hdcp_output *output)
    155{
    156	enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
    157	struct mod_hdcp_connection *conn = &hdcp->connection;
    158	struct mod_hdcp_link_adjustment *adjust = &hdcp->connection.link.adjust;
    159
    160	switch (current_state(hdcp)) {
    161	case D1_A0_DETERMINE_RX_HDCP_CAPABLE:
    162		if (input->bcaps_read != PASS) {
    163			/* 1A-04: no authentication on bcaps read failure */
    164			fail_and_restart_in_ms(0, &status, output);
    165			break;
    166		} else if (input->hdcp_capable_dp != PASS) {
    167			adjust->hdcp1.disable = 1;
    168			fail_and_restart_in_ms(0, &status, output);
    169			break;
    170		}
    171		callback_in_ms(0, output);
    172		set_state_id(hdcp, output, D1_A1_EXCHANGE_KSVS);
    173		break;
    174	case D1_A1_EXCHANGE_KSVS:
    175		if (input->create_session != PASS) {
    176			/* out of sync with psp state */
    177			adjust->hdcp1.disable = 1;
    178			fail_and_restart_in_ms(0, &status, output);
    179			break;
    180		} else if (input->an_write != PASS ||
    181				input->aksv_write != PASS ||
    182				input->bksv_read != PASS ||
    183				input->bksv_validation != PASS ||
    184				input->ainfo_write == FAIL) {
    185			/* 1A-05: consider invalid bksv a failure */
    186			fail_and_restart_in_ms(0, &status, output);
    187			break;
    188		}
    189		set_watchdog_in_ms(hdcp, 100, output);
    190		set_state_id(hdcp, output, D1_A23_WAIT_FOR_R0_PRIME);
    191		break;
    192	case D1_A23_WAIT_FOR_R0_PRIME:
    193		if (input->bstatus_read != PASS) {
    194			fail_and_restart_in_ms(0, &status, output);
    195			break;
    196		} else if (input->r0p_available_dp != PASS) {
    197			if (event_ctx->event == MOD_HDCP_EVENT_WATCHDOG_TIMEOUT)
    198				fail_and_restart_in_ms(0, &status, output);
    199			else
    200				increment_stay_counter(hdcp);
    201			break;
    202		}
    203		callback_in_ms(0, output);
    204		set_state_id(hdcp, output, D1_A2_COMPUTATIONS_A3_VALIDATE_RX_A5_TEST_FOR_REPEATER);
    205		break;
    206	case D1_A2_COMPUTATIONS_A3_VALIDATE_RX_A5_TEST_FOR_REPEATER:
    207		if (input->r0p_read != PASS) {
    208			fail_and_restart_in_ms(0, &status, output);
    209			break;
    210		} else if (input->rx_validation != PASS) {
    211			if (hdcp->state.stay_count < 2 &&
    212					!hdcp->connection.is_hdcp1_revoked) {
    213				/* allow 2 additional retries */
    214				callback_in_ms(0, output);
    215				increment_stay_counter(hdcp);
    216			} else {
    217				/*
    218				 * 1A-06: consider invalid r0' a failure
    219				 * after 3 attempts.
    220				 * 1A-08: consider bksv listed in SRM a failure
    221				 */
    222				/*
    223				 * some slow RX will fail rx validation when it is
    224				 * not ready. give it more time to react before retry.
    225				 */
    226				fail_and_restart_in_ms(1000, &status, output);
    227			}
    228			break;
    229		} else if ((!conn->is_repeater && input->encryption != PASS) ||
    230				(!conn->is_repeater && is_dp_mst_hdcp(hdcp) && input->stream_encryption_dp != PASS)) {
    231			fail_and_restart_in_ms(0, &status, output);
    232			break;
    233		} else if (conn->hdcp1_retry_count < conn->link.adjust.hdcp1.min_auth_retries_wa) {
    234			fail_and_restart_in_ms(200, &status, output);
    235			break;
    236		}
    237		if (conn->is_repeater) {
    238			set_watchdog_in_ms(hdcp, 5000, output);
    239			set_state_id(hdcp, output, D1_A6_WAIT_FOR_READY);
    240		} else {
    241			set_state_id(hdcp, output, D1_A4_AUTHENTICATED);
    242			set_auth_complete(hdcp, output);
    243		}
    244		break;
    245	case D1_A4_AUTHENTICATED:
    246		if (input->link_integrity_check == FAIL ||
    247				input->reauth_request_check == FAIL) {
    248			/* 1A-07: restart hdcp on a link integrity failure */
    249			fail_and_restart_in_ms(0, &status, output);
    250			break;
    251		}
    252		break;
    253	case D1_A6_WAIT_FOR_READY:
    254		if (input->link_integrity_check == FAIL ||
    255				input->reauth_request_check == FAIL) {
    256			fail_and_restart_in_ms(0, &status, output);
    257			break;
    258		} else if (input->ready_check != PASS) {
    259			if (event_ctx->event ==
    260					MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) {
    261				/* 1B-04: fail hdcp on ksv list READY timeout */
    262				/* prevent black screen in next attempt */
    263				adjust->hdcp1.postpone_encryption = 1;
    264				fail_and_restart_in_ms(0, &status, output);
    265			} else {
    266				increment_stay_counter(hdcp);
    267			}
    268			break;
    269		}
    270		callback_in_ms(0, output);
    271		set_state_id(hdcp, output, D1_A7_READ_KSV_LIST);
    272		break;
    273	case D1_A7_READ_KSV_LIST:
    274		if (input->binfo_read_dp != PASS ||
    275				input->max_cascade_check != PASS ||
    276				input->max_devs_check != PASS) {
    277			/* 1B-06: consider MAX_DEVS_EXCEEDED a failure */
    278			/* 1B-07: consider MAX_CASCADE_EXCEEDED a failure */
    279			fail_and_restart_in_ms(0, &status, output);
    280			break;
    281		} else if (input->device_count_check != PASS) {
    282			/*
    283			 * some slow dongle doesn't update
    284			 * device count as soon as downstream is connected.
    285			 * give it more time to react.
    286			 */
    287			adjust->hdcp1.postpone_encryption = 1;
    288			fail_and_restart_in_ms(1000, &status, output);
    289			break;
    290		} else if (input->ksvlist_read != PASS ||
    291				input->vp_read != PASS) {
    292			fail_and_restart_in_ms(0, &status, output);
    293			break;
    294		} else if (input->ksvlist_vp_validation != PASS) {
    295			if (hdcp->state.stay_count < 2 &&
    296					!hdcp->connection.is_hdcp1_revoked) {
    297				/* allow 2 additional retries */
    298				callback_in_ms(0, output);
    299				increment_stay_counter(hdcp);
    300			} else {
    301				/*
    302				 * 1B-05: consider invalid v' a failure
    303				 * after 3 attempts.
    304				 */
    305				fail_and_restart_in_ms(0, &status, output);
    306			}
    307			break;
    308		} else if (input->encryption != PASS ||
    309				(is_dp_mst_hdcp(hdcp) && input->stream_encryption_dp != PASS)) {
    310			fail_and_restart_in_ms(0, &status, output);
    311			break;
    312		}
    313		set_state_id(hdcp, output, D1_A4_AUTHENTICATED);
    314		set_auth_complete(hdcp, output);
    315		break;
    316	default:
    317		fail_and_restart_in_ms(0, &status, output);
    318		break;
    319	}
    320
    321	return status;
    322}