<div class="socmaildefaultfont" dir="ltr" style="font-family:Arial, Helvetica, sans-serif;font-size:10pt" ><div dir="ltr" >The TCG document that describes the TPM 2.0 crypto agile log format (including the fact that it is little endian) is here <a href="https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClientSpecPlat_TPM_2p0_1p04_pub.pdf" >https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClientSpecPlat_TPM_2p0_1p04_pub.pdf</a> in section 9
<div><br>Chris Engel<br>Power Firmware Security Architect<br>IBM Rochester, MN<br>(507)253-2306<br>internet: cjengel@us.ibm.com</div>
<div> </div>
<div>"Security is not a binary; it is a sliding scale of risk management" - Josh Bressers</div></div>
<div dir="ltr" > </div>
<div dir="ltr" > </div>
<blockquote data-history-content-modified="1" dir="ltr" style="border-left:solid #aaaaaa 2px; margin-left:5px; padding-left:5px; direction:ltr; margin-right:0px" >----- Original message -----<br>From: "Stefan Berger" <stefanb@linux.ibm.com><br>To: "Alexey Kardashevskiy" <aik@ozlabs.ru>, slof@lists.ozlabs.org<br>Cc: kevin@koconnor.net, segher@kernel.crashing.org, Christopher J Engel/Rochester/IBM@IBMUS<br>Subject: Re: [PATCH v6 6/7] tcgbios: Add TPM 2.0 support and firmware API<br>Date: Mon, Jan 20, 2020 11:08 AM<br> 
<div><font size="2" face="Default Monospace,Courier New,Courier,monospace" >On 1/20/20 3:09 AM, Alexey Kardashevskiy wrote:<br>><br>> On 16/01/2020 07:00, Stefan Berger wrote:<br>>> This patch adds TPM 2.0 support along with the firmware API<br>>> that Linux uses to transfer the firmware log.<br>>><br>>> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com><br>>> ---<br>>>   board-qemu/slof/Makefile            |  13 +-<br>>>   board-qemu/slof/tree.fs             |   3 +<br>>>   board-qemu/slof/vio-vtpm-cdriver.fs | 134 ++++<br>>>   board-qemu/slof/vtpm-sml.fs         | 115 ++++<br>>>   include/helpers.h                   |   1 +<br>>>   lib/libtpm/Makefile                 |   2 +-<br>>>   lib/libtpm/tcgbios.c                | 918 ++++++++++++++++++++++++++++<br>>>   lib/libtpm/tcgbios.h                |  32 +<br>>>   lib/libtpm/tcgbios_int.h            | 240 ++++++++<br>>>   lib/libtpm/tpm.code                 | 130 ++++<br>>>   lib/libtpm/tpm.in                   |  26 +<br>>>   slof/fs/packages/disk-label.fs      |  10 +-<br>>>   slof/fs/start-up.fs                 |   5 +<br>>>   13 files changed, 1624 insertions(+), 5 deletions(-)<br>>>   create mode 100644 board-qemu/slof/vio-vtpm-cdriver.fs<br>>>   create mode 100644 board-qemu/slof/vtpm-sml.fs<br>>>   create mode 100644 lib/libtpm/tcgbios.c<br>>>   create mode 100644 lib/libtpm/tcgbios.h<br>>>   create mode 100644 lib/libtpm/tpm.code<br>>>   create mode 100644 lib/libtpm/tpm.in<br>>><br>>> diff --git a/board-qemu/slof/Makefile b/board-qemu/slof/Makefile<br>>> index d7ed2d7..a8cff6d 100644<br>>> --- a/board-qemu/slof/Makefile<br>>> +++ b/board-qemu/slof/Makefile<br>>> @@ -22,7 +22,8 @@ CPPFLAGS = -I$(LIBCMNDIR)/libbootmsg -I$(LIBCMNDIR)/libhvcall \<br>>>     -I$(LIBCMNDIR)/libvirtio -I$(LIBCMNDIR)/libnvram \<br>>>     -I$(LIBCMNDIR)/libusb -I$(LIBCMNDIR)/libveth \<br>>>     -I$(LIBCMNDIR)/libe1k -I$(LIBCMNDIR)/libnet \<br>>> -   -I$(LIBCMNDIR)/libbootmenu<br>>> +   -I$(LIBCMNDIR)/libbootmenu -I$(LIBCMNDIR)/libtpm<br>>> +<br>>>   SLOF_LIBS = \<br>>>   $(LIBCMNDIR)/libbootmsg.a \<br>>>   $(LIBCMNDIR)/libelf.a \<br>>> @@ -33,7 +34,9 @@ SLOF_LIBS = \<br>>>   $(LIBCMNDIR)/libveth.a \<br>>>   $(LIBCMNDIR)/libe1k.a \<br>>>   $(LIBCMNDIR)/libnet.a \<br>>> - $(LIBCMNDIR)/libbootmenu.a<br>>> + $(LIBCMNDIR)/libbootmenu.a \<br>>> + $(LIBCMNDIR)/libtpm.a<br>>> +<br>>>   BOARD_SLOF_IN = \<br>>>   $(LIBCMNDIR)/libhvcall/hvcall.in \<br>>>   $(LIBCMNDIR)/libvirtio/virtio.in \<br>>> @@ -45,7 +48,9 @@ BOARD_SLOF_IN = \<br>>>   $(LIBCMNDIR)/libveth/veth.in \<br>>>   $(LIBCMNDIR)/libe1k/e1k.in \<br>>>   $(LIBCMNDIR)/libnet/libnet.in \<br>>> - $(LIBCMNDIR)/libbootmenu/bootmenu.in<br>>> + $(LIBCMNDIR)/libbootmenu/bootmenu.in \<br>>> + $(LIBCMNDIR)/libtpm/tpm.in<br>>> +<br>>>   BOARD_SLOF_CODE = $(BOARD_SLOF_IN:%.in=%.code)<br>>>  <br>>>   include $(SLOFCMNDIR)/Makefile.inc<br>>> @@ -83,6 +88,7 @@ VIO_FFS_FILES = \<br>>>   $(SLOFBRDDIR)/pci-device_1af4_1050.fs \<br>>>   $(SLOFBRDDIR)/vio-hvterm.fs \<br>>>   $(SLOFBRDDIR)/vio-vscsi.fs \<br>>> + $(SLOFBRDDIR)/vio-vtpm-cdriver.fs \<br>><br>> s/vio-vtpm-cdriver.fs/vio-vtpm.fs/ ?<br>><br>><br>>>   $(SLOFBRDDIR)/vio-veth.fs \<br>>>   $(SLOFBRDDIR)/rtas-nvram.fs \<br>>>   $(SLOFBRDDIR)/virtio-net.fs \<br>>> @@ -114,6 +120,7 @@ OF_FFS_FILES = \<br>>>   $(SLOFBRDDIR)/default-font.bin \<br>>>   $(SLOFBRDDIR)/pci-phb.fs \<br>>>   $(SLOFBRDDIR)/rtas.fs \<br>>> + $(SLOFBRDDIR)/vtpm-sml.fs \<br>>>   $(SLOFBRDDIR)/pci-device_1234_1111.fs \<br>>>   $(SLOFBRDDIR)/pci-device_1013_00b8.fs \<br>>>   $(SLOFBRDDIR)/pci-device_8086_100e.fs \<br>>> diff --git a/board-qemu/slof/tree.fs b/board-qemu/slof/tree.fs<br>>> index d95fde3..7b34125 100644<br>>> --- a/board-qemu/slof/tree.fs<br>>> +++ b/board-qemu/slof/tree.fs<br>>> @@ -87,6 +87,9 @@ include fbuffer.fs<br>>>      2dup " qemu,spapr-nvram" strequal IF<br>>>       " rtas-nvram.fs" included<br>>>      THEN<br>>> +    2dup " IBM,vtpm20" strequal IF<br>>> +                " vio-vtpm-cdriver.fs" included<br>>> +    THEN<br>>>               2drop<br>>>          THEN<br>>>          peer<br>>> diff --git a/board-qemu/slof/vio-vtpm-cdriver.fs b/board-qemu/slof/vio-vtpm-cdriver.fs<br>>> new file mode 100644<br>>> index 0000000..8d17d0e<br>>> --- /dev/null<br>>> +++ b/board-qemu/slof/vio-vtpm-cdriver.fs<br>>> @@ -0,0 +1,134 @@<br>>> +\ *****************************************************************************<br>>> +\ * Copyright (c) 2015-2020 IBM Corporation<br>>> +\ * All rights reserved.<br>>> +\ * This program and the accompanying materials<br>>> +\ * are made available under the terms of the BSD License<br>>> +\ * which accompanies this distribution, and is available at<br>>> +\ * <a href="http://www.opensource.org/licenses/bsd-license.php" target="_blank" >http://www.opensource.org/licenses/bsd-license.php</a><br>>> +\ *<br>>> +\ * Contributors:<br>>> +\ *     IBM Corporation - initial implementation<br>>> +\ ****************************************************************************/<br>>> +<br>>> +." Populating " pwd<br>>> +<br>>> +false VALUE vtpm-debug?<br>>> +0     VALUE vtpm-unit<br>>> +0     VALUE vtpm-ihandle<br>>> +<br>>> +: setup-alias<br>>> +    " ibm,vtpm" find-alias 0= IF<br>>> +        " ibm,vtpm" get-node node>path set-alias<br>>> +    ELSE<br>>> +        drop<br>>> +    THEN<br>>> +;<br>>> +<br>>> +: vtpm-cleanup ( )<br>>> +    vtpm-debug? IF ." VTPM: Disabling RTAS bypass" cr THEN<br>>> +    tpm-finalize<br>>> +    vtpm-unit 0 rtas-set-tce-bypass<br>>> +;<br>>> +<br>>> +: vtpm-init ( -- true | false )<br>>> +    0 0 get-node open-node ?dup 0= IF EXIT THEN<br>>> +    my-self >r<br>>> +    dup to my-self<br>>> +<br>>> +    vtpm-debug? IF ." VTPM: Initializing for c-driver" cr THEN<br>>> +<br>>> +    my-unit to vtpm-unit<br>>> +<br>>> +    \ Enable TCE bypass special qemu feature<br>>> +    vtpm-unit 1 rtas-set-tce-bypass<br>>> +<br>>> +    \ Have TCE bypass cleaned up<br>>> +    ['] vtpm-cleanup add-quiesce-xt<br>>> +<br>>> +    tpm-start ?dup 0= IF<br>>> +        vtpm-debug? IF ." VTPM: Success from tpm-start" cr THEN<br>>> +        setup-alias<br>>> +    ELSE<br>>> +        ." VTPM: Error code from tpm-start: " . cr<br>>> +    THEN<br>>> +<br>>> +    close-node<br>>> +    r> to my-self<br>>> +;<br>>> +<br>>> +\ forward a call to /ibm,vtpm, which implements the function with the<br>>> +\ given name<br>>> +: vtpm-call-forward ( arg ... arg name namelen -- ret ... ret failure? )<br>>> +    \ assign /ibm,vtpm node to vtpm-ihandle, if not assigned<br>>> +    vtpm-ihandle 0= IF<br>>> +        s" /ibm,vtpm" open-dev to vtpm-ihandle<br>><br>> Why does not "open" do this? Is this vtpm supposed to run even before<br>> the client tries using the vtpm services? It does not look like it.<br><br>Initialization of the vTPM is supposed to happen before any client can<br>talk to the firmware.<br><br><br>><br>><br>>> +    THEN<br>>> +<br>>> +    vtpm-ihandle 0<> IF<br>>> +        vtpm-ihandle                   ( arg ... arg name namelen ihandle )<br>>> +        $call-method                   ( ret ... ret )<br>>> +        false                          ( ret ... ret false )<br>>> +    ELSE<br>>> +        true                           ( true )<br>>> +    THEN<br>>> +;<br>>> +<br>>> +\ firmware API call<br>>> +: sml-get-allocated-size ( -- buffer-size)<br>>> +    " sml-get-allocated-size" vtpm-call-forward IF<br>>> +        \ vtpm-call-forward failed<br>>> +        0<br>>> +    THEN<br>>> +;<br>>> +<br>>> +\ firmware API call<br>>> +: sml-get-handover-size ( -- size)<br>>> +    " sml-get-handover-size" vtpm-call-forward IF<br>>> +        \ vtpm-call-forward failed<br>>> +        0<br>>> +    THEN<br>>> +;<br>>> +<br>>> +\ firmware API call<br>>> +: sml-handover ( dest size -- )<br>>> +    " sml-handover" vtpm-call-forward IF<br>>> +        \ vtpm-call-forward failed; clean up stack<br>>> +        2drop<br>>> +    THEN<br>>> +;<br>>> +<br>>> +\ firmware API call<br>>> +: get-failure-reason ( -- reason )<br>>> +    " get-failure-reason" vtpm-call-forward IF<br>>> +        \ vtpm-call-forward failed; return a value<br>>> +        0 \ invalid<br>>> +    THEN<br>>> +;<br>>> +<br>>> +0 0 s" ibm,sml-efi-reformat-supported" property<br>>> +<br>>> +\ firmware API call<br>>> +: reformat-sml-to-efi-alignment ( -- success )<br>>> +    " reformat-sml-to-efi-alignment" vtpm-call-forward IF<br>>> +        false<br>>> +    THEN<br>>> +;<br>>> +<br>>> +: open ( )<br>>> +    vtpm-debug? IF ." VTPM: vTPM open()" cr THEN<br>>> +    true<br>>> +;<br>>> +<br>>> +: close ( )<br>>> +    vtpm-debug? IF ." VTPM: vTPM close()" cr THEN<br>>> +;<br>>> +<br>>> +\ setup alias and the RTAS bypass<br>>> +vtpm-init<br>>> +<br>>> +\ setup the log<br>>> +include vtpm-sml.fs<br>>> +<br>>> +s" /ibm,vtpm" find-node ?dup IF<br>>> +  s" measure-scrtm" rot $call-static<br>>> +THEN<br>><br>> The above 22 lines confuse me a lot.<br>> Why vtpm-sml.fs?<br><br>You mean why does vtpm-sml.fs exist at all?Or why not just put all vTPM<br>code into one file?<br><br><br>> Why "open" does not open?<br>> Why vtpm-init is not in "open"?<br>> Why the device methods are in vtpm-sml.fs?<br>><br>> The Linux finds the device, opens it and calls methods (passing<br>> ihandle), why this complication?<br>><br>> I am missing the point in all of this and 2 lines commit log does not<br>> help at all.<br>><br>><br>><br>><br>>> diff --git a/board-qemu/slof/vtpm-sml.fs b/board-qemu/slof/vtpm-sml.fs<br>>> new file mode 100644<br>>> index 0000000..865dce6<br>>> --- /dev/null<br>>> +++ b/board-qemu/slof/vtpm-sml.fs<br>>> @@ -0,0 +1,115 @@<br>>> +\ *****************************************************************************<br>>> +\ * Copyright (c) 2015-2020 IBM Corporation<br>>> +\ * All rights reserved.<br>>> +\ * This program and the accompanying materials<br>>> +\ * are made available under the terms of the BSD License<br>>> +\ * which accompanies this distribution, and is available at<br>>> +\ * <a href="http://www.opensource.org/licenses/bsd-license.php" target="_blank" >http://www.opensource.org/licenses/bsd-license.php</a><br>>> +\ *<br>>> +\ * Contributors:<br>>> +\ *     IBM Corporation - initial implementation<br>>> +\ ****************************************************************************/<br>>> +<br>>> +\ KVM/qemu TPM Stored Measurement Log (SML) entries in /ibm,vtpm<br>>> +<br>>> +" /" find-device<br>>> +<br>>> +new-device<br>>> +<br>>> +false VALUE    vtpm-debug?<br>>> +0     VALUE    log-base<br>>> +40000 CONSTANT LOG-SIZE   \ 256k per VTPM FW spec.<br>><br>> What is this spec's name exactly? It may not be available to the public<br>> but I could try and get it in IBM internally.<br><br><br>"PFW Virtual TPM Driver" Version 1.1 (or later)<br><br><br>--- /dev/null<br>>> +++ b/lib/libtpm/tcgbios.c<br>>> @@ -0,0 +1,918 @@<br>>> +/*****************************************************************************<br>>> + * Copyright (c) 2015-2020 IBM Corporation<br>>> + * All rights reserved.<br>>> + * This program and the accompanying materials<br>>> + * are made available under the terms of the BSD License<br>>> + * which accompanies this distribution, and is available at<br>>> + * <a href="http://www.opensource.org/licenses/bsd-license.php" target="_blank" >http://www.opensource.org/licenses/bsd-license.php</a><br>>> + *<br>>> + * Contributors:<br>>> + *     IBM Corporation - initial implementation<br>>> + *     Stefan Berger, stefanb@linux.ibm.com<br>>> + *     Kevin O'Connor, kevin@koconnor.net<br>>> + *****************************************************************************/<br>>> +<br>>> +/*<br>>> + *  Implementation of the TPM BIOS extension according to the specification<br>>> + *  described in the IBM VTPM Firmware document<br>><br>> Is this "A Protocol for VTPM Communications" from<br>> M_vtpm_protocol_v0r3.pdf or something else?<br><br>The title of the document is 'PFW Virtual TPM Driver'.<br>PFW_CTPM_CLDD_1.1-1.pdf is the file I have.<br><br><br><br>><br>><br>>> and the TCG Specification<br>>> + *  that can be found here under the following link:<br>>> + *  <a href="http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios" target="_blank" >http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios</a><br>><br>> The link is broken.<br><br><br><a href="https://trustedcomputinggroup.org/resource/pc-client-work-group-specific-implementation-specification-for-conventional-bios/" target="_blank" >https://trustedcomputinggroup.org/resource/pc-client-work-group-specific-implementation-specification-for-conventional-bios/</a><br><br><br><br>><br>><br>>> + */<br>>> +<br>>> +#include <stddef.h><br>>> +#include <stdlib.h><br>>> +<br>>> +#include "types.h"<br>>> +#include "byteorder.h"<br>>> +#include "tpm_drivers.h"<br>>> +#include "string.h"<br>>> +#include "tcgbios.h"<br>>> +#include "tcgbios_int.h"<br>>> +#include "stdio.h"<br>>> +#include "sha256.h"<br>>> +#include "helpers.h"<br>>> +#include "version.h"<br>>> +#include "OF.h"<br>>> +<br>>> +#undef TCGBIOS_DEBUG<br>>> +//#define TCGBIOS_DEBUG<br>>> +#ifdef TCGBIOS_DEBUG<br>>> +#define dprintf(_x ...) do { printf("TCGBIOS: " _x); } while(0)<br>>> +#else<br>>> +#define dprintf(_x ...)<br>>> +#endif<br>>> +<br>>> +#define MIN(a, b) ((a) < (b) ? (a) : (b))<br>>> +<br>>> +struct tpm_state {<br>>> + unsigned tpm_probed:1;<br>>> + unsigned tpm_found:1;<br>>> + unsigned tpm_working:1;<br>>> +<br>>> + /* base address of the log area */<br>>> + uint8_t *log_base;<br>>> +<br>>> + /* size of the logging area */<br>>> + size_t log_area_size;<br>>> +<br>>> + /* where to write the next log entry to */<br>>> + uint8_t *log_area_next_entry;<br>>> +};<br>>> +<br>>> +static struct tpm_state tpm_state;<br>> You do not pass a pointer to tpm_state anywhere (it would great if you<br>> did - this way a reader could tell what functions actually need it) so<br>> you do not need "struct tpm_state" type, can be just "struct tpm_state {<br>> ... } tpm_state;"<br><br><br>It's all global variables collected in one structure. I removed the name<br>of the structure.<br><br><br><br>><br>><br>><br>><br>>> +<br>>> +/*<br>>> + * TPM 2 logs are written in little endian format.<br>>> + */<br>>> +static inline uint32_t log32_to_cpu(uint32_t val)<br>>> +{<br>>> + return le32_to_cpu(val);<br>>> +}<br>>> +<br>>> +static inline uint32_t cpu_to_log32(uint32_t val)<br>>> +{<br>>> + return cpu_to_le32(val);<br>>> +}<br>>> +<br>>> +static inline uint16_t cpu_to_log16(uint16_t val)<br>>> +{<br>>> + return cpu_to_le16(val);<br>>> +}<br>>> +<br>>> +/********************************************************<br>>> +  Extensions for TCG-enabled BIOS<br>>> + *******************************************************/<br>>> +<br>>> +static void probe_tpm(void)<br>>> +{<br>>> + tpm_state.tpm_probed = true;<br>>> + tpm_state.tpm_found = spapr_is_vtpm_present();<br>>> + tpm_state.tpm_working = tpm_state.tpm_found;<br>>> +}<br>>> +<br>>> +/****************************************************************<br>>> + * Digest formatting<br>>> + ****************************************************************/<br>>> +<br>>> +static uint32_t tpm20_pcr_selection_size;<br>>> +static struct tpml_pcr_selection *tpm20_pcr_selection;<br>><br>> Any reason these are not in tpm_state?<br><br>I will move them there.<br><br><br>><br>><br>>> +<br>>> +/* A 'struct tpm_log_entry' is a local data structure containing a<br>>> + * 'tpm_log_header' followed by space for the maximum supported<br>>> + * digest. The digest is a series of tpm2_digest_value structs on tpm2.0.<br>>> + */<br>> This comment is rather useless, what I would really be interested to is<br>> the endianness (little endian because it is v2.0?) and the name of the<br>> spec which defines it.<br><br>PPC64 TPM 2.0 logging is supposed to be compatible with client code<br>written for x86_64 Linux. While TPM 1.2 logs on PPC64 were big endian,<br>TPM 2.0 logs are now little endian. I am cc'in Christopher Engel who may<br>have a more recent spec. and told me this is how it's supposed to work.<br><br><br><br>><br>><br>>> +struct tpm_log_entry {<br>>> + struct tpm_log_header hdr;<br>>> + uint8_t pad[sizeof(struct tpm2_digest_values)<br>>> +   + 5 * sizeof(struct tpm2_digest_value)<br>>> +   + SHA1_BUFSIZE + SHA256_BUFSIZE + SHA384_BUFSIZE<br>>> +   + SHA512_BUFSIZE + SM3_256_BUFSIZE];<br>>> +} __attribute__((packed));<br>>> +<br>>> +static const struct hash_parameters {<br>>> + uint16_t hashalg;<br>>> + uint8_t  hashalg_flag;<br>>> + uint8_t  hash_buffersize;<br>>> + const char *name;<br>> name and hashalg_flag are not used.<br><br>True. This occurred when re-splitting the patch.<br><br><br>><br>>> +} hash_parameters[] = {<br>>> + {<br>>> + .hashalg = TPM2_ALG_SHA1,<br>><br>> TPM2_ALG_xxx are basically 1<<index_in_this_array and can be dropped,<br>> can't they?<br><br><br>No:<br><br>lib/libtpm/tcgbios_int.h:#define TPM2_ALG_SHA1 0x0004<br>lib/libtpm/tcgbios_int.h:#define TPM2_ALG_SHA256 0x000b<br>lib/libtpm/tcgbios_int.h:#define TPM2_ALG_SHA384 0x000c<br>lib/libtpm/tcgbios_int.h:#define TPM2_ALG_SHA512 0x000d<br>lib/libtpm/tcgbios_int.h:#define TPM2_ALG_SM3_256 0x0012<br><br><br>><br>><br>>> + .hash_buffersize = SHA1_BUFSIZE,<br>>> + }, {<br>>> + .hashalg = TPM2_ALG_SHA256,<br>>> + .hash_buffersize = SHA256_BUFSIZE,<br>>> + }, {<br>>> + .hashalg = TPM2_ALG_SHA384,<br>>> + .hash_buffersize = SHA384_BUFSIZE,<br>>> + }, {<br>>> + .hashalg = TPM2_ALG_SHA512,<br>>> + .hash_buffersize = SHA512_BUFSIZE,<br>>> + }, {<br>>> + .hashalg = TPM2_ALG_SM3_256,<br>>> + .hash_buffersize = SM3_256_BUFSIZE,<br>>> + }<br>>> +};<br>>> +<br>>> +static int<br>>> +tpm20_get_hash_buffersize(uint16_t hashAlg)<br>>> +{<br>>> + unsigned i;<br>>> +<br>>> + for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {<br>>> + if (hash_parameters[i].hashalg == hashAlg)<br>>> + return hash_parameters[i].hash_buffersize;<br>>> + }<br>>> + return -1;<br>> Just make it return (const struct hash_parameters *) as 7/7 adds one<br>> helper like this for every field of hash_parameters.<br><br><br>OK.<br><br><br>><br>><br>>> +}<br>>> +<br>>> +/*<br>>> + * Build the TPM2 tpm2_digest_values data structure from the given hash.<br>>> + * Follow the PCR bank configuration of the TPM and write the same hash<br>>> + * in either truncated or zero-padded form in the areas of all the other<br>>> + * hashes. For example, write the sha1 hash in the area of the sha256<br>>> + * hash and fill the remaining bytes with zeros. Or truncate the sha256<br>>> + * hash when writing it in the area of the sha1 hash.<br>> It must be correct since you did this but what is the point of this? If<br>> the digest does not fit, fill it with 0xBAADF00D and return an error?<br><br>A TPM 2 has typically 24 platform control registers (PCRs). These<br>registers are storing each a hash (rather than an integer). Basically<br>there is one operation on a hash, which is an 'extend':<br><br>pcr1 = sha256(pcr1 || hash)<br><br>So it takes the current value of PCR 1 and concatenates it with the<br>'hash' to extend it and hashes this concatenation and assigns the result<br>to PCR 1.<br><br>A TPM 2 may have several hash banks, such as for sha1, sha256, sha384,<br>sha512, sm3-256 etc.  So there may be multiple PCR 1 registers, one for<br>the sha1 bank, one for the sha256 bank etc.<br><br>For the logging of measurements we are only using one hash, that is<br>sha256 now, and extend this in PCR1 of sha1, sha256, etc. We do this for<br>all the 'active' PCR banks basically. We log the 'hash' value that a PCR<br>was extended so that someone looking at the current PCR value can use<br>the log to replay (simulate) the extensions of the PCRs. Since we are<br>now using sha256 for hashing we will need to truncate the sha256 when<br>logging it for the sha1 bank and zero pad it for sha384 since sha384 has<br>more bytes. There is the integrity measurement architecture (IMA) in<br>Linux that basically does the same thing:<br><br><br><br>><br>><br>>> + *<br>>> + * le: the log entry to build the digest in<br>>> + * sha1: the sha1 hash value to use<br>>> + * bigEndian: whether to build in big endian format for the TPM or log<br>>> + *            little endian for the log (TPM 2.0)<br>>> + *<br>>> + * Returns the digest size; -1 on fatal error<br>>> + */<br>>> +static int tpm20_build_digest(struct tpm_log_entry *le, const uint8_t *sha256,<br>>> +      bool bigEndian)<br>><br>> Is not it always little endian as it is v2.0 only?<br><br>There are callers for this function who want to send the resulting data<br>structures to the TPM. Other callers want this for the log written in<br>little endian.<br><br><br>><br>>> +{<br>>> + struct tpms_pcr_selection *sel;<br>>> + void *nsel, *end;<br>>> + void *dest = le->hdr.digest + sizeof(struct tpm2_digest_values);<br>>> + uint32_t count;<br>>> + struct tpm2_digest_value *v;<br>>> + struct tpm2_digest_values *vs;<br>>> +<br>>> + if (!tpm20_pcr_selection)<br>><br>> This is allocated at tpm20_startup() and if allocation failed, then we<br>> should not get this far, or can we?<br><br><br>It's a safety net. Cannot keep ?<br><br><br><br>> +<br>> +static int<br>> +tpm20_get_pcrbanks(void)<br>> +{<br>> + uint8_t buffer[128];<br>> + uint32_t size;<br>> + struct tpm2_res_getcapability *trg =<br>> + (struct tpm2_res_getcapability *)&buffer;<br>> +<br>> + int ret = tpm20_getcapability(TPM2_CAP_PCRS, 0, 8, &trg->hdr,<br>> +      sizeof(buffer));<br>> + if (ret)<br>> + return ret;<br>> +<br>> + /* defend against (broken) TPM sending packets that are too short */<br>> + uint32_t resplen = be32_to_cpu(trg->hdr.totlen);<br>><br>> -Werror=declaration-after-statement is not  enforced in SLOF (may be I<br>> should fix it...) but we try follow the linux coding style here in SLOF<br>> :) There are few spots like this.<br><br><br>I fixed these occurrences.<br><br><br>><br>><br>><br>>> + if (resplen <= offset_of(struct tpm2_res_getcapability, data))<br>>> + return -1;<br>>> +<br>>> + size = resplen - offset_of(struct tpm2_res_getcapability, data);<br>>> + /* we need a valid tpml_pcr_selection up to and including sizeOfSelect*/<br>>> + if (size < offset_of(struct tpml_pcr_selection, selections) +<br>>> +   offset_of(struct tpms_pcr_selection, pcrSelect))<br>>> + return -1;<br>>> +<br>>> + tpm20_pcr_selection = SLOF_alloc_mem(size);<br>>> + if (tpm20_pcr_selection) {<br>>> + memcpy(tpm20_pcr_selection, &trg->data, size);<br>>> + tpm20_pcr_selection_size = size;<br>>> + } else {<br>>> + printf("TCGBIOS: Failed to allocated %u bytes.\n", size);<br>>> + ret = -1;<br>> return -1;<br>><br>>> + }<br>>> +<br>>> + return ret;<br>> return 0;<br><br><br>Fixed.<br><br><br>><br>>> +}<br>>> +<br>>> +static int tpm20_extend(struct tpm_log_entry *le, int digest_len)<br>>> +{<br>>> + struct tpm2_req_extend tmp_tre = {<br>>> + .hdr.tag     = cpu_to_be16(TPM2_ST_SESSIONS),<br>>> + .hdr.totlen  = cpu_to_be32(0),<br>>> + .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Extend),<br>>> + .pcrindex    = cpu_to_be32(log32_to_cpu(le->hdr.pcrindex)),<br>>> + .authblocksize = cpu_to_be32(sizeof(tmp_tre.authblock)),<br>>> + .authblock = {<br>>> + .handle = cpu_to_be32(TPM2_RS_PW),<br>>> + .noncesize = cpu_to_be16(0),<br>>> + .contsession = TPM2_YES,<br>>> + .pwdsize = cpu_to_be16(0),<br>>> + },<br>>> + };<br>>> + uint8_t buffer[sizeof(tmp_tre) + sizeof(le->pad)];<br>>> + struct tpm2_req_extend *tre = (struct tpm2_req_extend *)buffer;<br>>> +<br>>> + memcpy(tre, &tmp_tre, sizeof(tmp_tre));<br>>> + memcpy(&tre->digest[0], le->hdr.digest, digest_len);<br>>> +<br>>> + tre->hdr.totlen = cpu_to_be32(sizeof(tmp_tre) + digest_len);<br>>> +<br>>> + struct tpm_rsp_header rsp;<br>>> + uint32_t resp_length = sizeof(rsp);<br>>> + int ret = tpmhw_transmit(0, &tre->hdr, &rsp, &resp_length,<br>>> +                         TPM_DURATION_TYPE_SHORT);<br>>> + if (ret || resp_length != sizeof(rsp) || rsp.errcode)<br>>> + return -1;<br>>> +<br>>> + return 0;<br>>> +}<br>>> +<br>>> +static int tpm20_stirrandom(void)<br>>> +{<br>>> + struct tpm2_req_stirrandom stir = {<br>>> + .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),<br>>> + .hdr.totlen = cpu_to_be32(sizeof(stir)),<br>>> + .hdr.ordinal = cpu_to_be32(TPM2_CC_StirRandom),<br>>> + .size = cpu_to_be16(sizeof(stir.stir)),<br>>> + .stir = rand(),<br>>> + };<br>>> + struct tpm_rsp_header rsp;<br>>> + uint32_t resp_length = sizeof(rsp);<br>>> + int ret = tpmhw_transmit(0, &stir.hdr, &rsp, &resp_length,<br>>> + TPM_DURATION_TYPE_SHORT);<br>>> + if (ret || resp_length != sizeof(rsp) || rsp.errcode)<br>>> + ret = -1;<br>>> +<br>>> + dprintf("TCGBIOS: Return value from sending TPM2_CC_StirRandom = 0x%08x\n",<br>>> + ret);<br>>> +<br>>> + return ret;<br>>> +}<br>>> +<br>>> +static int tpm20_getrandom(uint8_t *buf, uint16_t buf_len)<br>>> +{<br>>> + struct tpm2_res_getrandom rsp;<br>>> + struct tpm2_req_getrandom trgr = {<br>>> + .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),<br>>> + .hdr.totlen = cpu_to_be32(sizeof(trgr)),<br>>> + .hdr.ordinal = cpu_to_be32(TPM2_CC_GetRandom),<br>>> + .bytesRequested = cpu_to_be16(buf_len),<br>>> + };<br>>> + uint32_t resp_length = sizeof(rsp);<br>>> +<br>>> + if (buf_len > sizeof(rsp.rnd.buffer))<br>>> + return -1;<br>>> +<br>>> + int ret = tpmhw_transmit(0, &trgr.hdr, &rsp, &resp_length,<br>>> + TPM_DURATION_TYPE_MEDIUM);<br>>> + if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)<br>>> + ret = -1;<br>>> + else<br>>> + memcpy(buf, rsp.rnd.buffer, buf_len);<br>>> +<br>>> + dprintf("TCGBIOS: Return value from sending TPM2_CC_GetRandom = 0x%08x\n",<br>>> + ret);<br>>> +<br>>> + return ret;<br>>> +}<br>>> +<br>>> +static int tpm20_hierarchychangeauth(uint8_t auth[20])<br>>> +{<br>>> + struct tpm2_req_hierarchychangeauth trhca = {<br>>> + .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),<br>>> + .hdr.totlen = cpu_to_be32(sizeof(trhca)),<br>>> + .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyChangeAuth),<br>>> + .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),<br>>> + .authblocksize = cpu_to_be32(sizeof(trhca.authblock)),<br>>> + .authblock = {<br>>> + .handle = cpu_to_be32(TPM2_RS_PW),<br>>> + .noncesize = cpu_to_be16(0),<br>>> + .contsession = TPM2_YES,<br>>> + .pwdsize = cpu_to_be16(0),<br>>> + },<br>>> + .newAuth = {<br>>> + .size = cpu_to_be16(sizeof(trhca.newAuth.buffer)),<br>>> + },<br>>> + };<br>>> + memcpy(trhca.newAuth.buffer, auth, sizeof(trhca.newAuth.buffer));<br>>> +<br>>> + struct tpm_rsp_header rsp;<br>>> + uint32_t resp_length = sizeof(rsp);<br>>> + int ret = tpmhw_transmit(0, &trhca.hdr, &rsp, &resp_length,<br>>> + TPM_DURATION_TYPE_MEDIUM);<br>>> + if (ret || resp_length != sizeof(rsp) || rsp.errcode)<br>>> + ret = -1;<br>>> +<br>>> + dprintf("TCGBIOS: Return value from sending TPM2_CC_HierarchyChangeAuth = 0x%08x\n",<br>>> + ret);<br>>> +<br>>> + return ret;<br>>> +}<br>>> +<br>>> +static int tpm20_hierarchycontrol(uint32_t hierarchy, uint8_t state)<br>>> +{<br>>> + /* we will try to deactivate the TPM now - ignoring all errors */<br>><br>> Is the comment correct? Neither the name of the function nor the<br>> structure below suggest deactivation, I may also be missing the point here.<br><br><br>I dropped the comment. A caller controlled hierarchy is disabled with<br>this function.<br><br> From the spec:<br><br>"This command enables and disables use of a hierarchy and its associated<br>NV storage. The command allows phEnable, phEnableNV, shEnable, and<br>ehEnable to be changed when the proper authorization is provided."<br><br><br>><br>>> + struct tpm2_req_hierarchycontrol trh = {<br>>> + .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),<br>>> + .hdr.totlen = cpu_to_be32(sizeof(trh)),<br>>> + .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyControl),<br>>> + .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),<br>>> + .authblocksize = cpu_to_be32(sizeof(trh.authblock)),<br>>> + .authblock = {<br>>> + .handle = cpu_to_be32(TPM2_RS_PW),<br>>> + .noncesize = cpu_to_be16(0),<br>>> + .contsession = TPM2_YES,<br>>> + .pwdsize = cpu_to_be16(0),<br>>> + },<br>>> + .enable = cpu_to_be32(hierarchy),<br>>> + .state = state,<br>>> + };<br>>> + struct tpm_rsp_header rsp;<br>>> + uint32_t resp_length = sizeof(rsp);<br>>> + int ret = tpmhw_transmit(0, &trh.hdr, &rsp, &resp_length,<br>>> + TPM_DURATION_TYPE_MEDIUM);<br>>> + if (ret || resp_length != sizeof(rsp) || rsp.errcode)<br>>> + ret = -1;<br>>> +<br>>> + dprintf("TCGBIOS: Return value from sending TPM2_CC_HierarchyControl = 0x%08x\n",<br>>> + ret);<br>>> +<br>>> + return ret;<br>>> +}<br>>> +<br>>> +/****************************************************************<br>>> + * Setup and Measurements<br>>> + ****************************************************************/<br>>> +<br>>> +bool tpm_is_working(void)<br>>> +{<br>>> + if (!tpm_state.tpm_probed)<br>>> + probe_tpm();<br>>> +<br>>> + return tpm_state.tpm_working;<br>>> +}<br>>> +<br>>> +static void tpm_set_failure(void)<br>>> +{<br>>> + tpm20_hierarchycontrol(TPM2_RH_ENDORSEMENT, TPM2_NO);<br>>> + tpm20_hierarchycontrol(TPM2_RH_OWNER, TPM2_NO);<br>>> +<br>>> + tpm_state.tpm_working = false;<br>>> +}<br>>> +<br>>> +/*<br>>> + * Extend the OFDT log with the given entry by copying the<br>>> + * entry data into the log.<br>>> + *<br>>> + * @pcpes: Pointer to the structure to be copied into the log<br>>> + * @event: The event to be appended to 'pcpes'<br>>> + * @event_length: The length of the event<br>>> + *<br>>> + * Returns 0 on success, an error code otherwise.<br>>> + */<br>>> +static uint32_t tpm_log_event_long(struct tpm_log_header *entry,<br>>> +   int digest_len,<br>>> +   const void *event, uint32_t event_length)<br>>> +{<br>>> + size_t size, logsize;<br>>> + void *dest;<br>>> +<br>>> + dprintf("log base address = %p, next entry = %p\n",<br>>> + tpm_state.log_base, tpm_state.log_area_next_entry);<br>>> +<br>>> + if (tpm_state.log_area_next_entry == NULL)<br>>> + return TCGBIOS_LOGOVERFLOW;<br>>> +<br>>> + size = sizeof(*entry) + digest_len +<br>>> +       sizeof(struct tpm_log_trailer) + event_length;<br>>> + logsize = (tpm_state.log_area_next_entry + size -<br>>> +           tpm_state.log_base);<br>>> + if (logsize > tpm_state.log_area_size) {<br>>> + dprintf("TCGBIOS: LOG OVERFLOW: size = %zu\n", size);<br>>> + return TCGBIOS_LOGOVERFLOW;<br>>> + }<br>>> +<br>>> + dest = tpm_state.log_area_next_entry;<br>>> + memcpy(dest, entry, sizeof(*entry) + digest_len);<br>>> + struct tpm_log_trailer *t = dest + sizeof(*entry) + digest_len;<br>>> + t->eventdatasize = cpu_to_log32(event_length);<br>>> + if (event_length)<br>>> + memcpy(t->event, event, event_length);<br>>> +<br>>> + tpm_state.log_area_next_entry += size;<br>>> +<br>>> + return 0;<br>>> +}<br>>> +<br>>> +/* Add an entry at the start of the log describing digest formats<br>>> + */<br>>> +static int tpm20_write_EfiSpecIdEventStruct(void)<br>>> +{<br>>> + if (!tpm20_pcr_selection)<br>>> + return -1;<br>>> +<br>>> + struct {<br>>> + struct TCG_EfiSpecIdEventStruct hdr;<br>>> + uint32_t pad[256];<br>>> + } event = {<br>>> + .hdr.signature = "Spec ID Event03",<br>>> + .hdr.platformClass = TPM_TCPA_ACPI_CLASS_CLIENT,<br>>> + .hdr.specVersionMinor = 0,<br>>> + .hdr.specVersionMajor = 2,<br>>> + .hdr.specErrata = 0,<br>>> + .hdr.uintnSize = 2,<br>>> + };<br>>> +<br>>> + struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections;<br>>> + void *nsel, *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size;<br>>> + int event_size;<br>>> + uint32_t *vendorInfoSize;<br>>> + struct tpm_log_entry le = {<br>>> + .hdr.eventtype = cpu_to_log32(EV_NO_ACTION),<br>>> + };<br>>> + uint32_t count;<br>>> +<br>>> + for (count = 0;<br>>> +     count < be32_to_cpu(tpm20_pcr_selection->count);<br>>> +     count++) {<br>>> + int hsize;<br>>> + uint8_t sizeOfSelect = sel->sizeOfSelect;<br>>> +<br>>> + nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;<br>>> + if (nsel > end)<br>>> + break;<br>>> +<br>>> + hsize = tpm20_get_hash_buffersize(be16_to_cpu(sel->hashAlg));<br>>> + if (hsize < 0) {<br>>> + dprintf("TPM is using an unsupported hash: %d\n",<br>>> + be16_to_cpu(sel->hashAlg));<br>>> + return -1;<br>>> + }<br>>> +<br>>> + event_size = offset_of(struct TCG_EfiSpecIdEventStruct,<br>>> +       digestSizes[count+1]);<br>>> + if (event_size > sizeof(event) - sizeof(uint32_t)) {<br>>> + dprintf("EfiSpecIdEventStruct pad too small\n");<br>>> + return -1;<br>>> + }<br>>> +<br>>> + event.hdr.digestSizes[count].algorithmId =<br>>> + cpu_to_log16(be16_to_cpu(sel->hashAlg));<br>>> + event.hdr.digestSizes[count].digestSize = cpu_to_log16(hsize);<br>>> +<br>>> + sel = nsel;<br>>> + }<br>>> +<br>>> + if (sel != end) {<br>>> + dprintf("Malformed pcr selection structure fron TPM\n");<br>>> + return -1;<br>>> + }<br>>> +<br>>> + event.hdr.numberOfAlgorithms = cpu_to_log32(count);<br>>> + event_size = offset_of(struct TCG_EfiSpecIdEventStruct,<br>>> +       digestSizes[count]);<br>>> + vendorInfoSize = (void*)&event + event_size;<br>>> + *vendorInfoSize = 0;<br>>> + event_size += sizeof(*vendorInfoSize);<br>>> +<br>>> + return tpm_log_event_long(&le.hdr, SHA1_BUFSIZE, &event, event_size);<br>>> +}<br>>> +<br>>> +static int tpm20_startup(void)<br>>> +{<br>>> + int ret;<br>>> +<br>>> + ret = tpm_simple_cmd(0, TPM2_CC_Startup,<br>>> +     2, TPM2_SU_CLEAR, TPM_DURATION_TYPE_SHORT);<br>>> + dprintf("TCGBIOS: Return value from sending TPM2_CC_Startup(SU_CLEAR) = 0x%08x\n",<br>>> + ret);<br>>> +<br>>> + if (ret)<br>>> + goto err_exit;<br>>> +<br>>> + ret = tpm_simple_cmd(0, TPM2_CC_SelfTest,<br>>> +     1, TPM2_YES, TPM_DURATION_TYPE_LONG);<br>>> +<br>>> + dprintf("TCGBIOS: Return value from sending TPM2_CC_SELF_TEST = 0x%08x\n",<br>>> + ret);<br>>> +<br>>> + if (ret)<br>>> + goto err_exit;<br>>> +<br>>> + ret = tpm20_get_pcrbanks();<br>>> + if (ret)<br>>> + goto err_exit;<br>>> +<br>>> + /* the log parameters will be passed from Forth layer */<br>>> +<br>>> + return 0;<br>>> +<br>>> +err_exit:<br>>> + dprintf("TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);<br>>> +<br>>> + tpm_set_failure();<br>>> + return -1;<br>>> +}<br>>> +<br>>> +uint32_t tpm_start(void)<br>>> +{<br>>> + probe_tpm();<br>>> +<br>>> + if (!tpm_is_working()) {<br>>> + dprintf("%s: Machine does not have a working TPM\n",<br>>> + __func__);<br>>> + return TCGBIOS_FATAL_COM_ERROR;<br>>> + }<br>>> +<br>>> + return tpm20_startup();<br>>> +}<br>>> +<br>>> +void tpm_finalize(void)<br>>> +{<br>>> + spapr_vtpm_finalize();<br>>> +}<br>>> +<br>>> +static void tpm20_prepboot(void)<br>>> +{<br>>> + uint8_t auth[20];<br>>> + int ret = tpm20_stirrandom();<br>>> + if (ret)<br>>> + goto err_exit;<br>>> +<br>>> + ret = tpm20_getrandom(&auth[0], sizeof(auth));<br>>> + if (ret)<br>>> + goto err_exit;<br>>> +<br>>> + ret = tpm20_hierarchychangeauth(auth);<br>>> + if (ret)<br>>> + goto err_exit;<br>>> +<br>>> + return;<br>>> +<br>>> +err_exit:<br>>> + dprintf("TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);<br>>> +<br>>> + tpm_set_failure();<br>>> +}<br>>> +<br>>> +/*<br>>> + * Prepare TPM for boot; this function has to be called before<br>>> + * the firmware transitions to the boot loader.<br>><br>> I do not see any caller of this one.<br>><br>><br>>> + */<br>>> +uint32_t tpm_leave_firmware(void)<br>> static?<br>><br>><br>>> +{<br>>> + tpm20_prepboot();<br>>> +<br>>> + return 0;<br>>> +}<br>>> +<br>>> +/****************************************************************<br>>> + * Forth interface<br>>> + ****************************************************************/<br>>> +<br>>> +void tpm_set_log_parameters(void *addr, size_t size)<br>>> +{<br>>> + int ret;<br>>> +<br>>> + dprintf("Log is at 0x%llx; size is %zu bytes\n",<br>>> + (uint64_t)addr, size);<br>>> + tpm_state.log_base = addr;<br>>> + tpm_state.log_area_next_entry = addr;<br>>> + tpm_state.log_area_size = size;<br>>> +<br>>> + ret = tpm20_write_EfiSpecIdEventStruct();<br>>> + if (ret)<br>>> + tpm_set_failure();<br>>> +}<br>>> +<br>>> +uint32_t tpm_get_logsize(void)<br>>> +{<br>>> + uint32_t logsize = tpm_state.log_area_next_entry - tpm_state.log_base;<br>>> +<br>>> + dprintf("log size: %u\n", logsize);<br>>> +<br>>> + return logsize;<br>>> +}<br>>> +<br>>> +/*<br>>> + * Add a measurement to the log;<br>>> + *<br>>> + * Input parameters:<br>>> + *  @pcrindex : PCR to extend<br>>> + *  @event_type : type of event<br>>> + *  @info : pointer to info (i.e., string) to be added to the log as-is<br>>> + *  @info_length: length of the info<br>>> + *  @hashdata : pointer to data to be hashed<br>>> + *  @hashdata_length: length of the data<br>>> + *<br>>> + */<br>>> +static uint32_t tpm_add_measurement_to_log(uint32_t pcrindex,<br>>> +   uint32_t eventtype,<br>>> +   const char *info,<br>>> +   uint32_t infolen,<br>>> +   const uint8_t *hashdata,<br>>> +   uint32_t hashdatalen)<br>>> +{<br>>> + uint8_t hash[SHA256_BUFSIZE];<br>>> + struct tpm_log_entry le = {<br>>> + .hdr.pcrindex = cpu_to_log32(pcrindex),<br>>> + .hdr.eventtype = cpu_to_log32(eventtype),<br>>> + };<br>>> + int digest_len;<br>>> +<br>>> + sha256(hashdata, hashdatalen, hash);<br>>> + digest_len = tpm20_build_digest(&le, hash, true);<br>>> + if (digest_len < 0)<br>>> + return TCGBIOS_GENERAL_ERROR;<br>>> + int ret = tpm20_extend(&le, digest_len);<br>>> + if (ret) {<br>>> + tpm_set_failure();<br>>> + return TCGBIOS_COMMAND_ERROR;<br>>> + }<br>>> + tpm20_build_digest(&le, hash, false);<br>>> + return tpm_log_event_long(&le.hdr, digest_len, info, infolen);<br>>> +}<br>>> +<br>>> +/*<br>>> + * Add an EV_ACTION measurement to the list of measurements<br>>> + */<br>>> +static uint32_t tpm_add_action(uint32_t pcrIndex, const char *string)<br>>> +{<br>>> + uint32_t len = strlen(string);<br>>> +<br>>> + return tpm_add_measurement_to_log(pcrIndex, EV_ACTION,<br>>> +  string, len, (uint8_t *)string, len);<br>>> +}<br>>> +<br>>> +/*<br>>> + * Add event separators for a range of PCRs<br>>> + */<br>>> +uint32_t tpm_add_event_separators(uint32_t start_pcr, uint32_t end_pcr)<br>>> +{<br>>> + static const uint8_t evt_separator[] = {0xff,0xff,0xff,0xff};<br>>> + uint32_t rc = 0;<br>>> + uint32_t pcrIndex;<br>>> +<br>>> + if (!tpm_is_working())<br>>> + return TCGBIOS_GENERAL_ERROR;<br>>> +<br>>> + if (start_pcr >= 24 || start_pcr > end_pcr)<br>>> + return TCGBIOS_INVALID_INPUT_PARA;<br>>> +<br>>> + /* event separators need to be extended and logged for PCRs 0-7 */<br>>> + for (pcrIndex = start_pcr; pcrIndex <= end_pcr; pcrIndex++) {<br>>> + rc = tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,<br>>> + NULL, 0,<br>>> + evt_separator,<br>>> + sizeof(evt_separator));<br>>> + if (rc)<br>>> + break;<br>> return rc;<br>><br>><br>>> + }<br>>> +<br>>> + return rc;<br>><br>> return 0;<br>><br>><br>>> +}<br>>> +<br>>> +uint32_t tpm_measure_bcv_mbr(uint32_t bootdrv, const uint8_t *addr,<br>>> +     uint32_t length)<br>>> +{<br>>> + uint32_t rc;<br>>> + const char *string;<br>>> +<br>>> + if (!tpm_is_working())<br>>> + return TCGBIOS_GENERAL_ERROR;<br>>> +<br>>> + if (length < 0x200)<br>>> + return TCGBIOS_INVALID_INPUT_PARA;<br>>> +<br>>> + string = "Booting BCV device 00h (Floppy)";<br>>> + if (bootdrv == BCV_DEVICE_HDD)<br>>> + string = "Booting BCV device 80h (HDD)";<br>>> +<br>>> + rc = tpm_add_action(4, string);<br>>> + if (rc)<br>>> + return rc;<br>>> +<br>>> + /*<br>>> + * equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum<br>>> + */<br>>> + string = "MBR";<br>><br>> What about GPT (I am not extemely familiar with MBR/GPT but I see my<br>> ubuntu images use GPT these days)?<br>><br>><br>>> + rc = tpm_add_measurement_to_log(4, EV_IPL,<br>>> + string, strlen(string),<br>>> + addr, 0x1b8);<br>>> + if (rc)<br>>> + return rc;<br>>> +<br>>> + /*<br>>> + * equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum<br>>> + */<br>>> + string = "MBR PARTITION TABLE";<br>>> + return tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,<br>>> +  string, strlen(string),<br>>> +  addr + 0x1b8, 0x48);<br>>> +}<br>>> +<br>>> +uint32_t tpm_measure_scrtm(void)<br>>> +{<br>>> + uint32_t rc;<br>>> + char *version_start = strstr((char *)&print_version, "FW Version");<br>>> + char *version_end;<br>>> + uint32_t version_length;<br>>> + char *slof_data_start = (char *)&_slof_data;<br>>> + char *slof_text_start = (char *)&_slof_text;<br>>> + uint32_t slof_data_length = (long)&_slof_data_end - (long)&_slof_data;<br>>> + uint32_t slof_text_length = (long)&_slof_text_end - (long)&_slof_text;<br>>> + const char *scrtm = "S-CRTM Contents";<br>>> +<br>>> + version_end = strchr(version_start, '\r');<br>>> + version_length = version_end - version_start;<br>>> +<br>>> + dprintf("Measure S-CRTM Version: addr = %p, length = %d\n",<br>>> + version_start, version_length);<br>>> +<br>>> + rc = tpm_add_measurement_to_log(0, EV_S_CRTM_VERSION,<br>>> + version_start, version_length,<br>>> + (uint8_t *)version_start,<br>>> + version_length);<br>>> + if (rc)<br>>> + return rc;<br>>> +<br>>> + dprintf("Measure S-CRTM Content (data): start = %p, length = %d\n",<br>>> + slof_data_start, slof_data_length);<br>>> +<br>>> + rc = tpm_add_measurement_to_log(0, EV_S_CRTM_CONTENTS,<br>>> + scrtm, strlen(scrtm),<br>>> + (uint8_t *)slof_data_start,<br>>> + slof_data_length);<br>>> + if (rc)<br>>> + return rc;<br>>> +<br>>> + dprintf("Measure S-CRTM Content (text): start = %p, length = %d\n",<br>>> + slof_text_start, slof_text_length);<br>>> +<br>>> + rc = tpm_add_measurement_to_log(0, EV_S_CRTM_CONTENTS,<br>>> + scrtm, strlen(scrtm),<br>>> + (uint8_t *)slof_text_start,<br>>> + slof_text_length);<br>>> +<br>>> + return rc;<br>>> +}<br>>> +<br>>> +/*<br>>> + * tpm_driver_get_failure_reason: Function for interfacing with the firmware<br>>> + *                                API<br>>> + */<br>>> +uint32_t tpm_driver_get_failure_reason(void)<br>>> +{<br>>> + /* do not check for a working TPM here */<br>>> + if (!tpm_state.tpm_found)<br>>> + return VTPM_DRV_STATE_INVALID;<br>>> +<br>>> + return spapr_vtpm_get_error();<br>>> +}<br>>> +<br>>> +/*<br>>> + * tpm_driver_set_failure_reason: Function for interfacing with the firmware<br>>> + *                                API<br>>> + */<br>>> +void tpm_driver_set_failure_reason(uint32_t errcode)<br>>> +{<br>>> + if (!tpm_state.tpm_found)<br>>> + return;<br>>> +<br>>> + spapr_vtpm_set_error(errcode);<br>>> +}<br>>> diff --git a/lib/libtpm/tcgbios.h b/lib/libtpm/tcgbios.h<br>>> new file mode 100644<br>>> index 0000000..e9f9c36<br>>> --- /dev/null<br>>> +++ b/lib/libtpm/tcgbios.h<br>>> @@ -0,0 +1,32 @@<br>>> +/*****************************************************************************<br>>> + * Copyright (c) 2015-2020 IBM Corporation<br>>> + * All rights reserved.<br>>> + * This program and the accompanying materials<br>>> + * are made available under the terms of the BSD License<br>>> + * which accompanies this distribution, and is available at<br>>> + * <a href="http://www.opensource.org/licenses/bsd-license.php" target="_blank" >http://www.opensource.org/licenses/bsd-license.php</a><br>>> + *<br>>> + * Contributors:<br>>> + *     IBM Corporation - initial implementation<br>>> + *****************************************************************************/<br>>> +<br>>> +#ifndef TCGBIOS_H<br>>> +#define TCGBIOS_H<br>>> +<br>>> +#include <stdint.h><br>>> +#include <stdbool.h><br>>> +<br>>> +uint32_t tpm_start(void);<br>>> +void tpm_finalize(void);<br>>> +uint32_t tpm_leave_firmware(void);<br>>> +uint32_t tpm_measure_scrtm(void);<br>>> +void tpm_set_log_parameters(void *address, size_t size);<br>>> +uint32_t tpm_get_logsize(void);<br>>> +uint32_t tpm_measure_bcv_mbr(uint32_t bootdrv, const uint8_t *addr,<br>>> +                             uint32_t length);<br>>> +uint32_t tpm_add_event_separators(uint32_t start_pcr, uint32_t end_pcr);<br>>> +uint32_t tpm_driver_get_failure_reason(void);<br>>> +void tpm_driver_set_failure_reason(uint32_t errcode);<br>>> +bool tpm_is_working(void);<br>>> +<br>>> +#endif /* TCGBIOS_H */<br>>> diff --git a/lib/libtpm/tcgbios_int.h b/lib/libtpm/tcgbios_int.h<br>>> index 835bd36..3cc4f46 100644<br>>> --- a/lib/libtpm/tcgbios_int.h<br>>> +++ b/lib/libtpm/tcgbios_int.h<br>>> @@ -15,6 +15,94 @@<br>>>  <br>>>   #include <stdint.h><br>>>  <br>>> +/* internal error codes */<br>>> +#define TCGBIOS_OK                       0x0<br>>> +#define TCGBIOS_LOGOVERFLOW              0x1<br>>> +#define TCGBIOS_GENERAL_ERROR            0x2<br>>> +#define TCGBIOS_FIRMWARE_ERROR           0x3<br>>> +#define TCGBIOS_FATAL_COM_ERROR          0x4<br>>> +#define TCGBIOS_INVALID_INPUT_PARA       0x5<br>>> +#define TCGBIOS_COMMAND_ERROR            0x6<br>>> +#define TCGBIOS_INTERFACE_SHUTDOWN       0x7<br>>> +<br>>> +/* event types */<br>>> +#define EV_POST_CODE                     1<br>>> +#define EV_NO_ACTION                     3<br>>> +#define EV_SEPARATOR                     4<br>>> +#define EV_ACTION                        5<br>>> +#define EV_EVENT_TAG                     6<br>>> +#define EV_S_CRTM_CONTENTS               7<br>>> +#define EV_S_CRTM_VERSION                8<br>>> +#define EV_IPL                          13<br>>> +#define EV_IPL_PARTITION_DATA           14<br>>> +<br>>> +#define SHA1_BUFSIZE                    20<br>>> +#define SHA256_BUFSIZE                  32<br>>> +#define SHA384_BUFSIZE                  48<br>>> +#define SHA512_BUFSIZE                  64<br>>> +#define SM3_256_BUFSIZE                 32<br>>> +<br>>> +#define BCV_DEVICE_HDD     0x80<br>>> +<br>>> +struct tpm2_digest_value {<br>>> + uint16_t hashAlg;<br>>> + uint8_t hash[0]; /* size depends on hashAlg */<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct tpm2_digest_values {<br>>> + uint32_t count;<br>>> + struct tpm2_digest_value digest[0];<br>>> +} __attribute__((packed));<br>>> +<br>>> +/* Each entry in the TPM log contains: a tpm_log_header, a variable<br>>> + * length digest, a tpm_log_trailer, and a variable length event.  The<br>>> + * 'digest' matches what is sent to the TPM hardware via the Extend<br>>> + * command.  On TPM1.2 the digest is a SHA1 hash; on TPM2.0 the digest<br>>> + * contains a tpm2_digest_values struct followed by a variable number<br>>> + * of tpm2_digest_value structs (as specified by the hardware via the<br>>> + * TPM2_CAP_PCRS request).<br>>> + */<br>>> +struct tpm_log_header {<br>>> + uint32_t pcrindex;<br>>> + uint32_t eventtype;<br>>> + uint8_t digest[0];<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct tpm_log_trailer {<br>>> + uint32_t eventdatasize;<br>>> + uint8_t event[0];<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct TCG_EfiSpecIdEventStruct {<br>>> + uint8_t signature[16];<br>>> + uint32_t platformClass;<br>>> +#define TPM_TCPA_ACPI_CLASS_CLIENT 0<br>>> + uint8_t specVersionMinor;<br>>> + uint8_t specVersionMajor;<br>>> + uint8_t specErrata;<br>>> + uint8_t uintnSize;<br>>> + uint32_t numberOfAlgorithms;<br>>> + struct TCG_EfiSpecIdEventAlgorithmSize {<br>>> + uint16_t algorithmId;<br>>> + uint16_t digestSize;<br>>> + } digestSizes[0];<br>>> + /*<br>>> + uint8_t vendorInfoSize;<br>>> + uint8_t vendorInfo[0];<br>>> + */<br>>> +} __attribute__((packed));<br>>> +<br>>> +/* Input and Output blocks for the TCG BIOS commands */<br>>> +<br>>> +/* PCClient_PCREventStruct -- format of log entries; compatible with x86 */<br>>> +struct pcpes {<br>>> + uint32_t pcrindex;<br>>> + uint32_t eventtype;<br>>> + uint8_t digest[SHA1_BUFSIZE];<br>>> + uint32_t eventdatasize;<br>>> + uint32_t event;<br>>> +} __attribute__((packed));<br>>> +<br>>>   struct tpm_req_header {<br>>>   uint16_t tag;<br>>>   uint32_t totlen;<br>>> @@ -27,4 +115,156 @@ struct tpm_rsp_header {<br>>>   uint32_t errcode;<br>>>   } __attribute__((packed));<br>>>  <br>>> +/****************************************************************<br>>> + * TPM v2.0 hardware commands<br>>> + ****************************************************************/<br>>> +<br>>> +#define TPM2_NO                     0<br>>> +#define TPM2_YES                    1<br>>> +<br>>> +#define TPM2_SU_CLEAR               0x0000<br>>> +#define TPM2_SU_STATE               0x0001<br>>> +<br>>> +#define TPM2_RH_OWNER               0x40000001<br>>> +#define TPM2_RS_PW                  0x40000009<br>>> +#define TPM2_RH_ENDORSEMENT         0x4000000b<br>>> +#define TPM2_RH_PLATFORM            0x4000000c<br>>> +<br>>> +#define TPM2_ALG_SHA1               0x0004<br>>> +#define TPM2_ALG_SHA256             0x000b<br>>> +#define TPM2_ALG_SHA384             0x000c<br>>> +#define TPM2_ALG_SHA512             0x000d<br>>> +#define TPM2_ALG_SM3_256            0x0012<br>>> +<br>>> +#define TPM2_ALG_SHA1_FLAG          (1 << 0)<br>>> +#define TPM2_ALG_SHA256_FLAG        (1 << 1)<br>>> +#define TPM2_ALG_SHA384_FLAG        (1 << 2)<br>>> +#define TPM2_ALG_SHA512_FLAG        (1 << 3)<br>>> +#define TPM2_ALG_SM3_256_FLAG       (1 << 4)<br>>> +<br>>> +/* TPM 2 command tags */<br>>> +#define TPM2_ST_NO_SESSIONS         0x8001<br>>> +#define TPM2_ST_SESSIONS            0x8002<br>>> +<br>>> +/* TPM 2 commands */<br>>> +#define TPM2_CC_HierarchyControl    0x121<br>>> +#define TPM2_CC_Clear               0x126<br>>> +#define TPM2_CC_ClearControl        0x127<br>>> +#define TPM2_CC_HierarchyChangeAuth 0x129<br>>> +#define TPM2_CC_PCR_Allocate        0x12b<br>>> +#define TPM2_CC_SelfTest            0x143<br>>> +#define TPM2_CC_Startup             0x144<br>>> +#define TPM2_CC_Shutdown            0x145<br>>> +#define TPM2_CC_StirRandom          0x146<br>>> +#define TPM2_CC_GetCapability       0x17a<br>>> +#define TPM2_CC_GetRandom           0x17b<br>>> +#define TPM2_CC_PCR_Extend          0x182<br>>> +<br>>> +/* TPM 2 Capabilities */<br>>> +#define TPM2_CAP_PCRS               0x00000005<br>>> +<br>>> +/* TPM 2 data structures */<br>>> +<br>>> +struct tpm2_req_stirrandom {<br>>> + struct tpm_req_header hdr;<br>>> + uint16_t size;<br>>> + uint64_t stir;<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct tpm2_req_getrandom {<br>>> + struct tpm_req_header hdr;<br>>> + uint16_t bytesRequested;<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct tpm2b_20 {<br>>> + uint16_t size;<br>>> + uint8_t buffer[20];<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct tpm2_res_getrandom {<br>>> + struct tpm_rsp_header hdr;<br>>> + struct tpm2b_20 rnd;<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct tpm2_authblock {<br>>> + uint32_t handle;<br>>> + uint16_t noncesize;  /* always 0 */<br>>> + uint8_t contsession; /* always TPM2_YES */<br>>> + uint16_t pwdsize;    /* always 0 */<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct tpm2_req_hierarchychangeauth {<br>>> + struct tpm_req_header hdr;<br>>> + uint32_t authhandle;<br>>> + uint32_t authblocksize;<br>>> + struct tpm2_authblock authblock;<br>>> + struct tpm2b_20 newAuth;<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct tpm2_req_extend {<br>>> + struct tpm_req_header hdr;<br>>> + uint32_t pcrindex;<br>>> + uint32_t authblocksize;<br>>> + struct tpm2_authblock authblock;<br>>> + uint8_t digest[0];<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct tpm2_req_clearcontrol {<br>>> + struct tpm_req_header hdr;<br>>> + uint32_t authhandle;<br>>> + uint32_t authblocksize;<br>>> + struct tpm2_authblock authblock;<br>>> + uint8_t disable;<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct tpm2_req_clear {<br>>> + struct tpm_req_header hdr;<br>>> + uint32_t authhandle;<br>>> + uint32_t authblocksize;<br>>> + struct tpm2_authblock authblock;<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct tpm2_req_hierarchycontrol {<br>>> + struct tpm_req_header hdr;<br>>> + uint32_t authhandle;<br>>> + uint32_t authblocksize;<br>>> + struct tpm2_authblock authblock;<br>>> + uint32_t enable;<br>>> + uint8_t state;<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct tpm2_req_getcapability {<br>>> + struct tpm_req_header hdr;<br>>> + uint32_t capability;<br>>> + uint32_t property;<br>>> + uint32_t propertycount;<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct tpm2_res_getcapability {<br>>> + struct tpm_rsp_header hdr;<br>>> + uint8_t moreData;<br>>> + uint32_t capability;<br>>> + uint8_t data[0]; /* capability dependent data */<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct tpm2_req_pcr_allocate {<br>>> + struct tpm_req_header hdr;<br>>> + uint32_t authhandle;<br>>> + uint32_t authblocksize;<br>>> + struct tpm2_authblock authblock;<br>>> + uint32_t count;<br>>> + uint8_t tpms_pcr_selections[4];<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct tpms_pcr_selection {<br>>> + uint16_t hashAlg;<br>>> + uint8_t sizeOfSelect;<br>>> + uint8_t pcrSelect[0];<br>>> +} __attribute__((packed));<br>>> +<br>>> +struct tpml_pcr_selection {<br>>> + uint32_t count;<br>>> + struct tpms_pcr_selection selections[0];<br>>> +} __attribute__((packed));<br>>> +<br>><br>> Please separate somehow what is defined for SLOF only (is<br>> TPM2_ALG_SHA1_FLAG/etc?) and for everything else - what comes from what<br>> spec.<br>><br>><br>><br>>>   #endif /* TCGBIOS_INT_H */<br>>> diff --git a/lib/libtpm/tpm.code b/lib/libtpm/tpm.code<br>>> new file mode 100644<br>>> index 0000000..05f4547<br>>> --- /dev/null<br>>> +++ b/lib/libtpm/tpm.code<br>>> @@ -0,0 +1,130 @@<br>>> +/******************************************************************************<br>>> + * Copyright (c) 2015-2020 IBM Corporation<br>>> + * All rights reserved.<br>>> + * This program and the accompanying materials<br>>> + * are made available under the terms of the BSD License<br>>> + * which accompanies this distribution, and is available at<br>>> + * <a href="http://www.opensource.org/licenses/bsd-license.php" target="_blank" >http://www.opensource.org/licenses/bsd-license.php</a><br>>> + *<br>>> + * Contributors:<br>>> + *     IBM Corporation - initial implementation<br>>> + *****************************************************************************/<br>>> +/*<br>>> + * libtpm bindings for SLOF - implementation<br>>> + */<br>>> +<br>>> +#include <tcgbios.h><br>>> +#include <stdbool.h><br>>> +<br>>> +/************************************************/<br>>> +/* Startup TPM code                             */<br>>> +/* SLOF:   tpm-start  ( -- errcode )            */<br>>> +/* LIBTPM: tpm_start(void)                      */<br>>> +/************************************************/<br>>> +PRIM(tpm_X2d_start)<br>>> + PUSH;<br>>> + TOS.n = tpm_start();<br>>> +MIRP<br>>> +<br>>> +/************************************************/<br>>> +/* Shutdown TPM layer before OS takes over      */<br>>> +/* SLOF:   tpm-finalize  ( -- )                 */<br>>> +/* LIBTPM: tpm_finalize(void)                   */<br>>> +/************************************************/<br>>> +PRIM(tpm_X2d_finalize)<br>>> + tpm_finalize();<br>>> +MIRP<br>>> +<br>>> +/***************************************************************/<br>>> +/* Prepare TPM state for bootloader                            */<br>>> +/* SLOF:   tpm-leave-firwmare  ( -- errcode )                  */<br>>> +/* LIBTPM: tpm_leave_firmware(void)                            */<br>>> +/***************************************************************/<br>>> +PRIM(tpm_X2d_leave_X2d_firmware)<br>>> + PUSH;<br>>> + TOS.n = tpm_leave_firmware();<br>>> +MIRP<br>>> +<br>>> +/*************************************************************/<br>>> +/* Convey log address and size                               */<br>>> +/* SLOF:   tpm-set-log-parameters  ( addr size -- )          */<br>>> +/* LIBTPM: tpm_set_log_parameters(void *addr, uint64_t size) */<br>>> +/*************************************************************/<br>>> +PRIM(tpm_X2d_set_X2d_log_X2d_parameters)<br>>> + int size = TOS.u; POP;<br>>> + void *addr = TOS.a; POP;<br>>> + tpm_set_log_parameters(addr, size);<br>>> +MIRP<br>>> +<br>>> +/*********************************************************/<br>>> +/* Firmware API                                          */<br>>> +/* SLOF:   tpm-driver-get_failure-reason ( -- errcode)   */<br>>> +/* LIBTPM: errcode = tpm_driver_get_failure_reason(void) */<br>>> +/*********************************************************/<br>>> +PRIM(tpm_X2d_driver_X2d_get_X2d_failure_X2d_reason)<br>>> + PUSH;<br>>> + TOS.n = tpm_driver_get_failure_reason();<br>>> +MIRP<br>>> +<br>>> +/********************************************************/<br>>> +/* Firmware API                                         */<br>>> +/* SLOF:   tpm-driver-set-failure_reason ( errcode -- ) */<br>>> +/* LIBTPM: tpm_driver_set_failure_reason(errcode)       */<br>>> +/********************************************************/<br>>> +PRIM(tpm_X2d_driver_X2d_set_X2d_failure_X2d_reason)<br>>> + int errcode = TOS.u; POP;<br>>> + tpm_driver_set_failure_reason(errcode);<br>>> +MIRP<br>>> +<br>>> +/************************************************/<br>>> +/* Get the size of the log                      */<br>>> +/* SLOF:   tpm-get-logsize         ( -- size )  */<br>>> +/* LIBTPM: logsize = tpm_get_logsize(void)      */<br>>> +/************************************************/<br>>> +PRIM(tpm_X2d_get_X2d_logsize)<br>>> + PUSH;<br>>> + TOS.n = tpm_get_logsize();<br>>> +MIRP<br>>> +<br>>> +/**********************************************************************/<br>>> +/* Measure and log event separators                                   */<br>>> +/* SLOF:   tpm-add-event-separators  ( start-pcr end-pcr -- errcode)  */<br>>> +/* LIBTPM: errcode = tpm_add_event_separators(start_pcr, end_pcr)     */<br>>> +/**********************************************************************/<br>>> +PRIM(tpm_X2d_add_X2d_event_X2d_separators)<br>>> + int end_pcr = TOS.u; POP;<br>>> + int start_pcr = TOS.u;<br>>> + TOS.n = tpm_add_event_separators(start_pcr, end_pcr);<br>>> +MIRP<br>>> +<br>>> +/*************************************************************************/<br>>> +/* Measure and log boot connect vector (bcv) device's master boot record */<br>>> +/* SLOF:   tpm-measure-bcv-mbr  ( bootdrv addr length -- errcode )       */<br>>> +/* LIBTPM: errcode = tpm_measure_bcv_mbr(bbotdrv, addr, length)          */<br>>> +/*************************************************************************/<br>>> +PRIM(tpm_X2d_measure_X2d_bcv_X2d_mbr)<br>>> + int length = TOS.u; POP;<br>>> + void *addr = TOS.a; POP;<br>>> + int bootdrv = TOS.u;<br>>> + TOS.n = tpm_measure_bcv_mbr(bootdrv, addr, length);<br>>> +MIRP<br>>> +<br>>> +/************************************************/<br>>> +/* Check whether the TPM is working             */<br>>> +/* SLOF:   tpm-is-working  ( -- true | false )  */<br>>> +/* LIBTPM: bool = tpm_is_working()              */<br>>> +/************************************************/<br>><br>> What is calling this one? Now I am really not sure they all are actually<br>> have a user. Thanks,<br>><br>><br>>> +PRIM(tpm_X2d_is_X2d_working)<br>>> + PUSH;<br>>> + TOS.n = tpm_is_working();<br>>> +MIRP<br>>> +<br>>> +/************************************************/<br>>> +/* Have the S-CRTM measured                     */<br>>> +/* SLOF:   tpm-measure-scrtm  ( -- errcode )    */<br>>> +/* LIBTPM: errcode = tpm_measure_scrtm          */<br>>> +/************************************************/<br>>> +PRIM(tpm_X2d_measure_X2d_scrtm)<br>>> + PUSH;<br>>> + TOS.n = tpm_measure_scrtm();<br>>> +MIRP<br>>> diff --git a/lib/libtpm/tpm.in b/lib/libtpm/tpm.in<br>>> new file mode 100644<br>>> index 0000000..22713e4<br>>> --- /dev/null<br>>> +++ b/lib/libtpm/tpm.in<br>>> @@ -0,0 +1,26 @@<br>>> +/******************************************************************************<br>>> + * Copyright (c) 2015-2020 IBM Corporation<br>>> + * All rights reserved.<br>>> + * This program and the accompanying materials<br>>> + * are made available under the terms of the BSD License<br>>> + * which accompanies this distribution, and is available at<br>>> + * <a href="http://www.opensource.org/licenses/bsd-license.php" target="_blank" >http://www.opensource.org/licenses/bsd-license.php</a><br>>> + *<br>>> + * Contributors:<br>>> + *     IBM Corporation - initial implementation<br>>> + *****************************************************************************/<br>>> +/*<br>>> + * libtpm bindings for SLOF - definitions<br>>> + */<br>>> +<br>>> +cod(tpm-start)<br>>> +cod(tpm-finalize)<br>>> +cod(tpm-leave-firmware)<br>>> +cod(tpm-set-log-parameters)<br>>> +cod(tpm-get-logsize)<br>>> +cod(tpm-add-event-separators)<br>>> +cod(tpm-measure-bcv-mbr)<br>>> +cod(tpm-is-working)<br>>> +cod(tpm-measure-scrtm)<br>>> +cod(tpm-driver-get-failure-reason)<br>>> +cod(tpm-driver-set-failure-reason)<br>>> diff --git a/slof/fs/packages/disk-label.fs b/slof/fs/packages/disk-label.fs<br>>> index 8859fb0..77bb0f5 100644<br>>> --- a/slof/fs/packages/disk-label.fs<br>>> +++ b/slof/fs/packages/disk-label.fs<br>>> @@ -550,7 +550,15 @@ B9E5                CONSTANT GPT-BASIC-DATA-PARTITION-2<br>>>   \ load from a bootable partition<br>>>   : load-from-boot-partition ( addr -- size )<br>>>      debug-disk-label? IF ." Trying DOS boot " .s cr THEN<br>>> -   dup load-from-dos-boot-partition ?dup 0 <> IF nip EXIT THEN<br>>> +   dup load-from-dos-boot-partition ?dup 0 <> IF<br>>> +      nip<br>>> +      block s" /ibm,vtpm" find-node ?dup IF<br>>> +         s" measure-hdd-mbr" rot $call-static<br>>> +      ELSE<br>>> +         drop<br>>> +      THEN<br>>> +      EXIT<br>>> +   THEN<br>>>  <br>>>      debug-disk-label? IF ." Trying CHRP boot " .s cr THEN<br>>>      1 disk-chrp-boot !<br>>> diff --git a/slof/fs/start-up.fs b/slof/fs/start-up.fs<br>>> index 7020f5c..c1f931a 100644<br>>> --- a/slof/fs/start-up.fs<br>>> +++ b/slof/fs/start-up.fs<br>>> @@ -56,6 +56,11 @@<br>>>   ;<br>>>  <br>>>   : (boot?) ( -- )<br>>> +   \ last step before we boot we give up physical presence on the TPM<br>>> +   s" /ibm,vtpm" find-node ?dup IF<br>>> +      s" leave-firmware" rot $call-static<br>>> +   THEN<br>>> +<br>>>      of-prompt? not auto-boot? and IF<br>>>         (boot)<br>>>      THEN<br>>></font><br> </div></blockquote>
<div dir="ltr" > </div></div><BR>