blob: cebc239d0d3528d56dc2736c8842dd4cf8d3cce1 [file] [log] [blame]
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001// Implementation of the TCG BIOS extension according to the specification
Stefan Berger2aff1c12015-05-26 15:48:33 -04002// described in specs found at
3// http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios
Stefan Bergerb310dfa2015-03-23 14:22:16 -04004//
Stefan Berger2aff1c12015-05-26 15:48:33 -04005// Copyright (C) 2006-2011, 2014, 2015 IBM Corporation
Stefan Bergerb310dfa2015-03-23 14:22:16 -04006//
7// Authors:
8// Stefan Berger <stefanb@linux.vnet.ibm.com>
9//
10// This file may be distributed under the terms of the GNU LGPLv3 license.
11
Kevin O'Connordf50aaa2015-11-19 09:24:18 -050012#include "bregs.h" // struct bregs
Stefan Bergerb310dfa2015-03-23 14:22:16 -040013#include "byteorder.h" // cpu_to_*
Kevin O'Connordf50aaa2015-11-19 09:24:18 -050014#include "config.h" // CONFIG_TCGBIOS
Stefan Bergerb310dfa2015-03-23 14:22:16 -040015#include "farptr.h" // MAKE_FLATPTR
Kevin O'Connordf50aaa2015-11-19 09:24:18 -050016#include "fw/paravirt.h" // runningOnXen
17#include "hw/tpm_drivers.h" // tpm_drivers[]
18#include "output.h" // dprintf
19#include "sha1.h" // sha1
20#include "std/acpi.h" // RSDP_SIGNATURE, rsdt_descriptor
21#include "std/smbios.h" // struct smbios_entry_point
22#include "std/tcg.h" // TCG_PC_LOGOVERFLOW
Stefan Bergerb310dfa2015-03-23 14:22:16 -040023#include "string.h" // checksum
24#include "tcgbios.h"// tpm_*, prototypes
25#include "util.h" // printf, get_keystroke
Stefan Berger320df852015-11-30 11:14:19 -050026#include "stacks.h" // wait_threads, reset
Stefan Bergerb310dfa2015-03-23 14:22:16 -040027
Stefan Berger0d289b52015-06-09 19:56:29 -040028static const u8 Startup_ST_CLEAR[] = { 0x00, TPM_ST_CLEAR };
29static const u8 Startup_ST_STATE[] = { 0x00, TPM_ST_STATE };
Stefan Bergerb310dfa2015-03-23 14:22:16 -040030
Stefan Berger0d289b52015-06-09 19:56:29 -040031static const u8 PhysicalPresence_CMD_ENABLE[] = { 0x00, 0x20 };
32static const u8 PhysicalPresence_CMD_DISABLE[] = { 0x01, 0x00 };
33static const u8 PhysicalPresence_PRESENT[] = { 0x00, 0x08 };
34static const u8 PhysicalPresence_NOT_PRESENT_LOCK[] = { 0x00, 0x14 };
Stefan Bergerb310dfa2015-03-23 14:22:16 -040035
36static const u8 CommandFlag_FALSE[1] = { 0x00 };
37static const u8 CommandFlag_TRUE[1] = { 0x01 };
38
Kevin O'Connor27065322015-11-28 14:25:41 -050039typedef u8 tpm_ppi_code;
40
Stefan Bergerb310dfa2015-03-23 14:22:16 -040041
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050042/****************************************************************
Kevin O'Connor27065322015-11-28 14:25:41 -050043 * ACPI TCPA table interface
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050044 ****************************************************************/
Stefan Bergerb310dfa2015-03-23 14:22:16 -040045
Kevin O'Connor27065322015-11-28 14:25:41 -050046struct {
Stefan Berger60bb9e92015-11-21 14:54:42 -050047 /* length of the TCPA log buffer */
48 u32 log_area_minimum_length;
49
50 /* start address of TCPA log buffer */
51 u8 * log_area_start_address;
52
53 /* number of log entries written */
54 u32 entry_count;
55
56 /* address to write next log entry to */
57 u8 * log_area_next_entry;
58
59 /* address of last entry written (need for TCG_StatusCheck) */
60 u8 * log_area_last_entry;
Kevin O'Connor27065322015-11-28 14:25:41 -050061} tpm_state VARLOW;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050062
63static struct tcpa_descriptor_rev2 *
64find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
65{
Kevin O'Connor27065322015-11-28 14:25:41 -050066 if (!rsdp) {
67 dprintf(DEBUG_tcg,
68 "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
69 return NULL;
70 }
71 struct rsdt_descriptor *rsdt = (void*)rsdp->rsdt_physical_address;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050072 if (!rsdt)
73 return NULL;
74
Kevin O'Connor27065322015-11-28 14:25:41 -050075 u32 length = rsdt->length;
76 u16 off = offsetof(struct rsdt_descriptor, entry);
77 u32 ctr = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050078 while ((off + sizeof(rsdt->entry[0])) <= length) {
79 /* try all pointers to structures */
Kevin O'Connor27065322015-11-28 14:25:41 -050080 struct tcpa_descriptor_rev2 *tcpa = (void*)rsdt->entry[ctr];
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050081
82 /* valid TCPA ACPI table ? */
Kevin O'Connor27065322015-11-28 14:25:41 -050083 if (tcpa->signature == TCPA_SIGNATURE
84 && checksum(tcpa, tcpa->length) == 0)
85 return tcpa;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050086
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050087 off += sizeof(rsdt->entry[0]);
88 ctr++;
89 }
90
Kevin O'Connor27065322015-11-28 14:25:41 -050091 dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
92 return NULL;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050093}
94
Kevin O'Connor27065322015-11-28 14:25:41 -050095static int
96tpm_tcpa_probe(void)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050097{
Kevin O'Connor27065322015-11-28 14:25:41 -050098 struct tcpa_descriptor_rev2 *tcpa = find_tcpa_by_rsdp(RsdpAddr);
99 if (!tcpa)
100 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500101
Kevin O'Connor27065322015-11-28 14:25:41 -0500102 u8 *log_area_start_address = (u8*)(long)tcpa->log_area_start_address;
103 u32 log_area_minimum_length = tcpa->log_area_minimum_length;
104 if (!log_area_start_address || !log_area_minimum_length)
105 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500106
Kevin O'Connor27065322015-11-28 14:25:41 -0500107 memset(log_area_start_address, 0, log_area_minimum_length);
108 tpm_state.log_area_start_address = log_area_start_address;
109 tpm_state.log_area_minimum_length = log_area_minimum_length;
110 tpm_state.log_area_next_entry = log_area_start_address;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500111 tpm_state.log_area_last_entry = NULL;
112 tpm_state.entry_count = 0;
Kevin O'Connor27065322015-11-28 14:25:41 -0500113 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500114}
115
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500116/*
117 * Extend the ACPI log with the given entry by copying the
118 * entry data into the log.
119 * Input
120 * pcpes : Pointer to the event 'header' to be copied into the log
121 * event : Pointer to the event 'body' to be copied into the log
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500122 *
123 * Output:
124 * Returns an error code in case of faiure, 0 in case of success
125 */
126static u32
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500127tpm_log_event(struct pcpes *pcpes, const void *event)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500128{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500129 dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n",
130 tpm_state.log_area_start_address, tpm_state.log_area_next_entry);
131
Kevin O'Connorf4820ac2015-11-22 11:00:06 -0500132 if (tpm_state.log_area_next_entry == NULL)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500133 return TCG_PC_LOGOVERFLOW;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500134
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500135 u32 size = sizeof(*pcpes) + pcpes->eventdatasize;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500136
137 if ((tpm_state.log_area_next_entry + size - tpm_state.log_area_start_address) >
138 tpm_state.log_area_minimum_length) {
139 dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500140 return TCG_PC_LOGOVERFLOW;
141 }
142
Kevin O'Connorbad6f962015-11-23 22:32:09 -0500143 memcpy(tpm_state.log_area_next_entry, pcpes, sizeof(*pcpes));
144 memcpy(tpm_state.log_area_next_entry + sizeof(*pcpes),
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500145 event, pcpes->eventdatasize);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500146
147 tpm_state.log_area_last_entry = tpm_state.log_area_next_entry;
148 tpm_state.log_area_next_entry += size;
149 tpm_state.entry_count++;
150
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500151 return 0;
152}
153
154
155/****************************************************************
156 * Helper functions
157 ****************************************************************/
158
Kevin O'Connord559a232015-11-28 08:35:26 -0500159u8 TPM_working VARLOW;
160
161int
162tpm_is_working(void)
163{
164 return CONFIG_TCGBIOS && TPM_working;
165}
166
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400167/*
168 * Send a TPM command with the given ordinal. Append the given buffer
169 * containing all data in network byte order to the command (this is
170 * the custom part per command) and expect a response of the given size.
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400171 */
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500172static int
Stefan Berger47b9df52015-11-21 14:54:40 -0500173build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500174 enum tpmDurationType to_t)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400175{
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500176 struct {
177 struct tpm_req_header trqh;
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500178 u8 cmd[2];
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500179 } PACKED req = {
180 .trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500181 .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + append_size),
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500182 .trqh.ordinal = cpu_to_be32(ordinal),
183 };
Stefan Bergerece25612015-11-12 10:14:46 -0500184 u8 obuffer[64];
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400185 struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400186 u32 obuffer_len = sizeof(obuffer);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400187 memset(obuffer, 0x0, sizeof(obuffer));
188
Kevin O'Connor71479612015-12-29 14:32:19 -0500189 if (append_size > sizeof(req.cmd)) {
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500190 warn_internalerror();
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500191 return -1;
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500192 }
193 if (append_size)
194 memcpy(req.cmd, append, append_size);
195
Kevin O'Connor2df70282015-11-28 13:43:22 -0500196 u32 rc = tpmhw_transmit(locty, &req.trqh, obuffer, &obuffer_len, to_t);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500197 int ret = rc ? -1 : be32_to_cpu(trsh->errcode);
198 dprintf(DEBUG_tcg, "Return from build_and_send_cmd(%x, %x %x) = %x\n",
199 ordinal, req.cmd[0], req.cmd[1], ret);
200 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400201}
202
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500203static void
204tpm_set_failure(void)
205{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500206 /* we will try to deactivate the TPM now - ignoring all errors */
207 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
208 PhysicalPresence_CMD_ENABLE,
209 sizeof(PhysicalPresence_CMD_ENABLE),
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500210 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500211
212 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
213 PhysicalPresence_PRESENT,
214 sizeof(PhysicalPresence_PRESENT),
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500215 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500216
217 build_and_send_cmd(0, TPM_ORD_SetTempDeactivated,
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500218 NULL, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500219
Kevin O'Connord559a232015-11-28 08:35:26 -0500220 TPM_working = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500221}
222
Kevin O'Connorca606362015-12-29 14:21:29 -0500223static int
224tpm_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize)
225{
226 struct tpm_req_getcap trgc = {
227 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
228 .hdr.totlen = cpu_to_be32(sizeof(trgc)),
229 .hdr.ordinal = cpu_to_be32(TPM_ORD_GetCapability),
230 .capArea = cpu_to_be32(cap),
231 .subCapSize = cpu_to_be32(sizeof(trgc.subCap)),
232 .subCap = cpu_to_be32(subcap)
233 };
234 u32 resp_size = rsize;
235 u32 rc = tpmhw_transmit(0, &trgc.hdr, rsp, &resp_size,
236 TPM_DURATION_TYPE_SHORT);
237 int ret = (rc || resp_size != rsize) ? -1 : be32_to_cpu(rsp->errcode);
238 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(%d, %d)"
239 " = %x\n", cap, subcap, ret);
240 if (ret) {
241 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
242 tpm_set_failure();
243 }
244 return ret;
245}
246
247static int
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400248determine_timeouts(void)
249{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400250 struct tpm_res_getcap_timeouts timeouts;
Kevin O'Connorca606362015-12-29 14:21:29 -0500251 int ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_TIS_TIMEOUT
252 , &timeouts.hdr, sizeof(timeouts));
253 if (ret)
254 return ret;
255
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400256 struct tpm_res_getcap_durations durations;
Kevin O'Connorca606362015-12-29 14:21:29 -0500257 ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION
258 , &durations.hdr, sizeof(durations));
259 if (ret)
260 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400261
Kevin O'Connorca606362015-12-29 14:21:29 -0500262 int i;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400263 for (i = 0; i < 3; i++)
264 durations.durations[i] = be32_to_cpu(durations.durations[i]);
265
266 for (i = 0; i < 4; i++)
267 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
268
269 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
270 timeouts.timeouts[0],
271 timeouts.timeouts[1],
272 timeouts.timeouts[2],
273 timeouts.timeouts[3]);
274
275 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
276 durations.durations[0],
277 durations.durations[1],
278 durations.durations[2]);
279
Kevin O'Connorba86edb2015-11-19 18:03:35 -0500280 tpmhw_set_timeouts(timeouts.timeouts, durations.durations);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400281
282 return 0;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400283}
284
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500285static u32
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500286tpm_log_extend_event(struct pcpes *pcpes, const void *event)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500287{
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500288 if (pcpes->pcrindex >= 24)
289 return TCG_INVALID_INPUT_PARA;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500290
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500291 struct tpm_req_extend tre = {
Kevin O'Connora0599152015-11-28 08:08:57 -0500292 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
293 .hdr.totlen = cpu_to_be32(sizeof(tre)),
294 .hdr.ordinal = cpu_to_be32(TPM_ORD_Extend),
295 .pcrindex = cpu_to_be32(pcpes->pcrindex),
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500296 };
297 memcpy(tre.digest, pcpes->digest, sizeof(tre.digest));
298
299 struct tpm_rsp_extend rsp;
300 u32 resp_length = sizeof(rsp);
Kevin O'Connor2df70282015-11-28 13:43:22 -0500301 u32 rc = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length,
302 TPM_DURATION_TYPE_SHORT);
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500303 if (rc || resp_length != sizeof(rsp) || rsp.hdr.errcode)
304 return rc ?: TCG_TCG_COMMAND_ERROR;
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500305
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500306 return tpm_log_event(pcpes, event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500307}
308
Kevin O'Connor92244402015-11-22 16:54:18 -0500309static void
310tpm_fill_hash(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length)
311{
312 if (hashdata)
313 sha1(hashdata, hashdata_length, pcpes->digest);
314}
315
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500316/*
317 * Add a measurement to the log; the data at data_seg:data/length are
318 * appended to the TCG_PCClientPCREventStruct
319 *
320 * Input parameters:
321 * pcrindex : which PCR to extend
322 * event_type : type of event; specs section on 'Event Types'
323 * event : pointer to info (e.g., string) to be added to log as-is
324 * event_length: length of the event
325 * hashdata : pointer to the data to be hashed
326 * hashdata_length: length of the data to be hashed
327 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500328static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500329tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
330 const char *event, u32 event_length,
331 const u8 *hashdata, u32 hashdata_length)
332{
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500333 if (!tpm_is_working())
334 return;
335
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500336 struct pcpes pcpes = {
337 .pcrindex = pcrindex,
338 .eventtype = event_type,
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500339 .eventdatasize = event_length,
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500340 };
Kevin O'Connor92244402015-11-22 16:54:18 -0500341 tpm_fill_hash(&pcpes, hashdata, hashdata_length);
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500342 u32 rc = tpm_log_extend_event(&pcpes, event);
343 if (rc)
344 tpm_set_failure();
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500345}
346
347
348/****************************************************************
349 * Setup and Measurements
350 ****************************************************************/
351
Kevin O'Connora6175422015-11-22 11:28:14 -0500352// Add an EV_ACTION measurement to the list of measurements
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500353static void
Kevin O'Connora6175422015-11-22 11:28:14 -0500354tpm_add_action(u32 pcrIndex, const char *string)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500355{
Kevin O'Connora6175422015-11-22 11:28:14 -0500356 u32 len = strlen(string);
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500357 tpm_add_measurement_to_log(pcrIndex, EV_ACTION,
358 string, len, (u8 *)string, len);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500359}
360
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500361/*
362 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
363 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500364static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500365tpm_add_event_separators(void)
366{
Kevin O'Connora6175422015-11-22 11:28:14 -0500367 static const u8 evt_separator[] = {0xff,0xff,0xff,0xff};
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500368 u32 pcrIndex;
369 for (pcrIndex = 0; pcrIndex <= 7; pcrIndex++)
370 tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,
371 NULL, 0,
372 evt_separator,
373 sizeof(evt_separator));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500374}
375
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500376static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500377tpm_smbios_measure(void)
378{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500379 struct pcctes pcctes = {
380 .eventid = 1,
381 .eventdatasize = SHA1_BUFSIZE,
382 };
383 struct smbios_entry_point *sep = SMBiosAddr;
384
385 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
386
387 if (!sep)
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500388 return;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500389
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500390 sha1((const u8 *)sep->structure_table_address,
391 sep->structure_table_length, pcctes.digest);
392 tpm_add_measurement_to_log(1,
393 EV_EVENT_TAG,
394 (const char *)&pcctes, sizeof(pcctes),
395 (u8 *)&pcctes, sizeof(pcctes));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500396}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400397
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500398static int
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400399tpm_startup(void)
400{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400401 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500402 int ret = build_and_send_cmd(0, TPM_ORD_Startup,
403 Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
404 TPM_DURATION_TYPE_SHORT);
405 if (CONFIG_COREBOOT && ret == TPM_INVALID_POSTINIT)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400406 /* with other firmware on the system the TPM may already have been
407 * initialized
408 */
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500409 ret = 0;
410 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400411 goto err_exit;
412
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500413 ret = determine_timeouts();
Kevin O'Connorca606362015-12-29 14:21:29 -0500414 if (ret)
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500415 return -1;
Stefan Bergerec42c8d2015-11-21 14:54:41 -0500416
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500417 ret = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
418 TPM_DURATION_TYPE_LONG);
419 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400420 goto err_exit;
421
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500422 ret = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
423 TPM_DURATION_TYPE_SHORT);
424 if (ret && ret != TPM_BAD_LOCALITY)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400425 goto err_exit;
426
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400427 return 0;
428
429err_exit:
430 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
431
Stefan Berger7fce1d92015-11-12 10:14:45 -0500432 tpm_set_failure();
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500433 return -1;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400434}
435
Kevin O'Connord6aca442015-06-10 11:00:17 -0400436void
437tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400438{
439 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400440 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400441
Kevin O'Connor27065322015-11-28 14:25:41 -0500442 int ret = tpmhw_probe();
443 if (ret)
444 return;
445
446 ret = tpm_tcpa_probe();
447 if (ret)
448 return;
449
450 TPM_working = 1;
451
Quan Xu67643952015-04-30 19:43:04 -0400452 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400453 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400454
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500455 ret = tpm_startup();
456 if (ret)
457 return;
458
459 tpm_smbios_measure();
460 tpm_add_action(2, "Start Option ROM Scan");
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400461}
462
Kevin O'Connord6aca442015-06-10 11:00:17 -0400463void
464tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400465{
Kevin O'Connord559a232015-11-28 08:35:26 -0500466 if (!tpm_is_working())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400467 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400468
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500469 int ret = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
470 PhysicalPresence_CMD_ENABLE,
471 sizeof(PhysicalPresence_CMD_ENABLE),
472 TPM_DURATION_TYPE_SHORT);
473 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400474 goto err_exit;
475
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500476 ret = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
477 PhysicalPresence_NOT_PRESENT_LOCK,
478 sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
479 TPM_DURATION_TYPE_SHORT);
480 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400481 goto err_exit;
482
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500483 tpm_add_action(4, "Calling INT 19h");
484 tpm_add_event_separators();
Stefan Berger2aff1c12015-05-26 15:48:33 -0400485
Kevin O'Connord6aca442015-06-10 11:00:17 -0400486 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400487
488err_exit:
489 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
490
Stefan Berger7fce1d92015-11-12 10:14:45 -0500491 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400492}
493
Stefan Berger5aa2a752015-03-23 14:22:17 -0400494/*
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500495 * Add measurement to the log about an option rom
Stefan Berger5aa2a752015-03-23 14:22:17 -0400496 */
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500497void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500498tpm_option_rom(const void *addr, u32 len)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400499{
Kevin O'Connord559a232015-11-28 08:35:26 -0500500 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500501 return;
Stefan Berger7fce1d92015-11-12 10:14:45 -0500502
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500503 struct pcctes_romex pcctes = {
504 .eventid = 7,
505 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
Stefan Berger5aa2a752015-03-23 14:22:17 -0400506 };
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500507 sha1((const u8 *)addr, len, pcctes.digest);
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500508 tpm_add_measurement_to_log(2,
509 EV_EVENT_TAG,
510 (const char *)&pcctes, sizeof(pcctes),
511 (u8 *)&pcctes, sizeof(pcctes));
Stefan Berger6c376b42015-11-12 10:14:49 -0500512}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400513
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500514void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400515tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
516{
Kevin O'Connord559a232015-11-28 08:35:26 -0500517 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500518 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -0400519
Stefan Berger4cdbc412015-11-30 11:14:18 -0500520 if (length < 0x200)
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500521 return;
Stefan Berger4cdbc412015-11-30 11:14:18 -0500522
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500523 const char *string = "Booting BCV device 00h (Floppy)";
524 if (bootdrv == 0x80)
525 string = "Booting BCV device 80h (HDD)";
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500526 tpm_add_action(4, string);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400527
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500528 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
529 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500530 string = "MBR";
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500531 tpm_add_measurement_to_log(4, EV_IPL,
532 string, strlen(string),
533 addr, 0x1b8);
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500534
535 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
536 string = "MBR PARTITION_TABLE";
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500537 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
538 string, strlen(string),
539 addr + 0x1b8, 0x48);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400540}
541
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500542void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400543tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
544{
Kevin O'Connord559a232015-11-28 08:35:26 -0500545 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500546 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -0400547
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500548 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400549
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500550 /* specs: see section 'El Torito' */
551 const char *string = "EL TORITO IPL";
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500552 tpm_add_measurement_to_log(4, EV_IPL,
553 string, strlen(string),
554 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400555}
556
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500557void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400558tpm_add_cdrom_catalog(const u8 *addr, u32 length)
559{
Kevin O'Connord559a232015-11-28 08:35:26 -0500560 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500561 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -0400562
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500563 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400564
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500565 /* specs: see section 'El Torito' */
566 const char *string = "BOOT CATALOG";
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500567 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
568 string, strlen(string),
569 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400570}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400571
Kevin O'Connord6aca442015-06-10 11:00:17 -0400572void
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400573tpm_s3_resume(void)
574{
Kevin O'Connord559a232015-11-28 08:35:26 -0500575 if (!tpm_is_working())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400576 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400577
578 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
579
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500580 int ret = build_and_send_cmd(0, TPM_ORD_Startup,
581 Startup_ST_STATE, sizeof(Startup_ST_STATE),
582 TPM_DURATION_TYPE_SHORT);
583 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400584 goto err_exit;
585
Kevin O'Connord6aca442015-06-10 11:00:17 -0400586 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400587
588err_exit:
589 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
590
Stefan Berger7fce1d92015-11-12 10:14:45 -0500591 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400592}
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500593
594
595/****************************************************************
596 * BIOS interface
597 ****************************************************************/
598
Kevin O'Connor59076132015-11-28 13:55:09 -0500599u8 TPM_interface_shutdown VARLOW;
600
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500601static inline void *input_buf32(struct bregs *regs)
602{
603 return MAKE_FLATPTR(regs->es, regs->di);
604}
605
606static inline void *output_buf32(struct bregs *regs)
607{
608 return MAKE_FLATPTR(regs->ds, regs->si);
609}
610
611static u32
612hash_log_extend_event_int(const struct hleei_short *hleei_s,
613 struct hleeo *hleeo)
614{
615 u32 rc = 0;
616 struct hleo hleo;
617 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
618 const void *logdataptr;
619 u32 logdatalen;
620 struct pcpes *pcpes;
621 u32 pcrindex;
622
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500623 /* short or long version? */
624 switch (hleei_s->ipblength) {
625 case sizeof(struct hleei_short):
626 /* short */
627 logdataptr = hleei_s->logdataptr;
628 logdatalen = hleei_s->logdatalen;
629 pcrindex = hleei_s->pcrindex;
630 break;
631
632 case sizeof(struct hleei_long):
633 /* long */
634 logdataptr = hleei_l->logdataptr;
635 logdatalen = hleei_l->logdatalen;
636 pcrindex = hleei_l->pcrindex;
637 break;
638
639 default:
640 /* bad input block */
641 rc = TCG_INVALID_INPUT_PARA;
642 goto err_exit;
643 }
644
645 pcpes = (struct pcpes *)logdataptr;
646
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500647 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != pcrindex
648 || logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500649 rc = TCG_INVALID_INPUT_PARA;
650 goto err_exit;
651 }
652
Kevin O'Connor92244402015-11-22 16:54:18 -0500653 tpm_fill_hash(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen);
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500654 rc = tpm_log_extend_event(pcpes, pcpes->event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500655 if (rc)
656 goto err_exit;
657
658 hleeo->opblength = sizeof(struct hleeo);
659 hleeo->reserved = 0;
660 hleeo->eventnumber = hleo.eventnumber;
661
662err_exit:
663 if (rc != 0) {
664 hleeo->opblength = 4;
665 hleeo->reserved = 0;
666 }
667
668 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500669}
670
671static u32
672pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto)
673{
674 u32 rc = 0;
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500675 struct tpm_req_header *trh = (void*)pttti->tpmopin;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500676
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500677 if (pttti->ipblength < sizeof(struct pttti) + sizeof(trh)
678 || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen)
679 || pttti->opblength < sizeof(struct pttto)) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500680 rc = TCG_INVALID_INPUT_PARA;
681 goto err_exit;
682 }
683
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500684 u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
Kevin O'Connor2df70282015-11-28 13:43:22 -0500685 rc = tpmhw_transmit(0, trh, pttto->tpmopout, &resbuflen,
686 TPM_DURATION_TYPE_LONG /* worst case */);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500687 if (rc)
688 goto err_exit;
689
690 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
691 pttto->reserved = 0;
692
693err_exit:
694 if (rc != 0) {
695 pttto->opblength = 4;
696 pttto->reserved = 0;
697 }
698
699 return rc;
700}
701
702static u32
703shutdown_preboot_interface(void)
704{
Kevin O'Connor59076132015-11-28 13:55:09 -0500705 TPM_interface_shutdown = 1;
706 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500707}
708
709static u32
710hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
711{
712 u32 rc = 0;
713 u16 size;
714 struct pcpes *pcpes;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500715
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500716 size = hlei->ipblength;
717 if (size != sizeof(*hlei)) {
718 rc = TCG_INVALID_INPUT_PARA;
719 goto err_exit;
720 }
721
722 pcpes = (struct pcpes *)hlei->logdataptr;
723
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500724 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != hlei->pcrindex
725 || pcpes->eventtype != hlei->logeventtype
726 || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500727 rc = TCG_INVALID_INPUT_PARA;
728 goto err_exit;
729 }
730
Kevin O'Connor92244402015-11-22 16:54:18 -0500731 tpm_fill_hash(pcpes, hlei->hashdataptr, hlei->hashdatalen);
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500732 rc = tpm_log_event(pcpes, pcpes->event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500733 if (rc)
734 goto err_exit;
735
736 /* updating the log was fine */
737 hleo->opblength = sizeof(struct hleo);
738 hleo->reserved = 0;
Kevin O'Connor5afdced2015-11-22 16:39:59 -0500739 hleo->eventnumber = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500740
741err_exit:
742 if (rc != 0) {
743 hleo->opblength = 2;
744 hleo->reserved = 0;
745 }
746
747 return rc;
748}
749
750static u32
751hash_all_int(const struct hai *hai, u8 *hash)
752{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500753 if (hai->ipblength != sizeof(struct hai) ||
754 hai->hashdataptr == 0 ||
755 hai->hashdatalen == 0 ||
756 hai->algorithmid != TPM_ALG_SHA)
757 return TCG_INVALID_INPUT_PARA;
758
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500759 sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
760 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500761}
762
763static u32
764tss_int(struct ti *ti, struct to *to)
765{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500766 to->opblength = sizeof(struct to);
767 to->reserved = 0;
768
Kevin O'Connor59076132015-11-28 13:55:09 -0500769 return TCG_PC_UNSUPPORTED;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500770}
771
772static u32
773compact_hash_log_extend_event_int(u8 *buffer,
774 u32 info,
775 u32 length,
776 u32 pcrindex,
777 u32 *edx_ptr)
778{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500779 struct pcpes pcpes = {
780 .pcrindex = pcrindex,
781 .eventtype = EV_COMPACT_HASH,
782 .eventdatasize = sizeof(info),
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500783 };
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500784
Kevin O'Connor92244402015-11-22 16:54:18 -0500785 tpm_fill_hash(&pcpes, buffer, length);
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500786 u32 rc = tpm_log_extend_event(&pcpes, &info);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500787 if (rc == 0)
Kevin O'Connor5afdced2015-11-22 16:39:59 -0500788 *edx_ptr = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500789
790 return rc;
791}
792
793void VISIBLE32FLAT
794tpm_interrupt_handler32(struct bregs *regs)
795{
796 if (!CONFIG_TCGBIOS)
797 return;
798
799 set_cf(regs, 0);
800
Kevin O'Connor59076132015-11-28 13:55:09 -0500801 if (TPM_interface_shutdown && regs->al) {
802 regs->eax = TCG_INTERFACE_SHUTDOWN;
803 return;
804 }
805
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500806 switch ((enum irq_ids)regs->al) {
807 case TCG_StatusCheck:
Kevin O'Connord559a232015-11-28 08:35:26 -0500808 if (!tpmhw_is_present()) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500809 /* no TPM available */
810 regs->eax = TCG_PC_TPM_NOT_PRESENT;
811 } else {
812 regs->eax = 0;
813 regs->ebx = TCG_MAGIC;
814 regs->ch = TCG_VERSION_MAJOR;
815 regs->cl = TCG_VERSION_MINOR;
816 regs->edx = 0x0;
817 regs->esi = (u32)tpm_state.log_area_start_address;
818 regs->edi = (u32)tpm_state.log_area_last_entry;
819 }
820 break;
821
822 case TCG_HashLogExtendEvent:
823 regs->eax =
824 hash_log_extend_event_int(
825 (struct hleei_short *)input_buf32(regs),
826 (struct hleeo *)output_buf32(regs));
827 break;
828
829 case TCG_PassThroughToTPM:
830 regs->eax =
831 pass_through_to_tpm_int((struct pttti *)input_buf32(regs),
832 (struct pttto *)output_buf32(regs));
833 break;
834
835 case TCG_ShutdownPreBootInterface:
836 regs->eax = shutdown_preboot_interface();
837 break;
838
839 case TCG_HashLogEvent:
840 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
841 (struct hleo*)output_buf32(regs));
842 break;
843
844 case TCG_HashAll:
845 regs->eax =
846 hash_all_int((struct hai*)input_buf32(regs),
847 (u8 *)output_buf32(regs));
848 break;
849
850 case TCG_TSS:
851 regs->eax = tss_int((struct ti*)input_buf32(regs),
852 (struct to*)output_buf32(regs));
853 break;
854
855 case TCG_CompactHashLogExtendEvent:
856 regs->eax =
857 compact_hash_log_extend_event_int((u8 *)input_buf32(regs),
858 regs->esi,
859 regs->ecx,
860 regs->edx,
861 &regs->edx);
862 break;
863
864 default:
865 set_cf(regs, 1);
866 }
867
868 return;
869}
Stefan Berger320df852015-11-30 11:14:19 -0500870
Kevin O'Connor26e36172015-12-29 12:20:23 -0500871
872/****************************************************************
873 * TPM Configuration Menu
874 ****************************************************************/
875
Stefan Berger320df852015-11-30 11:14:19 -0500876static u32
877read_stclear_flags(char *buf, int buf_len)
878{
Stefan Berger320df852015-11-30 11:14:19 -0500879 memset(buf, 0, buf_len);
880
Kevin O'Connorca606362015-12-29 14:21:29 -0500881 struct tpm_res_getcap_stclear_flags stcf;
882 int ret = tpm_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_VOLATILE
883 , &stcf.hdr, sizeof(stcf));
884 if (ret)
885 return TCG_TCG_COMMAND_ERROR;
Stefan Berger320df852015-11-30 11:14:19 -0500886
887 memcpy(buf, &stcf.stclear_flags, buf_len);
888
889 return 0;
Stefan Berger320df852015-11-30 11:14:19 -0500890}
891
892static u32
893assert_physical_presence(int verbose)
894{
Stefan Berger320df852015-11-30 11:14:19 -0500895 struct tpm_stclear_flags stcf;
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500896 u32 rc = read_stclear_flags((char *)&stcf, sizeof(stcf));
Stefan Berger320df852015-11-30 11:14:19 -0500897 if (rc) {
898 dprintf(DEBUG_tcg,
899 "Error reading STClear flags: 0x%08x\n", rc);
900 return rc;
901 }
902
903 if (stcf.flags[STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE])
904 /* physical presence already asserted */
905 return 0;
906
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500907 int ret = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
908 PhysicalPresence_CMD_ENABLE,
909 sizeof(PhysicalPresence_CMD_ENABLE),
910 TPM_DURATION_TYPE_SHORT);
911 if (ret) {
Stefan Berger320df852015-11-30 11:14:19 -0500912 if (verbose)
913 printf("Error: Could not enable physical presence.\n\n");
914 goto err_exit;
915 }
916
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500917 ret = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
918 PhysicalPresence_PRESENT,
919 sizeof(PhysicalPresence_PRESENT),
920 TPM_DURATION_TYPE_SHORT);
921 if (ret) {
Stefan Berger320df852015-11-30 11:14:19 -0500922 if (verbose)
923 printf("Error: Could not set presence flag.\n\n");
924 goto err_exit;
925 }
926
927 return 0;
928
929err_exit:
930 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
931
932 tpm_set_failure();
Stefan Berger320df852015-11-30 11:14:19 -0500933 return TCG_TCG_COMMAND_ERROR;
934}
935
936static u32
937read_permanent_flags(char *buf, int buf_len)
938{
Stefan Berger320df852015-11-30 11:14:19 -0500939 memset(buf, 0, buf_len);
940
Kevin O'Connorca606362015-12-29 14:21:29 -0500941 struct tpm_res_getcap_perm_flags pf;
942 int ret = tpm_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT
943 , &pf.hdr, sizeof(pf));
944 if (ret)
945 return TCG_TCG_COMMAND_ERROR;
Stefan Berger320df852015-11-30 11:14:19 -0500946
947 memcpy(buf, &pf.perm_flags, buf_len);
948
949 return 0;
Stefan Berger320df852015-11-30 11:14:19 -0500950}
951
952static u32
953read_has_owner(int *has_owner)
954{
Stefan Berger320df852015-11-30 11:14:19 -0500955 struct tpm_res_getcap_ownerauth oauth;
Kevin O'Connorca606362015-12-29 14:21:29 -0500956 int ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_OWNER
957 , &oauth.hdr, sizeof(oauth));
958 if (ret)
959 return TCG_TCG_COMMAND_ERROR;
Stefan Berger320df852015-11-30 11:14:19 -0500960
961 *has_owner = oauth.flag;
962
963 return 0;
Stefan Berger320df852015-11-30 11:14:19 -0500964}
965
966static u32
967enable_tpm(int enable, u32 *returnCode, int verbose)
968{
969 u32 rc;
970 struct tpm_permanent_flags pf;
971
972 rc = read_permanent_flags((char *)&pf, sizeof(pf));
973 if (rc)
974 return rc;
975
976 if (pf.flags[PERM_FLAG_IDX_DISABLE] && !enable)
977 return 0;
978
979 rc = assert_physical_presence(verbose);
980 if (rc) {
981 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
982 return rc;
983 }
984
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500985 int ret = build_and_send_cmd(0, enable ? TPM_ORD_PhysicalEnable
986 : TPM_ORD_PhysicalDisable,
987 NULL, 0, TPM_DURATION_TYPE_SHORT);
988 *returnCode = ret;
989 if (ret)
Stefan Berger320df852015-11-30 11:14:19 -0500990 goto err_exit;
991
992 return 0;
993
994err_exit:
995 if (enable)
996 dprintf(DEBUG_tcg, "TCGBIOS: Enabling the TPM failed.\n");
997 else
998 dprintf(DEBUG_tcg, "TCGBIOS: Disabling the TPM failed.\n");
999
1000 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1001
1002 tpm_set_failure();
Stefan Berger320df852015-11-30 11:14:19 -05001003 return TCG_TCG_COMMAND_ERROR;
1004}
1005
1006static u32
1007activate_tpm(int activate, int allow_reset, u32 *returnCode, int verbose)
1008{
1009 u32 rc;
1010 struct tpm_permanent_flags pf;
1011
1012 rc = read_permanent_flags((char *)&pf, sizeof(pf));
1013 if (rc)
1014 return rc;
1015
1016 if (pf.flags[PERM_FLAG_IDX_DEACTIVATED] && !activate)
1017 return 0;
1018
1019 if (pf.flags[PERM_FLAG_IDX_DISABLE])
1020 return 0;
1021
1022 rc = assert_physical_presence(verbose);
1023 if (rc) {
1024 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
1025 return rc;
1026 }
1027
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001028 int ret = build_and_send_cmd(0, TPM_ORD_PhysicalSetDeactivated,
1029 activate ? CommandFlag_FALSE
1030 : CommandFlag_TRUE,
1031 activate ? sizeof(CommandFlag_FALSE)
1032 : sizeof(CommandFlag_TRUE),
1033 TPM_DURATION_TYPE_SHORT);
1034 *returnCode = ret;
1035 if (ret)
Stefan Berger320df852015-11-30 11:14:19 -05001036 goto err_exit;
1037
1038 if (activate && allow_reset) {
1039 if (verbose) {
1040 printf("Requiring a reboot to activate the TPM.\n");
1041
1042 msleep(2000);
1043 }
1044 reset();
1045 }
1046
1047 return 0;
1048
1049err_exit:
1050 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1051
1052 tpm_set_failure();
Stefan Berger320df852015-11-30 11:14:19 -05001053 return TCG_TCG_COMMAND_ERROR;
1054}
1055
1056static u32
1057enable_activate(int allow_reset, u32 *returnCode, int verbose)
1058{
1059 u32 rc;
1060
1061 rc = enable_tpm(1, returnCode, verbose);
1062 if (rc)
1063 return rc;
1064
1065 rc = activate_tpm(1, allow_reset, returnCode, verbose);
1066
1067 return rc;
1068}
1069
1070static u32
1071force_clear(int enable_activate_before, int enable_activate_after,
1072 u32 *returnCode, int verbose)
1073{
1074 u32 rc;
1075 int has_owner;
1076
1077 rc = read_has_owner(&has_owner);
1078 if (rc)
1079 return rc;
1080 if (!has_owner) {
1081 if (verbose)
1082 printf("TPM does not have an owner.\n");
1083 return 0;
1084 }
1085
1086 if (enable_activate_before) {
1087 rc = enable_activate(0, returnCode, verbose);
1088 if (rc) {
1089 dprintf(DEBUG_tcg,
1090 "TCGBIOS: Enabling/activating the TPM failed.\n");
1091 return rc;
1092 }
1093 }
1094
1095 rc = assert_physical_presence(verbose);
1096 if (rc) {
1097 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
1098 return rc;
1099 }
1100
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001101 int ret = build_and_send_cmd(0, TPM_ORD_ForceClear,
1102 NULL, 0, TPM_DURATION_TYPE_SHORT);
1103 *returnCode = ret;
1104 if (ret)
Stefan Berger320df852015-11-30 11:14:19 -05001105 goto err_exit;
1106
1107 if (!enable_activate_after) {
1108 if (verbose)
1109 printf("Owner successfully cleared.\n"
1110 "You will need to enable/activate the TPM again.\n\n");
1111 return 0;
1112 }
1113
1114 enable_activate(1, returnCode, verbose);
1115
1116 return 0;
1117
1118err_exit:
1119 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1120
1121 tpm_set_failure();
Stefan Berger320df852015-11-30 11:14:19 -05001122 return TCG_TCG_COMMAND_ERROR;
1123}
1124
1125static u32
1126set_owner_install(int allow, u32 *returnCode, int verbose)
1127{
1128 u32 rc;
1129 int has_owner;
1130 struct tpm_permanent_flags pf;
1131
1132 rc = read_has_owner(&has_owner);
1133 if (rc)
1134 return rc;
1135 if (has_owner) {
1136 if (verbose)
1137 printf("Must first remove owner.\n");
1138 return 0;
1139 }
1140
1141 rc = read_permanent_flags((char *)&pf, sizeof(pf));
1142 if (rc)
1143 return rc;
1144
1145 if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
1146 if (verbose)
1147 printf("TPM must first be enable.\n");
1148 return 0;
1149 }
1150
1151 rc = assert_physical_presence(verbose);
1152 if (rc) {
1153 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
1154 return rc;
1155 }
1156
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001157 int ret = build_and_send_cmd(0, TPM_ORD_SetOwnerInstall,
1158 (allow) ? CommandFlag_TRUE
1159 : CommandFlag_FALSE,
1160 sizeof(CommandFlag_TRUE),
1161 TPM_DURATION_TYPE_SHORT);
1162 *returnCode = ret;
1163 if (ret)
Stefan Berger320df852015-11-30 11:14:19 -05001164 goto err_exit;
1165
1166 if (verbose)
1167 printf("Installation of owner %s.\n", allow ? "enabled" : "disabled");
1168
1169 return 0;
1170
1171err_exit:
1172 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1173 tpm_set_failure();
Stefan Berger320df852015-11-30 11:14:19 -05001174 return TCG_TCG_COMMAND_ERROR;
1175}
1176
1177static u32
1178tpm_process_cfg(tpm_ppi_code msgCode, int verbose, u32 *returnCode)
1179{
1180 u32 rc = 0;
1181
1182 switch (msgCode) {
1183 case TPM_PPI_OP_NOOP: /* no-op */
1184 break;
1185
1186 case TPM_PPI_OP_ENABLE:
1187 rc = enable_tpm(1, returnCode, verbose);
1188 break;
1189
1190 case TPM_PPI_OP_DISABLE:
1191 rc = enable_tpm(0, returnCode, verbose);
1192 break;
1193
1194 case TPM_PPI_OP_ACTIVATE:
1195 rc = activate_tpm(1, 1, returnCode, verbose);
1196 break;
1197
1198 case TPM_PPI_OP_DEACTIVATE:
1199 rc = activate_tpm(0, 1, returnCode, verbose);
1200 break;
1201
1202 case TPM_PPI_OP_CLEAR:
1203 rc = force_clear(1, 0, returnCode, verbose);
1204 break;
1205
1206 case TPM_PPI_OP_SET_OWNERINSTALL_TRUE:
1207 rc = set_owner_install(1, returnCode, verbose);
1208 break;
1209
1210 case TPM_PPI_OP_SET_OWNERINSTALL_FALSE:
1211 rc = set_owner_install(0, returnCode, verbose);
1212 break;
1213
1214 default:
1215 break;
1216 }
1217
1218 if (rc)
1219 printf("Op %d: An error occurred: 0x%x TPM return code: 0x%x\n",
1220 msgCode, rc, *returnCode);
1221
1222 return rc;
1223}
1224
1225static int
1226get_tpm_state(void)
1227{
1228 int state = 0;
1229 struct tpm_permanent_flags pf;
1230 int has_owner;
1231
1232 if (read_permanent_flags((char *)&pf, sizeof(pf)) ||
1233 read_has_owner(&has_owner))
1234 return ~0;
1235
1236 if (!pf.flags[PERM_FLAG_IDX_DISABLE])
1237 state |= TPM_STATE_ENABLED;
1238
1239 if (!pf.flags[PERM_FLAG_IDX_DEACTIVATED])
1240 state |= TPM_STATE_ACTIVE;
1241
1242 if (has_owner) {
1243 state |= TPM_STATE_OWNED;
1244 } else {
1245 if (pf.flags[PERM_FLAG_IDX_OWNERSHIP])
1246 state |= TPM_STATE_OWNERINSTALL;
1247 }
1248
1249 return state;
1250}
1251
1252static void
1253show_tpm_menu(int state, int next_scancodes[7])
1254{
1255 int i = 0;
1256
1257 printf("\nThe current state of the TPM is:\n");
1258
1259 if (state & TPM_STATE_ENABLED)
1260 printf(" Enabled");
1261 else
1262 printf(" Disabled");
1263
1264 if (state & TPM_STATE_ACTIVE)
1265 printf(" and active\n");
1266 else
1267 printf(" and deactivated\n");
1268
1269 if (state & TPM_STATE_OWNED)
1270 printf(" Ownership has been taken\n");
1271 else {
1272 printf(" Ownership has not been taken\n");
1273 if (state & TPM_STATE_OWNERINSTALL)
1274 printf(" A user can take ownership of the TPM\n");
1275 else
1276 printf(" Taking ownership of the TPM has been disabled\n");
1277 }
1278
1279 if ((state & (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) !=
1280 (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) {
1281 printf("\nNote: To make use of all functionality, the TPM must be "
1282 "enabled and active.\n");
1283 }
1284
1285 printf("\nAvailable options are:\n");
1286 if (state & TPM_STATE_ENABLED) {
1287 printf(" d. Disable the TPM\n");
1288 next_scancodes[i++] = 32;
1289
1290 if (state & TPM_STATE_ACTIVE) {
1291 printf(" v. Deactivate the TPM\n");
1292 next_scancodes[i++] = 47;
1293
1294 if (state & TPM_STATE_OWNERINSTALL) {
1295 printf(" p. Prevent installation of an owner\n");
1296 next_scancodes[i++] = 25;
1297 } else {
1298 printf(" s. Allow installation of an owner\n");
1299 next_scancodes[i++] = 31;
1300 }
1301 } else {
1302 printf(" a. Activate the TPM\n");
1303 next_scancodes[i++] = 30;
1304 }
1305
1306 } else {
1307 printf(" e. Enable the TPM\n");
1308 next_scancodes[i++] = 18;
1309 }
1310
1311 if (state & TPM_STATE_OWNED) {
1312 printf(" c. Clear ownership\n");
1313 next_scancodes[i++] = 46;
1314 }
1315
1316 next_scancodes[i++] = 0;
1317}
1318
1319void
1320tpm_menu(void)
1321{
1322 if (!CONFIG_TCGBIOS)
1323 return;
1324
1325 int scancode, next_scancodes[7];
1326 u32 rc, returnCode;
1327 tpm_ppi_code msgCode;
1328 int state = 0, i;
1329 int waitkey;
1330
1331 while (get_keystroke(0) >= 0)
1332 ;
1333 wait_threads();
1334
1335 printf("The Trusted Platform Module (TPM) is a hardware device in "
1336 "this machine.\n"
1337 "It can help verify the integrity of system software.\n\n");
1338
1339 for (;;) {
1340 if ((state = get_tpm_state()) != ~0) {
1341 show_tpm_menu(state, next_scancodes);
1342 } else {
1343 printf("TPM is not working correctly.\n");
1344 return;
1345 }
1346
1347 printf("\nIf no change is desired or if this menu was reached by "
1348 "mistake, press ESC to\n"
1349 "reboot the machine.\n");
1350
1351 msgCode = TPM_PPI_OP_NOOP;
1352
1353 waitkey = 1;
1354
1355 while (waitkey) {
1356 while ((scancode = get_keystroke(1000)) == ~0)
1357 ;
1358
1359 switch (scancode) {
1360 case 1:
1361 // ESC
1362 reset();
1363 break;
1364 case 18: /* e. enable */
1365 msgCode = TPM_PPI_OP_ENABLE;
1366 break;
1367 case 32: /* d. disable */
1368 msgCode = TPM_PPI_OP_DISABLE;
1369 break;
1370 case 30: /* a. activate */
1371 msgCode = TPM_PPI_OP_ACTIVATE;
1372 break;
1373 case 47: /* v. deactivate */
1374 msgCode = TPM_PPI_OP_DEACTIVATE;
1375 break;
1376 case 46: /* c. clear owner */
1377 msgCode = TPM_PPI_OP_CLEAR;
1378 break;
1379 case 25: /* p. prevent ownerinstall */
1380 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_FALSE;
1381 break;
1382 case 31: /* s. allow ownerinstall */
1383 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_TRUE;
1384 break;
1385 default:
1386 continue;
1387 }
1388
1389 /*
1390 * Using the next_scancodes array, check whether the
1391 * pressed key is currently a valid option.
1392 */
1393 for (i = 0; i < sizeof(next_scancodes); i++) {
1394 if (next_scancodes[i] == 0)
1395 break;
1396
1397 if (next_scancodes[i] == scancode) {
1398 rc = tpm_process_cfg(msgCode, 1, &returnCode);
1399
1400 if (rc)
1401 printf("An error occurred: 0x%x\n", rc);
1402 waitkey = 0;
1403 break;
1404 }
1405 }
1406 }
1407 }
1408}