summaryrefslogtreecommitdiff
path: root/src/security/tpm/tss/vendor/cr50/cr50.c
blob: ae2f7c25162cb862324a50dbcbfef3b5a565c9e0 (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
/*
 * Copyright 2016 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 <console/console.h>
#include <endian.h>
#include <vb2_api.h>
#include <security/tpm/tis.h>
#include <security/tpm/tss.h>

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

uint32_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 commmits\n");

	response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, &sub_command);

	if (response == NULL || (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_E_IOERROR;
	}
	return TPM_SUCCESS;
}

uint32_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_E_IOERROR;

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

uint32_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_E_IOERROR;

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

uint32_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_E_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_E_MUST_REBOOT;
	}

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

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

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

	return TPM_SUCCESS;
}

uint32_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_E_IOERROR;

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

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

	*boot_mode = response->vcr.boot_mode;

	return TPM_SUCCESS;
}

uint32_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_E_IOERROR;

	return TPM_SUCCESS;
}