summaryrefslogtreecommitdiff
path: root/board/cr50/tpm2/tpm_mode.c
blob: 9d249fc106a59e3692078cd4d3307db159f2fe07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/*
 * Copyright 2018 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "config.h"
#include "Global.h"
#include "board.h"
#include "closed_source_set1.h"
#include "console.h"
#include "dcrypto.h"
#include "extension.h"
#include "hooks.h"
#include "nvmem.h"
#include "system.h"
#include "timer.h"
#include "tpm_registers.h"
#include "tpm_vendor_cmds.h"

#define CPRINTS(format, args...) cprints(CC_EXTENSION, format, ## args)

static void disable_tpm(void)
{
	nvmem_enable_commits();
	tpm_stop();
	DCRYPTO_ladder_revoke();
	nvmem_clear_cache();

	if (board_uses_closed_source_set1())
		close_source_set1_disable_tpm();
}
DECLARE_DEFERRED(disable_tpm);

/*
 * Set TPM mode to TPM_MODE_ENABLED or TPM_MODE_DISABLED once per tpm reset.
 *
 * If mode is set to TPM_MODE_ENABLED, it can't be set to DISABLED until the
 * AP resets.
 *
 * If mode is set to TPM_MODE_DISABLED, the AP loses the ability to
 * communicate with the TPM until next TPM reset (which will trigger the H1
 * hardware reset in that case). Resetting the TPM will clear tpm_mode field and
 * enable AP communication, but the TPM will not be fully operational until the
 * crypto hardware is restarted. That's why a full Cr50 reboot is required to
 * restore TPM operation.
 *
 * On TPM reset event, tpm_reset_now() in tpm_registers.c clears TPM2 BSS memory
 * area. By placing s_tpm_mode in TPM2 BSS area, TPM mode value shall be
 * "TPM_MODE_ENABLED_TENTATIVE" on every TPM reset events.
 */
static enum tpm_modes s_tpm_mode __attribute__((section(".bss.Tpm2_common")));

static enum vendor_cmd_rc process_tpm_mode(struct vendor_cmd_params *p)
{
	uint8_t mode_val;
	uint8_t *buffer;

	p->out_size = 0;

	if (p->in_size > sizeof(uint8_t))
		return VENDOR_RC_NOT_ALLOWED;

	buffer = (uint8_t *)p->buffer;
	if (p->in_size == sizeof(uint8_t)) {

		if (s_tpm_mode != TPM_MODE_ENABLED_TENTATIVE)
			return VENDOR_RC_NOT_ALLOWED;

		mode_val = buffer[0];

		switch (mode_val) {
		case TPM_MODE_ENABLED:
			/*
			 * If Key ladder is disabled, then fail this request.
			 */
			if (!DCRYPTO_ladder_is_enabled())
				return VENDOR_RC_INTERNAL_ERROR;
			break;
		case TPM_MODE_DISABLED:
			/*
			 * If it is to be disabled, call disable_tpm() deferred
			 * so that this vendor command can be responded to
			 * before TPM stops.
			 */
			hook_call_deferred(&disable_tpm_data, 10 * MSEC);
			break;
		default:
			return VENDOR_RC_NO_SUCH_SUBCOMMAND;
		}
		s_tpm_mode = mode_val;
	} else {
		if (s_tpm_mode < TPM_MODE_DISABLED &&
		    !DCRYPTO_ladder_is_enabled())
			return VENDOR_RC_INTERNAL_ERROR;
	}

	p->out_size = sizeof(uint8_t);
	buffer[0] = (uint8_t) s_tpm_mode;

	return VENDOR_RC_SUCCESS;
}
DECLARE_VENDOR_COMMAND_P(VENDOR_CC_TPM_MODE, process_tpm_mode);

enum tpm_modes get_tpm_mode(void)
{
	return s_tpm_mode;
}