blob: e6512e88f9f6224e5430f9cd05f795fc0a166b8a [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 */
172static u32
Stefan Berger47b9df52015-11-21 14:54:40 -0500173build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
Kevin O'Connor71479612015-12-29 14:32:19 -0500174 u32 *returnCode, 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;
178 u8 cmd[20];
179 } 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();
191 return TCG_FIRMWARE_ERROR;
192 }
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);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400197 if (rc)
198 return rc;
199
200 *returnCode = be32_to_cpu(trsh->errcode);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400201 return 0;
202}
203
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500204static void
205tpm_set_failure(void)
206{
207 u32 returnCode;
208
209 /* we will try to deactivate the TPM now - ignoring all errors */
210 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
211 PhysicalPresence_CMD_ENABLE,
212 sizeof(PhysicalPresence_CMD_ENABLE),
Kevin O'Connor71479612015-12-29 14:32:19 -0500213 &returnCode, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500214
215 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
216 PhysicalPresence_PRESENT,
217 sizeof(PhysicalPresence_PRESENT),
Kevin O'Connor71479612015-12-29 14:32:19 -0500218 &returnCode, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500219
220 build_and_send_cmd(0, TPM_ORD_SetTempDeactivated,
Kevin O'Connor71479612015-12-29 14:32:19 -0500221 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500222
Kevin O'Connord559a232015-11-28 08:35:26 -0500223 TPM_working = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500224}
225
Kevin O'Connorca606362015-12-29 14:21:29 -0500226static int
227tpm_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize)
228{
229 struct tpm_req_getcap trgc = {
230 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
231 .hdr.totlen = cpu_to_be32(sizeof(trgc)),
232 .hdr.ordinal = cpu_to_be32(TPM_ORD_GetCapability),
233 .capArea = cpu_to_be32(cap),
234 .subCapSize = cpu_to_be32(sizeof(trgc.subCap)),
235 .subCap = cpu_to_be32(subcap)
236 };
237 u32 resp_size = rsize;
238 u32 rc = tpmhw_transmit(0, &trgc.hdr, rsp, &resp_size,
239 TPM_DURATION_TYPE_SHORT);
240 int ret = (rc || resp_size != rsize) ? -1 : be32_to_cpu(rsp->errcode);
241 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(%d, %d)"
242 " = %x\n", cap, subcap, ret);
243 if (ret) {
244 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
245 tpm_set_failure();
246 }
247 return ret;
248}
249
250static int
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400251determine_timeouts(void)
252{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400253 struct tpm_res_getcap_timeouts timeouts;
Kevin O'Connorca606362015-12-29 14:21:29 -0500254 int ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_TIS_TIMEOUT
255 , &timeouts.hdr, sizeof(timeouts));
256 if (ret)
257 return ret;
258
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400259 struct tpm_res_getcap_durations durations;
Kevin O'Connorca606362015-12-29 14:21:29 -0500260 ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION
261 , &durations.hdr, sizeof(durations));
262 if (ret)
263 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400264
Kevin O'Connorca606362015-12-29 14:21:29 -0500265 int i;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400266 for (i = 0; i < 3; i++)
267 durations.durations[i] = be32_to_cpu(durations.durations[i]);
268
269 for (i = 0; i < 4; i++)
270 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
271
272 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
273 timeouts.timeouts[0],
274 timeouts.timeouts[1],
275 timeouts.timeouts[2],
276 timeouts.timeouts[3]);
277
278 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
279 durations.durations[0],
280 durations.durations[1],
281 durations.durations[2]);
282
Kevin O'Connorba86edb2015-11-19 18:03:35 -0500283 tpmhw_set_timeouts(timeouts.timeouts, durations.durations);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400284
285 return 0;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400286}
287
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500288static u32
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500289tpm_log_extend_event(struct pcpes *pcpes, const void *event)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500290{
Kevin O'Connord559a232015-11-28 08:35:26 -0500291 if (!tpm_is_working())
Kevin O'Connorf4820ac2015-11-22 11:00:06 -0500292 return TCG_GENERAL_ERROR;
293
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500294 if (pcpes->pcrindex >= 24)
295 return TCG_INVALID_INPUT_PARA;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500296
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500297 struct tpm_req_extend tre = {
Kevin O'Connora0599152015-11-28 08:08:57 -0500298 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
299 .hdr.totlen = cpu_to_be32(sizeof(tre)),
300 .hdr.ordinal = cpu_to_be32(TPM_ORD_Extend),
301 .pcrindex = cpu_to_be32(pcpes->pcrindex),
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500302 };
303 memcpy(tre.digest, pcpes->digest, sizeof(tre.digest));
304
305 struct tpm_rsp_extend rsp;
306 u32 resp_length = sizeof(rsp);
Kevin O'Connor2df70282015-11-28 13:43:22 -0500307 u32 rc = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length,
308 TPM_DURATION_TYPE_SHORT);
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500309 if (rc || resp_length != sizeof(rsp)) {
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500310 tpm_set_failure();
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500311 return rc;
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500312 }
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500313
314 rc = tpm_log_event(pcpes, event);
315 if (rc)
316 tpm_set_failure();
317 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500318}
319
Kevin O'Connor92244402015-11-22 16:54:18 -0500320static void
321tpm_fill_hash(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length)
322{
323 if (hashdata)
324 sha1(hashdata, hashdata_length, pcpes->digest);
325}
326
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500327/*
328 * Add a measurement to the log; the data at data_seg:data/length are
329 * appended to the TCG_PCClientPCREventStruct
330 *
331 * Input parameters:
332 * pcrindex : which PCR to extend
333 * event_type : type of event; specs section on 'Event Types'
334 * event : pointer to info (e.g., string) to be added to log as-is
335 * event_length: length of the event
336 * hashdata : pointer to the data to be hashed
337 * hashdata_length: length of the data to be hashed
338 */
339static u32
340tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
341 const char *event, u32 event_length,
342 const u8 *hashdata, u32 hashdata_length)
343{
344 struct pcpes pcpes = {
345 .pcrindex = pcrindex,
346 .eventtype = event_type,
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500347 .eventdatasize = event_length,
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500348 };
Kevin O'Connor92244402015-11-22 16:54:18 -0500349 tpm_fill_hash(&pcpes, hashdata, hashdata_length);
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500350 return tpm_log_extend_event(&pcpes, event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500351}
352
353
354/****************************************************************
355 * Setup and Measurements
356 ****************************************************************/
357
Kevin O'Connora6175422015-11-22 11:28:14 -0500358// Add an EV_ACTION measurement to the list of measurements
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500359static u32
Kevin O'Connora6175422015-11-22 11:28:14 -0500360tpm_add_action(u32 pcrIndex, const char *string)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500361{
Kevin O'Connora6175422015-11-22 11:28:14 -0500362 u32 len = strlen(string);
363 return tpm_add_measurement_to_log(pcrIndex, EV_ACTION,
364 string, len, (u8 *)string, len);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500365}
366
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500367/*
368 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
369 */
370static u32
371tpm_add_event_separators(void)
372{
373 u32 rc;
374 u32 pcrIndex = 0;
375
Kevin O'Connord559a232015-11-28 08:35:26 -0500376 if (!tpm_is_working())
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500377 return TCG_GENERAL_ERROR;
378
Kevin O'Connora6175422015-11-22 11:28:14 -0500379 static const u8 evt_separator[] = {0xff,0xff,0xff,0xff};
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500380 while (pcrIndex <= 7) {
Kevin O'Connora6175422015-11-22 11:28:14 -0500381 rc = tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,
382 NULL, 0,
383 (u8 *)evt_separator,
384 sizeof(evt_separator));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500385 if (rc)
386 break;
387 pcrIndex ++;
388 }
389
390 return rc;
391}
392
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500393static u32
394tpm_smbios_measure(void)
395{
Kevin O'Connord559a232015-11-28 08:35:26 -0500396 if (!tpm_is_working())
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500397 return TCG_GENERAL_ERROR;
398
399 u32 rc;
400 struct pcctes pcctes = {
401 .eventid = 1,
402 .eventdatasize = SHA1_BUFSIZE,
403 };
404 struct smbios_entry_point *sep = SMBiosAddr;
405
406 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
407
408 if (!sep)
409 return 0;
410
411 rc = sha1((const u8 *)sep->structure_table_address,
412 sep->structure_table_length, pcctes.digest);
413 if (rc)
414 return rc;
415
416 return tpm_add_measurement_to_log(1,
417 EV_EVENT_TAG,
418 (const char *)&pcctes, sizeof(pcctes),
419 (u8 *)&pcctes, sizeof(pcctes));
420}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400421
422static u32
423tpm_startup(void)
424{
425 u32 rc;
426 u32 returnCode;
427
Kevin O'Connord559a232015-11-28 08:35:26 -0500428 if (!tpm_is_working())
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400429 return TCG_GENERAL_ERROR;
430
431 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Stefan Berger5aa2a752015-03-23 14:22:17 -0400432 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400433 Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
Kevin O'Connor71479612015-12-29 14:32:19 -0500434 &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400435
436 dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n",
437 returnCode);
438
439 if (CONFIG_COREBOOT) {
440 /* with other firmware on the system the TPM may already have been
441 * initialized
442 */
443 if (returnCode == TPM_INVALID_POSTINIT)
444 returnCode = 0;
445 }
446
447 if (rc || returnCode)
448 goto err_exit;
449
Kevin O'Connorca606362015-12-29 14:21:29 -0500450 int ret = determine_timeouts();
451 if (ret)
452 return TCG_TCG_COMMAND_ERROR;
Stefan Bergerec42c8d2015-11-21 14:54:41 -0500453
Stefan Berger5aa2a752015-03-23 14:22:17 -0400454 rc = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
Kevin O'Connor71479612015-12-29 14:32:19 -0500455 &returnCode, TPM_DURATION_TYPE_LONG);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400456
457 dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n",
458 returnCode);
459
460 if (rc || returnCode)
461 goto err_exit;
462
Stefan Berger5aa2a752015-03-23 14:22:17 -0400463 rc = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
Kevin O'Connor71479612015-12-29 14:32:19 -0500464 &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400465
466 dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n",
467 returnCode);
468
469 if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY))
470 goto err_exit;
471
Stefan Berger2aff1c12015-05-26 15:48:33 -0400472 rc = tpm_smbios_measure();
473 if (rc)
474 goto err_exit;
475
Kevin O'Connor12575332015-11-22 11:34:38 -0500476 rc = tpm_add_action(2, "Start Option ROM Scan");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400477 if (rc)
478 goto err_exit;
479
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400480 return 0;
481
482err_exit:
483 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
484
Stefan Berger7fce1d92015-11-12 10:14:45 -0500485 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400486 if (rc)
487 return rc;
488 return TCG_TCG_COMMAND_ERROR;
489}
490
Kevin O'Connord6aca442015-06-10 11:00:17 -0400491void
492tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400493{
494 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400495 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400496
Kevin O'Connor27065322015-11-28 14:25:41 -0500497 int ret = tpmhw_probe();
498 if (ret)
499 return;
500
501 ret = tpm_tcpa_probe();
502 if (ret)
503 return;
504
505 TPM_working = 1;
506
Quan Xu67643952015-04-30 19:43:04 -0400507 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400508 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400509
Kevin O'Connord6aca442015-06-10 11:00:17 -0400510 tpm_startup();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400511}
512
Kevin O'Connord6aca442015-06-10 11:00:17 -0400513void
514tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400515{
516 u32 rc;
517 u32 returnCode;
518
Kevin O'Connord559a232015-11-28 08:35:26 -0500519 if (!tpm_is_working())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400520 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400521
Stefan Berger5aa2a752015-03-23 14:22:17 -0400522 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400523 PhysicalPresence_CMD_ENABLE,
524 sizeof(PhysicalPresence_CMD_ENABLE),
Kevin O'Connor71479612015-12-29 14:32:19 -0500525 &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400526 if (rc || returnCode)
527 goto err_exit;
528
Stefan Berger5aa2a752015-03-23 14:22:17 -0400529 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400530 PhysicalPresence_NOT_PRESENT_LOCK,
531 sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
Kevin O'Connor71479612015-12-29 14:32:19 -0500532 &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400533 if (rc || returnCode)
534 goto err_exit;
535
Kevin O'Connor12575332015-11-22 11:34:38 -0500536 rc = tpm_add_action(4, "Calling INT 19h");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400537 if (rc)
538 goto err_exit;
539
540 rc = tpm_add_event_separators();
541 if (rc)
542 goto err_exit;
543
Kevin O'Connord6aca442015-06-10 11:00:17 -0400544 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400545
546err_exit:
547 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
548
Stefan Berger7fce1d92015-11-12 10:14:45 -0500549 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400550}
551
Stefan Berger5aa2a752015-03-23 14:22:17 -0400552/*
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500553 * Add measurement to the log about an option rom
Stefan Berger5aa2a752015-03-23 14:22:17 -0400554 */
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500555u32
556tpm_option_rom(const void *addr, u32 len)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400557{
Kevin O'Connord559a232015-11-28 08:35:26 -0500558 if (!tpm_is_working())
Stefan Berger7fce1d92015-11-12 10:14:45 -0500559 return TCG_GENERAL_ERROR;
560
Stefan Berger5aa2a752015-03-23 14:22:17 -0400561 u32 rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500562 struct pcctes_romex pcctes = {
563 .eventid = 7,
564 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
Stefan Berger5aa2a752015-03-23 14:22:17 -0400565 };
566
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500567 rc = sha1((const u8 *)addr, len, pcctes.digest);
Stefan Berger6c376b42015-11-12 10:14:49 -0500568 if (rc)
569 return rc;
570
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500571 return tpm_add_measurement_to_log(2,
572 EV_EVENT_TAG,
573 (const char *)&pcctes, sizeof(pcctes),
574 (u8 *)&pcctes, sizeof(pcctes));
Stefan Berger6c376b42015-11-12 10:14:49 -0500575}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400576
Stefan Berger2aff1c12015-05-26 15:48:33 -0400577u32
578tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
579{
Kevin O'Connord559a232015-11-28 08:35:26 -0500580 if (!tpm_is_working())
Stefan Berger2aff1c12015-05-26 15:48:33 -0400581 return TCG_GENERAL_ERROR;
582
Stefan Berger4cdbc412015-11-30 11:14:18 -0500583 if (length < 0x200)
584 return TCG_INVALID_INPUT_PARA;
585
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500586 const char *string = "Booting BCV device 00h (Floppy)";
587 if (bootdrv == 0x80)
588 string = "Booting BCV device 80h (HDD)";
589 u32 rc = tpm_add_action(4, string);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400590 if (rc)
591 return rc;
592
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500593 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
594 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500595 string = "MBR";
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500596 rc = tpm_add_measurement_to_log(4, EV_IPL,
597 string, strlen(string),
598 addr, 0x1b8);
599 if (rc)
600 return rc;
601
602 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
603 string = "MBR PARTITION_TABLE";
604 return tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
605 string, strlen(string),
606 addr + 0x1b8, 0x48);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400607}
608
609u32
610tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
611{
Kevin O'Connord559a232015-11-28 08:35:26 -0500612 if (!tpm_is_working())
Stefan Berger2aff1c12015-05-26 15:48:33 -0400613 return TCG_GENERAL_ERROR;
614
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500615 u32 rc = tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400616 if (rc)
617 return rc;
618
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500619 /* specs: see section 'El Torito' */
620 const char *string = "EL TORITO IPL";
621 return tpm_add_measurement_to_log(4, EV_IPL,
622 string, strlen(string),
623 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400624}
625
626u32
627tpm_add_cdrom_catalog(const u8 *addr, u32 length)
628{
Kevin O'Connord559a232015-11-28 08:35:26 -0500629 if (!tpm_is_working())
Stefan Berger2aff1c12015-05-26 15:48:33 -0400630 return TCG_GENERAL_ERROR;
631
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500632 u32 rc = tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400633 if (rc)
634 return rc;
635
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500636 /* specs: see section 'El Torito' */
637 const char *string = "BOOT CATALOG";
638 return tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
639 string, strlen(string),
640 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400641}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400642
Kevin O'Connord6aca442015-06-10 11:00:17 -0400643void
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400644tpm_s3_resume(void)
645{
646 u32 rc;
647 u32 returnCode;
648
Kevin O'Connord559a232015-11-28 08:35:26 -0500649 if (!tpm_is_working())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400650 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400651
652 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
653
Stefan Berger5aa2a752015-03-23 14:22:17 -0400654 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400655 Startup_ST_STATE, sizeof(Startup_ST_STATE),
Kevin O'Connor71479612015-12-29 14:32:19 -0500656 &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400657
658 dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n",
659 returnCode);
660
661 if (rc || returnCode)
662 goto err_exit;
663
Kevin O'Connord6aca442015-06-10 11:00:17 -0400664 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400665
666err_exit:
667 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
668
Stefan Berger7fce1d92015-11-12 10:14:45 -0500669 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400670}
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500671
672
673/****************************************************************
674 * BIOS interface
675 ****************************************************************/
676
Kevin O'Connor59076132015-11-28 13:55:09 -0500677u8 TPM_interface_shutdown VARLOW;
678
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500679static inline void *input_buf32(struct bregs *regs)
680{
681 return MAKE_FLATPTR(regs->es, regs->di);
682}
683
684static inline void *output_buf32(struct bregs *regs)
685{
686 return MAKE_FLATPTR(regs->ds, regs->si);
687}
688
689static u32
690hash_log_extend_event_int(const struct hleei_short *hleei_s,
691 struct hleeo *hleeo)
692{
693 u32 rc = 0;
694 struct hleo hleo;
695 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
696 const void *logdataptr;
697 u32 logdatalen;
698 struct pcpes *pcpes;
699 u32 pcrindex;
700
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500701 /* short or long version? */
702 switch (hleei_s->ipblength) {
703 case sizeof(struct hleei_short):
704 /* short */
705 logdataptr = hleei_s->logdataptr;
706 logdatalen = hleei_s->logdatalen;
707 pcrindex = hleei_s->pcrindex;
708 break;
709
710 case sizeof(struct hleei_long):
711 /* long */
712 logdataptr = hleei_l->logdataptr;
713 logdatalen = hleei_l->logdatalen;
714 pcrindex = hleei_l->pcrindex;
715 break;
716
717 default:
718 /* bad input block */
719 rc = TCG_INVALID_INPUT_PARA;
720 goto err_exit;
721 }
722
723 pcpes = (struct pcpes *)logdataptr;
724
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500725 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != pcrindex
726 || 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, hleei_s->hashdataptr, hleei_s->hashdatalen);
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500732 rc = tpm_log_extend_event(pcpes, pcpes->event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500733 if (rc)
734 goto err_exit;
735
736 hleeo->opblength = sizeof(struct hleeo);
737 hleeo->reserved = 0;
738 hleeo->eventnumber = hleo.eventnumber;
739
740err_exit:
741 if (rc != 0) {
742 hleeo->opblength = 4;
743 hleeo->reserved = 0;
744 }
745
746 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500747}
748
749static u32
750pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto)
751{
752 u32 rc = 0;
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500753 struct tpm_req_header *trh = (void*)pttti->tpmopin;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500754
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500755 if (pttti->ipblength < sizeof(struct pttti) + sizeof(trh)
756 || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen)
757 || pttti->opblength < sizeof(struct pttto)) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500758 rc = TCG_INVALID_INPUT_PARA;
759 goto err_exit;
760 }
761
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500762 u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
Kevin O'Connor2df70282015-11-28 13:43:22 -0500763 rc = tpmhw_transmit(0, trh, pttto->tpmopout, &resbuflen,
764 TPM_DURATION_TYPE_LONG /* worst case */);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500765 if (rc)
766 goto err_exit;
767
768 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
769 pttto->reserved = 0;
770
771err_exit:
772 if (rc != 0) {
773 pttto->opblength = 4;
774 pttto->reserved = 0;
775 }
776
777 return rc;
778}
779
780static u32
781shutdown_preboot_interface(void)
782{
Kevin O'Connor59076132015-11-28 13:55:09 -0500783 TPM_interface_shutdown = 1;
784 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500785}
786
787static u32
788hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
789{
790 u32 rc = 0;
791 u16 size;
792 struct pcpes *pcpes;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500793
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500794 size = hlei->ipblength;
795 if (size != sizeof(*hlei)) {
796 rc = TCG_INVALID_INPUT_PARA;
797 goto err_exit;
798 }
799
800 pcpes = (struct pcpes *)hlei->logdataptr;
801
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500802 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != hlei->pcrindex
803 || pcpes->eventtype != hlei->logeventtype
804 || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500805 rc = TCG_INVALID_INPUT_PARA;
806 goto err_exit;
807 }
808
Kevin O'Connor92244402015-11-22 16:54:18 -0500809 tpm_fill_hash(pcpes, hlei->hashdataptr, hlei->hashdatalen);
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500810 rc = tpm_log_event(pcpes, pcpes->event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500811 if (rc)
812 goto err_exit;
813
814 /* updating the log was fine */
815 hleo->opblength = sizeof(struct hleo);
816 hleo->reserved = 0;
Kevin O'Connor5afdced2015-11-22 16:39:59 -0500817 hleo->eventnumber = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500818
819err_exit:
820 if (rc != 0) {
821 hleo->opblength = 2;
822 hleo->reserved = 0;
823 }
824
825 return rc;
826}
827
828static u32
829hash_all_int(const struct hai *hai, u8 *hash)
830{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500831 if (hai->ipblength != sizeof(struct hai) ||
832 hai->hashdataptr == 0 ||
833 hai->hashdatalen == 0 ||
834 hai->algorithmid != TPM_ALG_SHA)
835 return TCG_INVALID_INPUT_PARA;
836
837 return sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
838}
839
840static u32
841tss_int(struct ti *ti, struct to *to)
842{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500843 to->opblength = sizeof(struct to);
844 to->reserved = 0;
845
Kevin O'Connor59076132015-11-28 13:55:09 -0500846 return TCG_PC_UNSUPPORTED;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500847}
848
849static u32
850compact_hash_log_extend_event_int(u8 *buffer,
851 u32 info,
852 u32 length,
853 u32 pcrindex,
854 u32 *edx_ptr)
855{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500856 struct pcpes pcpes = {
857 .pcrindex = pcrindex,
858 .eventtype = EV_COMPACT_HASH,
859 .eventdatasize = sizeof(info),
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500860 };
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500861
Kevin O'Connor92244402015-11-22 16:54:18 -0500862 tpm_fill_hash(&pcpes, buffer, length);
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500863 u32 rc = tpm_log_extend_event(&pcpes, &info);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500864 if (rc == 0)
Kevin O'Connor5afdced2015-11-22 16:39:59 -0500865 *edx_ptr = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500866
867 return rc;
868}
869
870void VISIBLE32FLAT
871tpm_interrupt_handler32(struct bregs *regs)
872{
873 if (!CONFIG_TCGBIOS)
874 return;
875
876 set_cf(regs, 0);
877
Kevin O'Connor59076132015-11-28 13:55:09 -0500878 if (TPM_interface_shutdown && regs->al) {
879 regs->eax = TCG_INTERFACE_SHUTDOWN;
880 return;
881 }
882
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500883 switch ((enum irq_ids)regs->al) {
884 case TCG_StatusCheck:
Kevin O'Connord559a232015-11-28 08:35:26 -0500885 if (!tpmhw_is_present()) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500886 /* no TPM available */
887 regs->eax = TCG_PC_TPM_NOT_PRESENT;
888 } else {
889 regs->eax = 0;
890 regs->ebx = TCG_MAGIC;
891 regs->ch = TCG_VERSION_MAJOR;
892 regs->cl = TCG_VERSION_MINOR;
893 regs->edx = 0x0;
894 regs->esi = (u32)tpm_state.log_area_start_address;
895 regs->edi = (u32)tpm_state.log_area_last_entry;
896 }
897 break;
898
899 case TCG_HashLogExtendEvent:
900 regs->eax =
901 hash_log_extend_event_int(
902 (struct hleei_short *)input_buf32(regs),
903 (struct hleeo *)output_buf32(regs));
904 break;
905
906 case TCG_PassThroughToTPM:
907 regs->eax =
908 pass_through_to_tpm_int((struct pttti *)input_buf32(regs),
909 (struct pttto *)output_buf32(regs));
910 break;
911
912 case TCG_ShutdownPreBootInterface:
913 regs->eax = shutdown_preboot_interface();
914 break;
915
916 case TCG_HashLogEvent:
917 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
918 (struct hleo*)output_buf32(regs));
919 break;
920
921 case TCG_HashAll:
922 regs->eax =
923 hash_all_int((struct hai*)input_buf32(regs),
924 (u8 *)output_buf32(regs));
925 break;
926
927 case TCG_TSS:
928 regs->eax = tss_int((struct ti*)input_buf32(regs),
929 (struct to*)output_buf32(regs));
930 break;
931
932 case TCG_CompactHashLogExtendEvent:
933 regs->eax =
934 compact_hash_log_extend_event_int((u8 *)input_buf32(regs),
935 regs->esi,
936 regs->ecx,
937 regs->edx,
938 &regs->edx);
939 break;
940
941 default:
942 set_cf(regs, 1);
943 }
944
945 return;
946}
Stefan Berger320df852015-11-30 11:14:19 -0500947
Kevin O'Connor26e36172015-12-29 12:20:23 -0500948
949/****************************************************************
950 * TPM Configuration Menu
951 ****************************************************************/
952
Stefan Berger320df852015-11-30 11:14:19 -0500953static u32
954read_stclear_flags(char *buf, int buf_len)
955{
Stefan Berger320df852015-11-30 11:14:19 -0500956 memset(buf, 0, buf_len);
957
Kevin O'Connorca606362015-12-29 14:21:29 -0500958 struct tpm_res_getcap_stclear_flags stcf;
959 int ret = tpm_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_VOLATILE
960 , &stcf.hdr, sizeof(stcf));
961 if (ret)
962 return TCG_TCG_COMMAND_ERROR;
Stefan Berger320df852015-11-30 11:14:19 -0500963
964 memcpy(buf, &stcf.stclear_flags, buf_len);
965
966 return 0;
Stefan Berger320df852015-11-30 11:14:19 -0500967}
968
969static u32
970assert_physical_presence(int verbose)
971{
972 u32 rc = 0;
973 u32 returnCode;
974 struct tpm_stclear_flags stcf;
975
976 rc = read_stclear_flags((char *)&stcf, sizeof(stcf));
977 if (rc) {
978 dprintf(DEBUG_tcg,
979 "Error reading STClear flags: 0x%08x\n", rc);
980 return rc;
981 }
982
983 if (stcf.flags[STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE])
984 /* physical presence already asserted */
985 return 0;
986
987 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
988 PhysicalPresence_CMD_ENABLE,
989 sizeof(PhysicalPresence_CMD_ENABLE),
Kevin O'Connor71479612015-12-29 14:32:19 -0500990 &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Berger320df852015-11-30 11:14:19 -0500991
992 dprintf(DEBUG_tcg,
993 "Return code from TSC_PhysicalPresence(CMD_ENABLE) = 0x%08x\n",
994 returnCode);
995
996 if (rc || returnCode) {
997 if (verbose)
998 printf("Error: Could not enable physical presence.\n\n");
999 goto err_exit;
1000 }
1001
1002 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
1003 PhysicalPresence_PRESENT,
1004 sizeof(PhysicalPresence_PRESENT),
Kevin O'Connor71479612015-12-29 14:32:19 -05001005 &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Berger320df852015-11-30 11:14:19 -05001006
1007 dprintf(DEBUG_tcg,
1008 "Return code from TSC_PhysicalPresence(PRESENT) = 0x%08x\n",
1009 returnCode);
1010
1011 if (rc || returnCode) {
1012 if (verbose)
1013 printf("Error: Could not set presence flag.\n\n");
1014 goto err_exit;
1015 }
1016
1017 return 0;
1018
1019err_exit:
1020 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1021
1022 tpm_set_failure();
1023 if (rc)
1024 return rc;
1025 return TCG_TCG_COMMAND_ERROR;
1026}
1027
1028static u32
1029read_permanent_flags(char *buf, int buf_len)
1030{
Stefan Berger320df852015-11-30 11:14:19 -05001031 memset(buf, 0, buf_len);
1032
Kevin O'Connorca606362015-12-29 14:21:29 -05001033 struct tpm_res_getcap_perm_flags pf;
1034 int ret = tpm_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT
1035 , &pf.hdr, sizeof(pf));
1036 if (ret)
1037 return TCG_TCG_COMMAND_ERROR;
Stefan Berger320df852015-11-30 11:14:19 -05001038
1039 memcpy(buf, &pf.perm_flags, buf_len);
1040
1041 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001042}
1043
1044static u32
1045read_has_owner(int *has_owner)
1046{
Stefan Berger320df852015-11-30 11:14:19 -05001047 struct tpm_res_getcap_ownerauth oauth;
Kevin O'Connorca606362015-12-29 14:21:29 -05001048 int ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_OWNER
1049 , &oauth.hdr, sizeof(oauth));
1050 if (ret)
1051 return TCG_TCG_COMMAND_ERROR;
Stefan Berger320df852015-11-30 11:14:19 -05001052
1053 *has_owner = oauth.flag;
1054
1055 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001056}
1057
1058static u32
1059enable_tpm(int enable, u32 *returnCode, int verbose)
1060{
1061 u32 rc;
1062 struct tpm_permanent_flags pf;
1063
1064 rc = read_permanent_flags((char *)&pf, sizeof(pf));
1065 if (rc)
1066 return rc;
1067
1068 if (pf.flags[PERM_FLAG_IDX_DISABLE] && !enable)
1069 return 0;
1070
1071 rc = assert_physical_presence(verbose);
1072 if (rc) {
1073 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
1074 return rc;
1075 }
1076
1077 rc = build_and_send_cmd(0, enable ? TPM_ORD_PhysicalEnable
1078 : TPM_ORD_PhysicalDisable,
Kevin O'Connor71479612015-12-29 14:32:19 -05001079 NULL, 0, returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Berger320df852015-11-30 11:14:19 -05001080 if (enable)
1081 dprintf(DEBUG_tcg, "Return code from TPM_PhysicalEnable = 0x%08x\n",
1082 *returnCode);
1083 else
1084 dprintf(DEBUG_tcg, "Return code from TPM_PhysicalDisable = 0x%08x\n",
1085 *returnCode);
1086
1087 if (rc || *returnCode)
1088 goto err_exit;
1089
1090 return 0;
1091
1092err_exit:
1093 if (enable)
1094 dprintf(DEBUG_tcg, "TCGBIOS: Enabling the TPM failed.\n");
1095 else
1096 dprintf(DEBUG_tcg, "TCGBIOS: Disabling the TPM failed.\n");
1097
1098 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1099
1100 tpm_set_failure();
1101 if (rc)
1102 return rc;
1103 return TCG_TCG_COMMAND_ERROR;
1104}
1105
1106static u32
1107activate_tpm(int activate, int allow_reset, u32 *returnCode, int verbose)
1108{
1109 u32 rc;
1110 struct tpm_permanent_flags pf;
1111
1112 rc = read_permanent_flags((char *)&pf, sizeof(pf));
1113 if (rc)
1114 return rc;
1115
1116 if (pf.flags[PERM_FLAG_IDX_DEACTIVATED] && !activate)
1117 return 0;
1118
1119 if (pf.flags[PERM_FLAG_IDX_DISABLE])
1120 return 0;
1121
1122 rc = assert_physical_presence(verbose);
1123 if (rc) {
1124 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
1125 return rc;
1126 }
1127
1128 rc = build_and_send_cmd(0, TPM_ORD_PhysicalSetDeactivated,
1129 activate ? CommandFlag_FALSE
1130 : CommandFlag_TRUE,
1131 activate ? sizeof(CommandFlag_FALSE)
1132 : sizeof(CommandFlag_TRUE),
Kevin O'Connor71479612015-12-29 14:32:19 -05001133 returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Berger320df852015-11-30 11:14:19 -05001134
1135 dprintf(DEBUG_tcg,
1136 "Return code from PhysicalSetDeactivated(%d) = 0x%08x\n",
1137 activate ? 0 : 1, *returnCode);
1138
1139 if (rc || *returnCode)
1140 goto err_exit;
1141
1142 if (activate && allow_reset) {
1143 if (verbose) {
1144 printf("Requiring a reboot to activate the TPM.\n");
1145
1146 msleep(2000);
1147 }
1148 reset();
1149 }
1150
1151 return 0;
1152
1153err_exit:
1154 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1155
1156 tpm_set_failure();
1157 if (rc)
1158 return rc;
1159 return TCG_TCG_COMMAND_ERROR;
1160}
1161
1162static u32
1163enable_activate(int allow_reset, u32 *returnCode, int verbose)
1164{
1165 u32 rc;
1166
1167 rc = enable_tpm(1, returnCode, verbose);
1168 if (rc)
1169 return rc;
1170
1171 rc = activate_tpm(1, allow_reset, returnCode, verbose);
1172
1173 return rc;
1174}
1175
1176static u32
1177force_clear(int enable_activate_before, int enable_activate_after,
1178 u32 *returnCode, int verbose)
1179{
1180 u32 rc;
1181 int has_owner;
1182
1183 rc = read_has_owner(&has_owner);
1184 if (rc)
1185 return rc;
1186 if (!has_owner) {
1187 if (verbose)
1188 printf("TPM does not have an owner.\n");
1189 return 0;
1190 }
1191
1192 if (enable_activate_before) {
1193 rc = enable_activate(0, returnCode, verbose);
1194 if (rc) {
1195 dprintf(DEBUG_tcg,
1196 "TCGBIOS: Enabling/activating the TPM failed.\n");
1197 return rc;
1198 }
1199 }
1200
1201 rc = assert_physical_presence(verbose);
1202 if (rc) {
1203 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
1204 return rc;
1205 }
1206
1207 rc = build_and_send_cmd(0, TPM_ORD_ForceClear,
Kevin O'Connor71479612015-12-29 14:32:19 -05001208 NULL, 0, returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Berger320df852015-11-30 11:14:19 -05001209
1210 dprintf(DEBUG_tcg, "Return code from TPM_ForceClear() = 0x%08x\n",
1211 *returnCode);
1212
1213 if (rc || *returnCode)
1214 goto err_exit;
1215
1216 if (!enable_activate_after) {
1217 if (verbose)
1218 printf("Owner successfully cleared.\n"
1219 "You will need to enable/activate the TPM again.\n\n");
1220 return 0;
1221 }
1222
1223 enable_activate(1, returnCode, verbose);
1224
1225 return 0;
1226
1227err_exit:
1228 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1229
1230 tpm_set_failure();
1231 if (rc)
1232 return rc;
1233 return TCG_TCG_COMMAND_ERROR;
1234}
1235
1236static u32
1237set_owner_install(int allow, u32 *returnCode, int verbose)
1238{
1239 u32 rc;
1240 int has_owner;
1241 struct tpm_permanent_flags pf;
1242
1243 rc = read_has_owner(&has_owner);
1244 if (rc)
1245 return rc;
1246 if (has_owner) {
1247 if (verbose)
1248 printf("Must first remove owner.\n");
1249 return 0;
1250 }
1251
1252 rc = read_permanent_flags((char *)&pf, sizeof(pf));
1253 if (rc)
1254 return rc;
1255
1256 if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
1257 if (verbose)
1258 printf("TPM must first be enable.\n");
1259 return 0;
1260 }
1261
1262 rc = assert_physical_presence(verbose);
1263 if (rc) {
1264 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
1265 return rc;
1266 }
1267
1268 rc = build_and_send_cmd(0, TPM_ORD_SetOwnerInstall,
1269 (allow) ? CommandFlag_TRUE :
1270 CommandFlag_FALSE,
1271 sizeof(CommandFlag_TRUE),
Kevin O'Connor71479612015-12-29 14:32:19 -05001272 returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Berger320df852015-11-30 11:14:19 -05001273
1274 dprintf(DEBUG_tcg, "Return code from TPM_SetOwnerInstall() = 0x%08x\n",
1275 *returnCode);
1276
1277 if (rc || *returnCode)
1278 goto err_exit;
1279
1280 if (verbose)
1281 printf("Installation of owner %s.\n", allow ? "enabled" : "disabled");
1282
1283 return 0;
1284
1285err_exit:
1286 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1287 tpm_set_failure();
1288 if (rc)
1289 return rc;
1290 return TCG_TCG_COMMAND_ERROR;
1291}
1292
1293static u32
1294tpm_process_cfg(tpm_ppi_code msgCode, int verbose, u32 *returnCode)
1295{
1296 u32 rc = 0;
1297
1298 switch (msgCode) {
1299 case TPM_PPI_OP_NOOP: /* no-op */
1300 break;
1301
1302 case TPM_PPI_OP_ENABLE:
1303 rc = enable_tpm(1, returnCode, verbose);
1304 break;
1305
1306 case TPM_PPI_OP_DISABLE:
1307 rc = enable_tpm(0, returnCode, verbose);
1308 break;
1309
1310 case TPM_PPI_OP_ACTIVATE:
1311 rc = activate_tpm(1, 1, returnCode, verbose);
1312 break;
1313
1314 case TPM_PPI_OP_DEACTIVATE:
1315 rc = activate_tpm(0, 1, returnCode, verbose);
1316 break;
1317
1318 case TPM_PPI_OP_CLEAR:
1319 rc = force_clear(1, 0, returnCode, verbose);
1320 break;
1321
1322 case TPM_PPI_OP_SET_OWNERINSTALL_TRUE:
1323 rc = set_owner_install(1, returnCode, verbose);
1324 break;
1325
1326 case TPM_PPI_OP_SET_OWNERINSTALL_FALSE:
1327 rc = set_owner_install(0, returnCode, verbose);
1328 break;
1329
1330 default:
1331 break;
1332 }
1333
1334 if (rc)
1335 printf("Op %d: An error occurred: 0x%x TPM return code: 0x%x\n",
1336 msgCode, rc, *returnCode);
1337
1338 return rc;
1339}
1340
1341static int
1342get_tpm_state(void)
1343{
1344 int state = 0;
1345 struct tpm_permanent_flags pf;
1346 int has_owner;
1347
1348 if (read_permanent_flags((char *)&pf, sizeof(pf)) ||
1349 read_has_owner(&has_owner))
1350 return ~0;
1351
1352 if (!pf.flags[PERM_FLAG_IDX_DISABLE])
1353 state |= TPM_STATE_ENABLED;
1354
1355 if (!pf.flags[PERM_FLAG_IDX_DEACTIVATED])
1356 state |= TPM_STATE_ACTIVE;
1357
1358 if (has_owner) {
1359 state |= TPM_STATE_OWNED;
1360 } else {
1361 if (pf.flags[PERM_FLAG_IDX_OWNERSHIP])
1362 state |= TPM_STATE_OWNERINSTALL;
1363 }
1364
1365 return state;
1366}
1367
1368static void
1369show_tpm_menu(int state, int next_scancodes[7])
1370{
1371 int i = 0;
1372
1373 printf("\nThe current state of the TPM is:\n");
1374
1375 if (state & TPM_STATE_ENABLED)
1376 printf(" Enabled");
1377 else
1378 printf(" Disabled");
1379
1380 if (state & TPM_STATE_ACTIVE)
1381 printf(" and active\n");
1382 else
1383 printf(" and deactivated\n");
1384
1385 if (state & TPM_STATE_OWNED)
1386 printf(" Ownership has been taken\n");
1387 else {
1388 printf(" Ownership has not been taken\n");
1389 if (state & TPM_STATE_OWNERINSTALL)
1390 printf(" A user can take ownership of the TPM\n");
1391 else
1392 printf(" Taking ownership of the TPM has been disabled\n");
1393 }
1394
1395 if ((state & (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) !=
1396 (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) {
1397 printf("\nNote: To make use of all functionality, the TPM must be "
1398 "enabled and active.\n");
1399 }
1400
1401 printf("\nAvailable options are:\n");
1402 if (state & TPM_STATE_ENABLED) {
1403 printf(" d. Disable the TPM\n");
1404 next_scancodes[i++] = 32;
1405
1406 if (state & TPM_STATE_ACTIVE) {
1407 printf(" v. Deactivate the TPM\n");
1408 next_scancodes[i++] = 47;
1409
1410 if (state & TPM_STATE_OWNERINSTALL) {
1411 printf(" p. Prevent installation of an owner\n");
1412 next_scancodes[i++] = 25;
1413 } else {
1414 printf(" s. Allow installation of an owner\n");
1415 next_scancodes[i++] = 31;
1416 }
1417 } else {
1418 printf(" a. Activate the TPM\n");
1419 next_scancodes[i++] = 30;
1420 }
1421
1422 } else {
1423 printf(" e. Enable the TPM\n");
1424 next_scancodes[i++] = 18;
1425 }
1426
1427 if (state & TPM_STATE_OWNED) {
1428 printf(" c. Clear ownership\n");
1429 next_scancodes[i++] = 46;
1430 }
1431
1432 next_scancodes[i++] = 0;
1433}
1434
1435void
1436tpm_menu(void)
1437{
1438 if (!CONFIG_TCGBIOS)
1439 return;
1440
1441 int scancode, next_scancodes[7];
1442 u32 rc, returnCode;
1443 tpm_ppi_code msgCode;
1444 int state = 0, i;
1445 int waitkey;
1446
1447 while (get_keystroke(0) >= 0)
1448 ;
1449 wait_threads();
1450
1451 printf("The Trusted Platform Module (TPM) is a hardware device in "
1452 "this machine.\n"
1453 "It can help verify the integrity of system software.\n\n");
1454
1455 for (;;) {
1456 if ((state = get_tpm_state()) != ~0) {
1457 show_tpm_menu(state, next_scancodes);
1458 } else {
1459 printf("TPM is not working correctly.\n");
1460 return;
1461 }
1462
1463 printf("\nIf no change is desired or if this menu was reached by "
1464 "mistake, press ESC to\n"
1465 "reboot the machine.\n");
1466
1467 msgCode = TPM_PPI_OP_NOOP;
1468
1469 waitkey = 1;
1470
1471 while (waitkey) {
1472 while ((scancode = get_keystroke(1000)) == ~0)
1473 ;
1474
1475 switch (scancode) {
1476 case 1:
1477 // ESC
1478 reset();
1479 break;
1480 case 18: /* e. enable */
1481 msgCode = TPM_PPI_OP_ENABLE;
1482 break;
1483 case 32: /* d. disable */
1484 msgCode = TPM_PPI_OP_DISABLE;
1485 break;
1486 case 30: /* a. activate */
1487 msgCode = TPM_PPI_OP_ACTIVATE;
1488 break;
1489 case 47: /* v. deactivate */
1490 msgCode = TPM_PPI_OP_DEACTIVATE;
1491 break;
1492 case 46: /* c. clear owner */
1493 msgCode = TPM_PPI_OP_CLEAR;
1494 break;
1495 case 25: /* p. prevent ownerinstall */
1496 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_FALSE;
1497 break;
1498 case 31: /* s. allow ownerinstall */
1499 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_TRUE;
1500 break;
1501 default:
1502 continue;
1503 }
1504
1505 /*
1506 * Using the next_scancodes array, check whether the
1507 * pressed key is currently a valid option.
1508 */
1509 for (i = 0; i < sizeof(next_scancodes); i++) {
1510 if (next_scancodes[i] == 0)
1511 break;
1512
1513 if (next_scancodes[i] == scancode) {
1514 rc = tpm_process_cfg(msgCode, 1, &returnCode);
1515
1516 if (rc)
1517 printf("An error occurred: 0x%x\n", rc);
1518 waitkey = 0;
1519 break;
1520 }
1521 }
1522 }
1523 }
1524}