summaryrefslogtreecommitdiffstats
path: root/src/security/tpm/tss/vendor/cr50/cr50.c
blob: 87889d128b10f871f9a886e9e4f632f402752cd9 (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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/* SPDX-License-Identifier: BSD-3-Clause */

#include <console/console.h>
#include <endian.h>
#include <halt.h>
#include <vb2_api.h>
#include <security/tpm/tis.h>
#include <security/tpm/tss.h>

#include "../../tcg-2.0/tss_marshaling.h"

tpm_result_t tlcl_cr50_enable_nvcommits(void)
{
	uint16_t sub_command = TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS;
	struct tpm2_response *response;

	printk(BIOS_INFO, "Enabling cr50 nvmem commits\n");

	response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, &sub_command);

	if (!response || (response && response->hdr.tpm_code)) {
		if (response)
			printk(BIOS_INFO, "%s: failed %#x\n", __func__,
			       response->hdr.tpm_code);
		else
			printk(BIOS_INFO, "%s: failed\n", __func__);
		return TPM_IOERROR;
	}
	return TPM_SUCCESS;
}

tpm_result_t tlcl_cr50_enable_update(uint16_t timeout_ms,
				     uint8_t *num_restored_headers)
{
	struct tpm2_response *response;
	uint16_t command_body[] = {
		TPM2_CR50_SUB_CMD_TURN_UPDATE_ON, timeout_ms
	};

	printk(BIOS_INFO, "Checking cr50 for pending updates\n");

	response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, command_body);

	if (!response || response->hdr.tpm_code)
		return TPM_IOERROR;

	*num_restored_headers = response->vcr.num_restored_headers;
	return TPM_SUCCESS;
}

tpm_result_t tlcl_cr50_get_recovery_button(uint8_t *recovery_button_state)
{
	struct tpm2_response *response;
	uint16_t sub_command = TPM2_CR50_SUB_CMD_GET_REC_BTN;

	printk(BIOS_INFO, "Checking cr50 for recovery request\n");

	response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, &sub_command);

	if (!response || response->hdr.tpm_code)
		return TPM_IOERROR;

	*recovery_button_state = response->vcr.recovery_button_state;
	return TPM_SUCCESS;
}

tpm_result_t tlcl_cr50_get_tpm_mode(uint8_t *tpm_mode)
{
	struct tpm2_response *response;
	uint16_t mode_command = TPM2_CR50_SUB_CMD_TPM_MODE;
	*tpm_mode = TPM_MODE_INVALID;

	printk(BIOS_INFO, "Reading cr50 TPM mode\n");

	response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, &mode_command);

	if (!response)
		return TPM_IOERROR;

	if (response->hdr.tpm_code == VENDOR_RC_INTERNAL_ERROR) {
		/*
		 * The Cr50 returns VENDOR_RC_INTERNAL_ERROR iff the key ladder
		 * is disabled. The Cr50 requires a reboot to re-enable the key
		 * ladder.
		 */
		return TPM_CB_MUST_REBOOT;
	}

	if (response->hdr.tpm_code == VENDOR_RC_NO_SUCH_COMMAND ||
	    response->hdr.tpm_code == VENDOR_RC_NO_SUCH_SUBCOMMAND) {
		/*
		 * Explicitly inform caller when command is not supported
		 */
		return TPM_CB_NO_SUCH_COMMAND;
	}

	if (response->hdr.tpm_code) {
		/* Unexpected return code from Cr50 */
		return TPM_IOERROR;
	}

	/* TPM command completed without error */
	*tpm_mode = response->vcr.tpm_mode;

	return TPM_SUCCESS;
}

tpm_result_t tlcl_cr50_get_boot_mode(uint8_t *boot_mode)
{
	struct tpm2_response *response;
	uint16_t mode_command = TPM2_CR50_SUB_CMD_GET_BOOT_MODE;

	printk(BIOS_DEBUG, "Reading cr50 boot mode\n");

	response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, &mode_command);

	if (!response)
		return TPM_IOERROR;

	if (response->hdr.tpm_code == VENDOR_RC_NO_SUCH_COMMAND ||
	    response->hdr.tpm_code == VENDOR_RC_NO_SUCH_SUBCOMMAND)
		/* Explicitly inform caller when command is not supported */
		return TPM_CB_NO_SUCH_COMMAND;

	if (response->hdr.tpm_code)
		/* Unexpected return code from Cr50 */
		return TPM_IOERROR;

	*boot_mode = response->vcr.boot_mode;

	return TPM_SUCCESS;
}

tpm_result_t tlcl_cr50_immediate_reset(uint16_t timeout_ms)
{
	struct tpm2_response *response;
	uint16_t reset_command_body[] = {
		TPM2_CR50_SUB_CMD_IMMEDIATE_RESET, timeout_ms};

	/*
	 * Issue an immediate reset to the Cr50.
	 */
	printk(BIOS_INFO, "Issuing cr50 reset\n");
	response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND,
				       &reset_command_body);

	if (!response)
		return TPM_IOERROR;

	return TPM_SUCCESS;
}

tpm_result_t tlcl_cr50_reset_ec(void)
{
	struct tpm2_response *response;
	uint16_t reset_cmd = TPM2_CR50_SUB_CMD_RESET_EC;

	printk(BIOS_DEBUG, "Issuing EC reset\n");

	response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, &reset_cmd);

	if (!response)
		return TPM_IOERROR;

	if (response->hdr.tpm_code == VENDOR_RC_NO_SUCH_COMMAND ||
	    response->hdr.tpm_code == VENDOR_RC_NO_SUCH_SUBCOMMAND)
		/* Explicitly inform caller when command is not supported */
		return TPM_CB_NO_SUCH_COMMAND;

	if (response->hdr.tpm_code)
		/* Unexpected return code from Cr50 */
		return TPM_IOERROR;

	printk(BIOS_DEBUG, "EC reset coming up...\n");
	halt();

	return TPM_SUCCESS;
}