summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README167
-rw-r--r--tboot/Makefile49
-rw-r--r--tboot/README213
-rw-r--r--tboot/acmod.c991
-rw-r--r--tboot/acpi.c482
-rw-r--r--tboot/bits.S166
-rw-r--r--tboot/cmdline.c606
-rw-r--r--tboot/com.c134
-rw-r--r--tboot/efiboot.c613
-rw-r--r--tboot/eficonfig.c299
-rw-r--r--tboot/eficore.c534
-rw-r--r--tboot/efimemmap.c276
-rw-r--r--tboot/errors.c285
-rwxr-xr-xtboot/genlds.sh19
-rw-r--r--tboot/hash.c193
-rw-r--r--tboot/heap.c818
-rw-r--r--tboot/include/acpi.h518
-rw-r--r--tboot/include/atomic.h181
-rw-r--r--tboot/include/cmdline.h76
-rw-r--r--tboot/include/com.h311
-rw-r--r--tboot/include/compiler.h52
-rw-r--r--tboot/include/config.h133
-rw-r--r--tboot/include/ctype.h103
-rw-r--r--tboot/include/efibase.h46
-rw-r--r--tboot/include/eficonfig.h109
-rw-r--r--tboot/include/eficore.h134
-rw-r--r--tboot/include/hash.h123
-rw-r--r--tboot/include/integrity.h106
-rw-r--r--tboot/include/io.h91
-rw-r--r--tboot/include/lcp3.h282
-rw-r--r--tboot/include/lcp3_hlp.h117
-rw-r--r--tboot/include/misc.h95
-rw-r--r--tboot/include/mle.h96
-rw-r--r--tboot/include/msr.h90
-rw-r--r--tboot/include/mutex.h58
-rw-r--r--tboot/include/page.h66
-rw-r--r--tboot/include/paging.h122
-rw-r--r--tboot/include/pci_cfgreg.h73
-rw-r--r--tboot/include/printk.h79
-rw-r--r--tboot/include/processor.h340
-rw-r--r--tboot/include/rijndael.h58
-rw-r--r--tboot/include/sha1.h77
-rw-r--r--tboot/include/sha256.h30
-rw-r--r--tboot/include/string.h73
-rw-r--r--tboot/include/tb_error.h89
-rw-r--r--tboot/include/tb_policy.h388
-rw-r--r--tboot/include/tboot.h197
-rw-r--r--tboot/include/tpm.h521
-rw-r--r--tboot/include/tpm_20.h1503
-rw-r--r--tboot/include/txt/acmod.h195
-rw-r--r--tboot/include/txt/config_regs.h240
-rw-r--r--tboot/include/txt/errorcode.h105
-rw-r--r--tboot/include/txt/heap.h377
-rw-r--r--tboot/include/txt/mtrrs.h149
-rw-r--r--tboot/include/txt/smx.h171
-rw-r--r--tboot/include/txt/txt.h76
-rw-r--r--tboot/include/txt/verify.h57
-rw-r--r--tboot/include/txt/vmcs.h346
-rw-r--r--tboot/include/types.h104
-rw-r--r--tboot/include/uuid.h82
-rw-r--r--tboot/include/vga.h87
-rw-r--r--tboot/include/vmac.h168
-rw-r--r--tboot/launch.S484
-rw-r--r--tboot/misc.c455
-rw-r--r--tboot/mtrrs.c624
-rw-r--r--tboot/pci_cfgreg.c173
-rw-r--r--tboot/policy.c879
-rw-r--r--tboot/printk.c195
-rw-r--r--tboot/rijndael.c1270
-rw-r--r--tboot/sha1.c265
-rw-r--r--tboot/sha256.c242
-rw-r--r--tboot/string.c204
-rw-r--r--tboot/tb_error.c196
-rw-r--r--tboot/tboot.c473
-rw-r--r--tboot/tboot.cfg17
-rw-r--r--tboot/tpm.c911
-rw-r--r--tboot/tpm_12.c1952
-rw-r--r--tboot/tpm_20.c2406
-rw-r--r--tboot/txt.c755
-rw-r--r--tboot/verify.c601
-rw-r--r--tboot/vga.c140
-rw-r--r--tboot/vmac.c1228
-rw-r--r--tboot/vmcs.c603
-rw-r--r--tboot/vsprintf.c465
-rw-r--r--xen/series2
-rw-r--r--xen/xen-efi-build.patch54
-rw-r--r--xen/xen-efi-tboot-launch.patch284
-rwxr-xr-xxen/xen.cfg7
88 files changed, 29224 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..3653688
--- /dev/null
+++ b/README
@@ -0,0 +1,167 @@
+==============================================================================
+ __ _ _ _ _
+ / _(_) | | | | | |
+ ___| |_ _ ______| |_| |__ ___ ___ | |_
+ / _ \ _| |______| __| '_ \ / _ \ / _ \| __|
+ | __/ | | | | |_| |_) | (_) | (_) | |_
+ \___|_| |_| \__|_.__/ \___/ \___/ \__|
+
+==============================================================================
+
+ --- EFI TBOOT ---
+
+ /!\ The EFI TBOOT project is currently under development /!\
+
+EFI TBOOT is mostly a proof of concept at this point. It is not currently
+functional. It can be built and installed as an EFI boot loader. It only works
+in conjunction with Xen at the moment. The current development work is being
+done on Fedora 25 x64.
+
+The status as of March 14, 2017 is:
+ - EFI TBOOT will boot, but it needs a few key strokes to get getting
+ going (this is for debugging purposes).
+ - EFI TBOOT will relocate itself to EFI runtime memory and setup a shared
+ runtime variable with Xen.
+ - EFI related configuration setup is done as well as standard TBOOT pre-
+ launch configuration.
+ - Xen is launched and has code to call EFI TBOOT back after EBS.
+ - EFI TBOOT then does the SENTER successfully in the callback.
+ - The post launch entry point is reached but the switch back to long mode
+ is not working.
+
+ --- Get EFI TBOOT ---
+
+The efi-tboot repository can be found here (though if you are reading this you
+probably already know that):
+
+https://github.com/rossphilipson/efi-tboot
+
+$ git clone https://github.com/rossphilipson/efi-tboot.git
+
+Contents:
+
+README - this file
+tboot - all the sources and supporting files for EFI TBOOT
+xen - patches and support files for Xen
+
+ --- Install Xen ---
+
+Xen will be patched, built and installed from sources. Get the Xen 4.7.1
+tarball:
+
+https://www.xenproject.org/downloads/xen-archives/xen-project-47-series/xen-471.html
+
+Install some needed packages to build and configure everything:
+
+$ sudo dnf builddep xen
+$ sudo dnf builddep kernel
+$ sudo dnf install mingw64-binutils.x86_64
+$ sudo dnf install mingw64-gcc.x86_64
+$ sudo dnf install mtools.x86_64
+$ sudo dnf install efibootmgr
+
+Get the latest gnu-efi package, make and install it (see README.gnuefi in the
+project). Note Fedora had a gnu-efi RPM but these was some issue with it.
+Using the latest and building it is working fine.
+
+https://sourceforge.net/projects/gnu-efi/
+
+Xen needs to be patched with the patches found under efi-tboot/xen. Use quilt:
+
+$ cd xen-4.7.1
+$ mkdir patches
+$ cp ../efi-tboot/xen/*.patch patch
+$ cp ../efi-tboot/xen/series patch
+$ quilt push -a
+
+Build and install the Xen tools:
+
+$ ./configure --prefix=/usr --libdir=/usr/lib64 --enable-systemd
+$ make dist-tools
+$ sudo make install-tools
+
+Note had to comment a bunch of modules here: /lib/modules-load.d/xen.conf
+
+#evtchn
+#gntdev
+#netbk
+#blkbk
+#xen-scsibk
+#usbbk
+#pciback
+#blktap2
+
+At this point, building Xen is more or less following the instructions here:
+
+https://wiki.xenproject.org/index.php?title=Xen_EFI&oldid=14685
+
+Note this is an early version of the instructions which is being used. The
+xen.fedora.efi.build.patch patch mentioned here is already in the efi-tboot
+patch set for Xen and applied above. We will sort out build issues like using
+the new instructions later. To build and install:
+
+$ LD_EFI=/usr/x86_64-w64-mingw32/bin/ld make xen
+$ sudo mkdir /boot/efi/EFI/Xen
+$ sudo cp /boot/vmlinuz* /boot/efi/EFI/Xen
+$ sudo cp /boot/initr* /boot/efi/EFI/Xen
+$ sudo cp xen/xen.efi /boot/efi/EFI/Xen
+$ cp ../efi-tboot/xen/xen.cfg /boot/efi/EFI/Xen
+
+Make sure the kernel and initrd lines in the xen.cfg match the ones on your
+platform. Next, create new EFI boot target:
+
+$ efibootmgr -w -L Xen -l "\EFI\Xen\xen.efi" -c
+
+The efibootmgr tool can me used to manage and re-order the EFI boot
+targets. See the man page and help for more details.
+
+Enable the needed Xen services:
+
+$ systemctl enable xenstored.socket
+$ systemctl enable xenconsoled
+$ systemctl enable xen-init-dom0
+$ systemctl start xenstored.socket
+$ systemctl start xenconsoled
+$ systemctl start xen-init-dom0
+
+Reboot and choose Xen from the EFI boot manager.
+
+ --- Install EFI TBOOT ---
+
+Build and install EFI TBOOT and needed support files:
+
+$ cd efi-tboot/tboot
+$ make
+$ sudo mkdir /boot/efi/EFI/TBOOT
+$ sudo cp tboot.efi /boot/efi/EFI/TBOOT
+$ cp tboot.cfg /boot/efi/EFI/TBOOT
+
+Create new EFI boot target:
+
+$ efibootmgr -w -L TBOOT -l "\EFI\TBOOT\tboot.efi" -c
+
+EFI TBOOT needs a number of platform support files used with TXT (called
+Authenticated Code Modules or ACMs). For convenience the packages can be
+gotten from the OpenXT mirror:
+
+http://mirror.openxt.org/
+
+Download:
+
+5-i7-sinit-67.zip
+4th-gen-i5-i7-sinit-75.zip
+5th-gen-i5-i7-sinit_79.zip
+5th_gen_i5_i7-SINIT_79.zip
+6th_gen_i5_i7-SINIT_71.zip
+7th_gen_i5_i7-SINIT_74.zip
+GM45_GS45_PM45-SINIT_51.zip
+Q35-SINIT_51.zip
+Q45_Q43-SINIT_51.zip
+Xeon-5600-3500-SINIT-v1.1.zip
+Xeon-E7-8800-4800-2800-SINIT-v1.1.zip
+i5_i7_DUAL-SINIT_51.zip
+i7_QUAD-SINIT_51.zip
+
+Each package must be unzipped and the .bin or .BIN file in the package needs
+to be copied to /boot/efi/EFI/TBOOT
+
diff --git a/tboot/Makefile b/tboot/Makefile
new file mode 100644
index 0000000..fdae048
--- /dev/null
+++ b/tboot/Makefile
@@ -0,0 +1,49 @@
+# Build with GCC compiler, note .rodata section in .lds file
+#CC = gcc
+# Build with MinGW compiler, note .rdata section in .lds file
+CC = x86_64-w64-mingw32-gcc
+LD = x86_64-w64-mingw32-ld
+CFLAGS = -ffreestanding -fPIE -fno-exceptions -fshort-wchar -mno-ms-bitfields -DTPM_TRACE
+CFLAGS += -I/usr/include/efi -I/usr/include/efi/x86_64 -I/usr/include/efi/protocol -Iinclude
+AFLAGS = -D__ASSEMBLY__ $(patsubst -std=gnu%,,$(CFLAGS))
+#LDFLAGS = -nostdlib -Wl,-pie -shared -Wl,--no-seh -Wl,--subsystem,10 -e efi_main
+LDFLAGS = -nostdlib -pie -shared --no-seh --subsystem=10 -e efi_main
+ASM = launch.S bits.S # must be in order
+SRC = $(wildcard *.c)
+OBJ = $(ASM:.S=.o) # must be first
+OBJ += $(SRC:.c=.o)
+
+# Banner
+CFLAGS += -DTBOOT_CHANGESET=\""$(shell ((hg parents --template "{isodate|isodate} {rev}:{node|short}" >/dev/null && hg parents --template "{isodate|isodate} {rev}:{node|short}") || echo "2016-05-18 12:00 -0800 1.9.4") 2>/dev/null)"\"
+
+
+.PHONY: all
+all: tboot.lds tboot.efi tboot.dsm
+
+tboot.efi: $(OBJ)
+ $(LD) tboot.lds $(LDFLAGS) $^ -o $@
+
+# With lds
+#tboot.efi: $(OBJ)
+# $(CC) -T lds/tboot2.lds $(LDFLAGS) $^ -o $@
+# $(CC) -Wl,lds/tboot2.lds $(LDFLAGS) $^ -o $@
+
+# Grrr someone is frobbing the stack
+tpm_20.o: tpm_20.c
+ $(CC) $(CFLAGS) -mno-stack-arg-probe -o $@ -c $<
+
+%.o: %.c
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+%.o: %.S
+ $(CC) $(AFLAGS) -c $< -o $@
+
+tboot.lds:
+ $(PWD)/genlds.sh $(CC)
+
+tboot.dsm:
+ mingw-objdump -d tboot.efi > tboot.dsm
+
+.PHONY: clean
+clean:
+ rm -f tboot.efi *.o tboot.dsm tboot.lds
diff --git a/tboot/README b/tboot/README
new file mode 100644
index 0000000..6722143
--- /dev/null
+++ b/tboot/README
@@ -0,0 +1,213 @@
+###############################################################################
+Diffs
+
+include/types.h
+ ifdef NULL
+ Added wchar_t
+ Added TODO about x64
+ Changed uintptr_t and size_t to 64b
+
+include/acpi.h
+ Removed extern
+
+include/com.h
+ Removed extern
+
+include/vmac.h
+ Removed extern "C" and C++ stuff
+
+include/hash.h
+ Removed extern
+
+include/integrity.h
+ Removed extern
+
+include/printk.h
+ Removed extern
+
+include/misc.h
+ Removed extern
+
+include/tb_error.h
+ Removed extern
+
+include/tpm.h
+ Removed extern
+ Set tboot_alg_list size to 2
+
+include/tpm_20.h
+ Removed TRUE/FALSE
+
+include/tboot.h
+ Removed extern
+ TODO about tboot/xen shared struct
+
+include/sha1.h
+ Removed extern
+
+include/page.h
+ Use unsigned long long for PAGE UP/DOWN casts.
+
+include/ctype.h
+ Removed extern and use CTYPE_SIZE
+
+include/config.h
+ TODO about setting _start, _end
+ TODO about removing hard coded image locations.
+ Removed a bunch of old layout defines
+ All new layout map at top
+ Changed to .data# and .text# (see https://gcc.gnu.org/ml/gcc-help/2010-09/msg00088.html)
+ Removed __mlept section.
+
+include/cmdline.h
+ Stub out min_ram stuff for now
+ Removed extern
+
+include/msr.h
+ Move rd/wrmsr to assembly module
+
+include/tboot.h
+ Removed zip shit and made log buffer 0x8000, added is_init
+ Change name to begin_initial_launch
+
+include/mutex.h
+ Use 64b mutex obj
+
+include/processor.h
+ Fix 32b things - left orig commented out or comments
+ cpuid bits are fine in 64b
+
+include/txt/config_regs.h
+ TODO about warning, changed to ull
+
+include/txt/vmcs.h
+ Added ap_lock
+
+include/txt/heap.h
+ TODO about warning, changed to ull
+ Removed extern, lctx_addr
+
+include/txt/txt.h
+ TODO about loader_ctx
+ Removed extern
+ Added ap_wfs_count
+
+include/txt/acmod.h
+ Removed extern <function>
+
+include/txt/verify.h
+ Removed extern
+
+include/txt/smx.h
+ Removed extern
+
+include/txt/vmcs.h
+ Removed extern
+
+include/txt/mtrrs.h
+ Removed extern
+
+acpi.c
+ Increased to uint64_t for readl/writel etc.
+ Used unsigned long long when assigning wakeup_vector
+ Did return (struct acpi_rsdt *)(uint64_t)rsdp->rsdp1.rsdt;
+ Use EFI to get RSDP
+ Added cast to uint64_t* of ACPI struct
+
+printk.c
+ Replaced memlog with 1.7.4 one and inlined the buffer in the struct
+
+misc.c
+ Use CTYPE_SIZE for _ctype array size
+
+mtrr.c
+ Use read/write rflags
+ Fix 3 casts w/ unsigned long long
+
+vsnprintf.c
+ Cast arg in call to div64
+
+com.c
+ Removed extern
+
+policy.c
+ Fix lcp pointer in unwrap_lcp_policy unsigned long long
+ Switch to efi_launch_kernel (pre EBS only)
+ Fix externs, move to headers
+ Stub out verify modules function
+ Stub out bits of verify_module function and fix args
+ Call new LCP getter
+
+verify.c
+ Fix inline asm at top getting RFLAGS
+ Stubb out a bunch of e820 related functions w/ TODOs
+
+vmac.c
+ Removed redef of ALIGN and UINT64_C
+
+paging.c
+ Fix for 64b use unsigned long long
+
+mutex.S
+ Had to rewrite as 64b code
+ Merged into basics.S and gone
+
+tpm.c
+ Stubbed some crap so it builds, see TODOs
+ Set tboot_alg_list size to 2
+
+tpm_12.c
+ Stubbed some crap so it builds, see TODOs
+
+tpm_20.c
+ Removed loader.h and loader ctx extern (not needed)
+ Had to use -mno-stack-arg-probe to fix stack problems
+ Stubbed some crap so it builds, see TODOs
+
+hash.c
+ Modified stack buffer to not be stupid
+
+acmod.c
+ Modified a number of pointer casts to ull
+ See existing TODO about racm
+ Move global g_sinit here from txt.c
+
+heap.c
+ Removed include multiboot.h, lctx_addr check
+ Modified a number of pointer casts to ull
+ Fixed calls to verify_ext_data_elts with extra sizeof(size)
+
+error.c
+ Removed include loader.h
+ Added atomic.h inclue
+
+cmdline.c
+ Stub out min_ram stuff for now
+
+vga.c
+ Change from int to long long for writew/readw
+
+###############################################################################
+Special
+
+The following were put together bit by bit so changes are not tracked here:
+
+tboot.c
+txt.c
+
+Several small string modules were merged into string.c:
+strlen.c
+strcmp.c
+strncmp.c
+strncpy.c
+strtoul.c
+index.c
+memcmp.c
+
+###############################################################################
+--- Issues ---
+
+ - Had to initialize the cmdline to defaults otherwise the calls before loading
+the cmdline were returning garbage.
+
+ - Trying to init mwait was causing hangs on writemsr.
diff --git a/tboot/acmod.c b/tboot/acmod.c
new file mode 100644
index 0000000..6601222
--- /dev/null
+++ b/tboot/acmod.c
@@ -0,0 +1,991 @@
+/*
+ * acmod.c: support functions for use of Intel(r) TXT Authenticated
+ * Code (AC) Modules
+ *
+ * Copyright (c) 2003-2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef IS_INCLUDED /* defined in utils/acminfo.c */
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <printk.h>
+#include <compiler.h>
+#include <string.h>
+#include <processor.h>
+#include <msr.h>
+#include <misc.h>
+#include <uuid.h>
+#include <mle.h>
+#include <hash.h>
+#include <txt/acmod.h>
+#include <txt/config_regs.h>
+#include <txt/mtrrs.h>
+#include <txt/heap.h>
+#include <txt/smx.h>
+#include <tpm.h>
+#endif /* IS_INCLUDED */
+
+__data acm_hdr_t *g_sinit = 0;
+
+static acm_info_table_t *get_acmod_info_table(const acm_hdr_t* hdr)
+{
+ uint32_t user_area_off;
+
+ /* overflow? */
+ if ( plus_overflow_u32(hdr->header_len, hdr->scratch_size) ) {
+ printk(TBOOT_ERR"ACM header length plus scratch size overflows\n");
+ return NULL;
+ }
+
+ if ( multiply_overflow_u32((hdr->header_len + hdr->scratch_size), 4) ) {
+ printk(TBOOT_ERR"ACM header length and scratch size in bytes overflows\n");
+ return NULL;
+ }
+
+
+ /* this fn assumes that the ACM has already passed at least the initial */
+ /* is_acmod() checks */
+
+ user_area_off = (hdr->header_len + hdr->scratch_size) * 4;
+
+ /* overflow? */
+ if ( plus_overflow_u32(user_area_off, sizeof(acm_info_table_t)) ) {
+ printk(TBOOT_ERR"user_area_off plus acm_info_table_t size overflows\n");
+ return NULL;
+ }
+
+ /* check that table is within module */
+ if ( user_area_off + sizeof(acm_info_table_t) > hdr->size*4 ) {
+ printk(TBOOT_ERR"ACM info table size too large: %x\n",
+ user_area_off + (uint32_t)sizeof(acm_info_table_t));
+ return NULL;
+ }
+
+ /* overflow? */
+ if ( plus_overflow_u64((uint64_t)(uintptr_t)hdr, user_area_off) ) {
+ printk(TBOOT_ERR"hdr plus user_area_off overflows\n");
+ return NULL;
+ }
+
+ return (acm_info_table_t *)((unsigned long long)hdr + user_area_off);
+}
+
+static acm_chipset_id_list_t *get_acmod_chipset_list(const acm_hdr_t* hdr)
+{
+ acm_info_table_t* info_table;
+ uint32_t size, id_list_off;
+ acm_chipset_id_list_t *chipset_id_list;
+
+ /* this fn assumes that the ACM has already passed the is_acmod() checks */
+
+ info_table = get_acmod_info_table(hdr);
+ if ( info_table == NULL )
+ return NULL;
+ id_list_off = info_table->chipset_id_list;
+
+ size = hdr->size * 4;
+
+ /* overflow? */
+ if ( plus_overflow_u32(id_list_off, sizeof(acm_chipset_id_t)) ) {
+ printk(TBOOT_ERR"id_list_off plus acm_chipset_id_t size overflows\n");
+ return NULL;
+ }
+
+ /* check that chipset id table is w/in ACM */
+ if ( id_list_off + sizeof(acm_chipset_id_t) > size ) {
+ printk(TBOOT_ERR"ACM chipset id list is too big: chipset_id_list=%x\n",
+ id_list_off);
+ return NULL;
+ }
+
+ /* overflow? */
+ if ( plus_overflow_u64((uint64_t)(uintptr_t)hdr, id_list_off) ) {
+ printk(TBOOT_ERR"hdr plus id_list_off overflows\n");
+ return NULL;
+ }
+
+ chipset_id_list = (acm_chipset_id_list_t *)
+ ((unsigned long long)hdr + id_list_off);
+
+ /* overflow? */
+ if ( multiply_overflow_u32(chipset_id_list->count,
+ sizeof(acm_chipset_id_t)) ) {
+ printk(TBOOT_ERR"size of acm_chipset_id_list overflows\n");
+ return NULL;
+ }
+ if ( plus_overflow_u32(id_list_off + sizeof(acm_chipset_id_t),
+ chipset_id_list->count * sizeof(acm_chipset_id_t)) ) {
+ printk(TBOOT_ERR"size of all entries overflows\n");
+ return NULL;
+ }
+
+ /* check that all entries are w/in ACM */
+ if ( id_list_off + sizeof(acm_chipset_id_t) +
+ chipset_id_list->count * sizeof(acm_chipset_id_t) > size ) {
+ printk(TBOOT_ERR"ACM chipset id entries are too big:"
+ " chipset_id_list->count=%x\n", chipset_id_list->count);
+ return NULL;
+ }
+
+ return chipset_id_list;
+}
+
+static acm_processor_id_list_t *get_acmod_processor_list(const acm_hdr_t* hdr)
+{
+ acm_info_table_t* info_table;
+ uint32_t size, id_list_off;
+ acm_processor_id_list_t *proc_id_list;
+
+ /* this fn assumes that the ACM has already passed the is_acmod() checks */
+
+ info_table = get_acmod_info_table(hdr);
+ if ( info_table == NULL )
+ return NULL;
+ id_list_off = info_table->processor_id_list;
+
+ size = hdr->size * 4;
+
+ /* overflow? */
+ if ( plus_overflow_u32(id_list_off, sizeof(acm_processor_id_t)) ) {
+ printk(TBOOT_ERR"id_list_off plus acm_processor_id_t size overflows\n");
+ return NULL;
+ }
+
+ /* check that processor id table is w/in ACM */
+ if ( id_list_off + sizeof(acm_processor_id_t) > size ) {
+ printk(TBOOT_ERR"ACM processor id list is too big: processor_id_list=%x\n",
+ id_list_off);
+ return NULL;
+ }
+
+ /* overflow? */
+ if ( plus_overflow_u64((unsigned long long)hdr, id_list_off) ) {
+ printk(TBOOT_ERR"hdr plus id_list_off overflows\n");
+ return NULL;
+ }
+
+ proc_id_list = (acm_processor_id_list_t *)
+ ((unsigned long long)hdr + id_list_off);
+
+ /* overflow? */
+ if ( multiply_overflow_u32(proc_id_list->count,
+ sizeof(acm_processor_id_t)) ) {
+ printk(TBOOT_ERR"size of acm_processor_id_list overflows\n");
+ return NULL;
+ }
+ if ( plus_overflow_u32(id_list_off + sizeof(acm_processor_id_t),
+ proc_id_list->count * sizeof(acm_processor_id_t)) ) {
+ printk(TBOOT_ERR"size of all entries overflows\n");
+ return NULL;
+ }
+
+ /* check that all entries are w/in ACM */
+ if ( id_list_off + sizeof(acm_processor_id_t) +
+ proc_id_list->count * sizeof(acm_processor_id_t) > size ) {
+ printk(TBOOT_ERR"ACM processor id entries are too big:"
+ " proc_id_list->count=%x\n", proc_id_list->count);
+ return NULL;
+ }
+
+ return proc_id_list;
+}
+
+tpm_info_list_t *get_tpm_info_list(const acm_hdr_t* hdr)
+{
+ acm_info_table_t* info_table;
+ uint32_t size, tpm_info_off;
+ tpm_info_list_t *tpm_info;
+
+ /* this fn assumes that the ACM has already passed the is_acmod() checks */
+
+ info_table = get_acmod_info_table(hdr);
+ if ( info_table == NULL )
+ return NULL;
+ tpm_info_off = info_table->tpm_info_list_off;
+
+ size = hdr->size * 4;
+
+ /* overflow? */
+ if ( plus_overflow_u32(tpm_info_off, sizeof(tpm_info_list_t)) ) {
+ printk("tpm_info_off plus tpm_info_list_t size overflows\n");
+ return NULL;
+ }
+
+ /* check that tpm info list is w/in ACM */
+ if ( tpm_info_off + sizeof(tpm_info_list_t) > size ) {
+ printk("TPM info list is too big: tpm_info_list=%x\n",
+ tpm_info_off);
+ return NULL;
+ }
+
+ /* overflow? */
+ if ( plus_overflow_u64((unsigned long long)hdr, tpm_info_off) ) {
+ printk("hdr plus tpm_info_off overflows\n");
+ return NULL;
+ }
+
+ tpm_info = (tpm_info_list_t *)
+ ((unsigned long long)hdr + tpm_info_off);
+
+ /* overflow? */
+ if ( multiply_overflow_u32(tpm_info->count,
+ sizeof(uint16_t)) ) {
+ printk("size of tpm_info_list overflows\n");
+ return NULL;
+ }
+ if ( plus_overflow_u32(tpm_info_off + sizeof(tpm_info_list_t),
+ tpm_info->count * sizeof(uint16_t)) ) {
+ printk("size of all entries overflows\n");
+ return NULL;
+ }
+
+ /* check that all entries are w/in ACM */
+ if ( tpm_info_off + sizeof(tpm_info_list_t) +
+ tpm_info->count * sizeof(uint16_t) > size ) {
+ printk("TPM info list entries are too big:"
+ " tpm_info_list->count=%x\n", tpm_info->count);
+ return NULL;
+ }
+
+ return tpm_info;
+}
+
+void print_txt_caps(const char *prefix, txt_caps_t caps)
+{
+ printk(TBOOT_DETA"%scapabilities: 0x%08x\n", prefix, caps._raw);
+ printk(TBOOT_DETA"%s rlp_wake_getsec: %d\n", prefix, caps.rlp_wake_getsec);
+ printk(TBOOT_DETA"%s rlp_wake_monitor: %d\n", prefix, caps.rlp_wake_monitor);
+ printk(TBOOT_DETA"%s ecx_pgtbl: %d\n", prefix, caps.ecx_pgtbl);
+ printk(TBOOT_DETA"%s stm: %d\n", prefix, caps.stm);
+ printk(TBOOT_DETA"%s pcr_map_no_legacy: %d\n", prefix, caps.pcr_map_no_legacy);
+ printk(TBOOT_DETA"%s pcr_map_da: %d\n", prefix, caps.pcr_map_da);
+ printk(TBOOT_DETA"%s platform_type: %d\n", prefix, caps.platform_type);
+ printk(TBOOT_DETA"%s max_phy_addr: %d\n", prefix, caps.max_phy_addr);
+}
+
+static void print_acm_hdr(const acm_hdr_t *hdr, const char *mod_name)
+{
+ acm_info_table_t *info_table;
+
+ printk(TBOOT_DETA"AC module header dump for %s:\n",
+ (mod_name == NULL) ? "?" : mod_name);
+
+ /* header */
+ printk(TBOOT_DETA"\t type: 0x%x ", hdr->module_type);
+ if ( hdr->module_type == ACM_TYPE_CHIPSET )
+ printk(TBOOT_DETA"(ACM_TYPE_CHIPSET)\n");
+ else
+ printk(TBOOT_INFO"(unknown)\n");
+ printk(TBOOT_DETA"\t subtype: 0x%x ", hdr->module_subtype);
+ if ( hdr->module_subtype == ACM_SUBTYPE_RESET )
+ printk(TBOOT_INFO"(execute at reset)\n");
+ else if ( hdr->module_subtype == 0 )
+ printk(TBOOT_INFO"\n");
+ else
+ printk(TBOOT_INFO"(unknown)\n");
+ printk(TBOOT_DETA"\t length: 0x%x (%u)\n", hdr->header_len, hdr->header_len);
+ printk(TBOOT_DETA"\t version: %u\n", hdr->header_ver);
+ printk(TBOOT_DETA"\t chipset_id: 0x%x\n", (uint32_t)hdr->chipset_id);
+ printk(TBOOT_DETA"\t flags: 0x%x\n", (uint32_t)hdr->flags._raw);
+ printk(TBOOT_DETA"\t\t pre_production: %d\n", (int)hdr->flags.pre_production);
+ printk(TBOOT_DETA"\t\t debug_signed: %d\n", (int)hdr->flags.debug_signed);
+ printk(TBOOT_DETA"\t vendor: 0x%x\n", hdr->module_vendor);
+ printk(TBOOT_DETA"\t date: 0x%08x\n", hdr->date);
+ printk(TBOOT_DETA"\t size*4: 0x%x (%u)\n", hdr->size*4, hdr->size*4);
+ printk(TBOOT_DETA"\t txt_svn: 0x%08x\n", hdr->txt_svn);
+ printk(TBOOT_DETA"\t se_svn: 0x%08x\n", hdr->se_svn);
+ printk(TBOOT_DETA"\t code_control: 0x%x\n", hdr->code_control);
+ printk(TBOOT_DETA"\t entry point: 0x%08x:%08x\n", hdr->seg_sel,
+ hdr->entry_point);
+ printk(TBOOT_DETA"\t scratch_size: 0x%x (%u)\n", hdr->scratch_size,
+ hdr->scratch_size);
+
+ /* info table */
+ printk(TBOOT_DETA"\t info_table:\n");
+ info_table = get_acmod_info_table(hdr);
+ if ( info_table == NULL ) {
+ printk(TBOOT_ERR"\t\t <invalid>\n");
+ return;
+ }
+ printk(TBOOT_DETA"\t\t uuid: "); print_uuid(&info_table->uuid);
+ printk(TBOOT_DETA"\n");
+ if ( are_uuids_equal(&(info_table->uuid), &((uuid_t)ACM_UUID_V3)) )
+ printk(TBOOT_DETA"\t\t ACM_UUID_V3\n");
+ else
+ printk(TBOOT_DETA"\t\t unknown\n");
+ printk(TBOOT_DETA"\t\t chipset_acm_type: 0x%x ",
+ (uint32_t)info_table->chipset_acm_type);
+ if ( info_table->chipset_acm_type == ACM_CHIPSET_TYPE_SINIT )
+ printk(TBOOT_DETA"(SINIT)\n");
+ else if ( info_table->chipset_acm_type == ACM_CHIPSET_TYPE_BIOS )
+ printk(TBOOT_DETA"(BIOS)\n");
+ else
+ printk(TBOOT_DETA"(unknown)\n");
+ printk(TBOOT_DETA"\t\t version: %u\n", (uint32_t)info_table->version);
+ printk(TBOOT_DETA"\t\t length: 0x%x (%u)\n", (uint32_t)info_table->length,
+ (uint32_t)info_table->length);
+ printk(TBOOT_DETA"\t\t chipset_id_list: 0x%x\n", info_table->chipset_id_list);
+ printk(TBOOT_DETA"\t\t os_sinit_data_ver: 0x%x\n", info_table->os_sinit_data_ver);
+ printk(TBOOT_DETA"\t\t min_mle_hdr_ver: 0x%08x\n", info_table->min_mle_hdr_ver);
+ print_txt_caps("\t\t ", info_table->capabilities);
+ printk(TBOOT_DETA"\t\t acm_ver: %u\n", (uint32_t)info_table->acm_ver);
+
+ /* chipset list */
+ printk(TBOOT_DETA"\t chipset list:\n");
+ acm_chipset_id_list_t *chipset_id_list = get_acmod_chipset_list(hdr);
+ if ( chipset_id_list == NULL ) {
+ printk(TBOOT_ERR"\t\t <invalid>\n");
+ return;
+ }
+ printk(TBOOT_DETA"\t\t count: %u\n", chipset_id_list->count);
+ for ( unsigned int i = 0; i < chipset_id_list->count; i++ ) {
+ printk(TBOOT_DETA"\t\t entry %u:\n", i);
+ acm_chipset_id_t *chipset_id = &(chipset_id_list->chipset_ids[i]);
+ printk(TBOOT_DETA"\t\t flags: 0x%x\n", chipset_id->flags);
+ printk(TBOOT_DETA"\t\t vendor_id: 0x%x\n", (uint32_t)chipset_id->vendor_id);
+ printk(TBOOT_DETA"\t\t device_id: 0x%x\n", (uint32_t)chipset_id->device_id);
+ printk(TBOOT_DETA"\t\t revision_id: 0x%x\n",
+ (uint32_t)chipset_id->revision_id);
+ printk(TBOOT_DETA"\t\t extended_id: 0x%x\n", chipset_id->extended_id);
+ }
+
+ if ( info_table->version >= 4 ) {
+ /* processor list */
+ printk(TBOOT_DETA"\t processor list:\n");
+ acm_processor_id_list_t *proc_id_list = get_acmod_processor_list(hdr);
+ if ( proc_id_list == NULL ) {
+ printk(TBOOT_ERR"\t\t <invalid>\n");
+ return;
+ }
+ printk(TBOOT_DETA"\t\t count: %u\n", proc_id_list->count);
+ for ( unsigned int i = 0; i < proc_id_list->count; i++ ) {
+ printk(TBOOT_DETA"\t\t entry %u:\n", i);
+ acm_processor_id_t *proc_id = &(proc_id_list->processor_ids[i]);
+ printk(TBOOT_DETA"\t\t fms: 0x%x\n", proc_id->fms);
+ printk(TBOOT_DETA"\t\t fms_mask: 0x%x\n", proc_id->fms_mask);
+ printk(TBOOT_DETA"\t\t platform_id: 0x%Lx\n", (unsigned long long)proc_id->platform_id);
+ printk(TBOOT_DETA"\t\t platform_mask: 0x%Lx\n", (unsigned long long)proc_id->platform_mask);
+ }
+ }
+
+ if ( info_table->version >= 5 ){
+ /* tpm infor list */
+ printk(TBOOT_DETA"\t TPM info list:\n");
+ tpm_info_list_t *info_list = get_tpm_info_list(hdr);
+ if ( info_list == NULL ) {
+ printk(TBOOT_ERR"\t\t <invalid>\n");
+ return;
+ }
+ printk(TBOOT_DETA"\t\t TPM capability:\n");
+ printk(TBOOT_DETA"\t\t ext_policy: 0x%x\n", info_list->capabilities.ext_policy);
+ printk(TBOOT_DETA"\t\t tpm_family : 0x%x\n", info_list->capabilities.tpm_family);
+ printk(TBOOT_DETA"\t\t tpm_nv_index_set : 0x%x\n", info_list->capabilities.tpm_nv_index_set);
+ printk(TBOOT_DETA"\t\t alg count: %u\n", info_list->count);
+ for ( unsigned int i = 0; i < info_list->count; i++ ) {
+ printk(TBOOT_DETA"\t\t alg_id: 0x%x\n", info_list->alg_id[i]);
+ }
+ }
+}
+
+uint32_t get_supported_os_sinit_data_ver(const acm_hdr_t* hdr)
+{
+ /* assumes that it passed is_sinit_acmod() */
+
+ acm_info_table_t *info_table = get_acmod_info_table(hdr);
+ if ( info_table == NULL )
+ return 0;
+
+ return info_table->os_sinit_data_ver;
+}
+
+txt_caps_t get_sinit_capabilities(const acm_hdr_t* hdr)
+{
+ /* assumes that it passed is_sinit_acmod() */
+
+ acm_info_table_t *info_table = get_acmod_info_table(hdr);
+ if ( info_table == NULL || info_table->version < 3 )
+ return (txt_caps_t){ 0 };
+
+ return info_table->capabilities;
+}
+
+static bool is_acmod(const void *acmod_base, uint32_t acmod_size, uint8_t *type, bool quiet)
+{
+ acm_hdr_t *acm_hdr = (acm_hdr_t *)acmod_base;
+
+ /* first check size */
+ if ( acmod_size < sizeof(acm_hdr_t) ) {
+ if ( !quiet )
+ printk(TBOOT_ERR"\t ACM size is too small: acmod_size=%x,"
+ " sizeof(acm_hdr)=%x\n", acmod_size,
+ (uint32_t)sizeof(acm_hdr) );
+ return false;
+ }
+
+ /* then check overflow */
+ if ( multiply_overflow_u32(acm_hdr->size, 4) ) {
+ if ( !quiet )
+ printk(TBOOT_ERR"\t ACM header size in bytes overflows\n");
+ return false;
+ }
+
+ /* then check size equivalency */
+ if ( acmod_size != acm_hdr->size * 4 ) {
+ if ( !quiet )
+ printk(TBOOT_ERR"\t ACM size is too small: acmod_size=%x,"
+ " acm_hdr->size*4=%x\n", acmod_size, acm_hdr->size*4);
+ return false;
+ }
+
+ /* then check type and vendor */
+ if ( (acm_hdr->module_type != ACM_TYPE_CHIPSET) ||
+ (acm_hdr->module_vendor != ACM_VENDOR_INTEL) ) {
+ if ( !quiet )
+ printk(TBOOT_ERR"\t ACM type/vendor mismatch: module_type=%x,"
+ " module_vendor=%x\n", acm_hdr->module_type,
+ acm_hdr->module_vendor);
+ return false;
+ }
+
+ acm_info_table_t *info_table = get_acmod_info_table(acm_hdr);
+ if ( info_table == NULL )
+ return false;
+
+ /* check if ACM UUID is present */
+ if ( !are_uuids_equal(&(info_table->uuid), &((uuid_t)ACM_UUID_V3)) ) {
+ if ( !quiet ) {
+ printk(TBOOT_ERR"\t unknown UUID: "); print_uuid(&info_table->uuid);
+ printk(TBOOT_ERR"\n");
+ }
+ return false;
+ }
+
+ if ( type != NULL )
+ *type = info_table->chipset_acm_type;
+
+ if ( info_table->version < 3 ) {
+ if ( !quiet )
+ printk(TBOOT_ERR"\t ACM info_table version unsupported (%u)\n",
+ (uint32_t)info_table->version);
+ return false;
+ }
+ /* there is forward compatibility, so this is just a warning */
+ else if ( info_table->version > 5 ) {
+ if ( !quiet )
+ printk(TBOOT_WARN"\t ACM info_table version mismatch (%u)\n",
+ (uint32_t)info_table->version);
+ }
+
+ return true;
+}
+
+bool is_racm_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet)
+{
+ uint8_t type;
+
+ if ( !is_acmod(acmod_base, acmod_size, &type, quiet) )
+ return false;
+
+ if ( type != ACM_CHIPSET_TYPE_BIOS_REVOC &&
+ type != ACM_CHIPSET_TYPE_SINIT_REVOC ) {
+ printk(TBOOT_ERR"ACM is not an revocation ACM (%x)\n", type);
+ return false;
+ }
+
+ if ( acmod_size != 0x8000 && acmod_size != 0x10000 ) {
+ printk(TBOOT_ERR"ACM is not an RACM, bad size (0x%x)\n", acmod_size);
+ return false;
+ }
+
+ return true;
+}
+
+bool is_sinit_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet)
+{
+ uint8_t type;
+
+ if ( !is_acmod(acmod_base, acmod_size, &type, quiet) )
+ return false;
+
+ if ( type != ACM_CHIPSET_TYPE_SINIT ) {
+ printk(TBOOT_ERR"ACM is not an SINIT ACM (%x)\n", type);
+ return false;
+ }
+
+ return true;
+}
+
+bool does_acmod_match_platform(const acm_hdr_t* hdr)
+{
+ /* used to ensure we don't print chipset/proc info for each module */
+ static bool printed_host_info;
+
+ /* this fn assumes that the ACM has already passed the is_acmod() checks */
+
+ /* get chipset fusing, device, and vendor id info */
+ txt_didvid_t didvid;
+ didvid._raw = read_pub_config_reg(TXTCR_DIDVID);
+ txt_ver_fsbif_qpiif_t ver;
+ ver._raw = read_pub_config_reg(TXTCR_VER_FSBIF);
+ if ( (ver._raw & 0xffffffff) == 0xffffffff ||
+ (ver._raw & 0xffffffff) == 0x00 ) /* need to use VER.QPIIF */
+ ver._raw = read_pub_config_reg(TXTCR_VER_QPIIF);
+ if ( !printed_host_info ) {
+ printk(TBOOT_DETA"chipset production fused: %x\n", ver.prod_fused );
+ printk(TBOOT_DETA"chipset ids: vendor: 0x%x, device: 0x%x, revision: 0x%x\n",
+ didvid.vendor_id, didvid.device_id, didvid.revision_id);
+ }
+
+ /* get processor family/model/stepping and platform ID */
+ uint64_t platform_id;
+ uint32_t fms = cpuid_eax(1);
+ platform_id = rdmsr(MSR_IA32_PLATFORM_ID);
+ if ( !printed_host_info ) {
+ printk(TBOOT_DETA"processor family/model/stepping: 0x%x\n", fms );
+ printk(TBOOT_DETA"platform id: 0x%Lx\n", (unsigned long long)platform_id);
+ }
+ printed_host_info = true;
+
+ /*
+ * check if chipset fusing is same
+ */
+ if ( ver.prod_fused != !hdr->flags.debug_signed ) {
+ printk(TBOOT_ERR"\t production/debug mismatch between chipset and ACM\n");
+ return false;
+ }
+
+ /*
+ * check if chipset vendor/device/revision IDs match
+ */
+ acm_chipset_id_list_t *chipset_id_list = get_acmod_chipset_list(hdr);
+ if ( chipset_id_list == NULL )
+ return false;
+
+ printk(TBOOT_DETA"\t %x ACM chipset id entries:\n", chipset_id_list->count);
+ unsigned int i;
+ for ( i = 0; i < chipset_id_list->count; i++ ) {
+ acm_chipset_id_t *chipset_id = &(chipset_id_list->chipset_ids[i]);
+ printk(TBOOT_DETA"\t vendor: 0x%x, device: 0x%x, flags: 0x%x, "
+ "revision: 0x%x, extended: 0x%x\n",
+ (uint32_t)chipset_id->vendor_id,
+ (uint32_t)chipset_id->device_id, chipset_id->flags,
+ (uint32_t)chipset_id->revision_id, chipset_id->extended_id);
+
+ if ( (didvid.vendor_id == chipset_id->vendor_id ) &&
+ (didvid.device_id == chipset_id->device_id ) &&
+ ( ( ( (chipset_id->flags & 0x1) == 0) &&
+ (didvid.revision_id == chipset_id->revision_id) ) ||
+ ( ( (chipset_id->flags & 0x1) == 1) &&
+ ( (didvid.revision_id & chipset_id->revision_id) != 0 ) ) ) )
+ break;
+ }
+ if ( i >= chipset_id_list->count ) {
+ printk(TBOOT_ERR"\t chipset id mismatch\n");
+ return false;
+ }
+
+ /*
+ * check if processor family/model/stepping and platform IDs match
+ */
+ acm_info_table_t *info_table = get_acmod_info_table(hdr);
+ if ( info_table == NULL )
+ return false;
+
+ if ( info_table->version >= 4 ) {
+ acm_processor_id_list_t *proc_id_list = get_acmod_processor_list(hdr);
+ if ( proc_id_list == NULL )
+ return false;
+
+ printk(TBOOT_DETA"\t %x ACM processor id entries:\n", proc_id_list->count);
+ for ( i = 0; i < proc_id_list->count; i++ ) {
+ acm_processor_id_t *proc_id = &(proc_id_list->processor_ids[i]);
+ printk(TBOOT_DETA"\t fms: 0x%x, fms_mask: 0x%x, platform_id: 0x%Lx, "
+ "platform_mask: 0x%Lx\n",
+ proc_id->fms, proc_id->fms_mask,
+ (unsigned long long)proc_id->platform_id,
+ (unsigned long long)proc_id->platform_mask);
+
+ if ( (proc_id->fms == (fms & proc_id->fms_mask)) &&
+ (proc_id->platform_id == (platform_id & proc_id->platform_mask))
+ )
+ break;
+ }
+ if ( i >= proc_id_list->count ) {
+ printk(TBOOT_ERR"\t processor mismatch\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#ifndef IS_INCLUDED
+acm_hdr_t *get_bios_sinit(const void *sinit_region_base)
+{
+ txt_heap_t *txt_heap = get_txt_heap();
+ bios_data_t *bios_data = get_bios_data_start(txt_heap);
+
+ if ( bios_data->bios_sinit_size == 0 )
+ return NULL;
+
+ /* BIOS has loaded an SINIT module, so verify that it is valid */
+ printk(TBOOT_INFO"BIOS has already loaded an SINIT module\n");
+
+ /* is it a valid SINIT module? */
+ if ( !is_sinit_acmod(sinit_region_base, bios_data->bios_sinit_size, false) ||
+ !does_acmod_match_platform((acm_hdr_t *)sinit_region_base) )
+ return NULL;
+
+ return (acm_hdr_t *)sinit_region_base;
+}
+
+static void *alloc_racm_region(uint32_t size)
+{
+ /* TODO: find a real unused memory place through mbi */
+ return (void *)(unsigned long long)(0x2000000 + size - size); /* 32M */
+}
+
+acm_hdr_t *copy_racm(const acm_hdr_t *racm)
+{
+ /* find a 32KB aligned memory */
+ uint32_t racm_region_size = racm->size*4;
+ void *racm_region_base = alloc_racm_region(racm_region_size);
+ printk(TBOOT_DETA"RACM.BASE: %p\n", racm_region_base);
+ printk(TBOOT_DETA"RACM.SIZE: 0x%x (%u)\n", racm_region_size, racm_region_size);
+
+ /* copy it there */
+ memcpy(racm_region_base, racm, racm->size*4);
+
+ printk(TBOOT_DETA"copied RACM (size=%x) to %p\n", racm->size*4,
+ racm_region_base);
+
+ return (acm_hdr_t *)racm_region_base;
+}
+
+acm_hdr_t *copy_sinit(const acm_hdr_t *sinit)
+{
+ /* get BIOS-reserved region from TXT.SINIT.BASE config reg */
+ void *sinit_region_base =
+ (void*)(unsigned long long)read_pub_config_reg(TXTCR_SINIT_BASE);
+ uint32_t sinit_region_size = (uint32_t)read_pub_config_reg(TXTCR_SINIT_SIZE);
+ printk(TBOOT_DETA"TXT.SINIT.BASE: %p\n", sinit_region_base);
+ printk(TBOOT_DETA"TXT.SINIT.SIZE: 0x%x (%u)\n", sinit_region_size, sinit_region_size);
+
+ /*
+ * check if BIOS already loaded an SINIT module there
+ */
+ acm_hdr_t *bios_sinit = get_bios_sinit(sinit_region_base);
+ if ( bios_sinit != NULL ) {
+ /* no other SINIT was provided so must use one BIOS provided */
+ if ( sinit == NULL ) {
+ printk(TBOOT_WARN"no SINIT provided by bootloader; using BIOS SINIT\n");
+ return bios_sinit;
+ }
+
+ /* is it newer than the one we've been provided? */
+ if ( bios_sinit->date >= sinit->date ) {
+ printk(TBOOT_INFO"BIOS-provided SINIT is newer, so using it\n");
+ return bios_sinit; /* yes */
+ }
+ else
+ printk(TBOOT_INFO"BIOS-provided SINIT is older: date=%x\n", bios_sinit->date);
+ }
+ /* our SINIT is newer than BIOS's (or BIOS did not have one) */
+
+ /* BIOS SINIT not present or not valid and none provided */
+ if ( sinit == NULL )
+ return NULL;
+
+ /* overflow? */
+ if ( multiply_overflow_u32(sinit->size, 4) ) {
+ printk(TBOOT_ERR"sinit size in bytes overflows\n");
+ return NULL;
+ }
+
+ /* make sure our SINIT fits in the reserved region */
+ if ( (sinit->size * 4) > sinit_region_size ) {
+ printk(TBOOT_ERR"BIOS-reserved SINIT size (%x) is too small for loaded "
+ "SINIT (%x)\n", sinit_region_size, sinit->size*4);
+ return NULL;
+ }
+
+ /* copy it there */
+ memcpy(sinit_region_base, sinit, sinit->size*4);
+
+ printk(TBOOT_DETA"copied SINIT (size=%x) to %p\n", sinit->size*4,
+ sinit_region_base);
+
+ return (acm_hdr_t *)sinit_region_base;
+}
+#endif /* IS_INCLUDED */
+
+bool verify_racm(const acm_hdr_t *acm_hdr)
+{
+ getsec_parameters_t params;
+ uint32_t size;
+
+ /* assumes this already passed is_acmod() test */
+
+ size = acm_hdr->size * 4; /* hdr size is in dwords, we want bytes */
+
+ /*
+ * AC mod must start on 4k page boundary
+ */
+
+ if ( (unsigned long long)acm_hdr & 0xfff ) {
+ printk(TBOOT_ERR"AC mod base not 4K aligned (%p)\n", acm_hdr);
+ return false;
+ }
+ printk(TBOOT_INFO"AC mod base alignment OK\n");
+
+ /* AC mod size must:
+ * - be multiple of 64
+ * - greater than ???
+ * - less than max supported size for this processor
+ */
+
+ if ( (size == 0) || ((size % 64) != 0) ) {
+ printk(TBOOT_ERR"AC mod size %x bogus\n", size);
+ return false;
+ }
+
+ if ( !get_parameters(&params) ) {
+ printk(TBOOT_ERR"get_parameters() failed\n");
+ return false;
+ }
+
+ if ( size > params.acm_max_size ) {
+ printk(TBOOT_ERR"AC mod size too large: %x (max=%x)\n", size,
+ params.acm_max_size);
+ return false;
+ }
+
+ printk(TBOOT_INFO"AC mod size OK\n");
+
+ /*
+ * perform checks on AC mod structure
+ */
+
+ /* print it for debugging */
+ print_acm_hdr(acm_hdr, "RACM");
+
+ /* entry point is offset from base addr so make sure it is within module */
+ if ( acm_hdr->entry_point >= size ) {
+ printk(TBOOT_ERR"AC mod entry (%08x) >= AC mod size (%08x)\n",
+ acm_hdr->entry_point, size);
+ return false;
+ }
+
+ /* overflow? */
+ if ( plus_overflow_u32(acm_hdr->seg_sel, 8) ) {
+ printk(TBOOT_ERR"seg_sel plus 8 overflows\n");
+ return false;
+ }
+
+ if ( !acm_hdr->seg_sel || /* invalid selector */
+ (acm_hdr->seg_sel & 0x07) || /* LDT, PL!=0 */
+ (acm_hdr->seg_sel + 8 > acm_hdr->gdt_limit) ) {
+ printk(TBOOT_ERR"AC mod selector [%04x] bogus\n", acm_hdr->seg_sel);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Do some AC module sanity checks because any violations will cause
+ * an TXT.RESET. Instead detect these, print a desriptive message,
+ * and skip SENTER/ENTERACCS
+ */
+#ifndef IS_INCLUDED /* defined in utils/acminfo.c */
+void verify_IA32_se_svn_status(const acm_hdr_t *acm_hdr)
+{
+
+ printk(TBOOT_INFO"SGX:verify_IA32_se_svn_status is called\n");
+
+ //check if SGX is enabled by cpuid with ax=7, cx=0
+ if ((cpuid_ebx1(7,0) & 0x00000004) == 0){
+ printk(TBOOT_ERR"SGX is not enabled, cpuid.ebx: 0x%x\n", cpuid_ebx1(7,0));
+ return;
+ }
+ printk(TBOOT_INFO"SGX is enabled, cpuid.ebx:0x%x\n", cpuid_ebx1(7,0));
+ printk(TBOOT_INFO"Comparing se_svn with ACM Header se_svn\n");
+
+ if (((rdmsr(MSR_IA32_SE_SVN_STATUS)>>16) & 0xff) != acm_hdr->se_svn) {
+ printk(TBOOT_INFO"se_svn is not equal to ACM se_svn\n");
+ if (!g_tpm->nv_write(g_tpm, 0, g_tpm->sgx_svn_index, 0, (uint8_t *)&(acm_hdr->se_svn), 1))
+ printk(TBOOT_ERR"Write sgx_svn_index 0x%x failed. \n", g_tpm->sgx_svn_index);
+ else
+ printk(TBOOT_INFO"Write sgx_svn_index with 0x%x successful.\n", acm_hdr->se_svn);
+
+ if ((rdmsr(MSR_IA32_SE_SVN_STATUS) & 0X00000001) !=0) /* reset platform */
+ // printk(TBOOT_INFO"SGX:A reset is required in this boot\n");
+ outb(0xcf9, 0x06);
+ }
+ else
+ printk(TBOOT_INFO"se_svn is equal to ACM se_svn\n");
+
+}
+
+
+bool verify_acmod(const acm_hdr_t *acm_hdr)
+{
+ getsec_parameters_t params;
+ uint32_t size;
+
+ /* assumes this already passed is_acmod() test */
+
+ size = acm_hdr->size * 4; /* hdr size is in dwords, we want bytes */
+
+ /*
+ * AC mod must start on 4k page boundary
+ */
+
+ if ( (unsigned long long)acm_hdr & 0xfff ) {
+ printk(TBOOT_ERR"AC mod base not 4K aligned (%p)\n", acm_hdr);
+ return false;
+ }
+ printk(TBOOT_INFO"AC mod base alignment OK\n");
+
+ /* AC mod size must:
+ * - be multiple of 64
+ * - greater than ???
+ * - less than max supported size for this processor
+ */
+
+ if ( (size == 0) || ((size % 64) != 0) ) {
+ printk(TBOOT_ERR"AC mod size %x bogus\n", size);
+ return false;
+ }
+
+ if ( !get_parameters(&params) ) {
+ printk(TBOOT_ERR"get_parameters() failed\n");
+ return false;
+ }
+
+ if ( size > params.acm_max_size ) {
+ printk(TBOOT_ERR"AC mod size too large: %x (max=%x)\n", size,
+ params.acm_max_size);
+ return false;
+ }
+
+ printk(TBOOT_INFO"AC mod size OK\n");
+
+ /*
+ * perform checks on AC mod structure
+ */
+
+ /* print it for debugging */
+ print_acm_hdr(acm_hdr, "SINIT");
+
+ /* verify SE enablement status */
+ verify_IA32_se_svn_status(acm_hdr);
+
+ /* entry point is offset from base addr so make sure it is within module */
+ if ( acm_hdr->entry_point >= size ) {
+ printk(TBOOT_ERR"AC mod entry (%08x) >= AC mod size (%08x)\n",
+ acm_hdr->entry_point, size);
+ return false;
+ }
+
+ /* overflow? */
+ if ( plus_overflow_u32(acm_hdr->seg_sel, 8) ) {
+ printk(TBOOT_ERR"seg_sel plus 8 overflows\n");
+ return false;
+ }
+
+ if ( !acm_hdr->seg_sel || /* invalid selector */
+ (acm_hdr->seg_sel & 0x07) || /* LDT, PL!=0 */
+ (acm_hdr->seg_sel + 8 > acm_hdr->gdt_limit) ) {
+ printk(TBOOT_ERR"AC mod selector [%04x] bogus\n", acm_hdr->seg_sel);
+ return false;
+ }
+
+ /*
+ * check for compatibility with this MLE
+ */
+
+ acm_info_table_t *info_table = get_acmod_info_table(acm_hdr);
+ if ( info_table == NULL )
+ return false;
+
+ /* check MLE header versions */
+ if ( info_table->min_mle_hdr_ver > MLE_HDR_VER ) {
+ printk(TBOOT_ERR"AC mod requires a newer MLE (0x%08x)\n",
+ info_table->min_mle_hdr_ver);
+ return false;
+ }
+
+ /* check capabilities */
+ /* we need to match one of rlp_wake_{getsec, monitor} */
+ txt_caps_t caps_mask = { 0 };
+ caps_mask.rlp_wake_getsec = caps_mask.rlp_wake_monitor = 1;
+
+ if ( ( ( MLE_HDR_CAPS & caps_mask._raw ) &
+ ( info_table->capabilities._raw & caps_mask._raw) ) == 0 ) {
+ printk(TBOOT_ERR"SINIT and MLE not support compatible RLP wake mechanisms\n");
+ return false;
+ }
+ /* we also expect ecx_pgtbl to be set */
+ if ( !info_table->capabilities.ecx_pgtbl ) {
+ printk(TBOOT_ERR"SINIT does not support launch with MLE pagetable in ECX\n");
+ /* TODO when SINIT ready
+ * return false;
+ */
+ }
+
+ /* check for version of OS to SINIT data */
+ /* we don't support old versions */
+ if ( info_table->os_sinit_data_ver < MIN_OS_SINIT_DATA_VER ) {
+ printk(TBOOT_ERR"SINIT's os_sinit_data version unsupported (%u)\n",
+ info_table->os_sinit_data_ver);
+ return false;
+ }
+ /* only warn if SINIT supports more recent version than us */
+ else if ( info_table->os_sinit_data_ver > MAX_OS_SINIT_DATA_VER ) {
+ printk(TBOOT_WARN"SINIT's os_sinit_data version unsupported (%u)\n",
+ info_table->os_sinit_data_ver);
+ }
+
+ return true;
+}
+#endif /* IS_INCLUDED */
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/acpi.c b/tboot/acpi.c
new file mode 100644
index 0000000..c2a25a4
--- /dev/null
+++ b/tboot/acpi.c
@@ -0,0 +1,482 @@
+/*
+ * acpi.c: ACPI utility fns
+ *
+ * Copyright (c) 2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <compiler.h>
+#include <processor.h>
+#include <io.h>
+#include <string.h>
+#include <printk.h>
+#include <tb_error.h>
+#include <eficore.h>
+#include <tboot.h>
+#include <acpi.h>
+#include <misc.h>
+#include <cmdline.h>
+#include <eficore.h>
+#include <pci_cfgreg.h>
+
+#ifdef ACPI_DEBUG
+#define acpi_printk printk
+#else
+#define acpi_printk(...) /* */
+#endif
+
+static struct acpi_rsdp *rsdp;
+static struct acpi_table_header *g_dmar_table;
+static __data bool g_hide_dmar;
+
+static void dump_gas(const char *reg_name,
+ const tboot_acpi_generic_address_t *reg)
+{
+ const char *space_id[] = { "memory", "I/O", "PCI config space", "EC",
+ "SMBus" };
+
+ printk(TBOOT_DETA"%s GAS @ %p:\n", reg_name, reg);
+ if ( reg == NULL )
+ return;
+
+ if ( reg->space_id >= ARRAY_SIZE(space_id) )
+ printk(TBOOT_DETA"\t space_id: unsupported (%u)\n", reg->space_id);
+ else
+ printk(TBOOT_DETA"\t space_id: %s\n", space_id[reg->space_id]);
+ printk(TBOOT_DETA"\t bit_width: %u\n", reg->bit_width);
+ printk(TBOOT_DETA"\t bit_offset: %u\n", reg->bit_offset);
+ printk(TBOOT_DETA"\t access_width: %u\n", reg->access_width);
+ printk(TBOOT_DETA"\t address: %Lx\n", reg->address);
+}
+
+static inline struct acpi_rsdt *get_rsdt(void)
+{
+ return (struct acpi_rsdt *)(uint64_t)rsdp->rsdp1.rsdt;
+}
+
+static inline struct acpi_xsdt *get_xsdt(void)
+{
+ if ( rsdp->rsdp_xsdt >= 0x100000000ULL ) {
+ printk(TBOOT_ERR"XSDT above 4GB\n");
+ return NULL;
+ }
+ return (struct acpi_xsdt *)(uintptr_t)rsdp->rsdp_xsdt;
+}
+
+static bool verify_acpi_checksum(uint8_t *start, uint8_t len)
+{
+ uint8_t sum = 0;
+ while ( len ) {
+ sum += *start++;
+ len--;
+ }
+ return (sum == 0);
+}
+
+static bool find_rsdp_in_range(void *start, void *end)
+{
+#define RSDP_BOUNDARY 16 /* rsdp ranges on 16-byte boundaries */
+#define RSDP_CHKSUM_LEN 20 /* rsdp check sum length, defined in ACPI 1.0 */
+
+ for ( ; start < end; start += RSDP_BOUNDARY ) {
+ rsdp = (struct acpi_rsdp *)start;
+
+ if ( memcmp(rsdp->rsdp1.signature, RSDP_SIG,
+ sizeof(rsdp->rsdp1.signature)) == 0 ) {
+ if ( verify_acpi_checksum((uint8_t *)rsdp, RSDP_CHKSUM_LEN) ) {
+ printk(TBOOT_DETA"RSDP (v%u, %.6s) @ %p\n", rsdp->rsdp1.revision,
+ rsdp->rsdp1.oemid, rsdp);
+ return true;
+ }
+ else {
+ printk(TBOOT_ERR"checksum failed.\n");
+ return false;
+ }
+ }
+ }
+ return false;
+}
+
+static bool find_rsdp(void)
+{
+ uint8_t *ldr_rsdp = NULL;
+
+ if ( rsdp != NULL )
+ return true;
+
+ /* We can get the RSDP from EFI */
+ ldr_rsdp = efi_get_rsdp();
+ if (ldr_rsdp != NULL) {
+ rsdp = (struct acpi_rsdp *) ldr_rsdp;
+ return true;
+ }
+
+ /* 0x00 - 0x400 */
+ if ( find_rsdp_in_range(RSDP_SCOPE1_LOW, RSDP_SCOPE1_HIGH) )
+ return true;
+
+ /* 0xE0000 - 0x100000 */
+ if ( find_rsdp_in_range(RSDP_SCOPE2_LOW, RSDP_SCOPE2_HIGH) )
+ return true;
+
+ printk(TBOOT_ERR"can't find RSDP\n");
+ rsdp = NULL;
+ return false;
+}
+
+struct acpi_rsdp
+*get_rsdp(void)
+{
+ if (rsdp != NULL)
+ return rsdp;
+ if (true == find_rsdp())
+ return rsdp;
+
+ return NULL;
+}
+
+/* this function can find dmar table whether or not it was hidden */
+static struct acpi_table_header *find_table(const char *table_name)
+{
+ if ( !find_rsdp() ) {
+ printk(TBOOT_ERR"no rsdp to use\n");
+ return NULL;
+ }
+
+ struct acpi_table_header *table = NULL;
+ struct acpi_xsdt *xsdt = get_xsdt(); /* it is ok even on 1.0 tables */
+ /* because value will be ignored */
+
+ if ( rsdp->rsdp1.revision >= 2 && xsdt != NULL ) { /* ACPI 2.0+ */
+ for ( uint64_t *curr_table = (uint64_t*)xsdt->table_offsets;
+ curr_table < (uint64_t *)((void *)xsdt + xsdt->hdr.length);
+ curr_table++ ) {
+ table = (struct acpi_table_header *)(uintptr_t)*curr_table;
+ if ( memcmp(table->signature, table_name,
+ sizeof(table->signature)) == 0 )
+ return table;
+ }
+ }
+ else { /* ACPI 1.0 */
+ struct acpi_rsdt *rsdt = get_rsdt();
+
+ if ( rsdt == NULL ) {
+ printk(TBOOT_ERR"rsdt is invalid.\n");
+ return NULL;
+ }
+
+ for ( uint32_t *curr_table = rsdt->table_offsets;
+ curr_table < (uint32_t *)((void *)rsdt + rsdt->hdr.length);
+ curr_table++ ) {
+ table = (struct acpi_table_header *)(uintptr_t)*curr_table;
+ if ( memcmp(table->signature, table_name,
+ sizeof(table->signature)) == 0 )
+ return table;
+ }
+ }
+
+ printk(TBOOT_ERR"cann't find %s table.\n", table_name);
+ return NULL;
+}
+
+static struct acpi_dmar *get_vtd_dmar_table(void)
+{
+ return (struct acpi_dmar *)find_table(DMAR_SIG);
+}
+
+bool save_vtd_dmar_table(void)
+{
+ /* find DMAR table and save it */
+ g_dmar_table = (struct acpi_table_header *)get_vtd_dmar_table();
+
+ printk(TBOOT_DETA"DMAR table @ %p saved.\n", g_dmar_table);
+ return true;
+}
+
+bool restore_vtd_dmar_table(void)
+{
+ struct acpi_table_header *hdr;
+
+ g_hide_dmar = false;
+
+ /* find DMAR table first */
+ hdr = (struct acpi_table_header *)get_vtd_dmar_table();
+ if ( hdr != NULL ) {
+ printk(TBOOT_DETA"DMAR table @ %p is still there, skip restore step.\n", hdr);
+ return true;
+ }
+
+ /* check saved DMAR table */
+ if ( g_dmar_table == NULL ) {
+ printk(TBOOT_ERR"No DMAR table saved, abort restore step.\n");
+ return false;
+ }
+
+ /* restore DMAR if needed */
+ memcpy(g_dmar_table->signature, DMAR_SIG, sizeof(g_dmar_table->signature));
+
+ /* need to hide DMAR table while resume from S3 */
+ g_hide_dmar = true;
+ printk(TBOOT_DETA"DMAR table @ %p restored.\n", hdr);
+ return true;
+}
+
+bool remove_vtd_dmar_table(void)
+{
+ struct acpi_table_header *hdr;
+
+ /* check whether it is needed */
+ if ( !g_hide_dmar ) {
+ printk(TBOOT_DETA"No need to hide DMAR table.\n");
+ return true;
+ }
+
+ /* find DMAR table */
+ hdr = (struct acpi_table_header *)get_vtd_dmar_table();
+ if ( hdr == NULL ) {
+ printk(TBOOT_DETA"No DMAR table, skip remove step.\n");
+ return true;
+ }
+
+ /* remove DMAR table */
+ hdr->signature[0] = '\0';
+ printk(TBOOT_DETA"DMAR table @ %p removed.\n", hdr);
+ return true;
+}
+
+static struct acpi_madt *get_apic_table(void)
+{
+ return (struct acpi_madt *)find_table(MADT_SIG);
+}
+
+uint32_t get_madt_apic_base(void)
+{
+ struct acpi_madt *madt = get_apic_table();
+ if ( madt == NULL ) {
+ printk(TBOOT_ERR"no MADT table found\n");
+ return 0;
+ }
+ return (uint32_t)madt->local_apic_address;
+}
+
+struct acpi_table_ioapic *get_acpi_ioapic_table(void)
+{
+ struct acpi_madt *madt = get_apic_table();
+ if ( madt == NULL ) {
+ printk(TBOOT_ERR"no MADT table found\n");
+ return NULL;
+ }
+
+ /* APIC tables begin after MADT */
+ union acpi_madt_entry *entry = (union acpi_madt_entry *)(madt + 1);
+
+ while ( (void *)entry < ((void *)madt + madt->hdr.length) ) {
+ uint8_t length = entry->madt_lapic.length;
+
+ if ( entry->madt_lapic.apic_type == ACPI_MADT_IOAPIC ) {
+ if ( length != sizeof(entry->madt_ioapic) ) {
+ printk(TBOOT_ERR"APIC length error.\n");
+ return NULL;
+ }
+ return (struct acpi_table_ioapic *)entry;
+ }
+ entry = (void *)entry + length;
+ }
+ printk(TBOOT_ERR"no IOAPIC type.\n");
+ return NULL;
+}
+
+struct acpi_mcfg *get_acpi_mcfg_table(void)
+{
+ return (struct acpi_mcfg *)find_table(MCFG_SIG);
+}
+
+static bool write_to_reg(const tboot_acpi_generic_address_t *reg,
+ uint32_t val)
+{
+ if ( reg->address >= 100000000ULL ) {
+ printk(TBOOT_ERR"GAS address >4GB (0x%Lx)\n", reg->address);
+ return false;
+ }
+ uint64_t address = (uint64_t)reg->address;
+
+ if ( reg->space_id == GAS_SYSTEM_IOSPACE ) {
+ switch ( reg->bit_width ) {
+ case 8:
+ outb(address, (uint8_t)val);
+ return true;
+ case 16:
+ outw(address, (uint16_t)val);
+ return true;
+ case 32:
+ outl(address, val);
+ return true;
+ default:
+ printk(TBOOT_ERR"unsupported GAS bit width: %u\n", reg->bit_width);
+ return false;
+ }
+ }
+ else if ( reg->space_id == GAS_SYSTEM_MEMORY ) {
+ switch ( reg->bit_width ) {
+ case 8:
+ writeb(address, (uint8_t)val);
+ return true;
+ case 16:
+ writew(address, (uint16_t)val);
+ return true;
+ case 32:
+ writel(address, val);
+ return true;
+ default:
+ printk(TBOOT_ERR"unsupported GAS bit width: %u\n", reg->bit_width);
+ return false;
+ }
+ }
+
+ printk(TBOOT_ERR"unsupported GAS addr space ID: %u\n", reg->space_id);
+ return false;
+}
+
+static bool read_from_reg(const tboot_acpi_generic_address_t *reg,
+ uint32_t *val)
+{
+ if ( reg->address >= 100000000ULL ) {
+ printk(TBOOT_ERR"GAS address >4GB (0x%Lx)\n", reg->address);
+ return false;
+ }
+ uint64_t address = (uint64_t)reg->address;
+
+ if ( reg->space_id == GAS_SYSTEM_IOSPACE ) {
+ switch ( reg->bit_width ) {
+ case 8:
+ *val = inb(address);
+ return true;
+ case 16:
+ *val = inw(address);
+ return true;
+ case 32:
+ *val = inl(address);
+ return true; default:
+ printk(TBOOT_ERR"unsupported GAS bit width: %u\n", reg->bit_width);
+ return false;
+ }
+ }
+ else if ( reg->space_id == GAS_SYSTEM_MEMORY ) {
+ switch ( reg->bit_width ) {
+ case 8:
+ *val = readb(address);
+ return true;
+ case 16:
+ *val = readw(address);
+ return true;
+ case 32:
+ *val = readl(address);
+ return true;
+ default:
+ printk(TBOOT_ERR"unsupported GAS bit width: %u\n", reg->bit_width);
+ return false;
+ }
+ }
+
+ printk(TBOOT_ERR"unsupported GAS addr space ID: %u\n", reg->space_id);
+ return false;
+}
+
+static void wait_to_sleep(const tboot_acpi_sleep_info_t *acpi_sinfo)
+{
+#define WAKE_STATUS 0x8000 /* the 15th bit */
+ while ( true ) {
+ uint32_t pm1a_value = 0, pm1b_value = 0;
+
+ if ( acpi_sinfo->pm1a_evt_blk.address ) {
+ if ( read_from_reg(&acpi_sinfo->pm1a_evt_blk, &pm1a_value) &&
+ ( pm1a_value & WAKE_STATUS ) )
+ return;
+ }
+
+ if ( acpi_sinfo->pm1b_evt_blk.address ) {
+ if ( read_from_reg(&acpi_sinfo->pm1b_evt_blk, &pm1b_value) &&
+ ( pm1b_value & WAKE_STATUS ) )
+ return;
+ }
+ }
+}
+
+bool machine_sleep(const tboot_acpi_sleep_info_t *acpi_sinfo)
+{
+ dump_gas("PM1A", &acpi_sinfo->pm1a_cnt_blk);
+ dump_gas("PM1B", &acpi_sinfo->pm1b_cnt_blk);
+
+ wbinvd();
+
+ if ( acpi_sinfo->pm1a_cnt_blk.address ) {
+ if ( !write_to_reg(&acpi_sinfo->pm1a_cnt_blk, acpi_sinfo->pm1a_cnt_val) )
+ return false;;
+ }
+
+ if ( acpi_sinfo->pm1b_cnt_blk.address ) {
+ if ( !write_to_reg(&acpi_sinfo->pm1b_cnt_blk, acpi_sinfo->pm1b_cnt_val) )
+ return false;
+ }
+
+ /* just to wait, the machine may shutdown before here */
+ wait_to_sleep(acpi_sinfo);
+ return true;
+}
+
+void set_s3_resume_vector(const tboot_acpi_sleep_info_t *acpi_sinfo,
+ uint64_t resume_vector)
+{
+ if ( acpi_sinfo->vector_width <= 32 )
+ *(uint32_t *)(unsigned long long)(acpi_sinfo->wakeup_vector) =
+ (uint32_t)resume_vector;
+ else if ( acpi_sinfo->vector_width <= 64 )
+ *(uint64_t *)(unsigned long long)(acpi_sinfo->wakeup_vector) =
+ resume_vector;
+ else
+ printk(TBOOT_WARN"vector_width error.\n");
+
+ acpi_printk(TBOOT_DETA"wakeup_vector_address = %llx\n", acpi_sinfo->wakeup_vector);
+ acpi_printk(TBOOT_DETA"wakeup_vector_value = %llxx\n", resume_vector);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/bits.S b/tboot/bits.S
new file mode 100644
index 0000000..0cf6ea1
--- /dev/null
+++ b/tboot/bits.S
@@ -0,0 +1,166 @@
+/*
+ * bits.S: Assembly support routines and bits.
+ *
+ * Copyright (c) 2017 Assured Information Security.
+ *
+ * Ross Philipson <philipsonr@ainfosec.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#define REF(x) x(%rip)
+
+#define SOFF 16
+
+ENTRY(print_test_chars)
+ pushq %rcx
+ pushq %rdx
+ xorq %rcx, %rcx
+1:
+ cmpb $5, %cl
+ jz 2f
+ movw $0x3f8, %dx
+ addw $5, %dx
+3:
+ inb %dx, %al
+ testb $0x20, %al
+ jz 3b
+ movw $0x3f8, %dx
+ movb $0x41, %al
+ addb %cl, %al
+ outb %al, %dx
+ incb %cl
+ jmp 1b
+2:
+ popq %rdx
+ popq %rcx
+ ret
+
+ENTRY(memcpy)
+ pushq %rbp
+ movq %rsp, %rbp
+ movq %rcx, SOFF(%rbp) # dst
+ movq %rdx, SOFF+8(%rbp) # src
+ movq %r8, SOFF+16(%rbp) # size
+
+ movq %rcx, %rdi
+ movq %rdx, %rsi
+ movq %r8, %rcx
+ shrq $3, %rcx
+ cld
+ rep
+ movsq # mov quad words forward
+ movq %r8, %rcx
+ andq $7, %rcx
+ rep
+ movsb # mov remaining bytes forward
+ popq %rbp
+ ret
+
+ENTRY(read_msr)
+ pushq %rdx
+ /* ECX already has MSR number, go for it */
+ rdmsr
+ movq $0xffffffff, %rcx
+ andq %rcx, %rax
+ shlq $32, %rdx
+ movq $0xffffffff00000000, %rcx
+ andq %rcx, %rdx
+ orq %rdx, %rax
+ popq %rdx
+ ret
+
+ENTRY(write_msr)
+ pushq %rax
+ movq %rdx, %rax
+ shrq $32, %rdx
+ /* ECX already has MSR number */
+ wrmsr
+ popq %rax
+ ret
+
+ENTRY(read_tsc)
+ rdtsc
+ movq $0xffffffff, %rcx
+ andq %rcx, %rax
+ shlq $32, %rdx
+ movq $0xffffffff00000000, %rcx
+ andq %rcx, %rdx
+ orq %rdx, %rax
+ ret
+
+/*
+ * Mutex code ported to 64b from:
+ * $OpenBSD: mutex.S,v 1.6 2009/04/27 21:48:56 kettenis Exp $
+ *
+ * Copyright (c) 2004 Artur Grabowski <art@openbsd.org>
+ * All rights reserved.
+ *
+ * BSD 2-Clause
+ */
+
+ENTRY(mtx_init)
+ pushq %rbp
+ movq %rsp, %rbp
+ movq %rcx, SOFF(%rbp) # home var
+ movq $0, (%rcx)
+ popq %rbp
+ ret
+
+ENTRY(mtx_enter)
+ pushq %rbp
+ movq %rsp, %rbp
+1: movq %rcx, SOFF(%rbp) # home var
+ /*
+ * %rcx contains the mtx as passed from caller
+ */
+ movq $1, %rax
+ xchgq %rax, (%rcx) # test_and_set(mtx->mtx_lock)
+ testq %rax, %rax # if (already held)
+ jnz 2f
+ popq %rbp
+ ret
+2: pause
+ movq (%rcx), %rax
+ testq %rax, %rax
+ jz 1b
+ jmp 2b
+
+ENTRY(mtx_leave)
+ pushq %rbp
+ movq %rsp, %rbp
+ movq %rcx, SOFF(%rbp) # home var
+ movq $0, (%rcx)
+ popq %rbp
+ ret
+
+ENTRY(get_rip)
+ movq (%rsp), %rax
+ ret
diff --git a/tboot/cmdline.c b/tboot/cmdline.c
new file mode 100644
index 0000000..cee60a5
--- /dev/null
+++ b/tboot/cmdline.c
@@ -0,0 +1,606 @@
+/*
+ * cmdline.c: command line parsing fns
+ *
+ * Copyright (c) 2006-2012, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <compiler.h>
+#include <string.h>
+#include <misc.h>
+#include <printk.h>
+#include <cmdline.h>
+#include <eficore.h>
+#include <eficonfig.h>
+#include <tpm.h>
+#include <tb_error.h>
+#include <tboot.h>
+#include <mle.h>
+#include <txt/mtrrs.h>
+#include <txt/config_regs.h>
+
+/*
+ * copy of original command line
+ * part of tboot measurement (hence in .text section)
+ */
+__text char g_cmdline[CMDLINE_SIZE] = { 0 };
+
+/* Used for kernel command line parameter setup */
+typedef struct {
+ const char *name; /* set to NULL for last item in list */
+ const char *def_val;
+} cmdline_option_t;
+
+#define MAX_VALUE_LEN 64
+
+/*
+ * the option names and default values must be separate from the actual
+ * params entered
+ * this allows the names and default values to be part of the MLE measurement
+ * param_values[] need to be in .bss section so that will get cleared on launch
+ */
+
+/* global option array for command line */
+static const cmdline_option_t g_tboot_cmdline_options[] = {
+ { "loglvl", "all" }, /* all|err,warn,info|none */
+ { "logging", "serial,vga,efi" }, /* vga,serial,memory,efi|none */
+ { "serial", "115200,8n1,0x3f8" },
+ /* serial=<baud>[/<clock_hz>][,<DPS>[,<io-base>[,<irq>[,<serial-bdf>[,<bridge-bdf>]]]]] */
+ { "vga_delay", "0" }, /* # secs */
+ { "ap_wake_mwait", "false" }, /* true|false */
+ { "pcr_map", "legacy" }, /* legacy|da */
+ { "min_ram", "0" }, /* size in bytes | 0 for no min */
+ { "call_racm", "false" }, /* true|false|check */
+ { "measure_nv", "false" }, /* true|false */
+ { "extpol", "sha1" }, /* agile|embedded|sha1|sha256|sm3|... */
+ { NULL, NULL }
+};
+static char g_tboot_param_values[ARRAY_SIZE(g_tboot_cmdline_options)][MAX_VALUE_LEN];
+
+static const cmdline_option_t g_linux_cmdline_options[] = {
+ { "vga", "" },
+ { "mem", "" },
+ { NULL, NULL }
+};
+static char g_linux_param_values[ARRAY_SIZE(g_linux_cmdline_options)][MAX_VALUE_LEN];
+
+typedef struct {
+ const char *log_name;
+ uint8_t log_val;
+} tb_loglvl_map_t;
+
+/* map */
+static const tb_loglvl_map_t g_loglvl_map[] = {
+ { "none", TBOOT_LOG_LEVEL_NONE },
+ { "err", TBOOT_LOG_LEVEL_ERR },
+ { "warn", TBOOT_LOG_LEVEL_WARN },
+ { "info", TBOOT_LOG_LEVEL_INFO },
+ { "detail",TBOOT_LOG_LEVEL_DETA },
+ { "all", TBOOT_LOG_LEVEL_ALL },
+};
+
+static const char* get_option_val(const cmdline_option_t *options, char vals[][MAX_VALUE_LEN], const char *opt_name)
+{
+ for ( int i = 0; options[i].name != NULL; i++ ) {
+ if ( strcmp(options[i].name, opt_name) == 0 )
+ return vals[i];
+ }
+ printk(TBOOT_ERR"requested unknown option: %s\n", opt_name);
+ return NULL;
+}
+
+static void cmdline_parse(const char *cmdline, const cmdline_option_t *options,
+ char vals[][MAX_VALUE_LEN])
+{
+ const char *p = cmdline;
+ int i;
+
+ /* copy default values to vals[] */
+ for ( i = 0; options[i].name != NULL; i++ ) {
+ strncpy(vals[i], options[i].def_val, MAX_VALUE_LEN-1);
+ vals[i][MAX_VALUE_LEN-1] = '\0';
+ }
+
+ if ( p == NULL )
+ return;
+
+ /* parse options */
+ while ( true )
+ {
+ /* skip whitespace */
+ while ( isspace(*p) )
+ p++;
+ if ( *p == '\0' )
+ break;
+
+ /* find end of current option */
+ const char *opt_start = p;
+ const char *opt_end = strchr(opt_start, ' ');
+ if ( opt_end == NULL )
+ opt_end = opt_start + strlen(opt_start);
+ p = opt_end;
+
+ /* find value part; if no value found, use default and continue */
+ const char *val_start = strchr(opt_start, '=');
+ if ( val_start == NULL || val_start > opt_end )
+ continue;
+ val_start++;
+
+ unsigned int opt_name_size = val_start - opt_start - 1;
+ unsigned int copy_size = opt_end - val_start;
+ if ( copy_size > MAX_VALUE_LEN - 1 )
+ copy_size = MAX_VALUE_LEN - 1;
+ if ( opt_name_size == 0 || copy_size == 0 )
+ continue;
+
+ /* value found, so copy it */
+ for ( i = 0; options[i].name != NULL; i++ ) {
+ if ( strncmp(options[i].name, opt_start, opt_name_size ) == 0 ) {
+ strncpy(vals[i], val_start, copy_size);
+ vals[i][copy_size] = '\0'; /* add '\0' to the end of string */
+ break;
+ }
+ }
+ }
+}
+
+void tboot_parse_cmdline(bool defaults)
+{
+ if (!defaults)
+ cmdline_parse(g_cmdline, g_tboot_cmdline_options, g_tboot_param_values);
+ else
+ cmdline_parse(NULL, g_tboot_cmdline_options, g_tboot_param_values);
+}
+
+void linux_parse_cmdline(const char *cmdline)
+{
+ cmdline_parse(cmdline, g_linux_cmdline_options, g_linux_param_values);
+}
+
+uint8_t get_loglvl_prefix(char **pbuf, int *len)
+{
+ uint8_t log_level = TBOOT_LOG_LEVEL_ALL;
+
+ if ( *len > 2 && **pbuf == '<' && *(*pbuf+2) == '>'
+ && isdigit(*(*pbuf+1)) ) {
+ unsigned int i = *(*pbuf+1) - '0';
+ if ( i < ARRAY_SIZE(g_loglvl_map) )
+ log_level = g_loglvl_map[i].log_val;
+ *pbuf += 3;
+ *len = *len - 3;
+ }
+
+ return log_level;
+}
+
+void get_tboot_loglvl(void)
+{
+ const char *loglvl = get_option_val(g_tboot_cmdline_options,
+ g_tboot_param_values, "loglvl");
+ if ( loglvl == NULL )
+ return;
+
+ /* determine whether the target is set explicitly */
+ while ( isspace(*loglvl) )
+ loglvl++;
+
+ g_log_level = TBOOT_LOG_LEVEL_NONE;
+
+ while ( *loglvl != '\0' ) {
+ unsigned int i;
+
+ for ( i = 0; i < ARRAY_SIZE(g_loglvl_map); i++ ) {
+ if ( strncmp(loglvl, g_loglvl_map[i].log_name,
+ strlen(g_loglvl_map[i].log_name)) == 0 ) {
+ loglvl += strlen(g_loglvl_map[i].log_name);
+
+ if ( g_loglvl_map[i].log_val == TBOOT_LOG_LEVEL_NONE ) {
+ g_log_level = TBOOT_LOG_LEVEL_NONE;
+ return;
+ }
+ else {
+ g_log_level |= g_loglvl_map[i].log_val;
+ break;
+ }
+ }
+ }
+
+ if ( i == ARRAY_SIZE(g_loglvl_map) )
+ break; /* unrecognized, end loop */
+
+ /* skip ',' */
+ if ( *loglvl == ',' )
+ loglvl++;
+ else
+ break; /* unrecognized, end loop */
+ }
+}
+
+void get_tboot_log_targets(void)
+{
+ const char *targets = get_option_val(g_tboot_cmdline_options,
+ g_tboot_param_values, "logging");
+
+ /* nothing set, leave defaults */
+ if ( targets == NULL || *targets == '\0' )
+ return;
+
+ /* determine if no targets set explicitly */
+ if ( strcmp(targets, "none") == 0 ) {
+ g_log_targets = TBOOT_LOG_TARGET_NONE; /* print nothing */
+ return;
+ }
+
+ /* else init to nothing and parse the possible targets */
+ g_log_targets = TBOOT_LOG_TARGET_NONE;
+
+ while ( *targets != '\0' ) {
+ if ( strncmp(targets, "memory", 6) == 0 ) {
+ g_log_targets |= TBOOT_LOG_TARGET_MEMORY;
+ targets += 6;
+ }
+ else if ( strncmp(targets, "serial", 6) == 0 ) {
+ g_log_targets |= TBOOT_LOG_TARGET_SERIAL;
+ targets += 6;
+ }
+ else if ( strncmp(targets, "vga", 3) == 0 && g_post_ebs ) {
+ g_log_targets |= TBOOT_LOG_TARGET_VGA;
+ targets += 3;
+ }
+ else if ( strncmp(targets, "efi", 3) == 0 && !g_post_ebs ) {
+ g_log_targets |= TBOOT_LOG_TARGET_EFI;
+ targets += 3;
+ }
+ else
+ break; /* unrecognized, end loop */
+
+ if ( *targets == ',' )
+ targets++;
+ else
+ break; /* unrecognized, end loop */
+ }
+}
+
+static bool parse_pci_bdf(const char **bdf, uint32_t *bus, uint32_t *slot,
+ uint32_t *func)
+{
+ *bus = strtoul(*bdf, (char **)bdf, 16);
+ if ( **bdf != ':' )
+ return false;
+ (*bdf)++;
+ *slot = strtoul(*bdf, (char **)bdf, 16);
+ if ( **bdf != '.' )
+ return false;
+ (*bdf)++;
+ *func = strtoul(*bdf, (char **)bdf, 16);
+
+ return true;
+}
+
+bool g_psbdf_enabled = false;
+static bool parse_com_psbdf(const char **bdf)
+{
+ g_psbdf_enabled = parse_pci_bdf(bdf,
+ &g_com_port.comc_psbdf.bus,
+ &g_com_port.comc_psbdf.slot,
+ &g_com_port.comc_psbdf.func);
+
+ return g_psbdf_enabled;
+}
+
+bool g_pbbdf_enabled = false;
+static bool parse_com_pbbdf(const char **bdf)
+{
+ g_pbbdf_enabled = parse_pci_bdf(bdf,
+ &g_com_port.comc_pbbdf.bus,
+ &g_com_port.comc_pbbdf.slot,
+ &g_com_port.comc_pbbdf.func);
+
+ return g_pbbdf_enabled;
+}
+
+static bool parse_com_fmt(const char **fmt)
+{
+ /* fmt: <5|6|7|8><n|o|e|m|s><0|1> */
+ /* default 8n1 */
+ uint8_t data_bits = 8;
+ uint8_t parity = 'n';
+ uint8_t stop_bits = 1;
+
+
+ /* must specify all values */
+ if ( strlen(*fmt) < 3 )
+ return false;
+
+ /* data bits */
+ if ( **fmt >= '5' && **fmt <= '8' )
+ data_bits = **fmt - '0';
+ else
+ return false;
+ (*fmt)++;
+
+ /* parity */
+ if ( **fmt == 'n' || **fmt == 'o' || **fmt == 'e' || **fmt == 'm' ||
+ **fmt == 's' )
+ parity = **fmt;
+ else
+ return false;
+ (*fmt)++;
+
+ /* stop bits */
+ if ( **fmt == '0' || **fmt == '1' )
+ stop_bits = **fmt - '0';
+ else
+ return false;
+ (*fmt)++;
+
+ g_com_port.comc_fmt = GET_LCR_VALUE(data_bits, stop_bits, parity);
+
+ return true;
+}
+
+static bool parse_serial_param(const char *com)
+{
+ /* parse baud */
+ g_com_port.comc_curspeed = strtoul(com, (char **)&com, 10);
+ if ( (g_com_port.comc_curspeed < 1200) ||
+ (g_com_port.comc_curspeed > 115200) )
+ return false;
+
+ /* parse clock hz */
+ if ( *com == '/' ) {
+ ++com;
+ g_com_port.comc_clockhz = strtoul(com, (char **)&com, 0) << 4;
+ if ( g_com_port.comc_clockhz == 0 )
+ return false;
+ }
+
+ /* parse data_bits/parity/stop_bits */
+ if ( *com != ',' )
+ goto exit;
+ ++com;
+ while ( isspace(*com) )
+ com++;
+ if ( !parse_com_fmt(&com) )
+ return false;
+
+ /* parse IO base */
+ if ( *com != ',' )
+ goto exit;
+ ++com;
+ g_com_port.comc_port = strtoul(com, (char **)&com, 0);
+ if ( g_com_port.comc_port == 0 )
+ return false;
+
+ /* parse irq */
+ if ( *com != ',' )
+ goto exit;
+ ++com;
+ g_com_port.comc_irq = strtoul(com, (char **)&com, 10);
+ if ( g_com_port.comc_irq == 0 )
+ return false;
+
+ /* parse PCI serial controller bdf */
+ if ( *com != ',' )
+ goto exit;
+ ++com;
+ if ( !parse_com_psbdf(&com) )
+ return false;
+
+ /* parse PCI bridge bdf */
+ if ( *com != ',' )
+ goto exit;
+ ++com;
+ if ( !parse_com_pbbdf(&com) )
+ return false;
+
+ exit:
+ return true;
+}
+
+bool get_tboot_serial(void)
+{
+ const char *serial = get_option_val(g_tboot_cmdline_options,
+ g_tboot_param_values, "serial");
+ if ( serial == NULL || *serial == '\0' )
+ return false;
+
+ return parse_serial_param(serial);
+}
+
+void get_tboot_vga_delay(void)
+{
+ const char *vga_delay = get_option_val(g_tboot_cmdline_options,
+ g_tboot_param_values, "vga_delay");
+ if ( vga_delay == NULL )
+ return;
+
+ g_vga_delay = strtoul(vga_delay, NULL, 0);
+}
+
+bool get_tboot_prefer_da(void)
+{
+ const char *value = get_option_val(g_tboot_cmdline_options,
+ g_tboot_param_values, "pcr_map");
+ if ( value != NULL && strcmp(value, "da") == 0 )
+ return true;
+
+ return false;
+}
+
+uint32_t g_min_ram;
+void get_tboot_min_ram(void)
+{
+ const char *min_ram = get_option_val(g_tboot_cmdline_options,
+ g_tboot_param_values, "min_ram");
+ if ( min_ram == NULL )
+ return;
+
+ g_min_ram = strtoul(min_ram, NULL, 0);
+}
+
+bool get_tboot_mwait(void)
+{
+ const char *mwait = get_option_val(g_tboot_cmdline_options,
+ g_tboot_param_values, "ap_wake_mwait");
+ if ( mwait == NULL || strcmp(mwait, "false") == 0 )
+ return false;
+ return true;
+}
+
+bool get_tboot_call_racm(void)
+{
+ const char *call_racm = get_option_val(g_tboot_cmdline_options,
+ g_tboot_param_values, "call_racm");
+ if ( call_racm == NULL || strcmp(call_racm, "true") != 0 )
+ return false;
+ return true;
+}
+
+bool get_tboot_call_racm_check(void)
+{
+ const char *call_racm = get_option_val(g_tboot_cmdline_options,
+ g_tboot_param_values, "call_racm");
+ if ( call_racm == NULL || strcmp(call_racm, "check") != 0 )
+ return false;
+ return true;
+}
+
+bool get_tboot_measure_nv(void)
+{
+ const char *measure_nv = get_option_val(g_tboot_cmdline_options,
+ g_tboot_param_values, "measure_nv");
+ if ( measure_nv == NULL || strcmp(measure_nv, "true") != 0 )
+ return false;
+ return true;
+}
+
+
+void get_tboot_extpol(void)
+{
+ const char *extpol = get_option_val(g_tboot_cmdline_options, g_tboot_param_values, "extpol");
+
+ if ( extpol == NULL ) {
+ g_tpm->extpol = TB_EXTPOL_FIXED;
+ g_tpm->cur_alg = TB_HALG_SHA256;
+ return;
+ }
+
+ if ( strcmp(extpol, "agile") == 0 ) {
+ g_tpm->extpol = TB_EXTPOL_AGILE;
+ g_tpm->cur_alg = TB_HALG_SHA256;
+ } else if ( strcmp(extpol, "embedded") == 0 ) {
+ g_tpm->extpol = TB_EXTPOL_EMBEDDED;
+ g_tpm->cur_alg = TB_HALG_SHA256;
+ } else if ( strcmp(extpol, "sha256") == 0 ) {
+ g_tpm->extpol = TB_EXTPOL_FIXED;
+ g_tpm->cur_alg = TB_HALG_SHA256;
+ } else if ( strcmp(extpol, "sha1") == 0 ) {
+ g_tpm->extpol = TB_EXTPOL_FIXED;
+ g_tpm->cur_alg = TB_HALG_SHA1;
+ } else if ( strcmp(extpol, "sm3") == 0 ) {
+ g_tpm->extpol = TB_EXTPOL_FIXED;
+ g_tpm->cur_alg = TB_HALG_SM3;
+ }
+}
+
+/*
+ * linux kernel command line parsing
+ */
+
+bool get_linux_vga(int *vid_mode)
+{
+ const char *vga = get_option_val(g_linux_cmdline_options,
+ g_linux_param_values, "vga");
+ if ( vga == NULL || vid_mode == NULL )
+ return false;
+
+ if ( strcmp(vga, "normal") == 0 )
+ *vid_mode = 0xFFFF;
+ else if ( strcmp(vga, "ext") == 0 )
+ *vid_mode = 0xFFFE;
+ else if ( strcmp(vga, "ask") == 0 )
+ *vid_mode = 0xFFFD;
+ else
+ *vid_mode = strtoul(vga, NULL, 0);
+
+ return true;
+}
+
+bool get_linux_mem(uint64_t *max_mem)
+{
+ char *last = NULL;
+ const char *mem = get_option_val(g_linux_cmdline_options,
+ g_linux_param_values, "mem");
+ if ( mem == NULL || max_mem == NULL )
+ return false;
+
+ *max_mem = strtoul(mem, &last, 0);
+ if ( *max_mem == 0 )
+ return false;
+
+ if ( last == NULL )
+ return true;
+
+ switch ( *last ) {
+ case 'G':
+ case 'g':
+ *max_mem = *max_mem << 30;
+ return true;
+ case 'M':
+ case 'm':
+ *max_mem = *max_mem << 20;
+ return true;
+ case 'K':
+ case 'k':
+ *max_mem = *max_mem << 10;
+ return true;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/com.c b/tboot/com.c
new file mode 100644
index 0000000..c1851a6
--- /dev/null
+++ b/tboot/com.c
@@ -0,0 +1,134 @@
+/*-
+ * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Portions copyright (c) 2010, Intel Corporation
+ */
+
+/*
+ * sys/boot/i386/libi386/comconsole.c
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <misc.h>
+#include <mutex.h>
+#include <io.h>
+#include <pci_cfgreg.h>
+#include <com.h>
+
+#define COMC_TXWAIT 0x40000 /* transmit timeout */
+#define COMC_BPS(x) (115200 / (x)) /* speed to DLAB divisor */
+#define COMC_DIV2BPS(x) (115200 / (x)) /* DLAB divisor to speed */
+
+#define OUTB(add, val) outb(g_com_port.comc_port + (add), (val))
+#define INB(add) inb(g_com_port.comc_port + (add))
+
+serial_port_t g_com_port = {115200, 0, 0x3, COM1_ADDR}; /* com1,115200,8n1 */
+
+bool g_psbdf_enabled;
+bool g_pbbdf_enabled;
+struct mutex pcicfg_mtx;
+
+static void comc_putchar(int c)
+{
+ int wait;
+
+ for ( wait = COMC_TXWAIT; wait > 0; wait-- )
+ if ( INB(com_lsr) & LSR_TXRDY ) {
+ OUTB(com_data, (u_char)c);
+ break;
+ }
+}
+
+static void comc_setup(int speed)
+{
+ OUTB(com_cfcr, CFCR_DLAB | g_com_port.comc_fmt);
+ OUTB(com_dlbl, COMC_BPS(speed) & 0xff);
+ OUTB(com_dlbh, COMC_BPS(speed) >> 8);
+ OUTB(com_cfcr, g_com_port.comc_fmt);
+ OUTB(com_mcr, MCR_RTS | MCR_DTR);
+
+ for ( int wait = COMC_TXWAIT; wait > 0; wait-- ) {
+ INB(com_data);
+ if ( !(INB(com_lsr) & LSR_RXRDY) )
+ break;
+ }
+}
+
+static void comc_pci_setup(void)
+{
+ if ( g_psbdf_enabled ) {
+ if ( g_pbbdf_enabled ) {
+ pcireg_cfgwrite(g_com_port.comc_pbbdf.bus,
+ g_com_port.comc_pbbdf.slot,
+ g_com_port.comc_pbbdf.func,
+ PCIR_IOBASEL_1,
+ (g_com_port.comc_port & 0xF000)
+ | ((g_com_port.comc_port & 0xF000) >> 8),
+ 2);
+ }
+ pcireg_cfgwrite(g_com_port.comc_psbdf.bus,
+ g_com_port.comc_psbdf.slot,
+ g_com_port.comc_psbdf.func,
+ PCIR_BARS,
+ g_com_port.comc_port | 0x1,
+ 4);
+ pcireg_cfgwrite(g_com_port.comc_psbdf.bus,
+ g_com_port.comc_psbdf.slot,
+ g_com_port.comc_psbdf.func,
+ PCIR_COMMAND,
+ 0x1,
+ 2);
+
+ mtx_init(&pcicfg_mtx);
+ }
+}
+
+void comc_init(void)
+{
+ comc_pci_setup();
+ comc_setup(g_com_port.comc_curspeed);
+}
+
+void comc_puts(const char *s, unsigned int cnt)
+{
+ while ( *s && cnt-- ) {
+ if ( *s == '\n' )
+ comc_putchar('\r');
+ comc_putchar(*s++);
+ }
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/efiboot.c b/tboot/efiboot.c
new file mode 100644
index 0000000..37ff734
--- /dev/null
+++ b/tboot/efiboot.c
@@ -0,0 +1,613 @@
+/*
+ * efiboot.c: EFI boot entry, early relocation and load code.
+ *
+ * Copyright (c) 2017 Assured Information Security.
+ *
+ * Ross Philipson <philipsonr@ainfosec.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <string.h>
+#include <stdbool.h>
+#include <misc.h>
+#include <page.h>
+#include <printk.h>
+#include <eficore.h>
+#include <eficonfig.h>
+#include <uuid.h>
+#include <hash.h>
+#include <mle.h>
+#include <txt/acmod.h>
+#include <tb_error.h>
+#include <tboot.h>
+
+static EFI_HANDLE g_image_handle;
+static EFI_HANDLE g_device_handle;
+static EFI_DEVICE_PATH *g_device_path;
+static void *g_init_base; /* before reloc */
+ void *g_image_base; /* after reloc */
+ void *g_rtmem_base; /* base of TBOOT runtime memory */
+ uint64_t g_image_size;
+ void *g_text_base;
+ uint64_t g_text_size;
+ void *g_bss_base;
+ uint64_t g_bss_size;
+
+static efi_file_t *g_configs;
+static EFI_FILE_IO_INTERFACE *g_file_system = NULL;
+
+/* Store raw config files in MLE so they can be measured */
+static __text uint8_t g_tboot_config_file[EFI_MAX_CONFIG_FILE];
+static __text uint8_t g_xen_config_file[EFI_MAX_CONFIG_FILE];
+
+#ifdef EFI_DEBUG
+static void efi_debug_pause(void)
+{
+ EFI_STATUS status;
+ EFI_INPUT_KEY key;
+
+ ST->ConIn->Reset(ST->ConIn, FALSE);
+ while ((status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key)) == EFI_NOT_READY);
+}
+
+static void efi_debug_print_g(void)
+{
+ printk("EFI global:\n");
+ printk(" g_image_handle = %p\n", g_image_handle);
+ printk(" g_device_handle = %p\n", g_device_handle);
+ printk(" g_device_path = %p\n", g_device_path);
+ printk(" g_init_base = %p\n", g_init_base);
+ printk(" g_image_base = %p\n", g_image_base);
+ printk(" g_rtmem_base = %p\n", g_rtmem_base);
+ printk(" g_image_size = %x\n", (uint32_t)g_image_size);
+
+ efi_debug_pause();
+}
+
+static void efi_begin_launch(efi_xen_tboot_data_t *xtd);
+
+static void efi_debug_print_v(efi_tboot_xen_var_t *v)
+{
+ printk("EFI shared variable:\n");
+ printk(" revision = %llx\n", v->revision);
+ printk(" xen_config = %p\n", v->xen_config);
+ printk(" xen_config_size = %llx\n", v->xen_config_size);
+ printk(" begin_launch_cb = %llx\n", v->begin_launch_cb);
+ printk(" begin_launch = %p\n", efi_begin_launch);
+
+ efi_debug_pause();
+}
+
+static void efi_debug_print_w(const char *pfx, const wchar_t *wstr)
+{
+ char *p = wtoa_alloc(wstr);
+ printk("%s %s\n", pfx, p);
+ BS->FreePool(p);
+}
+
+#define efi_debug_print_s(p, s) printk("%s %s\n", p, s)
+
+#else
+#define efi_debug_pause()
+#define efi_debug_print_g()
+#define efi_debug_print_v(s)
+#define efi_debug_print_w(p, w)
+#define efi_debug_print_s(p, s)
+#endif
+
+static EFI_STATUS efi_start_next_image(const wchar_t *path)
+{
+ EFI_STATUS status = EFI_SUCCESS;
+ EFI_DEVICE_PATH *dev_path = NULL;
+ EFI_HANDLE image_handle = NULL;
+ EFI_LOADED_IMAGE *loaded_image;
+
+ dev_path = efi_get_device_path(path, g_device_handle);
+ if (dev_path == NULL) {
+ char *p = wtoa_alloc(path);
+ printk("Failed to get device path for file %s\n", p);
+ BS->FreePool(p);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ status = BS->LoadImage(FALSE,
+ g_image_handle,
+ dev_path,
+ NULL,
+ 0,
+ &image_handle);
+ if (EFI_ERROR(status)) {
+ printk("Failed to load image - status: %d\n", status);
+ goto out;
+ }
+
+ status = BS->HandleProtocol(image_handle,
+ &LoadedImageProtocol,
+ (VOID*)&loaded_image);
+ if (EFI_ERROR(status)) {
+ printk("Failed to get loaded image info - status: %d\n", status);
+ goto out;
+ }
+ efi_store_xen_info(loaded_image->ImageBase, loaded_image->ImageSize);
+
+ status = BS->StartImage(image_handle, NULL, NULL);
+ if (EFI_ERROR(status))
+ printk("Failed to start image - status: %d\n", status);
+
+out:
+ BS->FreePool(dev_path);
+ return status;
+}
+
+void efi_launch_kernel(void)
+{
+ EFI_STATUS status;
+ wchar_t *file_path;
+
+ file_path = atow_alloc(efi_cfg_get_value(EFI_CONFIG_TBOOT_PARSED,
+ SECTION_TBOOT, ITEM_XENPATH));
+ if (!file_path) {
+ printk("Failed to allocate buffer for Xen file\n");
+ status = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ status = efi_start_next_image(file_path);
+ /* If we are still here then someting failed anyway */
+out:
+ ST->RuntimeServices->ResetSystem(EfiResetShutdown, EFI_OUT_OF_RESOURCES, 0, NULL);
+}
+
+static void efi_begin_launch(efi_xen_tboot_data_t *xtd)
+{
+ g_post_ebs = true;
+ begin_launch(xtd);
+}
+
+static EFI_STATUS efi_setup_tboot_xen_var(void)
+{
+ EFI_STATUS status = EFI_SUCCESS;
+ efi_tboot_xen_var_t var;
+
+ memset(&var, 0, sizeof(efi_tboot_xen_var_t));
+ var.revision = EFI_TBOOT_XEN_REV;
+ var.begin_launch_cb = (uint64_t)efi_begin_launch;
+ var.xen_config = g_configs[EFI_CONFIG_XEN].u.buffer;
+ var.xen_config_size = g_configs[EFI_CONFIG_XEN].size;
+
+ status = RT->SetVariable(EFI_TBOOT_XEN_NAME,
+ &TbootXenGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(efi_tboot_xen_var_t),
+ &var);
+ if (EFI_ERROR(status))
+ printk("Failed to set shared RT variable - status: %d\n", status);
+
+ efi_debug_print_v(&var);
+
+ return status;
+}
+
+static bool efi_is_platform_sinit_module(wchar_t *file_path,
+ efi_file_t *file_out)
+{
+ EFI_STATUS status;
+
+ /* Read the TBOOT config into RT memory and store */
+ status = efi_read_file(g_file_system,
+ file_path,
+ EfiRuntimeServicesData,
+ &file_out->size,
+ &file_out->u.addr);
+ if (EFI_ERROR(status)) {
+ printk("Failed to read ACM file - status: %d\n", status);
+ return false;
+ }
+
+ if (is_sinit_acmod(file_out->u.buffer, file_out->size, true) &&
+ does_acmod_match_platform((acm_hdr_t*)file_out->u.buffer)) {
+ printk(TBOOT_DETA"SINIT matches platform\n");
+ return true;
+ }
+
+ BS->FreePages(file_out->u.addr, PFN_UP(file_out->size));
+ file_out->u.addr = 0;
+ file_out->size = 0;
+
+ return false;
+}
+
+static EFI_STATUS efi_load_core_files(void)
+{
+ EFI_STATUS status = EFI_SUCCESS;
+ int key;
+ char keystr[16];
+ const char *value;
+ wchar_t *file_path;
+ uint32_t size;
+ efi_file_t sinit_file = {0, 0};
+
+ /* TODO we don't have any RACMs right now so kick the can down the road... */
+ /* TODO we don't use an LCP so kick the can down the road... */
+
+ for (key = 0; ; key++) {
+ snprintf(keystr, 16, "%d", key);
+ value = efi_cfg_get_value(EFI_CONFIG_TBOOT_PARSED,
+ SECTION_ACM, keystr);
+ if (!value)
+ break;
+
+ file_path = atow_cat(g_tboot_dir, value);
+ if (!file_path) {
+ printk("Failed to allocate buffer for ACM file name\n");
+ status = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ efi_debug_print_w("ACM:", file_path);
+
+ /* Found one */
+ if (efi_is_platform_sinit_module(file_path, &sinit_file)) {
+ BS->FreePool(file_path);
+ break;
+ }
+
+ BS->FreePool(file_path);
+
+ /* Errors not fatal but the config likely includes missing files */
+ }
+
+ if (!sinit_file.u.buffer) {
+ printk(TBOOT_ERR"no SINIT AC module found\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* Set the files we found */
+ efi_store_files(&sinit_file, NULL, NULL);
+out:
+ return status;
+}
+
+static void efi_form_config_path(wchar_t *path)
+{
+ wchar_t *ptr = path + wcslen(path);
+
+ efi_debug_print_w("IMAGE PATH:", path);
+
+ /* Form the config file path */
+ while (ptr >= path) {
+ if (*ptr == L'.') {
+ memcpy((ptr + 1), L"cfg\0", 8);
+ break;
+ }
+ ptr--;
+ }
+
+ efi_debug_print_w("CONFIG PATH:", path);
+}
+
+static EFI_STATUS efi_load_configs(void)
+{
+ EFI_STATUS status;
+ wchar_t *file_path = NULL;
+ EFI_PHYSICAL_ADDRESS addr = TBOOT_MAX_IMAGE_MEM;
+ void *buffer = NULL;
+ uint64_t size;
+
+ /* Get file path for TBOOT image and config */
+ status = BS->AllocatePool(EfiLoaderData,
+ (EFI_MAX_PATH + 4)*sizeof(wchar_t),
+ (void**)&file_path);
+ if (EFI_ERROR(status)) {
+ printk("Failed to alloc image path buffer - status: %d\n", status);
+ return status;
+ }
+
+ status = efi_device_path_to_text(g_device_path,
+ file_path,
+ EFI_MAX_PATH);
+ if (EFI_ERROR(status)) {
+ printk("Failed to get TBOOT config path - status: %d\n", status);
+ goto err;
+ }
+
+ /* Save a copy of the TBOOT dir for later */
+ if (!efi_cfg_copy_tboot_path(file_path)) {
+ status = EFI_INVALID_PARAMETER;
+ printk("Failed to save TBOOT path - status: %d\n", status);
+ goto err;
+ }
+
+ efi_form_config_path(file_path);
+
+ /* Read the TBOOT config into RT memory and store */
+ status = efi_read_file(g_file_system,
+ file_path,
+ EfiRuntimeServicesData,
+ &size,
+ &addr);
+ if (EFI_ERROR(status)) {
+ printk("Failed to read TBOOT config file - status: %d\n", status);
+ goto err;
+ }
+
+ if (size > EFI_MAX_CONFIG_FILE) {
+ status = EFI_INVALID_PARAMETER;
+ printk("TBOOT config file too big - size: %d\n", size);
+ goto err;
+ }
+
+ /* Make a copy of the raw TBOOT config in the MLE */
+ memcpy(g_tboot_config_file, (void*)addr, size);
+ g_configs[EFI_CONFIG_TBOOT].u.buffer = g_tboot_config_file;
+ g_configs[EFI_CONFIG_TBOOT].size = size;
+
+ /* Parse original */
+ g_configs[EFI_CONFIG_TBOOT_PARSED].u.addr = addr;
+ g_configs[EFI_CONFIG_TBOOT_PARSED].size = size;
+ efi_cfg_pre_parse(&g_configs[EFI_CONFIG_TBOOT_PARSED]);
+ BS->FreePool(file_path);
+
+ /* Get file path for Xen image and config */
+ file_path = atow_alloc(efi_cfg_get_value(EFI_CONFIG_TBOOT_PARSED,
+ SECTION_TBOOT, ITEM_XENPATH));
+ if (!file_path) {
+ printk("Failed to allocate buffer for Xen config file\n");
+ status = EFI_OUT_OF_RESOURCES;
+ goto err;
+ }
+
+ efi_form_config_path(file_path);
+
+ /* Read the Xen config (non-modified) into RT memory and store */
+ status = efi_read_file(g_file_system,
+ file_path,
+ EfiRuntimeServicesData,
+ &size,
+ &addr);
+ if (EFI_ERROR(status)) {
+ printk("Failed to read Xen config file - status: %d\n", status);
+ goto err;
+ }
+
+ if (size > EFI_MAX_CONFIG_FILE) {
+ status = EFI_INVALID_PARAMETER;
+ printk("Xen config file too big - size: %d\n", size);
+ goto err;
+ }
+
+ /* Make a copy of the raw TBOOT config in the MLE */
+ memcpy(g_xen_config_file, (void*)addr, size);
+ g_configs[EFI_CONFIG_XEN].u.buffer = g_xen_config_file;
+ g_configs[EFI_CONFIG_XEN].size = size;
+
+ /* Parse original */
+ g_configs[EFI_CONFIG_XEN_PARSED].u.addr = addr;
+ g_configs[EFI_CONFIG_XEN_PARSED].size = size;
+ efi_cfg_pre_parse(&g_configs[EFI_CONFIG_XEN_PARSED]);
+ BS->FreePool(file_path);
+
+ /* Locate and split off the kernel cmdline */
+ if (!efi_split_kernel_line()) {
+ printk("Failed to parse and find kernel entry in Xen config\n");
+ status = EFI_INVALID_PARAMETER;
+ goto err;
+ }
+ efi_debug_print_s("KERNEL CMDLINE:", g_kernel_cmdline);
+
+ return EFI_SUCCESS;
+
+err:
+ if (g_configs[EFI_CONFIG_XEN].u.buffer)
+ BS->FreePages(g_configs[EFI_CONFIG_XEN].u.addr,
+ PFN_UP(g_configs[EFI_CONFIG_XEN].size));
+ if (g_configs[EFI_CONFIG_TBOOT].u.buffer)
+ BS->FreePages(g_configs[EFI_CONFIG_TBOOT].u.addr,
+ PFN_UP(g_configs[EFI_CONFIG_TBOOT].size));
+
+ if (file_path)
+ BS->FreePool(file_path);
+
+ return status;
+}
+
+EFI_STATUS efi_start(EFI_HANDLE ImageHandle,
+ EFI_SYSTEM_TABLE *SystemTable)
+{
+ EFI_STATUS status;
+
+ printk("TBOOT START Entry Point: %p\n", efi_start);
+ efi_debug_print_g();
+
+ /* Open the file system for the boot partition once up front */
+ status = BS->OpenProtocol(g_device_handle,
+ &FileSystemProtocol,
+ (void**)&g_file_system,
+ g_image_handle,
+ NULL,
+ EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL);
+ if (EFI_ERROR(status)) {
+ printk("Failed to open FileSystemProtocol - status: %d\n", status);
+ goto out;
+ }
+
+ efi_cfg_init();
+ g_configs = efi_get_configs();
+
+ /* Locate the .text section and length */
+ g_text_base = efi_get_pe_section(".text", g_image_base,
+ &g_text_size);
+ if (g_text_base) {
+ printk("Located .text section: %p size: %llx\n",
+ g_text_base, g_text_size);
+ /* Sanity check the location of the .text section in the image */
+ if ((g_text_base - g_image_base) != PAGE_SIZE) {
+ printk("The .text offset must be at 1 page into TBOOT image!\n");
+ goto out;
+ }
+ }
+ else {
+ printk("Failed to locate .text section\n");
+ status = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ /* Locate the .bss section and length */
+ g_bss_base = efi_get_pe_section(".bss", g_image_base,
+ &g_bss_size);
+ if (g_bss_base) {
+ printk("Located .bss section: %p size: %llx\n",
+ g_bss_base, g_bss_size);
+ }
+ else {
+ printk("Failed to locate .text section\n");
+ status = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ /* Load the configuration files and information */
+ status = efi_load_configs();
+ if (EFI_ERROR(status))
+ goto out;
+
+ /* Load the platform SINIT, RACM and LCP */
+ status = efi_load_core_files();
+ if (EFI_ERROR(status))
+ goto out;
+
+ /* Setup RT shared variable */
+ status = efi_setup_tboot_xen_var();
+ if (EFI_ERROR(status))
+ goto out;
+
+ /* Begin initial launch */
+ begin_initial_launch();
+
+ /* Start Xen here */
+ efi_launch_kernel();
+
+ /* SNO */
+ printk("FATAL: could not launch Xen!\n");
+
+out:
+ efi_debug_pause();
+
+ /* Should not reach here unless something failed */
+ ST->RuntimeServices->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS efi_reloc_and_call(void)
+{
+ EFI_STATUS status;
+ uint64_t size;
+ EFI_PHYSICAL_ADDRESS addr = TBOOT_MAX_IMAGE_MEM;
+ uint64_t efi_start_ptr;
+
+ /*
+ * TODO we may have to pick and force an address since right now we are at
+ * the mercy of EFI picking a runtime service code range. If this ends up
+ * outside the PMRs due to the crazy min_ram stuff then pain and misery
+ * will ensue.
+ */
+
+ status = BS->AllocatePages(AllocateMaxAddress,
+ EfiRuntimeServicesCode,
+ PFN_UP(g_image_size) + TBOOT_RTMEM_COUNT,
+ &addr);
+ if (EFI_ERROR(status))
+ return status;
+
+ g_rtmem_base = (void*)addr;
+ g_image_base = (void*)(addr + TBOOT_RTMEM_SIZE);
+ memset(g_rtmem_base, 0, g_image_size + TBOOT_RTMEM_SIZE);
+
+ /* Copy me to new location */
+ memcpy(g_image_base, g_init_base, g_image_size);
+
+ efi_start_ptr = (uint64_t)g_image_base +
+ ((uint64_t)efi_start - (uint64_t)g_init_base);
+
+ /* End of the line */
+ __asm__ __volatile__ (
+ "movq %0, %%rdx\n\t"
+ "movq %1, %%rcx\n\t"
+ "call *%%rax\n\t"
+ :
+ : "g" (ST), "g" (g_image_handle), "a" (efi_start_ptr));
+
+ return EFI_LOAD_ERROR; /* SNO! */
+}
+
+EFI_STATUS efi_main(EFI_HANDLE ImageHandle,
+ EFI_SYSTEM_TABLE *SystemTable)
+{
+ EFI_STATUS status;
+ EFI_LOADED_IMAGE *loaded_image;
+
+ /* Store the system table for future use in other functions */
+ ST = SystemTable;
+ BS = ST->BootServices;
+ RT = ST->RuntimeServices;
+
+ /* So we can use printk via EFI console protocol */
+ printk_init(INIT_EARLY_EFI);
+ printk("TBOOT EFI Entry Point: %p\n", efi_main);
+
+ status = BS->HandleProtocol(ImageHandle,
+ &LoadedImageProtocol,
+ (VOID*)&loaded_image);
+
+ if (!EFI_ERROR(status)) {
+ /* Device we were loaded from, EFI partition */
+ g_device_handle = loaded_image->DeviceHandle;
+ g_device_path = loaded_image->FilePath;
+ g_init_base = loaded_image->ImageBase;
+ g_image_size = loaded_image->ImageSize;
+ g_image_handle = ImageHandle;
+ }
+ else {
+ printk("TBOOT FATAL! Cannot get loaded image information\n");
+ ST->RuntimeServices->ResetSystem(EfiResetShutdown, status, 0, NULL);
+ }
+
+ efi_debug_print_g();
+
+ /* Relocate this image and call, never return */
+ status = efi_reloc_and_call();
+
+ /* Should not be here! */
+ printk("TBOOT FATAL! relocate and call failed - status: %x\n", status);
+ ST->RuntimeServices->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
+
+ return status;
+}
diff --git a/tboot/eficonfig.c b/tboot/eficonfig.c
new file mode 100644
index 0000000..2d6d699
--- /dev/null
+++ b/tboot/eficonfig.c
@@ -0,0 +1,299 @@
+/*
+ * eficonfig.c: EFI related configuration settings and data.
+ *
+ * Copyright (c) 2017 Assured Information Security.
+ *
+ * Ross Philipson <philipsonr@ainfosec.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <stdbool.h>
+#include <types.h>
+#include <ctype.h>
+#include <string.h>
+#include <misc.h>
+#include <eficore.h>
+#include <eficonfig.h>
+#include <printk.h>
+
+/* The main config files read from disk */
+efi_file_t g_efi_configs[EFI_CONFIG_MAX];
+
+/* Root path to TBOOT image home */
+wchar_t g_tboot_dir[EFI_MAX_PATH];
+
+/* Is this pre or post EBS */
+bool g_post_ebs = false;
+
+const char *g_kernel_cmdline = "";
+
+/* Core TXT and TBOOT files stored in EfiRuntimeServicesData */
+efi_file_t g_platform_sinit;
+efi_file_t g_platform_racm;
+efi_file_t g_lcp;
+
+/* The xen image plush the kernl and ramdisk images passed back from Xen */
+efi_file_t g_xen;
+efi_file_t g_kernel;
+efi_file_t g_ramdisk;
+
+/* EFI memory map just before EBS from Xen */
+void *g_memory_map;
+uint64_t g_memory_map_size;
+uint64_t g_memory_desc_size;
+
+/* Xen post launch callback */
+uint64_t g_xen_post_launch_cb;
+
+void efi_cfg_init(void)
+{
+ memset(&g_tboot_dir[0], 0, EFI_MAX_PATH*sizeof(wchar_t));
+ memset(&g_efi_configs[0], 0, EFI_CONFIG_MAX*sizeof(efi_file_t));
+}
+
+efi_file_t *efi_get_configs(void)
+{
+ return &g_efi_configs[0];
+}
+
+void efi_cfg_pre_parse(efi_file_t *config)
+{
+ char *ptr = config->u.buffer, *end = ptr + config->size;
+ bool start = true, comment = false;
+
+ for ( ; ptr < end; ++ptr ) {
+ if ( iscntrl(*ptr) ) {
+ comment = false;
+ start = true;
+ *ptr = 0;
+ }
+ else if ( comment || (start && isspace(*ptr)) ) {
+ *ptr = 0;
+ }
+ else if ( *ptr == '#' || (start && *ptr == ';') ) {
+ comment = true;
+ *ptr = 0;
+ }
+ else
+ start = false;
+ }
+ if ( config->size && end[-1] )
+ printk("No newline at end of config file last line will be ignored.\n");
+}
+
+char *efi_cfg_get_value(int index, const char *section,
+ const char *item)
+{
+ efi_file_t *config;
+ char *ptr, *end;
+ size_t slen = section ? strlen(section) : 0, ilen = strlen(item);
+ bool match = !slen;
+
+ if (index >= EFI_CONFIG_MAX)
+ return NULL;
+
+ config = &g_efi_configs[index];
+ ptr = config->u.buffer;
+ end = ptr + config->size;
+
+ for ( ; ptr < end; ++ptr ) {
+ switch ( *ptr ) {
+ case 0:
+ continue;
+ case '[':
+ if ( !slen )
+ break;
+ if ( match )
+ return NULL;
+ match = strncmp(++ptr, section, slen) == 0 && ptr[slen] == ']';
+ break;
+ default:
+ if ( match && strncmp(ptr, item, ilen) == 0 && ptr[ilen] == '=' ) {
+ ptr += ilen + 1;
+ /* strip off any leading spaces */
+ while ( *ptr && isspace(*ptr) )
+ ptr++;
+ return ptr;
+ }
+ break;
+ }
+ ptr += strlen(ptr);
+ }
+ return NULL;
+}
+
+bool efi_split_kernel_line(void)
+{
+ char *ptr;
+
+ ptr = efi_cfg_get_value(EFI_CONFIG_XEN_PARSED,
+ SECTION_GLOBAL, ITEM_DEFAULT);
+ if (!ptr)
+ return false;
+
+ ptr = efi_cfg_get_value(EFI_CONFIG_XEN_PARSED,
+ ptr, ITEM_KERNEL);
+ if (!ptr)
+ return false;
+
+ for ( ; *ptr && !isspace(*ptr); ptr++);
+
+ if (ptr) {
+ *ptr = 0;
+ g_kernel_cmdline = ptr + 1;
+ }
+ /* Else there is no kernel cmdline - I guess that is possible */
+
+ return true;
+}
+
+bool efi_cfg_copy_tboot_path(const wchar_t *file_path)
+{
+ uint64_t len = wcslen(file_path);
+ wchar_t *ptr = g_tboot_dir + len;
+
+ if (len >= EFI_MAX_PATH)
+ return false;
+
+ memcpy(g_tboot_dir, file_path, len*sizeof(wchar_t));
+
+ while (ptr >= g_tboot_dir) {
+ if (*ptr == L'\\') {
+ *(ptr + 1) = L'\0';
+ return true;
+ }
+ ptr--;
+ }
+
+ return false;
+}
+
+const efi_file_t *efi_get_platform_sinit(void)
+{
+ if (g_platform_sinit.size > 0)
+ return &g_platform_sinit;
+ return NULL;
+}
+
+const efi_file_t *efi_get_platform_racm(void)
+{
+ if (g_platform_racm.size > 0)
+ return &g_platform_racm;
+ return NULL;
+}
+
+const efi_file_t *efi_get_lcp(void)
+{
+ if (g_lcp.size > 0)
+ return &g_lcp;
+ return NULL;
+}
+
+void efi_store_files(const efi_file_t *platform_sinit,
+ const efi_file_t *platform_racm,
+ const efi_file_t *lcp)
+{
+ memset(&g_platform_sinit, 0, sizeof(efi_file_t));
+ memset(&g_platform_racm, 0, sizeof(efi_file_t));
+ memset(&g_lcp, 0, sizeof(efi_file_t));
+
+ if (platform_sinit && platform_sinit->u.buffer)
+ g_platform_sinit = *platform_sinit;
+ if (platform_racm && platform_racm->u.buffer)
+ g_platform_racm = *platform_racm;
+ if (lcp && lcp->u.buffer)
+ g_lcp = *lcp;
+}
+
+const efi_file_t *efi_get_xen(void)
+{
+ if (g_xen.size > 0)
+ return &g_xen;
+ return NULL;
+}
+
+const efi_file_t *efi_get_kernel(void)
+{
+ if (g_kernel.size > 0)
+ return &g_kernel;
+ return NULL;
+}
+
+const efi_file_t *efi_get_ramdisk(void)
+{
+ if (g_ramdisk.size > 0)
+ return &g_ramdisk;
+ return NULL;
+}
+
+const void *efi_get_memory_map(uint64_t *size_out, uint64_t *size_desc_out)
+{
+ *size_out = g_memory_map_size;
+ *size_desc_out = g_memory_desc_size;
+ return g_memory_map;
+}
+
+uint64_t efi_get_xen_post_launch_cb(void)
+{
+ return g_xen_post_launch_cb;
+}
+
+void efi_store_xen_info(void *base, uint64_t size)
+{
+ memset(&g_xen, 0, sizeof(efi_file_t));
+ g_xen.u.buffer = base;
+ g_xen.size = size;
+}
+
+bool efi_store_xen_tboot_data(efi_xen_tboot_data_t *xtd)
+{
+ /* sanity */
+ if ( (xtd->kernel == NULL) || (xtd->kernel_size == 0) ||
+ (xtd->ramdisk == NULL) || (xtd->ramdisk_size == 0) ||
+ (xtd->memory_map == NULL) || (xtd->memory_map_size == 0) ||
+ (xtd->memory_desc_size == 0))
+ return false;
+
+ memset(&g_kernel, 0, sizeof(efi_file_t));
+ memset(&g_ramdisk, 0, sizeof(efi_file_t));
+
+ g_kernel.u.buffer = xtd->kernel;
+ g_kernel.size = xtd->kernel_size;
+ g_ramdisk.u.buffer = xtd->ramdisk;
+ g_ramdisk.size = xtd->ramdisk_size;
+ g_memory_map = xtd->memory_map;
+ g_memory_map_size = xtd->memory_map_size;
+ g_memory_desc_size = xtd->memory_desc_size;
+ g_xen_post_launch_cb = xtd->post_launch_cb;
+
+ return true;
+}
+
diff --git a/tboot/eficore.c b/tboot/eficore.c
new file mode 100644
index 0000000..71cdc09
--- /dev/null
+++ b/tboot/eficore.c
@@ -0,0 +1,534 @@
+/*
+ * eficore.c: EFI core support code.
+ *
+ * Copyright (c) 2017 Assured Information Security.
+ *
+ * Ross Philipson <philipsonr@ainfosec.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <stdbool.h>
+#include <string.h>
+#include <page.h>
+#include <printk.h>
+#include <eficore.h>
+#include <eficonfig.h>
+#include <pe.h>
+#include <tb_error.h>
+#include <tboot.h>
+
+/* Global Table Pointers */
+EFI_SYSTEM_TABLE *ST;
+EFI_BOOT_SERVICES *BS;
+EFI_RUNTIME_SERVICES *RT;
+
+/* Local device paths */
+EFI_DEVICE_PATH EfiRootDevicePath[] = {
+ {END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH,0}}
+};
+
+EFI_DEVICE_PATH EfiEndDevicePath[] = {
+ {END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH, 0}}
+};
+
+EFI_DEVICE_PATH EfiEndInstanceDevicePath[] = {
+ {END_DEVICE_PATH_TYPE, END_INSTANCE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH, 0}}
+};
+
+
+/* EFI IDs */
+EFI_GUID EfiGlobalVariable = EFI_GLOBAL_VARIABLE;
+EFI_GUID NullGuid = { 0,0,0,{0,0,0,0,0,0,0,0} };
+EFI_GUID UnknownDevice = UNKNOWN_DEVICE_GUID;
+
+/* Protocol IDs */
+EFI_GUID DevicePathProtocol = DEVICE_PATH_PROTOCOL;
+EFI_GUID LoadedImageProtocol = LOADED_IMAGE_PROTOCOL;
+EFI_GUID FileSystemProtocol = SIMPLE_FILE_SYSTEM_PROTOCOL;
+
+/* File system information IDs */
+EFI_GUID GenericFileInfo = EFI_FILE_INFO_ID;
+
+/* Configuration Table GUIDs */
+EFI_GUID AcpiTableGuid = ACPI_TABLE_GUID;
+EFI_GUID Acpi20TableGuid = ACPI_20_TABLE_GUID;
+EFI_GUID SMBIOSTableGuid = SMBIOS_TABLE_GUID;
+
+/* TBOOT/Xen */
+EFI_GUID TbootXenGuid = EFI_TBOOT_XEN_GUID;
+
+void atow(wchar_t *dst, const char *src, uint64_t count)
+{
+ uint64_t i;
+
+ for (i = 0; i < count; i++, dst++, src++)
+ *dst = (*src & 0x7f);
+}
+
+bool wtoa(char *dst, const wchar_t *src, uint64_t count)
+{
+ uint64_t i;
+ bool r = true;
+
+ for (i = 0; i < count; i++, dst++, src++) {
+ if (*dst <= 0x7f) {
+ *dst = *src;
+ }
+ else {
+ r = false;
+ *dst = '_';
+ }
+ }
+
+ return r;
+}
+
+uint64_t wcslen(const wchar_t *str)
+{
+ uint64_t len;
+
+ for (len = 0; *str != L'\0'; str++, len++)
+ ;
+
+ return ++len;
+}
+
+wchar_t *atow_alloc(const char *src)
+{
+ EFI_STATUS status = EFI_SUCCESS;
+ wchar_t *dst;
+ uint64_t count, size;
+
+ if (!src)
+ return NULL;
+
+ count = strlen(src);
+ size = (count + 1)*sizeof(wchar_t);
+
+ status = BS->AllocatePool(EfiLoaderData, size, (void**)&dst);
+ if (EFI_ERROR(status))
+ return NULL;
+
+ memset(dst, 0, size);
+
+ atow(dst, src, count);
+ return dst;
+}
+
+char *wtoa_alloc(const wchar_t *src)
+{
+ EFI_STATUS status = EFI_SUCCESS;
+ char *dst;
+ uint64_t count, size;
+
+ if (!src)
+ return NULL;
+
+ count = wcslen(src);
+ size = (count + 1)*sizeof(char);
+
+ status = BS->AllocatePool(EfiLoaderData, size, (void**)&dst);
+ if (EFI_ERROR(status))
+ return NULL;
+
+ memset(dst, 0, size);
+
+ wtoa(dst, src, count);
+ return dst;
+}
+
+wchar_t *atow_cat(const wchar_t *base, const char *tail)
+{
+ EFI_STATUS status = EFI_SUCCESS;
+ wchar_t *dst;
+ uint64_t wcount, scount, size;
+
+ if (!base || !tail)
+ return NULL;
+
+ scount = strlen(tail);
+ wcount = wcslen(base);
+ size = (wcount + scount + 1)*sizeof(wchar_t);
+
+ status = BS->AllocatePool(EfiLoaderData, size, (void**)&dst);
+ if (EFI_ERROR(status))
+ return NULL;
+
+ memset(dst, 0, size);
+ memcpy(dst, g_tboot_dir, wcount*sizeof(wchar_t));
+ atow((dst + wcount - 1), tail, scount);
+
+ return dst;
+}
+
+uint8_t *efi_get_rsdp(void)
+{
+ EFI_CONFIGURATION_TABLE *conf_table = ST->ConfigurationTable;
+ uint8_t *acpi_rsdp = NULL;
+ uint64_t count;
+
+ for (count = 0; count < ST->NumberOfTableEntries; count++, conf_table++) {
+ if (!memcmp(&Acpi20TableGuid, &conf_table->VendorGuid, sizeof(EFI_GUID)) ||
+ !memcmp(&AcpiTableGuid, &conf_table->VendorGuid, sizeof(EFI_GUID))) {
+ acpi_rsdp = conf_table->VendorTable;
+ break;
+ }
+ }
+
+ return acpi_rsdp;
+}
+
+void *efi_get_pe_section(const char *name, void *image_base,
+ uint64_t *size_out)
+{
+#define calc_addr(b, o) (void*)(((uint8_t*)b) + o);
+ IMAGE_DOS_HEADER *dosh;
+ IMAGE_NT_HEADERS *nth;
+ IMAGE_FILE_HEADER *fh;
+ IMAGE_SECTION_HEADER *sh;
+ uint16_t i;
+ void *text = NULL;
+ size_t length = strlen(name);
+
+ dosh = (IMAGE_DOS_HEADER*)image_base;
+ nth = (IMAGE_NT_HEADERS*)calc_addr(dosh, dosh->e_lfanew);
+
+ if (dosh->e_magic != IMAGE_DOS_SIGNATURE) {
+ printk("Invalid DOS header signature: %x\n", dosh->e_magic);
+ return NULL;
+ }
+
+ if (nth->Signature != IMAGE_NT_SIGNATURE) {
+ printk("Invalid NT header signature: %x\n", nth->Signature);
+ return NULL;
+ }
+
+ fh = (IMAGE_FILE_HEADER*)calc_addr(nth, sizeof(uint32_t));
+ sh = (IMAGE_SECTION_HEADER*)calc_addr(fh, sizeof(IMAGE_FILE_HEADER) +
+ fh->SizeOfOptionalHeader);
+
+ for (i = 0; i < fh->NumberOfSections; i++, sh++) {
+ if (!memcmp(name, sh->Name, length)) {
+ text = (void*)((uint8_t*)image_base + sh->VirtualAddress);
+ *size_out = sh->Misc.VirtualSize;
+ break;
+ }
+ }
+
+ return text;
+}
+
+void efi_shutdown_system(uint32_t shutdown_type)
+{
+ switch (shutdown_type) {
+ case TB_SHUTDOWN_S5:
+ RT->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
+ case TB_SHUTDOWN_REBOOT:
+ RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
+ defaut:
+ ;
+ };
+}
+
+/* Logging support */
+static void atow_log(CHAR16 *dst, const char *src, uint32_t count)
+{
+ uint32_t i;
+ char c;
+
+ for (i = 0; i < count; i++, dst++, src++) {
+ c = (*src & 0x7f);
+ if (c == '\n') {
+ *dst = L'\r';
+ dst++;
+ }
+ *dst = c;
+ }
+}
+
+void efi_puts(const char *s, unsigned int count)
+{
+ CHAR16 wbuf[2*TBOOT_LOGBUF_SIZE];
+
+ memset(wbuf, 0, sizeof(CHAR16)*2*TBOOT_LOGBUF_SIZE);
+ atow_log(wbuf, s, count);
+ (void)ST->ConOut->OutputString(ST->ConOut, wbuf);
+}
+
+static uint64_t efi_device_path_size(EFI_DEVICE_PATH *dpath)
+{
+ EFI_DEVICE_PATH *tpath = dpath;
+
+ while (!IsDevicePathEnd(tpath))
+ tpath = NextDevicePathNode(tpath);
+
+ return ((uint64_t)tpath - (uint64_t)dpath) + sizeof(EFI_DEVICE_PATH);
+}
+
+static EFI_DEVICE_PATH *efi_device_path_instance(EFI_DEVICE_PATH **dpath,
+ uint64_t *size)
+{
+ EFI_DEVICE_PATH *spath = *dpath, *npath, *tpath = *dpath;
+
+ if (!tpath)
+ return NULL;
+
+ for ( ; ; ) {
+ npath = NextDevicePathNode(tpath);
+
+ if (IsDevicePathEndType(tpath))
+ break;
+
+ tpath = npath;
+ }
+
+ if (DevicePathSubType(tpath) == END_ENTIRE_DEVICE_PATH_SUBTYPE)
+ npath = NULL;
+
+ *dpath = npath;
+
+ if (size)
+ *size = ((uint64_t)tpath) - ((uint64_t)spath);
+ return spath;
+}
+
+static EFI_DEVICE_PATH *efi_append_device_path(EFI_DEVICE_PATH *dpath1,
+ EFI_DEVICE_PATH *dpath2)
+{
+ EFI_STATUS status = EFI_SUCCESS;
+ uint64_t size1, size2, inst = 0, size;
+ EFI_DEVICE_PATH *tpath = dpath1, *ipath, *opath;
+ uint8_t *pos;
+
+ size1 = efi_device_path_size(dpath1);
+ size2 = efi_device_path_size(dpath2);
+
+ while (efi_device_path_instance(&tpath, NULL))
+ inst++;
+
+ size = (size1 * inst) + size2;
+
+ status = BS->AllocatePool(EfiLoaderData, size, (void**)&opath);
+ if (EFI_ERROR(status))
+ return NULL;
+
+ pos = (uint8_t*)opath;
+ ipath = efi_device_path_instance(&dpath1, &size);
+
+ for ( ; ; ) {
+ if (!ipath)
+ break;
+
+ memcpy(pos, ipath, size);
+ pos += size;
+ memcpy(pos, dpath2, size2);
+ pos += size2;
+ memcpy(pos, EfiEndInstanceDevicePath, sizeof(EFI_DEVICE_PATH));
+ pos += sizeof(EFI_DEVICE_PATH);
+
+ ipath = efi_device_path_instance(&dpath1, &size);
+ }
+
+ pos -= sizeof(EFI_DEVICE_PATH);
+ memcpy(pos, EfiEndDevicePath, sizeof(EFI_DEVICE_PATH));
+
+ return opath;
+}
+
+EFI_DEVICE_PATH *efi_get_device_path(const wchar_t *path, EFI_HANDLE parent)
+{
+ EFI_STATUS status = EFI_SUCCESS;
+ FILEPATH_DEVICE_PATH *file_path = NULL;
+ EFI_DEVICE_PATH *dev_path = NULL, *parent_path, *eo_path;
+ uint64_t size = wcslen(path)*sizeof(wchar_t);
+
+ status = BS->AllocatePool(EfiLoaderData,
+ size + SIZE_OF_FILEPATH_DEVICE_PATH + sizeof(EFI_DEVICE_PATH),
+ (void**)&file_path);
+ if (EFI_ERROR(status))
+ return NULL;
+
+ status = BS->HandleProtocol(parent, &DevicePathProtocol, (void**)&parent_path);
+ if (EFI_ERROR(status)) {
+ BS->FreePool(file_path);
+ return NULL;
+ }
+
+ file_path->Header.Type = MEDIA_DEVICE_PATH;
+ file_path->Header.SubType = MEDIA_FILEPATH_DP;
+ SetDevicePathNodeLength(&file_path->Header, size + SIZE_OF_FILEPATH_DEVICE_PATH);
+ memcpy(file_path->PathName, path, size);
+ eo_path = NextDevicePathNode(&file_path->Header);
+ SetDevicePathEndNode(eo_path);
+
+ dev_path = efi_append_device_path(parent_path, (EFI_DEVICE_PATH*)file_path);
+ BS->FreePool(file_path);
+
+ return dev_path;
+}
+
+EFI_STATUS efi_device_path_to_text(EFI_DEVICE_PATH *dev_path,
+ wchar_t *path_out,
+ uint64_t count)
+{
+#define size_needed(d) (DevicePathNodeLength(d) - \
+ (sizeof(EFI_DEVICE_PATH) - sizeof(wchar_t)))
+#define copy_size(d) (DevicePathNodeLength(d) - sizeof(EFI_DEVICE_PATH))
+ EFI_STATUS status = EFI_SUCCESS;
+ FILEPATH_DEVICE_PATH *file_path;
+ uint64_t size = count*sizeof(wchar_t);
+
+ while (DevicePathType(dev_path) != END_DEVICE_PATH_TYPE) {
+ /* Space check first */
+ if (size < size_needed(dev_path))
+ return EFI_BUFFER_TOO_SMALL;
+
+ /* Copy in latest bits of the path */
+ file_path = (FILEPATH_DEVICE_PATH*)dev_path;
+ memcpy(path_out, file_path->PathName, copy_size(dev_path));
+ path_out[copy_size(dev_path)/sizeof(wchar_t)] = 0;
+ dev_path = (EFI_DEVICE_PATH*)((uint64_t)dev_path +
+ DevicePathNodeLength(dev_path));
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_FILE_INFO *efi_get_file_info(EFI_FILE *target_file,
+ EFI_MEMORY_TYPE mem_type)
+{
+ EFI_STATUS status;
+ void *buffer = NULL;
+ UINTN size = SIZE_OF_EFI_FILE_INFO + 256;
+ uint32_t i;
+
+ for (i = 0; i < 2; i++) {
+ status = BS->AllocatePool(mem_type, size, &buffer);
+ if (!buffer)
+ return NULL;
+
+ status = target_file->GetInfo(target_file,
+ &GenericFileInfo,
+ &size,
+ buffer);
+ if (EFI_ERROR(status)) {
+ BS->FreePool(buffer);
+ buffer = NULL;
+ if (status != EFI_BUFFER_TOO_SMALL)
+ return NULL;
+ continue;
+ }
+ break;
+ }
+
+ return buffer;
+}
+
+EFI_STATUS efi_read_file(EFI_FILE_IO_INTERFACE *file_system,
+ wchar_t *file_name,
+ EFI_MEMORY_TYPE mem_type,
+ uint64_t *size_out,
+ EFI_PHYSICAL_ADDRESS *addr_out)
+{
+ EFI_FILE *root_file = NULL;
+ EFI_FILE *target_file = NULL;
+ EFI_FILE_INFO *file_info;
+ EFI_STATUS status = EFI_SUCCESS;
+ uint64_t size;
+ EFI_PHYSICAL_ADDRESS addr = TBOOT_MAX_IMAGE_MEM;
+ char *print_name = wtoa_alloc(file_name);
+
+ *size_out = 0;
+ *addr_out = 0;
+
+ status = file_system->OpenVolume(file_system, &root_file);
+ if (EFI_ERROR(status)) {
+ printk("Failed to open root File handle - status: %d\n", status);
+ goto out;
+ }
+
+ status = root_file->Open(root_file,
+ &target_file,
+ file_name,
+ EFI_FILE_MODE_READ,
+ EFI_FILE_READ_ONLY);
+ if (EFI_ERROR(status)) {
+ printk("Failed to open file %s - status: %d\n", print_name, status);
+ goto out;
+ }
+
+ status = target_file->SetPosition(target_file, 0);
+ if (EFI_ERROR(status)) {
+ printk("Failed to seek 0 file %s - status: %d\n", print_name, status);
+ goto out;
+ }
+
+ file_info = efi_get_file_info(target_file, mem_type);
+ if (!file_info) {
+ printk("Failed to get file %s information\n", print_name);
+ status = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+ size = file_info->FileSize;
+ BS->FreePool(file_info);
+
+ status = BS->AllocatePages(AllocateMaxAddress,
+ mem_type,
+ PFN_UP(size),
+ &addr);
+ if (EFI_ERROR(status)) {
+ printk("Failed to allocate buffer to read file %s\n", print_name);
+ status = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ status = target_file->Read(target_file, &size, (void*)addr);
+ if (EFI_ERROR(status)) {
+ printk("Failed to read file %s\n", print_name);
+ BS->FreePages(addr, PFN_UP(size));
+ goto out;
+ }
+
+ *size_out = size;
+ *addr_out = addr;
+
+out:
+ if (target_file)
+ target_file->Close(target_file);
+
+ if (root_file)
+ root_file->Close(root_file);
+
+ if (print_name)
+ BS->FreePool(print_name);
+
+ return status;
+}
diff --git a/tboot/efimemmap.c b/tboot/efimemmap.c
new file mode 100644
index 0000000..a9ff517
--- /dev/null
+++ b/tboot/efimemmap.c
@@ -0,0 +1,276 @@
+/*
+ * efimemmap.c: EFI memory map processing and storage.
+ *
+ * Copyright (c) 2017 Assured Information Security.
+ *
+ * Ross Philipson <philipsonr@ainfosec.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <stdbool.h>
+#include <string.h>
+#include <atomic.h>
+#include <page.h>
+#include <printk.h>
+#include <eficore.h>
+#include <eficonfig.h>
+#include <pe.h>
+#include <tb_error.h>
+#include <tboot.h>
+#include <txt/txt.h>
+
+#define MAX_RAMMEM_BLOCKS 128
+#define MEM_NONE 0
+#define MEM_RAM 1
+#define MEM_OTHER 2
+
+typedef struct mem_map {
+ uint64_t addr;
+ uint64_t length;
+ uint64_t type;
+} mem_map_t;
+
+static __data mem_map_t g_ram_map[MAX_RAMMEM_BLOCKS];
+static __data uint64_t g_ram_map_count = 0;
+
+/* minimum size of RAM (type 1) region that cannot be marked as reserved even
+ if it comes after a reserved region; 0 for no minimum (i.e. current
+ behavior) */
+/* TODO this needs some evaluation - preserve for now. If using this causes the
+ * PMRs to not cover the MLE then game over. See the reloc code in boot.c.
+ */
+uint32_t g_min_ram = 0;
+
+/*
+ * All we really care about are conventional RAM regions. This will include
+ * coalesced RAM, EFI loader and boot services memory.
+ */
+bool efi_scan_memory_map(void)
+{
+ const EFI_MEMORY_DESCRIPTOR *desc;
+ const void *memory_map;
+ uint64_t size, size_desc, length, type, last = MEM_NONE, i;
+ mem_map_t *entry = g_ram_map - 1;
+
+ memory_map = efi_get_memory_map(&size, &size_desc);
+ if (!memory_map || size == 0 ||
+ size_desc < sizeof(EFI_MEMORY_DESCRIPTOR)) {
+ printk(TBOOT_ERR"System memory map invalid?!\n");
+ return false;
+ }
+
+ memset(g_ram_map, 0, sizeof(mem_map_t)*MAX_RAMMEM_BLOCKS);
+
+ printk(TBOOT_DETA"EFI memory map:\n");
+ for (i = 0; i < size; i += size_desc) {
+ desc = memory_map + i;
+ length = desc->NumberOfPages << EFI_PAGE_SHIFT;
+
+ printk(TBOOT_DETA" %016llx - %016llx type=%u attr=%016llx\n",
+ desc->PhysicalStart, desc->PhysicalStart + length - 1,
+ desc->Type, desc->Attribute);
+ switch (desc->Type)
+ {
+ case EfiBootServicesCode:
+ case EfiBootServicesData:
+ case EfiLoaderCode:
+ case EfiLoaderData:
+ case EfiConventionalMemory:
+ if (desc->Attribute & EFI_MEMORY_WB)
+ type = MEM_RAM;
+ else
+ type = MEM_OTHER;
+ break;
+ default:
+ type = MEM_OTHER;
+ };
+
+ if (g_ram_map_count >= MAX_RAMMEM_BLOCKS) {
+ printk(TBOOT_ERR"Exhausted RAM memory blocks\n");
+ return false;
+ }
+
+ if (g_ram_map_count && type == last &&
+ desc->PhysicalStart == entry->addr + entry->length) {
+ entry->length += length;
+ }
+ else {
+ ++entry;
+ entry->addr = desc->PhysicalStart;
+ entry->length = length;
+ entry->type = type;
+ ++g_ram_map_count;
+ }
+
+ last = type;
+ }
+
+ entry = g_ram_map;
+ printk(TBOOT_DETA"RAM map:\n");
+ for (i = 0; i < g_ram_map_count; i++, entry++) {
+ printk(TBOOT_DETA" %016llx - %016llx type: %s\n",
+ entry->addr, entry->addr + entry->length,
+ (entry->type == MEM_RAM ? "RAM" : "OTHER"));
+ }
+
+ return true;
+}
+
+bool efi_add_resmap_entry(uint64_t addr, uint64_t length)
+{
+ /*
+ * TODO Xen will have to sort things out like e820_reserve_ram in its
+ * copy of the E820 it gives to dom0. We don't do E820 around these parts.
+ */
+
+ if (_tboot_shared.reserve_map_count >= TB_RESMEM_BLOCKS) {
+ printk(TBOOT_ERR"Exhausted RES memory blocks\n");
+ return false;
+ }
+
+ _tboot_shared.reserve_map[++_tboot_shared.reserve_map_count].addr = addr;
+ _tboot_shared.reserve_map[_tboot_shared.reserve_map_count].length = length;
+
+ return true;
+}
+
+/* find highest (< <limit>) RAM region of at least <size> bytes */
+static void get_highest_sized_ram(uint64_t size, uint64_t limit,
+ uint64_t *ram_base, uint64_t *ram_size)
+{
+ uint64_t last_fit_base = 0, last_fit_size = 0, i;
+ mem_map_t *entry = g_ram_map;
+
+ if ( ram_base == NULL || ram_size == NULL )
+ return;
+
+ for ( i = 0; i < g_ram_map_count; i++, entry++ ) {
+ /* over 4GB so use the last region that fit */
+ if ( entry->addr + entry->length > limit )
+ break;
+ if ( size <= entry->length ) {
+ last_fit_base = entry->addr;
+ last_fit_size = entry->length;
+ }
+ }
+
+ *ram_base = last_fit_base;
+ *ram_size = last_fit_size;
+}
+
+bool efi_get_ram_ranges(uint64_t *min_lo_ram, uint64_t *max_lo_ram,
+ uint64_t *min_hi_ram, uint64_t *max_hi_ram)
+{
+ bool found_reserved_region = false;
+ uint64_t last_min_ram_base = 0, last_min_ram_size = 0, i;
+ mem_map_t *entry = g_ram_map;
+
+ if ( min_lo_ram == NULL || max_lo_ram == NULL ||
+ min_hi_ram == NULL || max_hi_ram == NULL )
+ return false;
+
+ *min_lo_ram = *min_hi_ram = ~0ULL;
+ *max_lo_ram = *max_hi_ram = 0;
+
+ /*
+ * if g_min_ram > 0, we will never mark a region > g_min_ram in size
+ * as reserved even if it is after a reserved region (effectively
+ * we ignore reserved regions below the last type 1 region
+ * > g_min_ram in size)
+ * so in order to reserve RAM regions above this last region, we need
+ * to find it first so that we can tell when we have passed it
+ */
+ if ( g_min_ram > 0 ) {
+ get_highest_sized_ram(g_min_ram, 0x100000000ULL, &last_min_ram_base,
+ &last_min_ram_size);
+ printk(TBOOT_DETA"highest min_ram (0x%x) region found: base=0x%Lx, size=0x%Lx\n",
+ g_min_ram, last_min_ram_base, last_min_ram_size);
+ }
+
+ for ( i = 0; i < g_ram_map_count; i++, entry++ ) {
+ uint64_t base = entry->addr;
+ uint64_t limit = entry->addr + entry->length;
+
+ if ( entry->type == MEM_RAM ) {
+ /* if range straddles 4GB boundary, that is an error */
+ if ( base < 0x100000000ULL && limit > 0x100000000ULL ) {
+ printk(TBOOT_ERR"e820 memory range straddles 4GB boundary\n");
+ return false;
+ }
+
+ /*
+ * some BIOSes put legacy USB buffers in reserved regions <4GB,
+ * which if DMA protected cause SMM to hang, so make sure that
+ * we don't overlap any of these even if that wastes RAM
+ * ...unless min_ram was specified
+ */
+ if ( !found_reserved_region || base <= last_min_ram_base ) {
+ if ( base < 0x100000000ULL && base < *min_lo_ram )
+ *min_lo_ram = base;
+ if ( limit <= 0x100000000ULL && limit > *max_lo_ram )
+ *max_lo_ram = limit;
+ }
+ else { /* need to reserve low RAM above reserved regions */
+ if ( base < 0x100000000ULL ) {
+ if (txt_is_launched()) {
+ printk(TBOOT_DETA"discarding RAM above reserved"
+ "regions: 0x%Lx - 0x%Lx\n", base, limit);
+ if ( !efi_add_resmap_entry(base, limit - base) )
+ return false;
+ }
+ }
+ }
+
+ if ( base >= 0x100000000ULL && base < *min_hi_ram )
+ *min_hi_ram = base;
+ if ( limit > 0x100000000ULL && limit > *max_hi_ram )
+ *max_hi_ram = limit;
+ }
+ else {
+ /* parts of low memory may be reserved for cseg, ISA hole,
+ etc. but these seem OK to DMA protect, so ignore reserved
+ regions <0x100000 */
+ if ( *min_lo_ram != ~0ULL && limit > 0x100000ULL )
+ found_reserved_region = true;
+ }
+ }
+
+ /* no low RAM found */
+ if ( *min_lo_ram >= *max_lo_ram ) {
+ printk(TBOOT_ERR"no low ram in e820 map\n");
+ return false;
+ }
+ /* no high RAM found */
+ if ( *min_hi_ram >= *max_hi_ram )
+ *min_hi_ram = *max_hi_ram = 0;
+
+ return true;
+}
diff --git a/tboot/errors.c b/tboot/errors.c
new file mode 100644
index 0000000..5d22b40
--- /dev/null
+++ b/tboot/errors.c
@@ -0,0 +1,285 @@
+/*
+ * errors.c: parse and return status of Intel(r) TXT error codes
+ *
+ * Copyright (c) 2003-2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <stdbool.h>
+#include <types.h>
+#include <string.h>
+#include <printk.h>
+#include <atomic.h>
+#include <uuid.h>
+#include <tb_error.h>
+#include <txt/txt.h>
+#include <txt/config_regs.h>
+#include <txt/errorcode.h>
+
+
+static void display_errors(void)
+{
+ txt_errorcode_t err;
+ txt_ests_t ests;
+ txt_e2sts_t e2sts;
+ txt_errorcode_sw_t sw_err;
+ acmod_error_t acmod_err;
+
+ /*
+ * display TXT.ERRORODE error
+ */
+ err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE);
+ if (err._raw == 0 || err._raw == 0xc0000001 || err._raw == 0xc0000009)
+ printk(TBOOT_INFO"TXT.ERRORCODE: 0x%Lx\n", err._raw);
+ else
+ printk(TBOOT_ERR"TXT.ERRORCODE: 0x%Lx\n", err._raw);
+
+ /* AC module error (don't know how to parse other errors) */
+ if ( err.valid ) {
+ if ( err.external == 0 ) /* processor error */
+ printk(TBOOT_ERR"\t processor error 0x%x\n", (uint32_t)err.type);
+ else { /* external SW error */
+ sw_err._raw = err.type;
+ if ( sw_err.src == 1 ) /* unknown SW error */
+ printk(TBOOT_ERR"unknown SW error 0x%x:0x%x\n", sw_err.err1, sw_err.err2);
+ else { /* ACM error */
+ acmod_err._raw = sw_err._raw;
+ if ( acmod_err._raw == 0x0 || acmod_err._raw == 0x1 ||
+ acmod_err._raw == 0x9 )
+ printk(TBOOT_INFO"AC module error : acm_type=0x%x, progress=0x%02x, "
+ "error=0x%x\n", acmod_err.acm_type, acmod_err.progress,
+ acmod_err.error);
+ else
+ printk(TBOOT_ERR"AC module error : acm_type=0x%x, progress=0x%02x, "
+ "error=0x%x\n", acmod_err.acm_type, acmod_err.progress,
+ acmod_err.error);
+ /* error = 0x0a, progress = 0x0d => TPM error */
+ if ( acmod_err.error == 0x0a && acmod_err.progress == 0x0d )
+ printk(TBOOT_ERR"TPM error code = 0x%x\n", acmod_err.tpm_err);
+ /* progress = 0x10 => LCP2 error */
+ else if ( acmod_err.progress == 0x10 && acmod_err.lcp_minor != 0 )
+ printk(TBOOT_ERR"LCP2 error: minor error = 0x%x, index = %u\n",
+ acmod_err.lcp_minor, acmod_err.lcp_index);
+ }
+ }
+ }
+
+ /*
+ * display TXT.ESTS error
+ */
+ ests = (txt_ests_t)read_pub_config_reg(TXTCR_ESTS);
+ if (ests._raw == 0)
+ printk(TBOOT_INFO"TXT.ESTS: 0x%Lx\n", ests._raw);
+ else
+ printk(TBOOT_ERR"TXT.ESTS: 0x%Lx\n", ests._raw);
+
+ /*
+ * display TXT.E2STS error
+ */
+ e2sts = (txt_e2sts_t)read_pub_config_reg(TXTCR_E2STS);
+ if (e2sts._raw == 0 || e2sts._raw == 0x200000000)
+ printk(TBOOT_INFO"TXT.E2STS: 0x%Lx\n", e2sts._raw);
+ else
+ printk(TBOOT_ERR"TXT.E2STS: 0x%Lx\n", e2sts._raw);
+}
+
+bool txt_get_error(void)
+{
+ txt_errorcode_t err;
+
+ display_errors();
+
+ err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE);
+ if ( err.valid )
+ return false;
+ else
+ return true;
+}
+
+#define CLASS_ACM_ENTRY 0x1
+enum ENUM_ACM_ENTRY {
+ ERR_LAUNCH = 1,
+ ERR_NEM_ENABLED,
+ ERR_CPU_LT_TYPE,
+ ERR_DEV_ID,
+ ERR_CPU_ID,
+ ERR_NO_UCODE_UPDATE ,
+ ERR_DEBUG_MCU,
+ ERR_DMI_LINK_DOWN,
+ ERR_ACM_REVOKED,
+ ERR_TPM_DOUBLE_AUX
+};
+#define CLASS_TPM_ACCESS 0x4
+enum ENUM_TPM_ACCESS {
+ ERR_OK, /* Indicator of successful execution of the function.*/
+ ERR_TPM_ERROR, /* TPM returned an error */
+ ERR_LOCALITY,
+ ERR_ACC_INVLD,
+ ERR_NV_UNLOCKED, /* TPM NV RAM not locked */
+ ERR_TPM_DISABLED, /* TPM is disabled */
+ ERR_TPM_DEACTIVATED, /* TPM is deactivated */
+ ERR_TPM_NV_INDEX_INVALID, /* TPM NV indices incorrectly defined */
+ ERR_TPM_INCOMPET_BIOSAC, /* Incompatible BIOS ACM */
+ ERR_TPM_INCOMPET_AUXREV, /* Incompatible AUX revision */
+ ERR_TPM_INBUF_TOO_SHORT, /* Input buffer is too short */
+ ERR_TPM_OUTBUF_TOO_SHORT, /* Output buffer is too short */
+ ERR_TPM_NV_PO_INDEX_INVALID = 0x10,
+
+ /*
+ * Errors returned by TPM driver
+ */
+ ERR_OUTPUT_BUFFER_TOO_SHORT = 0x1B, /* Output buffer for the TPM response to short */
+ ERR_INVALID_INPUT_PARA = 0x1C, /* Input parameter for the function invalid */
+ ERR_INVALID_RESPONSE_WR = 0x1D, /* The response from the TPM was invalid */
+ ERR_INVALID_RESPONSE_RD = 0x1E, /* The response from the TPM was invalid */
+ ERR_RESPONSE_TIMEOUT = 0x1F /* Time out for TPM response */
+};
+#define CLASS_MISC_CONFIG 0x8
+enum ENUM_MISC_CONFIG {
+ ERR_INTERRUPT = 1,
+ ERR_FORBIDDEN_BY_OWNER = 0x10,
+ ERR_TOOL_LAUNCH,
+ ERR_CANNOT_REVERSE,
+ ERR_ALREADY_REVOKED,
+ ERR_INVALID_RETURN_ADDR,
+ ERR_NO_TPM,
+};
+
+void txt_get_racm_error(void)
+{
+ txt_errorcode_t err;
+ acmod_error_t acmod_err;
+
+ /*
+ * display TXT.ERRORODE error
+ */
+ err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE);
+
+ /* AC module error (don't know how to parse other errors) */
+ if ( err.valid == 0 ) {
+ printk(TBOOT_ERR
+ "Cannot retrieve status - ERRORSTS register is not valid.\n");
+ return;
+ }
+
+ if ( err.external == 0 ) { /* processor error */
+ printk(TBOOT_ERR"CPU generated error 0x%x\n", (uint32_t)err.type);
+ return;
+ }
+
+ acmod_err._raw = err.type;
+ if ( acmod_err.src == 1 ) {
+ printk(TBOOT_ERR"Unknown SW error.\n");
+ return;
+ }
+
+ if ( acmod_err.acm_type != 0x9 ) {
+ printk(TBOOT_ERR
+ "Cannot retrieve status - wrong ACM type in ERRORSTS register.\n");
+ return;
+ }
+
+ if ( acmod_err.progress == CLASS_ACM_ENTRY &&
+ acmod_err.error == ERR_TPM_DOUBLE_AUX ) {
+ printk(TBOOT_ERR
+ "Nothing to do: double AUX index is not valid TXT configuration.\n");
+ return;
+ }
+
+ if ( acmod_err.progress == CLASS_TPM_ACCESS &&
+ acmod_err.error == ERR_TPM_NV_INDEX_INVALID ) {
+ printk(TBOOT_ERR
+ "Nothing to do: invalid AUX index attributes.\n");
+ return;
+ }
+
+ if ( acmod_err.progress == CLASS_TPM_ACCESS &&
+ acmod_err.error == ERR_TPM_NV_PO_INDEX_INVALID ) {
+ printk(TBOOT_ERR
+ "Error: invalid PO index attributes.\n");
+ return;
+ }
+
+ if ( acmod_err.progress == CLASS_MISC_CONFIG &&
+ acmod_err.error == ERR_ALREADY_REVOKED ) {
+ printk(TBOOT_ERR
+ "Nothing to do: already revoked.\n");
+ return;
+ }
+
+ if ( acmod_err.progress == CLASS_MISC_CONFIG &&
+ acmod_err.error == ERR_FORBIDDEN_BY_OWNER ) {
+ printk(TBOOT_ERR
+ "Error: revocation forbidden by owner.\n");
+ return;
+ }
+
+ if ( acmod_err.progress == CLASS_MISC_CONFIG &&
+ acmod_err.error == ERR_CANNOT_REVERSE ) {
+ printk(TBOOT_ERR
+ "Error: cannot decrement revocation version.\n");
+ return;
+ }
+
+ if ( acmod_err.progress == CLASS_MISC_CONFIG &&
+ acmod_err.error == ERR_INVALID_RETURN_ADDR ) {
+ printk(TBOOT_ERR
+ "Error: invalid input address of return point.\n");
+ return;
+ }
+
+ if ( acmod_err.progress == CLASS_MISC_CONFIG &&
+ acmod_err.error == ERR_NO_TPM ) {
+ printk(TBOOT_ERR
+ "Nothing to do: No TPM present.\n");
+ return;
+ }
+
+ if ( acmod_err.progress == 0 && acmod_err.error == 0 ) {
+ printk(TBOOT_INFO
+ "Success: Revocation completed.\n");
+ return;
+ }
+
+ printk(TBOOT_ERR"RACM generated error 0x%Lx.\n", err._raw);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/genlds.sh b/tboot/genlds.sh
new file mode 100755
index 0000000..3d2806f
--- /dev/null
+++ b/tboot/genlds.sh
@@ -0,0 +1,19 @@
+#! /bin/sh
+
+RO_DATA_SECTION=".rdata"
+
+if [ "$1" == "gcc" ]; then
+ RO_DATA_SECTION=".rodata"
+fi
+
+cat << EOF >> tboot.lds
+SECTIONS
+{
+ .text : {
+ . = ALIGN(4096);
+ *(.text)
+ *($RO_DATA_SECTION)
+ *(SORT($RO_DATA_SECTION*))
+ }
+}
+EOF
diff --git a/tboot/hash.c b/tboot/hash.c
new file mode 100644
index 0000000..cc0cdd2
--- /dev/null
+++ b/tboot/hash.c
@@ -0,0 +1,193 @@
+/*
+ * hash.c: support functions for tb_hash_t type
+ *
+ * Copyright (c) 2006-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <printk.h>
+#include <compiler.h>
+#include <string.h>
+#include <misc.h>
+#include <sha1.h>
+#include <sha256.h>
+#include <hash.h>
+
+/*
+ * are_hashes_equal
+ *
+ * compare whether two hash values are equal.
+ *
+ */
+bool are_hashes_equal(const tb_hash_t *hash1, const tb_hash_t *hash2,
+ uint16_t hash_alg)
+{
+ unsigned int len;
+
+ if ( ( hash1 == NULL ) || ( hash2 == NULL ) ) {
+ printk(TBOOT_ERR"Error: hash pointer is zero.\n");
+ return false;
+ }
+
+ len = get_hash_size(hash_alg);
+ if ( len > 0 )
+ return (memcmp(hash1, hash2, len) == 0);
+ else {
+ printk(TBOOT_ERR"unsupported hash alg (%u)\n", hash_alg);
+ return false;
+ }
+}
+
+/*
+ * hash_buffer
+ *
+ * hash the buffer according to the algorithm
+ *
+ */
+bool hash_buffer(const unsigned char* buf, size_t size, tb_hash_t *hash,
+ uint16_t hash_alg)
+{
+ if ( hash == NULL ) {
+ printk(TBOOT_ERR"Error: There is no space for output hash.\n");
+ return false;
+ }
+
+ if ( hash_alg == TB_HALG_SHA1 ) {
+ sha1_buffer(buf, size, hash->sha1);
+ return true;
+ }
+ else if ( hash_alg == TB_HALG_SHA256 ) {
+ sha256_buffer(buf, size, hash->sha256);
+ return true;
+ }
+ else if ( hash_alg == TB_HALG_SM3 ) {
+ printk(TBOOT_ERR"unsupported hash alg (%u)\n", hash_alg);
+ return false;
+ }
+ else {
+ printk(TBOOT_ERR"unsupported hash alg (%u)\n", hash_alg);
+ return false;
+ }
+}
+
+/*
+ * extend_hash
+ *
+ * perform "extend" of two hashes (i.e. hash1 = SHA(hash1 || hash2)
+ *
+ */
+bool extend_hash(tb_hash_t *hash1, const tb_hash_t *hash2, uint16_t hash_alg)
+{
+ uint8_t buf[2*SHA512_LENGTH];
+
+ /* RJP this is nuts - don't do that - it freaks the compiler out:
+ uint8_t buf[2*get_hash_size(hash_alg)]; */
+
+ if ( hash1 == NULL || hash2 == NULL ) {
+ printk(TBOOT_ERR"Error: There is no space for output hash.\n");
+ return false;
+ }
+
+ if ( hash_alg == TB_HALG_SHA1 ) {
+ memcpy(buf, &(hash1->sha1), sizeof(hash1->sha1));
+ memcpy(buf + sizeof(hash1->sha1), &(hash2->sha1), sizeof(hash1->sha1));
+ sha1_buffer(buf, 2*sizeof(hash1->sha1), hash1->sha1);
+ return true;
+ }
+ else if ( hash_alg == TB_HALG_SHA256 ) {
+ memcpy(buf, &(hash1->sha256), sizeof(hash1->sha256));
+ memcpy(buf + sizeof(hash1->sha256), &(hash2->sha256), sizeof(hash1->sha256));
+ sha256_buffer(buf, 2*sizeof(hash1->sha256), hash1->sha256);
+ return true;
+ }
+ else if ( hash_alg == TB_HALG_SM3 ) {
+ printk(TBOOT_ERR"unsupported hash alg (%u)\n", hash_alg);
+ return false;
+ }
+ else {
+ printk(TBOOT_ERR"unsupported hash alg (%u)\n", hash_alg);
+ return false;
+ }
+}
+
+void print_hash(const tb_hash_t *hash, uint16_t hash_alg)
+{
+ if ( hash == NULL ) {
+ printk(TBOOT_WARN"NULL");
+ return;
+ }
+
+ if ( hash_alg == TB_HALG_SHA1 )
+ print_hex(NULL, (uint8_t *)hash->sha1, sizeof(hash->sha1));
+ else if ( hash_alg == TB_HALG_SHA256 )
+ print_hex(NULL, (uint8_t *)hash->sha256, sizeof(hash->sha256));
+ else if ( hash_alg == TB_HALG_SM3 )
+ print_hex(NULL, (uint8_t *)hash->sm3, sizeof(hash->sm3));
+ else if ( hash_alg == TB_HALG_SHA384 )
+ print_hex(NULL, (uint8_t *)hash->sha384, sizeof(hash->sha384));
+ else {
+ printk(TBOOT_WARN"unsupported hash alg (%u)\n", hash_alg);
+ return;
+ }
+}
+
+void copy_hash(tb_hash_t *dest_hash, const tb_hash_t *src_hash,
+ uint16_t hash_alg)
+{
+ unsigned int len;
+
+ if ( dest_hash == NULL || src_hash == NULL ) {
+ printk(TBOOT_WARN"hashes are NULL\n");
+ return;
+ }
+
+ len = get_hash_size(hash_alg);
+ if ( len > 0 )
+ memcpy(dest_hash, src_hash, len);
+ else
+ printk(TBOOT_WARN"unsupported hash alg (%u)\n", hash_alg);
+}
+
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/heap.c b/tboot/heap.c
new file mode 100644
index 0000000..0fadb57
--- /dev/null
+++ b/tboot/heap.c
@@ -0,0 +1,818 @@
+/*
+ * heap.c: fns for verifying and printing the Intel(r) TXT heap data structs
+ *
+ * Copyright (c) 2003-2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef IS_INCLUDED
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <compiler.h>
+#include <processor.h>
+#include <string.h>
+#include <printk.h>
+#include <uuid.h>
+#include <mle.h>
+#include <misc.h>
+#include <hash.h>
+#include <tpm.h>
+#include <txt/mtrrs.h>
+#include <txt/config_regs.h>
+#include <txt/heap.h>
+#endif
+
+/*
+ * extended data elements
+ */
+
+/* HEAP_BIOS_SPEC_VER_ELEMENT */
+static void print_bios_spec_ver_elt(const heap_ext_data_element_t *elt)
+{
+ const heap_bios_spec_ver_elt_t *bios_spec_ver_elt =
+ (const heap_bios_spec_ver_elt_t *)elt->data;
+
+ printk(TBOOT_INFO"\t\t BIOS_SPEC_VER:\n");
+ printk(TBOOT_INFO"\t\t major: 0x%x\n", bios_spec_ver_elt->spec_ver_major);
+ printk(TBOOT_INFO"\t\t minor: 0x%x\n", bios_spec_ver_elt->spec_ver_minor);
+ printk(TBOOT_INFO"\t\t rev: 0x%x\n", bios_spec_ver_elt->spec_ver_rev);
+}
+
+static bool verify_bios_spec_ver_elt(const heap_ext_data_element_t *elt)
+{
+ const heap_bios_spec_ver_elt_t *bios_spec_ver_elt =
+ (const heap_bios_spec_ver_elt_t *)elt->data;
+
+ if ( elt->size != sizeof(*elt) + sizeof(*bios_spec_ver_elt) ) {
+ printk(TBOOT_ERR"HEAP_BIOS_SPEC_VER element has wrong size (%u)\n", elt->size);
+ return false;
+ }
+
+ /* any values are allowed */
+ return true;
+}
+
+/* HEAP_ACM_ELEMENT */
+static void print_acm_elt(const heap_ext_data_element_t *elt)
+{
+ const heap_acm_elt_t *acm_elt = (const heap_acm_elt_t *)elt->data;
+
+ printk(TBOOT_DETA"\t\t ACM:\n");
+ printk(TBOOT_DETA"\t\t num_acms: %u\n", acm_elt->num_acms);
+ for ( unsigned int i = 0; i < acm_elt->num_acms; i++ )
+ printk(TBOOT_DETA"\t\t acm_addrs[%u]: 0x%jx\n", i, acm_elt->acm_addrs[i]);
+}
+
+static bool verify_acm_elt(const heap_ext_data_element_t *elt)
+{
+ const heap_acm_elt_t *acm_elt = (const heap_acm_elt_t *)elt->data;
+
+ if ( elt->size != sizeof(*elt) + sizeof(*acm_elt) +
+ acm_elt->num_acms*sizeof(uint64_t) ) {
+ printk(TBOOT_ERR"HEAP_ACM element has wrong size (%u)\n", elt->size);
+ return false;
+ }
+
+ /* no addrs is not error, but print warning */
+ if ( acm_elt->num_acms == 0 )
+ printk(TBOOT_WARN"HEAP_ACM element has no ACM addrs\n");
+
+ for ( unsigned int i = 0; i < acm_elt->num_acms; i++ ) {
+ if ( acm_elt->acm_addrs[i] == 0 ) {
+ printk(TBOOT_ERR"HEAP_ACM element ACM addr (%u) is NULL\n", i);
+ return false;
+ }
+
+ if ( acm_elt->acm_addrs[i] >= 0x100000000UL ) {
+ printk(TBOOT_ERR"HEAP_ACM element ACM addr (%u) is >4GB (0x%jx)\n", i,
+ acm_elt->acm_addrs[i]);
+ return false;
+ }
+
+ /* not going to check if ACM addrs are valid ACMs */
+ }
+
+ return true;
+}
+
+/* HEAP_CUSTOM_ELEMENT */
+static void print_custom_elt(const heap_ext_data_element_t *elt)
+{
+ const heap_custom_elt_t *custom_elt = (const heap_custom_elt_t *)elt->data;
+
+ printk(TBOOT_DETA"\t\t CUSTOM:\n");
+ printk(TBOOT_DETA"\t\t size: %u\n", elt->size);
+ printk(TBOOT_DETA"\t\t uuid: "); print_uuid(&custom_elt->uuid);
+ printk(TBOOT_DETA"\n");
+}
+
+static bool verify_custom_elt(const heap_ext_data_element_t *elt)
+{
+ const heap_custom_elt_t *custom_elt = (const heap_custom_elt_t *)elt->data;
+
+ if ( elt->size < sizeof(*elt) + sizeof(*custom_elt) ) {
+ printk(TBOOT_ERR"HEAP_CUSTOM element has wrong size (%u)\n", elt->size);
+ return false;
+ }
+
+ /* any values are allowed */
+ return true;
+}
+
+/* HEAP_EVENT_LOG_POINTER_ELEMENT */
+static inline void print_heap_hash(const sha1_hash_t hash)
+{
+ print_hash((const tb_hash_t *)hash, TB_HALG_SHA1);
+}
+
+void print_event(const tpm12_pcr_event_t *evt)
+{
+ printk(TBOOT_DETA"\t\t\t Event:\n");
+ printk(TBOOT_DETA"\t\t\t PCRIndex: %u\n", evt->pcr_index);
+ printk(TBOOT_DETA"\t\t\t Type: 0x%x\n", evt->type);
+ printk(TBOOT_DETA"\t\t\t Digest: ");
+ print_heap_hash(evt->digest);
+ printk(TBOOT_DETA"\t\t\t Data: %u bytes", evt->data_size);
+ print_hex("\t\t\t ", evt->data, evt->data_size);
+}
+
+static void print_evt_log(const event_log_container_t *elog)
+{
+ printk(TBOOT_DETA"\t\t\t Event Log Container:\n");
+ printk(TBOOT_DETA"\t\t\t Signature: %s\n", elog->signature);
+ printk(TBOOT_DETA"\t\t\t ContainerVer: %u.%u\n",
+ elog->container_ver_major, elog->container_ver_minor);
+ printk(TBOOT_DETA"\t\t\t PCREventVer: %u.%u\n",
+ elog->pcr_event_ver_major, elog->pcr_event_ver_minor);
+ printk(TBOOT_DETA"\t\t\t Size: %u\n", elog->size);
+ printk(TBOOT_DETA"\t\t\t EventsOffset: [%u,%u)\n",
+ elog->pcr_events_offset, elog->next_event_offset);
+
+ const tpm12_pcr_event_t *curr, *next;
+ curr = (tpm12_pcr_event_t *)((void*)elog + elog->pcr_events_offset);
+ next = (tpm12_pcr_event_t *)((void*)elog + elog->next_event_offset);
+
+ while ( curr < next ) {
+ print_event(curr);
+ curr = (void *)curr + sizeof(*curr) + curr->data_size;
+ }
+}
+
+static bool verify_evt_log(const event_log_container_t *elog)
+{
+ if ( elog == NULL ) {
+ printk(TBOOT_ERR"Event log container pointer is NULL\n");
+ return false;
+ }
+
+ if ( memcmp(elog->signature, EVTLOG_SIGNATURE, sizeof(elog->signature)) ) {
+ printk(TBOOT_ERR"Bad event log container signature: %s\n", elog->signature);
+ return false;
+ }
+
+ if ( elog->size != MAX_EVENT_LOG_SIZE ) {
+ printk(TBOOT_ERR"Bad event log container size: 0x%x\n", elog->size);
+ return false;
+ }
+
+ /* no need to check versions */
+
+ if ( elog->pcr_events_offset < sizeof(*elog) ||
+ elog->next_event_offset < elog->pcr_events_offset ||
+ elog->next_event_offset > elog->size ) {
+ printk(TBOOT_ERR"Bad events offset range: [%u, %u)\n",
+ elog->pcr_events_offset, elog->next_event_offset);
+ return false;
+ }
+
+ return true;
+}
+
+static void print_evt_log_ptr_elt(const heap_ext_data_element_t *elt)
+{
+ const heap_event_log_ptr_elt_t *elog_elt =
+ (const heap_event_log_ptr_elt_t *)elt->data;
+
+ printk(TBOOT_DETA"\t\t EVENT_LOG_POINTER:\n");
+ printk(TBOOT_DETA"\t\t size: %u\n", elt->size);
+ printk(TBOOT_DETA"\t\t elog_addr: 0x%jx\n", elog_elt->event_log_phys_addr);
+
+ if ( elog_elt->event_log_phys_addr )
+ print_evt_log((event_log_container_t *)(unsigned long long)
+ elog_elt->event_log_phys_addr);
+}
+
+static bool verify_evt_log_ptr_elt(const heap_ext_data_element_t *elt)
+{
+ const heap_event_log_ptr_elt_t *elog_elt =
+ (const heap_event_log_ptr_elt_t *)elt->data;
+
+ if ( elt->size != sizeof(*elt) + sizeof(*elog_elt) ) {
+ printk(TBOOT_ERR"HEAP_EVENT_LOG_POINTER element has wrong size (%u)\n",
+ elt->size);
+ return false;
+ }
+
+ return verify_evt_log((event_log_container_t *)(unsigned long long)
+ elog_elt->event_log_phys_addr);
+}
+
+void print_event_2(void *evt, uint16_t alg)
+{
+ uint32_t hash_size, data_size;
+ void *next = evt;
+
+ hash_size = get_hash_size(alg);
+ if ( hash_size == 0 )
+ return;
+
+ printk(TBOOT_DETA"\t\t\t Event:\n");
+ printk(TBOOT_DETA"\t\t\t PCRIndex: %u\n", *((uint32_t *)next));
+
+ if ( *((uint32_t *)next) > 24 && *((uint32_t *)next) != 0xFF ) {
+ printk(TBOOT_DETA"\t\t\t Wrong Event Log.\n");
+ return;
+ }
+
+ next += sizeof(uint32_t);
+ printk(TBOOT_DETA"\t\t\t Type: 0x%x\n", *((uint32_t *)next));
+
+ if ( *((uint32_t *)next) > 0xFFF ) {
+ printk(TBOOT_DETA"\t\t\t Wrong Event Log.\n");
+ return;
+ }
+
+ next += sizeof(uint32_t);
+ printk(TBOOT_DETA"\t\t\t Digest: ");
+ print_hex(NULL, (uint8_t *)next, hash_size);
+ next += hash_size;
+ data_size = *(uint32_t *)next;
+ printk(TBOOT_DETA"\t\t\t Data: %u bytes", data_size);
+ if ( data_size > 4096 ) {
+ printk(TBOOT_DETA"\t\t\t Wrong Event Log.\n");
+ return;
+ }
+
+ next += sizeof(uint32_t);
+ if ( data_size )
+ print_hex("\t\t\t ", (uint8_t *)next, data_size);
+ else
+ printk(TBOOT_DETA"\n");
+}
+
+static void print_evt_log_ptr_elt_2(const heap_ext_data_element_t *elt)
+{
+ const heap_event_log_ptr_elt2_t *elog_elt =
+ (const heap_event_log_ptr_elt2_t *)elt->data;
+ const heap_event_log_descr_t *log_descr;
+
+ printk(TBOOT_DETA"\t\t EVENT_LOG_PTR:\n");
+ printk(TBOOT_DETA"\t\t size: %u\n", elt->size);
+ printk(TBOOT_DETA"\t\t count: %d\n", elog_elt->count);
+
+ for ( unsigned int i=0; i<elog_elt->count; i++ ) {
+ log_descr = &elog_elt->event_log_descr[i];
+ printk(TBOOT_DETA"\t\t\t Log Descrption:\n");
+ printk(TBOOT_DETA"\t\t\t Alg: %u\n", log_descr->alg);
+ printk(TBOOT_DETA"\t\t\t Size: %u\n", log_descr->size);
+ printk(TBOOT_DETA"\t\t\t EventsOffset: [%u,%u)\n",
+ log_descr->pcr_events_offset,
+ log_descr->next_event_offset);
+
+ if (log_descr->pcr_events_offset == log_descr->next_event_offset) {
+ printk(TBOOT_DETA"\t\t\t No Event Log.\n");
+ continue;
+ }
+
+ uint32_t hash_size, data_size;
+ hash_size = get_hash_size(log_descr->alg);
+ if ( hash_size == 0 )
+ return;
+
+ void *curr, *next;
+
+ curr = (void *)(unsigned long long)log_descr->phys_addr +
+ log_descr->pcr_events_offset;
+ next = (void *)(unsigned long long)log_descr->phys_addr +
+ log_descr->next_event_offset;
+
+ //It is required for each of the non-SHA1 event log the first entry to be the following
+ //TPM1.2 style TCG_PCR_EVENT record specifying type of the log:
+ //TCG_PCR_EVENT.PCRIndex = 0
+ //TCG_PCR_EVENT.EventType = 0x03 // EV_NO_ACTION per TCG EFI
+ // Platform specification
+ //TCG_PCR_EVENT.Digest = {00…00} // 20 zeros
+ //TCG_PCR_EVENT.EventDataSize = sizeof(TCG_LOG_DESCRIPTOR).
+ //TCG_PCR_EVENT.EventData = TCG_LOG_DESCRIPTOR
+ //The digest of this record MUST NOT be extended into any PCR.
+
+ if (log_descr->alg != TB_HALG_SHA1){
+ print_event_2(curr, TB_HALG_SHA1);
+ curr += sizeof(tpm12_pcr_event_t) + sizeof(tpm20_log_descr_t);
+ }
+
+ while ( curr < next ) {
+ print_event_2(curr, log_descr->alg);
+ data_size = *(uint32_t *)(curr + 2*sizeof(uint32_t) + hash_size);
+ curr += 3*sizeof(uint32_t) + hash_size + data_size;
+ }
+ }
+}
+
+static bool verify_evt_log_ptr_elt_2(const heap_ext_data_element_t *elt)
+{
+ if ( !elt )
+ return false;
+
+ return true;
+}
+
+static void print_ext_data_elts(const heap_ext_data_element_t elts[])
+{
+ const heap_ext_data_element_t *elt = elts;
+
+ printk(TBOOT_DETA"\t ext_data_elts[]:\n");
+ while ( elt->type != HEAP_EXTDATA_TYPE_END ) {
+ switch ( elt->type ) {
+ case HEAP_EXTDATA_TYPE_BIOS_SPEC_VER:
+ print_bios_spec_ver_elt(elt);
+ break;
+ case HEAP_EXTDATA_TYPE_ACM:
+ print_acm_elt(elt);
+ break;
+ case HEAP_EXTDATA_TYPE_CUSTOM:
+ print_custom_elt(elt);
+ break;
+ case HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR:
+ print_evt_log_ptr_elt(elt);
+ break;
+ case HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR_2:
+ print_evt_log_ptr_elt_2(elt);
+ break;
+ default:
+ printk(TBOOT_WARN"\t\t unknown element: type: %u, size: %u\n",
+ elt->type, elt->size);
+ break;
+ }
+ elt = (void *)elt + elt->size;
+ }
+}
+
+static bool verify_ext_data_elts(const heap_ext_data_element_t elts[],
+ size_t elts_size)
+{
+ const heap_ext_data_element_t *elt = elts;
+
+ while ( true ) {
+ if ( elts_size < sizeof(*elt) ) {
+ printk(TBOOT_ERR"heap ext data elements too small\n");
+ return false;
+ }
+ if ( elts_size < elt->size || elt->size == 0 ) {
+ printk(TBOOT_ERR"invalid element size: type: %u, size: %u\n",
+ elt->type, elt->size);
+ return false;
+ }
+ switch ( elt->type ) {
+ case HEAP_EXTDATA_TYPE_END:
+ return true;
+ case HEAP_EXTDATA_TYPE_BIOS_SPEC_VER:
+ if ( !verify_bios_spec_ver_elt(elt) )
+ return false;
+ break;
+ case HEAP_EXTDATA_TYPE_ACM:
+ if ( !verify_acm_elt(elt) )
+ return false;
+ break;
+ case HEAP_EXTDATA_TYPE_CUSTOM:
+ if ( !verify_custom_elt(elt) )
+ return false;
+ break;
+ case HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR:
+ if ( !verify_evt_log_ptr_elt(elt) )
+ return false;
+ break;
+ case HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR_2:
+ if ( !verify_evt_log_ptr_elt_2(elt) )
+ return false;
+ break;
+ default:
+ printk(TBOOT_WARN"unknown element: type: %u, size: %u\n", elt->type,
+ elt->size);
+ break;
+ }
+ elts_size -= elt->size;
+ elt = (void *)elt + elt->size;
+ }
+ return true;
+}
+
+
+static void print_bios_data(const bios_data_t *bios_data, uint64_t size)
+{
+ printk(TBOOT_DETA"bios_data (@%p, %jx):\n", bios_data,
+ *((uint64_t *)bios_data - 1));
+ printk(TBOOT_DETA"\t version: %u\n", bios_data->version);
+ printk(TBOOT_DETA"\t bios_sinit_size: 0x%x (%u)\n", bios_data->bios_sinit_size,
+ bios_data->bios_sinit_size);
+ printk(TBOOT_DETA"\t lcp_pd_base: 0x%jx\n", bios_data->lcp_pd_base);
+ printk(TBOOT_DETA"\t lcp_pd_size: 0x%jx (%ju)\n", bios_data->lcp_pd_size,
+ bios_data->lcp_pd_size);
+ printk(TBOOT_DETA"\t num_logical_procs: %u\n", bios_data->num_logical_procs);
+ if ( bios_data->version >= 3 )
+ printk(TBOOT_DETA"\t flags: 0x%08jx\n", bios_data->flags);
+ if ( bios_data->version >= 4 && size > sizeof(*bios_data) + sizeof(size) )
+ print_ext_data_elts(bios_data->ext_data_elts);
+}
+
+bool verify_bios_data(const txt_heap_t *txt_heap)
+{
+ uint64_t heap_base = read_pub_config_reg(TXTCR_HEAP_BASE);
+ uint64_t heap_size = read_pub_config_reg(TXTCR_HEAP_SIZE);
+ printk(TBOOT_DETA"TXT.HEAP.BASE: 0x%jx\n", heap_base);
+ printk(TBOOT_DETA"TXT.HEAP.SIZE: 0x%jx (%ju)\n", heap_size, heap_size);
+
+ /* verify that heap base/size are valid */
+ if ( txt_heap == NULL || heap_base == 0 || heap_size == 0 )
+ return false;
+
+ /* check size */
+ uint64_t size = get_bios_data_size(txt_heap);
+ if ( size == 0 ) {
+ printk(TBOOT_ERR"BIOS data size is 0\n");
+ return false;
+ }
+ if ( size > heap_size ) {
+ printk(TBOOT_ERR"BIOS data size is larger than heap size "
+ "(%jx, heap size=%jx)\n", size, heap_size);
+ return false;
+ }
+
+ bios_data_t *bios_data = get_bios_data_start(txt_heap);
+
+ /* check version */
+ if ( bios_data->version < 2 ) {
+ printk(TBOOT_ERR"unsupported BIOS data version (%u)\n", bios_data->version);
+ return false;
+ }
+ /* we assume backwards compatibility but print a warning */
+ if ( bios_data->version > 4 )
+ printk(TBOOT_WARN"unsupported BIOS data version (%u)\n", bios_data->version);
+
+ /* all TXT-capable CPUs support at least 1 core */
+ if ( bios_data->num_logical_procs < 1 ) {
+ printk(TBOOT_ERR"BIOS data has incorrect num_logical_procs (%u)\n",
+ bios_data->num_logical_procs);
+ return false;
+ }
+ else if ( bios_data->num_logical_procs > NR_CPUS ) {
+ printk(TBOOT_ERR"BIOS data specifies too many CPUs (%u)\n",
+ bios_data->num_logical_procs);
+ return false;
+ }
+
+ if ( bios_data->version >= 4 && size > sizeof(*bios_data) ) {
+ if ( !verify_ext_data_elts(bios_data->ext_data_elts,
+ size - sizeof(*bios_data)) )
+ return false;
+ }
+
+ print_bios_data(bios_data, size);
+
+ return true;
+}
+
+#ifndef IS_INCLUDED
+
+static void print_os_mle_data(const os_mle_data_t *os_mle_data)
+{
+ printk(TBOOT_DETA"os_mle_data (@%p, %Lx):\n", os_mle_data,
+ *((uint64_t *)os_mle_data - 1));
+ printk(TBOOT_DETA"\t version: %u\n", os_mle_data->version);
+ /* TBD: perhaps eventually print saved_mtrr_state field */
+}
+
+static bool verify_os_mle_data(const txt_heap_t *txt_heap)
+{
+ uint64_t size, heap_size;
+ os_mle_data_t *os_mle_data;
+
+ /* check size */
+ heap_size = read_priv_config_reg(TXTCR_HEAP_SIZE);
+ size = get_os_mle_data_size(txt_heap);
+ if ( size == 0 ) {
+ printk(TBOOT_ERR"OS to MLE data size is 0\n");
+ return false;
+ }
+ if ( size > heap_size ) {
+ printk(TBOOT_ERR"OS to MLE data size is larger than heap size "
+ "(%Lx, heap size=%Lx)\n", size, heap_size);
+ return false;
+ }
+ if ( size != (sizeof(os_mle_data_t) + sizeof(size)) ) {
+ printk(TBOOT_ERR"OS to MLE data size (%Lx) is not equal to "
+ "os_mle_data_t size (%x)\n", size, sizeof(os_mle_data_t));
+ return false;
+ }
+
+ os_mle_data = get_os_mle_data_start(txt_heap);
+
+ /* check version */
+ /* since this data is from our pre-launch to post-launch code only, it */
+ /* should always be this */
+ if ( os_mle_data->version != 3 ) {
+ printk(TBOOT_ERR"unsupported OS to MLE data version (%u)\n",
+ os_mle_data->version);
+ return false;
+ }
+
+ /* NOTE remove lctx_addr - not really used */
+
+ print_os_mle_data(os_mle_data);
+
+ return true;
+}
+
+/*
+ * Make sure version is in [MIN_OS_SINIT_DATA_VER, MAX_OS_SINIT_DATA_VER]
+ * before calling calc_os_sinit_data_size
+ */
+uint64_t calc_os_sinit_data_size(uint32_t version)
+{
+ uint64_t size[] = {
+ offsetof(os_sinit_data_t, efi_rsdt_ptr) + sizeof(uint64_t),
+ sizeof(os_sinit_data_t) + sizeof(uint64_t),
+ sizeof(os_sinit_data_t) + sizeof(uint64_t) +
+ 2 * sizeof(heap_ext_data_element_t) +
+ sizeof(heap_event_log_ptr_elt_t)
+ };
+
+ if ( g_tpm->major == TPM20_VER_MAJOR ) {
+ u32 count;
+ if ( g_tpm->extpol == TB_EXTPOL_AGILE )
+ count = g_tpm->banks;
+ else if ( g_tpm->extpol == TB_EXTPOL_EMBEDDED )
+ count = g_tpm->alg_count;
+ else
+ count = 1;
+
+ size[2] = sizeof(os_sinit_data_t) + sizeof(uint64_t) +
+ 2 * sizeof(heap_ext_data_element_t) +
+ 4 + count*sizeof(heap_event_log_descr_t);
+ }
+
+ if ( version >= 6 )
+ return size[2];
+ else
+ return size[version - MIN_OS_SINIT_DATA_VER];
+}
+
+void print_os_sinit_data(const os_sinit_data_t *os_sinit_data)
+{
+ printk(TBOOT_DETA"os_sinit_data (@%p, %Lx):\n", os_sinit_data,
+ *((uint64_t *)os_sinit_data - 1));
+ printk(TBOOT_DETA"\t version: %u\n", os_sinit_data->version);
+ printk(TBOOT_DETA"\t flags: %u\n", os_sinit_data->flags);
+ printk(TBOOT_DETA"\t mle_ptab: 0x%Lx\n", os_sinit_data->mle_ptab);
+ printk(TBOOT_DETA"\t mle_size: 0x%Lx (%Lu)\n", os_sinit_data->mle_size,
+ os_sinit_data->mle_size);
+ printk(TBOOT_DETA"\t mle_hdr_base: 0x%Lx\n", os_sinit_data->mle_hdr_base);
+ printk(TBOOT_DETA"\t vtd_pmr_lo_base: 0x%Lx\n", os_sinit_data->vtd_pmr_lo_base);
+ printk(TBOOT_DETA"\t vtd_pmr_lo_size: 0x%Lx\n", os_sinit_data->vtd_pmr_lo_size);
+ printk(TBOOT_DETA"\t vtd_pmr_hi_base: 0x%Lx\n", os_sinit_data->vtd_pmr_hi_base);
+ printk(TBOOT_DETA"\t vtd_pmr_hi_size: 0x%Lx\n", os_sinit_data->vtd_pmr_hi_size);
+ printk(TBOOT_DETA"\t lcp_po_base: 0x%Lx\n", os_sinit_data->lcp_po_base);
+ printk(TBOOT_DETA"\t lcp_po_size: 0x%Lx (%Lu)\n", os_sinit_data->lcp_po_size,
+ os_sinit_data->lcp_po_size);
+ print_txt_caps("\t ", os_sinit_data->capabilities);
+ if ( os_sinit_data->version >= 5 )
+ printk(TBOOT_DETA"\t efi_rsdt_ptr: 0x%Lx\n", os_sinit_data->efi_rsdt_ptr);
+ if ( os_sinit_data->version >= 6 )
+ print_ext_data_elts(os_sinit_data->ext_data_elts);
+}
+
+static bool verify_os_sinit_data(const txt_heap_t *txt_heap)
+{
+ uint64_t size, heap_size;
+ os_sinit_data_t *os_sinit_data;
+
+ /* check size */
+ heap_size = read_priv_config_reg(TXTCR_HEAP_SIZE);
+ size = get_os_sinit_data_size(txt_heap);
+ if ( size == 0 ) {
+ printk(TBOOT_ERR"OS to SINIT data size is 0\n");
+ return false;
+ }
+ if ( size > heap_size ) {
+ printk(TBOOT_ERR"OS to SINIT data size is larger than heap size "
+ "(%Lx, heap size=%Lx)\n", size, heap_size);
+ return false;
+ }
+
+ os_sinit_data = get_os_sinit_data_start(txt_heap);
+
+ /* check version (but since we create this, it should always be OK) */
+ if ( os_sinit_data->version < MIN_OS_SINIT_DATA_VER ||
+ os_sinit_data->version > MAX_OS_SINIT_DATA_VER ) {
+ printk(TBOOT_ERR"unsupported OS to SINIT data version (%u)\n",
+ os_sinit_data->version);
+ return false;
+ }
+
+ if ( size != calc_os_sinit_data_size(os_sinit_data->version) ) {
+ printk(TBOOT_ERR"OS to SINIT data size (%Lx) does not match for version (%x)\n",
+ size, sizeof(os_sinit_data_t));
+ return false;
+ }
+
+ if ( os_sinit_data->version >= 6 ) {
+ if ( !verify_ext_data_elts(os_sinit_data->ext_data_elts,
+ size - sizeof(*os_sinit_data)) )
+ return false;
+ }
+
+ print_os_sinit_data(os_sinit_data);
+
+ return true;
+}
+
+static void print_sinit_mdrs(const sinit_mdr_t mdrs[], uint32_t num_mdrs)
+{
+ static const char *mem_types[] = {"GOOD", "SMRAM OVERLAY",
+ "SMRAM NON-OVERLAY",
+ "PCIE EXTENDED CONFIG", "PROTECTED"};
+
+ printk(TBOOT_DETA"\t sinit_mdrs:\n");
+ for ( unsigned int i = 0; i < num_mdrs; i++ ) {
+ printk(TBOOT_DETA"\t\t %016Lx - %016Lx ", mdrs[i].base,
+ mdrs[i].base + mdrs[i].length);
+ if ( mdrs[i].mem_type < sizeof(mem_types)/sizeof(mem_types[0]) )
+ printk(TBOOT_DETA"(%s)\n", mem_types[mdrs[i].mem_type]);
+ else
+ printk(TBOOT_DETA"(%d)\n", (int)mdrs[i].mem_type);
+ }
+}
+
+static void print_sinit_mle_data(const sinit_mle_data_t *sinit_mle_data)
+{
+ printk(TBOOT_DETA"sinit_mle_data (@%p, %Lx):\n", sinit_mle_data,
+ *((uint64_t *)sinit_mle_data - 1));
+ printk(TBOOT_DETA"\t version: %u\n", sinit_mle_data->version);
+ printk(TBOOT_DETA"\t bios_acm_id: \n\t");
+ print_heap_hash(sinit_mle_data->bios_acm_id);
+ printk(TBOOT_DETA"\t edx_senter_flags: 0x%08x\n",
+ sinit_mle_data->edx_senter_flags);
+ printk(TBOOT_DETA"\t mseg_valid: 0x%Lx\n", sinit_mle_data->mseg_valid);
+ printk(TBOOT_DETA"\t sinit_hash:\n\t"); print_heap_hash(sinit_mle_data->sinit_hash);
+ printk(TBOOT_DETA"\t mle_hash:\n\t"); print_heap_hash(sinit_mle_data->mle_hash);
+ printk(TBOOT_DETA"\t stm_hash:\n\t"); print_heap_hash(sinit_mle_data->stm_hash);
+ printk(TBOOT_DETA"\t lcp_policy_hash:\n\t");
+ print_heap_hash(sinit_mle_data->lcp_policy_hash);
+ printk(TBOOT_DETA"\t lcp_policy_control: 0x%08x\n",
+ sinit_mle_data->lcp_policy_control);
+ printk(TBOOT_DETA"\t rlp_wakeup_addr: 0x%x\n", sinit_mle_data->rlp_wakeup_addr);
+ printk(TBOOT_DETA"\t num_mdrs: %u\n", sinit_mle_data->num_mdrs);
+ printk(TBOOT_DETA"\t mdrs_off: 0x%x\n", sinit_mle_data->mdrs_off);
+ printk(TBOOT_DETA"\t num_vtd_dmars: %u\n", sinit_mle_data->num_vtd_dmars);
+ printk(TBOOT_DETA"\t vtd_dmars_off: 0x%x\n", sinit_mle_data->vtd_dmars_off);
+ print_sinit_mdrs((sinit_mdr_t *)
+ (((void *)sinit_mle_data - sizeof(uint64_t)) +
+ sinit_mle_data->mdrs_off), sinit_mle_data->num_mdrs);
+ if ( sinit_mle_data->version >= 8 )
+ printk(TBOOT_DETA"\t proc_scrtm_status: 0x%08x\n",
+ sinit_mle_data->proc_scrtm_status);
+ if ( sinit_mle_data->version >= 9 )
+ print_ext_data_elts(sinit_mle_data->ext_data_elts);
+}
+
+static bool verify_sinit_mle_data(const txt_heap_t *txt_heap)
+{
+ uint64_t size, heap_size;
+ sinit_mle_data_t *sinit_mle_data;
+
+ /* check size */
+ heap_size = read_priv_config_reg(TXTCR_HEAP_SIZE);
+ size = get_sinit_mle_data_size(txt_heap);
+ if ( size == 0 ) {
+ printk(TBOOT_ERR"SINIT to MLE data size is 0\n");
+ return false;
+ }
+ if ( size > heap_size ) {
+ printk(TBOOT_ERR"SINIT to MLE data size is larger than heap size\n"
+ "(%Lx, heap size=%Lx)\n", size, heap_size);
+ return false;
+ }
+
+ sinit_mle_data = get_sinit_mle_data_start(txt_heap);
+
+ /* check version */
+ if ( sinit_mle_data->version < 6 ) {
+ printk(TBOOT_ERR"unsupported SINIT to MLE data version (%u)\n",
+ sinit_mle_data->version);
+ return false;
+ }
+ else if ( sinit_mle_data->version > 9 ) {
+ printk(TBOOT_WARN"unsupported SINIT to MLE data version (%u)\n",
+ sinit_mle_data->version);
+ }
+
+ /* this data is generated by SINIT and so is implicitly trustworthy, */
+ /* so we don't need to validate it's fields */
+
+ print_sinit_mle_data(sinit_mle_data);
+
+ return true;
+}
+
+bool verify_txt_heap(const txt_heap_t *txt_heap, bool bios_data_only)
+{
+ /* verify BIOS to OS data */
+ if ( !verify_bios_data(txt_heap) )
+ return false;
+
+ if ( bios_data_only )
+ return true;
+
+ /* check that total size is within the heap */
+ uint64_t size1 = get_bios_data_size(txt_heap);
+ uint64_t size2 = get_os_mle_data_size(txt_heap);
+ uint64_t size3 = get_os_sinit_data_size(txt_heap);
+ uint64_t size4 = get_sinit_mle_data_size(txt_heap);
+
+ /* overflow? */
+ if ( plus_overflow_u64(size1, size2) ) {
+ printk(TBOOT_ERR"TXT heap data size overflows\n");
+ return false;
+ }
+ if ( plus_overflow_u64(size3, size4) ) {
+ printk(TBOOT_ERR"TXT heap data size overflows\n");
+ return false;
+ }
+ if ( plus_overflow_u64(size1 + size2, size3 + size4) ) {
+ printk(TBOOT_ERR"TXT heap data size overflows\n");
+ return false;
+ }
+
+ if ( (size1 + size2 + size3 + size4) >
+ read_priv_config_reg(TXTCR_HEAP_SIZE) ) {
+ printk(TBOOT_ERR"TXT heap data sizes (%Lx, %Lx, %Lx, %Lx) are larger than\n"
+ "heap total size (%Lx)\n", size1, size2, size3, size4,
+ read_priv_config_reg(TXTCR_HEAP_SIZE));
+ return false;
+ }
+
+ /* verify OS to MLE data */
+ if ( !verify_os_mle_data(txt_heap) )
+ return false;
+
+ /* verify OS to SINIT data */
+ if ( !verify_os_sinit_data(txt_heap) )
+ return false;
+
+ /* verify SINIT to MLE data */
+ if ( !verify_sinit_mle_data(txt_heap) )
+ return false;
+
+ return true;
+}
+
+#endif
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/acpi.h b/tboot/include/acpi.h
new file mode 100644
index 0000000..430b422
--- /dev/null
+++ b/tboot/include/acpi.h
@@ -0,0 +1,518 @@
+/* $OpenBSD: acpireg.h,v 1.17 2009/04/11 08:22:48 kettenis Exp $ */
+/*
+ * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
+ * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Portions copyright (c) 2010, Intel Corporation
+ */
+
+#ifndef __ACPI_H__
+#define __ACPI_H__
+
+//#define ACPI_DEBUG
+
+#define RSDP_SCOPE1_LOW (void *)0x000000
+#define RSDP_SCOPE1_HIGH (void *)0x000400
+#define RSDP_SCOPE2_LOW (void *)0x0E0000
+#define RSDP_SCOPE2_HIGH (void *)0x100000
+
+/* Root System Descriptor Pointer (RSDP) for ACPI 1.0 */
+struct acpi_rsdp1 {
+ u_int8_t signature[8];
+#define RSDP_SIG "RSD PTR "
+
+ u_int8_t checksum; /* make sum == 0 */
+ u_int8_t oemid[6];
+ u_int8_t revision; /* 0 for v1.0, 2 for v2.0 */
+ u_int32_t rsdt; /* physical */
+} __packed;
+
+/* Root System Descriptor Pointer (RSDP) for ACPI 2.0 */
+struct acpi_rsdp {
+ struct acpi_rsdp1 rsdp1;
+ /*
+ * The following values are only valid
+ * when rsdp_revision == 2
+ */
+ u_int32_t rsdp_length; /* length of rsdp */
+ u_int64_t rsdp_xsdt; /* physical */
+ u_int8_t rsdp_extchecksum; /* entire table */
+ u_int8_t rsdp_reserved[3]; /* must be zero */
+} __packed;
+
+/* Common System Description Table Header */
+struct acpi_table_header {
+ u_int8_t signature[4];
+ u_int32_t length;
+ u_int8_t revision;
+ u_int8_t checksum;
+ u_int8_t oemid[6];
+ u_int8_t oemtableid[8];
+ u_int32_t oemrevision;
+
+ u_int8_t aslcompilerid[4];
+ u_int32_t aslcompilerrevision;
+} __packed;
+
+/* Root System Description Table (RSDT) */
+struct acpi_rsdt {
+ struct acpi_table_header hdr;
+#define RSDT_SIG "RSDT"
+
+ u_int32_t table_offsets[1];
+} __packed;
+
+/* Extended System Descriptiion Table */
+struct acpi_xsdt {
+ struct acpi_table_header hdr;
+#define XSDT_SIG "XSDT"
+
+ u_int64_t table_offsets[1];
+} __packed;
+
+
+/* Generic Address Structure */
+struct acpi_gas {
+ u_int8_t address_space_id;
+#define GAS_SYSTEM_MEMORY 0
+#define GAS_SYSTEM_IOSPACE 1
+#define GAS_PCI_CFG_SPACE 2
+#define GAS_EMBEDDED 3
+#define GAS_SMBUS 4
+#define GAS_FUNCTIONAL_FIXED 127
+ u_int8_t register_bit_width;
+ u_int8_t register_bit_offset;
+ u_int8_t access_size;
+#define GAS_ACCESS_UNDEFINED 0
+#define GAS_ACCESS_BYTE 1
+#define GAS_ACCESS_WORD 2
+#define GAS_ACCESS_DWORD 3
+#define GAS_ACCESS_QWORD 4
+ u_int64_t address;
+} __packed;
+
+/* Fixed ACPI Descriptiion Table */
+struct acpi_fadt {
+ struct acpi_table_header hdr;
+#define FADT_SIG "FACP"
+
+ u_int32_t firmware_ctl; /* phys addr FACS */
+ u_int32_t dsdt; /* phys addr DSDT */
+
+ /* int_model is defined in ACPI 1.0, in ACPI 2.0, it should be zero */
+ u_int8_t int_model; /* interrupt model (hdr_revision < 3) */
+
+#define FADT_INT_DUAL_PIC 0
+#define FADT_INT_MULTI_APIC 1
+ u_int8_t pm_profile; /* power mgmt profile */
+#define FADT_PM_UNSPEC 0
+#define FADT_PM_DESKTOP 1
+#define FADT_PM_MOBILE 2
+#define FADT_PM_WORKSTATION 3
+#define FADT_PM_ENT_SERVER 4
+#define FADT_PM_SOHO_SERVER 5
+#define FADT_PM_APPLIANCE 6
+#define FADT_PM_PERF_SERVER 7
+ u_int16_t sci_int; /* SCI interrupt */
+ u_int32_t smi_cmd; /* SMI command port */
+ u_int8_t acpi_enable; /* value to enable */
+ u_int8_t acpi_disable; /* value to disable */
+ u_int8_t s4bios_req; /* value for S4 */
+ u_int8_t pstate_cnt; /* value for performance (hdr_revision > 2) */
+ u_int32_t pm1a_evt_blk; /* power management 1a */
+ u_int32_t pm1b_evt_blk; /* power mangement 1b */
+ u_int32_t pm1a_cnt_blk; /* pm control 1a */
+ u_int32_t pm1b_cnt_blk; /* pm control 1b */
+ u_int32_t pm2_cnt_blk; /* pm control 2 */
+ u_int32_t pm_tmr_blk;
+ u_int32_t gpe0_blk;
+ u_int32_t gpe1_blk;
+ u_int8_t pm1_evt_len;
+ u_int8_t pm1_cnt_len;
+ u_int8_t pm2_cnt_len;
+ u_int8_t pm_tmr_len;
+ u_int8_t gpe0_blk_len;
+ u_int8_t gpe1_blk_len;
+ u_int8_t gpe1_base;
+ u_int8_t cst_cnt; /* (hdr_revision > 2) */
+ u_int16_t p_lvl2_lat;
+ u_int16_t p_lvl3_lat;
+ u_int16_t flush_size;
+ u_int16_t flush_stride;
+ u_int8_t duty_offset;
+ u_int8_t duty_width;
+ u_int8_t day_alrm;
+ u_int8_t mon_alrm;
+ u_int8_t century;
+ u_int16_t iapc_boot_arch; /* (hdr_revision > 2) */
+#define FADT_LEGACY_DEVICES 0x0001 /* Legacy devices supported */
+#define FADT_i8042 0x0002 /* Keyboard controller present */
+#define FADT_NO_VGA 0x0004 /* Do not probe VGA */
+ u_int8_t reserved1;
+ u_int32_t flags;
+#define FADT_WBINVD 0x00000001
+#define FADT_WBINVD_FLUSH 0x00000002
+#define FADT_PROC_C1 0x00000004
+#define FADT_P_LVL2_UP 0x00000008
+#define FADT_PWR_BUTTON 0x00000010
+#define FADT_SLP_BUTTON 0x00000020
+#define FADT_FIX_RTC 0x00000040
+#define FADT_RTC_S4 0x00000080
+#define FADT_TMR_VAL_EXT 0x00000100
+#define FADT_DCK_CAP 0x00000200
+#define FADT_RESET_REG_SUP 0x00000400
+#define FADT_SEALED_CASE 0x00000800
+#define FADT_HEADLESS 0x00001000
+#define FADT_CPU_SW_SLP 0x00002000
+#define FADT_PCI_EXP_WAK 0x00004000
+#define FADT_USE_PLATFORM_CLOCK 0x00008000
+#define FADT_S4_RTC_STS_VALID 0x00010000
+#define FADT_REMOTE_POWER_ON_CAPABLE 0x00020000
+#define FADT_FORCE_APIC_CLUSTER_MODEL 0x00040000
+#define FADT_FORCE_APIC_PHYS_DEST_MODE 0x00080000
+ /*
+ * Following values only exist when rev > 1
+ * If the extended addresses exists, they
+ * must be used in preferense to the non-
+ * extended values above
+ */
+ struct acpi_gas reset_reg;
+ u_int8_t reset_value;
+
+ u_int8_t reserved2a;
+ u_int8_t reserved2b;
+ u_int8_t reserved2c;
+
+ u_int64_t x_firmware_ctl;
+ u_int64_t x_dsdt;
+ struct acpi_gas x_pm1a_evt_blk;
+ struct acpi_gas x_pm1b_evt_blk;
+ struct acpi_gas x_pm1a_cnt_blk;
+ struct acpi_gas x_pm1b_cnt_blk;
+ struct acpi_gas x_pm2_cnt_blk;
+ struct acpi_gas x_pm_tmr_blk;
+ struct acpi_gas x_gpe0_blk;
+ struct acpi_gas x_gpe1_blk;
+} __packed;
+
+struct acpi_madt {
+ struct acpi_table_header hdr;
+#define MADT_SIG "APIC"
+
+ u_int32_t local_apic_address;
+ u_int32_t flags;
+#define ACPI_APIC_PCAT_COMPAT 0x00000001
+} __packed;
+
+struct acpi_madt_lapic {
+ u_int8_t apic_type;
+#define ACPI_MADT_LAPIC 0
+ u_int8_t length;
+ u_int8_t acpi_proc_id;
+ u_int8_t apic_id;
+ u_int32_t flags;
+#define ACPI_PROC_ENABLE 0x00000001
+} __packed;
+
+struct acpi_madt_ioapic {
+ u_int8_t apic_type;
+#define ACPI_MADT_IOAPIC 1
+ u_int8_t length;
+ u_int8_t acpi_ioapic_id;
+ u_int8_t reserved;
+ u_int32_t address;
+ u_int32_t global_int_base;
+} __packed;
+typedef struct acpi_madt_ioapic acpi_table_ioapic_t;
+
+struct acpi_madt_override {
+ u_int8_t apic_type;
+#define ACPI_MADT_OVERRIDE 2
+ u_int8_t length;
+ u_int8_t bus;
+#define ACPI_OVERRIDE_BUS_ISA 0
+ u_int8_t source;
+ u_int32_t global_int;
+ u_int16_t flags;
+#define ACPI_OVERRIDE_POLARITY_BITS 0x3
+#define ACPI_OVERRIDE_POLARITY_BUS 0x0
+#define ACPI_OVERRIDE_POLARITY_HIGH 0x1
+#define ACPI_OVERRIDE_POLARITY_LOW 0x3
+#define ACPI_OVERRIDE_TRIGGER_BITS 0xc
+#define ACPI_OVERRIDE_TRIGGER_BUS 0x0
+#define ACPI_OVERRIDE_TRIGGER_EDGE 0x4
+#define ACPI_OVERRIDE_TRIGGER_LEVEL 0xc
+} __packed;
+
+struct acpi_madt_nmi {
+ u_int8_t apic_type;
+#define ACPI_MADT_NMI 3
+ u_int8_t length;
+ u_int16_t flags; /* Same flags as acpi_madt_override */
+ u_int32_t global_int;
+} __packed;
+
+struct acpi_madt_lapic_nmi {
+ u_int8_t apic_type;
+#define ACPI_MADT_LAPIC_NMI 4
+ u_int8_t length;
+ u_int8_t acpi_proc_id;
+ u_int16_t flags; /* Same flags as acpi_madt_override */
+ u_int8_t local_apic_lint;
+} __packed;
+
+struct acpi_madt_lapic_override {
+ u_int8_t apic_type;
+#define ACPI_MADT_LAPIC_OVERRIDE 5
+ u_int8_t length;
+ u_int16_t reserved;
+ u_int64_t lapic_address;
+} __packed;
+
+struct acpi_madt_io_sapic {
+ u_int8_t apic_type;
+#define ACPI_MADT_IO_SAPIC 6
+ u_int8_t length;
+ u_int8_t iosapic_id;
+ u_int8_t reserved;
+ u_int32_t global_int_base;
+ u_int64_t iosapic_address;
+} __packed;
+
+struct acpi_madt_local_sapic {
+ u_int8_t apic_type;
+#define ACPI_MADT_LOCAL_SAPIC 7
+ u_int8_t length;
+ u_int8_t acpi_proc_id;
+ u_int8_t local_sapic_id;
+ u_int8_t local_sapic_eid;
+ u_int8_t reserved[3];
+ u_int32_t flags; /* Same flags as acpi_madt_lapic */
+ u_int32_t acpi_proc_uid;
+ u_int8_t acpi_proc_uid_string[1];
+} __packed;
+
+struct acpi_madt_platform_int {
+ u_int8_t apic_type;
+#define ACPI_MADT_PLATFORM_INT 8
+ u_int8_t length;
+ u_int16_t flags; /* Same flags as acpi_madt_override */
+ u_int8_t int_type;
+#define ACPI_MADT_PLATFORM_PMI 1
+#define ACPI_MADT_PLATFORM_INIT 2
+#define ACPI_MADT_PLATFORM_CORR_ERROR 3
+ u_int8_t proc_id;
+ u_int8_t proc_eid;
+ u_int8_t io_sapic_vec;
+ u_int32_t global_int;
+ u_int32_t platform_int_flags;
+#define ACPI_MADT_PLATFORM_CPEI 0x00000001
+} __packed;
+
+union acpi_madt_entry {
+ struct acpi_madt_lapic madt_lapic;
+ struct acpi_madt_ioapic madt_ioapic;
+ struct acpi_madt_override madt_override;
+ struct acpi_madt_nmi madt_nmi;
+ struct acpi_madt_lapic_nmi madt_lapic_nmi;
+ struct acpi_madt_lapic_override madt_lapic_override;
+ struct acpi_madt_io_sapic madt_io_sapic;
+ struct acpi_madt_local_sapic madt_local_sapic;
+ struct acpi_madt_platform_int madt_platform_int;
+} __packed;
+
+struct device_scope {
+ u_int8_t type;
+ u_int8_t length;
+ u_int16_t reserved;
+ u_int8_t enumeration_id;
+ u_int8_t start_bus_number;
+ u_int16_t path[1]; /* Path starts here */
+} __packed;
+
+struct dmar_remapping {
+ u_int16_t type;
+#define DMAR_REMAPPING_DRHD 0
+#define DMAR_REMAPPING_RMRR 1
+#define DMAR_REMAPPING_ATSR 2
+#define DMAR_REMAPPING_RHSA 3
+#define DMAR_REMAPPING_RESERVED 4
+ u_int16_t length;
+ u_int8_t flags;
+#define REMAPPING_INCLUDE_PCI_ALL Ox01
+
+ u_int8_t reserved;
+ u_int16_t segment_number;
+ u_int8_t register_base_address[8];
+ struct device_scope device_scope_entry[1]; /* Device Scope starts here */
+} __packed;
+
+struct acpi_dmar {
+ struct acpi_table_header hdr;
+#define DMAR_SIG "DMAR"
+ u_int8_t host_address_width;
+ u_int8_t flags;
+#define DMAR_INTR_REMAP 0x01
+
+ u_int8_t reserved[10];
+ struct dmar_remapping table_offsets[1]; /* dmar_remapping structure starts here */
+} __packed;
+
+struct acpi_mcfg_mmcfg {
+ u_int64_t base_address;
+ u_int16_t group_number;
+ u_int8_t start_bus_number;
+ u_int8_t end_bus_number;
+ u_int32_t reserved;
+} __packed;
+
+struct acpi_mcfg {
+ struct acpi_table_header hdr;
+#define MCFG_SIG "MCFG"
+
+ u_int64_t reserved;
+ /* struct acpi_mcfg_mmcfg table_offsets[1]; */
+ u_int32_t base_address;
+} __packed;
+typedef struct acpi_mcfg acpi_table_mcfg_t;
+
+#if 0
+
+#define ACPI_FREQUENCY 3579545 /* Per ACPI spec */
+
+/*
+ * PCI Configuration space
+ */
+#define ACPI_PCI_BUS(addr) (u_int16_t)((addr) >> 48)
+#define ACPI_PCI_DEV(addr) (u_int16_t)((addr) >> 32)
+#define ACPI_PCI_FN(addr) (u_int16_t)((addr) >> 16)
+#define ACPI_PCI_REG(addr) (u_int16_t)(addr)
+#define ACPI_PCI_ADDR(b,d,f,r) ((u_int64_t)(b)<<48LL | (u_int64_t)(d)<<32LL | (f)<<16LL | (r))
+
+/*
+ * PM1 Status Registers Fixed Hardware Feature Status Bits
+ */
+#define ACPI_PM1_STATUS 0x00
+#define ACPI_PM1_TMR_STS 0x0001
+#define ACPI_PM1_BM_STS 0x0010
+#define ACPI_PM1_GBL_STS 0x0020
+#define ACPI_PM1_PWRBTN_STS 0x0100
+#define ACPI_PM1_SLPBTN_STS 0x0200
+#define ACPI_PM1_RTC_STS 0x0400
+#define ACPI_PM1_PCIEXP_WAKE_STS 0x4000
+#define ACPI_PM1_WAK_STS 0x8000
+
+/*
+ * PM1 Enable Registers
+ */
+#define ACPI_PM1_ENABLE 0x02
+#define ACPI_PM1_TMR_EN 0x0001
+#define ACPI_PM1_GBL_EN 0x0020
+#define ACPI_PM1_PWRBTN_EN 0x0100
+#define ACPI_PM1_SLPBTN_EN 0x0200
+#define ACPI_PM1_RTC_EN 0x0400
+#define ACPI_PM1_PCIEXP_WAKE_DIS 0x4000
+
+/*
+ * PM1 Control Registers
+ */
+#define ACPI_PM1_CONTROL 0x00
+#define ACPI_PM1_SCI_EN 0x0001
+#define ACPI_PM1_BM_RLD 0x0002
+#define ACPI_PM1_GBL_RLS 0x0004
+#define ACPI_PM1_SLP_TYPX(x) ((x) << 10)
+#define ACPI_PM1_SLP_TYPX_MASK 0x1c00
+#define ACPI_PM1_SLP_EN 0x2000
+
+/*
+ * PM2 Control Registers
+ */
+#define ACPI_PM2_CONTROL 0x06
+#define ACPI_PM2_ARB_DIS 0x0001
+
+
+/*
+ * Sleeping States
+ */
+#define ACPI_STATE_S0 0
+#define ACPI_STATE_S1 1
+#define ACPI_STATE_S2 2
+#define ACPI_STATE_S3 3
+#define ACPI_STATE_S4 4
+#define ACPI_STATE_S5 5
+
+/*
+ * ACPI Device IDs
+ */
+#define ACPI_DEV_TIM "PNP0100" /* System timer */
+#define ACPI_DEV_ACPI "PNP0C08" /* ACPI device */
+#define ACPI_DEV_PCIB "PNP0A03" /* PCI bus */
+#define ACPI_DEV_GISAB "PNP0A05" /* Generic ISA Bus */
+#define ACPI_DEV_EIOB "PNP0A06" /* Extended I/O Bus */
+#define ACPI_DEV_PCIEB "PNP0A08" /* PCIe bus */
+#define ACPI_DEV_MR "PNP0C02" /* Motherboard resources */
+#define ACPI_DEV_NPROC "PNP0C04" /* Numeric data processor */
+#define ACPI_DEV_CS "PNP0C08" /* ACPI-Compliant System */
+#define ACPI_DEV_ECD "PNP0C09" /* Embedded Controller Device */
+#define ACPI_DEV_CMB "PNP0C0A" /* Control Method Battery */
+#define ACPI_DEV_FAN "PNP0C0B" /* Fan Device */
+#define ACPI_DEV_PBD "PNP0C0C" /* Power Button Device */
+#define ACPI_DEV_LD "PNP0C0D" /* Lid Device */
+#define ACPI_DEV_SBD "PNP0C0E" /* Sleep Button Device */
+#define ACPI_DEV_PILD "PNP0C0F" /* PCI Interrupt Link Device */
+#define ACPI_DEV_MEMD "PNP0C80" /* Memory Device */
+#define ACPI_DEV_SHC "ACPI0001" /* SMBus 1.0 Host Controller */
+#define ACPI_DEV_SMS1 "ACPI0002" /* Smart Battery Subsystem */
+#define ACPI_DEV_AC "ACPI0003" /* AC Device */
+#define ACPI_DEV_MD "ACPI0004" /* Module Device */
+#define ACPI_DEV_SMS2 "ACPI0005" /* SMBus 2.0 Host Controller */
+#define ACPI_DEV_GBD "ACPI0006" /* GPE Block Device */
+#define ACPI_DEV_PD "ACPI0007" /* Processor Device */
+#define ACPI_DEV_ALSD "ACPI0008" /* Ambient Light Sensor Device */
+#define ACPI_DEV_IOXA "ACPI0009" /* IO x APIC Device */
+#define ACPI_DEV_IOA "ACPI000A"/ /* IO APIC Device */
+#define ACPI_DEV_IOSA "ACPI000B" /* IO SAPIC Device */
+#define ACPI_DEV_THZ "THERMALZONE" /* Thermal Zone */
+#define ACPI_DEV_FFB "FIXEDBUTTON" /* Fixed Feature Button */
+#define ACPI_DEV_ASUS "ASUS010" /* ASUS Hotkeys */
+#define ACPI_DEV_THINKPAD "IBM0068" /* ThinkPad support */
+
+#endif
+
+bool save_vtd_dmar_table(void);
+bool restore_vtd_dmar_table(void);
+bool remove_vtd_dmar_table(void);
+
+struct acpi_table_ioapic *get_acpi_ioapic_table(void);
+struct acpi_mcfg *get_acpi_mcfg_table(void);
+void disable_smis(void);
+
+bool machine_sleep(const tboot_acpi_sleep_info_t *);
+void set_s3_resume_vector(const tboot_acpi_sleep_info_t *, uint64_t);
+struct acpi_rsdp *get_rsdp(void);
+uint32_t get_madt_apic_base(void);
+
+#endif /* __ACPI_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/atomic.h b/tboot/include/atomic.h
new file mode 100644
index 0000000..502cc36
--- /dev/null
+++ b/tboot/include/atomic.h
@@ -0,0 +1,181 @@
+/*-
+ * Copyright (c) 1998 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/i386/include/atomic.h,v 1.47.2.2.2.1 2010/02/10 00:26:20 kensmith Exp $
+ */
+/*
+ * Portions copyright (c) 2010, Intel Corporation
+ */
+
+#ifndef __ATOMIC_H__
+#define __ATOMIC_H__
+
+/*
+ * Various simple operations on memory, each of which is atomic in the
+ * presence of interrupts and multiple processors.
+ *
+ * atomic_set_char(P, V) (*(u_char *)(P) |= (V))
+ * atomic_clear_char(P, V) (*(u_char *)(P) &= ~(V))
+ * atomic_add_char(P, V) (*(u_char *)(P) += (V))
+ * atomic_subtract_char(P, V) (*(u_char *)(P) -= (V))
+ *
+ * atomic_set_short(P, V) (*(u_short *)(P) |= (V))
+ * atomic_clear_short(P, V) (*(u_short *)(P) &= ~(V))
+ * atomic_add_short(P, V) (*(u_short *)(P) += (V))
+ * atomic_subtract_short(P, V) (*(u_short *)(P) -= (V))
+ *
+ * atomic_set_int(P, V) (*(u_int *)(P) |= (V))
+ * atomic_clear_int(P, V) (*(u_int *)(P) &= ~(V))
+ * atomic_add_int(P, V) (*(u_int *)(P) += (V))
+ * atomic_subtract_int(P, V) (*(u_int *)(P) -= (V))
+ * atomic_readandclear_int(P) (return (*(u_int *)(P)); *(u_int *)(P) = 0;)
+ *
+ * atomic_set_long(P, V) (*(u_long *)(P) |= (V))
+ * atomic_clear_long(P, V) (*(u_long *)(P) &= ~(V))
+ * atomic_add_long(P, V) (*(u_long *)(P) += (V))
+ * atomic_subtract_long(P, V) (*(u_long *)(P) -= (V))
+ * atomic_readandclear_long(P) (return (*(u_long *)(P)); *(u_long *)(P) = 0;)
+ */
+
+/*
+ * The above functions are expanded inline in the statically-linked
+ * kernel. Lock prefixes are generated if an SMP kernel is being
+ * built.
+ *
+ * Kernel modules call real functions which are built into the kernel.
+ * This allows kernel modules to be portable between UP and SMP systems.
+ */
+
+/* all operations will be defined only for 'int's */
+#define atomic_t u_int
+
+#define MPLOCKED "lock ; "
+
+/*
+ * The assembly is volatilized to avoid code chunk removal by the compiler.
+ * GCC aggressively reorders operations and memory clobbering is necessary
+ * in order to avoid that for memory barriers.
+ */
+#define ATOMIC_ASM(NAME, TYPE, OP, CONS, V) \
+static __inline void \
+atomic_##NAME##_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\
+{ \
+ __asm __volatile(MPLOCKED OP \
+ : "=m" (*p) \
+ : CONS (V), "m" (*p)); \
+} \
+ \
+static __inline void \
+atomic_##NAME##_barr_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\
+{ \
+ __asm __volatile(MPLOCKED OP \
+ : "=m" (*p) \
+ : CONS (V), "m" (*p) \
+ : "memory"); \
+} \
+struct __hack
+
+/*
+ * Atomically add the value of v to the integer pointed to by p and return
+ * the previous value of *p.
+ */
+static __inline u_int
+atomic_fetchadd_int(volatile u_int *p, u_int v)
+{
+
+ __asm __volatile(
+ " " MPLOCKED " "
+ " xaddl %0, %1 ; "
+ "# atomic_fetchadd_int"
+ : "+r" (v), /* 0 (result) */
+ "=m" (*p) /* 1 */
+ : "m" (*p)); /* 2 */
+
+ return (v);
+}
+
+#define ATOMIC_STORE_LOAD(TYPE, LOP, SOP) \
+static __inline u_##TYPE \
+atomic_load_acq_##TYPE(volatile u_##TYPE *p) \
+{ \
+ u_##TYPE res; \
+ \
+ __asm __volatile(MPLOCKED LOP \
+ : "=a" (res), /* 0 */ \
+ "=m" (*p) /* 1 */ \
+ : "m" (*p) /* 2 */ \
+ : "memory"); \
+ \
+ return (res); \
+} \
+ \
+/* \
+ * The XCHG instruction asserts LOCK automagically. \
+ */ \
+static __inline void \
+atomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\
+{ \
+ __asm __volatile(SOP \
+ : "=m" (*p), /* 0 */ \
+ "+r" (v) /* 1 */ \
+ : "m" (*p) /* 2 */ \
+ : "memory"); \
+} \
+struct __hack
+
+ATOMIC_ASM(set, int, "orl %1,%0", "ir", v);
+ATOMIC_ASM(clear, int, "andl %1,%0", "ir", ~v);
+ATOMIC_ASM(add, int, "addl %1,%0", "ir", v);
+ATOMIC_ASM(subtract, int, "subl %1,%0", "ir", v);
+
+ATOMIC_STORE_LOAD(int, "cmpxchgl %0,%1", "xchgl %1,%0");
+
+#undef ATOMIC_ASM
+#undef ATOMIC_STORE_LOAD
+
+/* Read the current value and store a zero in the destination. */
+static __inline u_int
+atomic_readandclear_int(volatile u_int *addr)
+{
+ u_int res;
+
+ res = 0;
+ __asm __volatile(
+ " xchgl %1,%0 ; "
+ "# atomic_readandclear_int"
+ : "+r" (res), /* 0 */
+ "=m" (*addr) /* 1 */
+ : "m" (*addr));
+
+ return (res);
+}
+
+
+#define atomic_read(atom) atomic_load_acq_int(atom)
+#define atomic_inc(atom) atomic_add_int((atom), 1)
+#define atomic_dec(atom) atomic_subtract_int((atom), 1)
+#define atomic_set(atom, val) atomic_set_int((atom), (val))
+
+#endif /* __ATOMIC_H__ */
diff --git a/tboot/include/cmdline.h b/tboot/include/cmdline.h
new file mode 100644
index 0000000..4b01c20
--- /dev/null
+++ b/tboot/include/cmdline.h
@@ -0,0 +1,76 @@
+/*
+ * cmdline.h: support functions for command line parsing
+ *
+ * Copyright (c) 2006-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __CMDLINE_H__
+#define __CMDLINE_H__
+
+#define CMDLINE_SIZE 512
+char g_cmdline[CMDLINE_SIZE];
+
+
+void tboot_parse_cmdline(bool defaults);
+void get_tboot_loglvl(void);
+void get_tboot_log_targets(void);
+bool get_tboot_serial(void);
+void get_tboot_baud(void);
+void get_tboot_fmt(void);
+void get_tboot_vga_delay(void);
+bool get_tboot_mwait(void);
+bool get_tboot_prefer_da(void);
+void get_tboot_min_ram(void);
+bool get_tboot_call_racm(void);
+bool get_tboot_call_racm_check(void);
+bool get_tboot_measure_nv(void);
+void get_tboot_extpol(void);
+
+/* for parse cmdline of linux kernel, say vga and mem */
+void linux_parse_cmdline(const char *cmdline);
+bool get_linux_vga(int *vid_mode);
+bool get_linux_mem(uint64_t *initrd_max_mem);
+
+uint8_t get_loglvl_prefix(char **pbuf, int *len);
+
+#endif /* __CMDLINE_H__ */
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/com.h b/tboot/include/com.h
new file mode 100644
index 0000000..c51a9fd
--- /dev/null
+++ b/tboot/include/com.h
@@ -0,0 +1,311 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)ns16550.h 7.1 (Berkeley) 5/9/91
+ * $FreeBSD: src/sys/dev/ic/ns16550.h,v 1.20 2010/01/11 04:13:06 imp Exp $
+ */
+/*
+ * Portions copyright (c) 2010, Intel Corporation
+ */
+
+/*
+ * NS8250... UART registers.
+ */
+#ifndef __COM_H__
+#define __COM_H__
+
+/* 8250 registers #[0-6]. */
+
+#define com_data 0 /* data register (R/W) */
+#define REG_DATA com_data
+
+#define com_ier 1 /* interrupt enable register (W) */
+#define REG_IER com_ier
+#define IER_ERXRDY 0x1
+#define IER_ETXRDY 0x2
+#define IER_ERLS 0x4
+#define IER_EMSC 0x8
+
+#define IER_BITS "\20\1ERXRDY\2ETXRDY\3ERLS\4EMSC"
+
+#define com_iir 2 /* interrupt identification register (R) */
+#define REG_IIR com_iir
+#define IIR_IMASK 0xf
+#define IIR_RXTOUT 0xc
+#define IIR_BUSY 0x7
+#define IIR_RLS 0x6
+#define IIR_RXRDY 0x4
+#define IIR_TXRDY 0x2
+#define IIR_NOPEND 0x1
+#define IIR_MLSC 0x0
+#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */
+
+#define IIR_BITS "\20\1NOPEND\2TXRDY\3RXRDY"
+
+#define com_lcr 3 /* line control register (R/W) */
+#define com_cfcr com_lcr /* character format control register (R/W) */
+#define REG_LCR com_lcr
+#define LCR_DLAB 0x80
+#define CFCR_DLAB LCR_DLAB
+#define LCR_EFR_ENABLE 0xbf /* magic to enable EFR on 16650 up */
+#define CFCR_EFR_ENABLE LCR_EFR_ENABLE
+#define LCR_SBREAK 0x40
+#define CFCR_SBREAK LCR_SBREAK
+#define LCR_PZERO 0x30
+#define CFCR_PZERO LCR_PZERO
+#define LCR_PONE 0x20
+#define CFCR_PONE LCR_PONE
+#define LCR_PEVEN 0x10
+#define CFCR_PEVEN LCR_PEVEN
+#define LCR_PODD 0x00
+#define CFCR_PODD LCR_PODD
+#define LCR_PENAB 0x08
+#define CFCR_PENAB LCR_PENAB
+#define LCR_STOPB 0x04
+#define CFCR_STOPB LCR_STOPB
+#define LCR_8BITS 0x03
+#define CFCR_8BITS LCR_8BITS
+#define LCR_7BITS 0x02
+#define CFCR_7BITS LCR_7BITS
+#define LCR_6BITS 0x01
+#define CFCR_6BITS LCR_6BITS
+#define LCR_5BITS 0x00
+#define CFCR_5BITS LCR_5BITS
+
+#define LCR_ODD_PARITY (LCR_PENAB | LCR_PODD)
+#define LCR_EVEN_PARITY (LCR_PENAB | LCR_PEVEN)
+#define LCR_MARK_PARITY (LCR_PENAB | LCR_PONE)
+#define LCR_SPACE_PARITY (LCR_PENAB | LCR_PZERO)
+
+#define com_mcr 4 /* modem control register (R/W) */
+#define REG_MCR com_mcr
+#define MCR_PRESCALE 0x80 /* only available on 16650 up */
+#define MCR_LOOPBACK 0x10
+#define MCR_IE 0x08
+#define MCR_IENABLE MCR_IE
+#define MCR_DRS 0x04
+#define MCR_RTS 0x02
+#define MCR_DTR 0x01
+
+#define MCR_BITS "\20\1DTR\2RTS\3DRS\4IE\5LOOPBACK\10PRESCALE"
+
+#define com_lsr 5 /* line status register (R/W) */
+#define REG_LSR com_lsr
+#define LSR_RCV_FIFO 0x80
+#define LSR_TEMT 0x40
+#define LSR_TSRE LSR_TEMT
+#define LSR_THRE 0x20
+#define LSR_TXRDY LSR_THRE
+#define LSR_BI 0x10
+#define LSR_FE 0x08
+#define LSR_PE 0x04
+#define LSR_OE 0x02
+#define LSR_RXRDY 0x01
+#define LSR_RCV_MASK 0x1f
+
+#define LSR_BITS "\20\1RXRDY\2OE\3PE\4FE\5BI\6THRE\7TEMT\10RCV_FIFO"
+
+#define com_msr 6 /* modem status register (R/W) */
+#define REG_MSR com_msr
+#define MSR_DCD 0x80
+#define MSR_RI 0x40
+#define MSR_DSR 0x20
+#define MSR_CTS 0x10
+#define MSR_DDCD 0x08
+#define MSR_TERI 0x04
+#define MSR_DDSR 0x02
+#define MSR_DCTS 0x01
+
+#define MSR_BITS "\20\1DCTS\2DDSR\3TERI\4DDCD\5CTS\6DSR\7RI\10DCD"
+
+/* 8250 multiplexed registers #[0-1]. Access enabled by LCR[7]. */
+#define com_dll 0 /* divisor latch low (R/W) */
+#define com_dlbl com_dll
+#define com_dlm 1 /* divisor latch high (R/W) */
+#define com_dlbh com_dlm
+#define REG_DLL com_dll
+#define REG_DLH com_dlm
+
+/* 16450 register #7. Not multiplexed. */
+#define com_scr 7 /* scratch register (R/W) */
+
+/* 16550 register #2. Not multiplexed. */
+#define com_fcr 2 /* FIFO control register (W) */
+#define com_fifo com_fcr
+#define REG_FCR com_fcr
+#define FCR_ENABLE 0x01
+#define FIFO_ENABLE FCR_ENABLE
+#define FCR_RCV_RST 0x02
+#define FIFO_RCV_RST FCR_RCV_RST
+#define FCR_XMT_RST 0x04
+#define FIFO_XMT_RST FCR_XMT_RST
+#define FCR_DMA 0x08
+#define FIFO_DMA_MODE FCR_DMA
+#define FCR_RX_LOW 0x00
+#define FIFO_RX_LOW FCR_RX_LOW
+#define FCR_RX_MEDL 0x40
+#define FIFO_RX_MEDL FCR_RX_MEDL
+#define FCR_RX_MEDH 0x80
+#define FIFO_RX_MEDH FCR_RX_MEDH
+#define FCR_RX_HIGH 0xc0
+#define FIFO_RX_HIGH FCR_RX_HIGH
+
+#define FCR_BITS "\20\1ENABLE\2RCV_RST\3XMT_RST\4DMA"
+
+/* 16650 registers #2,[4-7]. Access enabled by LCR_EFR_ENABLE. */
+
+#define com_efr 2 /* enhanced features register (R/W) */
+#define REG_EFR com_efr
+#define EFR_CTS 0x80
+#define EFR_AUTOCTS EFR_CTS
+#define EFR_RTS 0x40
+#define EFR_AUTORTS EFR_RTS
+#define EFR_EFE 0x10 /* enhanced functions enable */
+
+#define com_xon1 4 /* XON 1 character (R/W) */
+#define com_xon2 5 /* XON 2 character (R/W) */
+#define com_xoff1 6 /* XOFF 1 character (R/W) */
+#define com_xoff2 7 /* XOFF 2 character (R/W) */
+
+#define com_usr 39 /* Octeon 16750/16550 Uart Status Reg */
+#define REG_USR com_usr
+#define USR_TXFIFO_NOTFULL 2 /* Uart TX FIFO Not full */
+
+/* 16950 register #1. Access enabled by ACR[7]. Also requires !LCR[7]. */
+#define com_asr 1 /* additional status register (R[0-7]/W[0-1]) */
+
+/* 16950 register #3. R/W access enabled by ACR[7]. */
+#define com_rfl 3 /* receiver fifo level (R) */
+
+/*
+ * 16950 register #4. Access enabled by ACR[7]. Also requires
+ * !LCR_EFR_ENABLE.
+ */
+#define com_tfl 4 /* transmitter fifo level (R) */
+
+/*
+ * 16950 register #5. Accessible if !LCR_EFR_ENABLE. Read access also
+ * requires ACR[6].
+ */
+#define com_icr 5 /* index control register (R/W) */
+
+/*
+ * 16950 register #7. It is the same as com_scr except it has a different
+ * abbreviation in the manufacturer's data sheet and it also serves as an
+ * index into the Indexed Control register set.
+ */
+#define com_spr com_scr /* scratch pad (and index) register (R/W) */
+#define REG_SPR com_scr
+
+/*
+ * 16950 indexed control registers #[0-0x13]. Access is via index in SPR,
+ * data in ICR (if ICR is accessible).
+ */
+
+#define com_acr 0 /* additional control register (R/W) */
+#define ACR_ASE 0x80 /* ASR/RFL/TFL enable */
+#define ACR_ICRE 0x40 /* ICR enable */
+#define ACR_TLE 0x20 /* TTL/RTL enable */
+
+#define com_cpr 1 /* clock prescaler register (R/W) */
+#define com_tcr 2 /* times clock register (R/W) */
+#define com_ttl 4 /* transmitter trigger level (R/W) */
+#define com_rtl 5 /* receiver trigger level (R/W) */
+/* ... */
+
+/* Hardware extension mode register for RSB-2000/3000. */
+#define com_emr com_msr
+#define EMR_EXBUFF 0x04
+#define EMR_CTSFLW 0x08
+#define EMR_DSRFLW 0x10
+#define EMR_RTSFLW 0x20
+#define EMR_DTRFLW 0x40
+#define EMR_EFMODE 0x80
+
+/* com port */
+#define COM1_ADDR 0x3f8
+#define COM2_ADDR 0x2f8
+#define COM3_ADDR 0x3e8
+#define COM4_ADDR 0x2e8
+
+#define GET_LCR_DATABIT(x) ({ \
+ typeof(x) val = 0; \
+ val = (((x) == 5) ? LCR_5BITS : (val)); \
+ val = (((x) == 6) ? LCR_6BITS : (val)); \
+ val = (((x) == 7) ? LCR_7BITS : (val)); \
+ val = (((x) == 8) ? LCR_8BITS : (val)); \
+ val; })
+
+#define GET_LCR_STOPBIT(x) ({ \
+ typeof(x) val = 0; \
+ val = (((x) > 1) ? LCR_STOPB : val); \
+ val; })
+
+#define GET_LCR_PARITY(x) ({ \
+ typeof(x) val = 0; \
+ val = (((x) == 'n') ? (!LCR_PENAB) : val); \
+ val = (((x) == 'o') ? LCR_ODD_PARITY : val); \
+ val = (((x) == 'e') ? LCR_EVEN_PARITY : val); \
+ val = (((x) == 'm') ? LCR_MARK_PARITY : val); \
+ val = (((x) == 's') ? LCR_SPACE_PARITY : val); \
+ val; })
+
+#define GET_LCR_VALUE(data, stop, parity) \
+ (GET_LCR_DATABIT(data) | GET_LCR_STOPBIT(stop) | GET_LCR_PARITY(parity))
+
+typedef struct __packed {
+ uint32_t bus;
+ uint32_t slot;
+ uint32_t func;
+} bdf_t;
+
+typedef struct __packed {
+ uint32_t comc_curspeed; /* baud rate */
+ uint32_t comc_clockhz; /* clock hz */
+ uint8_t comc_fmt; /* lcr value */
+ uint32_t comc_port; /* serial port, COM[1|2|3|4] */
+ uint32_t comc_irq; /* irq */
+ bdf_t comc_psbdf; /* PCI serial controller bdf */
+ bdf_t comc_pbbdf; /* PCI bridge bdf */
+} serial_port_t;
+
+void comc_init(void);
+void comc_puts(const char*, unsigned int);
+
+#endif /* __COM_H__ */
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/compiler.h b/tboot/include/compiler.h
new file mode 100644
index 0000000..8987161
--- /dev/null
+++ b/tboot/include/compiler.h
@@ -0,0 +1,52 @@
+/*
+ * compiler.h: These are various compiler-related defines
+ *
+ * Copyright (c) 2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __COMPILER_H__
+#define __COMPILER_H__
+
+#define inline __inline__
+#define always_inline __inline__ __attribute__ ((always_inline))
+
+#endif /* __COMPILER_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/config.h b/tboot/include/config.h
new file mode 100644
index 0000000..9f9d8d1
--- /dev/null
+++ b/tboot/include/config.h
@@ -0,0 +1,133 @@
+/*
+ * config.h: project-wide definitions
+ *
+ * Copyright (c) 2006-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+
+/* EFI and MLE layout values */
+/* TODO MLE should cover .rdata too. Address that later */
+
+/**********************************************************
+ * TBOOT rumtime layout
+ *
+ * +---------------+ 0xXXXX0000
+ * | | Post Launch page tables
+ * | PLETP | 4K pages below 2M
+ * | | 2M pages below 4G
+ * +---------------+ 0xXXXX7000
+ * | MLEPT | Measure Launch page tables
+ * | | Cover MLE/.text section
+ * +---------------+ 0xXXXXA000
+ * | PE HDR |
+ * +---------------+ 0xXXXXB000
+ * | |
+ * | MLE | The MLE/.text section.
+ * | |
+ * +---------------+
+ * | |
+ * | DATA |
+ * | SHATED | The rest of the TBOOT image.
+ * | ETC |
+ * | |
+ * +---------------+
+ *
+ **********************************************************/
+
+/* Somewhere just below 4G */
+#define TBOOT_MAX_IMAGE_MEM 0xfffff000
+
+/* TBOOT post launch page table block */
+#define TBOOT_PLEPT_COUNT (7)
+#define TBOOT_PLEPT_SIZE (TBOOT_PLEPT_COUNT*PAGE_SIZE)
+
+/* TBOOT MLE page table block */
+#define TBOOT_MLEPT_COUNT (3)
+#define TBOOT_MLEPT_SIZE (TBOOT_MLEPT_COUNT*PAGE_SIZE)
+
+/* Totals */
+#define TBOOT_RTMEM_COUNT (TBOOT_PLEPT_COUNT + TBOOT_MLEPT_COUNT)
+#define TBOOT_RTMEM_SIZE (TBOOT_PLEPT_SIZE + TBOOT_MLEPT_SIZE)
+
+#ifndef NR_CPUS
+#define NR_CPUS 512
+#endif
+
+#ifdef __ASSEMBLY__
+#define ENTRY(name) \
+ .globl name; \
+ .align 16,0x90; \
+ name:
+#endif
+
+#define COMPILE_TIME_ASSERT(e) \
+{ \
+ struct tmp { \
+ int a : ((e) ? 1 : -1); \
+ }; \
+}
+
+#define __data __attribute__ ((__section__ (".data#")))
+#define __text __attribute__ ((__section__ (".text#")))
+
+#define __packed __attribute__ ((packed))
+
+/* tboot log level */
+#ifdef NO_TBOOT_LOGLVL
+#define TBOOT_NONE
+#define TBOOT_ERR
+#define TBOOT_WARN
+#define TBOOT_INFO
+#define TBOOT_DETA
+#define TBOOT_ALL
+#else /* NO_TBOOT_LOGLVL */
+#define TBOOT_NONE "<0>"
+#define TBOOT_ERR "<1>"
+#define TBOOT_WARN "<2>"
+#define TBOOT_INFO "<3>"
+#define TBOOT_DETA "<4>"
+#define TBOOT_ALL "<5>"
+#endif /* NO_TBOOT_LOGLVL */
+
+#endif /* __CONFIG_H__ */
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/ctype.h b/tboot/include/ctype.h
new file mode 100644
index 0000000..20d6769
--- /dev/null
+++ b/tboot/include/ctype.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __CTYPE_H__
+#define __CTYPE_H__
+
+#include <stdbool.h>
+#include <types.h>
+#include <compiler.h>
+
+/* from:
+ * http://fxr.watson.org/fxr/source/dist/acpica/acutils.h?v=NETBSD5
+*/
+#define CTYPE_SIZE 257
+const uint8_t _ctype[CTYPE_SIZE];
+
+#define _XA 0x00 /* extra alphabetic - not supported */
+#define _XS 0x40 /* extra space */
+#define _BB 0x00 /* BEL, BS, etc. - not supported */
+#define _CN 0x20 /* CR, FF, HT, NL, VT */
+#define _DI 0x04 /* ''-'9' */
+#define _LO 0x02 /* 'a'-'z' */
+#define _PU 0x10 /* punctuation */
+#define _SP 0x08 /* space */
+#define _UP 0x01 /* 'A'-'Z' */
+#define _XD 0x80 /* ''-'9', 'A'-'F', 'a'-'f' */
+
+static always_inline bool isdigit(int c)
+{
+ return (_ctype[(unsigned char)(c)] & (_DI));
+}
+static always_inline bool isspace(int c)
+{
+ return (_ctype[(unsigned char)(c)] & (_SP));
+}
+static always_inline bool isxdigit(int c)
+{
+ return (_ctype[(unsigned char)(c)] & (_XD));
+}
+static always_inline bool isupper(int c)
+{
+ return (_ctype[(unsigned char)(c)] & (_UP));
+}
+static always_inline bool islower(int c)
+{
+ return (_ctype[(unsigned char)(c)] & (_LO));
+}
+static always_inline bool isprint(int c)
+{
+ return (_ctype[(unsigned char)(c)] & (_LO | _UP | _DI |
+ _SP | _PU));
+}
+static always_inline bool isalpha(int c)
+{
+ return (_ctype[(unsigned char)(c)] & (_LO | _UP));
+}
+static always_inline bool iscntrl(int c)
+{
+ return (_ctype[(unsigned char)(c)] & (_CN));
+}
+
+
+#endif /* __CTYPE_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/efibase.h b/tboot/include/efibase.h
new file mode 100644
index 0000000..7138b79
--- /dev/null
+++ b/tboot/include/efibase.h
@@ -0,0 +1,46 @@
+/*
+ * efibase.h: EFI base includes.
+ *
+ * Copyright (c) 2017 Assured Information Security.
+ *
+ * Ross Philipson <philipsonr@ainfosec.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __EFIBASE_H__
+#define __EFIBASE_H__
+
+#include <efi.h>
+#include <efilib.h>
+#include <efirtlib.h>
+
+#include <efivar.h>
+#include <efigpt.h>
+
+#endif /* __EFIBASE_H__ */
diff --git a/tboot/include/eficonfig.h b/tboot/include/eficonfig.h
new file mode 100644
index 0000000..fc2cf16
--- /dev/null
+++ b/tboot/include/eficonfig.h
@@ -0,0 +1,109 @@
+/*
+ * eficonfig.h: EFI related config definitions.
+ *
+ * Copyright (c) 2017 Assured Information Security.
+ *
+ * Ross Philipson <philipsonr@ainfosec.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __EFI_CONFIG_H__
+#define __EFI_CONFIG_H__
+
+#define EFI_MAX_PATH 512
+#define EFI_MAX_CONFIG_FILE 1024 /* plenty of room for a config file */
+
+/* TBOOT config */
+#define SECTION_TBOOT "tboot"
+# define ITEM_OPTIONS "options"
+# define ITEM_XENPATH "xenpath"
+# define ITEM_LCP "lcp"
+#define SECTION_ACM "acm"
+#define SECTION_RACM "racm"
+
+/* Xen config */
+#define SECTION_GLOBAL "global"
+# define ITEM_DEFAULT "default"
+# define ITEM_KERNEL "kernel"
+
+enum {
+ EFI_CONFIG_TBOOT = 0,
+ EFI_CONFIG_TBOOT_PARSED,
+ EFI_CONFIG_XEN,
+ EFI_CONFIG_XEN_PARSED,
+ EFI_CONFIG_MAX
+};
+
+typedef struct {
+ union {
+ char *buffer;
+ EFI_PHYSICAL_ADDRESS addr;
+ } u;
+ uint64_t size;
+} efi_file_t;
+
+wchar_t g_tboot_dir[EFI_MAX_PATH];
+bool g_post_ebs;
+const char *g_kernel_cmdline;
+
+/* Locations of runtime offsets */
+void *g_rtmem_base;
+void *g_image_base;
+uint64_t g_image_size;
+void *g_text_base;
+uint64_t g_text_size;
+void *g_bss_base;
+uint64_t g_bss_size;
+
+void efi_cfg_init(void);
+efi_file_t *efi_get_configs(void);
+void efi_cfg_pre_parse(efi_file_t *config);
+char *efi_cfg_get_value(int index, const char *section,
+ const char *item);
+
+bool efi_split_kernel_line(void);
+bool efi_cfg_copy_tboot_path(const wchar_t *file_path);
+
+const efi_file_t *efi_get_platform_sinit(void);
+const efi_file_t *efi_get_platform_racm(void);
+const efi_file_t *efi_get_lcp(void);
+void efi_store_files(const efi_file_t *platform_sinit,
+ const efi_file_t *platform_racm,
+ const efi_file_t *lcp);
+
+const efi_file_t *efi_get_xen(void);
+const efi_file_t *efi_get_kernel(void);
+const efi_file_t *efi_get_ramdisk(void);
+const void *efi_get_memory_map(uint64_t *size_out, uint64_t *size_desc_out);
+uint64_t efi_get_xen_post_launch_cb(void);
+
+void efi_store_xen_info(void *base, uint64_t size);
+bool efi_store_xen_tboot_data(efi_xen_tboot_data_t *xtd);
+
+#endif /* __EFI_CONFIG_H__ */
diff --git a/tboot/include/eficore.h b/tboot/include/eficore.h
new file mode 100644
index 0000000..bea8694
--- /dev/null
+++ b/tboot/include/eficore.h
@@ -0,0 +1,134 @@
+/*
+ * eficore.h: EFI core support definitions.
+ *
+ * Copyright (c) 2017 Assured Information Security.
+ *
+ * Ross Philipson <philipsonr@ainfosec.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __EFICORE_H__
+#define __EFICORE_H__
+
+#define EFI_EARLY_PRINTK
+
+/* TODO debug only stuffs */
+#define EFI_DEBUG
+
+/* Shared RT variable between TBOOT and Xen */
+#define EFI_TBOOT_XEN_GUID \
+ { 0xf112e6cb, 0xce01, 0x4573, {0xa0, 0x52, 0xfb, 0xdb, 0x6c, 0xc0, 0xc7, 0xcb} }
+
+#define EFI_TBOOT_XEN_REV 1
+#define EFI_TBOOT_XEN_NAME L"TbootXenVar"
+
+/* Un-extern these that are defined in the GNU-EFI headers */
+EFI_SYSTEM_TABLE *ST;
+EFI_BOOT_SERVICES *BS;
+EFI_RUNTIME_SERVICES *RT;
+
+EFI_GUID EfiGlobalVariable;
+EFI_GUID NullGuid;
+EFI_GUID UnknownDevice;
+EFI_GUID DevicePathProtocol;
+EFI_GUID LoadedImageProtocol;
+EFI_GUID FileSystemProtocol;
+EFI_GUID GenericFileInfo;
+EFI_GUID AcpiTableGuid;
+EFI_GUID Acpi20TableGuid;
+EFI_GUID SMBIOSTableGuid;
+EFI_GUID TbootXenGuid;
+
+typedef void (*post_launch_t)(void *ets);
+
+typedef struct __packed efi_xen_tboot_data {
+ void *kernel;
+ uint64_t kernel_size;
+ void *ramdisk;
+ uint64_t ramdisk_size;
+ void *memory_map;
+ uint64_t memory_map_size;
+ uint64_t memory_desc_size;
+ uint64_t post_launch_cb;
+} efi_xen_tboot_data_t;
+
+typedef void (*begin_launch_t)(efi_xen_tboot_data_t *xtd);
+
+typedef struct __packed efi_tboot_xen_var {
+ uint64_t revision;
+ const char *xen_config;
+ uint64_t xen_config_size;
+ uint64_t begin_launch_cb;
+} efi_tboot_xen_var_t;
+
+/* The following routines are available before and after EBS */
+
+void atow(wchar_t *dst, const char *src, uint64_t count);
+bool wtoa(char *dst, const wchar_t *src, uint64_t count);
+uint64_t wcslen(const wchar_t *str);
+
+uint8_t *efi_get_rsdp(void);
+
+void *efi_get_pe_section(const char *name, void *image_base,
+ uint64_t *size_out);
+
+void efi_shutdown_system(uint32_t shutdown_type);
+
+/* The following routines are only available after EBS */
+
+bool efi_scan_memory_map(void);
+bool efi_add_resmap_entry(uint64_t addr, uint64_t length);
+bool efi_get_ram_ranges(uint64_t *min_lo_ram, uint64_t *max_lo_ram,
+ uint64_t *min_hi_ram, uint64_t *max_hi_ram);
+
+/* The following routines are unavailable after EBS */
+
+wchar_t *atow_alloc(const char *src);
+char *wtoa_alloc(const wchar_t *src);
+
+wchar_t *atow_cat(const wchar_t *base, const char *tail);
+
+void efi_puts(const char *s, unsigned int count);
+
+EFI_DEVICE_PATH *efi_get_device_path(const wchar_t *path,
+ EFI_HANDLE parent);
+EFI_STATUS efi_device_path_to_text(EFI_DEVICE_PATH *dev_path,
+ wchar_t *path_out,
+ uint64_t count);
+EFI_FILE_INFO *efi_get_file_info(EFI_FILE *target_file,
+ EFI_MEMORY_TYPE mem_type);
+EFI_STATUS efi_read_file(EFI_FILE_IO_INTERFACE *file_system,
+ wchar_t *file_name,
+ EFI_MEMORY_TYPE mem_type,
+ uint64_t *size_out,
+ EFI_PHYSICAL_ADDRESS *addr_out);
+
+void efi_launch_kernel(void);
+
+#endif /* __EFICORE_H__ */
diff --git a/tboot/include/hash.h b/tboot/include/hash.h
new file mode 100644
index 0000000..9d961e7
--- /dev/null
+++ b/tboot/include/hash.h
@@ -0,0 +1,123 @@
+/*
+ * hash.h: definition of and support fns for tb_hash_t type
+ *
+ * Copyright (c) 2006-2007, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __HASH_H__
+#define __HASH_H__
+
+#define TB_HALG_SHA1_LG 0x0000 /* legacy define for SHA1 */
+#define TB_HALG_SHA1 0x0004
+#define TB_HALG_SHA256 0x000B
+#define TB_HALG_SM3 0x0012
+#define TB_HALG_SHA384 0x000C
+#define TB_HALG_SHA512 0x000D
+#define TB_HALG_NULL 0x0010
+
+#define SHA1_LENGTH 20
+#define SHA256_LENGTH 32
+#define SM3_LENGTH 32
+#define SHA384_LENGTH 48
+#define SHA512_LENGTH 64
+
+typedef uint8_t sha1_hash_t[SHA1_LENGTH];
+typedef uint8_t sha256_hash_t[SHA256_LENGTH];
+typedef uint8_t sm3_hash_t[SM3_LENGTH];
+typedef uint8_t sha384_hash_t[SHA384_LENGTH];
+typedef uint8_t sha512_hash_t[SHA512_LENGTH];
+
+typedef union {
+ uint8_t sha1[SHA1_LENGTH];
+ uint8_t sha256[SHA256_LENGTH];
+ uint8_t sm3[SM3_LENGTH];
+ uint8_t sha384[SHA384_LENGTH];
+} tb_hash_t;
+
+static inline const char *hash_alg_to_string(uint16_t hash_alg)
+{
+ if ( hash_alg == TB_HALG_SHA1 || hash_alg == TB_HALG_SHA1_LG )
+ return "TB_HALG_SHA1";
+ else if ( hash_alg == TB_HALG_SHA256 )
+ return "TB_HALG_SHA256";
+ else if ( hash_alg == TB_HALG_SM3 )
+ return "TB_HALG_SM3";
+ else if ( hash_alg == TB_HALG_SHA384 )
+ return "TB_HALG_SHA384";
+ else if ( hash_alg == TB_HALG_SHA512 )
+ return "TB_HALG_SHA512";
+ else {
+ static char buf[32];
+ snprintf(buf, sizeof(buf), "unsupported (%u)", hash_alg);
+ return buf;
+ }
+}
+
+static inline unsigned int get_hash_size(uint16_t hash_alg)
+{
+ if ( hash_alg == TB_HALG_SHA1 || hash_alg == TB_HALG_SHA1_LG )
+ return SHA1_LENGTH;
+ else if ( hash_alg == TB_HALG_SHA256 )
+ return SHA256_LENGTH;
+ else if ( hash_alg == TB_HALG_SM3 )
+ return SM3_LENGTH;
+ else if ( hash_alg == TB_HALG_SHA384 )
+ return SHA384_LENGTH;
+ else if ( hash_alg == TB_HALG_SHA512 )
+ return SHA512_LENGTH;
+ else
+ return 0;
+}
+
+bool are_hashes_equal(const tb_hash_t *hash1, const tb_hash_t *hash2,
+ uint16_t hash_alg);
+bool hash_buffer(const unsigned char* buf, size_t size, tb_hash_t *hash,
+ uint16_t hash_alg);
+bool extend_hash(tb_hash_t *hash1, const tb_hash_t *hash2,
+ uint16_t hash_alg);
+void print_hash(const tb_hash_t *hash, uint16_t hash_alg);
+void copy_hash(tb_hash_t *dest_hash, const tb_hash_t *src_hash,
+ uint16_t hash_alg);
+
+
+#endif /* __HASH_H__ */
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/integrity.h b/tboot/include/integrity.h
new file mode 100644
index 0000000..1051e71
--- /dev/null
+++ b/tboot/include/integrity.h
@@ -0,0 +1,106 @@
+/*
+ * integrity.h: routines for memory integrity measurement &
+ * verification. Memory integrity is protected with tpm seal
+ *
+ * Copyright (c) 2007-2009, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _TBOOT_INTEGRITY_H_
+#define _TBOOT_INTEGRITY_H_
+
+#include <vmac.h>
+#include <hash.h>
+
+/*
+ * state that must be saved across S3 and will be sealed for integrity
+ * before extending PCRs and launching kernel
+ */
+#define MAX_VL_HASHES 32
+#define MAX_ALG_NUM 5
+
+typedef struct {
+ uint16_t alg;
+ tb_hash_t hash;
+} hash_entry_t;
+
+typedef struct {
+ uint32_t count;
+ hash_entry_t entries[MAX_ALG_NUM];
+} hash_list_t;
+
+typedef struct {
+ /* low and high memory regions to protect w/ VT-d PMRs */
+ uint64_t vtd_pmr_lo_base;
+ uint64_t vtd_pmr_lo_size;
+ uint64_t vtd_pmr_hi_base;
+ uint64_t vtd_pmr_hi_size;
+ /* VL policy at time of sealing */
+ tb_hash_t pol_hash;
+ /* verified launch measurements to be re-extended in DRTM PCRs
+ * a given PCR may have more than one hash and will get extended in the
+ * order it appears in the list */
+ uint8_t num_vl_entries;
+ struct {
+ uint8_t pcr;
+ hash_list_t hl;
+ } vl_entries[MAX_VL_HASHES];
+} pre_k_s3_state_t;
+
+/*
+ * state that must be saved across S3 and will be sealed for integrity
+ * just before entering S3 (after kernel shuts down)
+ */
+typedef struct {
+ uint64_t kernel_s3_resume_vector;
+ vmac_t kernel_integ;
+} post_k_s3_state_t;
+
+
+pre_k_s3_state_t g_pre_k_s3_state;
+post_k_s3_state_t g_post_k_s3_state;
+
+bool seal_pre_k_state(void);
+bool seal_post_k_state(void);
+bool verify_integrity(void);
+
+#endif /* _TBOOT_INTEGRITY_H_ */
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/io.h b/tboot/include/io.h
new file mode 100644
index 0000000..71ef0ad
--- /dev/null
+++ b/tboot/include/io.h
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+/*
+ * Portions copyright (c) 2010, Intel Corporation
+ */
+
+#ifndef __IO_H__
+#define __IO_H__
+
+/* from:
+ * $FreeBSD: src/sys/i386/include/cpufunc.h,v 1.158 2010/01/01 20:55:11 obrien Exp $
+ */
+
+/* modified to use tboot's types */
+
+#define readb(va) (*(volatile uint8_t *) (va))
+#define readw(va) (*(volatile uint16_t *) (va))
+#define readl(va) (*(volatile uint32_t *) (va))
+
+#define writeb(va, d) (*(volatile uint8_t *) (va) = (d))
+#define writew(va, d) (*(volatile uint16_t *) (va) = (d))
+#define writel(va, d) (*(volatile uint32_t *) (va) = (d))
+
+static inline uint8_t inb(uint16_t port)
+{
+ uint8_t data;
+
+ __asm volatile("inb %w1, %0" : "=a" (data) : "Nd" (port));
+ return (data);
+}
+
+static inline uint16_t inw(uint16_t port)
+{
+ uint16_t data;
+
+ __asm volatile("inw %w1, %0" : "=a" (data) : "Nd" (port));
+ return (data);
+}
+
+static inline uint32_t inl(uint16_t port)
+{
+ uint32_t data;
+
+ __asm volatile("inl %w1, %0" : "=a" (data) : "Nd" (port));
+ return (data);
+}
+
+static inline void outb(uint16_t port, uint8_t data)
+{
+ __asm __volatile("outb %0, %w1" : : "a" (data), "Nd" (port));
+}
+
+static inline void outw(uint16_t port, uint16_t data)
+{
+ __asm volatile("outw %0, %w1" : : "a" (data), "Nd" (port));
+}
+
+static inline void outl(uint16_t port, uint32_t data)
+{
+ __asm volatile("outl %0, %w1" : : "a" (data), "Nd" (port));
+}
+
+
+#endif /* __IO_H__ */
diff --git a/tboot/include/lcp3.h b/tboot/include/lcp3.h
new file mode 100644
index 0000000..4c717fe
--- /dev/null
+++ b/tboot/include/lcp3.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2014 Intel Corporation. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name Intel Corporation nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LCP_H__
+#define __LCP_H__
+
+#ifndef __packed
+#define __packed __attribute__ ((packed))
+#endif
+
+/*
+ * Version = 3.0 - new version format of LCP Policy. Major version
+ * is incremented since layout is incompatible with previous revision.
+ */
+
+/*--------- LCP UUID ------------*/
+#define LCP_POLICY_DATA_UUID {0xab0d1925, 0xeee7, 0x48eb, 0xa9fc, \
+ {0xb, 0xac, 0x5a, 0x26, 0x2d, 0xe}}
+
+/*--------- CUSTOM ELT UUID ------------*/
+#define LCP_CUSTOM_ELEMENT_TBOOT_UUID {0xc3930641, 0xe3cb, 0x4f40, 0x91d7, \
+ {0x27, 0xf8, 0xb9, 0xe2, 0x5c, 0x86}}
+
+/*--------- LCP FILE SIGNATURE ------------*/
+#define LCP_POLICY_DATA_FILE_SIGNATURE "Intel(R) TXT LCP_POLICY_DATA\0\0\0\0"
+
+/*--------- LCP Policy Type ------------*/
+#define LCP_POLTYPE_LIST 0
+#define LCP_POLTYPE_ANY 1
+
+
+#define LCP_DEFAULT_POLICY_VERSION 0x0300
+#define LCP_DEFAULT_POLICY_CONTROL 0x00
+
+#define LCP_MAX_LISTS 8
+
+
+/*--------- with LCP_POLICY version 2.0 ------------*/
+#define SHA1_LENGTH 20
+#define SHA256_LENGTH 32
+
+typedef union {
+ uint8_t sha1[SHA1_LENGTH];
+ uint8_t sha256[SHA256_LENGTH];
+} lcp_hash_t;
+
+#define LCP_POLSALG_NONE 0
+#define LCP_POLSALG_RSA_PKCS_15 1
+
+#define LCP_SIG_EXPONENT 65537
+
+typedef struct __packed {
+ uint16_t revocation_counter;
+ uint16_t pubkey_size;
+ uint8_t pubkey_value[0];
+ uint8_t sig_block[];
+} lcp_signature_t;
+
+/* set bit 0: override PS policy for this element type */
+#define DEFAULT_POL_ELT_CONTROL 0x0001
+typedef struct __packed {
+ uint32_t size;
+ uint32_t type;
+ uint32_t policy_elt_control;
+ uint8_t data[];
+} lcp_policy_element_t;
+
+#define LCP_POLELT_TYPE_CUSTOM 3
+typedef struct __packed {
+ uuid_t uuid;
+ uint8_t data[];
+} lcp_custom_element_t;
+
+#define LCP_DEFAULT_POLICY_LIST_VERSION 0x0200
+#define LCP_TPM12_POLICY_LIST_VERSION 0x0100
+#define LCP_TPM20_POLICY_LIST_VERSION 0x0200
+typedef struct __packed {
+ uint16_t version; /* = 1.0 */
+ uint8_t reserved;
+ uint8_t sig_alg;
+ uint32_t policy_elements_size;
+ lcp_policy_element_t policy_elements[];
+ /* optionally: */
+ /* lcp_signature_t sig; */
+} lcp_policy_list_t;
+
+#define LCP_FILE_SIG_LENGTH 32
+typedef struct __packed {
+ char file_signature[LCP_FILE_SIG_LENGTH];
+ uint8_t reserved[3];
+ uint8_t num_lists;
+ lcp_policy_list_t policy_lists[];
+} lcp_policy_data_t;
+
+#define LCP_DEFAULT_POLICY_VERSION_2 0x0202
+typedef struct __packed {
+ uint16_t version;
+ uint8_t hash_alg; /* one of LCP_POLHALG_* */
+ uint8_t policy_type; /* one of LCP_POLTYPE_* */
+ uint8_t sinit_min_version;
+ uint8_t reserved1;
+ uint16_t data_revocation_counters[LCP_MAX_LISTS];
+ uint32_t policy_control;
+ uint32_t reserved2[2];
+ lcp_hash_t policy_hash;
+} lcp_policy_t;
+
+
+/*--------- LCP_POLICY version 3.0 ------------*/
+#define TPM_ALG_SHA1 0x0004
+#define TPM_ALG_SHA256 0x000B
+#define TPM_ALG_SHA384 0x000C
+#define TPM_ALG_SHA512 0x000D
+#define TPM_ALG_NULL 0x0010
+#define TPM_ALG_SM3_256 0x0012
+
+#define TPM_ALG_RSASSA 0x0014
+#define TPM_ALG_ECDSA 0x0018
+#define TPM_ALG_SM2 0x001B
+
+#define SHA1_DIGEST_SIZE 20
+#define SHA256_DIGEST_SIZE 32
+#define SHA384_DIGEST_SIZE 48
+#define SHA512_DIGEST_SIZE 64
+#define SM3_256_DIGEST_SIZE 32
+
+typedef union {
+ uint8_t sha1[SHA1_DIGEST_SIZE];
+ uint8_t sha256[SHA256_DIGEST_SIZE];
+ uint8_t sha384[SHA384_DIGEST_SIZE];
+ uint8_t sha512[SHA512_DIGEST_SIZE];
+ uint8_t sm3[SM3_256_DIGEST_SIZE];
+} lcp_hash_t2;
+
+typedef struct __packed {
+ uint16_t hash_alg;
+ uint8_t size_of_select;
+ uint8_t pcr_select[];
+} tpms_pcr_selection_t;
+
+typedef struct __packed {
+ uint32_t count;
+ tpms_pcr_selection_t pcr_selections;
+} tpml_pcr_selection_t;
+
+typedef struct __packed {
+ uint16_t size;
+ uint8_t buffer[];
+} tpm2b_digest_t;
+
+typedef struct __packed {
+ tpml_pcr_selection_t pcr_selection;
+ tpm2b_digest_t pcr_digest;
+} tpms_quote_info_t;
+
+#define LCP_POLELT_TYPE_MLE2 0x10
+typedef struct __packed {
+ uint8_t sinit_min_version;
+ uint8_t reserved;
+ uint16_t hash_alg;
+ uint16_t num_hashes;
+ lcp_hash_t2 hashes[];
+} lcp_mle_element_t2;
+
+#define LCP_POLELT_TYPE_PCONF2 0x11
+typedef struct __packed {
+ uint16_t hash_alg;
+ uint16_t num_pcr_infos;
+ tpms_quote_info_t prc_infos[];
+} lcp_pconf_element_t2;
+
+#define LCP_POLELT_TYPE_SBIOS2 0x12
+typedef struct __packed {
+ uint16_t hash_alg;
+ uint8_t reserved1[2];
+ lcp_hash_t2 fallback_hash;
+ uint16_t reserved2;
+ uint16_t num_hashes;
+ lcp_hash_t2 hashes[];
+} lcp_sbios_element_t2;
+
+#define LCP_POLELT_TYPE_CUSTOM2 0x13
+typedef struct __packed {
+ uuid_t uuid;
+ uint8_t data[];
+} lcp_custom_element_t2;
+
+#define LCP_POLELT_TYPE_STM2 0x14
+typedef struct __packed {
+ uint16_t hash_alg;
+ uint16_t num_hashes;
+ lcp_hash_t2 hashes[];
+} lcp_stm_element_t2;
+
+typedef struct __packed {
+ uint16_t version; /* = 3.0 */
+ uint16_t hash_alg; /* one of LCP_POLHALG_* */
+ uint8_t policy_type; /* one of LCP_POLTYPE_* */
+ uint8_t sinit_min_version;
+ uint16_t data_revocation_counters[LCP_MAX_LISTS];
+ uint32_t policy_control;
+ uint8_t max_sinit_min_ver; /* Defined for PO only. Reserved for PS */
+ uint8_t max_biosac_min_ver; /* Defined for PO only. Reserved for PS */
+ uint16_t lcp_hash_alg_mask; /* Mask of approved algorithms for LCP evaluation */
+ uint32_t lcp_sign_alg_mask; /* Mask of approved signature algorithms for LCP evaluation */
+ uint16_t aux_hash_alg_mask; /* Approved algorithm for auto - promotion hash */
+ uint16_t reserved2;
+ lcp_hash_t2 policy_hash;
+} lcp_policy_t2;
+
+typedef struct __packed {
+ uint16_t revocation_counter;
+ uint16_t pubkey_size;
+ uint8_t pubkey_value[0];
+ uint8_t sig_block[];
+} lcp_rsa_signature_t;
+
+typedef struct __packed {
+ uint16_t revocation_counter;
+ uint16_t pubkey_size;
+ uint32_t reserved;
+ uint8_t qx[0];
+ uint8_t qy[0];
+ uint8_t r[0];
+ uint8_t s[0];
+} lcp_ecc_signature_t;
+
+typedef union __packed {
+ lcp_rsa_signature_t rsa_signature;
+ lcp_ecc_signature_t ecc_signature;
+} lcp_signature_t2;
+
+typedef struct __packed {
+ uint16_t version; /* = 2.0 */
+ uint16_t sig_alg;
+ uint32_t policy_elements_size;
+ lcp_policy_element_t policy_elements[];
+//#if (sig_alg != TPM_ALG_NULL)
+// lcp_signature_t sig;
+//#endif
+} lcp_policy_list_t2;
+
+typedef union __packed {
+ lcp_policy_list_t tpm12_policy_list;
+ lcp_policy_list_t2 tpm20_policy_list;
+} lcp_list_t;
+
+typedef struct __packed {
+ char file_signature[32];
+ uint8_t reserved[3];
+ uint8_t num_lists;
+ lcp_list_t policy_lists[];
+} lcp_policy_data_t2;
+
+#endif /* __LCP_H__ */
diff --git a/tboot/include/lcp3_hlp.h b/tboot/include/lcp3_hlp.h
new file mode 100644
index 0000000..92061e4
--- /dev/null
+++ b/tboot/include/lcp3_hlp.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2014 Intel Corporation. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name Intel Corporation nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __TXT_LCP2_HELPER_H__
+#define __TXT_LCP2_HELPER_H__
+
+static inline lcp_signature_t *get_tpm12_signature(const lcp_policy_list_t *pollist)
+{
+ if ( pollist == NULL )
+ return NULL;
+
+ if ( pollist->sig_alg != LCP_POLSALG_RSA_PKCS_15 )
+ return NULL;
+
+ return (lcp_signature_t *)((const void *)&pollist->policy_elements +
+ pollist->policy_elements_size);
+}
+
+static inline size_t get_tpm12_signature_size(const lcp_signature_t *sig)
+{
+ if ( sig == NULL )
+ return 0;
+
+ return offsetof(lcp_signature_t, pubkey_value) + 2*sig->pubkey_size;
+}
+
+static inline size_t get_tpm12_policy_list_size(const lcp_policy_list_t *pollist)
+{
+ size_t size = 0;
+
+ if ( pollist == NULL )
+ return 0;
+
+ size = offsetof(lcp_policy_list_t, policy_elements) +
+ pollist->policy_elements_size;
+
+ /* add sig size */
+ if ( pollist->sig_alg == LCP_POLSALG_RSA_PKCS_15 )
+ size += get_tpm12_signature_size(get_tpm12_signature(pollist));
+
+ return size;
+}
+
+static inline lcp_signature_t2 *get_tpm20_signature(const lcp_policy_list_t2 *pollist)
+{
+ if ( pollist == NULL || pollist->sig_alg == TPM_ALG_NULL )
+ return NULL;
+
+ return (lcp_signature_t2 *)((const void *)&pollist->policy_elements +
+ pollist->policy_elements_size);
+}
+
+static inline size_t get_tpm20_signature_size(const lcp_signature_t2 *sig,
+ const uint16_t sig_alg)
+{
+ if ( sig == NULL )
+ return 0;
+
+ if ( sig_alg == TPM_ALG_RSASSA)
+ return offsetof(lcp_rsa_signature_t, pubkey_value) +
+ 2*sig->rsa_signature.pubkey_size;
+ else if ( sig_alg == TPM_ALG_ECDSA)
+ return offsetof(lcp_ecc_signature_t, qx) +
+ 2*sig->ecc_signature.pubkey_size;
+
+ return 0;
+}
+
+static inline size_t get_tpm20_policy_list_size(const lcp_policy_list_t2 *pollist)
+{
+ size_t size = 0;
+
+ if ( pollist == NULL )
+ return 0;
+
+ size = offsetof(lcp_policy_list_t2, policy_elements) +
+ pollist->policy_elements_size;
+
+ /* add sig size */
+ if ( pollist->sig_alg == TPM_ALG_RSASSA ||
+ pollist->sig_alg == TPM_ALG_ECDSA ||
+ pollist->sig_alg == TPM_ALG_SM2 )
+ size += get_tpm20_signature_size(get_tpm20_signature(pollist),
+ pollist->sig_alg);
+
+ return size;
+}
+
+
+#endif /* __TXT_LCP3_HELPER_H__ */
diff --git a/tboot/include/misc.h b/tboot/include/misc.h
new file mode 100644
index 0000000..6c118c0
--- /dev/null
+++ b/tboot/include/misc.h
@@ -0,0 +1,95 @@
+/*
+ * misc.h: miscellaneous support fns
+ *
+ * Copyright (c) 2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __MISC_H__
+#define __MISC_H__
+
+void print_hex(const char * buf, const void * prtptr, size_t size);
+
+void print_system_values(void);
+
+void print_test_chars(void);
+
+bool test_virt_to_phys(uint64_t vaddr);
+void dump_page_tables(void);
+
+void delay(int millisecs);
+
+/*
+ * These three "plus overflow" functions take a "x" value
+ * and add the "y" value to it and if the two values are
+ * greater than the size of the variable type, they will
+ * overflow the type and end up with a smaller value and
+ * return TRUE - that they did overflow. i.e.
+ * x + y <= variable type maximum.
+ */
+static inline bool plus_overflow_u64(uint64_t x, uint64_t y)
+{
+ return ((((uint64_t)(~0)) - x) < y);
+}
+
+static inline bool plus_overflow_u32(uint32_t x, uint32_t y)
+{
+ return ((((uint32_t)(~0)) - x) < y);
+}
+
+/*
+ * This checks to see if two numbers multiplied together are larger
+ * than the type that they are. Returns TRUE if OVERFLOWING.
+ * If the first parameter "x" is greater than zero and
+ * if that is true, that the largest possible value 0xFFFFFFFF / "x"
+ * is less than the second parameter "y". If "y" is zero then
+ * it will also fail because no unsigned number is less than zero.
+ */
+static inline bool multiply_overflow_u32(uint32_t x, uint32_t y)
+{
+ return (x > 0) ? ((((uint32_t)(~0))/x) < y) : false;
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+#define AP_WAKE_TRIGGER_DEF 0xffffffff
+
+#endif /* __MISC_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/mle.h b/tboot/include/mle.h
new file mode 100644
index 0000000..c0d7386
--- /dev/null
+++ b/tboot/include/mle.h
@@ -0,0 +1,96 @@
+/*
+ * mle.h: Intel(r) TXT MLE header definition
+ *
+ * Copyright (c) 2003-2008, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __MLE_H__
+#define __MLE_H__
+
+/*
+ * SINIT/MLE capabilities
+ */
+typedef union {
+ uint32_t _raw;
+ struct {
+ uint32_t rlp_wake_getsec : 1;
+ uint32_t rlp_wake_monitor : 1;
+ uint32_t ecx_pgtbl : 1;
+ uint32_t stm : 1;
+ uint32_t pcr_map_no_legacy : 1;
+ uint32_t pcr_map_da : 1;
+ uint32_t platform_type : 2;
+ uint32_t max_phy_addr : 1;
+ uint32_t reserved1 : 23;
+ };
+} txt_caps_t;
+
+
+/*
+ * MLE header structure
+ * describes an MLE for SINIT and OS/loader SW
+ */
+typedef struct {
+ uuid_t uuid;
+ uint32_t length;
+ uint32_t version;
+ uint32_t entry_point;
+ uint32_t first_valid_page;
+ uint32_t mle_start_off;
+ uint32_t mle_end_off;
+ txt_caps_t capabilities;
+ uint32_t cmdline_start_off;
+ uint32_t cmdline_end_off;
+} mle_hdr_t;
+
+#define MLE_HDR_UUID {0x9082ac5a, 0x476f, 0x74a7, 0x5c0f, \
+ {0x55, 0xa2, 0xcb, 0x51, 0xb6, 0x42}}
+
+/*
+ * values supported by current version of tboot
+ */
+#define MLE_HDR_VER 0x00020001 /* 2.1 */
+#define MLE_HDR_CAPS 0x00000027 /* rlp_wake_{getsec, monitor} = 1,
+ ecx_pgtbl = 1, nolg = 0, da = 1 */
+
+#endif /* __MLE_H__ */
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/msr.h b/tboot/include/msr.h
new file mode 100644
index 0000000..70f1a32
--- /dev/null
+++ b/tboot/include/msr.h
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+/*
+ * Portions copyright (c) 2010-2011, Intel Corporation
+ */
+
+
+#ifndef __MSR_H__
+#define __MSR_H__
+
+/* N.B. see processor.h, rd/wrmsr got moved and are not implemented as inline
+ * asm any longer.
+ */
+
+/*
+ * from: @(#)specialreg.h 7.1 (Berkeley) 5/9/91
+ * $FreeBSD: src/sys/i386/include/specialreg.h,v 1.53.2.1.2.2 2009/11/06 17:09:04 attilio Exp $
+ */
+
+#define MSR_IA32_PLATFORM_ID 0x017
+#define MSR_APICBASE 0x01b
+#define MSR_IA32_FEATURE_CONTROL 0x03a
+#define MSR_IA32_SMM_MONITOR_CTL 0x09b
+#define MSR_MTRRcap 0x0fe
+#define MSR_MCG_CAP 0x179
+#define MSR_MCG_STATUS 0x17a
+#define MSR_IA32_MISC_ENABLE 0x1a0
+#define MSR_IA32_MISC_ENABLE_MONITOR_FSM (1<<18)
+#define MSR_MTRRdefType 0x2ff
+#define MSR_MC0_STATUS 0x401
+#define MSR_IA32_VMX_BASIC_MSR 0x480
+#define MSR_IA32_VMX_PINBASED_CTLS_MSR 0x481
+#define MSR_IA32_VMX_PROCBASED_CTLS_MSR 0x482
+#define MSR_IA32_VMX_EXIT_CTLS_MSR 0x483
+#define MSR_IA32_VMX_ENTRY_CTLS_MSR 0x484
+#define MSR_IA32_SE_SVN_STATUS 0x500
+/*
+ * Constants related to MSR's.
+ */
+#define APICBASE_BSP 0x00000100
+
+#define MSR_IA32_SMM_MONITOR_CTL_VALID 1
+#define MSR_IA32_SMM_MONITOR_CTL_MSEG_BASE(x) (x>>12)
+
+/* MSRs & bits used for VMX enabling */
+#define IA32_FEATURE_CONTROL_MSR_LOCK 0x1
+#define IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_IN_SMX 0x2
+#define IA32_FEATURE_CONTROL_MSR_SENTER_PARAM_CTL 0x7f00
+#define IA32_FEATURE_CONTROL_MSR_ENABLE_SENTER 0x8000
+
+/* AMD64 MSR's */
+#define MSR_EFER 0xc0000080 /* extended features */
+
+/* EFER bits */
+#define _EFER_LME 8 /* Long mode enable */
+#define _EFER_LMA 10 /* Long mode active */
+
+#define MTRR_TYPE_UNCACHABLE 0
+#define MTRR_TYPE_WRTHROUGH 4
+#define MTRR_TYPE_WRBACK 6
+
+
+#endif /* __MSR_H__ */
diff --git a/tboot/include/mutex.h b/tboot/include/mutex.h
new file mode 100644
index 0000000..d61bd99
--- /dev/null
+++ b/tboot/include/mutex.h
@@ -0,0 +1,58 @@
+/* $OpenBSD: mutex.h,v 1.6 2009/04/27 21:48:56 kettenis Exp $ */
+/*
+ * Copyright (c) 2004 Artur Grabowski <art@openbsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Portions copyright (c) 2010, Intel Corporation
+ */
+
+#ifndef __MUTEX_H__
+#define __MUTEX_H__
+
+/*
+ * A mutex is:
+ * - owned by a cpu.
+ * - non-recursive.
+ * - spinning.
+ * - not providing mutual exclusion between processes, only cpus.
+ * - providing interrupt blocking when necessary.
+ *
+ * Different mutexes can be nested, but not interleaved. This is ok:
+ * "mtx_enter(foo); mtx_enter(bar); mtx_leave(bar); mtx_leave(foo);"
+ * This is _not_ ok:
+ * "mtx_enter(foo); mtx_enter(bar); mtx_leave(foo); mtx_leave(bar);"
+ */
+
+struct mutex {
+ __volatile__ uint64_t mtx_lock;
+};
+
+/*
+ * Some architectures need to do magic for the ipl, so they need a macro.
+ */
+void mtx_init(struct mutex *);
+void mtx_enter(struct mutex *);
+void mtx_leave(struct mutex *);
+
+#endif /* __MUTEX_H__ */
diff --git a/tboot/include/page.h b/tboot/include/page.h
new file mode 100644
index 0000000..b0588f6
--- /dev/null
+++ b/tboot/include/page.h
@@ -0,0 +1,66 @@
+/*
+ * page.h: definitions for page size/mask/shift/etc.
+ *
+ * Copyright (c) 2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __PAGE_H__
+#define __PAGE_H__
+
+/* From http://fxr.watson.org/fxr/source/i386/include/param.h */
+#define PAGE_SHIFT 12 /* LOG2(PAGE_SIZE) */
+#define PAGE_SIZE (1 << PAGE_SHIFT) /* bytes/page */
+/* PAGE_MASK is used to pass bits 12 and above. */
+#define PAGE_MASK (~(PAGE_SIZE-1))
+
+/* This is used to address the L2's 4MB pages */
+/* From figure 4-3 of IA64/IA32 Arch SDM vol 3A */
+#define FOURMB_PAGE_SHIFT 22
+
+/* macros to rounds things up/down to a page/pfn */
+#define PAGE_UP(p) (((unsigned long long)(p) + PAGE_SIZE- 1) & PAGE_MASK)
+#define PAGE_DOWN(p) ((unsigned long long)(p) & PAGE_MASK)
+#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
+#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+
+#endif /* __PAGE_H__ */
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/paging.h b/tboot/include/paging.h
new file mode 100644
index 0000000..7896824
--- /dev/null
+++ b/tboot/include/paging.h
@@ -0,0 +1,122 @@
+/*
+ * paging.h: Definitions for paging in tboot (PAE+PSE)
+ *
+ * Copyright (c) 2006-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __PAGING_H__
+#define __PAGING_H__
+
+/* direct map starts from 0, size 64M */
+#define DIRECTMAP_VIRT_START 0
+#define DIRECTMAP_VIRT_ORDER 26
+#define DIRECTMAP_VIRT_SIZE (1UL << DIRECTMAP_VIRT_ORDER)
+#define DIRECTMAP_VIRT_END (DIRECTMAP_VIRT_START + DIRECTMAP_VIRT_SIZE)
+
+/* MAC window starts from 0x80000000, size 1G */
+#define MAC_VIRT_START 0x80000000
+#define MAC_VIRT_ORDER 30
+#define MAC_VIRT_SIZE (1UL << MAC_VIRT_ORDER)
+#define MAC_VIRT_END (MAC_VIRT_START + MAC_VIRT_SIZE)
+
+/* PAE with 2-Mbyte Pages */
+#define TB_PAGETABLE_ORDER 9
+#define TB_L1_PAGETABLE_ENTRIES (1 << TB_PAGETABLE_ORDER)
+#define TB_L2_PAGETABLE_ENTRIES (1 << TB_PAGETABLE_ORDER)
+
+#define TB_L1_PAGETABLE_SHIFT 21
+#define TB_L2_PAGETABLE_SHIFT 30
+
+#define MAC_PAGE_SIZE (1UL << TB_L1_PAGETABLE_SHIFT)
+#define MAC_PAGE_MASK (~(MAC_PAGE_SIZE - 1))
+
+#define _PAGE_PRESENT 0x01
+#define _PAGE_RW 0x02
+#define _PAGE_SIZE 0x80
+
+
+#define MAKE_TB_PDE(paddr) \
+ (((uint64_t)(paddr) & ~0x00000000001FFFFF) | _PAGE_PRESENT \
+ | _PAGE_RW | _PAGE_SIZE)
+#define MAKE_TB_PDPTE(paddr) \
+ (((uint64_t)(paddr) & ~0x0000000000000FFF) | _PAGE_PRESENT)
+
+/* Given a virtual address, get an entry offset into a page table. */
+#define pd_table_offset(a) \
+ (((a) >> TB_L1_PAGETABLE_SHIFT) & (TB_L1_PAGETABLE_ENTRIES - 1))
+#define pdptr_table_offset(a) \
+ (((a) >> TB_L2_PAGETABLE_SHIFT) & (TB_L2_PAGETABLE_ENTRIES - 1))
+
+/* PAE: 52 bit physical address */
+#define PADDR_BIT 52
+#define PADDR_MASK ((1ULL << PADDR_BIT) - 1)
+
+/*
+ * PDE entry
+ * 31-bit pfn = pde[51:21]
+ * 13-bit flags = pde[12:0]
+ */
+#define PDE_FLAG_BIT 13
+#define PDE_FLAG_MASK ((1UL << PDE_FLAG_BIT) - 1)
+#define PDE_PADDR_MASK (PADDR_MASK & (~PDE_FLAG_MASK))
+#define get_pde_flags(pde) ((int)(pde) & PDE_FLAG_MASK)
+#define get_pde_paddr(pde) ((pde) & PDE_PADDR_MASK)
+
+/*
+ * PDPTE entry
+ * 40-bit pfn = pdptre[51:12]
+ * 12-bit flags = pdptre[11:0]
+ */
+#define PDPTE_FLAG_BIT 12
+#define PDPTE_FLAG_MASK ((1UL << PDPTE_FLAG_BIT) - 1)
+#define PDPTE_PADDR_MASK (PADDR_MASK & (~PDPTE_FLAG_MASK))
+#define get_pdptre_flags(pdptre) ((int)(pdptre) & PDPTE_FLAG_MASK)
+#define get_pdptre_paddr(pdptre) ((pdptre) & PDPTE_PADDR_MASK)
+
+void map_pages_to_tboot(unsigned long vstart,
+ unsigned long pfn,
+ unsigned long nr_pfns);
+void destroy_tboot_mapping(unsigned long vstart, unsigned long vend);
+bool enable_paging(void);
+bool disable_paging(void);
+
+#endif /* __PAGING_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/pci_cfgreg.h b/tboot/include/pci_cfgreg.h
new file mode 100644
index 0000000..d231e86
--- /dev/null
+++ b/tboot/include/pci_cfgreg.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/i386/include/pci_cfgreg.h,v 1.15.2.1.4.1 2010/06/14 02:09:06 kensmith Exp $
+ * $FreeBSD: src/sys/dev/pci/pcireg.h,v 1.72.2.4.2.1 2010/06/14 02:09:06 kensmith Exp $
+ */
+/*
+ * Portions copyright (c) 2010, Intel Corporation
+ */
+
+#ifndef __PCI_CFGREG_H__
+#define __PCI_CFGREG_H__
+
+#define PCI_BUSMAX 255 /* highest supported bus number */
+#define PCI_SLOTMAX 31 /* highest supported slot number */
+#define PCI_FUNCMAX 7 /* highest supported function number */
+#define PCI_REGMAX 255 /* highest supported config register addr. */
+
+#define CONF1_ADDR_PORT 0x0cf8
+#define CONF1_DATA_PORT 0x0cfc
+
+#define CONF1_ENABLE 0x80000000ul
+#define CONF1_ENABLE_CHK 0x80000000ul
+#define CONF1_ENABLE_MSK 0x7f000000ul
+#define CONF1_ENABLE_CHK1 0xff000001ul
+#define CONF1_ENABLE_MSK1 0x80000001ul
+#define CONF1_ENABLE_RES1 0x80000000ul
+
+#define CONF2_ENABLE_PORT 0x0cf8
+#define CONF2_FORWARD_PORT 0x0cfa
+
+#define CONF2_ENABLE_CHK 0x0e
+#define CONF2_ENABLE_RES 0x0e
+
+#define PCIR_COMMAND 0x04
+#define PCIR_BARS 0x10
+#define PCIR_IOBASEL_1 0x1c
+
+int pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
+void pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
+
+#endif /* __PCI_CFGREG_H__ */
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/printk.h b/tboot/include/printk.h
new file mode 100644
index 0000000..d72d2f2
--- /dev/null
+++ b/tboot/include/printk.h
@@ -0,0 +1,79 @@
+/*
+ * printk.h: printk to serial for very early boot stages
+ *
+ * Copyright (c) 2006-2010, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __PRINTK_H__
+#define __PRINTK_H__
+
+#include <com.h>
+#include <vga.h>
+
+#define TBOOT_LOGBUF_SIZE 256
+
+#define TBOOT_LOG_LEVEL_NONE 0x00
+#define TBOOT_LOG_LEVEL_ERR 0x01
+#define TBOOT_LOG_LEVEL_WARN 0x02
+#define TBOOT_LOG_LEVEL_INFO 0x04
+#define TBOOT_LOG_LEVEL_DETA 0x08
+#define TBOOT_LOG_LEVEL_ALL 0xFF
+
+#define TBOOT_LOG_TARGET_NONE 0x00
+#define TBOOT_LOG_TARGET_VGA 0x01
+#define TBOOT_LOG_TARGET_SERIAL 0x02
+#define TBOOT_LOG_TARGET_MEMORY 0x04
+#define TBOOT_LOG_TARGET_EFI 0x10
+
+uint8_t g_log_level;
+uint8_t g_log_targets;
+uint8_t g_vga_delay;
+serial_port_t g_com_port;
+
+#define serial_init() comc_init()
+#define serial_write(s, n) comc_puts(s, n)
+
+#define vga_write(s,n) vga_puts(s, n)
+
+#define efi_write(s,n) efi_puts(s, n)
+
+typedef enum {
+ INIT_EARLY_EFI,
+ INIT_PRE_LAUNCH,
+ INIT_POST_EBS,
+ INIT_POST_LAUNCH
+} printk_init_t;
+
+void printk_init(printk_init_t init_type);
+void printk(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+#endif
diff --git a/tboot/include/processor.h b/tboot/include/processor.h
new file mode 100644
index 0000000..83b9fe4
--- /dev/null
+++ b/tboot/include/processor.h
@@ -0,0 +1,340 @@
+/* Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+/*
+ * Portions copyright (c) 2010, Intel Corporation
+ */
+
+#ifndef __PROCESSOR_H__
+#define __PROCESSOR_H__
+
+/* from: @(#)specialreg.h 7.1 (Berkeley) 5/9/91
+ * $FreeBSD: stable/8/sys/i386/include/specialreg.h 198989 2009-11-06 15:24:48Z attilio $
+ */
+
+/*
+ * EFLAGS bits
+ */
+#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
+#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
+#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
+#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
+#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
+#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
+#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
+#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
+#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
+#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
+#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
+#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
+#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
+#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
+#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
+#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
+#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
+
+/*
+ * Bits in 386 special registers:
+ */
+#define CR0_PE 0x00000001 /* Protected mode Enable */
+#define CR0_MP 0x00000002 /* "Math" (fpu) Present */
+#define CR0_EM 0x00000004 /* EMulate FPU instructions. (trap ESC only) */
+#define CR0_TS 0x00000008 /* Task Switched (if MP, trap ESC and WAIT) */
+#define CR0_ET 0x00000010 /* Extension type */
+#define CR0_PG 0x80000000 /* PaGing enable */
+
+/*
+ * Bits in 486 special registers:
+ */
+#define CR0_NE 0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */
+#define CR0_WP 0x00010000 /* Write Protect (honor page protect in all modes) */
+#define CR0_AM 0x00040000 /* Alignment Mask (set to enable AC flag) */
+#define CR0_NW 0x20000000 /* Not Write-through */
+#define CR0_CD 0x40000000 /* Cache Disable */
+
+/*
+ * Bits in PPro special registers
+ */
+#define CR4_VME 0x00000001 /* Virtual 8086 mode extensions */
+#define CR4_PVI 0x00000002 /* Protected-mode virtual interrupts */
+#define CR4_TSD 0x00000004 /* Time stamp disable */
+#define CR4_DE 0x00000008 /* Debugging extensions */
+#define CR4_PSE 0x00000010 /* Page size extensions */
+#define CR4_PAE 0x00000020 /* Physical address extension */
+#define CR4_MCE 0x00000040 /* Machine check enable */
+#define CR4_PGE 0x00000080 /* Page global enable */
+#define CR4_PCE 0x00000100 /* Performance monitoring counter enable */
+#define CR4_FXSR 0x00000200/* Fast FPU save/restore used by OS */
+#define CR4_XMM 0x00000400 /* enable SIMD/MMX2 to use except 16 */
+#define CR4_VMXE 0x00002000/* enable VMX */
+#define CR4_SMXE 0x00004000/* enable SMX */
+#define CR4_PCIDE 0x00020000/* enable PCID */
+
+#ifndef __ASSEMBLY__
+
+/* from:
+ * $FreeBSD: src/sys/i386/include/cpufunc.h,v 1.158 2010/01/01 20:55:11 obrien Exp $
+ */
+
+static inline void do_cpuid(unsigned int ax, uint32_t *p)
+{
+ __asm__ __volatile__ ("cpuid"
+ : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
+ : "0" (ax));
+}
+
+static inline void do_cpuid1(unsigned int ax, unsigned int cx, uint32_t *p)
+{
+ __asm__ __volatile__ ("cpuid"
+ : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
+ : "0" (ax), "c" (cx));
+}
+
+static always_inline uint32_t cpuid_eax(unsigned int op)
+{
+ /* eax: regs[0], ebx: regs[1], ecx: regs[2], edx: regs[3] */
+ uint32_t regs[4];
+
+ do_cpuid(op, regs);
+
+ return regs[0];
+}
+
+static always_inline uint32_t cpuid_ebx(unsigned int op)
+{
+ /* eax: regs[0], ebx: regs[1], ecx: regs[2], edx: regs[3] */
+ uint32_t regs[4];
+
+ do_cpuid(op, regs);
+
+ return regs[1];
+}
+
+static always_inline uint32_t cpuid_ebx1(unsigned int op1, unsigned int op2)
+{
+ /* eax: regs[0], ebx: regs[1], ecx: regs[2], edx: regs[3] */
+ uint32_t regs[4];
+
+ do_cpuid1(op1, op2, regs);
+
+ return regs[1];
+}
+static always_inline uint32_t cpuid_ecx(unsigned int op)
+{
+ /* eax: regs[0], ebx: regs[1], ecx: regs[2], edx: regs[3] */
+ uint32_t regs[4];
+
+ do_cpuid(op, regs);
+
+ return regs[2];
+}
+
+#define CPUID_X86_FEATURE_XMM3 (1<<0)
+#define CPUID_X86_FEATURE_VMX (1<<5)
+#define CPUID_X86_FEATURE_SMX (1<<6)
+
+/* Note, removed read/write ecx, not used */
+
+static inline unsigned long long read_cr0(void)
+{
+ unsigned long long data;
+ /* 64: movl -> movq */
+ __asm__ __volatile__ ("movq %%cr0,%0" : "=r" (data));
+ return (data);
+}
+
+static inline void write_cr0(unsigned long long data)
+{
+ /* 64: movl -> movq */
+ __asm__ __volatile__("movq %0,%%cr0" : : "r" (data));
+}
+
+static inline unsigned long long read_cr4(void)
+{
+ unsigned long long data;
+ /* 64: movl -> movq */
+ __asm__ __volatile__ ("movq %%cr4,%0" : "=r" (data));
+ return (data);
+}
+
+static inline void write_cr4(unsigned long long data)
+{
+ /* 64: movl -> movq */
+ __asm__ __volatile__ ("movq %0,%%cr4" : : "r" (data));
+}
+
+static inline unsigned long long read_cr3(void)
+{
+ unsigned long long data;
+ /* 64: movl -> movq */
+ __asm__ __volatile__ ("movq %%cr3,%0" : "=r" (data));
+ return (data);
+}
+
+static inline void write_cr3(unsigned long long data)
+{
+ /* 64: movl -> movq */
+ __asm__ __volatile__("movq %0,%%cr3" : : "r" (data) : "memory");
+}
+
+static inline uint64_t read_rflags(void)
+{
+ uint64_t rf;
+ /* 32: EFLAGS stuff __asm__ __volatile__ ("pushfl; popl %0" : "=r" (ef));*/
+ __asm__ __volatile__ ("pushfq; popq %0" : "=r" (rf));
+ return (rf);
+}
+
+static inline void write_rflags(uint64_t rf)
+{
+ /* 32: EFLAGS stuff __asm__ __volatile__ ("pushl %0; popfl" : : "r" (ef));*/
+ __asm__ __volatile__ ("pushq %0; popfq" : : "r" (rf));
+}
+
+static inline void disable_intr(void)
+{
+ __asm__ __volatile__ ("cli" : : : "memory");
+}
+
+static inline void enable_intr(void)
+{
+ __asm__ __volatile__ ("sti");
+}
+
+/* was ia32_pause() */
+static inline void cpu_relax(void)
+{
+ __asm__ __volatile__ ("pause");
+}
+
+static inline void halt(void)
+{
+ __asm__ __volatile__ ("hlt");
+}
+
+static inline unsigned int get_apicid(void)
+{
+ return cpuid_ebx(1) >> 24;
+}
+
+static inline void wbinvd(void)
+{
+ __asm__ __volatile__ ("wbinvd");
+}
+
+static inline uint32_t bsrl(uint32_t mask)
+{
+ uint32_t result;
+
+ /* 64: Ok to shift 32b mask */
+ __asm__ __volatile__ ("bsrl %1,%0" : "=r" (result) : "rm" (mask) : "cc");
+ return (result);
+}
+
+static inline int fls(int mask)
+{
+ return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
+}
+
+static always_inline void mb(void)
+{
+ /* 32: __asm__ __volatile__ ("lock;addl $0,0(%%esp)" : : : "memory"); */
+ __asm__ __volatile__ ("lock;addq $0,0(%%rsp)" : : : "memory");
+}
+
+static inline void cpu_monitor(const void *addr, int extensions, int hints)
+{
+ /* 64: a=rax, c=rcx, d=rdx ints are 32b into ecx, edx */
+ __asm __volatile__ ("monitor;" : :"a" (addr), "c" (extensions), "d"(hints));
+}
+
+static inline void cpu_mwait(int extensions, int hints)
+{
+ /* 64: a=rax, c=rcx ints are 32b into eax, ecx */
+ __asm __volatile__ ("mwait;" : :"a" (hints), "c" (extensions));
+}
+
+static inline void flush_tlb(void)
+{
+ __asm__ __volatile__ (
+ "movq %%cr3, %%rax\n"
+ "movq %%rax, %%cr3\n"
+ : : : "rax");
+}
+
+typedef struct __packed lmode_desc {
+ uint16_t limit;
+ uint64_t base;
+} lmode_desc_t;
+
+static inline void store_gdt(lmode_desc_t *gdt)
+{
+ __asm__ __volatile__("sgdt %0\n\t"
+ : "=m" (*gdt) : : "memory");
+}
+
+static inline void store_idt(lmode_desc_t *idt)
+{
+ __asm__ __volatile__("sidt %0\n\t"
+ : "=m" (*idt): : "memory");
+}
+
+#define lea_reference(i, o) __asm__ __volatile__ \
+ ("lea "#i"(%%rip), %%rax\n\t" : "=a" (o))
+
+#define mov_sel(r, o) __asm__ __volatile__ \
+ ("movw %%"#r"s, %0\n\t" : "=m" (o) : : "memory");
+
+/* In inline asm, these 3 use the A constraint to specify the EDX:EAX register
+ * pair. The inline assembler was getting the code badly wrong so the
+ * implementation of these moved to the assembly module (and renamed).
+ */
+uint64_t read_msr(uint32_t msr);
+void write_msr(uint32_t msr, uint64_t newval);
+uint64_t read_tsc(void);
+
+uint64_t get_rip(void);
+uint64_t bsp_stack_ref(void);
+
+#define rdmsr read_msr
+#define wrmsr write_msr
+#define rdtsc read_tsc
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __PROCESSOR_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/rijndael.h b/tboot/include/rijndael.h
new file mode 100644
index 0000000..2974602
--- /dev/null
+++ b/tboot/include/rijndael.h
@@ -0,0 +1,58 @@
+/* $OpenBSD: rijndael.h,v 1.13 2008/06/09 07:49:45 djm Exp $ */
+
+/**
+ * rijndael-alg-fst.h
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __RIJNDAEL_H
+#define __RIJNDAEL_H
+
+#define AES_MAXKEYBITS (256)
+#define AES_MAXKEYBYTES (AES_MAXKEYBITS/8)
+/* for 256-bit keys, fewer for less */
+#define AES_MAXROUNDS 14
+
+//typedef unsigned char u8;
+//typedef unsigned short u16;
+//typedef unsigned int u32;
+
+/* The structure for key information */
+typedef struct {
+ int enc_only; /* context contains only encrypt schedule */
+ int Nr; /* key-length-dependent number of rounds */
+ u32 ek[4*(AES_MAXROUNDS + 1)]; /* encrypt key schedule */
+ u32 dk[4*(AES_MAXROUNDS + 1)]; /* decrypt key schedule */
+} rijndael_ctx;
+
+int rijndael_set_key(rijndael_ctx *, const u_char *, int);
+int rijndael_set_key_enc_only(rijndael_ctx *, const u_char *, int);
+void rijndael_decrypt(rijndael_ctx *, const u_char *, u_char *);
+void rijndael_encrypt(rijndael_ctx *, const u_char *, u_char *);
+
+int rijndaelKeySetupEnc(unsigned int [], const unsigned char [], int);
+int rijndaelKeySetupDec(unsigned int [], const unsigned char [], int);
+void rijndaelEncrypt(const unsigned int [], int, const unsigned char [],
+ unsigned char []);
+
+#endif /* __RIJNDAEL_H */
diff --git a/tboot/include/sha1.h b/tboot/include/sha1.h
new file mode 100644
index 0000000..10d89df
--- /dev/null
+++ b/tboot/include/sha1.h
@@ -0,0 +1,77 @@
+/*$FreeBSD: src/sys/crypto/sha1.h,v 1.8.36.1.2.1 2009/10/25 01:10:29 kensmith Exp $ */
+/*$KAME: sha1.h,v 1.5 2000/03/27 04:36:23 sumikawa Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Portions copyright (c) 2010, Intel Corporation
+ */
+
+/*
+ * FIPS pub 180-1: Secure Hash Algorithm (SHA-1)
+ * based on: http://csrc.nist.gov/fips/fip180-1.txt
+ * implemented by Jun-ichiro itojun Itoh <itojun@itojun.org>
+ */
+
+#ifndef __SHA1_H__
+#define __SHA1_H__
+
+struct sha1_ctxt {
+ union {
+ uint8_t b8[20];
+ uint32_t b32[5];
+ } h;
+ union {
+ uint8_t b8[8];
+ uint64_t b64[1];
+ } c;
+ union {
+ uint8_t b8[64];
+ uint32_t b32[16];
+ } m;
+ uint8_t count;
+};
+
+void sha1_init(struct sha1_ctxt *);
+void sha1_pad(struct sha1_ctxt *);
+void sha1_loop(struct sha1_ctxt *, const uint8_t *, size_t);
+void sha1_result(struct sha1_ctxt *, unsigned char *);
+#define SHA1_RESULTLEN (160/8)
+
+/* compatibilty with other SHA1 source codes */
+typedef struct sha1_ctxt SHA_CTX;
+#define SHA1_Init(x) sha1_init((x))
+#define SHA1_Update(x, y, z) sha1_loop((x), (y), (z))
+#define SHA1_Final(x, y) sha1_result((y), (x))
+#define SHA_DIGEST_LENGTH SHA1_RESULTLEN
+
+int sha1_buffer(const unsigned char *buffer, size_t len,
+ unsigned char md[SHA_DIGEST_LENGTH]);
+
+#endif /* __SHA1_H__ */
diff --git a/tboot/include/sha256.h b/tboot/include/sha256.h
new file mode 100644
index 0000000..2c3fc56
--- /dev/null
+++ b/tboot/include/sha256.h
@@ -0,0 +1,30 @@
+#ifndef __SHA256_H__
+#define __SHA256_H__
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define STORE32H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
+ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32H(x, y) \
+ { x = ((unsigned long)((y)[0] & 255)<<24) | \
+ ((unsigned long)((y)[1] & 255)<<16) | \
+ ((unsigned long)((y)[2] & 255)<<8) | \
+ ((unsigned long)((y)[3] & 255)); }
+
+typedef struct {
+ u64 length;
+ u32 state[8], curlen;
+ unsigned char buf[64];
+}sha256_state;
+
+void sha256_buffer(const unsigned char *buffer, size_t len,
+ unsigned char hash[32]);
+
+#endif /* __SHA256_H__ */
+
diff --git a/tboot/include/string.h b/tboot/include/string.h
new file mode 100644
index 0000000..30b571b
--- /dev/null
+++ b/tboot/include/string.h
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)libkern.h 8.1 (Berkeley) 6/10/93
+ * $FreeBSD: src/sys/sys/libkern.h,v 1.60 2009/02/14 11:34:57 rrs Exp $
+ */
+/*
+ * Portions copyright (c) 2010, Intel Corporation
+ */
+
+#ifndef __STRING_H__
+#define __STRING_H__
+
+#include <stdarg.h>
+#include <types.h>
+
+int memcmp(const void *b1, const void *b2, size_t len);
+char *index(const char *, int);
+int strcmp(const char *, const char *);
+size_t strlen(const char *);
+int strncmp(const char *, const char *, size_t);
+char *strncpy(char * __restrict, const char * __restrict, size_t);
+void *memcpy(void *dst, const void *src, size_t len);
+int snprintf(char *buf, size_t size, const char *fmt, ...);
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list ap);
+unsigned long strtoul(const char *nptr, char **endptr, int base);
+
+static inline void *memset(void *b, int c, size_t len)
+{
+ char *bb;
+
+ for (bb = (char *)b; len--; )
+ *bb++ = c;
+
+ return (b);
+}
+
+static inline void *memmove(void *dest, const void *src, size_t n)
+{
+ return memcpy(dest, src, n);
+}
+
+static __inline char *strchr(const char *p, int ch)
+{
+ return index(p, ch);
+}
+
+#endif /* __STRING_H__ */
diff --git a/tboot/include/tb_error.h b/tboot/include/tb_error.h
new file mode 100644
index 0000000..428fd51
--- /dev/null
+++ b/tboot/include/tb_error.h
@@ -0,0 +1,89 @@
+/*
+ * tb_error.h: error code definitions
+ *
+ * Copyright (c) 2006-2007, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TB_ERROR_H__
+#define __TB_ERROR_H__
+
+typedef enum {
+ TB_ERR_NONE = 0, /* succeed */
+ TB_ERR_FIXED = 1, /* previous error has been fixed */
+
+ TB_ERR_GENERIC, /* non-fatal generic error */
+
+ TB_ERR_TPM_NOT_READY, /* tpm not ready */
+ TB_ERR_SMX_NOT_SUPPORTED, /* smx not supported */
+ TB_ERR_VMX_NOT_SUPPORTED, /* vmx not supported */
+ TB_ERR_TXT_NOT_SUPPORTED, /* txt not supported */
+
+ TB_ERR_MODULE_VERIFICATION_FAILED, /* module failed to verify against
+ policy */
+ TB_ERR_MODULES_NOT_IN_POLICY, /* modules in mbi but not in
+ policy */
+ TB_ERR_POLICY_INVALID, /* policy is invalid */
+ TB_ERR_POLICY_NOT_PRESENT, /* no policy in TPM NV */
+
+ TB_ERR_SINIT_NOT_PRESENT, /* SINIT ACM not provided */
+ TB_ERR_ACMOD_VERIFY_FAILED, /* verifying AC module failed */
+
+ TB_ERR_POST_LAUNCH_VERIFICATION, /* verification of post-launch
+ failed */
+ TB_ERR_S3_INTEGRITY, /* creation or verification of
+ S3 integrity measurements
+ failed */
+
+ TB_ERR_FATAL, /* generic fatal error */
+ TB_ERR_NV_VERIFICATION_FAILED, /* NV failed to verify against
+ policy */
+ TB_ERR_MAX
+} tb_error_t;
+
+
+void print_tb_error_msg(tb_error_t error);
+bool read_tb_error_code(tb_error_t *error);
+bool write_tb_error_code(tb_error_t error);
+bool was_last_boot_error(void);
+
+
+#endif /* __TB_ERROR_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/tb_policy.h b/tboot/include/tb_policy.h
new file mode 100644
index 0000000..118a735
--- /dev/null
+++ b/tboot/include/tb_policy.h
@@ -0,0 +1,388 @@
+/*
+ * tb_policy.h: data structures, definitions, and helper fns for tboot
+ * verified launch policies
+ *
+ * Copyright (c) 2006-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TB_POLICY_H__
+#define __TB_POLICY_H__
+
+/*
+ * policy types
+ */
+enum {
+ TB_POLTYPE_CONT_NON_FATAL, /* ignore all non-fatal errors and */
+ /* continue */
+ TB_POLTYPE_CONT_VERIFY_FAIL, /* ignore verification errors and */
+ /* halt otherwise */
+ TB_POLTYPE_HALT, /* halt on any errors */
+ TB_POLTYPE_MAX
+};
+
+/*
+ * policy hash types
+ */
+enum {
+ TB_HTYPE_ANY,
+ TB_HTYPE_IMAGE,
+};
+
+
+#define TB_POL_MAX_MOD_NUM 127 /* largest supported module number */
+#define TB_POL_MOD_NUM_ANY 129 /* matches any module number */
+ /* (should be last entry of modules) */
+#define TB_POL_MOD_NUM_NV 130 /* indicate this is a nv index entry */
+#define TB_POL_MOD_NUM_NV_RAW 131 /* a nv entry verified by raw content */
+
+#define TB_POL_MAX_PCR 23 /* largest supported PCR number */
+#define TB_POL_PCR_NONE 255 /* don't extend measurement into a PCR */
+
+
+/*
+ * policies
+ */
+
+typedef struct __packed {
+ uint8_t mod_num; /* 0-based or TB_POL_MOD_NUM_* */
+ uint8_t pcr; /* PCR number (0-23) or TB_POL_PCR_* */
+ uint8_t hash_type; /* TB_HTYPE_* */
+ uint32_t nv_index; /* nv index to be measured, effective when */
+ /* mod_num==TB_POL_MOD_NUM_{NV | NV_RAW} */
+ /* mod_num: */
+ /* TB_POL_MOD_NUM_NV_RAW: */
+ /* check index size==hash size, */
+ /* no hashing before verify and extend */
+ /* TB_POL_MOD_NUM_NV: */
+ /* hashing before verify and extend */
+ uint8_t num_hashes;
+ tb_hash_t hashes[];
+} tb_policy_entry_t;
+
+#define TB_POLCTL_EXTEND_PCR17 0x1 /* extend policy into PCR 17 */
+
+typedef struct __packed {
+ uint8_t version; /* currently 2 */
+ uint8_t policy_type; /* TB_POLTYPE_* */
+ /* TODO should be changed to 16bit for TPM 2.0 */
+ uint8_t hash_alg; /* TB_HALG_* */
+ uint32_t policy_control; /* bitwise OR of TB_POLCTL_* */
+ uint32_t reserved;
+ uint8_t num_entries;
+ tb_policy_entry_t entries[];
+} tb_policy_t;
+
+/*
+ * TPM NV index for VL policy
+ */
+
+/* max size of policy in TPM NV (assumes 8 entries w/ 4 hashes each) */
+#define MAX_TB_POLICY_SIZE \
+ sizeof(tb_policy_t) + 8*(sizeof(tb_policy_entry_t) + 4*sizeof(tb_hash_t))
+
+#define TB_POLICY_INDEX 0x20000001 /* policy index for Verified Launch */
+
+
+/*
+ * helper fns
+ */
+#ifndef PRINT
+#define PRINT(...) {}
+#endif
+
+static inline const char *hash_type_to_string(uint8_t hash_type)
+{
+ if ( hash_type == TB_HTYPE_ANY )
+ return "TB_HTYPE_ANY";
+ else if ( hash_type == TB_HTYPE_IMAGE )
+ return "TB_HTYPE_IMAGE";
+ else {
+ static char buf[32];
+ snprintf(buf, sizeof(buf), "unsupported (%u)", hash_type);
+ return buf;
+ }
+}
+
+static inline const char *policy_type_to_string(uint8_t policy_type)
+{
+ if ( policy_type == TB_POLTYPE_CONT_NON_FATAL )
+ return "TB_POLTYPE_CONT_NON_FATAL";
+ else if ( policy_type == TB_POLTYPE_CONT_VERIFY_FAIL )
+ return "TB_POLTYPE_CONT_VERIFY_FAIL";
+ else if ( policy_type == TB_POLTYPE_HALT )
+ return "TB_POLTYPE_HALT";
+ else {
+ static char buf[32];
+ snprintf(buf, sizeof(buf), "unsupported (%u)", policy_type);
+ return buf;
+ }
+}
+
+static inline const char *policy_control_to_string(uint32_t policy_control)
+{
+ static char buf[64] = "";
+
+ if ( policy_control & TB_POLCTL_EXTEND_PCR17 )
+ strncpy(buf, "EXTEND_PCR17", sizeof(buf));
+
+ return buf;
+}
+
+static inline size_t calc_policy_entry_size(const tb_policy_entry_t *pol_entry,
+ uint16_t hash_alg)
+{
+ if ( pol_entry == NULL )
+ return 0;
+
+ size_t size = sizeof(*pol_entry);
+ /* tb_policy_entry_t has empty hash array, which isn't counted in size */
+ /* so add size of each hash */
+ size += pol_entry->num_hashes * get_hash_size(hash_alg);
+
+ return size;
+}
+
+static inline size_t calc_policy_size(const tb_policy_t *policy)
+{
+ size_t size = sizeof(*policy);
+
+ /* tb_policy_t has empty array, which isn't counted in size */
+ /* so add size of each policy */
+ const tb_policy_entry_t *pol_entry = policy->entries;
+ for ( int i = 0; i < policy->num_entries; i++ ) {
+ size_t entry_size = calc_policy_entry_size(pol_entry,
+ policy->hash_alg);
+ pol_entry = (void *)pol_entry + entry_size;
+ size += entry_size;
+ }
+
+ return size;
+}
+
+static inline tb_hash_t *get_policy_entry_hash(
+ const tb_policy_entry_t *pol_entry, uint16_t hash_alg, int i)
+{
+ /* assumes policy has already been validated */
+
+ if ( pol_entry == NULL ) {
+ PRINT(TBOOT_ERR"Error: pol_entry pointer is NULL\n");
+ return NULL;
+ }
+
+ if ( i < 0 || i >= pol_entry->num_hashes ) {
+ PRINT(TBOOT_ERR"Error: position is not correct.\n");
+ return NULL;
+ }
+
+ return (tb_hash_t *)((void *)pol_entry->hashes +
+ i * get_hash_size(hash_alg));
+}
+
+static inline tb_policy_entry_t* get_policy_entry(const tb_policy_t *policy,
+ int i)
+{
+ /* assumes policy has already been validated */
+
+ if ( policy == NULL ) {
+ PRINT(TBOOT_ERR"Error: policy pointer is NULL\n");
+ return NULL;
+ }
+
+ if ( i < 0 || i >= policy->num_entries ) {
+ PRINT(TBOOT_ERR"Error: position is not correct.\n");
+ return NULL;
+ }
+
+ tb_policy_entry_t *pol_entry = (tb_policy_entry_t *)policy->entries;
+ for ( int j = 0; j < i; j++ ) {
+ pol_entry = (void *)pol_entry +
+ calc_policy_entry_size(pol_entry, policy->hash_alg);
+ }
+
+ return pol_entry;
+}
+
+static inline tb_policy_entry_t* find_policy_entry(const tb_policy_t *policy,
+ uint8_t mod_num)
+{
+ /* assumes policy has already been validated */
+
+ if ( policy == NULL ) {
+ PRINT(TBOOT_ERR"Error: policy pointer is NULL\n");
+ return NULL;
+ }
+
+ for ( int i = 0; i < policy->num_entries; i++ ) {
+ tb_policy_entry_t *pol_entry = get_policy_entry(policy, i);
+ if ( pol_entry == NULL )
+ return NULL;
+
+ if ( pol_entry->mod_num == mod_num ||
+ pol_entry->mod_num == TB_POL_MOD_NUM_ANY )
+ return pol_entry;
+ }
+
+ return NULL;
+}
+
+/*
+ * verify and display policy
+ */
+static inline bool verify_policy(const tb_policy_t *policy, size_t size, bool print)
+{
+ if ( print ) PRINT(TBOOT_DETA"policy:\n");
+
+ if ( policy == NULL ) {
+ if ( print ) PRINT(TBOOT_ERR"policy pointer is NULL\n");
+ return false;
+ }
+
+ if ( size < sizeof(tb_policy_t) ) {
+ if ( print ) PRINT(TBOOT_ERR"size of policy is too small (%lu)\n",
+ (unsigned long)size);
+ return false;
+ }
+
+ if ( policy->version != 0x02 ) {
+ if ( print ) PRINT(TBOOT_ERR"unsupported version (%u)\n", policy->version);
+ return false;
+ }
+ if ( print ) PRINT(TBOOT_DETA"\t version: %u\n", policy->version);
+
+ if ( print ) PRINT(TBOOT_DETA"\t policy_type: %s\n",
+ policy_type_to_string(policy->policy_type));
+ if ( policy->policy_type >= TB_POLTYPE_MAX )
+ return false;
+
+ if ( print ) PRINT(TBOOT_DETA"\t hash_alg: %s\n",
+ hash_alg_to_string(policy->hash_alg));
+
+ if ( print ) PRINT(TBOOT_DETA"\t policy_control: %08x (%s)\n",
+ policy->policy_control,
+ policy_control_to_string(policy->policy_control));
+
+ if ( print ) PRINT(TBOOT_DETA"\t num_entries: %u\n", policy->num_entries);
+
+ const tb_policy_entry_t *pol_entry = policy->entries;
+ for ( int i = 0; i < policy->num_entries; i++ ) {
+ /* check header of policy entry */
+ if ( ((void *)pol_entry - (void *)policy + sizeof(*pol_entry)) >
+ size ) {
+ if ( print ) PRINT(TBOOT_ERR"size of policy entry is too small (%lu)\n",
+ (unsigned long)size);
+ return false;
+ }
+
+ if ( print ) PRINT(TBOOT_DETA"\t policy entry[%d]:\n", i);
+
+ if ( pol_entry->mod_num > TB_POL_MAX_MOD_NUM &&
+ pol_entry->mod_num != TB_POL_MOD_NUM_ANY &&
+ pol_entry->mod_num != TB_POL_MOD_NUM_NV &&
+ pol_entry->mod_num != TB_POL_MOD_NUM_NV_RAW ) {
+ if ( print ) PRINT(TBOOT_ERR"mod_num invalid (%u)\n", pol_entry->mod_num);
+ return false;
+ }
+ if ( print ) PRINT(TBOOT_DETA"\t\t mod_num: ");
+ if ( pol_entry->mod_num == TB_POL_MOD_NUM_ANY ) {
+ if ( print ) PRINT(TBOOT_DETA"any\n");
+ }
+ else if ( pol_entry->mod_num == TB_POL_MOD_NUM_NV ) {
+ if ( print )
+ PRINT(TBOOT_DETA"nv\n"
+ "\t\t nv_index: %08x\n",
+ pol_entry->nv_index);
+ }
+ else if ( pol_entry->mod_num == TB_POL_MOD_NUM_NV_RAW ) {
+ if ( print )
+ PRINT(TBOOT_DETA"nv_raw\n"
+ "\t\t nv_index: %08x\n",
+ pol_entry->nv_index);
+ }
+ else
+ if ( print ) PRINT(TBOOT_DETA"%u\n", pol_entry->mod_num);
+
+ if ( pol_entry->pcr > TB_POL_MAX_PCR &&
+ pol_entry->pcr != TB_POL_PCR_NONE ) {
+ if ( print ) PRINT(TBOOT_ERR"pcr invalid (%u)\n", pol_entry->pcr);
+ return false;
+ }
+ if ( print ) PRINT(TBOOT_DETA"\t\t pcr: ");
+ if ( pol_entry->pcr == TB_POL_PCR_NONE ) {
+ if ( print ) PRINT(TBOOT_DETA"none\n");
+ }
+ else
+ if ( print ) PRINT(TBOOT_DETA"%u\n", pol_entry->pcr);
+
+ if ( print ) PRINT(TBOOT_DETA"\t\t hash_type: %s\n",
+ hash_type_to_string(pol_entry->hash_type));
+ if ( pol_entry->hash_type > TB_HTYPE_IMAGE )
+ return false;
+
+ if ( print ) PRINT(TBOOT_DETA"\t\t num_hashes: %u\n", pol_entry->num_hashes);
+
+ /* check all of policy */
+ if ( ((void *)pol_entry - (void *)policy + sizeof(*pol_entry) +
+ pol_entry->num_hashes * get_hash_size(policy->hash_alg))
+ > size ) {
+ if ( print ) PRINT(TBOOT_ERR"size of policy entry is too small (%lu)\n",
+ (unsigned long)size);
+ return false;
+ }
+
+ for ( int j = 0; j < pol_entry->num_hashes; j++ ) {
+ if ( print ) {
+ PRINT(TBOOT_DETA"\t\t hashes[%d]: ", j);
+ print_hash(get_policy_entry_hash(pol_entry,
+ policy->hash_alg, j),
+ policy->hash_alg);
+ }
+ }
+
+ pol_entry = (void *)pol_entry +
+ calc_policy_entry_size(pol_entry, policy->hash_alg);
+ }
+
+ return true;
+}
+
+#endif /* __TB_POLICY_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
diff --git a/tboot/include/tboot.h b/tboot/include/tboot.h
new file mode 100644
index 0000000..ecf7dbe
--- /dev/null
+++ b/tboot/include/tboot.h
@@ -0,0 +1,197 @@
+/*
+ * tboot.h: shared data structure with MLE and kernel and functions
+ * used by kernel for runtime support
+ *
+ * Copyright (c) 2006-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __TBOOT_H__
+#define __TBOOT_H__
+
+#ifndef __packed
+#define __packed __attribute__ ((packed))
+#endif
+
+#define TB_CURRENT_VER 7
+
+/* define uuid_t here in case uuid.h wasn't pre-included */
+/* (i.e. so tboot.h can be self-sufficient) */
+#ifndef __UUID_H__
+typedef struct __packed {
+ uint32_t data1;
+ uint16_t data2;
+ uint16_t data3;
+ uint16_t data4;
+ uint8_t data5[6];
+} uuid_t;
+#endif
+
+/*
+ * used to communicate between tboot and the launched kernel (i.e. Xen)
+ */
+
+#define TB_KEY_SIZE 64 /* 512 bits */
+
+#define MAX_TB_MAC_REGIONS 32
+typedef struct __packed {
+ uint64_t start; /* must be 4k byte -aligned */
+ uint32_t size; /* must be 4k byte -granular */
+} tboot_mac_region_t;
+
+/* GAS - Generic Address Structure (ACPI 2.0+) */
+typedef struct __packed {
+ uint8_t space_id; /* only 0,1 (memory, I/O) are supported */
+ uint8_t bit_width;
+ uint8_t bit_offset;
+ uint8_t access_width; /* only 1-3 (byte, word, dword) are supported */
+ uint64_t address;
+} tboot_acpi_generic_address_t;
+
+typedef struct __packed {
+ tboot_acpi_generic_address_t pm1a_cnt_blk;
+ tboot_acpi_generic_address_t pm1b_cnt_blk;
+ tboot_acpi_generic_address_t pm1a_evt_blk;
+ tboot_acpi_generic_address_t pm1b_evt_blk;
+ uint16_t pm1a_cnt_val;
+ uint16_t pm1b_cnt_val;
+ uint64_t wakeup_vector;
+ uint32_t vector_width;
+ uint64_t kernel_s3_resume_vector;
+} tboot_acpi_sleep_info_t;
+
+#define TB_RESMEM_BLOCKS 128
+
+typedef struct __packed {
+ uint64_t addr;
+ uint64_t length;
+} reserve_map_t;
+
+typedef struct __packed {
+ /* version 3+ fields: */
+ uuid_t uuid; /* {663C8DFF-E8B3-4b82-AABF-19EA4D057A08} */
+ uint32_t version; /* currently 7 for EFI support */
+ uint32_t log_addr; /* physical addr of log or NULL if none */
+ uint32_t shutdown_entry; /* entry point for tboot shutdown */
+ uint32_t shutdown_type; /* type of shutdown (TB_SHUTDOWN_*) */
+ tboot_acpi_sleep_info_t
+ acpi_sinfo; /* where kernel put acpi sleep info in Sx */
+ uint32_t tboot_base; /* starting addr for tboot */
+ uint32_t tboot_size; /* size of tboot */
+ uint8_t num_mac_regions; /* number mem regions to MAC on S3 */
+ /* contig regions memory to MAC on S3 */
+ tboot_mac_region_t mac_regions[MAX_TB_MAC_REGIONS];
+ /* version 4+ fields: */
+ /* populated by tboot; will be encrypted */
+ uint8_t s3_key[TB_KEY_SIZE];
+ /* version 5+ fields: */
+ uint8_t reserved_align[3]; /* used to 4byte-align num_in_wfs */
+ uint32_t num_in_wfs; /* number of processors in wait-for-SIPI */
+ /* version 6+ fields: */
+ uint32_t flags;
+ uint64_t ap_wake_addr; /* phys addr of kernel/VMM SIPI vector */
+ uint32_t ap_wake_trigger; /* kernel/VMM writes APIC ID to wake AP */
+ /* version 7+ fields */
+ /* reserve mem blocks to adjust dom0 E820 */
+ uint64_t reserve_map_count;
+ reserve_map_t reserve_map[TB_RESMEM_BLOCKS];
+} tboot_shared_t;
+
+#define TB_SHUTDOWN_REBOOT 0
+#define TB_SHUTDOWN_S5 1
+#define TB_SHUTDOWN_S4 2
+#define TB_SHUTDOWN_S3 3
+#define TB_SHUTDOWN_HALT 4
+#define TB_SHUTDOWN_WFS 5
+
+#define TB_FLAG_AP_WAKE_SUPPORT 0x00000001 /* kernel/VMM use INIT-SIPI-SIPI
+ if clear, ap_wake_* if set */
+
+/* {663C8DFF-E8B3-4b82-AABF-19EA4D057A08} */
+#define TBOOT_SHARED_UUID {0x663c8dff, 0xe8b3, 0x4b82, 0xaabf, \
+ {0x19, 0xea, 0x4d, 0x5, 0x7a, 0x8 }}
+#define TBOOT_MEM_LOG_SIZE 0x8000
+/*
+ * used to log tboot printk output
+ */
+typedef struct {
+ uuid_t uuid;
+ bool is_init;
+ uint16_t max_size;
+ uint16_t curr_pos;
+ char buf[TBOOT_MEM_LOG_SIZE];
+} tboot_log_t;
+
+/* {C0192526-6B30-4db4-844C-A3E953B88174} */
+#define TBOOT_LOG_UUID {0xc0192526, 0x6b30, 0x4db4, 0x844c, \
+ {0xa3, 0xe9, 0x53, 0xb8, 0x81, 0x74 }}
+
+/* The tboot_shared page */
+tboot_shared_t _tboot_shared;
+
+long s3_flag;
+
+static inline void print_tboot_shared(const tboot_shared_t *tboot_shared)
+{
+ printk(TBOOT_DETA"tboot_shared data:\n");
+ printk(TBOOT_DETA"\t version: %d\n", tboot_shared->version);
+ printk(TBOOT_DETA"\t log_addr: 0x%08x\n", tboot_shared->log_addr);
+ printk(TBOOT_DETA"\t shutdown_entry: 0x%08x\n", tboot_shared->shutdown_entry);
+ printk(TBOOT_DETA"\t shutdown_type: %d\n", tboot_shared->shutdown_type);
+ printk(TBOOT_DETA"\t tboot_base: 0x%08x\n", tboot_shared->tboot_base);
+ printk(TBOOT_DETA"\t tboot_size: 0x%x\n", tboot_shared->tboot_size);
+ printk(TBOOT_DETA"\t num_in_wfs: %u\n", tboot_shared->num_in_wfs);
+ printk(TBOOT_DETA"\t flags: 0x%8.8x\n", tboot_shared->flags);
+ printk(TBOOT_DETA"\t ap_wake_addr: 0x%08x\n", (uint32_t)tboot_shared->ap_wake_addr);
+ printk(TBOOT_DETA"\t ap_wake_trigger: %u\n", tboot_shared->ap_wake_trigger);
+}
+
+void begin_initial_launch(void);
+void begin_launch(efi_xen_tboot_data_t *xtd);
+void s3_launch(void);
+void shutdown(void);
+void cpu_wakeup(uint32_t cpuid, uint64_t sipi_vec);
+
+/* policy */
+void verify_all_modules(void);
+void apply_policy(tb_error_t error);
+tb_error_t set_policy(void);
+
+#endif /* __TBOOT_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/tpm.h b/tboot/include/tpm.h
new file mode 100644
index 0000000..59ebde1
--- /dev/null
+++ b/tboot/include/tpm.h
@@ -0,0 +1,521 @@
+/*
+ * tpm.h: TPM-related support functions
+ *
+ * Copyright (c) 2006-2009, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TPM_H__
+#define __TPM_H__
+
+#include <types.h>
+#include <io.h>
+#include <hash.h>
+#include <integrity.h>
+
+/* un-comment to enable detailed command tracing */
+//#define TPM_TRACE
+
+#define TPM_IF_12 0
+#define TPM_IF_20_FIFO 1
+#define TPM_IF_20_CRB 2
+
+#define TPM_INTERFACE_ID_FIFO_20 0x0
+#define TPM_INTERFACE_ID_CRB 0x1
+#define TPM_INTERFACE_ID_FIFO_13 0xF
+
+#define TPM_LOCALITY_BASE 0xfed40000
+#define TPM_LOCALITY_0 TPM_LOCALITY_BASE
+#define TPM_LOCALITY_1 (TPM_LOCALITY_BASE | 0x1000)
+#define TPM_LOCALITY_2 (TPM_LOCALITY_BASE | 0x2000)
+#define TPM_LOCALITY_3 (TPM_LOCALITY_BASE | 0x3000)
+#define TPM_LOCALITY_4 (TPM_LOCALITY_BASE | 0x4000)
+#define TPM_LOCALITY_BASE_N(n) (TPM_LOCALITY_BASE | ((n) << 12))
+#define TPM_NR_LOCALITIES 5
+#define NR_TPM_LOCALITY_PAGES ((TPM_LOCALITY_1 - TPM_LOCALITY_0) >> PAGE_SHIFT)
+
+#define TPM_LOCALITY_CRB_BASE 0xfed40000
+#define TPM_LOCALITY_CRB_0 TPM_LOCALITY_CRB_BASE
+#define TPM_LOCALITY_CRB_1 (TPM_LOCALITY_CRB_BASE | 0x1000)
+#define TPM_LOCALITY_CRB_2 (TPM_LOCALITY_CRB_BASE | 0x2000)
+#define TPM_LOCALITY_CRB_3 (TPM_LOCALITY_CRB_BASE | 0x3000)
+#define TPM_LOCALITY_CRB_4 (TPM_LOCALITY_CRB_BASE | 0x4000)
+#define TPM_LOCALITY_CRB_BASE_N(n) (TPM_LOCALITY_CRB_BASE | ((n) << 12))
+#define TPM_NR_CRB_LOCALITIES 5
+#define NR_TPM_LOCALITY_CRB_PAGES ((TPM_LOCALITY_CRB_1 - TPM_LOCALITY_CRB_0) >> PAGE_SHIFT)
+/*
+ * Command Header Fields:
+ * 0 1 2 3 4 5 6 7 8 9 10 ...
+ * -------------------------------------------------------------
+ * | TAG | SIZE | COMMAND CODE | other ...
+ * -------------------------------------------------------------
+ *
+ * Response Header Fields:
+ * 0 1 2 3 4 5 6 7 8 9 10 ...
+ * -------------------------------------------------------------
+ * | TAG | SIZE | RETURN CODE | other ...
+ * -------------------------------------------------------------
+ */
+#define CMD_HEAD_SIZE 10
+#define RSP_HEAD_SIZE 10
+#define CMD_SIZE_OFFSET 2
+#define CMD_CC_OFFSET 6
+#define RSP_SIZE_OFFSET 2
+#define RSP_RST_OFFSET 6
+
+/*
+ * The term timeout applies to timings between various states
+ * or transitions within the interface protocol.
+ */
+#define TIMEOUT_UNIT (0x100000 / 330) /* ~1ms, 1 tpm r/w need > 330ns */
+#define TIMEOUT_A 750 /* 750ms */
+#define TIMEOUT_B 2000 /* 2s */
+#define TIMEOUT_C 75000 /* 750ms */
+#define TIMEOUT_D 750 /* 750ms */
+
+typedef struct __packed {
+ uint32_t timeout_a;
+ uint32_t timeout_b;
+ uint32_t timeout_c;
+ uint32_t timeout_d;
+} tpm_timeout_t;
+
+/*
+ * The TCG maintains a registry of all algorithms that have an
+ * assigned algorithm ID. That registry is the definitive list
+ * of algorithms that may be supported by a TPM.
+ */
+#define TPM_ALG_ERROR 0x0000
+#define TPM_ALG_FIRST 0x0001
+#define TPM_ALG_RSA 0x0001
+#define TPM_ALG_DES 0x0002
+#define TPM_ALG__3DES 0x0003
+#define TPM_ALG_SHA 0x0004
+#define TPM_ALG_SHA1 0x0004
+#define TPM_ALG_HMAC 0x0005
+#define TPM_ALG_AES 0x0006
+#define TPM_ALG_MGF1 0x0007
+#define TPM_ALG_KEYEDHASH 0x0008
+#define TPM_ALG_XOR 0x000A
+#define TPM_ALG_SHA256 0x000B
+#define TPM_ALG_SHA384 0x000C
+#define TPM_ALG_SHA512 0x000D
+#define TPM_ALG_WHIRLPOOL512 0x000E
+#define TPM_ALG_NULL 0x0010
+#define TPM_ALG_SM3_256 0x0012
+#define TPM_ALG_SM4 0x0013
+#define TPM_ALG_RSASSA 0x0014
+#define TPM_ALG_RSAES 0x0015
+#define TPM_ALG_RSAPSS 0x0016
+#define TPM_ALG_OAEP 0x0017
+#define TPM_ALG_ECDSA 0x0018
+#define TPM_ALG_ECDH 0x0019
+#define TPM_ALG_ECDAA 0x001A
+#define TPM_ALG_SM2 0x001B
+#define TPM_ALG_ECSCHNORR 0x001C
+#define TPM_ALG_KDF1_SP800_56a 0x0020
+#define TPM_ALG_KDF2 0x0021
+#define TPM_ALG_KDF1_SP800_108 0x0022
+#define TPM_ALG_ECC 0x0023
+#define TPM_ALG_SYMCIPHER 0x0025
+#define TPM_ALG_CTR 0x0040
+#define TPM_ALG_OFB 0x0041
+#define TPM_ALG_CBC 0x0042
+#define TPM_ALG_CFB 0x0043
+#define TPM_ALG_ECB 0x0044
+#define TPM_ALG_LAST 0x0044
+#define TPM_ALG_MAX_NUM (TPM_ALG_LAST - TPM_ALG_ERROR)
+
+
+// move from tpm.c
+
+/*
+ * TPM registers and data structures
+ *
+ * register values are offsets from each locality base
+ * see {read,write}_tpm_reg() for data struct format
+ */
+
+/* TPM_ACCESS_x */
+#define TPM_REG_ACCESS 0x00
+#define TPM_REG_STS 0x18
+
+typedef union {
+ u8 _raw[1]; /* 1-byte reg */
+ struct __packed {
+ u8 tpm_establishment : 1; /* RO, 0=T/OS has been established
+ before */
+ u8 request_use : 1; /* RW, 1=locality is requesting TPM use */
+ u8 pending_request : 1; /* RO, 1=other locality is requesting
+ TPM usage */
+ u8 seize : 1; /* WO, 1=seize locality */
+ u8 been_seized : 1; /* RW, 1=locality seized while active */
+ u8 active_locality : 1; /* RW, 1=locality is active */
+ u8 reserved : 1;
+ u8 tpm_reg_valid_sts : 1; /* RO, 1=other bits are valid */
+ };
+} tpm_reg_access_t;
+
+/* TPM_STS_x */
+
+typedef union {
+ u8 _raw[3]; /* 3-byte reg */
+ struct __packed {
+ u8 reserved1 : 1;
+ u8 response_retry : 1; /* WO, 1=re-send response */
+ u8 self_test_done : 1; /* RO, only for version 2 */
+ u8 expect : 1; /* RO, 1=more data for command expected */
+ u8 data_avail : 1; /* RO, 0=no more data for response */
+ u8 tpm_go : 1; /* WO, 1=execute sent command */
+ u8 command_ready : 1; /* RW, 1=TPM ready to receive new cmd */
+ u8 sts_valid : 1; /* RO, 1=data_avail and expect bits are valid */
+ u16 burst_count : 16; /* RO, # read/writes bytes before wait */
+ };
+} tpm12_reg_sts_t;
+
+typedef union {
+ u8 _raw[4]; /* 4-byte reg */
+ struct __packed {
+ u8 reserved1 : 1;
+ u8 response_retry : 1; /* WO, 1=re-send response */
+ u8 self_test_done : 1; /* RO, only for version 2 */
+ u8 expect : 1; /* RO, 1=more data for command expected */
+ u8 data_avail : 1; /* RO, 0=no more data for response */
+ u8 tpm_go : 1; /* WO, 1=execute sent command */
+ u8 command_ready : 1; /* RW, 1=TPM ready to receive new cmd */
+ u8 sts_valid : 1; /* RO, 1=data_avail and expect bits are
+ valid */
+ u16 burst_count : 16; /* RO, # read/writes bytes before wait */
+ /* version >= 2 */
+ u8 command_cancel : 1;
+ u8 reset_establishment : 1;
+ u8 tpm_family : 2;
+ u8 reserved2 : 4;
+ };
+} tpm20_reg_sts_t;
+
+//-----------------------------------------------------------------------------
+// CRB I/F related definitions, see TCG PC Client Platform TPM Profile (PTP) Specification, Level 00 Revision 00.43
+//-----------------------------------------------------------------------------
+#define TPM_REG_LOC_STATE 0x00
+#define TPM_REG_LOC_CTRL 0x8
+#define TPM_LOCALITY_STS 0x0C
+#define TPM_INTERFACE_ID 0x30
+#define TPM_CONTROL_AREA 0x40
+#define TPM_CRB_CTRL_REQ 0x40
+#define TPM_CRB_CTRL_STS 0x44
+#define TPM_CRB_CTRL_CANCEL 0x48
+#define TPM_CRB_CTRL_START 0x4C
+#define TPM_CRB_CTRL_CMD_SIZE 0x58
+#define TPM_CRB_CTRL_CMD_ADDR 0x5C
+#define TPM_CRB_CTRL_CMD_HADDR 0x60
+#define TPM_CRB_CTRL_RSP_SIZE 0x64
+#define TPM_CRB_CTRL_RSP_ADDR 0x68
+#define TPM_CRB_DATA_BUFFER 0x80
+#define TPMCRBBUF_LEN 0xF80 //3968 Bytes
+
+//#define CTRL_AREA_ADDR (uint32_t) (TPM_CRB_BASE + 0x40)
+//#define DATA_BUF_ADDR (uint32_t) (TPM_CRB_BASE + 0x80)
+
+typedef union {
+ u8 _raw[4]; /* 4-byte reg */
+ struct __packed {
+ u8 tpm_establishment : 1;
+ u8 loc_assigned : 1;
+ u8 active_locality : 3;
+ u8 reserved : 2;
+ u8 tpm_reg_valid_sts : 1; /* RO, 1=other bits are valid */
+ u8 reserved1 :8;
+ u16 reserved2 :16;
+ };
+} tpm_reg_loc_state_t;
+
+typedef union {
+ uint8_t _raw[4];
+ struct __packed {
+ uint32_t requestAccess:1;
+ uint32_t relinquish:1;
+ uint32_t seize:1;
+ uint32_t resetEstablishment:1;
+ uint32_t reserved1:28;
+ };
+} tpm_reg_loc_ctrl_t;
+
+typedef union {
+ uint8_t _raw[4];
+ struct __packed{
+ uint32_t Granted:1;
+ uint32_t BeenSeized:1;
+ uint32_t R:30;
+ };
+} tpm_reg_loc_sts_t;
+
+typedef union {
+ uint8_t _raw[8]; // 8-byte reg
+ struct __packed {
+ uint64_t interface_type:4;
+ uint64_t interface_version:4;
+ uint64_t interface_capability:4;
+ uint64_t interface_selector:4;
+ uint64_t rid:8;
+ uint64_t res:8;
+ uint64_t vid:16;
+ uint64_t did:16;
+ };
+} tpm_crb_interface_id_t;
+
+typedef union {
+ uint8_t _raw[4];
+ struct __packed{
+ uint32_t cmdReady:1;
+ uint32_t goIdle:1;
+ uint32_t Reserved:30;
+ };
+ } tpm_reg_ctrl_request_t;
+
+typedef union {
+ uint8_t _raw[4];
+ struct __packed{
+ uint32_t tpmsts:1;
+ uint32_t tpmidle:1;
+ uint32_t reserved:30;
+ };
+} tpm_reg_ctrl_sts_t;
+
+typedef union {
+ uint8_t _raw[4];
+ struct __packed{
+ uint32_t start;
+ };
+} tpm_reg_ctrl_start_t;
+
+typedef union {
+ uint8_t _raw[4];
+ struct __packed{
+ uint32_t cancel;
+ };
+} tpm_reg_ctrl_cancel_t;
+
+typedef union {
+ uint8_t _raw[8];
+ struct __packed{
+ uint32_t cmdladdr;
+ uint32_t cmdhaddr;
+ };
+} tpm_reg_ctrl_cmdaddr_t;
+
+typedef union {
+ uint8_t _raw[4];
+ struct __packed{
+ uint32_t cmdsize;
+ };
+} tpm_reg_ctrl_cmdsize_t;
+
+typedef union {
+ uint8_t _raw[8];
+ struct __packed{
+ uint64_t rspaddr;
+ };
+} tpm_reg_ctrl_rspaddr_t;
+
+typedef union {
+ uint8_t _raw[4];
+ struct __packed{
+ uint32_t rspsize;
+ };
+} tpm_reg_ctrl_rspsize_t;
+
+typedef union {
+ uint8_t _raw[48];
+ struct __packed {
+ tpm_reg_ctrl_request_t Request;
+ tpm_reg_ctrl_sts_t Status;
+ tpm_reg_ctrl_cancel_t Cancel;
+ tpm_reg_ctrl_start_t Start;
+ uint64_t R;
+ tpm_reg_ctrl_cmdsize_t CmdSize;
+ tpm_reg_ctrl_cmdaddr_t CmdAddr;
+ tpm_reg_ctrl_rspsize_t RspSize;
+ tpm_reg_ctrl_rspaddr_t RspAddr;
+ };
+} tpm_ctrl_area_t;
+
+// END OF CRB I/F
+
+/*
+ * assumes that all reg types follow above format:
+ * - packed
+ * - member named '_raw' which is array whose size is that of data to read
+ */
+#define read_tpm_reg(locality, reg, pdata) _read_tpm_reg(locality, reg, (pdata)->_raw, sizeof(*(pdata)))
+
+#define write_tpm_reg(locality, reg, pdata) _write_tpm_reg(locality, reg, (pdata)->_raw, sizeof(*(pdata)))
+
+static inline void _read_tpm_reg(int locality, u32 reg, u8 *_raw, size_t size)
+{
+ for ( size_t i = 0; i < size; i++ ) _raw[i] = readb((TPM_LOCALITY_BASE_N(locality) | reg) + i);
+}
+
+static inline void _write_tpm_reg(int locality, u32 reg, u8 *_raw, size_t size)
+{
+ for ( size_t i = 0; i < size; i++ ) writeb((TPM_LOCALITY_BASE_N(locality) | reg) + i, _raw[i]);
+}
+
+
+/*
+ * the following inline function reversely copy the bytes from 'in' to
+ * 'out', the byte number to copy is given in count.
+ */
+#define reverse_copy(out, in, count) _reverse_copy((uint8_t *)(out), (uint8_t *)(in), count)
+
+static inline void _reverse_copy(uint8_t *out, uint8_t *in, uint32_t count)
+{
+ for ( uint32_t i = 0; i < count; i++ )
+ out[i] = in[count - i - 1];
+}
+
+/* alg id list supported by Tboot */
+u16 tboot_alg_list[2];
+
+typedef tb_hash_t tpm_digest_t;
+typedef tpm_digest_t tpm_pcr_value_t;
+
+/* only for tpm1.2 to (un)seal */
+tpm_pcr_value_t post_launch_pcr17;
+tpm_pcr_value_t post_launch_pcr18;
+
+struct tpm_if;
+
+struct tpm_if {
+#define TPM12_VER_MAJOR 1
+#define TPM12_VER_MINOR 2
+#define TPM20_VER_MAJOR 2
+#define TPM20_VER_MINOR 0
+ u8 major;
+ u8 minor;
+ u16 family;
+
+ tpm_timeout_t timeout;
+
+ u32 error; /* last reported error */
+ u32 cur_loc;
+
+ u16 banks;
+ u16 algs_banks[TPM_ALG_MAX_NUM];
+ u16 alg_count;
+ u16 algs[TPM_ALG_MAX_NUM];
+
+ /*
+ * Only for version>=2. PCR extend policy.
+ */
+#define TB_EXTPOL_AGILE 0
+#define TB_EXTPOL_EMBEDDED 1
+#define TB_EXTPOL_FIXED 2
+ u8 extpol;
+ u16 cur_alg;
+
+ /* NV index to be used */
+ u32 lcp_own_index;
+ u32 tb_policy_index;
+ u32 tb_err_index;
+ u32 sgx_svn_index;
+
+ bool (*init)(struct tpm_if *ti);
+
+ bool (*pcr_read)(struct tpm_if *ti, u32 locality, u32 pcr, tpm_pcr_value_t *out);
+ bool (*pcr_extend)(struct tpm_if *ti, u32 locality, u32 pcr, const hash_list_t *in);
+ bool (*pcr_reset)(struct tpm_if *ti, u32 locality, u32 pcr);
+ bool (*hash)(struct tpm_if *ti, u32 locality, const u8 *data, u32 data_size, hash_list_t *hl);
+
+ bool (*nv_read)(struct tpm_if *ti, u32 locality, u32 index, u32 offset, u8 *data, u32 *data_size);
+ bool (*nv_write)(struct tpm_if *ti, u32 locality, u32 index, u32 offset, const u8 *data, u32 data_size);
+ bool (*get_nvindex_size)(struct tpm_if *ti, u32 locality, u32 index, u32 *size);
+
+#define TPM_NV_PER_WRITE_STCLEAR (1<<14)
+#define TPM_NV_PER_WRITEDEFINE (1<<13)
+#define TPM_NV_PER_WRITEALL (1<<12)
+#define TPM_NV_PER_AUTHWRITE (1<<2)
+#define TPM_NV_PER_OWNERWRITE (1<<1)
+#define TPM_NV_PER_PPWRITE (1<<0)
+ bool (*get_nvindex_permission)(struct tpm_if *ti, u32 locality, u32 index, u32 *attribute);
+
+ bool (*seal)(struct tpm_if *ti, u32 locality, u32 in_data_size, const u8 *in_data, u32 *sealed_data_size, u8 *sealed_data);
+ bool (*unseal)(struct tpm_if *ti, u32 locality, u32 sealed_data_size, const u8 *sealed_data, u32 *secret_size, u8 *secret);
+ bool (*verify_creation)(struct tpm_if *ti, u32 sealed_data_size, u8 *sealed_data);
+
+ bool (*get_random)(struct tpm_if *ti, u32 locality, u8 *random_data, u32 *data_size);
+
+ uint32_t (*save_state)(struct tpm_if *ti, u32 locality);
+
+ bool (*cap_pcrs)(struct tpm_if *ti, u32 locality, int pcr);
+ bool (*check)(void);
+};
+
+struct tpm_if tpm_12_if;
+struct tpm_if tpm_20_if;
+struct tpm_if *g_tpm;
+uint8_t g_tpm_family;
+
+bool tpm_validate_locality(uint32_t locality);
+bool tpm_validate_locality_crb(uint32_t locality);
+bool release_locality(uint32_t locality);
+bool prepare_tpm(void);
+bool tpm_detect(void);
+void tpm_print(struct tpm_if *ti);
+bool tpm_submit_cmd(u32 locality, u8 *in, u32 in_size, u8 *out, u32 *out_size);
+bool tpm_submit_cmd_crb(u32 locality, u8 *in, u32 in_size, u8 *out, u32 *out_size);
+bool tpm_wait_cmd_ready(uint32_t locality);
+bool tpm_request_locality_crb(uint32_t locality);
+bool tpm_relinquish_locality_crb(uint32_t locality);
+bool txt_is_launched(void);
+bool tpm_workaround_crb(void);
+
+
+//#define TPM_UNIT_TEST 1
+
+#ifdef TPM_UNIT_TEST
+void tpm_unit_test(void);
+#else
+#define tpm_unit_test()
+#endif /* TPM_UNIT_TEST */
+
+
+#endif /* __TPM_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/tpm_20.h b/tboot/include/tpm_20.h
new file mode 100644
index 0000000..af7dab5
--- /dev/null
+++ b/tboot/include/tpm_20.h
@@ -0,0 +1,1503 @@
+/*
+ * tpm_20.h: TPM2.0-related structure
+ *
+ * Copyright (c) 2006-2013, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TPM20_H__
+#define __TPM20_H__
+
+/*
+ * tpm2.0 structure defined in spec.
+ */
+
+typedef struct {
+ u16 size;
+ u8 buffer[1];
+} TPM2B;
+
+// Table 205 -- SHA1 Hash Values
+#define SHA1_DIGEST_SIZE 20
+#define SHA1_BLOCK_SIZE 64
+#define SHA1_DER_SIZE 15
+#define SHA1_DER {0x30,0x21,0x30,0x09,0x06, 0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,0x00,0x04,0x14}
+
+// Table 206 -- SHA256 Hash Values
+#define SHA256_DIGEST_SIZE 32
+#define SHA256_BLOCK_SIZE 64
+#define SHA256_DER_SIZE 19
+#define SHA256_DER {0x30,0x31,0x30,0x0d,0x06, 0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01, 0x05,0x00,0x04,0x20}
+
+// Table 207 -- SHA384 Hash Values
+#define SHA384_DIGEST_SIZE 48
+#define SHA384_BLOCK_SIZE 128
+#define SHA384_DER_SIZE 19
+#define SHA384_DER {0x30,0x41,0x30,0x0d,0x06, 0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02, 0x05,0x00,0x04,0x30}
+
+
+// Table 208 -- SHA512 Hash Values
+#define SHA512_DIGEST_SIZE 64
+#define SHA512_BLOCK_SIZE 128
+#define SHA512_DER_SIZE 19
+#define SHA512_DER {0x30,0x51,0x30,0x0d,0x06, \
+ 0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,\
+ 0x05,0x00,0x04,0x40}
+
+// Table 210 -- SM3_256 Hash Values
+#define SM3_256_DIGEST_SIZE 32
+#define SM3_256_BLOCK_SIZE 64
+#define SM3_256_DER_SIZE 18
+#define SM3_256_DER {0x30,0x30,0x30,0x0c,0x06, \
+ 0x08,0x2A,0x81,0x1C,0x81,0x45,0x01,0x83,0x11,0x05,\
+ 0x00,0x04,0x20}
+
+// Table 213 -- Logic Values
+#define YES 1
+#define NO 0
+#define SET 1
+#define CLEAR 0
+
+// Table 215 -- Implemented Algorithms
+#define ALG_RSA YES // 1
+#define ALG_SHA1 YES // 1
+#define ALG_HMAC YES // 1
+#define ALG_AES YES // 1
+#define ALG_MGF1 YES // 1
+#define ALG_XOR YES // 1
+#define ALG_KEYEDHASH YES // 1
+#define ALG_SHA256 YES // 1
+#define ALG_SHA384 YES // 0
+#define ALG_SHA512 YES // 0
+#define ALG_SM3_256 YES // 1
+#define ALG_SM4 YES // 1
+#define ALG_RSASSA YES // 1
+#define ALG_RSAES YES // 1
+#define ALG_RSAPSS YES // 1
+#define ALG_OAEP YES // 1
+#define ALG_ECC YES // 1
+#define ALG_ECDH YES // 1
+#define ALG_ECDSA YES // 1
+#define ALG_ECDAA YES // 1
+#define ALG_SM2 YES // 1
+#define ALG_ECSCHNORR YES // 1
+#define ALG_SYMCIPHER YES // 1
+#define ALG_KDF1_SP800_56a YES // 1
+#define ALG_KDF2 NO // 0
+#define ALG_KDF1_SP800_108 YES // 1
+#define ALG_CTR YES // 1
+#define ALG_OFB YES // 1
+#define ALG_CBC YES // 1
+#define ALG_CFB YES // 1
+#define ALG_ECB YES // 1
+
+#define HASH_COUNT (ALG_SHA1+ALG_SHA256+ALG_SM3_256+ALG_SHA384+ALG_SHA512)
+
+// Table 217 -- RSA Algorithm Constants
+#define RSA_KEY_SIZES_BITS {1024, 2048} // {1024,2048}
+#define MAX_RSA_KEY_BITS 2048
+#define MAX_RSA_KEY_BYTES ((MAX_RSA_KEY_BITS + 7) / 8) // 256
+
+// Table 218 -- ECC Algorithm Constants
+#define ECC_CURVES {TPM_ECC_NIST_P256,TPM_ECC_BN_P256,TPM_ECC_SM2_P256}
+#define ECC_KEY_SIZES_BITS {256}
+#define MAX_ECC_KEY_BITS 256
+#define MAX_ECC_KEY_BYTES ((MAX_ECC_KEY_BITS + 7) / 8) // 32
+
+// Table 219 -- AES Algorithm Constants
+#define AES_KEY_SIZES_BITS {128}
+#define MAX_AES_KEY_BITS 128
+#define MAX_AES_BLOCK_SIZE_BYTES 16
+#define MAX_AES_KEY_BYTES ((MAX_AES_KEY_BITS + 7) / 8) // 16
+
+// Table 221 -- Symmetric Algorithm Constants
+#define MAX_SYM_KEY_BITS MAX_AES_KEY_BITS // 128
+#define MAX_SYM_KEY_BYTES MAX_AES_KEY_BYTES // 16
+#define MAX_SYM_BLOCK_SIZE MAX_AES_BLOCK_SIZE_BYTES // 16
+
+// Table 222 -- Implementation Values
+#define FIELD_UPGRADE_IMPLEMENTED NO // 0
+typedef u16 BSIZE;
+#define BUFFER_ALIGNMENT 4
+#define IMPLEMENTATION_PCR 24
+#define PLATFORM_PCR 24
+#define DRTM_PCR 17
+#define NUM_LOCALITIES 5
+#define MAX_HANDLE_NUM 3
+#define MAX_ACTIVE_SESSIONS 64
+typedef u16 CONTEXT_SLOT;
+typedef u64 CONTEXT_COUNTER;
+#define MAX_LOADED_SESSIONS 3
+#define MAX_SESSION_NUM 3
+#define MAX_LOADED_OBJECTS 3
+#define MIN_EVICT_OBJECTS 2
+#define PCR_SELECT_MIN ((PLATFORM_PCR+7)/8) // 3
+#define PCR_SELECT_MAX ((IMPLEMENTATION_PCR+7)/8) // 3
+#define NUM_POLICY_PCR_GROUP 1
+#define NUM_AUTHVALUE_PCR_GROUP 1
+#define MAX_CONTEXT_SIZE 4000
+#define MAX_DIGEST_BUFFER 1024
+#define MAX_NV_INDEX_SIZE 1024
+#define MAX_CAP_BUFFER 1024
+#define NV_MEMORY_SIZE 16384
+#define NUM_STATIC_PCR 16
+#define MAX_ALG_LIST_SIZE 64
+#define TIMER_PRESCALE 100000
+#define PRIMARY_SEED_SIZE 32
+#define CONTEXT_ENCRYPT_ALG TPM_ALG_AES
+#define CONTEXT_ENCRYPT_KEY_BITS MAX_SYM_KEY_BITS // 128
+#define CONTEXT_ENCRYPT_KEY_BYTES ((CONTEXT_ENCRYPT_KEY_BITS+7)/8)
+#define CONTEXT_INTEGRITY_HASH_ALG TPM_ALG_SHA256
+#define CONTEXT_INTEGRITY_HASH_SIZE SHA256_DIGEST_SIZE // 32
+#define PROOF_SIZE CONTEXT_INTEGRITY_HASH_SIZE // 32
+#define NV_CLOCK_UPDATE_INTERVAL 12
+#define NUM_POLICY_PCR 1
+#define MAX_COMMAND_SIZE 4096
+#define MAX_RESPONSE_SIZE 4096
+#define ORDERLY_BITS 8
+#define MAX_ORDERLY_COUNT ((1 << ORDERLY_BITS) - 1) // 255
+#define ALG_ID_FIRST TPM_ALG_FIRST
+#define ALG_ID_LAST TPM_ALG_LAST
+#define MAX_SYM_DATA 128
+#define MAX_HASH_STATE_SIZE 512
+#define MAX_RNG_ENTROPY_SIZE 64
+#define RAM_INDEX_SPACE 512
+#define RSA_DEFAULT_PUBLIC_EXPONENT 0x00010001
+#define ENABLE_PCR_NO_INCREMENT YES // 1
+
+// Table 11 -- TPM_CC Constants <I/O,S>
+typedef u32 TPM_CC;
+
+#define TPM_CC_FIRST (TPM_CC)(0x0000011F)
+#define TPM_CC_PP_FIRST (TPM_CC)(0x0000011F)
+#define TPM_CC_NV_UndefineSpaceSpecial (TPM_CC)(0x0000011F)
+#define TPM_CC_EvictControl (TPM_CC)(0x00000120)
+#define TPM_CC_HierarchyControl (TPM_CC)(0x00000121)
+#define TPM_CC_NV_UndefineSpace (TPM_CC)(0x00000122)
+#define TPM_CC_ChangeEPS (TPM_CC)(0x00000124)
+#define TPM_CC_ChangePPS (TPM_CC)(0x00000125)
+#define TPM_CC_Clear (TPM_CC)(0x00000126)
+#define TPM_CC_ClearControl (TPM_CC)(0x00000127)
+#define TPM_CC_ClockSet (TPM_CC)(0x00000128)
+#define TPM_CC_HierarchyChangeAuth (TPM_CC)(0x00000129)
+#define TPM_CC_NV_DefineSpace (TPM_CC)(0x0000012A)
+#define TPM_CC_PCR_Allocate (TPM_CC)(0x0000012B)
+#define TPM_CC_PCR_SetAuthPolicy (TPM_CC)(0x0000012C)
+#define TPM_CC_PP_Commands (TPM_CC)(0x0000012D)
+#define TPM_CC_SetPrimaryPolicy (TPM_CC)(0x0000012E)
+#define TPM_CC_FieldUpgradeStart (TPM_CC)(0x0000012F)
+#define TPM_CC_ClockRateAdjust (TPM_CC)(0x00000130)
+#define TPM_CC_CreatePrimary (TPM_CC)(0x00000131)
+#define TPM_CC_NV_GlobalWriteLock (TPM_CC)(0x00000132)
+#define TPM_CC_PP_LAST (TPM_CC)(0x00000132)
+#define TPM_CC_GetCommandAuditDigest (TPM_CC)(0x00000133)
+#define TPM_CC_NV_Increment (TPM_CC)(0x00000134)
+#define TPM_CC_NV_SetBits (TPM_CC)(0x00000135)
+#define TPM_CC_NV_Extend (TPM_CC)(0x00000136)
+#define TPM_CC_NV_Write (TPM_CC)(0x00000137)
+#define TPM_CC_NV_WriteLock (TPM_CC)(0x00000138)
+#define TPM_CC_DictionaryAttackLockReset (TPM_CC)(0x00000139)
+#define TPM_CC_DictionaryAttackParameters (TPM_CC)(0x0000013A)
+#define TPM_CC_NV_ChangeAuth (TPM_CC)(0x0000013B)
+#define TPM_CC_PCR_Event (TPM_CC)(0x0000013C)
+#define TPM_CC_PCR_Reset (TPM_CC)(0x0000013D)
+#define TPM_CC_SequenceComplete (TPM_CC)(0x0000013E)
+#define TPM_CC_SetAlgorithmSet (TPM_CC)(0x0000013F)
+#define TPM_CC_SetCommandCodeAuditStatus (TPM_CC)(0x00000140)
+#define TPM_CC_FieldUpgradeData (TPM_CC)(0x00000141)
+#define TPM_CC_IncrementalSelfTest (TPM_CC)(0x00000142)
+#define TPM_CC_SelfTest (TPM_CC)(0x00000143)
+#define TPM_CC_Startup (TPM_CC)(0x00000144)
+#define TPM_CC_Shutdown (TPM_CC)(0x00000145)
+#define TPM_CC_StirRandom (TPM_CC)(0x00000146)
+#define TPM_CC_ActivateCredential (TPM_CC)(0x00000147)
+#define TPM_CC_Certify (TPM_CC)(0x00000148)
+#define TPM_CC_PolicyNV (TPM_CC)(0x00000149)
+#define TPM_CC_CertifyCreation (TPM_CC)(0x0000014A)
+#define TPM_CC_Duplicate (TPM_CC)(0x0000014B)
+#define TPM_CC_GetTime (TPM_CC)(0x0000014C)
+#define TPM_CC_GetSessionAuditDigest (TPM_CC)(0x0000014D)
+#define TPM_CC_NV_Read (TPM_CC)(0x0000014E)
+#define TPM_CC_NV_ReadLock (TPM_CC)(0x0000014F)
+#define TPM_CC_ObjectChangeAuth (TPM_CC)(0x00000150)
+#define TPM_CC_PolicySecret (TPM_CC)(0x00000151)
+#define TPM_CC_Rewrap (TPM_CC)(0x00000152)
+#define TPM_CC_Create (TPM_CC)(0x00000153)
+#define TPM_CC_ECDH_ZGen (TPM_CC)(0x00000154)
+#define TPM_CC_HMAC (TPM_CC)(0x00000155)
+#define TPM_CC_Import (TPM_CC)(0x00000156)
+#define TPM_CC_Load (TPM_CC)(0x00000157)
+#define TPM_CC_Quote (TPM_CC)(0x00000158)
+#define TPM_CC_RSA_Decrypt (TPM_CC)(0x00000159)
+#define TPM_CC_HMAC_Start (TPM_CC)(0x0000015B)
+#define TPM_CC_SequenceUpdate (TPM_CC)(0x0000015C)
+#define TPM_CC_Sign (TPM_CC)(0x0000015D)
+#define TPM_CC_Unseal (TPM_CC)(0x0000015E)
+#define TPM_CC_PolicySigned (TPM_CC)(0x00000160)
+#define TPM_CC_ContextLoad (TPM_CC)(0x00000161)
+#define TPM_CC_ContextSave (TPM_CC)(0x00000162)
+#define TPM_CC_ECDH_KeyGen (TPM_CC)(0x00000163)
+#define TPM_CC_EncryptDecrypt (TPM_CC)(0x00000164)
+#define TPM_CC_FlushContext (TPM_CC)(0x00000165)
+#define TPM_CC_LoadExternal (TPM_CC)(0x00000167)
+#define TPM_CC_MakeCredential (TPM_CC)(0x00000168)
+#define TPM_CC_NV_ReadPublic (TPM_CC)(0x00000169)
+#define TPM_CC_PolicyAuthorize (TPM_CC)(0x0000016A)
+#define TPM_CC_PolicyAuthValue (TPM_CC)(0x0000016B)
+#define TPM_CC_PolicyCommandCode (TPM_CC)(0x0000016C)
+#define TPM_CC_PolicyCounterTimer (TPM_CC)(0x0000016D)
+#define TPM_CC_PolicyCpHash (TPM_CC)(0x0000016E)
+#define TPM_CC_PolicyLocality (TPM_CC)(0x0000016F)
+#define TPM_CC_PolicyNameHash (TPM_CC)(0x00000170)
+#define TPM_CC_PolicyOR (TPM_CC)(0x00000171)
+#define TPM_CC_PolicyTicket (TPM_CC)(0x00000172)
+#define TPM_CC_ReadPublic (TPM_CC)(0x00000173)
+#define TPM_CC_RSA_Encrypt (TPM_CC)(0x00000174)
+#define TPM_CC_StartAuthSession (TPM_CC)(0x00000176)
+#define TPM_CC_VerifySignature (TPM_CC)(0x00000177)
+#define TPM_CC_ECC_Parameters (TPM_CC)(0x00000178)
+#define TPM_CC_FirmwareRead (TPM_CC)(0x00000179)
+#define TPM_CC_GetCapability (TPM_CC)(0x0000017A)
+#define TPM_CC_GetRandom (TPM_CC)(0x0000017B)
+#define TPM_CC_GetTestResult (TPM_CC)(0x0000017C)
+#define TPM_CC_Hash (TPM_CC)(0x0000017D)
+#define TPM_CC_PCR_Read (TPM_CC)(0x0000017E)
+#define TPM_CC_PolicyPCR (TPM_CC)(0x0000017F)
+#define TPM_CC_PolicyRestart (TPM_CC)(0x00000180)
+#define TPM_CC_ReadClock (TPM_CC)(0x00000181)
+#define TPM_CC_PCR_Extend (TPM_CC)(0x00000182)
+#define TPM_CC_PCR_SetAuthValue (TPM_CC)(0x00000183)
+#define TPM_CC_NV_Certify (TPM_CC)(0x00000184)
+#define TPM_CC_EventSequenceComplete (TPM_CC)(0x00000185)
+#define TPM_CC_HashSequenceStart (TPM_CC)(0x00000186)
+#define TPM_CC_PolicyPhysicalPresence (TPM_CC)(0x00000187)
+#define TPM_CC_PolicyDuplicationSelect (TPM_CC)(0x00000188)
+#define TPM_CC_PolicyGetDigest (TPM_CC)(0x00000189)
+#define TPM_CC_TestParms (TPM_CC)(0x0000018A)
+#define TPM_CC_Commit (TPM_CC)(0x0000018B)
+#define TPM_CC_PolicyPassword (TPM_CC)(0x0000018C)
+#define TPM_CC_SM2_ZGen (TPM_CC)(0x0000018D)
+#define TPM_CC_LAST (TPM_CC)(0x0000018D)
+
+// Table 15 -- TPM_RC Constants <O,S>
+typedef u32 TPM_RCS; // The 'safe' error codes
+typedef u32 TPM_RC;
+
+#define TPM_RC_SUCCESS (TPM_RC)(0x000)
+#define TPM_RC_BAD_TAG (TPM_RC)(0x030)
+#define RC_VER1 (TPM_RC)(0x100)
+#define TPM_RC_INITIALIZE (TPM_RC)(RC_VER1 + 0x000)
+#define TPM_RC_FAILURE (TPM_RC)(RC_VER1 + 0x001)
+#define TPM_RC_SEQUENCE (TPM_RC)(RC_VER1 + 0x003)
+#define TPM_RC_PRIVATE (TPM_RC)(RC_VER1 + 0x00B)
+#define TPM_RC_HMAC (TPM_RC)(RC_VER1 + 0x019)
+#define TPM_RC_DISABLED (TPM_RC)(RC_VER1 + 0x020)
+#define TPM_RC_EXCLUSIVE (TPM_RC)(RC_VER1 + 0x021)
+#define TPM_RC_AUTH_TYPE (TPM_RC)(RC_VER1 + 0x024)
+#define TPM_RC_AUTH_MISSING (TPM_RC)(RC_VER1 + 0x025)
+#define TPM_RC_POLICY (TPM_RC)(RC_VER1 + 0x026)
+#define TPM_RC_PCR (TPM_RC)(RC_VER1 + 0x027)
+#define TPM_RC_PCR_CHANGED (TPM_RC)(RC_VER1 + 0x028)
+#define TPM_RC_UPGRADE (TPM_RC)(RC_VER1 + 0x02D)
+#define TPM_RC_TOO_MANY_CONTEXTS (TPM_RC)(RC_VER1 + 0x02E)
+#define TPM_RC_AUTH_UNAVAILABLE (TPM_RC)(RC_VER1 + 0x02F)
+#define TPM_RC_REBOOT (TPM_RC)(RC_VER1 + 0x030)
+#define TPM_RC_UNBALANCED (TPM_RC)(RC_VER1 + 0x031)
+#define TPM_RC_COMMAND_SIZE (TPM_RC)(RC_VER1 + 0x042)
+#define TPM_RC_COMMAND_CODE (TPM_RC)(RC_VER1 + 0x043)
+#define TPM_RC_AUTHSIZE (TPM_RC)(RC_VER1 + 0x044)
+#define TPM_RC_AUTH_CONTEXT (TPM_RC)(RC_VER1 + 0x045)
+#define TPM_RC_NV_RANGE (TPM_RC)(RC_VER1 + 0x046)
+#define TPM_RC_NV_SIZE (TPM_RC)(RC_VER1 + 0x047)
+#define TPM_RC_NV_LOCKED (TPM_RC)(RC_VER1 + 0x048)
+#define TPM_RC_NV_AUTHORIZATION (TPM_RC)(RC_VER1 + 0x049)
+#define TPM_RC_NV_UNINITIALIZED (TPM_RC)(RC_VER1 + 0x04A)
+#define TPM_RC_NV_SPACE (TPM_RC)(RC_VER1 + 0x04B)
+#define TPM_RC_NV_DEFINED (TPM_RC)(RC_VER1 + 0x04C)
+#define TPM_RC_BAD_CONTEXT (TPM_RC)(RC_VER1 + 0x050)
+#define TPM_RC_CPHASH (TPM_RC)(RC_VER1 + 0x051)
+#define TPM_RC_PARENT (TPM_RC)(RC_VER1 + 0x052)
+#define TPM_RC_NEEDS_TEST (TPM_RC)(RC_VER1 + 0x053)
+#define TPM_RC_NO_RESULT (TPM_RC)(RC_VER1 + 0x054)
+#define TPM_RC_SENSITIVE (TPM_RC)(RC_VER1 + 0x055)
+#define RC_MAX_FM0 (TPM_RC)(RC_VER1 + 0x07F)
+#define RC_FMT1 (TPM_RC)(0x080)
+#define TPM_RC_ASYMMETRIC (TPM_RC)(RC_FMT1 + 0x001)
+#define TPM_RCS_ASYMMETRIC (TPM_RCS)(RC_FMT1 + 0x001)
+#define TPM_RC_ATTRIBUTES (TPM_RC)(RC_FMT1 + 0x002)
+#define TPM_RCS_ATTRIBUTES (TPM_RCS)(RC_FMT1 + 0x002)
+#define TPM_RC_HASH (TPM_RC)(RC_FMT1 + 0x003)
+#define TPM_RCS_HASH (TPM_RCS)(RC_FMT1 + 0x003)
+#define TPM_RC_VALUE (TPM_RC)(RC_FMT1 + 0x004)
+#define TPM_RCS_VALUE (TPM_RCS)(RC_FMT1 + 0x004)
+#define TPM_RC_HIERARCHY (TPM_RC)(RC_FMT1 + 0x005)
+#define TPM_RCS_HIERARCHY (TPM_RCS)(RC_FMT1 + 0x005)
+#define TPM_RC_KEY_SIZE (TPM_RC)(RC_FMT1 + 0x007)
+#define TPM_RCS_KEY_SIZE (TPM_RCS)(RC_FMT1 + 0x007)
+#define TPM_RC_MGF (TPM_RC)(RC_FMT1 + 0x008)
+#define TPM_RCS_MGF (TPM_RCS)(RC_FMT1 + 0x008)
+#define TPM_RC_MODE (TPM_RC)(RC_FMT1 + 0x009)
+#define TPM_RCS_MODE (TPM_RCS)(RC_FMT1 + 0x009)
+#define TPM_RC_TYPE (TPM_RC)(RC_FMT1 + 0x00A)
+#define TPM_RCS_TYPE (TPM_RCS)(RC_FMT1 + 0x00A)
+#define TPM_RC_HANDLE (TPM_RC)(RC_FMT1 + 0x00B)
+#define TPM_RCS_HANDLE (TPM_RCS)(RC_FMT1 + 0x00B)
+#define TPM_RC_KDF (TPM_RC)(RC_FMT1 + 0x00C)
+#define TPM_RCS_KDF (TPM_RCS)(RC_FMT1 + 0x00C)
+#define TPM_RC_RANGE (TPM_RC)(RC_FMT1 + 0x00D)
+#define TPM_RCS_RANGE (TPM_RCS)(RC_FMT1 + 0x00D)
+#define TPM_RC_AUTH_FAIL (TPM_RC)(RC_FMT1 + 0x00E)
+#define TPM_RCS_AUTH_FAIL (TPM_RCS)(RC_FMT1 + 0x00E)
+#define TPM_RC_NONCE (TPM_RC)(RC_FMT1 + 0x00F)
+#define TPM_RCS_NONCE (TPM_RCS)(RC_FMT1 + 0x00F)
+#define TPM_RC_PP (TPM_RC)(RC_FMT1 + 0x010)
+#define TPM_RCS_PP (TPM_RCS)(RC_FMT1 + 0x010)
+#define TPM_RC_SCHEME (TPM_RC)(RC_FMT1 + 0x012)
+#define TPM_RCS_SCHEME (TPM_RCS)(RC_FMT1 + 0x012)
+#define TPM_RC_SIZE (TPM_RC)(RC_FMT1 + 0x015)
+#define TPM_RCS_SIZE (TPM_RCS)(RC_FMT1 + 0x015)
+#define TPM_RC_SYMMETRIC (TPM_RC)(RC_FMT1 + 0x016)
+#define TPM_RCS_SYMMETRIC (TPM_RCS)(RC_FMT1 + 0x016)
+#define TPM_RC_TAG (TPM_RC)(RC_FMT1 + 0x017)
+#define TPM_RCS_TAG (TPM_RCS)(RC_FMT1 + 0x017)
+#define TPM_RC_SELECTOR (TPM_RC)(RC_FMT1 + 0x018)
+#define TPM_RCS_SELECTOR (TPM_RCS)(RC_FMT1 + 0x018)
+#define TPM_RC_INSUFFICIENT (TPM_RC)(RC_FMT1 + 0x01A)
+#define TPM_RCS_INSUFFICIENT (TPM_RCS)(RC_FMT1 + 0x01A)
+#define TPM_RC_SIGNATURE (TPM_RC)(RC_FMT1 + 0x01B)
+#define TPM_RCS_SIGNATURE (TPM_RCS)(RC_FMT1 + 0x01B)
+#define TPM_RC_KEY (TPM_RC)(RC_FMT1 + 0x01C)
+#define TPM_RCS_KEY (TPM_RCS)(RC_FMT1 + 0x01C)
+#define TPM_RC_POLICY_FAIL (TPM_RC)(RC_FMT1 + 0x01D)
+#define TPM_RCS_POLICY_FAIL (TPM_RCS)(RC_FMT1 + 0x01D)
+#define TPM_RC_INTEGRITY (TPM_RC)(RC_FMT1 + 0x01F)
+#define TPM_RCS_INTEGRITY (TPM_RCS)(RC_FMT1 + 0x01F)
+#define TPM_RC_TICKET (TPM_RC)(RC_FMT1 + 0x020)
+#define TPM_RCS_TICKET (TPM_RCS)(RC_FMT1 + 0x020)
+#define TPM_RC_RESERVED_BITS (TPM_RC)(RC_FMT1 + 0x021)
+#define TPM_RCS_RESERVED_BITS (TPM_RCS)(RC_FMT1 + 0x021)
+#define TPM_RC_BAD_AUTH (TPM_RC)(RC_FMT1 + 0x022)
+#define TPM_RCS_BAD_AUTH (TPM_RCS)(RC_FMT1 + 0x022)
+#define TPM_RC_EXPIRED (TPM_RC)(RC_FMT1 + 0x023)
+#define TPM_RCS_EXPIRED (TPM_RCS)(RC_FMT1 + 0x023)
+#define TPM_RC_POLICY_CC (TPM_RC)(RC_FMT1 + 0x024 )
+#define TPM_RCS_POLICY_CC (TPM_RCS)(RC_FMT1 + 0x024 )
+#define TPM_RC_BINDING (TPM_RC)(RC_FMT1 + 0x025)
+#define TPM_RCS_BINDING (TPM_RCS)(RC_FMT1 + 0x025)
+#define TPM_RC_CURVE (TPM_RC)(RC_FMT1 + 0x026)
+#define TPM_RCS_CURVE (TPM_RCS)(RC_FMT1 + 0x026)
+#define TPM_RC_ECC_POINT (TPM_RC)(RC_FMT1 + 0x027)
+#define TPM_RCS_ECC_POINT (TPM_RCS)(RC_FMT1 + 0x027)
+#define RC_WARN (TPM_RC)(0x900)
+#define TPM_RC_CONTEXT_GAP (TPM_RC)(RC_WARN + 0x001)
+#define TPM_RC_OBJECT_MEMORY (TPM_RC)(RC_WARN + 0x002)
+#define TPM_RC_SESSION_MEMORY (TPM_RC)(RC_WARN + 0x003)
+#define TPM_RC_MEMORY (TPM_RC)(RC_WARN + 0x004)
+#define TPM_RC_SESSION_HANDLES (TPM_RC)(RC_WARN + 0x005)
+#define TPM_RC_OBJECT_HANDLES (TPM_RC)(RC_WARN + 0x006)
+#define TPM_RC_LOCALITY (TPM_RC)(RC_WARN + 0x007)
+#define TPM_RC_YIELDED (TPM_RC)(RC_WARN + 0x008)
+#define TPM_RC_CANCELLED (TPM_RC)(RC_WARN + 0x009)
+#define TPM_RC_TESTING (TPM_RC)(RC_WARN + 0x00A)
+#define TPM_RC_REFERENCE_H0 (TPM_RC)(RC_WARN + 0x010)
+#define TPM_RC_REFERENCE_H1 (TPM_RC)(RC_WARN + 0x011)
+#define TPM_RC_REFERENCE_H2 (TPM_RC)(RC_WARN + 0x012)
+#define TPM_RC_REFERENCE_H3 (TPM_RC)(RC_WARN + 0x013)
+#define TPM_RC_REFERENCE_H4 (TPM_RC)(RC_WARN + 0x014)
+#define TPM_RC_REFERENCE_H5 (TPM_RC)(RC_WARN + 0x015)
+#define TPM_RC_REFERENCE_H6 (TPM_RC)(RC_WARN + 0x016)
+#define TPM_RC_REFERENCE_S0 (TPM_RC)(RC_WARN + 0x018)
+#define TPM_RC_REFERENCE_S1 (TPM_RC)(RC_WARN + 0x019)
+#define TPM_RC_REFERENCE_S2 (TPM_RC)(RC_WARN + 0x01A)
+#define TPM_RC_REFERENCE_S3 (TPM_RC)(RC_WARN + 0x01B)
+#define TPM_RC_REFERENCE_S4 (TPM_RC)(RC_WARN + 0x01C)
+#define TPM_RC_REFERENCE_S5 (TPM_RC)(RC_WARN + 0x01D)
+#define TPM_RC_REFERENCE_S6 (TPM_RC)(RC_WARN + 0x01E)
+#define TPM_RC_NV_RATE (TPM_RC)(RC_WARN + 0x020)
+#define TPM_RC_LOCKOUT (TPM_RC)(RC_WARN + 0x021)
+#define TPM_RC_RETRY (TPM_RC)(RC_WARN + 0x022)
+#define TPM_RC_NV_UNAVAILABLE (TPM_RC)(RC_WARN + 0x023)
+#define TPM_RC_NOT_USED (TPM_RC)(RC_WARN + 0x7F)
+#define TPM_RC_H (TPM_RC)(0x000)
+#define TPM_RC_P (TPM_RC)(0x040)
+#define TPM_RC_S (TPM_RC)(0x800)
+#define TPM_RC_1 (TPM_RC)(0x100)
+#define TPM_RC_2 (TPM_RC)(0x200)
+#define TPM_RC_3 (TPM_RC)(0x300)
+#define TPM_RC_4 (TPM_RC)(0x400)
+#define TPM_RC_5 (TPM_RC)(0x500)
+#define TPM_RC_6 (TPM_RC)(0x600)
+#define TPM_RC_7 (TPM_RC)(0x700)
+#define TPM_RC_8 (TPM_RC)(0x800)
+#define TPM_RC_9 (TPM_RC)(0x900)
+#define TPM_RC_A (TPM_RC)(0xA00)
+#define TPM_RC_B (TPM_RC)(0xB00)
+#define TPM_RC_C (TPM_RC)(0xC00)
+#define TPM_RC_D (TPM_RC)(0xD00)
+#define TPM_RC_E (TPM_RC)(0xE00)
+#define TPM_RC_F (TPM_RC)(0xF00)
+#define TPM_RC_N_MASK (TPM_RC)(0xF00)
+
+// Table 18 -- TPM_ST Constants <I/O,S>
+typedef u16 TPM_ST;
+
+#define TPM_ST_RSP_COMMAND (TPM_ST)(0x00C4)
+#define TPM_ST_NULL (TPM_ST)(0X8000)
+#define TPM_ST_NO_SESSIONS (TPM_ST)(0x8001)
+#define TPM_ST_SESSIONS (TPM_ST)(0x8002)
+#define TPM_ST_ATTEST_NV (TPM_ST)(0x8014)
+#define TPM_ST_ATTEST_COMMAND_AUDIT (TPM_ST)(0x8015)
+#define TPM_ST_ATTEST_SESSION_AUDIT (TPM_ST)(0x8016)
+#define TPM_ST_ATTEST_CERTIFY (TPM_ST)(0x8017)
+#define TPM_ST_ATTEST_QUOTE (TPM_ST)(0x8018)
+#define TPM_ST_ATTEST_TIME (TPM_ST)(0x8019)
+#define TPM_ST_ATTEST_CREATION (TPM_ST)(0x801A)
+#define TPM_ST_CREATION (TPM_ST)(0x8021)
+#define TPM_ST_VERIFIED (TPM_ST)(0x8022)
+#define TPM_ST_AUTH_SECRET (TPM_ST)(0x8023)
+#define TPM_ST_HASHCHECK (TPM_ST)(0x8024)
+#define TPM_ST_AUTH_SIGNED (TPM_ST)(0x8025)
+#define TPM_ST_FU_MANIFEST (TPM_ST)(0x8029)
+
+// Table 19 -- TPM_SU Constants <I>
+typedef u16 TPM_SU;
+
+#define TPM_SU_CLEAR (TPM_SU)(0x0000)
+#define TPM_SU_STATE (TPM_SU)(0x0001)
+
+// Table 21 -- TPM_CAP Constants <I/O,S>
+typedef u32 TPM_CAP;
+
+#define TPM_CAP_FIRST (TPM_CAP)(0x00000000)
+#define TPM_CAP_ALGS (TPM_CAP)(0x00000000)
+#define TPM_CAP_HANDLES (TPM_CAP)(0x00000001)
+#define TPM_CAP_COMMANDS (TPM_CAP)(0x00000002)
+#define TPM_CAP_PP_COMMANDS (TPM_CAP)(0x00000003)
+#define TPM_CAP_AUDIT_COMMANDS (TPM_CAP)(0x00000004)
+#define TPM_CAP_PCRS (TPM_CAP)(0x00000005)
+#define TPM_CAP_TPM_PROPERTIES (TPM_CAP)(0x00000006)
+#define TPM_CAP_PCR_PROPERTIES (TPM_CAP)(0x00000007)
+#define TPM_CAP_ECC_CURVES (TPM_CAP)(0x00000008)
+#define TPM_CAP_LAST (TPM_CAP)(0x00000008)
+#define TPM_CAP_VENDOR_PROPERTY (TPM_CAP)(0x00000100)
+
+// Table 25 -- Handles Types <I/O>
+typedef u32 TPM_HANDLE;
+typedef u8 TPM_HT;
+
+#define TPM_HT_PCR (TPM_HT)(0x00)
+#define TPM_HT_NV_INDEX (TPM_HT)(0x01)
+#define TPM_HT_HMAC_SESSION (TPM_HT)(0x02)
+#define TPM_HT_LOADED_SESSION (TPM_HT)(0x02)
+#define TPM_HT_POLICY_SESSION (TPM_HT)(0x03)
+#define TPM_HT_ACTIVE_SESSION (TPM_HT)(0x03)
+#define TPM_HT_PERMANENT (TPM_HT)(0x40)
+#define TPM_HT_TRANSIENT (TPM_HT)(0x80)
+#define TPM_HT_PERSISTENT (TPM_HT)(0x81)
+
+// Table 27 -- TPM_RH Constants <I,S>
+typedef u32 TPM_RH;
+
+#define TPM_RH_FIRST (TPM_RH)(0x40000000)
+#define TPM_RH_SRK (TPM_RH)(0x40000000)
+#define TPM_RH_OWNER (TPM_RH)(0x40000001)
+#define TPM_RH_REVOKE (TPM_RH)(0x40000002)
+#define TPM_RH_TRANSPORT (TPM_RH)(0x40000003)
+#define TPM_RH_OPERATOR (TPM_RH)(0x40000004)
+#define TPM_RH_ADMIN (TPM_RH)(0x40000005)
+#define TPM_RH_EK (TPM_RH)(0x40000006)
+#define TPM_RH_NULL (TPM_RH)(0x40000007)
+#define TPM_RH_UNASSIGNED (TPM_RH)(0x40000008)
+#define TPM_RS_PW (TPM_RH)(0x40000009)
+#define TPM_RH_LOCKOUT (TPM_RH)(0x4000000A)
+#define TPM_RH_ENDORSEMENT (TPM_RH)(0x4000000B)
+#define TPM_RH_PLATFORM (TPM_RH)(0x4000000C)
+#define TPM_RH_LAST (TPM_RH)(0x4000000C)
+
+// Table 29 -- TPMA_ALGORITHM Bits <I/O>
+typedef struct {
+ unsigned int asymmetric : 1;
+ unsigned int symmetric : 1;
+ unsigned int hash : 1;
+ unsigned int object : 1;
+ unsigned int reserved5 : 4;
+ unsigned int signing : 1;
+ unsigned int encrypting : 1;
+ unsigned int method : 1;
+ unsigned int reserved9 : 21;
+} TPMA_ALGORITHM ;
+
+// Table 30 -- TPMA_OBJECT Bits <I/O>
+typedef struct {
+ unsigned int reserved1 : 1;
+ unsigned int fixedTPM : 1;
+ unsigned int stClear : 1;
+ unsigned int reserved4 : 1;
+ unsigned int fixedParent : 1;
+ unsigned int sensitiveDataOrigin : 1;
+ unsigned int userWithAuth : 1;
+ unsigned int adminWithPolicy : 1;
+ unsigned int reserved9 : 2;
+ unsigned int noDA : 1;
+ unsigned int encryptedDuplication : 1;
+ unsigned int reserved12 : 4;
+ unsigned int restricted : 1; // Start of 2nd dword
+ unsigned int decrypt : 1;
+ unsigned int sign : 1;
+ unsigned int reserved16 : 13;
+} TPMA_OBJECT ;
+
+// Table 31 -- TPMA_SESSION Bits <I/O>
+typedef struct {
+ unsigned int continueSession : 1;
+ unsigned int auditExclusive : 1;
+ unsigned int auditReset : 1;
+ unsigned int reserved4 : 2;
+ unsigned int decrypt : 1;
+ unsigned int encrypt : 1;
+ unsigned int audit : 1;
+} TPMA_SESSION;
+
+// Table 32 -- TPMA_LOCALITY Bits <I/O>
+typedef struct {
+ unsigned int TPM_LOC_ZERO : 1;
+ unsigned int TPM_LOC_ONE : 1;
+ unsigned int TPM_LOC_TWO : 1;
+ unsigned int TPM_LOC_THREE : 1;
+ unsigned int TPM_LOC_FOUR : 1;
+ unsigned int reserved6 : 3;
+} TPMA_LOCALITY;
+
+// Table 66 -- TPMU_HA Union <I/O,S>
+typedef union {
+#ifdef TPM_ALG_SHA1
+ u8 sha1[SHA1_DIGEST_SIZE];
+#endif
+#ifdef TPM_ALG_SHA256
+ u8 sha256[SHA256_DIGEST_SIZE];
+#endif
+#ifdef TPM_ALG_SM3_256
+ u8 sm3_256[SM3_256_DIGEST_SIZE];
+#endif
+#ifdef TPM_ALG_SHA384
+ u8 sha384[SHA384_DIGEST_SIZE];
+#endif
+#ifdef TPM_ALG_SHA512
+ u8 sha512[SHA512_DIGEST_SIZE];
+#endif
+} TPMU_HA ;
+
+// Table 67 -- TPMT_HA Structure <I/O>
+typedef struct {
+ u16 hash_alg;
+ TPMU_HA digest;
+} TPMT_HA;
+
+// Table 68 -- TPM2B_DIGEST Structure <I/O>
+typedef struct {
+ u16 size;
+ u8 buffer[sizeof(TPMU_HA)];
+} DIGEST_2B;
+
+typedef union {
+ DIGEST_2B t;
+ TPM2B b;
+} TPM2B_DIGEST;
+
+// Table 69 -- TPM2B_DATA Structure <I/O>
+typedef struct {
+ u16 size;
+ u8 buffer[sizeof(TPMT_HA)];
+} DATA_2B;
+
+typedef union {
+ DATA_2B t;
+ TPM2B b;
+} TPM2B_DATA;
+
+// Table 70 -- TPM2B_NONCE Types <I/O>
+typedef TPM2B_DIGEST TPM2B_NONCE;
+
+// Table 71 -- TPM2B_AUTH Types <I/O>
+typedef TPM2B_DIGEST TPM2B_AUTH;
+
+// Table 73 -- TPM2B_EVENT Structure <I/O>
+typedef struct {
+ u16 size;
+ u8 buffer[1024];
+} EVENT_2B;
+
+typedef union {
+ EVENT_2B t;
+ TPM2B b;
+} TPM2B_EVENT;
+
+// Table 74 -- TPM2B_MAX_BUFFER Structure <I/O>
+typedef struct {
+ u16 size;
+ u8 buffer[MAX_DIGEST_BUFFER];
+} MAX_BUFFER_2B;
+
+typedef union {
+ MAX_BUFFER_2B t;
+ TPM2B b;
+} TPM2B_MAX_BUFFER;
+
+// Table 75 -- TPM2B_MAX_NV_BUFFER Structure <I/O>
+typedef struct {
+ u16 size;
+ u8 buffer[MAX_NV_INDEX_SIZE];
+} MAX_NV_BUFFER_2B;
+
+typedef union {
+ MAX_NV_BUFFER_2B t;
+ TPM2B b;
+} TPM2B_MAX_NV_BUFFER;
+
+// Table 79 -- TPMU_NAME Structure
+typedef union {
+ TPMT_HA digest;
+ u32 handle;
+} TPMU_NAME ;
+
+// Table 79 -- TPM2B_NAME Structure <I/O>
+typedef struct {
+ u16 size;
+ u8 name[sizeof(TPMU_NAME)];
+} NAME_2B;
+
+typedef union {
+ NAME_2B t;
+ TPM2B b;
+} TPM2B_NAME;
+
+// Table 80 -- TPMS_PCR_SELECTION Structure <I/O>
+typedef struct {
+ u16 hash;
+ u8 size_of_select;
+ u8 pcr_select[PCR_SELECT_MAX];
+} TPMS_PCR_SELECTION;
+
+// Table 84 -- TPMT_TK_CREATION Structure <I/O>
+typedef struct {
+ u16 tag;
+ u32 hierarchy;
+ TPM2B_DIGEST digest;
+} TPMT_TK_CREATION;
+
+// Table 86 -- TPMT_TK_HASHCHECK Structure <I/O>
+typedef struct {
+ u16 tag;
+ u32 hierarchy;
+ TPM2B_DIGEST digest;
+} TPMT_TK_HASHCHECK;
+
+// Table 88 -- TPMS_ALG_PROPERTY Structure <O,S>
+typedef struct {
+ u16 alg;
+ TPMA_ALGORITHM alg_pro;
+} TPMS_ALG_PROPERTY;
+
+// Table 95 -- TPML_DIGEST Structure <I/O>
+typedef struct {
+ u32 count;
+ TPM2B_DIGEST digests[8];
+} TPML_DIGEST;
+
+// Table 96 -- TPML_DIGEST_VALUES Structure <I/O>
+typedef struct {
+ u32 count;
+ TPMT_HA digests[HASH_COUNT];
+} TPML_DIGEST_VALUES;
+
+// Table 98 -- TPML_PCR_SELECTION Structure <I/O>
+typedef struct {
+ u32 count;
+ TPMS_PCR_SELECTION selections[HASH_COUNT];
+} TPML_PCR_SELECTION;
+
+#define MAX_CAP_DATA (MAX_CAP_BUFFER-sizeof(u32)-sizeof(u32))
+#define MAX_CAP_ALGS (MAX_CAP_DATA/sizeof(TPMS_ALG_PROPERTY))
+// Table 99 -- TPML_ALG_PROPERTY Structure <O,S>
+typedef struct {
+ u32 count;
+ TPMS_ALG_PROPERTY alg_pros[MAX_CAP_ALGS];
+} TPML_ALG_PROPERTY;
+
+// Table 103 -- TPMU_CAPABILITIES Union <O,S>
+typedef union {
+ TPML_ALG_PROPERTY algs;
+} TPMU_CAPABILITIES;
+
+// Table 104 -- TPMS_CAPABILITY_DATA Structure <O,S>
+typedef struct {
+ u32 capability;
+ TPMU_CAPABILITIES data;
+} TPMS_CAPABILITY_DATA;
+
+// Table 122 -- TPMU_SYM_KEY_BITS Union <I/O>
+typedef union {
+#ifdef TPM_ALG_AES
+ u16 aes;
+#endif
+#ifdef TPM_ALG_SM4
+ u16 sm4;
+#endif
+ u16 sym;
+#ifdef TPM_ALG_XOR
+ u16 xor;
+#endif
+} TPMU_SYM_KEY_BITS ;
+
+// Table 122 -- TPMU_SYM_MODE Union <I/O>
+typedef union {
+#ifdef TPM_ALG_AES
+ u16 aes;
+#endif
+#ifdef TPM_ALG_SM4
+ u16 sm4;
+#endif
+ u16 sym;
+} TPMU_SYM_MODE ;
+
+// Table 126 -- TPMT_SYM_DEF_OBJECT Structure <I/O>
+typedef struct {
+ u16 alg;
+ TPMU_SYM_KEY_BITS key_bits;
+ TPMU_SYM_MODE mode;
+} TPMT_SYM_DEF_OBJECT;
+
+// Table 126 -- TPM2B_SYM_KEY Structure <I/O>
+typedef struct {
+ u16 size;
+ u8 buffer[MAX_SYM_KEY_BYTES];
+} SYM_KEY_2B;
+
+typedef union {
+ SYM_KEY_2B t;
+ TPM2B b;
+} TPM2B_SYM_KEY;
+
+// Table 129 -- TPM2B_SENSITIVE_DATA Structure <I/O>
+typedef struct {
+ u16 size;
+ u8 buffer[MAX_SYM_DATA];
+} SENSITIVE_DATA_2B;
+
+typedef union {
+ SENSITIVE_DATA_2B t;
+ TPM2B b;
+} TPM2B_SENSITIVE_DATA;
+
+// Table 130 -- TPMS_SENSITIVE_CREATE Structure <I>
+typedef struct {
+ TPM2B_AUTH user_auth;
+ TPM2B_SENSITIVE_DATA data;
+} TPMS_SENSITIVE_CREATE;
+
+// Table 131 -- TPM2B_SENSITIVE_CREATE Structure <I,S>
+typedef struct {
+ u16 size;
+ TPMS_SENSITIVE_CREATE sensitive;
+} SENSITIVE_CREATE_2B;
+
+typedef union {
+ SENSITIVE_CREATE_2B t;
+ TPM2B b;
+} TPM2B_SENSITIVE_CREATE;
+
+// Table 132 -- TPMS_SCHEME_SIGHASH Structure <I/O>
+typedef struct {
+ u16 hash_alg;
+} TPMS_SCHEME_SIGHASH;
+
+// Table 134 -- HMAC_SIG_SCHEME Types <I/O>
+typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_HMAC;
+
+// Table 135 -- TPMS_SCHEME_XOR Structure <I/O>
+typedef struct {
+ u16 hash_alg;
+ u16 kdf;
+} TPMS_SCHEME_XOR;
+
+// Table 136 -- TPMU_SCHEME_KEYEDHASH Union <I/O,S>
+typedef union {
+#ifdef TPM_ALG_HMAC
+ TPMS_SCHEME_HMAC hmac;
+#endif
+#ifdef TPM_ALG_XOR
+ TPMS_SCHEME_XOR xor;
+#endif
+
+} TPMU_SCHEME_KEYEDHASH;
+
+// Table 137 -- TPMT_KEYEDHASH_SCHEME Structure <I/O>
+typedef struct {
+ u16 scheme;
+ TPMU_SCHEME_KEYEDHASH details;
+} TPMT_KEYEDHASH_SCHEME;
+
+// Table 138 -- RSA_SIG_SCHEMES Types <I/O>
+typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_RSASSA;
+typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_RSAPSS;
+
+// Table 139 -- ECC_SIG_SCHEMES Types <I/O>
+typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_ECDSA;
+typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_SM2;
+typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_ECSCHNORR;
+
+// Table 140 -- TPMS_SCHEME_ECDAA Structure <I/O>
+typedef struct {
+ u16 hash_alg;
+ u16 count;
+} TPMS_SCHEME_ECDAA;
+
+// Table 141 -- TPMU_SIG_SCHEME Union <I/O,S>
+typedef union {
+#ifdef TPM_ALG_RSASSA
+ TPMS_SCHEME_RSASSA rsassa;
+#endif
+#ifdef TPM_ALG_RSAPSS
+ TPMS_SCHEME_RSAPSS rsapss;
+#endif
+#ifdef TPM_ALG_ECDSA
+ TPMS_SCHEME_ECDSA ecdsa;
+#endif
+#ifdef TPM_ALG_SM2
+ TPMS_SCHEME_SM2 sm2;
+#endif
+#ifdef TPM_ALG_ECDAA
+ TPMS_SCHEME_ECDAA ecdaa;
+#endif
+#ifdef TPM_ALG_ECSCHNORR
+ TPMS_SCHEME_ECSCHNORR ec_schnorr;
+#endif
+#ifdef TPM_ALG_HMAC
+ TPMS_SCHEME_HMAC hmac;
+#endif
+ TPMS_SCHEME_SIGHASH any;
+
+} TPMU_SIG_SCHEME ;
+
+// Table 143 -- TPMS_SCHEME_OAEP Structure <I/O>
+typedef struct {
+ u16 hash_alg;
+} TPMS_SCHEME_OAEP;
+
+// Table 145 -- TPMS_SCHEME_MGF1 Structure <I/O>
+typedef struct {
+ u16 hash_alg;
+} TPMS_SCHEME_MGF1;
+
+// Table 146 -- TPMS_SCHEME_KDF1_SP800_56a Structure <I/O>
+typedef struct {
+ u16 hash_alg;
+} TPMS_SCHEME_KDF1_SP800_56a;
+
+// Table 147 -- TPMS_SCHEME_KDF2 Structure <I/O>
+typedef struct {
+ u16 hash_alg;
+} TPMS_SCHEME_KDF2;
+
+// Table 148 -- TPMS_SCHEME_KDF1_SP800_108 Structure <I/O>
+typedef struct {
+ u16 hash_alg;
+} TPMS_SCHEME_KDF1_SP800_108;
+
+// Table 149 -- TPMU_KDF_SCHEME Union <I/O,S>
+typedef union {
+#ifdef TPM_ALG_MGF1
+ TPMS_SCHEME_MGF1 mgf1;
+#endif
+#ifdef TPM_ALG_KDF1_SP800_56a
+ TPMS_SCHEME_KDF1_SP800_56a kdf1_SP800_56a;
+#endif
+#ifdef TPM_ALG_KDF2
+ TPMS_SCHEME_KDF2 kdf2;
+#endif
+#ifdef TPM_ALG_KDF1_SP800_108
+ TPMS_SCHEME_KDF1_SP800_108 kdf1_sp800_108;
+#endif
+} TPMU_KDF_SCHEME ;
+
+// Table 150 -- TPMT_KDF_SCHEME Structure <I/O>
+typedef struct {
+ u16 scheme;
+ TPMU_KDF_SCHEME details;
+} TPMT_KDF_SCHEME;
+
+// Table 152 -- TPMU_ASYM_SCHEME Union <I/O>
+typedef union {
+#ifdef TPM_ALG_RSASSA
+ TPMS_SCHEME_RSASSA rsassa;
+#endif
+#ifdef TPM_ALG_RSAPSS
+ TPMS_SCHEME_RSAPSS rsapss;
+#endif
+#ifdef TPM_ALG_OAEP
+ TPMS_SCHEME_OAEP oaep;
+#endif
+#ifdef TPM_ALG_ECDSA
+ TPMS_SCHEME_ECDSA ecdsa;
+#endif
+#ifdef TPM_ALG_SM2
+ TPMS_SCHEME_SM2 sm2;
+#endif
+#ifdef TPM_ALG_ECDAA
+ TPMS_SCHEME_ECDAA ecdaa;
+#endif
+#ifdef TPM_ALG_ECSCHNORR
+ TPMS_SCHEME_ECSCHNORR ec_schnorr;
+#endif
+ TPMS_SCHEME_SIGHASH any;
+
+} TPMU_ASYM_SCHEME;
+
+// Table 153 -- TPMT_ASYM_SCHEME Structure <>
+typedef struct {
+ u16 scheme;
+ TPMU_ASYM_SCHEME details;
+} TPMT_ASYM_SCHEME;
+
+// Table 155 -- TPMT_RSA_SCHEME Structure <I/O>
+typedef struct {
+ u16 scheme;
+ TPMU_ASYM_SCHEME details;
+} TPMT_RSA_SCHEME;
+
+// Table 158 -- TPM2B_PUBLIC_KEY_RSA Structure <I/O>
+typedef struct {
+ u16 size;
+ u8 buffer[MAX_RSA_KEY_BYTES];
+} PUBLIC_KEY_RSA_2B;
+
+typedef union {
+ PUBLIC_KEY_RSA_2B t;
+ TPM2B b;
+} TPM2B_PUBLIC_KEY_RSA;
+
+// Table 160 -- TPM2B_PRIVATE_KEY_RSA Structure <I/O>
+typedef struct {
+ u16 size;
+ u8 buffer[MAX_RSA_KEY_BYTES/2];
+} PRIVATE_KEY_RSA_2B;
+
+typedef union {
+ PRIVATE_KEY_RSA_2B t;
+ TPM2B b;
+} TPM2B_PRIVATE_KEY_RSA;
+
+// Table 161 -- TPM2B_ECC_PARAMETER Structure <I/O>
+typedef struct {
+ u16 size;
+ u8 buffer[MAX_ECC_KEY_BYTES];
+} ECC_PARAMETER_2B;
+
+typedef union {
+ ECC_PARAMETER_2B t;
+ TPM2B b;
+} TPM2B_ECC_PARAMETER;
+
+// Table 162 -- TPMS_ECC_POINT Structure <I/O>
+typedef struct {
+ TPM2B_ECC_PARAMETER x;
+ TPM2B_ECC_PARAMETER y;
+} TPMS_ECC_POINT;
+
+// Table 166 -- TPMT_ECC_SCHEME Structure <I/O>
+typedef struct {
+ u16 scheme;
+ TPMU_SIG_SCHEME details;
+} TPMT_ECC_SCHEME;
+
+// Table 176 -- TPMU_PUBLIC_ID Union <I/O,S>
+typedef union {
+#ifdef TPM_ALG_KEYEDHASH
+ TPM2B_DIGEST keyed_hash;
+#endif
+#ifdef TPM_ALG_SYMCIPHER
+ TPM2B_DIGEST sym;
+#endif
+#ifdef TPM_ALG_RSA
+ TPM2B_PUBLIC_KEY_RSA rsa;
+#endif
+#ifdef TPM_ALG_ECC
+ TPMS_ECC_POINT ecc;
+#endif
+} TPMU_PUBLIC_ID;
+
+// Table 177 -- TPMS_KEYEDHASH_PARMS Structure <I/O>
+typedef struct {
+ TPMT_KEYEDHASH_SCHEME scheme;
+} TPMS_KEYEDHASH_PARMS;
+
+// Table 178 -- TPMS_ASYM_PARMS Structure <I/O>
+typedef struct {
+ TPMT_SYM_DEF_OBJECT symmetric;
+ TPMT_ASYM_SCHEME scheme;
+} TPMS_ASYM_PARMS;
+
+// Table 179 -- TPMS_RSA_PARMS Structure <I/O>
+typedef struct {
+ TPMT_SYM_DEF_OBJECT symmetric;
+ TPMT_RSA_SCHEME scheme;
+ u16 key_bits;
+ u32 exponent;
+} TPMS_RSA_PARMS;
+
+// Table 180 -- TPMS_ECC_PARMS Structure <I/O>
+typedef struct {
+ TPMT_SYM_DEF_OBJECT symmetric;
+ TPMT_ECC_SCHEME scheme;
+ u16 curve_id;
+ TPMT_KDF_SCHEME kdf;
+} TPMS_ECC_PARMS;
+
+// Table 181 -- TPMU_PUBLIC_PARMS Union <I/O,S>
+typedef union {
+#ifdef TPM_ALG_KEYEDHASH
+ TPMS_KEYEDHASH_PARMS keyed_hash;
+#endif
+#ifdef TPM_ALG_SYMCIPHER
+ TPMT_SYM_DEF_OBJECT sym;
+#endif
+#ifdef TPM_ALG_RSA
+ TPMS_RSA_PARMS rsa;
+#endif
+#ifdef TPM_ALG_ECC
+ TPMS_ECC_PARMS ecc;
+#endif
+ TPMS_ASYM_PARMS asym;
+
+} TPMU_PUBLIC_PARMS;
+
+// Table 184 -- TPMT_PUBLIC Structure <I/O>
+typedef struct {
+ u16 type;
+ u16 name_alg;
+ TPMA_OBJECT object_attr;
+ TPM2B_DIGEST auth_policy;
+ TPMU_PUBLIC_PARMS param;
+ TPMU_PUBLIC_ID unique;
+} TPMT_PUBLIC;
+
+// Table 185 -- TPM2B_PUBLIC Structure <I/O>
+typedef struct {
+ u16 size;
+ TPMT_PUBLIC public_area;
+} PUBLIC_2B;
+
+typedef union {
+ PUBLIC_2B t;
+ TPM2B b;
+} TPM2B_PUBLIC;
+
+// Table 186 -- TPMU_SENSITIVE_COMPOSITE Union <I/O,S>
+typedef union {
+#ifdef TPM_ALG_RSA
+ TPM2B_PRIVATE_KEY_RSA rsa;
+#endif
+#ifdef TPM_ALG_ECC
+ TPM2B_ECC_PARAMETER ecc;
+#endif
+#ifdef TPM_ALG_KEYEDHASH
+ TPM2B_SENSITIVE_DATA bits;
+#endif
+#ifdef TPM_ALG_SYMCIPHER
+ TPM2B_SYM_KEY sym;
+#endif
+ TPM2B_SENSITIVE_DATA any;
+
+} TPMU_SENSITIVE_COMPOSITE ;
+
+// Table 187 -- TPMT_SENSITIVE Structure <I/O>
+typedef struct {
+ u16 type;
+ TPM2B_AUTH auth_value;
+ TPM2B_DIGEST seedValue;
+ TPMU_SENSITIVE_COMPOSITE sensitive;
+} TPMT_SENSITIVE;
+
+// Table 189 -- _PRIVATE Structure <>
+typedef struct {
+ TPM2B_DIGEST integrity_outer;
+ TPM2B_DIGEST integrity_inner;
+ TPMT_SENSITIVE sensitive;
+} _PRIVATE;
+
+// Table 190 -- TPM2B_PRIVATE Structure <I/O,S>
+typedef struct {
+ u16 size;
+ u8 buffer[sizeof(_PRIVATE)];
+} PRIVATE_2B;
+
+typedef union {
+ PRIVATE_2B t;
+ TPM2B b;
+} TPM2B_PRIVATE;
+
+// Table 195 -- TPMA_NV Bits <I/O>
+typedef struct {
+ unsigned int TPMA_NV_PPWRITE : 1;
+ unsigned int TPMA_NV_OWNERWRITE : 1;
+ unsigned int TPMA_NV_AUTHWRITE : 1;
+ unsigned int TPMA_NV_POLICYWRITE : 1;
+ unsigned int TPMA_NV_COUNTER : 1;
+ unsigned int TPMA_NV_BITS : 1;
+ unsigned int TPMA_NV_EXTEND : 1;
+ unsigned int reserved8 : 3;
+ unsigned int TPMA_NV_POLICY_DELETE : 1;
+ unsigned int TPMA_NV_WRITELOCKED : 1;
+ unsigned int TPMA_NV_WRITEALL : 1;
+ unsigned int TPMA_NV_WRITEDEFINE : 1;
+ unsigned int TPMA_NV_WRITE_STCLEAR : 1;
+ unsigned int TPMA_NV_GLOBALLOCK : 1;
+ unsigned int TPMA_NV_PPREAD : 1;
+ unsigned int TPMA_NV_OWNERREAD : 1;
+ unsigned int TPMA_NV_AUTHREAD : 1;
+ unsigned int TPMA_NV_POLICYREAD : 1;
+ unsigned int reserved19 : 5;
+ unsigned int TPMA_NV_NO_DA : 1;
+ unsigned int TPMA_NV_ORDERLY : 1;
+ unsigned int TPMA_NV_CLEAR_STCLEAR : 1;
+ unsigned int TPMA_NV_READLOCKED : 1;
+ unsigned int TPMA_NV_WRITTEN : 1;
+ unsigned int TPMA_NV_PLATFORMCREATE : 1;
+ unsigned int TPMA_NV_READ_STCLEAR : 1;
+} TPMA_NV ;
+
+// Table 196 -- TPMS_NV_PUBLIC Structure <I/O>
+typedef struct {
+ u32 index;
+ u16 name_alg;
+ TPMA_NV attr;
+ TPM2B_DIGEST auth_policy;
+ u16 data_size;
+} TPMS_NV_PUBLIC;
+
+// Table 197 -- TPM2B_NV_PUBLIC Structure <I/O>
+typedef struct {
+ u16 size;
+ TPMS_NV_PUBLIC nv_public;
+} NV_PUBLIC_2B;
+
+typedef union {
+ NV_PUBLIC_2B t;
+ TPM2B b;
+} TPM2B_NV_PUBLIC;
+
+// Table 203 -- TPMS_CREATION_DATA Structure <O,S>
+typedef struct {
+ TPML_PCR_SELECTION pcr_select;
+ TPM2B_DIGEST pcr_digest;
+ TPMA_LOCALITY locality;
+ u16 parent_name_alg;
+ TPM2B_NAME parent_name;
+ TPM2B_NAME parent_qualified_name;
+ TPM2B_DATA outside_info;
+} TPMS_CREATION_DATA;
+
+// Table 204 -- TPM2B_CREATION_DATA Structure <O,S>
+typedef struct {
+ u16 size;
+ TPMS_CREATION_DATA data;
+} CREATION_DATA_2B;
+
+typedef union {
+ CREATION_DATA_2B t;
+ TPM2B b;
+} TPM2B_CREATION_DATA;
+
+
+#define MAX_SESSIONS 3
+
+// Input structure for session data for a single session,
+typedef struct {
+ u32 session_handle;
+ TPM2B_NONCE nonce;
+ TPMA_SESSION session_attr;
+ TPM2B_AUTH hmac;
+} TPM_CMD_SESSION_DATA_IN ;
+
+// Input structure for sessions data.
+typedef struct {
+ u8 num_sessions;
+ TPM_CMD_SESSION_DATA_IN sessions[MAX_SESSION_NUM];
+} TPM_CMD_SESSIONS_IN;
+
+// Output structure for session data for a single session.
+typedef struct {
+ TPM2B_NONCE nonce;
+ TPMA_SESSION session_attr;
+ TPM2B_AUTH hmac;
+} TPM_CMD_SESSION_DATA_OUT;
+
+// Output structure for sessions data.
+typedef struct {
+ u8 num_sessions;
+ TPM_CMD_SESSION_DATA_OUT sessions[MAX_SESSION_NUM];
+} TPM_CMD_SESSIONS_OUT;
+
+
+/*
+ * command parameter related structure
+ */
+
+typedef struct {
+ TPML_PCR_SELECTION pcr_selection;
+} tpm_pcr_read_in;
+
+typedef struct {
+ u32 pcr_update_counter;
+ TPML_PCR_SELECTION pcr_selection;
+ TPML_DIGEST pcr_values;
+} tpm_pcr_read_out;
+
+typedef struct {
+ u32 pcr_handle;
+ TPM_CMD_SESSIONS_IN sessions;
+ TPML_DIGEST_VALUES digests;
+} tpm_pcr_extend_in;
+
+typedef struct {
+ TPM_CMD_SESSIONS_OUT sessions;
+} tpm_pcr_extend_out;
+
+typedef struct {
+ u32 pcr_handle;
+ TPM_CMD_SESSIONS_IN sessions;
+ TPM2B_EVENT data;
+} tpm_pcr_event_in;
+
+typedef struct {
+ TPML_DIGEST_VALUES digests;
+ TPM_CMD_SESSIONS_OUT sessions;
+} tpm_pcr_event_out;
+
+typedef struct {
+ u32 pcr_handle;
+ TPM_CMD_SESSIONS_IN sessions;
+} tpm_pcr_reset_in;
+
+typedef struct {
+ TPM_CMD_SESSIONS_OUT sessions;
+} tpm_pcr_reset_out;
+
+typedef struct {
+ TPM2B_AUTH auth;
+ u16 hash_alg;
+} tpm_sequence_start_in;
+
+typedef struct {
+ u32 handle;
+} tpm_sequence_start_out;
+
+typedef struct {
+ u32 handle;
+ TPM_CMD_SESSIONS_IN sessions;
+ TPM2B_MAX_BUFFER buf;
+} tpm_sequence_update_in;
+
+typedef struct {
+ TPM_CMD_SESSIONS_OUT sessions;
+} tpm_sequence_update_out;
+
+typedef struct {
+ u32 pcr_handle;
+ u32 seq_handle;
+ TPM_CMD_SESSIONS_IN sessions;
+ TPM2B_MAX_BUFFER buf;
+} tpm_sequence_complete_in;
+
+typedef struct {
+ TPML_DIGEST_VALUES results;
+ TPM_CMD_SESSIONS_OUT sessions;
+} tpm_sequence_complete_out;
+
+typedef struct {
+ u32 seq_handle;
+ TPM_CMD_SESSIONS_IN sessions;
+ TPM2B_MAX_BUFFER buf;
+ u32 hierarchy;
+} tpm_sequence_complete2_in;
+
+typedef struct {
+ TPML_DIGEST_VALUES results;
+ TPMT_TK_HASHCHECK validation;
+ TPM_CMD_SESSIONS_OUT sessions;
+} tpm_sequence_complete2_out;
+
+typedef struct {
+ u32 handle;
+ u32 index;
+ TPM_CMD_SESSIONS_IN sessions;
+ u16 size;
+ u16 offset;
+} tpm_nv_read_in;
+
+typedef struct {
+ TPM2B_MAX_NV_BUFFER data;
+ TPM_CMD_SESSIONS_OUT sessions;
+} tpm_nv_read_out;
+
+typedef struct {
+ u32 handle;
+ u32 index;
+ TPM_CMD_SESSIONS_IN sessions;
+ TPM2B_MAX_NV_BUFFER data;
+ u16 offset;
+} tpm_nv_write_in;
+
+typedef struct {
+ TPM_CMD_SESSIONS_OUT sessions;
+} tpm_nv_write_out;
+
+typedef struct {
+ u32 handle;
+ TPM_CMD_SESSIONS_IN sessions;
+ TPM2B_AUTH auth;
+ TPM2B_NV_PUBLIC public_info;
+} tpm_nv_define_space_in;
+
+typedef struct {
+ TPM_CMD_SESSIONS_OUT sessions;
+} tpm_nv_define_space_out;
+
+typedef struct {
+ u32 handle;
+ u32 index;
+ TPM_CMD_SESSIONS_IN sessions;
+} tpm_nv_undefine_space_in;
+
+typedef struct {
+ TPM_CMD_SESSIONS_OUT sessions;
+} tpm_nv_undefine_space_out;
+
+typedef struct {
+ u32 index;
+} tpm_nv_read_public_in;
+
+typedef struct {
+ TPM2B_NV_PUBLIC nv_public;
+ TPM2B_NAME nv_name;
+} tpm_nv_read_public_out;
+
+typedef struct {
+ u16 bytes_req;
+} tpm_get_random_in;
+
+typedef struct {
+ TPM2B_DIGEST random_bytes;
+} tpm_get_random_out;
+
+typedef struct {
+ u32 capability;
+ u32 property;
+ u32 property_count;
+} tpm_get_capability_in;
+
+typedef struct {
+ u8 more_data;
+ TPMS_CAPABILITY_DATA data;
+} tpm_get_capability_out;
+
+typedef struct {
+ u32 primary_handle;
+ TPM_CMD_SESSIONS_IN sessions;
+ TPM2B_SENSITIVE_CREATE sensitive;
+ TPM2B_PUBLIC public;
+ TPM2B_DATA outside_info;
+ TPML_PCR_SELECTION creation_pcr;
+} tpm_create_primary_in;
+
+typedef struct {
+ u32 obj_handle;
+ TPM2B_PUBLIC public;
+ TPM2B_CREATION_DATA creation_data;
+ TPM2B_DIGEST creation_hash;
+ TPMT_TK_CREATION creation_ticket;
+ TPM2B_NAME name;
+ TPM_CMD_SESSIONS_OUT sessions;
+} tpm_create_primary_out;
+
+typedef struct {
+ u32 parent_handle;
+ TPM_CMD_SESSIONS_IN sessions;
+ TPM2B_SENSITIVE_CREATE sensitive;
+ TPM2B_PUBLIC public;
+ TPM2B_DATA outside_info;
+ TPML_PCR_SELECTION creation_pcr;
+} tpm_create_in;
+
+typedef struct {
+ TPM2B_PRIVATE private;
+ TPM2B_PUBLIC public;
+ TPM2B_CREATION_DATA creation_data;
+ TPM2B_DIGEST creation_hash;
+ TPMT_TK_CREATION creation_ticket;
+ TPM_CMD_SESSIONS_OUT sessions;
+} tpm_create_out;
+
+typedef struct {
+ u32 parent_handle;
+ TPM_CMD_SESSIONS_IN sessions;
+ TPM2B_PRIVATE private;
+ TPM2B_PUBLIC public;
+} tpm_load_in;
+
+typedef struct {
+ u32 obj_handle;
+ TPM2B_NAME name;
+ TPM_CMD_SESSIONS_OUT sessions;
+} tpm_load_out;
+
+typedef struct {
+ u32 item_handle;
+ TPM_CMD_SESSIONS_IN sessions;
+} tpm_unseal_in;
+
+typedef struct {
+ TPM2B_SENSITIVE_DATA data;
+ TPM_CMD_SESSIONS_OUT sessions;
+} tpm_unseal_out;
+
+
+#endif /* __TPM20_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/txt/acmod.h b/tboot/include/txt/acmod.h
new file mode 100644
index 0000000..33f8b28
--- /dev/null
+++ b/tboot/include/txt/acmod.h
@@ -0,0 +1,195 @@
+/*
+ * acmod.c: support functions for use of Intel(r) TXT Authenticated
+ * Code (AC) Modules
+ *
+ * Copyright (c) 2003-2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TXT_ACMOD_H__
+#define __TXT_ACMOD_H__
+
+/*
+ * authenticated code (AC) module header (ver 0.0)
+ */
+
+typedef union {
+ uint16_t _raw;
+ struct {
+ uint16_t reserved : 14;
+ uint16_t pre_production : 1;
+ uint16_t debug_signed : 1;
+ };
+} acm_flags_t;
+
+typedef struct {
+ uint16_t module_type;
+ uint16_t module_subtype;
+ uint32_t header_len;
+ uint32_t header_ver; /* currently 0.0 */
+ uint16_t chipset_id;
+ acm_flags_t flags;
+ uint32_t module_vendor;
+ uint32_t date;
+ uint32_t size;
+ uint16_t txt_svn;
+ uint16_t se_svn;
+ uint32_t code_control;
+ uint32_t error_entry_point;
+ uint32_t gdt_limit;
+ uint32_t gdt_base;
+ uint32_t seg_sel;
+ uint32_t entry_point;
+ uint8_t reserved2[64];
+ uint32_t key_size;
+ uint32_t scratch_size;
+ uint8_t rsa2048_pubkey[256];
+ uint32_t pub_exp;
+ uint8_t rsa2048_sig[256];
+ uint32_t scratch[143];//
+ uint8_t user_area[];
+} acm_hdr_t;
+
+/* value of module_type field */
+#define ACM_TYPE_CHIPSET 0x02
+
+/* value of module_subtype field */
+#define ACM_SUBTYPE_RESET 0x01
+
+/* value of module_vendor field */
+#define ACM_VENDOR_INTEL 0x8086
+
+typedef union {
+ uint32_t _raw;
+ struct {
+ uint32_t ext_policy : 2;
+ uint32_t tpm_family : 4;
+ uint32_t tpm_nv_index_set : 1;
+ uint32_t reserved : 25;
+ };
+} tpm_cap_t;
+
+/* ext_policy field values */
+#define TPM_EXT_POLICY_ILLEGAL 0x00
+#define TPM_EXT_POLICY_ALG_AGILE_CMD 0x01
+#define TPM_EXT_POLICY_EMBEDED_ALGS 0x10
+#define TPM_EXT_POLICY_BOTH 0x11
+
+/* tpm_family field values */
+#define TPM_FAMILY_ILLEGAL 0x0000
+#define TPM_FAMILY_DTPM_12 0x0001
+#define TPM_FAMILY_DTPM_20 0x0010
+#define TPM_FAMILY_DTPM_BOTH 0x0011
+#define TPM_FAMILY_PTT_20 0x1000
+
+typedef struct {
+ tpm_cap_t capabilities;
+ uint16_t count;
+ uint16_t alg_id[];
+} tpm_info_list_t;
+
+typedef struct __packed {
+ uuid_t uuid;
+ uint8_t chipset_acm_type;
+ uint8_t version; /* currently 4 */
+ uint16_t length;
+ uint32_t chipset_id_list;
+ uint32_t os_sinit_data_ver;
+ uint32_t min_mle_hdr_ver;
+ txt_caps_t capabilities;
+ uint8_t acm_ver;
+ uint8_t reserved[3];
+ /* versions >= 4 */
+ uint32_t processor_id_list;
+ /* versions >= 5 */
+ uint32_t tpm_info_list_off;
+} acm_info_table_t;
+
+/* ACM UUID value */
+#define ACM_UUID_V3 {0x7fc03aaa, 0x46a7, 0x18db, 0xac2e, \
+ {0x69, 0x8f, 0x8d, 0x41, 0x7f, 0x5a}}
+
+/* chipset_acm_type field values */
+#define ACM_CHIPSET_TYPE_BIOS 0x00
+#define ACM_CHIPSET_TYPE_SINIT 0x01
+#define ACM_CHIPSET_TYPE_BIOS_REVOC 0x08
+#define ACM_CHIPSET_TYPE_SINIT_REVOC 0x09
+
+typedef struct __packed {
+ uint32_t flags;
+ uint16_t vendor_id;
+ uint16_t device_id;
+ uint16_t revision_id;
+ uint16_t reserved;
+ uint32_t extended_id;
+} acm_chipset_id_t;
+
+typedef struct __packed {
+ uint32_t count;
+ acm_chipset_id_t chipset_ids[];
+} acm_chipset_id_list_t;
+
+typedef struct __packed {
+ uint32_t fms;
+ uint32_t fms_mask;
+ uint64_t platform_id;
+ uint64_t platform_mask;
+} acm_processor_id_t;
+
+typedef struct __packed {
+ uint32_t count;
+ acm_processor_id_t processor_ids[];
+} acm_processor_id_list_t;
+
+acm_hdr_t *g_sinit;
+
+void print_txt_caps(const char *prefix, txt_caps_t caps);
+bool is_racm_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet);
+acm_hdr_t *copy_racm(const acm_hdr_t *racm);
+bool verify_racm(const acm_hdr_t *acm_hdr);
+bool is_sinit_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet);
+bool does_acmod_match_platform(const acm_hdr_t* hdr);
+acm_hdr_t *copy_sinit(const acm_hdr_t *sinit);
+bool verify_acmod(const acm_hdr_t *acm_hdr);
+uint32_t get_supported_os_sinit_data_ver(const acm_hdr_t* hdr);
+txt_caps_t get_sinit_capabilities(const acm_hdr_t* hdr);
+tpm_info_list_t *get_tpm_info_list(const acm_hdr_t* hdr);
+void verify_IA32_se_svn_status(const acm_hdr_t *acm_hdr);
+#endif /* __TXT_ACMOD_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/txt/config_regs.h b/tboot/include/txt/config_regs.h
new file mode 100644
index 0000000..4d02ea4
--- /dev/null
+++ b/tboot/include/txt/config_regs.h
@@ -0,0 +1,240 @@
+/*
+ * config_regs.h: Intel(r) TXT configuration register -related definitions
+ *
+ * Copyright (c) 2003-2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TXT_CONFIG_REGS_H__
+#define __TXT_CONFIG_REGS_H__
+
+/*
+ * TXT configuration registers (offsets from TXT_{PUB, PRIV}_CONFIG_REGS_BASE)
+ */
+
+#define TXT_PUB_CONFIG_REGS_BASE 0xfed30000
+#define TXT_PRIV_CONFIG_REGS_BASE 0xfed20000
+
+#define TXT_CONFIG_REGS_SIZE (TXT_PUB_CONFIG_REGS_BASE - \
+ TXT_PRIV_CONFIG_REGS_BASE)
+
+/* offsets to config regs (from either public or private _BASE) */
+#define TXTCR_STS 0x0000
+#define TXTCR_ESTS 0x0008
+#define TXTCR_ERRORCODE 0x0030
+#define TXTCR_CMD_RESET 0x0038
+#define TXTCR_CMD_CLOSE_PRIVATE 0x0048
+#define TXTCR_VER_FSBIF 0x0100
+#define TXTCR_DIDVID 0x0110
+#define TXTCR_VER_QPIIF 0x0200
+#define TXTCR_CMD_UNLOCK_MEM_CONFIG 0x0218
+#define TXTCR_SINIT_BASE 0x0270
+#define TXTCR_SINIT_SIZE 0x0278
+#define TXTCR_MLE_JOIN 0x0290
+#define TXTCR_HEAP_BASE 0x0300
+#define TXTCR_HEAP_SIZE 0x0308
+#define TXTCR_MSEG_BASE 0x0310
+#define TXTCR_MSEG_SIZE 0x0318
+#define TXTCR_DPR 0x0330
+#define TXTCR_CMD_OPEN_LOCALITY1 0x0380
+#define TXTCR_CMD_CLOSE_LOCALITY1 0x0388
+#define TXTCR_CMD_OPEN_LOCALITY2 0x0390
+#define TXTCR_CMD_CLOSE_LOCALITY2 0x0398
+#define TXTCR_PUBLIC_KEY 0x0400
+#define TXTCR_CMD_SECRETS 0x08e0
+#define TXTCR_CMD_NO_SECRETS 0x08e8
+#define TXTCR_E2STS 0x08f0
+
+/*
+ * format of ERRORCODE register
+ */
+typedef union {
+ uint64_t _raw;
+ struct {
+ uint64_t type : 30; /* external-specific error code */
+ uint64_t external : 1; /* 0=from proc, 1=from external SW */
+ uint64_t valid : 1; /* 1=valid */
+ };
+} txt_errorcode_t;
+
+/*
+ * format of ESTS register
+ */
+typedef union {
+ uint64_t _raw;
+ struct {
+ uint64_t txt_reset_sts : 1;
+ };
+} txt_ests_t;
+
+/*
+ * format of E2STS register
+ */
+typedef union {
+ uint64_t _raw;
+ struct {
+ uint64_t reserved : 1;
+ uint64_t secrets_sts : 1;
+ };
+} txt_e2sts_t;
+
+/*
+ * format of STS register
+ */
+typedef union {
+ uint64_t _raw;
+ struct {
+ uint64_t senter_done_sts : 1;
+ uint64_t sexit_done_sts : 1;
+ uint64_t reserved1 : 4;
+ uint64_t mem_config_lock_sts : 1;
+ uint64_t private_open_sts : 1;
+ uint64_t reserved2 : 7;
+ uint64_t locality_1_open_sts : 1;
+ uint64_t locality_2_open_sts : 1;
+ };
+} txt_sts_t;
+
+/*
+ * format of DIDVID register
+ */
+typedef union {
+ uint64_t _raw;
+ struct {
+ uint16_t vendor_id;
+ uint16_t device_id;
+ uint16_t revision_id;
+ uint16_t reserved;
+ };
+} txt_didvid_t;
+
+/*
+ * format of VER.FSBIF and VER.QPIIF registers
+ */
+typedef union {
+ uint64_t _raw;
+ struct {
+ uint64_t reserved : 31;
+ uint64_t prod_fused : 1;
+ };
+} txt_ver_fsbif_qpiif_t;
+
+/*
+ * format of DPR register
+ */
+typedef union {
+ uint64_t _raw;
+ struct {
+ uint64_t lock : 1;
+ uint64_t reserved1 : 3;
+ uint64_t size : 8;
+ uint64_t reserved2 : 8;
+ uint64_t top : 12;
+ uint64_t reserved3 : 32;
+ };
+} txt_dpr_t;
+
+/*
+ * RLP JOIN structure for GETSEC[WAKEUP] and MLE_JOIN register
+ */
+typedef struct {
+ uint32_t gdt_limit;
+ uint32_t gdt_base;
+ uint32_t seg_sel; /* cs (ds, es, ss are seg_sel+8) */
+ uint32_t entry_point; /* phys addr */
+} mle_join_t;
+
+/*
+ * format of MSEG header
+ */
+typedef struct {
+ uint32_t revision_id;
+ uint32_t smm_mon_feat;
+ uint32_t gdtr_limit;
+ uint32_t gdtr_base_offset;
+ uint32_t cs_sel;
+ uint32_t eip_offset;
+ uint32_t esp_offset;
+ uint32_t cr3_offset;
+} mseg_hdr_t;
+
+/* TODO these are causing warnings - changed to ull */
+
+/*
+ * fns to read/write TXT config regs
+ */
+
+#ifndef IS_INCLUDED
+static inline uint64_t read_config_reg(uint64_t config_regs_base, uint32_t reg)
+{
+ /* these are MMIO so make sure compiler doesn't optimize */
+ return *(volatile uint64_t *)(unsigned long long)(config_regs_base + reg);
+}
+#endif
+
+static inline void write_config_reg(uint64_t config_regs_base, uint32_t reg,
+ uint64_t val)
+{
+ /* these are MMIO so make sure compiler doesn't optimize */
+ *(volatile uint64_t *)(unsigned long long)(config_regs_base + reg) = val;
+}
+
+static inline uint64_t read_pub_config_reg(uint32_t reg)
+{
+ return read_config_reg(TXT_PUB_CONFIG_REGS_BASE, reg);
+}
+
+static inline void write_pub_config_reg(uint32_t reg, uint64_t val)
+{
+ write_config_reg(TXT_PUB_CONFIG_REGS_BASE, reg, val);
+}
+
+static inline uint64_t read_priv_config_reg(uint32_t reg)
+{
+ return read_config_reg(TXT_PRIV_CONFIG_REGS_BASE, reg);
+}
+
+static inline void write_priv_config_reg(uint32_t reg, uint64_t val)
+{
+ write_config_reg(TXT_PRIV_CONFIG_REGS_BASE, reg, val);
+}
+
+#endif /* __TXT_CONFIG_REGS_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/txt/errorcode.h b/tboot/include/txt/errorcode.h
new file mode 100644
index 0000000..fe85a3c
--- /dev/null
+++ b/tboot/include/txt/errorcode.h
@@ -0,0 +1,105 @@
+/*
+ * errorcode.h: Intel(r) TXT error definitions for ERRORCODE config register
+ *
+ * Copyright (c) 2003-2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TXT_ERRORCODE_H__
+#define __TXT_ERRORCODE_H__
+
+/*
+ * error values for processor error codes (ERRORCODE.external = 0)
+ */
+#define TXT_ERR_PROC_LEGACY_SHUTDOWN 0
+#define TXT_ERR_PROC_INVALID_ACM_MEM_TYPE 5
+#define TXT_ERR_PROC_UNSUPPORTED_ACM 6
+#define TXT_ERR_PROC_AUTH_FAIL 7
+#define TXT_ERR_PROC_INVALID_ACM_FORMAT 8
+#define TXT_ERR_PROC_UNEXPECTED_HITM 9
+#define TXT_ERR_PROC_INVALID_EVENT 10
+#define TXT_ERR_PROC_INVALID_JOIN_FORMAT 11
+#define TXT_ERR_PROC_UNRECOVERABLE_MCE 12
+#define TXT_ERR_PROC_VMX_ABORT 13
+#define TXT_ERR_PROC_ACM_CORRUPT 14
+#define TXT_ERR_PROC_INVALID_VIDB_RATIO 15
+
+/*
+ * for SW errors (ERRORCODE.external = 1)
+ */
+typedef union {
+ uint32_t _raw;
+ struct {
+ uint32_t err1 : 15; /* specific to src */
+ uint32_t src : 1; /* 0=ACM, 1=other */
+ uint32_t err2 : 14; /* specific to src */
+ uint32_t external : 1; /* always 1 for this type */
+ uint32_t valid : 1; /* always 1 */
+ };
+} txt_errorcode_sw_t;
+
+/*
+ * ACM errors (txt_errorcode_sw_t.src=0), format of err1+src+err2 fields
+ */
+typedef union __attribute__((packed)){
+ uint32_t _raw;
+ struct __attribute__((packed)){
+ uint32_t acm_type : 4; /* 0000=BIOS ACM, 0001=SINIT, */
+ /* 0010-1111=reserved */
+ uint32_t progress : 6;
+ uint32_t error : 5;
+ uint32_t src : 1; /* above value */
+ union __attribute__((packed)){
+ struct __attribute__((packed)) { /* progress=0x0d, error=1010 */
+ uint32_t tpm_err : 9;
+ uint32_t reserved1 : 5;
+ };
+ struct __attribute__((packed)) { /* progress=0x10 */
+ uint32_t lcp_minor : 6;
+ uint32_t lcp_index : 3;
+ uint32_t reserved2 : 5;
+ };
+ }; /* sub-error */
+ };
+} acmod_error_t;
+
+#endif /* __TXT_ERRORCODE_H__ */
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/txt/heap.h b/tboot/include/txt/heap.h
new file mode 100644
index 0000000..c4e2d51
--- /dev/null
+++ b/tboot/include/txt/heap.h
@@ -0,0 +1,377 @@
+/*
+ * heap.h: Intel(r) TXT heap definitions
+ *
+ * Copyright (c) 2003-2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TXT_HEAP_H__
+#define __TXT_HEAP_H__
+
+/*
+ * Extensible TXT heap data structure
+ */
+
+typedef struct __packed {
+ uint32_t type;
+ uint32_t size;
+ uint8_t data[];
+} heap_ext_data_element_t;
+
+/*
+ * HEAP_END_ELEMENT
+ */
+#define HEAP_EXTDATA_TYPE_END 0
+
+/* size == 8; there is no data[] */
+
+/*
+ * HEAP_BIOS_SPEC_VER_ELEMENT
+ */
+#define HEAP_EXTDATA_TYPE_BIOS_SPEC_VER 1
+
+typedef struct __packed {
+ uint16_t spec_ver_major;
+ uint16_t spec_ver_minor;
+ uint16_t spec_ver_rev;
+} heap_bios_spec_ver_elt_t;
+
+/*
+ * HEAP_ACM_ELEMENT
+ */
+#define HEAP_EXTDATA_TYPE_ACM 2
+
+typedef struct __packed {
+ uint32_t num_acms;
+ uint64_t acm_addrs[];
+} heap_acm_elt_t;
+
+/*
+ * HEAP_CUSTOM_ELEMENT
+ */
+#define HEAP_EXTDATA_TYPE_CUSTOM 4
+
+typedef struct __packed {
+ uuid_t uuid;
+ uint8_t data[];
+} heap_custom_elt_t;
+
+/*
+ * HEAP_EVENT_LOG_POINTER_ELEMENT
+ */
+#define HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR 5
+
+typedef struct __packed {
+ uint64_t event_log_phys_addr;
+} heap_event_log_ptr_elt_t;
+
+typedef struct __packed {
+ uint32_t pcr_index;
+ uint32_t type;
+ sha1_hash_t digest;
+ uint32_t data_size;
+ uint8_t data[];
+} tpm12_pcr_event_t;
+
+#define EVTLOG_SIGNATURE "TXT Event Container\0"
+#define EVTLOG_CNTNR_MAJOR_VER 1
+#define EVTLOG_CNTNR_MINOR_VER 0
+#define EVTLOG_EVT_MAJOR_VER 1
+#define EVTLOG_EVT_MINOR_VER 0
+typedef struct __packed {
+ uint8_t signature[20];
+ uint8_t reserved[12];
+ uint8_t container_ver_major;
+ uint8_t container_ver_minor;
+ uint8_t pcr_event_ver_major;
+ uint8_t pcr_event_ver_minor;
+ uint32_t size;
+ uint32_t pcr_events_offset;
+ uint32_t next_event_offset;
+ tpm12_pcr_event_t pcr_events[];
+} event_log_container_t;
+
+/*
+ * HEAP_EVENT_LOG_POINTER_ELEMENT2
+ */
+#define HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR_2 7
+
+#define DIGEST_ALG_ID_SHA_1 0x00000001
+#define DIGEST_ALG_ID_SHA_256 0x00000002
+#define DIGEST_ALG_ID_SHA_384 0x00000003
+#define DIGEST_ALG_ID_SHA_512 0x00000004
+#define DIGEST_ALG_ID_SM3 0x00000005
+static inline unsigned int get_evtlog_digest_id(uint16_t hash_alg)
+{
+ if ( hash_alg == TB_HALG_SHA1 )
+ return DIGEST_ALG_ID_SHA_1;
+ else if ( hash_alg == TB_HALG_SHA256 )
+ return DIGEST_ALG_ID_SHA_256;
+ else if ( hash_alg == TB_HALG_SM3 )
+ return DIGEST_ALG_ID_SM3;
+ else if ( hash_alg == TB_HALG_SHA384 )
+ return DIGEST_ALG_ID_SHA_384;
+ else if ( hash_alg == TB_HALG_SHA512 )
+ return DIGEST_ALG_ID_SHA_512;
+ else
+ return 0;
+}
+
+typedef struct __packed {
+ uint8_t signature[16];
+ uint32_t revision;
+ uint32_t digest_id;
+ uint32_t digest_size;
+} tpm20_log_descr_t;
+
+typedef struct __packed {
+ uint16_t alg;
+ uint16_t reserved;
+ uint64_t phys_addr;
+ uint32_t size;
+ uint32_t pcr_events_offset;
+ uint32_t next_event_offset;
+} heap_event_log_descr_t;
+
+typedef struct __packed {
+ uint32_t count;
+ heap_event_log_descr_t event_log_descr[];
+} heap_event_log_ptr_elt2_t;
+
+
+/*
+ * data-passing structures contained in TXT heap:
+ * - BIOS
+ * - OS/loader to MLE
+ * - OS/loader to SINIT
+ * - SINIT to MLE
+ */
+
+/*
+ * BIOS structure
+ */
+typedef struct __packed {
+ uint32_t version; /* currently 2-4 */
+ uint32_t bios_sinit_size;
+ uint64_t lcp_pd_base;
+ uint64_t lcp_pd_size;
+ uint32_t num_logical_procs;
+ /* versions >= 3 */
+ uint64_t flags; /* For TPM2, it is divided into sinit_flag and mle_flag */
+ /* versions >= 4 */
+ heap_ext_data_element_t ext_data_elts[];
+} bios_data_t;
+
+/*
+ * OS/loader to MLE structure
+ * - private to tboot (so can be any format we need)
+ */
+#define MAX_LCP_PO_DATA_SIZE 64*1024 /* 64k */
+#define MAX_EVENT_LOG_SIZE 5*4*1024 /* 4k*5 */
+
+typedef struct __packed {
+ uint32_t version; /* currently 3 */
+ mtrr_state_t saved_mtrr_state; /* saved prior to changes for SINIT */
+ uint64_t saved_misc_enable_msr; /* saved prior to SENTER */
+ /* PO policy data */
+ uint8_t lcp_po_data[MAX_LCP_PO_DATA_SIZE];
+ /* buffer for tpm event log */
+ uint8_t event_log_buffer[MAX_EVENT_LOG_SIZE];
+} os_mle_data_t;
+
+#define MIN_OS_SINIT_DATA_VER 4
+#define MAX_OS_SINIT_DATA_VER 7
+#define OS_SINIT_FLAGS_EXTPOL_MASK 0x00000001
+/*
+ * OS/loader to SINIT structure
+ */
+typedef struct __packed {
+ uint32_t version; /* currently 4-7 */
+ uint32_t flags; /* For TPM2: BIT0:= PCR Extend Policy Control */
+ uint64_t mle_ptab;
+ uint64_t mle_size;
+ uint64_t mle_hdr_base;
+ uint64_t vtd_pmr_lo_base;
+ uint64_t vtd_pmr_lo_size;
+ uint64_t vtd_pmr_hi_base;
+ uint64_t vtd_pmr_hi_size;
+ uint64_t lcp_po_base;
+ uint64_t lcp_po_size;
+ txt_caps_t capabilities;
+ /* versions >= 5 */
+ uint64_t efi_rsdt_ptr;
+ /* versions >= 6 */
+ heap_ext_data_element_t ext_data_elts[];
+} os_sinit_data_t;
+
+/*
+ * SINIT to MLE structure
+ */
+#define MDR_MEMTYPE_GOOD 0x00
+#define MDR_MEMTYPE_SMM_OVERLAY 0x01
+#define MDR_MEMTYPE_SMM_NONOVERLAY 0x02
+#define MDR_MEMTYPE_PCIE_CONFIG_SPACE 0x03
+#define MDR_MEMTYPE_PROTECTED 0x04
+
+typedef struct __packed {
+ uint64_t base;
+ uint64_t length;
+ uint8_t mem_type;
+ uint8_t reserved[7];
+} sinit_mdr_t;
+
+typedef struct __packed {
+ uint32_t version; /* currently 6-9 */
+ sha1_hash_t bios_acm_id; /* only for tpm1.2 */
+ uint32_t edx_senter_flags; /* only for tpm1.2 */
+ uint64_t mseg_valid; /* only for tpm1.2 */
+ sha1_hash_t sinit_hash; /* only for tpm1.2 */
+ sha1_hash_t mle_hash; /* only for tpm1.2 */
+ sha1_hash_t stm_hash; /* only for tpm1.2 */
+ sha1_hash_t lcp_policy_hash; /* only for tpm1.2 */
+ uint32_t lcp_policy_control; /* only for tpm1.2 */
+ uint32_t rlp_wakeup_addr;
+ uint32_t reserved;
+ uint32_t num_mdrs;
+ uint32_t mdrs_off;
+ uint32_t num_vtd_dmars;
+ uint32_t vtd_dmars_off;
+ /* versions >= 8 */
+ uint32_t proc_scrtm_status; /* only for tpm1.2 */
+ /* versions >= 9 */
+ heap_ext_data_element_t ext_data_elts[];
+} sinit_mle_data_t;
+
+
+/*
+ * TXT heap data format and field accessor fns
+ */
+
+/*
+ * offset length field
+ * ------ ------ -----
+ * 0 8 bios_data_size
+ * 8 bios_data_size - 8 bios_data
+ *
+ * bios_data_size 8 os_mle_data_size
+ * bios_data_size + os_mle_data_size - 8 os_mle_data
+ * 8
+ *
+ * bios_data_size + 8 os_sinit_data_size
+ * os_mle_data_size
+ * bios_data_size + os_sinit_data_size - 8 os_sinit_data
+ * os_mle_data_size +
+ * 8
+ *
+ * bios_data_size + 8 sinit_mle_data_size
+ * os_mle_data_size +
+ * os_sinit_data_size
+ * bios_data_size + sinit_mle_data_size - 8 sinit_mle_data
+ * os_mle_data_size +
+ * os_sinit_data_size +
+ * 8
+ */
+
+typedef void txt_heap_t;
+
+/* TODO these are causing warnings - changed to ull */
+
+/* this is a common use with annoying casting, so make it an inline */
+static inline txt_heap_t *get_txt_heap(void)
+{
+ return (txt_heap_t *)(unsigned long long)read_pub_config_reg(TXTCR_HEAP_BASE);
+}
+
+static inline uint64_t get_bios_data_size(const txt_heap_t *heap)
+{
+ return *(uint64_t *)heap;
+}
+
+static inline bios_data_t *get_bios_data_start(const txt_heap_t *heap)
+{
+ return (bios_data_t *)((char*)heap + sizeof(uint64_t));
+}
+
+static inline uint64_t get_os_mle_data_size(const txt_heap_t *heap)
+{
+ return *(uint64_t *)(heap + get_bios_data_size(heap));
+}
+
+static inline os_mle_data_t *get_os_mle_data_start(const txt_heap_t *heap)
+{
+ return (os_mle_data_t *)(heap + get_bios_data_size(heap) +
+ sizeof(uint64_t));
+}
+
+static inline uint64_t get_os_sinit_data_size(const txt_heap_t *heap)
+{
+ return *(uint64_t *)(heap + get_bios_data_size(heap) +
+ get_os_mle_data_size(heap));
+}
+
+static inline os_sinit_data_t *get_os_sinit_data_start(const txt_heap_t *heap)
+{
+ return (os_sinit_data_t *)(heap + get_bios_data_size(heap) +
+ get_os_mle_data_size(heap) +
+ sizeof(uint64_t));
+}
+
+static inline uint64_t get_sinit_mle_data_size(const txt_heap_t *heap)
+{
+ return *(uint64_t *)(heap + get_bios_data_size(heap) +
+ get_os_mle_data_size(heap) +
+ get_os_sinit_data_size(heap));
+}
+
+static inline sinit_mle_data_t *get_sinit_mle_data_start(const txt_heap_t *heap)
+{
+ return (sinit_mle_data_t *)(heap + get_bios_data_size(heap) +
+ get_os_mle_data_size(heap) +
+ get_os_sinit_data_size(heap) +
+ sizeof(uint64_t));
+}
+
+uint64_t calc_os_sinit_data_size(uint32_t version);
+bool verify_txt_heap(const txt_heap_t *txt_heap, bool bios_data_only);
+bool verify_bios_data(const txt_heap_t *txt_heap);
+void print_os_sinit_data(const os_sinit_data_t *os_sinit_data);
+
+#endif /* __TXT_HEAP_H__ */
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/txt/mtrrs.h b/tboot/include/txt/mtrrs.h
new file mode 100644
index 0000000..8b61f6e
--- /dev/null
+++ b/tboot/include/txt/mtrrs.h
@@ -0,0 +1,149 @@
+/*
+ * mtrrs.c: Intel(r) TXT MTRR-related definitions
+ *
+ * Copyright (c) 2003-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TXT_MTRRS_H__
+#define __TXT_MTRRS_H__
+
+#include <txt/acmod.h>
+
+enum fix_mtrr_t {
+ MTRR_FIX64K_00000 = 0x250,
+ MTRR_FIX16K_80000 = 0x258,
+ MTRR_FIX16K_A0000 = 0x259,
+ MTRR_FIX4K_C0000 = 0x268,
+ MTRR_FIX4K_C8000 = 0x269,
+ MTRR_FIX4K_D0000 = 0x26A,
+ MTRR_FIX4K_D8000 = 0x26B,
+ MTRR_FIX4K_E0000 = 0x26C,
+ MTRR_FIX4K_E8000 = 0x26D,
+ MTRR_FIX4K_F0000 = 0x26E,
+ MTRR_FIX4K_F8000 = 0x26F
+};
+
+typedef union {
+ uint64_t raw;
+ uint8_t type[8];
+} mtrr_fix_types_t;
+
+enum var_mtrr_t {
+ MTRR_PHYS_BASE0_MSR = 0x200,
+ MTRR_PHYS_MASK0_MSR = 0x201,
+ MTRR_PHYS_BASE1_MSR = 0x202,
+ MTRR_PHYS_MASK1_MSR = 0x203,
+ MTRR_PHYS_BASE2_MSR = 0x204,
+ MTRR_PHYS_MASK2_MSR = 0x205,
+ MTRR_PHYS_BASE3_MSR = 0x206,
+ MTRR_PHYS_MASK3_MSR = 0x207,
+ MTRR_PHYS_BASE4_MSR = 0x208,
+ MTRR_PHYS_MASK4_MSR = 0x209,
+ MTRR_PHYS_BASE5_MSR = 0x20A,
+ MTRR_PHYS_MASK5_MSR = 0x20B,
+ MTRR_PHYS_BASE6_MSR = 0x20C,
+ MTRR_PHYS_MASK6_MSR = 0x20D,
+ MTRR_PHYS_BASE7_MSR = 0x20E,
+ MTRR_PHYS_MASK7_MSR = 0x20F
+};
+
+typedef union {
+ uint64_t raw;
+ struct {
+ uint64_t vcnt : 8; /* num variable MTRR pairs */
+ uint64_t fix : 1; /* fixed range MTRRs are supported */
+ uint64_t reserved1 : 1;
+ uint64_t wc : 1; /* write-combining mem type supported */
+ uint64_t reserved2 : 53;
+ };
+} mtrr_cap_t;
+
+typedef union {
+ uint64_t raw;
+ struct {
+ uint64_t type : 8;
+ uint64_t reserved1 : 2;
+ uint64_t fe : 1; /* fixed MTRR enable */
+ uint64_t e : 1; /* (all) MTRR enable */
+ uint64_t reserved2 : 52;
+ };
+} mtrr_def_type_t;
+
+typedef union {
+ uint64_t raw;
+ struct {
+ uint64_t type : 8;
+ uint64_t reserved1 : 4;
+ uint64_t base : 52; /* define as max width and mask w/ */
+ /* MAXPHYADDR when using */
+ };
+} mtrr_physbase_t;
+
+typedef union {
+ uint64_t raw;
+ struct {
+ uint64_t reserved1 : 11;
+ uint64_t v : 1; /* valid */
+ uint64_t mask : 52; /* define as max width and mask w/ */
+ /* MAXPHYADDR when using */
+ };
+} mtrr_physmask_t;
+
+/* current procs only have 8, so this should hold us for a while */
+#define MAX_VARIABLE_MTRRS 16
+
+typedef struct {
+ mtrr_def_type_t mtrr_def_type;
+ unsigned int num_var_mtrrs;
+ mtrr_physbase_t mtrr_physbases[MAX_VARIABLE_MTRRS];
+ mtrr_physmask_t mtrr_physmasks[MAX_VARIABLE_MTRRS];
+} mtrr_state_t;
+
+bool set_mtrrs_for_acmod(const acm_hdr_t *hdr);
+void save_mtrrs(mtrr_state_t *saved_state);
+void set_all_mtrrs(bool enable);
+bool set_mem_type(const void *base, uint32_t size, uint32_t mem_type);
+void restore_mtrrs(const mtrr_state_t *saved_state);
+bool validate_mtrrs(const mtrr_state_t *saved_state);
+
+#endif /*__TXT_MTRRS_H__ */
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/txt/smx.h b/tboot/include/txt/smx.h
new file mode 100644
index 0000000..93645c7
--- /dev/null
+++ b/tboot/include/txt/smx.h
@@ -0,0 +1,171 @@
+/*
+ * smx.h: Intel(r) TXT SMX architecture-related definitions
+ *
+ * Copyright (c) 2003-2008, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TXT_SMX_H__
+#define __TXT_SMX_H__
+
+/*
+ * GETSEC[] instructions
+ */
+
+/* GETSEC instruction opcode */
+#define IA32_GETSEC_OPCODE ".byte 0x0f,0x37"
+
+/* GETSEC leaf function codes */
+#define IA32_GETSEC_CAPABILITIES 0
+#define IA32_GETSEC_ENTERACCS 2
+#define IA32_GETSEC_SENTER 4
+#define IA32_GETSEC_SEXIT 5
+#define IA32_GETSEC_PARAMETERS 6
+#define IA32_GETSEC_SMCTRL 7
+#define IA32_GETSEC_WAKEUP 8
+
+/*
+ * GETSEC[] leaf functions
+ */
+
+typedef union {
+ uint32_t _raw;
+ struct {
+ uint32_t chipset_present : 1;
+ uint32_t undefined1 : 1;
+ uint32_t enteraccs : 1;
+ uint32_t exitac : 1;
+ uint32_t senter : 1;
+ uint32_t sexit : 1;
+ uint32_t parameters : 1;
+ uint32_t smctrl : 1;
+ uint32_t wakeup : 1;
+ uint32_t undefined9 : 22;
+ uint32_t extended_leafs : 1;
+ };
+} capabilities_t;
+
+static inline capabilities_t __getsec_capabilities(uint32_t index)
+{
+ uint32_t cap;
+ __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n"
+ : "=a"(cap)
+ : "a"(IA32_GETSEC_CAPABILITIES), "b"(index));
+ return (capabilities_t)cap;
+}
+
+/* helper fn. for getsec_capabilities */
+/* this is arbitrary and can be increased when needed */
+#define MAX_SUPPORTED_ACM_VERSIONS 16
+
+typedef struct {
+ struct {
+ uint32_t mask;
+ uint32_t version;
+ } acm_versions[MAX_SUPPORTED_ACM_VERSIONS];
+ int n_versions;
+ uint32_t acm_max_size;
+ uint32_t acm_mem_types;
+ uint32_t senter_controls;
+ bool proc_based_scrtm;
+ bool preserve_mce;
+} getsec_parameters_t;
+
+bool get_parameters(getsec_parameters_t *params);
+
+
+static inline void __getsec_senter(uint32_t sinit_base, uint32_t sinit_size)
+{
+ __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n"
+ :
+ : "a"(IA32_GETSEC_SENTER),
+ "b"(sinit_base),
+ "c"(sinit_size),
+ "d"(0x0));
+}
+
+static inline void __getsec_sexit(void)
+{
+ __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n"
+ : : "a"(IA32_GETSEC_SEXIT));
+}
+
+static inline void __getsec_wakeup(void)
+{
+ __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n"
+ : : "a"(IA32_GETSEC_WAKEUP));
+}
+
+static inline void __getsec_smctrl(void)
+{
+ __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n"
+ : : "a"(IA32_GETSEC_SMCTRL), "b"(0x0));
+}
+
+static inline void __getsec_parameters(uint32_t index, int* param_type,
+ uint32_t* peax, uint32_t* pebx,
+ uint32_t* pecx)
+{
+ uint32_t eax=0, ebx=0, ecx=0;
+ __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n"
+ : "=a"(eax), "=b"(ebx), "=c"(ecx)
+ : "a"(IA32_GETSEC_PARAMETERS), "b"(index));
+
+ if ( param_type != NULL ) *param_type = eax & 0x1f;
+ if ( peax != NULL ) *peax = eax;
+ if ( pebx != NULL ) *pebx = ebx;
+ if ( pecx != NULL ) *pecx = ecx;
+}
+
+static inline void __getsec_enteraccs(uint32_t acm_base, uint32_t acm_size,
+ uint32_t fn)
+{
+ __asm__ __volatile__ (IA32_GETSEC_OPCODE "\n"
+ :
+ : "a"(IA32_GETSEC_ENTERACCS),
+ "b"(acm_base),
+ "c"(acm_size),
+ "D"(0),
+ "S"(fn));
+}
+
+
+#endif /* __TXT_SMX_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/txt/txt.h b/tboot/include/txt/txt.h
new file mode 100644
index 0000000..2555e70
--- /dev/null
+++ b/tboot/include/txt/txt.h
@@ -0,0 +1,76 @@
+/*
+ * txt.h: Intel(r) TXT support functions
+ *
+ * Copyright (c) 2003-2008, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TXT_TXT_H__
+#define __TXT_TXT_H__
+
+// #include <multiboot.h>
+
+void txt_init_mle_header(void);
+bool txt_build_mle_pagetable(void);
+bool txt_is_launched(void);
+bool txt_get_error(void);
+void txt_get_racm_error(void);
+tb_error_t supports_txt(void);
+tb_error_t txt_verify_platform(void);
+bool txt_prepare_cpu(void);
+tb_error_t txt_launch_environment(void);
+/* TODO need to address the loader business, stub out for now
+tb_error_t txt_launch_racm(loader_ctx *lctx);
+*/
+void txt_post_launch(void);
+tb_error_t txt_protect_mem_regions(void);
+tb_error_t txt_post_launch_verify_platform(void);
+bool txt_s3_launch_environment(void);
+void txt_shutdown(void);
+bool txt_is_powercycle_required(void);
+void ap_wait(unsigned int cpuid);
+
+uint32_t g_using_da;
+atomic_t ap_wfs_count;
+
+#endif /* __TXT_TXT_H__ */
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
diff --git a/tboot/include/txt/verify.h b/tboot/include/txt/verify.h
new file mode 100644
index 0000000..659af15
--- /dev/null
+++ b/tboot/include/txt/verify.h
@@ -0,0 +1,57 @@
+/*
+ * verify.h: support functions for platform Intel(r) TXT verification
+ *
+ * Copyright (c) 2003-2008, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TXT_VERIFY_H__
+#define __TXT_VERIFY_H__
+
+void set_vtd_pmrs(os_sinit_data_t *os_sinit_data,
+ uint64_t min_lo_ram, uint64_t max_lo_ram,
+ uint64_t min_hi_ram, uint64_t max_hi_ram);
+bool verify_e820_map(sinit_mdr_t* mdrs_base, uint32_t num_mdrs);
+bool verify_stm(unsigned int cpuid);
+bool use_mwait(void);
+
+#endif /* __TXT_VERIFY_H__ */
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/txt/vmcs.h b/tboot/include/txt/vmcs.h
new file mode 100644
index 0000000..74f6ecc
--- /dev/null
+++ b/tboot/include/txt/vmcs.h
@@ -0,0 +1,346 @@
+/*
+ * vmcs.h: VMCS definitions for creation of APs mini-guests
+ *
+ * Copyright (c) 2003-2009, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TXT_VMCS_H__
+#define __TXT_VMCS_H__
+
+struct vmcs_struct {
+ uint32_t vmcs_revision_id;
+ unsigned char data[0]; /* vmcs size is read from MSR */
+};
+
+union vmcs_arbytes {
+ struct arbyte_fields {
+ unsigned int seg_type : 4,
+ s : 1,
+ dpl : 2,
+ p : 1,
+ reserved0 : 4,
+ avl : 1,
+ reserved1 : 1,
+ default_ops_size: 1,
+ g : 1,
+ null_bit : 1,
+ reserved2 : 15;
+ } fields;
+ unsigned int bytes;
+};
+
+#define CPU_BASED_HLT_EXITING 0x00000080
+#define CPU_BASED_INVDPG_EXITING 0x00000200
+#define CPU_BASED_MWAIT_EXITING 0x00000400
+
+#define PIN_BASED_EXT_INTR_MASK 0x00000001
+#define PIN_BASED_NMI_EXITING 0x00000008
+
+#define VM_EXIT_IA32E_MODE 0x00000200
+#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000
+
+#define VM_ENTRY_IA32E_MODE 0x00000200
+#define VM_ENTRY_SMM 0x00000400
+#define VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800
+
+
+/* VMCS Encordings */
+enum vmcs_field {
+ GUEST_ES_SELECTOR = 0x00000800,
+ GUEST_CS_SELECTOR = 0x00000802,
+ GUEST_SS_SELECTOR = 0x00000804,
+ GUEST_DS_SELECTOR = 0x00000806,
+ GUEST_FS_SELECTOR = 0x00000808,
+ GUEST_GS_SELECTOR = 0x0000080a,
+ GUEST_LDTR_SELECTOR = 0x0000080c,
+ GUEST_TR_SELECTOR = 0x0000080e,
+ HOST_ES_SELECTOR = 0x00000c00,
+ HOST_CS_SELECTOR = 0x00000c02,
+ HOST_SS_SELECTOR = 0x00000c04,
+ HOST_DS_SELECTOR = 0x00000c06,
+ HOST_FS_SELECTOR = 0x00000c08,
+ HOST_GS_SELECTOR = 0x00000c0a,
+ HOST_TR_SELECTOR = 0x00000c0c,
+ IO_BITMAP_A = 0x00002000,
+ IO_BITMAP_A_HIGH = 0x00002001,
+ IO_BITMAP_B = 0x00002002,
+ IO_BITMAP_B_HIGH = 0x00002003,
+ VM_EXIT_MSR_STORE_ADDR = 0x00002006,
+ VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007,
+ VM_EXIT_MSR_LOAD_ADDR = 0x00002008,
+ VM_EXIT_MSR_LOAD_ADDR_HIGH = 0x00002009,
+ VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a,
+ VM_ENTRY_MSR_LOAD_ADDR_HIGH = 0x0000200b,
+ TSC_OFFSET = 0x00002010,
+ TSC_OFFSET_HIGH = 0x00002011,
+ VIRTUAL_APIC_PAGE_ADDR = 0x00002012,
+ VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013,
+ VMCS_LINK_POINTER = 0x00002800,
+ VMCS_LINK_POINTER_HIGH = 0x00002801,
+ GUEST_IA32_DEBUGCTL = 0x00002802,
+ GUEST_IA32_DEBUGCTL_HIGH = 0x00002803,
+ PIN_BASED_VM_EXEC_CONTROL = 0x00004000,
+ CPU_BASED_VM_EXEC_CONTROL = 0x00004002,
+ EXCEPTION_BITMAP = 0x00004004,
+ PAGE_FAULT_ERROR_CODE_MASK = 0x00004006,
+ PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008,
+ CR3_TARGET_COUNT = 0x0000400a,
+ VM_EXIT_CONTROLS = 0x0000400c,
+ VM_EXIT_MSR_STORE_COUNT = 0x0000400e,
+ VM_EXIT_MSR_LOAD_COUNT = 0x00004010,
+ VM_ENTRY_CONTROLS = 0x00004012,
+ VM_ENTRY_MSR_LOAD_COUNT = 0x00004014,
+ VM_ENTRY_INTR_INFO_FIELD = 0x00004016,
+ VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018,
+ VM_ENTRY_INSTRUCTION_LEN = 0x0000401a,
+ TPR_THRESHOLD = 0x0000401c,
+ SECONDARY_VM_EXEC_CONTROL = 0x0000401e,
+ VM_INSTRUCTION_ERROR = 0x00004400,
+ VM_EXIT_REASON = 0x00004402,
+ VM_EXIT_INTR_INFO = 0x00004404,
+ VM_EXIT_INTR_ERROR_CODE = 0x00004406,
+ IDT_VECTORING_INFO_FIELD = 0x00004408,
+ IDT_VECTORING_ERROR_CODE = 0x0000440a,
+ VM_EXIT_INSTRUCTION_LEN = 0x0000440c,
+ VMX_INSTRUCTION_INFO = 0x0000440e,
+ GUEST_ES_LIMIT = 0x00004800,
+ GUEST_CS_LIMIT = 0x00004802,
+ GUEST_SS_LIMIT = 0x00004804,
+ GUEST_DS_LIMIT = 0x00004806,
+ GUEST_FS_LIMIT = 0x00004808,
+ GUEST_GS_LIMIT = 0x0000480a,
+ GUEST_LDTR_LIMIT = 0x0000480c,
+ GUEST_TR_LIMIT = 0x0000480e,
+ GUEST_GDTR_LIMIT = 0x00004810,
+ GUEST_IDTR_LIMIT = 0x00004812,
+ GUEST_ES_AR_BYTES = 0x00004814,
+ GUEST_CS_AR_BYTES = 0x00004816,
+ GUEST_SS_AR_BYTES = 0x00004818,
+ GUEST_DS_AR_BYTES = 0x0000481a,
+ GUEST_FS_AR_BYTES = 0x0000481c,
+ GUEST_GS_AR_BYTES = 0x0000481e,
+ GUEST_LDTR_AR_BYTES = 0x00004820,
+ GUEST_TR_AR_BYTES = 0x00004822,
+ GUEST_INTERRUPTIBILITY_INFO = 0x00004824,
+ GUEST_ACTIVITY_STATE = 0x00004826,
+ GUEST_SYSENTER_CS = 0x0000482A,
+ HOST_IA32_SYSENTER_CS = 0x00004c00,
+ CR0_GUEST_HOST_MASK = 0x00006000,
+ CR4_GUEST_HOST_MASK = 0x00006002,
+ CR0_READ_SHADOW = 0x00006004,
+ CR4_READ_SHADOW = 0x00006006,
+ CR3_TARGET_VALUE0 = 0x00006008,
+ CR3_TARGET_VALUE1 = 0x0000600a,
+ CR3_TARGET_VALUE2 = 0x0000600c,
+ CR3_TARGET_VALUE3 = 0x0000600e,
+ EXIT_QUALIFICATION = 0x00006400,
+ GUEST_LINEAR_ADDRESS = 0x0000640a,
+ GUEST_CR0 = 0x00006800,
+ GUEST_CR3 = 0x00006802,
+ GUEST_CR4 = 0x00006804,
+ GUEST_ES_BASE = 0x00006806,
+ GUEST_CS_BASE = 0x00006808,
+ GUEST_SS_BASE = 0x0000680a,
+ GUEST_DS_BASE = 0x0000680c,
+ GUEST_FS_BASE = 0x0000680e,
+ GUEST_GS_BASE = 0x00006810,
+ GUEST_LDTR_BASE = 0x00006812,
+ GUEST_TR_BASE = 0x00006814,
+ GUEST_GDTR_BASE = 0x00006816,
+ GUEST_IDTR_BASE = 0x00006818,
+ GUEST_DR7 = 0x0000681a,
+ GUEST_RSP = 0x0000681c,
+ GUEST_RIP = 0x0000681e,
+ GUEST_RFLAGS = 0x00006820,
+ GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822,
+ GUEST_SYSENTER_ESP = 0x00006824,
+ GUEST_SYSENTER_EIP = 0x00006826,
+ HOST_CR0 = 0x00006c00,
+ HOST_CR3 = 0x00006c02,
+ HOST_CR4 = 0x00006c04,
+ HOST_FS_BASE = 0x00006c06,
+ HOST_GS_BASE = 0x00006c08,
+ HOST_TR_BASE = 0x00006c0a,
+ HOST_GDTR_BASE = 0x00006c0c,
+ HOST_IDTR_BASE = 0x00006c0e,
+ HOST_IA32_SYSENTER_ESP = 0x00006c10,
+ HOST_IA32_SYSENTER_EIP = 0x00006c12,
+ HOST_RSP = 0x00006c14,
+ HOST_RIP = 0x00006c16,
+};
+
+enum guest_activity_state {
+ GUEST_STATE_ACTIVE = 0,
+ GUEST_STATE_HALT = 1,
+ GUEST_STATE_SHUTDOWN = 2,
+ GUEST_STATE_WAIT_SIPI = 3,
+};
+
+#define VMCALL_OPCODE ".byte 0x0f,0x01,0xc1\n"
+#define VMCLEAR_OPCODE ".byte 0x66,0x0f,0xc7\n" /* reg/opcode: /6 */
+#define VMLAUNCH_OPCODE ".byte 0x0f,0x01,0xc2\n"
+#define VMPTRLD_OPCODE ".byte 0x0f,0xc7\n" /* reg/opcode: /6 */
+#define VMPTRST_OPCODE ".byte 0x0f,0xc7\n" /* reg/opcode: /7 */
+#define VMREAD_OPCODE ".byte 0x0f,0x78\n"
+#define VMRESUME_OPCODE ".byte 0x0f,0x01,0xc3\n"
+#define VMWRITE_OPCODE ".byte 0x0f,0x79\n"
+#define VMXOFF_OPCODE ".byte 0x0f,0x01,0xc4\n"
+#define VMXON_OPCODE ".byte 0xf3,0x0f,0xc7\n"
+
+#define MODRM_EAX_06 ".byte 0x30\n" /* [EAX], with reg/opcode: /6 */
+#define MODRM_EAX_07 ".byte 0x38\n" /* [EAX], with reg/opcode: /7 */
+#define MODRM_EAX_ECX ".byte 0xc1\n" /* [EAX], [ECX] */
+
+/*
+ * Exit Reasons
+ */
+#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000
+
+#define EXIT_REASON_INIT 3
+#define EXIT_REASON_SIPI 4
+#define EXIT_REASON_VMCALL 18
+#define EXIT_REASON_INVALID_GUEST_STATE 33
+#define EXIT_REASON_MSR_LOADING 34
+#define EXIT_REASON_MACHINE_CHECK 41
+
+static inline void __vmptrld(uint64_t addr)
+{
+ /* TBD: do not crash on failure */
+ __asm__ __volatile__ ( VMPTRLD_OPCODE
+ MODRM_EAX_06
+ /* CF==1 or ZF==1 --> crash (ud2) */
+ "ja 1f ; ud2 ; 1:\n"
+ :
+ : "a" (&addr)
+ : "memory");
+}
+
+static inline void __vmptrst(uint64_t addr)
+{
+ __asm__ __volatile__ ( VMPTRST_OPCODE
+ MODRM_EAX_07
+ :
+ : "a" (&addr)
+ : "memory");
+}
+
+static inline void __vmpclear(uint64_t addr)
+{
+ /* TBD: do not crash on failure */
+ __asm__ __volatile__ ( VMCLEAR_OPCODE
+ MODRM_EAX_06
+ /* CF==1 or ZF==1 --> crash (ud2) */
+ "ja 1f ; ud2 ; 1:\n"
+ :
+ : "a" (&addr)
+ : "memory");
+}
+
+static inline unsigned long __vmread(unsigned long field)
+{
+ unsigned long ecx;
+
+ /* TBD: do not crash on failure */
+ __asm__ __volatile__ ( VMREAD_OPCODE
+ MODRM_EAX_ECX
+ /* CF==1 or ZF==1 --> crash (ud2) */
+ "ja 1f ; ud2 ; 1:\n"
+ : "=c" (ecx)
+ : "a" (field)
+ : "memory");
+
+ return ecx;
+}
+
+static inline void __vmwrite(unsigned long field, unsigned long value)
+{
+ /* TBD: do not crash on failure */
+ __asm__ __volatile__ ( VMWRITE_OPCODE
+ MODRM_EAX_ECX
+ /* CF==1 or ZF==1 --> crash (ud2) */
+ "ja 1f ; ud2 ; 1:\n"
+ :
+ : "a" (field) , "c" (value)
+ : "memory");
+}
+
+static inline void __vmlaunch (void)
+{
+ __asm__ __volatile__ ( VMLAUNCH_OPCODE
+ ::: "memory");
+}
+
+static inline void __vmresume (void)
+{
+ __asm__ __volatile__ ( VMRESUME_OPCODE
+ ::: "memory");
+}
+
+static inline void __vmxoff (void)
+{
+ __asm__ __volatile__ ( VMXOFF_OPCODE
+ ::: "memory");
+}
+
+static inline int __vmxon (uint64_t addr)
+{
+ int rc;
+
+ __asm__ __volatile__ ( VMXON_OPCODE
+ MODRM_EAX_06
+ /* CF==1 or ZF==1 --> rc = -1 */
+ "setna %b0 ; neg %0"
+ : "=q" (rc)
+ : "0" (0), "a" (&addr)
+ : "memory");
+
+ return rc;
+}
+
+void handle_init_sipi_sipi(unsigned int cpuid);
+void force_aps_exit(void);
+void init_vmcs_addrs(void);
+
+struct mutex ap_lock;
+
+#endif /* __TXT_VMCS_H__ */
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/types.h b/tboot/include/types.h
new file mode 100644
index 0000000..f6fb7a2
--- /dev/null
+++ b/tboot/include/types.h
@@ -0,0 +1,104 @@
+/*
+ * types.h: defines size-based types for 32b builds
+ *
+ * Copyright (c) 2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __TYPES_H__
+#define __TYPES_H__
+
+/* Need for other later defines. */
+#include <config.h>
+
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+#if !defined(__GNUC__)
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+#endif
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+typedef signed short s16;
+
+typedef unsigned char u_char;
+
+typedef unsigned int u_int;
+
+typedef unsigned char u_int8_t;
+typedef unsigned short u_int16_t;
+typedef unsigned int u_int32_t;
+
+/*
+ * This should be unsigned int but gets an error in
+ * policy.c that expects it to be an unsigned long.
+ */
+/* TODO building for x64 now */
+typedef unsigned long long size_t;
+
+typedef uint16_t wchar_t;
+
+/*
+ * This is specifically for IA32.
+ */
+/* TODO building for x64 now */
+#if !defined(__GNUC__)
+typedef unsigned long long uintptr_t;
+typedef unsigned long long uint64_t;
+#endif
+typedef unsigned long long u64;
+typedef unsigned long long u_int64_t;
+
+#define BYTES_PER_LONG 4
+
+#if __GNUC__ > 3
+#define offsetof(type, field) __builtin_offsetof(type, field)
+#else
+#define offsetof(type, member) ((size_t) &((type *)0)->member)
+#endif
+
+#endif /* __TYPES_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/uuid.h b/tboot/include/uuid.h
new file mode 100644
index 0000000..256bd02
--- /dev/null
+++ b/tboot/include/uuid.h
@@ -0,0 +1,82 @@
+/*
+ * uuid.h: support functions for UUIDs
+ *
+ * Copyright (c) 2006-2007, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __UUID_H__
+#define __UUID_H__
+
+typedef struct __packed {
+ uint32_t data1;
+ uint16_t data2;
+ uint16_t data3;
+ uint16_t data4;
+ uint8_t data5[6];
+} uuid_t;
+
+static inline bool are_uuids_equal(const uuid_t *uuid1, const uuid_t *uuid2)
+{
+ return (memcmp(uuid1, uuid2, sizeof(*uuid1)) == 0);
+}
+
+#ifndef PRINT
+#define PRINT printk
+#endif
+
+#ifndef TBOOT_DETA
+#define TBOOT_DETA "<4>"
+#endif
+
+static inline void print_uuid(const uuid_t *uuid)
+{
+ PRINT(TBOOT_DETA"{0x%08x, 0x%04x, 0x%04x, 0x%04x,\n"
+ "\t\t{0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x}}",
+ uuid->data1, (uint32_t)uuid->data2, (uint32_t)uuid->data3,
+ (uint32_t)uuid->data4, (uint32_t)uuid->data5[0],
+ (uint32_t)uuid->data5[1], (uint32_t)uuid->data5[2],
+ (uint32_t)uuid->data5[3], (uint32_t)uuid->data5[4],
+ (uint32_t)uuid->data5[5]);
+}
+
+#endif /* __UUID_H__ */
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/vga.h b/tboot/include/vga.h
new file mode 100644
index 0000000..7e9914a
--- /dev/null
+++ b/tboot/include/vga.h
@@ -0,0 +1,87 @@
+/*
+ * vga.h: definitions of and supports functions for VGA
+ *
+ * Copyright (c) 2006-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __VGA_H__
+#define __VGA_H__
+
+#define VGA_BASE 0xb8000
+
+/* 80*25 text mode*/
+#define MAX_LINES 25
+#define MAX_COLS 80
+#define SCREEN_BUFFER (MAX_LINES*MAX_COLS*2)
+#define VGA_ADDR(x, y) (VGA_BASE + 2*(MAX_COLS*(y) + (x)))
+
+/* registers */
+#define CTL_ADDR_REG 0x3D4
+#define CTL_DATA_REG 0x3D5
+#define START_ADD_HIGH_REG 0x0C
+#define START_ADD_LOW_REG 0x0D
+
+/* colors */
+#define COLOR_BLACK 0x00
+#define COLOR_BLUE 0x01
+#define COLOR_GREEN 0x02
+#define COLOR_CYAN 0x03
+#define COLOR_RED 0x04
+#define COLOR_MAGENTA 0x05
+#define COLOR_BROWN 0x06
+#define COLOR_LTGRAY 0x07
+#define COLOR_DKGRAY 0x08
+#define COLOR_LTBLUE 0x09
+#define COLOR_LTGREEN 0x0A
+#define COLOR_LTCYAN 0x0B
+#define COLOR_LTRED 0x0C
+#define COLOR_LTMAGENTA 0x0D
+#define COLOR_LTBROWN 0x0E
+#define COLOR_WHITE 0x0F
+
+#define COLOR ((COLOR_BLACK << 4) | COLOR_LTGRAY)
+
+
+void vga_init(void);
+void vga_puts(const char *s, unsigned int cnt);
+
+#endif /* __VGA_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/include/vmac.h b/tboot/include/vmac.h
new file mode 100644
index 0000000..6104668
--- /dev/null
+++ b/tboot/include/vmac.h
@@ -0,0 +1,168 @@
+#ifndef HEADER_VMAC_H
+#define HEADER_VMAC_H
+
+/* --------------------------------------------------------------------------
+ * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai.
+ * This implementation is herby placed in the public domain.
+ * The authors offers no warranty. Use at your own risk.
+ * Please send bug reports to the authors.
+ * Last modified: 17 APR 08, 1700 PDT
+ * ----------------------------------------------------------------------- */
+
+/* --------------------------------------------------------------------------
+ * User definable settings.
+ * ----------------------------------------------------------------------- */
+#define VMAC_TAG_LEN 64 /* Must be 64 or 128 - 64 sufficient for most */
+#define VMAC_KEY_LEN 128 /* Must be 128, 192 or 256 */
+#define VMAC_NHBYTES 4096/* Must 2^i for any 3 < i < 13. Standard = 128 */
+#define VMAC_PREFER_BIG_ENDIAN 0 /* Prefer non-x86 */
+
+#define VMAC_USE_OPENSSL 0 /* Set to non-zero to use OpenSSL's AES */
+#define VMAC_CACHE_NONCES 1 /* Set to non-zero to cause caching */
+ /* of consecutive nonces on 64-bit tags */
+
+#define VMAC_RUN_TESTS 0 /* Set to non-zero to check vectors and speed */
+#define VMAC_HZ (448e6) /* Set to hz of host machine to get speed */
+#define VMAC_HASH_ONLY 0 /* Set to non-zero to time hash only (not-mac) */
+/* Speeds of cpus I have access to
+#define hz (2400e6) glyme Core 2 "Conroe"
+#define hz (2000e6) jupiter G5
+#define hz (1592e6) titan
+#define hz (2793e6) athena/gaia
+#define hz (1250e6) isis G4
+#define hz (2160e6) imac Core 2 "Merom"
+#define hz (266e6) ppc/arm
+#define hz (400e6) mips
+*/
+
+/* --------------------------------------------------------------------------
+ * This implementation uses uint32_t and uint64_t as names for unsigned 32-
+ * and 64-bit integer types. These are defined in C99 stdint.h. The
+ * following may need adaptation if you are not running a C99 or
+ * Microsoft C environment.
+ * ----------------------------------------------------------------------- */
+#define VMAC_USE_STDINT 1 /* Set to zero if system has no stdint.h */
+
+#if VMAC_USE_STDINT && !_MSC_VER /* Try stdint.h if non-Microsoft */
+//#include <stdint.h>
+#elif (_MSC_VER) /* Microsoft C does not have stdint.h */
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+#define UINT64_C(v) v ## UI64
+#else /* Guess sensibly - may need adaptation */
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+#define UINT64_C(v) v ## ULL
+#endif
+
+/* --------------------------------------------------------------------------
+ * This implementation supports two free AES implementations: OpenSSL's and
+ * Paulo Barreto's. To use OpenSSL's, you will need to include the OpenSSL
+ * crypto library (eg, gcc -lcrypto foo.c). For Barreto's, you will need
+ * to compile rijndael-alg-fst.c, last seen at http://www.iaik.tu-graz.ac.at/
+ * research/krypto/AES/old/~rijmen/rijndael/rijndael-fst-3.0.zip and
+ * http://homes.esat.kuleuven.be/~rijmen/rijndael/rijndael-fst-3.0.zip.
+ * To use a different implementation, use these definitions as a model.
+ * ----------------------------------------------------------------------- */
+#if VMAC_USE_OPENSSL
+
+#include <openssl/aes.h>
+typedef AES_KEY aes_int_key;
+
+#define aes_encryption(in,out,int_key) \
+ AES_encrypt((unsigned char *)(in),(unsigned char *)(out),(int_key))
+#define aes_key_setup(key,int_key) \
+ AES_set_encrypt_key((key),VMAC_KEY_LEN,(int_key))
+
+#else
+
+//#include "rijndael-alg-fst.h"
+typedef uint64_t vmac_t;
+#include "rijndael.h"
+typedef u32 aes_int_key[4*(VMAC_KEY_LEN/32+7)];
+
+#define aes_encryption(in,out,int_key) \
+ rijndaelEncrypt((u32 *)(int_key), \
+ ((VMAC_KEY_LEN/32)+6), \
+ (u8 *)(in), (u8 *)(out))
+#define aes_key_setup(user_key,int_key) \
+ rijndaelKeySetupEnc((u32 *)(int_key), \
+ (u8 *)(user_key), \
+ VMAC_KEY_LEN)
+#endif
+
+/* --------------------------------------------------------------------- */
+
+typedef struct {
+ uint64_t nhkey [(VMAC_NHBYTES/8)+2*(VMAC_TAG_LEN/64-1)];
+ uint64_t polykey[2*VMAC_TAG_LEN/64];
+ uint64_t l3key [2*VMAC_TAG_LEN/64];
+ uint64_t polytmp[2*VMAC_TAG_LEN/64];
+ aes_int_key cipher_key;
+ #if (VMAC_TAG_LEN == 64) && (VMAC_CACHE_NONCES)
+ uint64_t cached_nonce[2];
+ uint64_t cached_aes[2];
+ #endif
+ int first_block_processed;
+} vmac_ctx_t;
+
+/* --------------------------------------------------------------------- */
+/* --------------------------------------------------------------------------
+ * <<<<< USAGE NOTES >>>>>
+ *
+ * Given msg m (mbytes in length) and nonce buffer n
+ * this function returns a tag as its output. The tag is returned as
+ * a number. When VMAC_TAG_LEN == 64, the 'return'ed integer is the tag,
+ * and *tagl is meaningless. When VMAC_TAG_LEN == 128 the tag is the
+ * number y * 2^64 + *tagl where y is the function's return value.
+ * If you want to consider tags to be strings, then you must do so with
+ * an agreed upon endian orientation for interoperability, and convert
+ * the results appropriately. VHASH hashes m without creating any tag.
+ * Consecutive substrings forming a prefix of a message may be passed
+ * to vhash_update, with vhash or vmac being called with the remainder
+ * to produce the output.
+ *
+ * Requirements:
+ * - On 32-bit architectures with SSE2 instructions, ctx and m MUST be
+ * begin on 16-byte memory boundaries.
+ * - m MUST be your message followed by zeroes to the nearest 16-byte
+ * boundary. If m is a length multiple of 16 bytes, then it is already
+ * at a 16-byte boundary and needs no padding. mbytes should be your
+ * message length without any padding.
+ * - The first bit of the nonce buffer n must be 0. An i byte nonce, is made
+ * as the first 16-i bytes of n being zero, and the final i the nonce.
+ * - vhash_update MUST have mbytes be a positive multiple of VMAC_NHBYTES
+ * ----------------------------------------------------------------------- */
+
+#define vmac_update vhash_update
+
+void vhash_update(unsigned char m[],
+ unsigned int mbytes,
+ vmac_ctx_t *ctx);
+
+uint64_t vmac(unsigned char m[],
+ unsigned int mbytes,
+ unsigned char n[16],
+ uint64_t *tagl,
+ vmac_ctx_t *ctx);
+
+uint64_t vhash(unsigned char m[],
+ unsigned int mbytes,
+ uint64_t *tagl,
+ vmac_ctx_t *ctx);
+
+/* --------------------------------------------------------------------------
+ * When passed a VMAC_KEY_LEN bit user_key, this function initialazies ctx.
+ * ----------------------------------------------------------------------- */
+
+void vmac_set_key(unsigned char user_key[], vmac_ctx_t *ctx);
+
+/* --------------------------------------------------------------------------
+ * This function aborts current hash and resets ctx, ready for a new message.
+ * ----------------------------------------------------------------------- */
+
+void vhash_abort(vmac_ctx_t *ctx);
+
+/* --------------------------------------------------------------------- */
+
+#endif /* HEADER_AES_H */
diff --git a/tboot/launch.S b/tboot/launch.S
new file mode 100644
index 0000000..1d244ab
--- /dev/null
+++ b/tboot/launch.S
@@ -0,0 +1,484 @@
+/*
+ * launch.S: the MLE post launch entry code.
+ *
+ * Copyright (c) 2017 Assured Information Security.
+ *
+ * Ross Philipson <philipsonr@ainfosec.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <msr.h>
+#include <page.h>
+#include <processor.h>
+
+/* TXT config regs addrs/offsets */
+#define TXT_PRIV_CONFIG_REGS_BASE 0xfed20000
+#define TXTCR_STS 0x0000
+#define TXTCR_ERRORCODE 0x0030
+#define TXTCR_CMD_RESET 0x0038
+#define TXTCR_CMD_UNLOCK_MEM_CONFIG 0x0218
+#define TXTCR_HEAP_BASE 0x0300
+
+/* OsSinitData field offsets */
+#define MLE_PGTBL_OFFSET 8
+
+/* 64b selectors */
+#define CS_SEL64 0x0008
+#define DS_SEL64 0x0010
+
+/* errorcode for post-launch memory layout verfication failure */
+#define LAYOUT_ERR 0xc0008001
+
+#define BSP_STACK_SIZE 0x4000
+#define AP_STACK_SIZE 0x0800
+
+.section ".text"
+ .align PAGE_SIZE, 0
+
+.code32
+
+.global _mle_start
+_mle_start:
+
+/* Original:
+ * entry point post-launch, to verify memory layout
+ * (must all be w/in one page; since _start is page-aligned, it will be;
+ * which is why we can't call much other code (e.g. printk, TPM fns, etc.)
+ * EFI:
+ * this routine is on the first page of the .text section, page aligned and
+ * far smaller than PAGE_SIZE.
+ */
+ENTRY(post_launch_entry)
+ /*
+ * Per the spec:
+ * EBX - MLE entry point physical address.
+ * ECX - MLE page table base physical address.
+ *
+ * Restore the world, get back into longer mode. EBX contains the entry
+ * point which is our only known location in protected mode. We will
+ * use it to set things right then validate it later. If it is not
+ * what it is supposed to be, the world will come crashing down. Start
+ * by creating our page tables. Store it in ESI so EBX can be used.
+ *
+ * N.B. It seems though that TXT should guarantee the register contains
+ * what it says it should per the specification. Not sure why it would
+ * need verification.
+ *
+ * TODO if we end up needing to validate EBX here we can load a stack
+ * in some scratch location, call and pop to get EIP and then frob up
+ * a location to compare.
+ */
+ cli
+ movl %ebx, %esi
+
+ /* Fixup some addresses for the GDT and long jump */
+ movl %ebx, %ecx
+ addl $(gdt_desc64 - _mle_start + 2), %ecx
+ movl %ebx, %eax
+ addl $(gdt_table64 - _mle_start), %eax
+ movl %eax, (%ecx)
+
+ movl %ebx, %ecx
+ addl $(gdt_desc64_ptr - _mle_start), %ecx
+ movl %ebx, %eax
+ addl $(gdt_desc64 - _mle_start), %eax
+ movl %eax, (%ecx)
+
+ movl %ebx, %ecx
+ addl $(jump64 - _mle_start + 1), %ecx
+ movl %ebx, %eax
+ addl $(entry64 - _mle_start), %eax
+ movl %eax, (%ecx)
+
+ /* Zero out all page table pages so there are no surprises */
+ movl %ebx, %edi
+ subl $(TBOOT_RTMEM_SIZE + PAGE_SIZE), %edi
+ xorl %eax, %eax
+ movl $(TBOOT_PLEPT_SIZE/4), %ecx
+ rep stosl
+
+ /* First page is the PML4 table with one PDP entry */
+ movl %ebx, %eax
+ subl $(TBOOT_RTMEM_SIZE + PAGE_SIZE), %eax
+ movl %eax, %ecx
+ addl $PAGE_SIZE, %ecx
+ orl $0x3, %ecx
+ movl %ecx, (%eax)
+
+ /* Second page is the PDP table with 4 PD entries */
+ addl $PAGE_SIZE, %eax
+ movl %eax, %ecx
+ xorl %edx, %edx
+1:
+ addl $PAGE_SIZE, %ecx
+ cmpb $4, %dl
+ jz 2f
+ orl $0x3, %ecx
+ movl %ecx, (%eax)
+ addl $0x8, %eax
+ incb %dl
+ jmp 1b
+2: /* EAX Page 2 + 0x20 */
+
+ /* Next 4 pages are PDs that map all of mem < 4G as 2M pages */
+ addl $(PAGE_SIZE - 0x20), %eax
+ xorl %edx, %edx
+ xorl %ecx, %ecx
+ xorl %ebx, %ebx
+ addl $0x83, %ecx
+1:
+ cmpw $512, %dx
+ jz 2f
+ movl %ecx, (%eax)
+ addl $0x8, %eax
+ addl $0x200000, %ecx
+ incw %dx
+ jmp 1b
+2:
+ cmpb $3, %bl
+ jz 3f
+ incb %bl
+ xorl %edx, %edx
+ jmp 1b
+3: /* EAX Page 7 */
+
+ /* Return to first PD entry on first PD and setup a PT entry */
+ movl %eax, %ecx
+ subl $(4*PAGE_SIZE), %eax
+ orl $0x3, %ecx
+ movl %ecx, (%eax)
+
+ /* Page 7 is a PT that maps all of mem < 2M as 4K pages */
+ addl $(4*PAGE_SIZE), %eax
+ xorl %edx, %edx
+ xorl %ecx, %ecx
+ addl $0x3, %ecx
+1:
+ cmpw $512, %dx
+ jz 2f
+ movl %ecx, (%eax)
+ addl $0x8, %eax
+ addl $0x1000, %ecx
+ incw %dx
+ jmp 1b
+2: /* EAX Page 8 */
+
+ /*
+ * And done - all memory below 4G is identity mapped. Time to get back
+ * to long mode. EAX contains the base of the page table structures.
+ */
+ subl $(7*PAGE_SIZE), %eax
+
+ /* Restore CR4, PAE must be enabled before IA-32e mode */
+ movl %cr4, %ecx
+ orl $(CR4_PAE | CR4_PGE), %ecx
+ movl %ecx, %cr4
+
+ /* Load PML4 table location into PT base register */
+ movl %eax, %cr3
+
+ /* Enable IA-32e mode and paging */
+ movl $MSR_EFER, %ecx
+ rdmsr
+ orl $_EFER_LME, %eax
+ wrmsr
+ movl %cr0, %eax
+ orl $(CR0_PG | CR0_NE | CR0_ET | CR0_MP | CR0_PE), %eax
+ movl %eax, %cr0
+ jmp 1f
+1:
+ /* Now in IA-32e compatibility mode */
+
+ /* Setup GDT and ljmp to 64b mode */
+ movl %esi, %ebx
+ addl $(gdt_desc64_ptr - _mle_start), %ebx
+ lgdt (%ebx)
+
+jump64:
+ .byte 0xea /* far jmp op */
+ .long 0x00000000 /* offset (fixed up) */
+ .word CS_SEL64 /* 64b code segment selector */
+
+.code64
+
+entry64:
+ /* Load data segment regs */
+ movw DS_SEL64, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %ss
+
+ /* ESI still has original EBX, put it back */
+ xorq %rbx, %rbx
+ movl %esi, %ebx
+
+ /*
+ * Layout check from original TBOOT. If EBX did not contain the
+ * physaddr of the entry point we would probably be lost way before
+ * we got here. But check it anyway then check the page tables passed
+ * to SENTER.
+ */
+ leaq post_launch_entry(%rip), %rax
+ cmpl %eax, %ebx
+ jne 1f
+
+ /*
+ * Verify last entry in MLE page table is the one we expected
+ * this is sufficient because: 1) all addrs must be phys increasing
+ * and 2) tboot is phys contig -- therefore if any page were moved to
+ * a different phys addr then the last page would have to be different
+ * from tboot's last page. Note in paging mode identity mapped so
+ * phys == virt for this verification.
+ *
+ * Get addr of MLE page table from OsSinitData, with the start of
+ * TXT heap == BiosDataSize.
+ */
+ movq $TXT_PRIV_CONFIG_REGS_BASE, %rcx
+ mov TXTCR_HEAP_BASE(%rcx), %rax
+ addq (%rax), %rax /* skip BiosData */
+ addq (%rax), %rax /* skip OsMleData */
+ movq (MLE_PGTBL_OFFSET + 8)(%rax), %rax /* addr of MLE page table */
+ movq (%rax), %rax /* PDP -> PD page */
+ andq $PAGE_MASK, %rax
+ movq (%rax), %rax /* PD -> PT page */
+ andq $PAGE_MASK, %rax
+ /* Get the MLE size; this value was stored in the MLE and measured */
+ leaq _mle_size(%rip), %rdx
+ movq %rdx, %rcx
+ /* Use size to move past last valid PTE then one back */
+ shrq $PAGE_SHIFT - 3, %rcx /* Like size div 512 */
+ subq $8, %rcx
+ addq %rcx, %rax
+ movq (%rax), %rax /* PTE of last page */
+ andq $PAGE_MASK, %rax
+ /* Calculate expected addr of last page */
+ addq %rdx, %rbx
+ decq %rbx /* MLE start + size - 1 addr of last byte */
+ andq $PAGE_MASK, %rbx /* ...rounded to page start */
+ /* Are they equal? */
+ cmpq %rbx, %rax
+ je start64
+ /* Else fall through and die */
+
+ /* Layout check failed so TXT RESET with a special error code */
+1:
+ movq $TXT_PRIV_CONFIG_REGS_BASE, %rcx
+ movl $LAYOUT_ERR, TXTCR_ERRORCODE(%rcx)
+ /* unlock memory config (and serialize) */
+ movb $1, TXTCR_CMD_UNLOCK_MEM_CONFIG(%rcx)
+ movq TXTCR_STS(%rcx), %rax
+ /* TXT RESET */
+ movb $1, TXTCR_CMD_RESET(%rcx)
+ movb $6, %al
+ movw $0xcf9, %dx
+ outb %al, %dx /* for debug chipsets where TXT RESET may not work */
+ ud2
+
+start64:
+ /* Clear the .bss of pre-launch stuffs */
+ leaq _bss_start(%rip), %rdi
+ leaq _bss_size(%rip), %rcx
+ xorq %rax, %rax
+ rep stosb
+
+ /* Load up a stack */
+ leaq bsp_stack(%rip), %rax
+ movq %rax, %rsp
+
+ /* Fixup IDT table and descriptor, load and STI */
+ leaq idt_desc64_end(%rip), %rax
+ leaq idt_table64(%rip), %rcx
+ movq %rcx, -8(%rax)
+
+ leaq int_handler(%rip), %rax
+ xorq %rdx, %rdx
+1:
+ cmpw $256, %dx
+ jz 1f
+ movq %rax, %rbx
+ movw %bx, (%rcx)
+ shrq $16, %rbx
+ movw %bx, 12(%rcx)
+ shrq $16, %rbx
+ movl %ebx, 16(%rcx)
+ cmpw $18, %dx
+ jnz 2f
+ /* MCE vector */
+ movl $0x8f00, 8(%rcx) /* P, DPL=0, 64b, Trap */
+2:
+ incw %dx
+ addq $16, %rcx
+ jmp 1b
+1:
+ lidt idt_desc64(%rip)
+ sti
+
+ /* Enable MCE */
+ movq %cr4, %rax
+ orq $CR4_MCE, %rax
+ movq %rax, %cr4
+
+ /* And we are outa here... */
+ callq post_launch
+ ud2
+
+/*
+ * vmexit handler
+ */
+ENTRY(vmx_asm_vmexit_handler)
+ call vmx_vmexit_handler
+ /* fall through to loop if callee returns (shouldn't happen) */
+
+ENTRY(_mini_guest)
+ pause
+ /* TODO rest */
+ ret
+
+ENTRY(bsp_stack_ref)
+ leaq bsp_stack(%rip), %rax
+ ret
+
+/*
+ * Interrupt handler
+ */
+int_handler:
+ call handle_exception
+ ud2
+
+/* GDT */
+ .align 16
+gdt_desc64:
+ .word gdt_table64_end - gdt_table64 - 1 /* Limit */
+ .long 0x00000000 /* Base */
+gdt_desc64_end:
+
+gdt_desc64_ptr:
+ .long 0x00000000 /* Pointer to GDT descriptor */
+
+ .align 16
+gdt_table64:
+ /* Null Segment */
+ .quad 0x0000000000000000
+ /* Code Segment */
+ .word 0x0000 /* Limit 1 */
+ .word 0x0000 /* Base 1 */
+ .byte 0x00 /* Base 2 */
+ .byte 0x9a /* P=1 DPL=0 11=code C=0 R=1 A=0 */
+ .byte 0x20 /* G=0 D=0 L=1 D=0 AVL=0 Limit 2 */
+ .byte 0x00 /* Base 3 */
+ /* Data Segment */
+ .word 0x0000 /* Limit 1 */
+ .word 0x0000 /* Base 1 */
+ .byte 0x00 /* Base 2 */
+ .byte 0x92 /* P=1 DPL=0 10=code C=0 W=1 A=0 */
+ .byte 0x00 /* G=0 D=0 L=0 D=0 AVL=0 Limit 2 */
+ .byte 0x00 /* Base 3 */
+gdt_table64_end:
+
+/* IDT */
+ .align 16
+idt_desc64:
+ .word idt_table64_end - idt_table64 - 1 /* Limit */
+ .quad 0x0000000000000000 /* Base */
+idt_desc64_end:
+
+ .align 16
+
+idt_table64:
+ .rept 256
+ .word 0x0000 /* Offset 15 - 0 */
+ .word CS_SEL64 /* Segment selector */
+ .word 0x8e00 /* P, DPL=0, 64b, Interrupt (default) */
+ .word 0x0000 /* Offset 31 - 16 */
+ .long 0x00000000 /* Offset 63 - 32 */
+ .long 0x00000000 /* Reserved */
+ .endr
+idt_table64_end:
+
+.global _mle_size
+_mle_size:
+ .quad 0x0000000000000000 /* MLE size */
+
+.global _bss_size
+_bss_size:
+ .quad 0x0000000000000000 /* .bss size */
+
+.section ".data"
+ .align PAGE_SIZE, 0
+
+.section ".rdata"
+ .align PAGE_SIZE, 0
+
+/*
+ * shared data page with kernel (i.e. Xen)
+ * (put at end so that not split e820 region for tboot)
+ */
+.section ".tbootsh","w"
+ .align PAGE_SIZE, 0
+
+ .globl _tboot_shared
+_tboot_shared:
+ .fill PAGE_SIZE,1,0
+ .align PAGE_SIZE, 0
+
+.section ".bss"
+ .align PAGE_SIZE, 0
+
+.global _bss_start
+_bss_start:
+
+/* Stacks */
+
+bsp_stack_end:
+ .fill BSP_STACK_SIZE, 1, 0
+bsp_stack:
+
+ap_stacks_end:
+ .fill AP_STACK_SIZE * NR_CPUS, 1, 0
+ap_stacks:
+
+/* Page Table and VMCS data for AP bringup */
+
+ .align PAGE_SIZE, 0
+ .globl idle_pg_table
+idle_pg_table:
+ .fill 1*PAGE_SIZE,1,0
+
+ .align PAGE_SIZE, 0
+ .globl host_vmcs
+host_vmcs:
+ .fill 1*PAGE_SIZE,1,0
+
+ .align PAGE_SIZE, 0
+ .global ap_vmcs /* the input info when os/vmm kerneltrap into tboot */
+ap_vmcs:
+ .fill NR_CPUS * PAGE_SIZE, 1, 0
diff --git a/tboot/misc.c b/tboot/misc.c
new file mode 100644
index 0000000..480e9da
--- /dev/null
+++ b/tboot/misc.c
@@ -0,0 +1,455 @@
+/*
+ * misc.c: miscellaneous support fns
+ *
+ * Copyright (c) 2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <printk.h>
+#include <compiler.h>
+#include <processor.h>
+#include <atomic.h>
+#include <io.h>
+#include <msr.h>
+#include <page.h>
+#include <ctype.h>
+#include <misc.h>
+#include <tb_error.h>
+#include <txt/txt.h>
+
+/*
+ * if 'prefix' != NULL, print it before each line of hex string
+ */
+void print_hex(const char *prefix, const void *prtptr, size_t size)
+{
+ for ( size_t i = 0; i < size; i++ ) {
+ if ( i % 16 == 0 && prefix != NULL )
+ printk(TBOOT_DETA"\n%s", prefix);
+ printk(TBOOT_DETA"%02x ", *(uint8_t *)prtptr++);
+ }
+ printk(TBOOT_DETA"\n");
+}
+
+void print_system_values(void)
+{
+ lmode_desc_t gdt;
+ lmode_desc_t idt;
+
+ store_gdt(&gdt);
+ store_idt(&idt);
+
+ /* Note the limit is 1 less than the actual length */
+ printk(TBOOT_DETA"GDT %016llx:%04x\n", gdt.base, gdt.limit);
+ /*print_hex("GDT: ", (void*)gdt.base, gdt.limit + 1);*/
+ printk(TBOOT_DETA"IDT %016llx:%04x\n", idt.base, idt.limit);
+ /*print_hex("IDT: ", (void*)idt.base, idt.limit + 1);*/
+ printk(TBOOT_DETA"CR0: %08llx\n", read_cr0());
+ printk(TBOOT_DETA"CR3: %08llx\n", read_cr3());
+ printk(TBOOT_DETA"CR4: %08llx\n", read_cr4());
+ printk(TBOOT_DETA"IA32_EFER MSR: %016llx\n", rdmsr(MSR_EFER));
+}
+
+static bool g_calibrated = false;
+static uint64_t g_ticks_per_millisec;
+
+#define TIMER_FREQ 1193182
+#define TIMER_DIV(hz) ((TIMER_FREQ+(hz)/2)/(hz))
+
+static void wait_tsc_uip(void)
+{
+ do {
+ outb(0x43, 0xe8);
+ cpu_relax();
+ } while ( !(inb(0x42) & 0x80) );
+ do {
+ outb(0x43, 0xe8);
+ cpu_relax();
+ } while ( inb(0x42) & 0x80 );
+}
+
+static void calibrate_tsc(void)
+{
+ if ( g_calibrated )
+ return;
+
+ /* disable speeker */
+ uint8_t val = inb(0x61);
+ val = ((val & ~0x2) | 0x1);
+ outb(0x61, val);
+
+ /* 0xb6 - counter2, low then high byte write */
+ /* mode 3, binary */
+ outb(0x43, 0xb6);
+
+ /* 0x4a9 - divisor to get 1ms period time */
+ /* 1.19318 MHz / 1193 = 1000.15Hz */
+ uint16_t latch = TIMER_DIV(1000);
+ outb(0x42, latch & 0xff);
+ outb(0x42, latch >> 8);
+
+ /* 0xe8 - read back command, don't get count */
+ /* get status, counter2 select */
+ do {
+ outb(0x43, 0xe8);
+ cpu_relax();
+ } while ( inb(0x42) & 0x40 );
+
+ wait_tsc_uip();
+
+ /* get starting TSC val */
+ uint64_t start = rdtsc();
+
+ wait_tsc_uip();
+
+ uint64_t end = rdtsc();
+
+ /* # ticks in 1 millisecond */
+ g_ticks_per_millisec = end - start;
+
+ /* restore timer 1 programming */
+ outb(0x43, 0x54);
+ outb(0x41, 0x12);
+
+ g_calibrated = true;
+}
+
+void delay(int millisecs)
+{
+ if ( millisecs <= 0 )
+ return;
+
+ calibrate_tsc();
+
+ uint64_t rtc = rdtsc();
+
+ uint64_t end_ticks = rtc + millisecs * g_ticks_per_millisec;
+ while ( rtc < end_ticks ) {
+ cpu_relax();
+ rtc = rdtsc();
+ }
+}
+
+#define PAGE_IDX_MASK ((1ULL << 9) - 1) /* 0x1FF 9 bits */
+#define PHYS_ADDR_MASK ((1ULL << 52) - 0x1000) /* 0xFFFFFFFFFF000 52 bits, 4K masked */
+#define PHYS_ADDR_2M_MASK ((1ULL << 52) - 0x200000) /* 0xFFFFFFFE00000 52 bits, 2M masked */
+#define PHYS_ADDR_1G_MASK ((1ULL << 52) - 0x40000000) /* 0xFFFFFC0000000 52 bits, 1G masked */
+#define PAGE_4K_MASK 0xFFF
+#define PAGE_2M_MASK 0x1FFFFF
+#define PAGE_1G_MASK 0x3FFFFFFF
+#define ps_bit_set(e) ((e >> 7) & 1)
+#define p_bit_set(e) (e & 1)
+#define ENTRIES_PER_TABLE 512
+
+bool test_virt_to_phys(uint64_t vaddr)
+{
+ uint64_t pml4i = (vaddr >> 39) & PAGE_IDX_MASK;
+ uint64_t pdpi = (vaddr >> 30) & PAGE_IDX_MASK;
+ uint64_t pdi = (vaddr >> 21) & PAGE_IDX_MASK;
+ uint64_t pti = (vaddr >> 12) & PAGE_IDX_MASK;
+ uint64_t *pml4p, pml4e;
+ uint64_t *pdpp, pdpe;
+ uint64_t *pdp, pde;
+ uint64_t *ptp, pte;
+ uint64_t paddr;
+
+ pml4p = (uint64_t*)(read_cr3() & PAGE_MASK);
+ pml4e = pml4p[pml4i];
+ printk("V2P pml4p: %p pml4i: %016llx pml4e: %016llx\n",
+ pml4p, pml4i, pml4e);
+ if (!p_bit_set(pml4e)) {
+ printk("V2P Error pml4 entry not present!\n");
+ goto err;
+ }
+
+ pdpp = (uint64_t*)(pml4e & PHYS_ADDR_MASK);
+ pdpe = pdpp[pdpi];
+ printk("V2P pdpp: %p pdpi: %016llx pdpe: %016llx\n",
+ pdpp, pdpi, pdpe);
+ if (!p_bit_set(pdpe)) {
+ printk("V2P Error pdp entry not present!\n");
+ goto err;
+ }
+ if (ps_bit_set(pdpe)) {
+ printk("V2P 1G page\n");
+ paddr = (pdpe & PHYS_ADDR_1G_MASK) + (vaddr & PAGE_1G_MASK);
+ goto out;
+ }
+
+ pdp = (uint64_t*)(pdpe & PHYS_ADDR_MASK);
+ pde = pdp[pdi];
+ printk("V2P pdp: %p pdi: %016llx pde: %016llx\n",
+ pdp, pdi, pde);
+ if (!p_bit_set(pde)) {
+ printk("V2P Error pd entry not present!\n");
+ goto err;
+ }
+ if (ps_bit_set(pde)) {
+ printk("V2P 2M page\n");
+ paddr = (pde & PHYS_ADDR_2M_MASK) + (vaddr & PAGE_2M_MASK);
+ goto out;
+ }
+
+ ptp = (uint64_t*)(pde & PHYS_ADDR_MASK);
+ pte = ptp[pti];
+ printk("V2P ptp: %p pti: %016llx pte: %016llx\n",
+ ptp, pti, pte);
+ if (!p_bit_set(pte)) {
+ printk("V2P Error pt entry not present!\n");
+ goto err;
+ }
+
+ printk("V2P 4K page\n");
+ paddr = (pte & PHYS_ADDR_MASK) + (vaddr & PAGE_4K_MASK);
+
+out:
+ printk("V2P vaddr: %016llx paddr: %016llx\n",
+ vaddr, paddr);
+
+ if (vaddr != paddr)
+ return false;
+
+ return true;
+
+err:
+ return false;
+}
+
+void dump_page_tables(void)
+{
+ uint32_t l4i, l3i, l2i, l1i;
+ uint64_t *pml4p, *pdpp, *pdp, *ptp;
+
+ pml4p = (uint64_t*)(read_cr3() & PAGE_MASK);
+ printk("PAGE TABLE DUMP@ 0x%016llx\n", (uint64_t)pml4p);
+
+ for (l4i = 0; l4i < ENTRIES_PER_TABLE; l4i++) {
+ if (!p_bit_set(pml4p[l4i])) {
+ printk(" PML4 entry(%d) not present\n", l4i);
+ continue;
+ }
+
+ printk(" PML4 entry(%d) table: 0x%016llx\n", l4i, pml4p[l4i]);
+ pdpp = (uint64_t*)(pml4p[l4i] & PHYS_ADDR_MASK);
+ for (l3i = 0; l3i < ENTRIES_PER_TABLE; l3i++) {
+ if (!p_bit_set(pdpp[l3i])) {
+ printk(" PDP entry(%d) not present\n", l3i);
+ continue;
+ }
+ if (ps_bit_set(pdpp[l3i])) {
+ printk(" PDP entry(%d) 1G page: 0x%016llx\n", l3i, pdpp[l3i]);
+ continue;
+ }
+
+ printk(" PDP entry(%d) table: 0x%016llx\n", l3i, pdpp[l3i]);
+ pdp = (uint64_t*)(pdpp[l3i] & PHYS_ADDR_MASK);
+ for (l2i = 0; l2i < ENTRIES_PER_TABLE; l2i++) {
+ if (!p_bit_set(pdp[l2i])) {
+ printk(" PD entry(%d) not present\n", l2i);
+ continue;
+ }
+ if (ps_bit_set(pdp[l2i])) {
+ printk(" PD entry(%d) 2M page: 0x%016llx\n", l2i, pdp[l2i]);
+ continue;
+ }
+
+ printk(" PD entry(%d) table: 0x%016llx\n", l2i, pdp[l2i]);
+ ptp = (uint64_t*)(pdp[l2i] & PHYS_ADDR_MASK);
+ for (l1i = 0; l1i < ENTRIES_PER_TABLE; l1i++) {
+ if (!p_bit_set(ptp[l1i])) {
+ printk(" PT entry(%d) not present\n", l1i);
+ continue;
+ }
+ printk(" PT entry(%d) 4K page: 0x%016llx\n", l1i, ptp[l1i]);
+ }
+ }
+ }
+ }
+}
+
+/* used by isXXX() in ctype.h */
+/* originally from:
+ * http://fxr.watson.org/fxr/source/dist/acpica/utclib.c?v=NETBSD5
+ * re-licensed by Intel Corporation
+ */
+
+const uint8_t _ctype[CTYPE_SIZE] = {
+ _CN, /* 0x0 0. */
+ _CN, /* 0x1 1. */
+ _CN, /* 0x2 2. */
+ _CN, /* 0x3 3. */
+ _CN, /* 0x4 4. */
+ _CN, /* 0x5 5. */
+ _CN, /* 0x6 6. */
+ _CN, /* 0x7 7. */
+ _CN, /* 0x8 8. */
+ _CN|_SP, /* 0x9 9. */
+ _CN|_SP, /* 0xA 10. */
+ _CN|_SP, /* 0xB 11. */
+ _CN|_SP, /* 0xC 12. */
+ _CN|_SP, /* 0xD 13. */
+ _CN, /* 0xE 14. */
+ _CN, /* 0xF 15. */
+ _CN, /* 0x10 16. */
+ _CN, /* 0x11 17. */
+ _CN, /* 0x12 18. */
+ _CN, /* 0x13 19. */
+ _CN, /* 0x14 20. */
+ _CN, /* 0x15 21. */
+ _CN, /* 0x16 22. */
+ _CN, /* 0x17 23. */
+ _CN, /* 0x18 24. */
+ _CN, /* 0x19 25. */
+ _CN, /* 0x1A 26. */
+ _CN, /* 0x1B 27. */
+ _CN, /* 0x1C 28. */
+ _CN, /* 0x1D 29. */
+ _CN, /* 0x1E 30. */
+ _CN, /* 0x1F 31. */
+ _XS|_SP, /* 0x20 32. ' ' */
+ _PU, /* 0x21 33. '!' */
+ _PU, /* 0x22 34. '"' */
+ _PU, /* 0x23 35. '#' */
+ _PU, /* 0x24 36. '$' */
+ _PU, /* 0x25 37. '%' */
+ _PU, /* 0x26 38. '&' */
+ _PU, /* 0x27 39. ''' */
+ _PU, /* 0x28 40. '(' */
+ _PU, /* 0x29 41. ')' */
+ _PU, /* 0x2A 42. '*' */
+ _PU, /* 0x2B 43. '+' */
+ _PU, /* 0x2C 44. ',' */
+ _PU, /* 0x2D 45. '-' */
+ _PU, /* 0x2E 46. '.' */
+ _PU, /* 0x2F 47. '/' */
+ _XD|_DI, /* 0x30 48. '' */
+ _XD|_DI, /* 0x31 49. '1' */
+ _XD|_DI, /* 0x32 50. '2' */
+ _XD|_DI, /* 0x33 51. '3' */
+ _XD|_DI, /* 0x34 52. '4' */
+ _XD|_DI, /* 0x35 53. '5' */
+ _XD|_DI, /* 0x36 54. '6' */
+ _XD|_DI, /* 0x37 55. '7' */
+ _XD|_DI, /* 0x38 56. '8' */
+ _XD|_DI, /* 0x39 57. '9' */
+ _PU, /* 0x3A 58. ':' */
+ _PU, /* 0x3B 59. ';' */
+ _PU, /* 0x3C 60. '<' */
+ _PU, /* 0x3D 61. '=' */
+ _PU, /* 0x3E 62. '>' */
+ _PU, /* 0x3F 63. '?' */
+ _PU, /* 0x40 64. '@' */
+ _XD|_UP, /* 0x41 65. 'A' */
+ _XD|_UP, /* 0x42 66. 'B' */
+ _XD|_UP, /* 0x43 67. 'C' */
+ _XD|_UP, /* 0x44 68. 'D' */
+ _XD|_UP, /* 0x45 69. 'E' */
+ _XD|_UP, /* 0x46 70. 'F' */
+ _UP, /* 0x47 71. 'G' */
+ _UP, /* 0x48 72. 'H' */
+ _UP, /* 0x49 73. 'I' */
+ _UP, /* 0x4A 74. 'J' */
+ _UP, /* 0x4B 75. 'K' */
+ _UP, /* 0x4C 76. 'L' */
+ _UP, /* 0x4D 77. 'M' */
+ _UP, /* 0x4E 78. 'N' */
+ _UP, /* 0x4F 79. 'O' */
+ _UP, /* 0x50 80. 'P' */
+ _UP, /* 0x51 81. 'Q' */
+ _UP, /* 0x52 82. 'R' */
+ _UP, /* 0x53 83. 'S' */
+ _UP, /* 0x54 84. 'T' */
+ _UP, /* 0x55 85. 'U' */
+ _UP, /* 0x56 86. 'V' */
+ _UP, /* 0x57 87. 'W' */
+ _UP, /* 0x58 88. 'X' */
+ _UP, /* 0x59 89. 'Y' */
+ _UP, /* 0x5A 90. 'Z' */
+ _PU, /* 0x5B 91. '[' */
+ _PU, /* 0x5C 92. '\' */
+ _PU, /* 0x5D 93. ']' */
+ _PU, /* 0x5E 94. '^' */
+ _PU, /* 0x5F 95. '_' */
+ _PU, /* 0x60 96. '`' */
+ _XD|_LO, /* 0x61 97. 'a' */
+ _XD|_LO, /* 0x62 98. 'b' */
+ _XD|_LO, /* 0x63 99. 'c' */
+ _XD|_LO, /* 0x64 100. 'd' */
+ _XD|_LO, /* 0x65 101. 'e' */
+ _XD|_LO, /* 0x66 102. 'f' */
+ _LO, /* 0x67 103. 'g' */
+ _LO, /* 0x68 104. 'h' */
+ _LO, /* 0x69 105. 'i' */
+ _LO, /* 0x6A 106. 'j' */
+ _LO, /* 0x6B 107. 'k' */
+ _LO, /* 0x6C 108. 'l' */
+ _LO, /* 0x6D 109. 'm' */
+ _LO, /* 0x6E 110. 'n' */
+ _LO, /* 0x6F 111. 'o' */
+ _LO, /* 0x70 112. 'p' */
+ _LO, /* 0x71 113. 'q' */
+ _LO, /* 0x72 114. 'r' */
+ _LO, /* 0x73 115. 's' */
+ _LO, /* 0x74 116. 't' */
+ _LO, /* 0x75 117. 'u' */
+ _LO, /* 0x76 118. 'v' */
+ _LO, /* 0x77 119. 'w' */
+ _LO, /* 0x78 120. 'x' */
+ _LO, /* 0x79 121. 'y' */
+ _LO, /* 0x7A 122. 'z' */
+ _PU, /* 0x7B 123. '{' */
+ _PU, /* 0x7C 124. '|' */
+ _PU, /* 0x7D 125. '}' */
+ _PU, /* 0x7E 126. '~' */
+ _CN, /* 0x7F 127. */
+
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80 to 0x8F */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90 to 0x9F */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xA0 to 0xAF */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xB0 to 0xBF */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xC0 to 0xCF */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xD0 to 0xDF */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xE0 to 0xEF */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* 0xF0 to 0x100 */
+};
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/mtrrs.c b/tboot/mtrrs.c
new file mode 100644
index 0000000..0d02b90
--- /dev/null
+++ b/tboot/mtrrs.c
@@ -0,0 +1,624 @@
+/*
+ * mtrrs.c: support functions for manipulating MTRRs
+ *
+ * Copyright (c) 2003-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <compiler.h>
+#include <string.h>
+#include <processor.h>
+#include <msr.h>
+#include <printk.h>
+#include <misc.h>
+#include <page.h>
+#include <tb_error.h>
+#include <eficore.h>
+#include <tboot.h>
+#include <acpi.h>
+#include <mle.h>
+#include <txt/config_regs.h>
+#include <txt/mtrrs.h>
+#include <txt/acmod.h>
+#include <tpm.h>
+
+#define MTRR_TYPE_MIXED -1
+#define MMIO_APIC_BASE 0xFEE00000
+#define NR_MMIO_APIC_PAGES 1
+#define NR_MMIO_IOAPIC_PAGES 1
+#define NR_MMIO_PCICFG_PAGES 1
+#define SINIT_MTRR_MASK 0xFFFFFF /* SINIT requires 36b mask */
+
+/* saved MTRR state or NULL if orig. MTRRs have not been changed */
+static __data mtrr_state_t *g_saved_mtrrs = NULL;
+
+static uint64_t get_maxphyaddr_mask(void)
+{
+ static bool printed_msg = false;
+ union {
+ uint32_t raw;
+ struct {
+ uint32_t num_pa_bits : 8;
+ uint32_t num_la_bits : 8;
+ uint32_t reserved : 16;
+ };
+ } num_addr_bits;
+
+ /* does CPU support 0x80000008 CPUID leaf? (all TXT CPUs should) */
+ uint32_t max_ext_fn = cpuid_eax(0x80000000);
+ if ( max_ext_fn < 0x80000008 )
+ return 0xffffff; /* if not, default is 36b support */
+
+ num_addr_bits.raw = cpuid_eax(0x80000008);
+ if ( !printed_msg ) {
+ printk(TBOOT_DETA"CPU supports %u phys address bits\n", num_addr_bits.num_pa_bits);
+ printed_msg = true;
+ }
+ return ((1ULL << num_addr_bits.num_pa_bits) - 1) >> PAGE_SHIFT;
+}
+
+/*
+ * this must be done for each processor so that all have the same
+ * memory types
+ */
+bool set_mtrrs_for_acmod(const acm_hdr_t *hdr)
+{
+ unsigned long long rflags;
+ unsigned long long cr0, cr4;
+
+ /*
+ * need to do some things before we start changing MTRRs
+ *
+ * since this will modify some of the MTRRs, they should be saved first
+ * so that they can be restored once the AC mod is done
+ */
+
+ /* disable interrupts */
+ rflags = read_rflags();
+ disable_intr();
+
+ /* save CR0 then disable cache (CRO.CD=1, CR0.NW=0) */
+ cr0 = read_cr0();
+ write_cr0((cr0 & ~CR0_NW) | CR0_CD);
+
+ /* flush caches */
+ wbinvd();
+
+ /* save CR4 and disable global pages (CR4.PGE=0) */
+ cr4 = read_cr4();
+ if (cr4 & CR4_PGE)
+ write_cr4(cr4 & ~CR4_PGE);
+ else
+ flush_tlb();
+
+ /* disable MTRRs */
+ set_all_mtrrs(false);
+
+ /*
+ * now set MTRRs for AC mod and rest of memory
+ */
+ if ( !set_mem_type(hdr, hdr->size*4, MTRR_TYPE_WRBACK) )
+ return false;
+
+ /*
+ * now undo some of earlier changes and enable our new settings
+ */
+
+ /* flush caches */
+ wbinvd();
+
+ /* enable MTRRs */
+ set_all_mtrrs(true);
+
+ /* restore CR0 (cacheing) */
+ write_cr0(cr0);
+
+ /* restore CR4 (global pages) */
+ if (cr4 & CR4_PGE)
+ write_cr4(cr4);
+
+ /* enable interrupts */
+ write_rflags(rflags);
+
+ return true;
+}
+
+void save_mtrrs(mtrr_state_t *saved_state)
+{
+ mtrr_cap_t mtrr_cap;
+
+ /* IA32_MTRR_DEF_TYPE MSR */
+ saved_state->mtrr_def_type.raw = rdmsr(MSR_MTRRdefType);
+
+ /* number variable MTTRRs */
+ mtrr_cap.raw = rdmsr(MSR_MTRRcap);
+ if ( mtrr_cap.vcnt > MAX_VARIABLE_MTRRS ) {
+ /* print warning but continue saving what we can */
+ /* (set_mem_type() won't exceed the array, so we're safe doing this) */
+ printk(TBOOT_WARN"actual # var MTRRs (%d) > MAX_VARIABLE_MTRRS (%d)\n",
+ mtrr_cap.vcnt, MAX_VARIABLE_MTRRS);
+ saved_state->num_var_mtrrs = MAX_VARIABLE_MTRRS;
+ }
+ else
+ saved_state->num_var_mtrrs = mtrr_cap.vcnt;
+
+ /* physmask's and physbase's */
+ for ( unsigned int ndx = 0; ndx < saved_state->num_var_mtrrs; ndx++ ) {
+ saved_state->mtrr_physmasks[ndx].raw =
+ rdmsr(MTRR_PHYS_MASK0_MSR + ndx*2);
+ saved_state->mtrr_physbases[ndx].raw =
+ rdmsr(MTRR_PHYS_BASE0_MSR + ndx*2);
+ }
+
+ g_saved_mtrrs = saved_state;
+}
+
+static void print_mtrrs(const mtrr_state_t *saved_state)
+{
+ printk(TBOOT_DETA"mtrr_def_type: e = %d, fe = %d, type = %x\n",
+ saved_state->mtrr_def_type.e, saved_state->mtrr_def_type.fe,
+ saved_state->mtrr_def_type.type );
+ printk(TBOOT_DETA"mtrrs:\n");
+ printk(TBOOT_DETA"\t\t base mask type v\n");
+ for ( unsigned int i = 0; i < saved_state->num_var_mtrrs; i++ ) {
+ printk(TBOOT_DETA"\t\t%13.13Lx %13.13Lx %2.2x %d\n",
+ (uint64_t)saved_state->mtrr_physbases[i].base,
+ (uint64_t)saved_state->mtrr_physmasks[i].mask,
+ saved_state->mtrr_physbases[i].type,
+ saved_state->mtrr_physmasks[i].v );
+ }
+}
+
+/* base should be 4k-bytes aligned, no invalid overlap combination */
+static int get_page_type(const mtrr_state_t *saved_state, uint32_t base)
+{
+ int type = -1;
+ bool wt = false;
+ uint64_t maxphyaddr_mask = get_maxphyaddr_mask();
+
+ /* omit whether the fix mtrrs are enabled, just check var mtrrs */
+
+ base >>= PAGE_SHIFT;
+ for ( unsigned int i = 0; i < saved_state->num_var_mtrrs; i++ ) {
+ const mtrr_physbase_t *base_i = &saved_state->mtrr_physbases[i];
+ const mtrr_physmask_t *mask_i = &saved_state->mtrr_physmasks[i];
+
+ if ( mask_i->v == 0 )
+ continue;
+ if ( (base & mask_i->mask & maxphyaddr_mask) !=
+ (base_i->base & mask_i->mask & maxphyaddr_mask) )
+ continue;
+
+ type = base_i->type;
+ if ( type == MTRR_TYPE_UNCACHABLE )
+ return MTRR_TYPE_UNCACHABLE;
+ if ( type == MTRR_TYPE_WRTHROUGH )
+ wt = true;
+ }
+ if ( wt )
+ return MTRR_TYPE_WRTHROUGH;
+ if ( type != -1 )
+ return type;
+
+ return saved_state->mtrr_def_type.type;
+}
+
+static int get_region_type(const mtrr_state_t *saved_state,
+ uint32_t base, uint32_t pages)
+{
+ int type;
+ uint32_t end;
+
+ if ( pages == 0 )
+ return MTRR_TYPE_MIXED;
+
+ /* wrap the 4G address space */
+ if ( ((uint32_t)(~0) - base) < (pages << PAGE_SHIFT) )
+ return MTRR_TYPE_MIXED;
+
+ if ( saved_state->mtrr_def_type.e == 0 )
+ return MTRR_TYPE_UNCACHABLE;
+
+ /* align to 4k page boundary */
+ base &= PAGE_MASK;
+ end = base + (pages << PAGE_SHIFT);
+
+ type = get_page_type(saved_state, base);
+ base += PAGE_SIZE;
+ for ( ; base < end; base += PAGE_SIZE )
+ if ( type != get_page_type(saved_state, base) )
+ return MTRR_TYPE_MIXED;
+
+ return type;
+}
+
+static bool validate_mmio_regions(const mtrr_state_t *saved_state)
+{
+ acpi_table_mcfg_t *acpi_table_mcfg;
+ acpi_table_ioapic_t *acpi_table_ioapic;
+
+ /* mmio space for TXT private config space should be UC */
+ if ( get_region_type(saved_state, TXT_PRIV_CONFIG_REGS_BASE,
+ TXT_CONFIG_REGS_SIZE >> PAGE_SHIFT)
+ != MTRR_TYPE_UNCACHABLE ) {
+ printk(TBOOT_ERR"MMIO space for TXT private config space should be UC\n");
+ return false;
+ }
+
+ /* mmio space for TXT public config space should be UC */
+ if ( get_region_type(saved_state, TXT_PUB_CONFIG_REGS_BASE,
+ TXT_CONFIG_REGS_SIZE >> PAGE_SHIFT)
+ != MTRR_TYPE_UNCACHABLE ) {
+ printk(TBOOT_ERR"MMIO space for TXT public config space should be UC\n");
+ return false;
+ }
+
+ /* mmio space for TPM should be UC */
+ if ( get_region_type(saved_state, TPM_LOCALITY_BASE,
+ NR_TPM_LOCALITY_PAGES * TPM_NR_LOCALITIES)
+ != MTRR_TYPE_UNCACHABLE ) {
+ printk(TBOOT_ERR"MMIO space for TPM should be UC\n");
+ return false;
+ }
+
+ /* mmio space for APIC should be UC */
+ if ( get_region_type(saved_state, MMIO_APIC_BASE, NR_MMIO_APIC_PAGES)
+ != MTRR_TYPE_UNCACHABLE ) {
+ printk(TBOOT_ERR"MMIO space for APIC should be UC\n");
+ return false;
+ }
+
+ /* TBD: is this check useful if we aren't DMA protecting ACPI? */
+ /* mmio space for IOAPIC should be UC */
+ acpi_table_ioapic = (acpi_table_ioapic_t *)get_acpi_ioapic_table();
+ if ( acpi_table_ioapic == NULL) {
+ printk(TBOOT_ERR"acpi_table_ioapic == NULL\n");
+ return false;
+ }
+ printk(TBOOT_DETA"acpi_table_ioapic @ %p, .address = %x\n",
+ acpi_table_ioapic, acpi_table_ioapic->address);
+ if ( get_region_type(saved_state, acpi_table_ioapic->address,
+ NR_MMIO_IOAPIC_PAGES)
+ != MTRR_TYPE_UNCACHABLE ) {
+ printk(TBOOT_ERR"MMIO space(%x) for IOAPIC should be UC\n",
+ acpi_table_ioapic->address);
+ return false;
+ }
+
+ /* TBD: is this check useful if we aren't DMA protecting ACPI? */
+ /* mmio space for PCI config space should be UC */
+ acpi_table_mcfg = (acpi_table_mcfg_t *)get_acpi_mcfg_table();
+ if ( acpi_table_mcfg == NULL) {
+ printk(TBOOT_ERR"acpi_table_mcfg == NULL\n");
+ return false;
+ }
+ printk(TBOOT_DETA"acpi_table_mcfg @ %p, .base_address = %x\n",
+ acpi_table_mcfg, acpi_table_mcfg->base_address);
+ if ( get_region_type(saved_state, acpi_table_mcfg->base_address,
+ NR_MMIO_PCICFG_PAGES)
+ != MTRR_TYPE_UNCACHABLE ) {
+ printk(TBOOT_ERR"MMIO space(%x) for PCI config space should be UC\n",
+ acpi_table_mcfg->base_address);
+ return false;
+ }
+
+ return true;
+}
+
+bool validate_mtrrs(const mtrr_state_t *saved_state)
+{
+ mtrr_cap_t mtrr_cap;
+ uint64_t maxphyaddr_mask = get_maxphyaddr_mask();
+ uint64_t max_pages = maxphyaddr_mask + 1; /* max # 4k pages supported */
+
+ /* check is meaningless if MTRRs were disabled */
+ if ( saved_state->mtrr_def_type.e == 0 )
+ return true;
+
+ /* number variable MTRRs */
+ mtrr_cap.raw = rdmsr(MSR_MTRRcap);
+ if ( mtrr_cap.vcnt < saved_state->num_var_mtrrs ) {
+ printk(TBOOT_ERR"actual # var MTRRs (%d) < saved # (%d)\n",
+ mtrr_cap.vcnt, saved_state->num_var_mtrrs);
+ return false;
+ }
+
+ /* variable MTRRs describing non-contiguous memory regions */
+ for ( unsigned int ndx = 0; ndx < saved_state->num_var_mtrrs; ndx++ ) {
+ uint64_t tb;
+
+ if ( saved_state->mtrr_physmasks[ndx].v == 0 )
+ continue;
+
+ for ( tb = 1; tb != max_pages; tb = tb << 1 ) {
+ if ( (tb & saved_state->mtrr_physmasks[ndx].mask & maxphyaddr_mask)
+ != 0 )
+ break;
+ }
+ for ( ; tb != max_pages; tb = tb << 1 ) {
+ if ( (tb & saved_state->mtrr_physmasks[ndx].mask & maxphyaddr_mask)
+ == 0 )
+ break;
+ }
+ if ( tb != max_pages ) {
+ printk(TBOOT_ERR"var MTRRs with non-contiguous regions: base=0x%Lx, mask=0x%Lx\n",
+ (uint64_t)saved_state->mtrr_physbases[ndx].base
+ & maxphyaddr_mask,
+ (uint64_t)saved_state->mtrr_physmasks[ndx].mask
+ & maxphyaddr_mask);
+ print_mtrrs(saved_state);
+ return false;
+ }
+ }
+
+ /* overlaping regions with invalid memory type combinations */
+ for ( unsigned int ndx = 0; ndx < saved_state->num_var_mtrrs; ndx++ ) {
+ const mtrr_physbase_t *base_ndx = &saved_state->mtrr_physbases[ndx];
+ const mtrr_physmask_t *mask_ndx = &saved_state->mtrr_physmasks[ndx];
+
+ if ( mask_ndx->v == 0 )
+ continue;
+
+ for ( unsigned int i = ndx + 1; i < saved_state->num_var_mtrrs; i++ ) {
+ const mtrr_physbase_t *base_i = &saved_state->mtrr_physbases[i];
+ const mtrr_physmask_t *mask_i = &saved_state->mtrr_physmasks[i];
+
+ if ( mask_i->v == 0 )
+ continue;
+
+ if ( (base_ndx->base & mask_ndx->mask & mask_i->mask & maxphyaddr_mask)
+ != (base_i->base & mask_i->mask & maxphyaddr_mask) &&
+ (base_i->base & mask_i->mask & mask_ndx->mask & maxphyaddr_mask)
+ != (base_ndx->base & mask_ndx->mask & maxphyaddr_mask) )
+ continue;
+
+ if ( base_ndx->type == base_i->type )
+ continue;
+ if ( base_ndx->type == MTRR_TYPE_UNCACHABLE
+ || base_i->type == MTRR_TYPE_UNCACHABLE )
+ continue;
+ if ( base_ndx->type == MTRR_TYPE_WRTHROUGH
+ && base_i->type == MTRR_TYPE_WRBACK )
+ continue;
+ if ( base_ndx->type == MTRR_TYPE_WRBACK
+ && base_i->type == MTRR_TYPE_WRTHROUGH )
+ continue;
+
+ /* 2 overlapped regions have invalid mem type combination, */
+ /* need to check whether there is a third region which has type */
+ /* of UNCACHABLE and contains at least one of these two regions. */
+ /* If there is, then the combination of these 3 region is valid */
+ unsigned int j;
+ for ( j = 0; j < saved_state->num_var_mtrrs; j++ ) {
+ const mtrr_physbase_t *base_j
+ = &saved_state->mtrr_physbases[j];
+ const mtrr_physmask_t *mask_j
+ = &saved_state->mtrr_physmasks[j];
+
+ if ( mask_j->v == 0 )
+ continue;
+
+ if ( base_j->type != MTRR_TYPE_UNCACHABLE )
+ continue;
+
+ if ( (base_ndx->base & mask_ndx->mask & mask_j->mask & maxphyaddr_mask)
+ == (base_j->base & mask_j->mask & maxphyaddr_mask)
+ && (mask_j->mask & ~mask_ndx->mask & maxphyaddr_mask) == 0 )
+ break;
+
+ if ( (base_i->base & mask_i->mask & mask_j->mask & maxphyaddr_mask)
+ == (base_j->base & mask_j->mask & maxphyaddr_mask)
+ && (mask_j->mask & ~mask_i->mask & maxphyaddr_mask) == 0 )
+ break;
+ }
+ if ( j < saved_state->num_var_mtrrs )
+ continue;
+
+ printk(TBOOT_ERR"var MTRRs overlaping regions, invalid type combinations\n");
+ print_mtrrs(saved_state);
+ return false;
+ }
+ }
+
+ if ( !validate_mmio_regions(saved_state) ) {
+ printk(TBOOT_ERR"Some mmio region should be UC type\n");
+ print_mtrrs(saved_state);
+ return false;
+ }
+
+ print_mtrrs(saved_state);
+ return true;
+}
+
+void restore_mtrrs(const mtrr_state_t *saved_state)
+{
+ /* called by apply_policy() so use saved ptr */
+ if ( saved_state == NULL )
+ saved_state = g_saved_mtrrs;
+ /* haven't saved them yet, so return */
+ if ( saved_state == NULL )
+ return;
+
+ /* disable all MTRRs first */
+ set_all_mtrrs(false);
+
+ /* physmask's and physbase's */
+ for ( unsigned int ndx = 0; ndx < saved_state->num_var_mtrrs; ndx++ ) {
+ wrmsr(MTRR_PHYS_MASK0_MSR + ndx*2,
+ saved_state->mtrr_physmasks[ndx].raw);
+ wrmsr(MTRR_PHYS_BASE0_MSR + ndx*2,
+ saved_state->mtrr_physbases[ndx].raw);
+ }
+
+ /* IA32_MTRR_DEF_TYPE MSR */
+ wrmsr(MSR_MTRRdefType, saved_state->mtrr_def_type.raw);
+}
+
+/*
+ * set the memory type for specified range (base to base+size)
+ * to mem_type and everything else to UC
+ */
+bool set_mem_type(const void *base, uint32_t size, uint32_t mem_type)
+{
+ int num_pages;
+ int ndx;
+ mtrr_def_type_t mtrr_def_type;
+ mtrr_cap_t mtrr_cap;
+ mtrr_physmask_t mtrr_physmask;
+ mtrr_physbase_t mtrr_physbase;
+
+ /*
+ * disable all fixed MTRRs
+ * set default type to UC
+ */
+ mtrr_def_type.raw = rdmsr(MSR_MTRRdefType);
+ mtrr_def_type.fe = 0;
+ mtrr_def_type.type = MTRR_TYPE_UNCACHABLE;
+ wrmsr(MSR_MTRRdefType, mtrr_def_type.raw);
+
+ /*
+ * initially disable all variable MTRRs (we'll enable the ones we use)
+ */
+ mtrr_cap.raw = rdmsr(MSR_MTRRcap);
+ for ( ndx = 0; ndx < mtrr_cap.vcnt; ndx++ ) {
+ mtrr_physmask.raw = rdmsr(MTRR_PHYS_MASK0_MSR + ndx*2);
+ mtrr_physmask.v = 0;
+ wrmsr(MTRR_PHYS_MASK0_MSR + ndx*2, mtrr_physmask.raw);
+ }
+
+ /*
+ * map all AC module pages as mem_type
+ */
+
+ num_pages = PAGE_UP(size) >> PAGE_SHIFT;
+ ndx = 0;
+
+ printk(TBOOT_DETA"setting MTRRs for acmod: base=%p, size=%x, num_pages=%d\n",
+ base, size, num_pages);
+ /*
+ * Each VAR MTRR base must be a multiple if that MTRR's Size
+ */
+ unsigned long long base_v;
+ base_v = (unsigned long long) base;
+ int i =0;
+ // mtrr size in pages
+ int mtrr_s = 1;
+ while ((base_v & 0x01) == 0) {
+ i++;
+ base_v = base_v >>1 ;
+
+ }
+ for (int j=i-12; j>0; j--) mtrr_s =mtrr_s*2; //mtrr_s = mtrr_s << 1
+ printk(TBOOT_DETA"The maximum allowed MTRR range size=%d Pages \n", mtrr_s);
+
+ while (num_pages >= mtrr_s){
+
+ /* set the base of the current MTRR */
+ mtrr_physbase.raw = rdmsr(MTRR_PHYS_BASE0_MSR + ndx*2);
+ mtrr_physbase.base = ((unsigned long long)base >> PAGE_SHIFT) &
+ SINIT_MTRR_MASK;
+ mtrr_physbase.type = mem_type;
+ wrmsr(MTRR_PHYS_BASE0_MSR + ndx*2, mtrr_physbase.raw);
+
+ mtrr_physmask.raw = rdmsr(MTRR_PHYS_MASK0_MSR + ndx*2);
+ mtrr_physmask.mask = ~(mtrr_s - 1) & SINIT_MTRR_MASK;
+ mtrr_physmask.v = 1;
+ wrmsr(MTRR_PHYS_MASK0_MSR + ndx*2, mtrr_physmask.raw);
+
+ base += (mtrr_s * PAGE_SIZE);
+ num_pages -= mtrr_s;
+ ndx++;
+ if ( ndx == mtrr_cap.vcnt ) {
+ printk(TBOOT_ERR"exceeded number of var MTRRs when mapping range\n");
+ return false;
+ }
+ }
+ while ( num_pages > 0 ) {
+ uint32_t pages_in_range;
+
+ /* set the base of the current MTRR */
+ mtrr_physbase.raw = rdmsr(MTRR_PHYS_BASE0_MSR + ndx*2);
+ mtrr_physbase.base = ((unsigned long long)base >> PAGE_SHIFT) &
+ SINIT_MTRR_MASK;
+ mtrr_physbase.type = mem_type;
+ wrmsr(MTRR_PHYS_BASE0_MSR + ndx*2, mtrr_physbase.raw);
+
+ /*
+ * calculate MTRR mask
+ * MTRRs can map pages in power of 2
+ * may need to use multiple MTRRS to map all of region
+ */
+ pages_in_range = 1 << (fls(num_pages) - 1);
+
+ mtrr_physmask.raw = rdmsr(MTRR_PHYS_MASK0_MSR + ndx*2);
+ mtrr_physmask.mask = ~(pages_in_range - 1) & SINIT_MTRR_MASK;
+ mtrr_physmask.v = 1;
+ wrmsr(MTRR_PHYS_MASK0_MSR + ndx*2, mtrr_physmask.raw);
+
+ /*prepare for the next loop depending on number of pages
+ * We figure out from the above how many pages could be used in this
+ * mtrr. Then we decrement the count, increment the base,
+ * increment the mtrr we are dealing with, and if num_pages is
+ * still not zero, we do it again.
+ */
+ base += (pages_in_range * PAGE_SIZE);
+ num_pages -= pages_in_range;
+ ndx++;
+ if ( ndx == mtrr_cap.vcnt ) {
+ printk(TBOOT_ERR"exceeded number of var MTRRs when mapping range\n");
+ return false;
+ }
+ }
+ return true;
+}
+
+/* enable/disable all MTRRs */
+void set_all_mtrrs(bool enable)
+{
+ mtrr_def_type_t mtrr_def_type;
+
+ mtrr_def_type.raw = rdmsr(MSR_MTRRdefType);
+ mtrr_def_type.e = enable ? 1 : 0;
+ wrmsr(MSR_MTRRdefType, mtrr_def_type.raw);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil * End:
+ */
diff --git a/tboot/pci_cfgreg.c b/tboot/pci_cfgreg.c
new file mode 100644
index 0000000..5007b74
--- /dev/null
+++ b/tboot/pci_cfgreg.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
+ * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2000, BSDi
+ * Copyright (c) 2004, Scott Long <scottl@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* from:
+ * $FreeBSD: src/sys/i386/pci/pci_cfgreg.c,v 1.134.2.2.2.1 2010/06/14 02:09:06 kensmith Exp $
+ */
+/*
+ * Portions copyright (c) 2010, Intel Corporation
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <mutex.h>
+#include <io.h>
+#include <pci_cfgreg.h>
+
+enum {
+ CFGMECH_NONE = 0,
+ CFGMECH_1,
+ CFGMECH_2,
+ CFGMECH_PCIE,
+};
+
+struct mutex pcicfg_mtx;
+static const int cfgmech = CFGMECH_1;
+
+/*
+ * Configuration space access using direct register operations
+ */
+
+/* enable configuration space accesses and return data port address */
+static int
+pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
+{
+ int dataport = 0;
+
+ if (bus <= PCI_BUSMAX
+ && slot <= PCI_SLOTMAX
+ && func <= PCI_FUNCMAX
+ && (unsigned)reg <= PCI_REGMAX
+ && bytes != 3
+ && (unsigned)bytes <= 4
+ && (reg & (bytes - 1)) == 0) {
+ switch (cfgmech) {
+ case CFGMECH_PCIE:
+ case CFGMECH_1:
+ outl(CONF1_ADDR_PORT, (1 << 31)
+ | (bus << 16) | (slot << 11)
+ | (func << 8) | (reg & ~0x03));
+ dataport = CONF1_DATA_PORT + (reg & 0x03);
+ break;
+ case CFGMECH_2:
+ outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
+ outb(CONF2_FORWARD_PORT, bus);
+ dataport = 0xc000 | (slot << 8) | reg;
+ break;
+ default:
+ break;
+ }
+ }
+ return (dataport);
+}
+
+/* disable configuration space accesses */
+static void
+pci_cfgdisable(void)
+{
+ switch (cfgmech) {
+ case CFGMECH_PCIE:
+ case CFGMECH_1:
+ /*
+ * Do nothing for the config mechanism 1 case.
+ * Writing a 0 to the address port can apparently
+ * confuse some bridges and cause spurious
+ * access failures.
+ */
+ break;
+ case CFGMECH_2:
+ outb(CONF2_ENABLE_PORT, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+int pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
+{
+ int data = -1;
+ int port;
+
+ mtx_enter(&pcicfg_mtx);
+ port = pci_cfgenable(bus, slot, func, reg, bytes);
+ if (port != 0) {
+ switch (bytes) {
+ case 1:
+ data = inb(port);
+ break;
+ case 2:
+ data = inw(port);
+ break;
+ case 4:
+ data = inl(port);
+ break;
+ default:
+ break;
+ }
+ pci_cfgdisable();
+ }
+ mtx_leave(&pcicfg_mtx);
+ return (data);
+}
+
+void pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
+{
+ int port;
+
+ mtx_enter(&pcicfg_mtx);
+ port = pci_cfgenable(bus, slot, func, reg, bytes);
+ if (port != 0) {
+ switch (bytes) {
+ case 1:
+ outb(port, data);
+ break;
+ case 2:
+ outw(port, data);
+ break;
+ case 4:
+ outl(port, data);
+ break;
+ default:
+ break;
+ }
+ pci_cfgdisable();
+ }
+ mtx_leave(&pcicfg_mtx);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/policy.c b/tboot/policy.c
new file mode 100644
index 0000000..3c4d7d1
--- /dev/null
+++ b/tboot/policy.c
@@ -0,0 +1,879 @@
+/*
+ * policy.c: support functions for tboot verification launch
+ *
+ * Copyright (c) 2006-2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <stdarg.h>
+#include <types.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <printk.h>
+#include <compiler.h>
+#include <string.h>
+#include <processor.h>
+#include <eficore.h>
+#include <eficonfig.h>
+#include <misc.h>
+#include <uuid.h>
+#include <hash.h>
+#include <tb_error.h>
+#define PRINT printk
+#include <mle.h>
+#include <atomic.h>
+#include <tboot.h>
+#include <integrity.h>
+#include <tpm.h>
+#include <tb_policy.h>
+#include <lcp3.h>
+#include <lcp3_hlp.h>
+#include <cmdline.h>
+#include <txt/config_regs.h>
+#include <txt/mtrrs.h>
+#include <txt/txt.h>
+#include <txt/heap.h>
+
+/*
+ * policy actions
+ */
+typedef enum {
+ TB_POLACT_CONTINUE,
+ TB_POLACT_UNMEASURED_LAUNCH,
+ TB_POLACT_HALT,
+} tb_policy_action_t;
+
+/* policy map types */
+typedef struct {
+ tb_error_t error;
+ tb_policy_action_t action;
+} tb_policy_map_entry_t;
+
+typedef struct {
+ uint8_t policy_type;
+ tb_policy_action_t default_action;
+ tb_policy_map_entry_t exception_action_table[TB_ERR_MAX];
+ /* have TB_ERR_NONE as last entry */
+} tb_policy_map_t;
+
+/* map */
+static const tb_policy_map_t g_policy_map[] = {
+ { TB_POLTYPE_CONT_NON_FATAL, TB_POLACT_CONTINUE,
+ {
+ {TB_ERR_FATAL, TB_POLACT_HALT},
+ {TB_ERR_TPM_NOT_READY, TB_POLACT_UNMEASURED_LAUNCH},
+ {TB_ERR_SMX_NOT_SUPPORTED, TB_POLACT_UNMEASURED_LAUNCH},
+ {TB_ERR_VMX_NOT_SUPPORTED, TB_POLACT_UNMEASURED_LAUNCH},
+ {TB_ERR_TXT_NOT_SUPPORTED, TB_POLACT_UNMEASURED_LAUNCH},
+ {TB_ERR_SINIT_NOT_PRESENT, TB_POLACT_UNMEASURED_LAUNCH},
+ {TB_ERR_ACMOD_VERIFY_FAILED, TB_POLACT_UNMEASURED_LAUNCH},
+ {TB_ERR_NONE, TB_POLACT_CONTINUE},
+ }
+ },
+
+ { TB_POLTYPE_CONT_VERIFY_FAIL, TB_POLACT_HALT,
+ {
+ {TB_ERR_MODULE_VERIFICATION_FAILED, TB_POLACT_CONTINUE},
+ {TB_ERR_NV_VERIFICATION_FAILED, TB_POLACT_CONTINUE},
+ {TB_ERR_POLICY_NOT_PRESENT, TB_POLACT_CONTINUE},
+ {TB_ERR_POLICY_INVALID, TB_POLACT_CONTINUE},
+ {TB_ERR_NONE, TB_POLACT_CONTINUE},
+ }
+ },
+
+ { TB_POLTYPE_HALT, TB_POLACT_HALT,
+ {
+ {TB_ERR_NONE, TB_POLACT_CONTINUE},
+ }
+ },
+};
+
+/* buffer for policy as read from TPM NV */
+#define MAX_POLICY_SIZE \
+ (( MAX_TB_POLICY_SIZE > sizeof(lcp_policy_t) ) \
+ ? MAX_TB_POLICY_SIZE \
+ : sizeof(lcp_policy_t) )
+static uint8_t _policy_index_buf[MAX_POLICY_SIZE];
+
+/* default policy */
+static const tb_policy_t _def_policy = {
+ version : 2,
+ policy_type : TB_POLTYPE_CONT_NON_FATAL,
+ hash_alg : TB_HALG_SHA1,
+ policy_control : TB_POLCTL_EXTEND_PCR17,
+ num_entries : 3,
+ entries : {
+ { /* mod 0 is extended to PCR 18 by default, so don't re-extend it */
+ mod_num : 0,
+ pcr : TB_POL_PCR_NONE,
+ hash_type : TB_HTYPE_ANY,
+ num_hashes : 0
+ },
+ { /* all other modules are extended to PCR 19 */
+ mod_num : TB_POL_MOD_NUM_ANY,
+ pcr : 19,
+ hash_type : TB_HTYPE_ANY,
+ num_hashes : 0
+ },
+ { /* NV index for geo-tagging will be extended to PCR 22 */
+ mod_num : TB_POL_MOD_NUM_NV_RAW,
+ pcr : 22,
+ hash_type : TB_HTYPE_ANY,
+ nv_index : 0x40000010,
+ num_hashes : 0
+ }
+ }
+};
+
+/* default policy for Details/Authorities pcr mapping */
+static const tb_policy_t _def_policy_da = {
+ version : 2,
+ policy_type : TB_POLTYPE_CONT_NON_FATAL,
+ hash_alg : TB_HALG_SHA1,
+ policy_control : TB_POLCTL_EXTEND_PCR17,
+ num_entries : 3,
+ entries : {
+ { /* mod 0 is extended to PCR 17 by default, so don't re-extend it */
+ mod_num : 0,
+ pcr : TB_POL_PCR_NONE,
+ hash_type : TB_HTYPE_ANY,
+ num_hashes : 0
+ },
+ { /* all other modules are extended to PCR 17 */
+ mod_num : TB_POL_MOD_NUM_ANY,
+ pcr : 17,
+ hash_type : TB_HTYPE_ANY,
+ num_hashes : 0
+ },
+ { /* NV index for geo-tagging will be extended to PCR 22 */
+ mod_num : TB_POL_MOD_NUM_NV_RAW,
+ pcr : 22,
+ hash_type : TB_HTYPE_ANY,
+ nv_index : 0x40000010,
+ num_hashes : 0
+ }
+ }
+};
+
+/* current policy */
+static const tb_policy_t* g_policy = &_def_policy;
+
+/*
+ * read_policy_from_tpm
+ *
+ * read policy from TPM NV into buffer
+ *
+ * policy_index_size is in/out
+ */
+static bool read_policy_from_tpm(uint32_t index, void* policy_index, size_t *policy_index_size)
+{
+#define NV_READ_SEG_SIZE 256
+ unsigned int offset = 0;
+ unsigned int data_size = 0;
+ uint32_t ret, index_size;
+
+ if ( policy_index_size == NULL ) {
+ printk(TBOOT_ERR"size is NULL\n");
+ return false;
+ }
+
+ ret = g_tpm->get_nvindex_size(g_tpm, g_tpm->cur_loc, index, &index_size);
+ if ( !ret )
+ return false;
+
+ if ( index_size > *policy_index_size ) {
+ printk(TBOOT_WARN"policy in TPM NV %x was too big for buffer\n", index);
+ index_size = *policy_index_size;
+ }
+
+
+ do {
+ /* get data_size */
+ if ( (index_size - offset) > NV_READ_SEG_SIZE )
+ data_size = NV_READ_SEG_SIZE;
+ else
+ data_size = (uint32_t)(index_size - offset);
+
+ /* read! */
+ ret = g_tpm->nv_read(g_tpm, g_tpm->cur_loc, index, offset,
+ (uint8_t *)policy_index + offset, &data_size);
+ if ( !ret || data_size == 0 )
+ break;
+
+ /* adjust offset */
+ offset += data_size;
+ } while ( offset < index_size );
+
+ if ( offset == 0 && !ret ) {
+ printk(TBOOT_ERR"Error: read TPM error: 0x%x from index %x.\n", ret, index);
+ return false;
+ }
+
+ *policy_index_size = offset;
+
+ return true;
+}
+
+/*
+ * unwrap_lcp_policy
+ *
+ * unwrap custom element in lcp policy into tb policy
+ * assume sinit has already verified lcp policy and lcp policy data.
+ */
+static bool unwrap_lcp_policy(void)
+{
+ void* lcp_base;
+ uint32_t lcp_size;
+ const efi_file_t *lcp;
+
+ // scaffolding
+ printk(TBOOT_INFO"in unwrap_lcp_policy\n");
+
+ if ( txt_is_launched() ) {
+ txt_heap_t *txt_heap = get_txt_heap();
+ os_sinit_data_t *os_sinit_data = get_os_sinit_data_start(txt_heap);
+
+ lcp_base = (void *)(unsigned long long)os_sinit_data->lcp_po_base;
+ lcp_size = (uint32_t)os_sinit_data->lcp_po_size;
+ }
+ else {
+ lcp = efi_get_lcp();
+ if ( lcp == NULL )
+ return false;
+ lcp_base = lcp->u.buffer;
+ lcp_size = lcp->size;
+ }
+
+ /* if lcp policy data version is 2+ */
+ if ( memcmp((void *)lcp->u.buffer, LCP_POLICY_DATA_FILE_SIGNATURE,
+ LCP_FILE_SIG_LENGTH) == 0 ) {
+ lcp_policy_data_t *poldata = (lcp_policy_data_t *)lcp_base;
+ lcp_policy_list_t *pollist = &poldata->policy_lists[0];
+
+ for ( int i = 0; i < poldata->num_lists; i++ ) {
+ lcp_policy_element_t *elt = pollist->policy_elements;
+ uint32_t elts_size = 0;
+
+ while ( elt ) {
+ /* check element type */
+ if ( elt->type == LCP_POLELT_TYPE_CUSTOM ||
+ elt->type == LCP_POLELT_TYPE_CUSTOM2 ) {
+ lcp_custom_element_t *custom =
+ (lcp_custom_element_t *)&elt->data;
+
+ /* check uuid in custom element */
+ if ( are_uuids_equal(&custom->uuid,
+ &((uuid_t)LCP_CUSTOM_ELEMENT_TBOOT_UUID)) ) {
+ memcpy(_policy_index_buf, &custom->data,
+ elt->size - sizeof(*elt) - sizeof(uuid_t));
+ return true; /* find tb policy */
+ }
+ }
+
+ elts_size += elt->size;
+ if ( elts_size >= pollist->policy_elements_size )
+ break;
+
+ elt = (void *)elt + elt->size;
+ }
+ if ( pollist->version == LCP_TPM12_POLICY_LIST_VERSION )
+ pollist = (void *)pollist + get_tpm12_policy_list_size(pollist);
+ else if ( pollist->version == LCP_TPM20_POLICY_LIST_VERSION )
+ pollist = (void *)pollist + get_tpm20_policy_list_size(
+ (lcp_policy_list_t2 *)pollist);
+ }
+ }
+
+ return false;
+}
+
+/*
+ * set_policy
+ *
+ * load policy from TPM NV and validate it, else use default
+ *
+ */
+tb_error_t set_policy(void)
+{
+ /* try to read tboot policy from TB_POLICY_INDEX in TPM NV */
+ size_t policy_index_size = sizeof(_policy_index_buf);
+ printk(TBOOT_INFO"reading Verified Launch Policy from TPM NV...\n");
+ if ( read_policy_from_tpm(g_tpm->tb_policy_index,
+ _policy_index_buf, &policy_index_size) ) {
+ printk(TBOOT_DETA"\t:%lu bytes read\n", policy_index_size);
+ if ( verify_policy((tb_policy_t *)_policy_index_buf,
+ policy_index_size, true) ) {
+ goto policy_found;
+ }
+ }
+ printk(TBOOT_WARN"\t:reading failed\n");
+
+ /* tboot policy not found in TB_POLICY_INDEX, so see if it is wrapped
+ * in a custom element in the PO policy; if so, SINIT will have verified
+ * the policy and policy data for us; we just need to ensure the policy
+ * type is LCP_POLTYPE_LIST (since we could have been give a policy data
+ * file even though the policy was not a LIST */
+ printk(TBOOT_INFO"reading Launch Control Policy from TPM NV...\n");
+ if ( read_policy_from_tpm(g_tpm->lcp_own_index,
+ _policy_index_buf, &policy_index_size) ) {
+ printk(TBOOT_DETA"\t:%lu bytes read\n", policy_index_size);
+ /* assume lcp policy has been verified by sinit already */
+ lcp_policy_t *pol = (lcp_policy_t *)_policy_index_buf;
+ if ( pol->version == LCP_DEFAULT_POLICY_VERSION_2 &&
+ pol->policy_type == LCP_POLTYPE_LIST && unwrap_lcp_policy() ) {
+ if ( verify_policy((tb_policy_t *)_policy_index_buf,
+ calc_policy_size((tb_policy_t *)_policy_index_buf),
+ true) )
+ goto policy_found;
+ }
+ lcp_policy_t2 *pol2 = (lcp_policy_t2 *)_policy_index_buf;
+ if ( pol2->version == LCP_DEFAULT_POLICY_VERSION &&
+ pol2->policy_type == LCP_POLTYPE_LIST && unwrap_lcp_policy() ) {
+ if ( verify_policy((tb_policy_t *)_policy_index_buf,
+ calc_policy_size((tb_policy_t *)_policy_index_buf),
+ true) )
+ goto policy_found;
+ }
+ }
+ printk(TBOOT_WARN"\t:reading failed\n");
+
+ /* either no policy in TPM NV or policy is invalid, so use default */
+ printk(TBOOT_WARN"failed to read policy from TPM NV, using default\n");
+ g_policy = g_using_da ? &_def_policy_da : &_def_policy;
+ policy_index_size = calc_policy_size(g_policy);
+
+ /* sanity check; but if it fails something is really wrong */
+ if ( !verify_policy(g_policy, policy_index_size, true) )
+ return TB_ERR_FATAL;
+ else
+ return TB_ERR_POLICY_NOT_PRESENT;
+
+policy_found:
+ /* compatible with tb_policy tools for TPM 1.2 */
+ {
+ tb_policy_t *tmp_policy = (tb_policy_t *)_policy_index_buf;
+ if (tmp_policy->hash_alg == 0)
+ tmp_policy->hash_alg = TB_HALG_SHA1;
+ }
+ g_policy = (tb_policy_t *)_policy_index_buf;
+ return TB_ERR_NONE;
+}
+
+/* hash current policy */
+bool hash_policy(tb_hash_t *hash, uint16_t hash_alg)
+{
+ if ( hash == NULL ) {
+ printk(TBOOT_ERR"Error: input parameter is wrong.\n");
+ return false;
+ }
+
+ return hash_buffer((unsigned char *)g_policy, calc_policy_size(g_policy),
+ hash, hash_alg);
+}
+
+/* generate hash by hashing cmdline and module image */
+static bool hash_module(hash_list_t *hl,
+ const char* cmdline, void *base,
+ size_t size)
+{
+ if ( hl == NULL ) {
+ printk(TBOOT_ERR"Error: input parameter is wrong.\n");
+ return false;
+ }
+
+ /* final hash is SHA-1( SHA-1(cmdline) | SHA-1(image) ) */
+ /* where cmdline is first stripped of leading spaces, file name, then */
+ /* any spaces until the next non-space char */
+ /* (e.g. " /foo/bar baz" -> "baz"; "/foo/bar" -> "") */
+
+ /* hash command line */
+ if ( cmdline == NULL )
+ cmdline = "";
+ // else
+ // cmdline = skip_filename(cmdline);
+
+ switch (g_tpm->extpol) {
+ case TB_EXTPOL_FIXED:
+ hl->count = 1;
+ hl->entries[0].alg = g_tpm->cur_alg;
+
+ if ( !hash_buffer((const unsigned char *)cmdline, strlen(cmdline),
+ &hl->entries[0].hash, g_tpm->cur_alg) )
+ return false;
+ /* hash image and extend into cmdline hash */
+ tb_hash_t img_hash;
+ if ( !hash_buffer(base, size, &img_hash, g_tpm->cur_alg) )
+ return false;
+ if ( !extend_hash(&hl->entries[0].hash, &img_hash, g_tpm->cur_alg) )
+ return false;
+
+ break;
+
+ case TB_EXTPOL_AGILE:
+ {
+ hash_list_t img_hl, final_hl;
+ if ( !g_tpm->hash(g_tpm, 2, (const unsigned char *)cmdline,
+ strlen(cmdline), hl) ) {
+ if ( !g_tpm->hash(g_tpm, 2, base, size, hl) )
+ return false;
+ return true;
+ }
+
+ uint8_t buf[128];
+
+ if ( !g_tpm->hash(g_tpm, 2, base, size, &img_hl) )
+ return false;
+ for (unsigned int i=0; i<hl->count; i++) {
+ for (unsigned int j=0; j<img_hl.count; j++) {
+ if (hl->entries[i].alg == img_hl.entries[j].alg) {
+ copy_hash((tb_hash_t *)buf, &hl->entries[i].hash,
+ hl->entries[i].alg);
+ copy_hash((tb_hash_t *)buf + get_hash_size(hl->entries[i].alg),
+ &img_hl.entries[j].hash, hl->entries[i].alg);
+ if ( !g_tpm->hash(g_tpm, 2, buf,
+ 2*get_hash_size(hl->entries[i].alg), &final_hl) )
+ return false;
+
+ for (unsigned int k=0; k<final_hl.count; k++) {
+ if (hl->entries[i].alg == final_hl.entries[k].alg) {
+ copy_hash(&hl->entries[i].hash,
+ &final_hl.entries[k].hash,
+ hl->entries[i].alg);
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+
+ case TB_EXTPOL_EMBEDDED:
+ {
+ tb_hash_t img_hash;
+ hl->count = g_tpm->alg_count;
+ for (unsigned int i=0; i<hl->count; i++) {
+ hl->entries[i].alg = g_tpm->algs[i];
+ if ( !hash_buffer((const unsigned char *)cmdline, strlen(cmdline),
+ &hl->entries[i].hash, g_tpm->algs[i]) )
+ return false;
+
+ if ( !hash_buffer(base, size, &img_hash, g_tpm->algs[i]) )
+ return false;
+ if ( !extend_hash(&hl->entries[i].hash, &img_hash, g_tpm->algs[i]) )
+ return false;
+ }
+
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+static bool is_hash_in_policy_entry(const tb_policy_entry_t *pol_entry,
+ tb_hash_t *hash, uint16_t hash_alg)
+{
+ /* assumes policy entry has been validated */
+
+ if ( pol_entry == NULL || hash == NULL) {
+ printk(TBOOT_ERR"Error: input parameter is wrong.\n");
+ return false;
+ }
+
+ if ( pol_entry->hash_type == TB_HTYPE_ANY )
+ return true;
+ else if ( pol_entry->hash_type == TB_HTYPE_IMAGE ) {
+ for ( int i = 0; i < pol_entry->num_hashes; i++ ) {
+ if ( are_hashes_equal(get_policy_entry_hash(pol_entry, hash_alg,
+ i), hash, hash_alg) )
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*
+ * map policy type + error -> action
+ */
+static tb_policy_action_t evaluate_error(tb_error_t error)
+{
+ tb_policy_action_t action = TB_POLACT_HALT;
+
+ if ( error == TB_ERR_NONE )
+ return TB_POLACT_CONTINUE;
+
+ for ( unsigned int i = 0; i < ARRAY_SIZE(g_policy_map); i++ ) {
+ if ( g_policy_map[i].policy_type == g_policy->policy_type ) {
+ action = g_policy_map[i].default_action;
+ for ( unsigned int j = 0;
+ j < ARRAY_SIZE(g_policy_map[i].exception_action_table);
+ j++ ) {
+ if ( g_policy_map[i].exception_action_table[j].error ==
+ error )
+ action = g_policy_map[i].exception_action_table[j].action;
+ if ( g_policy_map[i].exception_action_table[j].error ==
+ TB_ERR_NONE )
+ break;
+ }
+ }
+ }
+
+ return action;
+}
+
+/*
+ * apply policy according to error happened.
+ */
+void apply_policy(tb_error_t error)
+{
+ tb_policy_action_t action;
+
+ /* save the error to TPM NV */
+ write_tb_error_code(error);
+
+ if ( error != TB_ERR_NONE )
+ print_tb_error_msg(error);
+
+ action = evaluate_error(error);
+ switch ( action ) {
+ case TB_POLACT_CONTINUE:
+ return;
+ case TB_POLACT_UNMEASURED_LAUNCH:
+ /* restore mtrr state saved before */
+ restore_mtrrs(NULL);
+ if ( s3_flag )
+ s3_launch();
+ else
+ efi_launch_kernel();
+ break; /* if launch xen fails, do halt at the end */
+ case TB_POLACT_HALT:
+ break; /* do halt at the end */
+ default:
+ printk(TBOOT_ERR"Error: invalid policy action (%d)\n", action);
+ /* do halt at the end */
+ }
+
+ _tboot_shared.shutdown_type = TB_SHUTDOWN_HALT;
+ shutdown();
+}
+
+#define VL_ENTRIES(i) g_pre_k_s3_state.vl_entries[i]
+#define NUM_VL_ENTRIES g_pre_k_s3_state.num_vl_entries
+
+/*
+ * verify modules against Verified Launch policy and save hash
+ * if pol_entry is NULL, assume it is for module 0, which gets extended
+ * to PCR 18
+ */
+static tb_error_t verify_module(void *base, size_t size,
+ tb_policy_entry_t *pol_entry,
+ uint16_t hash_alg)
+{
+ /* assumes module is valid */
+
+ char *cmdline = NULL; /* TODO get from configs get_module_cmd(g_ldr_ctx, module);*/
+
+ if ( pol_entry != NULL ) {
+ /* chunk the command line into 80 byte chunks */
+#define CHUNK_SIZE 80
+ int cmdlen = strlen(cmdline);
+ char *cptr = cmdline;
+ char cmdchunk[CHUNK_SIZE+1];
+ printk(TBOOT_INFO"verifying module \"");
+ while (cmdlen > 0) {
+ strncpy(cmdchunk, cptr, CHUNK_SIZE);
+ cmdchunk[CHUNK_SIZE] = 0;
+ printk(TBOOT_INFO"\n%s", cmdchunk);
+ cmdlen -= CHUNK_SIZE;
+ cptr += CHUNK_SIZE;
+ }
+ printk(TBOOT_INFO"\"...\n");
+ }
+
+ hash_list_t hl;
+ if ( !hash_module(&hl, cmdline, base, size) ) {
+ printk(TBOOT_ERR"\t hash cannot be generated.\n");
+ return TB_ERR_MODULE_VERIFICATION_FAILED;
+ }
+
+ /* add new hash to list (unless it doesn't get put in a PCR)
+ we'll just drop it if the list is full, but that will mean S3 resume
+ PCRs won't match pre-S3
+ NULL pol_entry means this is module 0 which is extended to PCR 18 */
+ if ( NUM_VL_ENTRIES >= MAX_VL_HASHES )
+ printk(TBOOT_WARN"\t too many hashes to save\n");
+ else if ( pol_entry == NULL || pol_entry->pcr != TB_POL_PCR_NONE ) {
+ uint8_t pcr = (pol_entry == NULL ) ?
+ (g_using_da ? 17 : 18) : pol_entry->pcr;
+ VL_ENTRIES(NUM_VL_ENTRIES).pcr = pcr;
+ VL_ENTRIES(NUM_VL_ENTRIES++).hl = hl;
+ }
+
+ if ( g_tpm->extpol != TB_EXTPOL_FIXED )
+ return TB_ERR_NONE;
+
+ if ( pol_entry != NULL &&
+ !is_hash_in_policy_entry(pol_entry, &hl.entries[0].hash, hash_alg) ) {
+ printk(TBOOT_ERR"\t verification failed\n");
+ return TB_ERR_MODULE_VERIFICATION_FAILED;
+ }
+
+ if ( pol_entry != NULL ) {
+ printk(TBOOT_DETA"\t OK : "); print_hash(&hl.entries[0].hash, hash_alg);
+ }
+
+ return TB_ERR_NONE;
+}
+
+static void verify_g_policy(void)
+{
+ /* assumes mbi is valid */
+ printk(TBOOT_INFO"verifying policy \n");
+
+ /* add entry for policy control field and (optionally) policy */
+ /* hash will be <policy control field (4bytes)> | <hash policy> */
+ /* where <hash policy> will be 0s if TB_POLCTL_EXTEND_PCR17 is clear */
+ static uint8_t buf[sizeof(tb_hash_t) + sizeof(g_policy->policy_control)];
+ memset(buf, 0, sizeof(buf));
+ memcpy(buf, &g_policy->policy_control, sizeof(g_policy->policy_control));
+ if ( g_policy->policy_control & TB_POLCTL_EXTEND_PCR17 ) {
+ if ( !hash_policy((tb_hash_t *)&buf[sizeof(g_policy->policy_control)],
+ g_tpm->cur_alg) ) {
+ printk(TBOOT_ERR"policy hash failed\n");
+ apply_policy(TB_ERR_MODULE_VERIFICATION_FAILED);
+ }
+ }
+
+ u32 size = get_hash_size(g_tpm->cur_alg) + sizeof(g_policy->policy_control);
+ switch (g_tpm->extpol) {
+ case TB_EXTPOL_FIXED:
+ VL_ENTRIES(NUM_VL_ENTRIES).hl.count = 1;
+ VL_ENTRIES(NUM_VL_ENTRIES).hl.entries[0].alg = g_tpm->cur_alg;
+ if ( !hash_buffer(buf, size,
+ &VL_ENTRIES(NUM_VL_ENTRIES).hl.entries[0].hash, g_tpm->cur_alg) )
+ apply_policy(TB_ERR_MODULE_VERIFICATION_FAILED);
+
+ break;
+
+ case TB_EXTPOL_AGILE:
+ if ( !g_tpm->hash(g_tpm, 2, buf, size, &VL_ENTRIES(NUM_VL_ENTRIES).hl) )
+ apply_policy(TB_ERR_MODULE_VERIFICATION_FAILED);
+ break;
+
+ case TB_EXTPOL_EMBEDDED:
+ {
+ VL_ENTRIES(NUM_VL_ENTRIES).hl.count = g_tpm->alg_count;
+ for (int i=0; i<g_tpm->alg_count; i++) {
+ VL_ENTRIES(NUM_VL_ENTRIES).hl.entries[i].alg = g_tpm->algs[i];
+ if ( !hash_buffer(buf, size, &VL_ENTRIES(NUM_VL_ENTRIES).hl.entries[i].hash,
+ g_tpm->algs[i]) )
+ return;
+ }
+
+ break;
+ }
+
+ default:
+ apply_policy(TB_ERR_MODULE_VERIFICATION_FAILED);
+ break;
+ }
+
+ VL_ENTRIES(NUM_VL_ENTRIES++).pcr = 17;
+ if ( g_using_da ) {
+ /* copying hash of policy_control into PCR 18 */
+ if ( NUM_VL_ENTRIES >= MAX_VL_HASHES )
+ printk(TBOOT_ERR"\t too many hashes to save for DA\n");
+ else {
+ VL_ENTRIES(NUM_VL_ENTRIES).hl = VL_ENTRIES(NUM_VL_ENTRIES-1).hl;
+ VL_ENTRIES(NUM_VL_ENTRIES++).pcr = 18;
+ }
+ }
+}
+
+void verify_all_modules(void)
+{
+ /* assumes mbi is valid */
+ verify_g_policy();
+
+ /* TODO this will be done after ebs with xen passing back the module
+ * information - the modules it loaded. */
+
+ printk(TBOOT_INFO"all modules are verified\n");
+}
+
+static int find_first_nvpolicy_entry(const tb_policy_t *policy)
+{
+ if ( policy == NULL ) {
+ PRINT(TBOOT_ERR"Error: policy pointer is NULL\n");
+ return -1;
+ }
+
+ for ( int i = 0; i < policy->num_entries; i++ ) {
+ tb_policy_entry_t *pol_entry = get_policy_entry(policy, i);
+ if ( pol_entry == NULL )
+ return -1;
+
+ if ( pol_entry->mod_num == TB_POL_MOD_NUM_NV ||
+ pol_entry->mod_num == TB_POL_MOD_NUM_NV_RAW )
+ return i;
+ }
+
+ return -1;
+}
+
+static int find_next_nvpolicy_entry(const tb_policy_t *policy, int i)
+{
+ if ( policy == NULL || i < 0 || i >= policy->num_entries )
+ return -1;
+
+ for ( i++; i < policy->num_entries; i++ ) {
+ tb_policy_entry_t *pol_entry = get_policy_entry(policy, i);
+ if ( pol_entry == NULL )
+ return -1;
+
+ if ( pol_entry->mod_num == TB_POL_MOD_NUM_NV ||
+ pol_entry->mod_num == TB_POL_MOD_NUM_NV_RAW )
+ return i;
+ }
+
+ return -1;
+}
+
+static uint8_t nv_buf[4096];
+
+static tb_error_t verify_nvindex(tb_policy_entry_t *pol_entry,
+ uint16_t hash_alg)
+{
+ size_t nv_size = sizeof(nv_buf);
+ tb_hash_t digest;
+ uint32_t attribute;
+
+ if ( pol_entry == NULL )
+ return TB_ERR_NV_VERIFICATION_FAILED;
+
+ printk(TBOOT_INFO"verifying nv index 0x%08X\n", pol_entry->nv_index);
+
+ /* check nv attribute */
+ if ( !g_tpm->get_nvindex_permission(g_tpm, 0, pol_entry->nv_index,
+ &attribute) ) {
+ printk(TBOOT_ERR"\t :reading nv index permission failed\n");
+ return TB_ERR_NV_VERIFICATION_FAILED;
+ }
+ if ( !(attribute & (TPM_NV_PER_OWNERWRITE | TPM_NV_PER_AUTHWRITE)) ) {
+ printk(TBOOT_ERR"\t :nv index should be OWNERWRITE or AUTHWRITE, bad permission!\n");
+ return TB_ERR_NV_VERIFICATION_FAILED;
+ }
+
+ /* get nv content */
+ memset(nv_buf, 0, sizeof(nv_buf));
+ if ( !read_policy_from_tpm(pol_entry->nv_index,
+ nv_buf, &nv_size) ) {
+ printk(TBOOT_ERR"\t :reading nv index 0x%08X failed\n",
+ pol_entry->nv_index);
+ return TB_ERR_NV_VERIFICATION_FAILED;
+ }
+
+ /* hash the buffer if needed */
+ switch ( pol_entry->mod_num ) {
+ case TB_POL_MOD_NUM_NV:
+ if ( !hash_buffer((const uint8_t*)nv_buf, nv_size, &digest,
+ TB_HALG_SHA1) ) {
+ printk(TBOOT_ERR"\t :nv content hash failed\n");
+ return TB_ERR_NV_VERIFICATION_FAILED;
+ }
+ break;
+ case TB_POL_MOD_NUM_NV_RAW:
+ if ( nv_size != sizeof(digest.sha1) ) {
+ printk(TBOOT_ERR"\t :raw nv with wrong size (%d), should be %d\n",
+ (int)nv_size, sizeof(digest.sha1));
+ return TB_ERR_NV_VERIFICATION_FAILED;
+ }
+ memcpy(digest.sha1, nv_buf, nv_size);
+ break;
+ default:
+ printk(TBOOT_ERR"\t :bad mod number for NV measuring in policy entry: %d\n",
+ pol_entry->mod_num);
+ return TB_ERR_NV_VERIFICATION_FAILED;
+ }
+
+ /* add new hash to list (unless it doesn't get put in a PCR)
+ we'll just drop it if the list is full, but that will mean S3 resume
+ PCRs won't match pre-S3 */
+ if ( NUM_VL_ENTRIES >= MAX_VL_HASHES )
+ printk(TBOOT_WARN"\t too many hashes to save\n");
+ else if ( pol_entry->pcr != TB_POL_PCR_NONE ) {
+ VL_ENTRIES(NUM_VL_ENTRIES).pcr = pol_entry->pcr;
+ VL_ENTRIES(NUM_VL_ENTRIES).hl.count = 1;
+ VL_ENTRIES(NUM_VL_ENTRIES).hl.entries[0].alg = TB_HALG_SHA1;
+ memcpy(VL_ENTRIES(NUM_VL_ENTRIES++).hl.entries[0].hash.sha1,
+ digest.sha1, SHA1_LENGTH);
+ }
+
+ /* verify nv content */
+ if ( !is_hash_in_policy_entry(pol_entry, &digest, hash_alg) ) {
+ printk(TBOOT_ERR"\t verification failed\n");
+ return TB_ERR_NV_VERIFICATION_FAILED;
+ }
+
+ printk(TBOOT_DETA"\t OK : "); print_hash(&digest, hash_alg);
+ return TB_ERR_NONE;
+}
+
+void verify_all_nvindices(void)
+{
+ /* go through nv policies in tb policy */
+ for ( int i = find_first_nvpolicy_entry(g_policy);
+ i >= 0;
+ i = find_next_nvpolicy_entry(g_policy, i) ) {
+ tb_policy_entry_t *pol_entry = get_policy_entry(g_policy, i);
+ apply_policy(verify_nvindex(pol_entry, g_policy->hash_alg));
+ }
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/printk.c b/tboot/printk.c
new file mode 100644
index 0000000..0bc4531
--- /dev/null
+++ b/tboot/printk.c
@@ -0,0 +1,195 @@
+/*
+ * printk.c: printk() output fn and helpers
+ *
+ * Copyright (c) 2006-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <compiler.h>
+#include <string.h>
+#include <mutex.h>
+#include <misc.h>
+#include <printk.h>
+#include <eficore.h>
+#include <cmdline.h>
+#include <tb_error.h>
+#include <tboot.h>
+
+uint8_t g_log_level = TBOOT_LOG_LEVEL_NONE;
+uint8_t g_log_targets = TBOOT_LOG_TARGET_NONE;
+
+static struct mutex print_lock;
+
+/*
+ * memory logging
+ */
+
+/* memory-based serial log (ensure in .data section so that not cleared) */
+__data tboot_log_t g_log = {0};
+
+static void memlog_init(void)
+{
+ if ( !g_log.is_init ) {
+ g_log.uuid = (uuid_t)TBOOT_LOG_UUID;
+ g_log.curr_pos = 0;
+ g_log.max_size = TBOOT_MEM_LOG_SIZE;
+ g_log.is_init = true;
+ }
+
+ /* initialize these post-launch as well, since bad/malicious values */
+ /* could compromise environment */
+ g_log.uuid = (uuid_t)TBOOT_LOG_UUID;
+ g_log.max_size = TBOOT_MEM_LOG_SIZE;
+
+ /* if we're calling this post-launch, verify that curr_pos is valid */
+ if ( g_log.curr_pos > g_log.max_size )
+ g_log.curr_pos = 0;
+}
+
+static void memlog_write(const char *str, unsigned int count)
+{
+ if ( count > g_log.max_size )
+ return;
+
+ /* wrap to beginning if too big to fit */
+ if ( g_log.curr_pos + count >= g_log.max_size )
+ g_log.curr_pos = 0;
+
+ memcpy(&g_log.buf[g_log.curr_pos], str, count);
+ g_log.curr_pos += count;
+
+ /* if the string wasn't NULL-terminated, then NULL-terminate the log */
+ if ( str[count-1] != '\0' )
+ g_log.buf[g_log.curr_pos] = '\0';
+ else {
+ /* so that curr_pos will point to the NULL and be overwritten */
+ /* on next copy */
+ g_log.curr_pos--;
+ }
+}
+
+void printk_init(printk_init_t init_type)
+{
+ if (init_type == INIT_EARLY_EFI || init_type == INIT_POST_LAUNCH)
+ mtx_init(&print_lock);
+
+ if (init_type == INIT_EARLY_EFI) {
+ /* Default to EFI logging at early startup */
+#ifdef EFI_EARLY_PRINTK
+ g_log_targets = TBOOT_LOG_TARGET_EFI;
+ g_log_level = TBOOT_LOG_LEVEL_ALL;
+#endif
+ return;
+ }
+
+ /* parse loglvl from string to int */
+ get_tboot_loglvl();
+
+ /* parse logging targets */
+ get_tboot_log_targets();
+
+ if (init_type == INIT_POST_EBS || init_type == INIT_POST_LAUNCH) {
+ /* now we can use VGA logging, EFI console is gone */
+ if ( g_log_targets & TBOOT_LOG_TARGET_VGA ) {
+ vga_init();
+ get_tboot_vga_delay(); /* parse vga delay time */
+ }
+
+ /* cannot use EFI logging any longer also */
+ g_log_targets &= ~TBOOT_LOG_TARGET_EFI;
+ }
+
+ if (init_type == INIT_PRE_LAUNCH || init_type == INIT_POST_LAUNCH) {
+ /* parse serial settings */
+ if ( !get_tboot_serial() )
+ g_log_targets &= ~TBOOT_LOG_TARGET_SERIAL;
+
+ if ( g_log_targets & TBOOT_LOG_TARGET_SERIAL )
+ serial_init();
+
+ if ( g_log_targets & TBOOT_LOG_TARGET_MEMORY )
+ memlog_init();
+ }
+}
+
+#define WRITE_LOGS(s, n) \
+ do { \
+ if (g_log_targets & TBOOT_LOG_TARGET_EFI) efi_write(s, n); \
+ if (g_log_targets & TBOOT_LOG_TARGET_MEMORY) memlog_write(s, n); \
+ if (g_log_targets & TBOOT_LOG_TARGET_SERIAL) serial_write(s, n); \
+ if (g_log_targets & TBOOT_LOG_TARGET_VGA) vga_write(s, n); \
+ } while (0)
+
+void printk(const char *fmt, ...)
+{
+ char buf[TBOOT_LOGBUF_SIZE];
+ char *pbuf = buf;
+ int n;
+ va_list ap;
+ uint8_t log_level;
+ static bool last_line_cr = true;
+
+ memset(buf, '\0', sizeof(buf));
+ va_start(ap, fmt);
+ n = vscnprintf(buf, sizeof(buf), fmt, ap);
+
+ log_level = get_loglvl_prefix(&pbuf, &n);
+
+ if ( !(g_log_level & log_level) )
+ goto exit;
+
+ mtx_enter(&print_lock);
+ /* prepend "TBOOT: " if the last line that was printed ended with a '\n' */
+ if ( last_line_cr )
+ WRITE_LOGS("TBOOT: ", 8);
+
+ last_line_cr = (n > 0 && (*(pbuf+n-1) == '\n'));
+ WRITE_LOGS(pbuf, n);
+ mtx_leave(&print_lock);
+
+exit:
+ va_end(ap);
+}
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/rijndael.c b/tboot/rijndael.c
new file mode 100644
index 0000000..0b49a8f
--- /dev/null
+++ b/tboot/rijndael.c
@@ -0,0 +1,1270 @@
+/* $OpenBSD: rijndael.c,v 1.19 2008/06/09 07:49:45 djm Exp $ */
+
+/**
+ * rijndael-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#include <sys/param.h>
+//#include <sys/systm.h>
+
+//#include <crypto/rijndael.h>
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <rijndael.h>
+
+#undef FULL_UNROLL
+
+/*
+Te0[x] = S [x].[02, 01, 01, 03];
+Te1[x] = S [x].[03, 02, 01, 01];
+Te2[x] = S [x].[01, 03, 02, 01];
+Te3[x] = S [x].[01, 01, 03, 02];
+Te4[x] = S [x].[01, 01, 01, 01];
+
+Td0[x] = Si[x].[0e, 09, 0d, 0b];
+Td1[x] = Si[x].[0b, 0e, 09, 0d];
+Td2[x] = Si[x].[0d, 0b, 0e, 09];
+Td3[x] = Si[x].[09, 0d, 0b, 0e];
+Td4[x] = Si[x].[01, 01, 01, 01];
+*/
+
+static const u32 Te0[256] = {
+ 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+ 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+ 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+ 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+ 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+ 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+ 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+ 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+ 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+ 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+ 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+ 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+ 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+ 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+ 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+ 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+ 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+ 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+ 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+ 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+ 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+ 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+ 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+ 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+ 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+ 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+ 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+ 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+ 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+ 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+ 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+ 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+ 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+ 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+ 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+ 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+ 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+ 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+ 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+ 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+ 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+ 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+ 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+ 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+ 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+ 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+ 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+ 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+ 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+ 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+ 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+ 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+ 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+ 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+ 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+ 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+ 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+ 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+ 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+ 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+ 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+ 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+ 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+ 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+static const u32 Te1[256] = {
+ 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+ 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+ 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+ 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+ 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+ 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+ 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+ 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+ 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+ 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+ 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+ 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+ 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+ 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+ 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+ 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+ 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+ 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+ 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+ 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+ 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+ 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+ 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+ 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+ 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+ 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+ 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+ 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+ 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+ 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+ 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+ 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+ 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+ 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+ 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+ 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+ 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+ 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+ 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+ 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+ 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+ 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+ 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+ 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+ 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+ 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+ 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+ 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+ 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+ 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+ 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+ 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+ 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+ 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+ 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+ 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+ 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+ 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+ 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+ 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+ 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+ 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+ 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+ 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
+};
+static const u32 Te2[256] = {
+ 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+ 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+ 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+ 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+ 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+ 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+ 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+ 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+ 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+ 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+ 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+ 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+ 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+ 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+ 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+ 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+ 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+ 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+ 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+ 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+ 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+ 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+ 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+ 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+ 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+ 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+ 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+ 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+ 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+ 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+ 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+ 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+ 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+ 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+ 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+ 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+ 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+ 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+ 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+ 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+ 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+ 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+ 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+ 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+ 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+ 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+ 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+ 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+ 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+ 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+ 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+ 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+ 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+ 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+ 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+ 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+ 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+ 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+ 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+ 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+ 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+ 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+ 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+ 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
+};
+static const u32 Te3[256] = {
+ 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+ 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+ 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+ 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+ 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+ 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+ 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+ 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+ 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+ 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+ 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+ 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+ 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+ 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+ 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+ 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+ 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+ 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+ 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+ 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+ 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+ 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+ 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+ 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+ 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+ 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+ 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+ 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+ 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+ 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+ 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+ 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+ 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+ 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+ 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+ 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+ 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+ 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+ 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+ 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+ 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+ 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+ 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+ 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+ 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+ 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+ 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+ 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+ 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+ 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+ 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+ 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+ 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+ 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+ 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+ 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+ 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+ 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+ 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+ 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+ 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+ 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+ 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+ 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
+};
+static const u32 Te4[256] = {
+ 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
+ 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
+ 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
+ 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
+ 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
+ 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
+ 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
+ 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
+ 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
+ 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
+ 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
+ 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
+ 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
+ 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
+ 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
+ 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
+ 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
+ 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
+ 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
+ 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
+ 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
+ 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
+ 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
+ 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
+ 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
+ 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
+ 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
+ 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
+ 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
+ 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
+ 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
+ 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
+ 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
+ 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
+ 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
+ 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
+ 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
+ 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
+ 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
+ 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
+ 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
+ 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
+ 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
+ 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
+ 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
+ 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
+ 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
+ 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
+ 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
+ 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
+ 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
+ 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
+ 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
+ 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
+ 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
+ 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
+ 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
+ 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
+ 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
+ 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
+ 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
+ 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
+ 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
+ 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
+};
+static const u32 Td0[256] = {
+ 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+ 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+ 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+ 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+ 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+ 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+ 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+ 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+ 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+ 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+ 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+ 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+ 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+ 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+ 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+ 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+ 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+ 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+ 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+ 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+ 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+ 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+ 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+ 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+ 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+ 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+ 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+ 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+ 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+ 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+ 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+ 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+ 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+ 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+ 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+ 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+ 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+ 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+ 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+ 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+ 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+ 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+ 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+ 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+ 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+ 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+ 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+ 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+ 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+ 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+ 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+ 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+ 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+ 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+ 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+ 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+ 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+ 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+ 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+ 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+ 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+ 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+ 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+ 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+static const u32 Td1[256] = {
+ 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+ 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+ 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+ 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+ 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+ 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+ 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+ 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+ 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+ 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+ 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+ 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+ 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+ 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+ 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+ 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+ 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+ 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+ 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+ 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+ 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+ 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+ 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+ 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+ 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+ 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+ 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+ 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+ 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+ 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+ 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+ 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+ 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+ 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+ 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+ 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+ 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+ 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+ 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+ 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+ 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+ 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+ 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+ 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+ 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+ 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+ 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+ 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+ 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+ 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+ 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+ 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+ 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+ 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+ 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+ 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+ 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+ 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+ 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+ 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+ 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+ 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+ 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+ 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
+};
+static const u32 Td2[256] = {
+ 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+ 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+ 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+ 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+ 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+ 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+ 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+ 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+ 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+ 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+ 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+ 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+ 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+ 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+ 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+ 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+ 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+ 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+ 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+ 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+ 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+ 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+ 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+ 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+ 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+ 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+ 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+ 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+ 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+ 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+ 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+ 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+ 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+ 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+ 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+ 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+ 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+ 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+ 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+ 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+ 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+ 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+ 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+ 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+ 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+ 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+ 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+ 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+ 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+ 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+ 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+ 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+ 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+ 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+ 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+ 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+ 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+ 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+ 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+ 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+ 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+ 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+ 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+ 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
+};
+static const u32 Td3[256] = {
+ 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+ 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+ 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+ 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+ 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+ 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+ 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+ 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+ 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+ 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+ 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+ 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+ 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+ 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+ 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+ 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+ 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+ 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+ 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+ 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+ 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+ 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+ 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+ 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+ 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+ 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+ 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+ 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+ 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+ 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+ 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+ 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+ 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+ 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+ 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+ 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+ 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+ 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+ 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+ 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+ 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+ 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+ 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+ 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+ 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+ 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+ 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+ 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+ 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+ 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+ 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+ 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+ 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+ 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+ 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+ 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+ 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+ 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+ 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+ 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+ 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+ 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+ 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+ 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
+};
+static const u32 Td4[256] = {
+ 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
+ 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
+ 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
+ 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
+ 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
+ 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
+ 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
+ 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
+ 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
+ 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
+ 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
+ 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
+ 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
+ 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
+ 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
+ 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
+ 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
+ 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
+ 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
+ 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
+ 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
+ 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
+ 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
+ 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
+ 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
+ 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
+ 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
+ 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
+ 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
+ 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
+ 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
+ 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
+ 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
+ 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
+ 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
+ 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
+ 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
+ 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
+ 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
+ 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
+ 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
+ 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
+ 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
+ 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
+ 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
+ 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
+ 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
+ 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
+ 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
+ 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
+ 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
+ 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
+ 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
+ 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
+ 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
+ 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
+ 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
+ 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
+ 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
+ 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
+ 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
+ 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
+ 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
+ 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
+};
+static const u32 rcon[] = {
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000, 0x80000000,
+ 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
+#define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
+
+/**
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * @return the number of rounds for the given cipher key size.
+ */
+int
+rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits)
+{
+ int i = 0;
+ u32 temp;
+
+ rk[0] = GETU32(cipherKey );
+ rk[1] = GETU32(cipherKey + 4);
+ rk[2] = GETU32(cipherKey + 8);
+ rk[3] = GETU32(cipherKey + 12);
+ if (keyBits == 128) {
+ for (;;) {
+ temp = rk[3];
+ rk[4] = rk[0] ^
+ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp ) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp >> 24) ] & 0x000000ff) ^
+ rcon[i];
+ rk[5] = rk[1] ^ rk[4];
+ rk[6] = rk[2] ^ rk[5];
+ rk[7] = rk[3] ^ rk[6];
+ if (++i == 10) {
+ return 10;
+ }
+ rk += 4;
+ }
+ }
+ rk[4] = GETU32(cipherKey + 16);
+ rk[5] = GETU32(cipherKey + 20);
+ if (keyBits == 192) {
+ for (;;) {
+ temp = rk[ 5];
+ rk[ 6] = rk[ 0] ^
+ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp ) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp >> 24) ] & 0x000000ff) ^
+ rcon[i];
+ rk[ 7] = rk[ 1] ^ rk[ 6];
+ rk[ 8] = rk[ 2] ^ rk[ 7];
+ rk[ 9] = rk[ 3] ^ rk[ 8];
+ if (++i == 8) {
+ return 12;
+ }
+ rk[10] = rk[ 4] ^ rk[ 9];
+ rk[11] = rk[ 5] ^ rk[10];
+ rk += 6;
+ }
+ }
+ rk[6] = GETU32(cipherKey + 24);
+ rk[7] = GETU32(cipherKey + 28);
+ if (keyBits == 256) {
+ for (;;) {
+ temp = rk[ 7];
+ rk[ 8] = rk[ 0] ^
+ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp ) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp >> 24) ] & 0x000000ff) ^
+ rcon[i];
+ rk[ 9] = rk[ 1] ^ rk[ 8];
+ rk[10] = rk[ 2] ^ rk[ 9];
+ rk[11] = rk[ 3] ^ rk[10];
+ if (++i == 7) {
+ return 14;
+ }
+ temp = rk[11];
+ rk[12] = rk[ 4] ^
+ (Te4[(temp >> 24) ] & 0xff000000) ^
+ (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp ) & 0xff] & 0x000000ff);
+ rk[13] = rk[ 5] ^ rk[12];
+ rk[14] = rk[ 6] ^ rk[13];
+ rk[15] = rk[ 7] ^ rk[14];
+ rk += 8;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Expand the cipher key into the decryption key schedule.
+ *
+ * @return the number of rounds for the given cipher key size.
+ */
+int
+rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits)
+{
+ int Nr, i, j;
+ u32 temp;
+
+ /* expand the cipher key: */
+ Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits);
+
+ /* invert the order of the round keys: */
+ for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
+ temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp;
+ temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+ temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+ temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+ }
+ /* apply the inverse MixColumn transform to all round keys but the first and the last: */
+ for (i = 1; i < Nr; i++) {
+ rk += 4;
+ rk[0] =
+ Td0[Te4[(rk[0] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[0] ) & 0xff] & 0xff];
+ rk[1] =
+ Td0[Te4[(rk[1] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[1] ) & 0xff] & 0xff];
+ rk[2] =
+ Td0[Te4[(rk[2] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[2] ) & 0xff] & 0xff];
+ rk[3] =
+ Td0[Te4[(rk[3] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[3] ) & 0xff] & 0xff];
+ }
+ return Nr;
+}
+
+void
+rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16],
+ u8 ct[16])
+{
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+ int r;
+#endif /* ?FULL_UNROLL */
+
+ /*
+ * map byte array block to cipher state
+ * and add initial round key:
+ */
+ s0 = GETU32(pt ) ^ rk[0];
+ s1 = GETU32(pt + 4) ^ rk[1];
+ s2 = GETU32(pt + 8) ^ rk[2];
+ s3 = GETU32(pt + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+ /* round 1: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
+ /* round 2: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
+ /* round 3: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
+ /* round 4: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
+ /* round 5: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
+ /* round 6: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
+ /* round 7: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
+ /* round 8: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
+ /* round 9: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
+ if (Nr > 10) {
+ /* round 10: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43];
+ /* round 11: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47];
+ if (Nr > 12) {
+ /* round 12: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51];
+ /* round 13: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55];
+ }
+ }
+ rk += Nr << 2;
+#else /* !FULL_UNROLL */
+ /*
+ * Nr - 1 full rounds:
+ */
+ r = Nr >> 1;
+ for (;;) {
+ t0 =
+ Te0[(s0 >> 24) ] ^
+ Te1[(s1 >> 16) & 0xff] ^
+ Te2[(s2 >> 8) & 0xff] ^
+ Te3[(s3 ) & 0xff] ^
+ rk[4];
+ t1 =
+ Te0[(s1 >> 24) ] ^
+ Te1[(s2 >> 16) & 0xff] ^
+ Te2[(s3 >> 8) & 0xff] ^
+ Te3[(s0 ) & 0xff] ^
+ rk[5];
+ t2 =
+ Te0[(s2 >> 24) ] ^
+ Te1[(s3 >> 16) & 0xff] ^
+ Te2[(s0 >> 8) & 0xff] ^
+ Te3[(s1 ) & 0xff] ^
+ rk[6];
+ t3 =
+ Te0[(s3 >> 24) ] ^
+ Te1[(s0 >> 16) & 0xff] ^
+ Te2[(s1 >> 8) & 0xff] ^
+ Te3[(s2 ) & 0xff] ^
+ rk[7];
+
+ rk += 8;
+ if (--r == 0) {
+ break;
+ }
+
+ s0 =
+ Te0[(t0 >> 24) ] ^
+ Te1[(t1 >> 16) & 0xff] ^
+ Te2[(t2 >> 8) & 0xff] ^
+ Te3[(t3 ) & 0xff] ^
+ rk[0];
+ s1 =
+ Te0[(t1 >> 24) ] ^
+ Te1[(t2 >> 16) & 0xff] ^
+ Te2[(t3 >> 8) & 0xff] ^
+ Te3[(t0 ) & 0xff] ^
+ rk[1];
+ s2 =
+ Te0[(t2 >> 24) ] ^
+ Te1[(t3 >> 16) & 0xff] ^
+ Te2[(t0 >> 8) & 0xff] ^
+ Te3[(t1 ) & 0xff] ^
+ rk[2];
+ s3 =
+ Te0[(t3 >> 24) ] ^
+ Te1[(t0 >> 16) & 0xff] ^
+ Te2[(t1 >> 8) & 0xff] ^
+ Te3[(t2 ) & 0xff] ^
+ rk[3];
+ }
+#endif /* ?FULL_UNROLL */
+ /*
+ * apply last round and
+ * map cipher state to byte array block:
+ */
+ s0 =
+ (Te4[(t0 >> 24) ] & 0xff000000) ^
+ (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t3 ) & 0xff] & 0x000000ff) ^
+ rk[0];
+ PUTU32(ct , s0);
+ s1 =
+ (Te4[(t1 >> 24) ] & 0xff000000) ^
+ (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t0 ) & 0xff] & 0x000000ff) ^
+ rk[1];
+ PUTU32(ct + 4, s1);
+ s2 =
+ (Te4[(t2 >> 24) ] & 0xff000000) ^
+ (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t1 ) & 0xff] & 0x000000ff) ^
+ rk[2];
+ PUTU32(ct + 8, s2);
+ s3 =
+ (Te4[(t3 >> 24) ] & 0xff000000) ^
+ (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t2 ) & 0xff] & 0x000000ff) ^
+ rk[3];
+ PUTU32(ct + 12, s3);
+}
+
+static void
+rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16],
+ u8 pt[16])
+{
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+ int r;
+#endif /* ?FULL_UNROLL */
+
+ /*
+ * map byte array block to cipher state
+ * and add initial round key:
+ */
+ s0 = GETU32(ct ) ^ rk[0];
+ s1 = GETU32(ct + 4) ^ rk[1];
+ s2 = GETU32(ct + 8) ^ rk[2];
+ s3 = GETU32(ct + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+ /* round 1: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
+ /* round 2: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
+ /* round 3: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
+ /* round 4: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
+ /* round 5: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
+ /* round 6: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
+ /* round 7: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
+ /* round 8: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
+ /* round 9: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
+ if (Nr > 10) {
+ /* round 10: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43];
+ /* round 11: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47];
+ if (Nr > 12) {
+ /* round 12: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51];
+ /* round 13: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55];
+ }
+ }
+ rk += Nr << 2;
+#else /* !FULL_UNROLL */
+ /*
+ * Nr - 1 full rounds:
+ */
+ r = Nr >> 1;
+ for (;;) {
+ t0 =
+ Td0[(s0 >> 24) ] ^
+ Td1[(s3 >> 16) & 0xff] ^
+ Td2[(s2 >> 8) & 0xff] ^
+ Td3[(s1 ) & 0xff] ^
+ rk[4];
+ t1 =
+ Td0[(s1 >> 24) ] ^
+ Td1[(s0 >> 16) & 0xff] ^
+ Td2[(s3 >> 8) & 0xff] ^
+ Td3[(s2 ) & 0xff] ^
+ rk[5];
+ t2 =
+ Td0[(s2 >> 24) ] ^
+ Td1[(s1 >> 16) & 0xff] ^
+ Td2[(s0 >> 8) & 0xff] ^
+ Td3[(s3 ) & 0xff] ^
+ rk[6];
+ t3 =
+ Td0[(s3 >> 24) ] ^
+ Td1[(s2 >> 16) & 0xff] ^
+ Td2[(s1 >> 8) & 0xff] ^
+ Td3[(s0 ) & 0xff] ^
+ rk[7];
+
+ rk += 8;
+ if (--r == 0) {
+ break;
+ }
+
+ s0 =
+ Td0[(t0 >> 24) ] ^
+ Td1[(t3 >> 16) & 0xff] ^
+ Td2[(t2 >> 8) & 0xff] ^
+ Td3[(t1 ) & 0xff] ^
+ rk[0];
+ s1 =
+ Td0[(t1 >> 24) ] ^
+ Td1[(t0 >> 16) & 0xff] ^
+ Td2[(t3 >> 8) & 0xff] ^
+ Td3[(t2 ) & 0xff] ^
+ rk[1];
+ s2 =
+ Td0[(t2 >> 24) ] ^
+ Td1[(t1 >> 16) & 0xff] ^
+ Td2[(t0 >> 8) & 0xff] ^
+ Td3[(t3 ) & 0xff] ^
+ rk[2];
+ s3 =
+ Td0[(t3 >> 24) ] ^
+ Td1[(t2 >> 16) & 0xff] ^
+ Td2[(t1 >> 8) & 0xff] ^
+ Td3[(t0 ) & 0xff] ^
+ rk[3];
+ }
+#endif /* ?FULL_UNROLL */
+ /*
+ * apply last round and
+ * map cipher state to byte array block:
+ */
+ s0 =
+ (Td4[(t0 >> 24) ] & 0xff000000) ^
+ (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t1 ) & 0xff] & 0x000000ff) ^
+ rk[0];
+ PUTU32(pt , s0);
+ s1 =
+ (Td4[(t1 >> 24) ] & 0xff000000) ^
+ (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t2 ) & 0xff] & 0x000000ff) ^
+ rk[1];
+ PUTU32(pt + 4, s1);
+ s2 =
+ (Td4[(t2 >> 24) ] & 0xff000000) ^
+ (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t3 ) & 0xff] & 0x000000ff) ^
+ rk[2];
+ PUTU32(pt + 8, s2);
+ s3 =
+ (Td4[(t3 >> 24) ] & 0xff000000) ^
+ (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t0 ) & 0xff] & 0x000000ff) ^
+ rk[3];
+ PUTU32(pt + 12, s3);
+}
+
+/* setup key context for encryption only */
+int
+rijndael_set_key_enc_only(rijndael_ctx *ctx, const u_char *key, int bits)
+{
+ int rounds;
+
+ rounds = rijndaelKeySetupEnc(ctx->ek, key, bits);
+ if (rounds == 0)
+ return -1;
+
+ ctx->Nr = rounds;
+ ctx->enc_only = 1;
+
+ return 0;
+}
+
+/* setup key context for both encryption and decryption */
+int
+rijndael_set_key(rijndael_ctx *ctx, const u_char *key, int bits)
+{
+ int rounds;
+
+ rounds = rijndaelKeySetupEnc(ctx->ek, key, bits);
+ if (rounds == 0)
+ return -1;
+ if (rijndaelKeySetupDec(ctx->dk, key, bits) != rounds)
+ return -1;
+
+ ctx->Nr = rounds;
+ ctx->enc_only = 0;
+
+ return 0;
+}
+
+void
+rijndael_decrypt(rijndael_ctx *ctx, const u_char *src, u_char *dst)
+{
+ rijndaelDecrypt(ctx->dk, ctx->Nr, src, dst);
+}
+
+void
+rijndael_encrypt(rijndael_ctx *ctx, const u_char *src, u_char *dst)
+{
+ rijndaelEncrypt(ctx->ek, ctx->Nr, src, dst);
+}
diff --git a/tboot/sha1.c b/tboot/sha1.c
new file mode 100644
index 0000000..cd4efe1
--- /dev/null
+++ b/tboot/sha1.c
@@ -0,0 +1,265 @@
+/*$KAME: sha1.c,v 1.5 2000/11/08 06:13:08 itojun Exp $ */
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Portions copyright (c) 2010, Intel Corporation
+ */
+
+/*
+ * From: FreeBSD sys/crypto/sha1.c
+ */
+
+/*
+ * FIPS pub 180-1: Secure Hash Algorithm (SHA-1)
+ * based on: http://csrc.nist.gov/fips/fip180-1.txt
+ * implemented by Jun-ichiro itojun Itoh <itojun@itojun.org>
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <compiler.h>
+#include <string.h>
+#include <sha1.h>
+
+#define BIG_ENDIAN \
+ (!(__x86_64__ || __i386__ || _M_IX86 || _M_X64 || __ARMEL__ || __MIPSEL__))
+#define LITTLE_ENDIAN !BIG_ENDIAN
+
+/* constant table */
+static uint32_t _K[] = { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 };
+#define K(t) _K[(t) / 20]
+#define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d)))
+#define F1(b, c, d) (((b) ^ (c)) ^ (d))
+#define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d)))
+#define F3(b, c, d) (((b) ^ (c)) ^ (d))
+#define S(n, x) (((x) << (n)) | ((x) >> (32 - n)))
+#define H(n) (ctxt->h.b32[(n)])
+#define COUNT (ctxt->count)
+#define BCOUNT (ctxt->c.b64[0] / 8)
+#define W(n) (ctxt->m.b32[(n)])
+#define PUTBYTE(x){\
+ ctxt->m.b8[(COUNT % 64)] = (x);\
+ COUNT++;\
+ COUNT %= 64;\
+ ctxt->c.b64[0] += 8;\
+ if (COUNT % 64 == 0)\
+ sha1_step(ctxt);\
+ }
+#define PUTPAD(x){\
+ ctxt->m.b8[(COUNT % 64)] = (x);\
+ COUNT++;\
+ COUNT %= 64;\
+ if (COUNT % 64 == 0)\
+ sha1_step(ctxt);\
+ }
+static void sha1_step(struct sha1_ctxt *ctxt)
+{
+ uint32_t a, b, c, d, e;
+ size_t t, s;
+ uint32_t tmp;
+
+#if LITTLE_ENDIAN
+ struct sha1_ctxt tctxt;
+ memcpy(&tctxt.m.b8[0], &ctxt->m.b8[0], 64);
+ ctxt->m.b8[0] = tctxt.m.b8[3]; ctxt->m.b8[1] = tctxt.m.b8[2];
+ ctxt->m.b8[2] = tctxt.m.b8[1]; ctxt->m.b8[3] = tctxt.m.b8[0];
+ ctxt->m.b8[4] = tctxt.m.b8[7]; ctxt->m.b8[5] = tctxt.m.b8[6];
+ ctxt->m.b8[6] = tctxt.m.b8[5]; ctxt->m.b8[7] = tctxt.m.b8[4];
+ ctxt->m.b8[8] = tctxt.m.b8[11]; ctxt->m.b8[9] = tctxt.m.b8[10];
+ ctxt->m.b8[10] = tctxt.m.b8[9]; ctxt->m.b8[11] = tctxt.m.b8[8];
+ ctxt->m.b8[12] = tctxt.m.b8[15]; ctxt->m.b8[13] = tctxt.m.b8[14];
+ ctxt->m.b8[14] = tctxt.m.b8[13]; ctxt->m.b8[15] = tctxt.m.b8[12];
+ ctxt->m.b8[16] = tctxt.m.b8[19]; ctxt->m.b8[17] = tctxt.m.b8[18];
+ ctxt->m.b8[18] = tctxt.m.b8[17]; ctxt->m.b8[19] = tctxt.m.b8[16];
+ ctxt->m.b8[20] = tctxt.m.b8[23]; ctxt->m.b8[21] = tctxt.m.b8[22];
+ ctxt->m.b8[22] = tctxt.m.b8[21]; ctxt->m.b8[23] = tctxt.m.b8[20];
+ ctxt->m.b8[24] = tctxt.m.b8[27]; ctxt->m.b8[25] = tctxt.m.b8[26];
+ ctxt->m.b8[26] = tctxt.m.b8[25]; ctxt->m.b8[27] = tctxt.m.b8[24];
+ ctxt->m.b8[28] = tctxt.m.b8[31]; ctxt->m.b8[29] = tctxt.m.b8[30];
+ ctxt->m.b8[30] = tctxt.m.b8[29]; ctxt->m.b8[31] = tctxt.m.b8[28];
+ ctxt->m.b8[32] = tctxt.m.b8[35]; ctxt->m.b8[33] = tctxt.m.b8[34];
+ ctxt->m.b8[34] = tctxt.m.b8[33]; ctxt->m.b8[35] = tctxt.m.b8[32];
+ ctxt->m.b8[36] = tctxt.m.b8[39]; ctxt->m.b8[37] = tctxt.m.b8[38];
+ ctxt->m.b8[38] = tctxt.m.b8[37]; ctxt->m.b8[39] = tctxt.m.b8[36];
+ ctxt->m.b8[40] = tctxt.m.b8[43]; ctxt->m.b8[41] = tctxt.m.b8[42];
+ ctxt->m.b8[42] = tctxt.m.b8[41]; ctxt->m.b8[43] = tctxt.m.b8[40];
+ ctxt->m.b8[44] = tctxt.m.b8[47]; ctxt->m.b8[45] = tctxt.m.b8[46];
+ ctxt->m.b8[46] = tctxt.m.b8[45]; ctxt->m.b8[47] = tctxt.m.b8[44];
+ ctxt->m.b8[48] = tctxt.m.b8[51]; ctxt->m.b8[49] = tctxt.m.b8[50];
+ ctxt->m.b8[50] = tctxt.m.b8[49]; ctxt->m.b8[51] = tctxt.m.b8[48];
+ ctxt->m.b8[52] = tctxt.m.b8[55]; ctxt->m.b8[53] = tctxt.m.b8[54];
+ ctxt->m.b8[54] = tctxt.m.b8[53]; ctxt->m.b8[55] = tctxt.m.b8[52];
+ ctxt->m.b8[56] = tctxt.m.b8[59]; ctxt->m.b8[57] = tctxt.m.b8[58];
+ ctxt->m.b8[58] = tctxt.m.b8[57]; ctxt->m.b8[59] = tctxt.m.b8[56];
+ ctxt->m.b8[60] = tctxt.m.b8[63]; ctxt->m.b8[61] = tctxt.m.b8[62];
+ ctxt->m.b8[62] = tctxt.m.b8[61]; ctxt->m.b8[63] = tctxt.m.b8[60];
+#endif
+
+ a = H(0); b = H(1); c = H(2); d = H(3); e = H(4);
+
+ for (t = 0; t < 20; t++) {
+ s = t & 0x0f;
+ if (t >= 16){
+ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
+ }
+ tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t);
+ e = d; d = c; c = S(30, b); b = a; a = tmp;
+ }
+ for (t = 20; t < 40; t++) {
+ s = t & 0x0f;
+ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
+ tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t);
+ e = d; d = c; c = S(30, b); b = a; a = tmp;
+ }
+ for (t = 40; t < 60; t++) {
+ s = t & 0x0f;
+ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
+ tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t);
+ e = d; d = c; c = S(30, b); b = a; a = tmp;
+ }
+ for (t = 60; t < 80; t++) {
+ s = t & 0x0f;
+ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
+ tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t);
+ e = d; d = c; c = S(30, b); b = a; a = tmp;
+ }
+
+ H(0) = H(0) + a;
+ H(1) = H(1) + b;
+ H(2) = H(2) + c;
+ H(3) = H(3) + d;
+ H(4) = H(4) + e;
+
+ memset(&ctxt->m.b8[0],0, 64);
+}
+
+/*------------------------------------------------------------*/
+
+void sha1_init(struct sha1_ctxt *ctxt)
+{
+ memset(ctxt,0, sizeof(struct sha1_ctxt));
+ H(0) = 0x67452301;
+ H(1) = 0xefcdab89;
+ H(2) = 0x98badcfe;
+ H(3) = 0x10325476;
+ H(4) = 0xc3d2e1f0;
+}
+
+void sha1_pad(struct sha1_ctxt *ctxt)
+{
+ size_t padlen; /*pad length in bytes*/
+ size_t padstart;
+
+ PUTPAD(0x80);
+
+ padstart = COUNT % 64;
+ padlen = 64 - padstart;
+ if (padlen < 8) {
+ memset(&ctxt->m.b8[padstart],0, padlen);
+ COUNT += padlen;
+ COUNT %= 64;
+ sha1_step(ctxt);
+ padstart = COUNT % 64; /* should be 0 */
+ padlen = 64 - padstart; /* should be 64 */
+ }
+ memset(&ctxt->m.b8[padstart],0, padlen - 8);
+ COUNT += (padlen - 8);
+ COUNT %= 64;
+#if BIG_ENDIAN
+ PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]);
+ PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[3]);
+ PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[5]);
+ PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[7]);
+#else
+ PUTPAD(ctxt->c.b8[7]); PUTPAD(ctxt->c.b8[6]);
+ PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[4]);
+ PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[2]);
+ PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[0]);
+#endif
+}
+
+void sha1_loop(struct sha1_ctxt *ctxt,const uint8_t *input,size_t len)
+{
+ size_t gaplen;
+ size_t gapstart;
+ size_t off;
+ size_t copysiz;
+
+ off = 0;
+
+ while (off < len) {
+ gapstart = COUNT % 64;
+ gaplen = 64 - gapstart;
+
+ copysiz = (gaplen < len - off) ? gaplen : len - off;
+ memcpy(&ctxt->m.b8[gapstart],&input[off], copysiz);
+ COUNT += copysiz;
+ COUNT %= 64;
+ ctxt->c.b64[0] += copysiz * 8;
+ if (COUNT % 64 == 0)
+ sha1_step(ctxt);
+ off += copysiz;
+ }
+}
+
+void sha1_result(struct sha1_ctxt *ctxt,unsigned char *digest0)
+{
+ uint8_t *digest;
+ digest = (uint8_t *)digest0;
+ sha1_pad(ctxt);
+#if BIG_ENDIAN
+ memcpy(digest, &ctxt->h.b8[0],20);
+#else
+ digest[0] = ctxt->h.b8[3]; digest[1] = ctxt->h.b8[2];
+ digest[2] = ctxt->h.b8[1]; digest[3] = ctxt->h.b8[0];
+ digest[4] = ctxt->h.b8[7]; digest[5] = ctxt->h.b8[6];
+ digest[6] = ctxt->h.b8[5]; digest[7] = ctxt->h.b8[4];
+ digest[8] = ctxt->h.b8[11]; digest[9] = ctxt->h.b8[10];
+ digest[10] = ctxt->h.b8[9]; digest[11] = ctxt->h.b8[8];
+ digest[12] = ctxt->h.b8[15]; digest[13] = ctxt->h.b8[14];
+ digest[14] = ctxt->h.b8[13]; digest[15] = ctxt->h.b8[12];
+ digest[16] = ctxt->h.b8[19]; digest[17] = ctxt->h.b8[18];
+ digest[18] = ctxt->h.b8[17]; digest[19] = ctxt->h.b8[16];
+#endif
+}
+
+int sha1_buffer(const unsigned char *buffer, size_t len,
+ unsigned char md[SHA_DIGEST_LENGTH])
+{
+ SHA_CTX c;
+
+ if (md == NULL)
+ return 1;
+ SHA1_Init(&c);
+ SHA1_Update(&c,buffer,len);
+ SHA1_Final(md,&c);
+ return 0;
+}
+
diff --git a/tboot/sha256.c b/tboot/sha256.c
new file mode 100644
index 0000000..d8542df
--- /dev/null
+++ b/tboot/sha256.c
@@ -0,0 +1,242 @@
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sha256.h>
+
+/* Various logical functions */
+#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) \
+ | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) \
+ & 0xFFFFFFFFUL)
+#define Ch(x,y,z) (z ^ (x & (y ^ z)))
+#define Maj(x,y,z) (((x | y) & z) | (x & y))
+#define S(x, n) RORc((x),(n))
+#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+
+/* compress 512-bits */
+static int sha256_compress(sha256_state * md, unsigned char *buf)
+{
+ u32 S[8], W[64], t0, t1;
+ int i;
+
+ /* copy state into S */
+ for (i = 0; i < 8; i++) {
+ S[i] = md->state[i];
+ }
+
+ /* copy the state into 512-bits into W[0..15] */
+ for (i = 0; i < 16; i++) {
+ LOAD32H(W[i], buf + (4*i));
+ }
+
+ /* fill W[16..63] */
+ for (i = 16; i < 64; i++) {
+ W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
+ }
+
+ /* Compress */
+#define RND(a,b,c,d,e,f,g,h,i,ki) \
+ t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \
+ t1 = Sigma0(a) + Maj(a, b, c); \
+ d += t0; \
+ h = t0 + t1;
+
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5);
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174);
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da);
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967);
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85);
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070);
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3);
+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee);
+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f);
+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814);
+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208);
+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa);
+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb);
+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7);
+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2);
+
+#undef RND
+
+ /* feedback */
+ for (i = 0; i < 8; i++) {
+ md->state[i] = md->state[i] + S[i];
+ }
+ return 0;
+}
+
+#define SHA256_BLOCK_SIZE 64
+#define MIN(x, y) ( ((x)<(y))?(x):(y) )
+int sha256_process(sha256_state * md, const unsigned char *in, unsigned long inlen)
+{
+ unsigned long n;
+ int err;
+
+ if (md == NULL || in == NULL)
+ return -1;
+ if (md->curlen > sizeof(md->buf))
+ return -1;
+
+ while (inlen > 0) {
+ if (md->curlen == 0 && inlen >= SHA256_BLOCK_SIZE) {
+ if ((err = sha256_compress(md, (unsigned char *)in)) != 0) {
+ return err;
+ }
+ md->length += SHA256_BLOCK_SIZE * 8;
+ in += SHA256_BLOCK_SIZE;
+ inlen -= SHA256_BLOCK_SIZE;
+ } else {
+ n = MIN(inlen, (SHA256_BLOCK_SIZE - md->curlen));
+ memcpy(md->buf + md->curlen, in, (size_t)n);
+ md->curlen += n;
+ in += n;
+ inlen -= n;
+ if (md->curlen == SHA256_BLOCK_SIZE) {
+ if ((err = sha256_compress(md, md->buf)) != 0) {
+ return err;
+ }
+ md->length += 8*SHA256_BLOCK_SIZE;
+ md->curlen = 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return CRYPT_OK if successful
+*/
+void sha256_init(sha256_state * md)
+{
+ if (md == NULL)
+ return;
+
+ md->curlen = 0;
+ md->length = 0;
+ md->state[0] = 0x6A09E667UL;
+ md->state[1] = 0xBB67AE85UL;
+ md->state[2] = 0x3C6EF372UL;
+ md->state[3] = 0xA54FF53AUL;
+ md->state[4] = 0x510E527FUL;
+ md->state[5] = 0x9B05688CUL;
+ md->state[6] = 0x1F83D9ABUL;
+ md->state[7] = 0x5BE0CD19UL;
+}
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (32 bytes)
+ @return 0 if successful
+*/
+int sha256_done(sha256_state * md, unsigned char *out)
+{
+ int i;
+
+ if (md == NULL || out == NULL)
+ return -1;
+
+ if (md->curlen >= sizeof(md->buf))
+ return -1;
+
+ /* increase the length of the message */
+ md->length += md->curlen * 8;
+
+ /* append the '1' bit */
+ md->buf[md->curlen++] = (unsigned char)0x80;
+
+ /* if the length is currently above 56 bytes we append zeros
+ * then compress. Then we can fall back to padding zeros and length
+ * encoding like normal.
+ */
+ if (md->curlen > 56) {
+ while (md->curlen < 64) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+ sha256_compress(md, md->buf);
+ md->curlen = 0;
+ }
+
+ /* pad upto 56 bytes of zeroes */
+ while (md->curlen < 56) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+
+ /* store length */
+ STORE64H(md->length, md->buf+56);
+ sha256_compress(md, md->buf);
+
+ /* copy output */
+ for (i = 0; i < 8; i++) {
+ STORE32H(md->state[i], out+(4*i));
+ }
+
+ return 0;
+}
+
+void sha256_buffer(const unsigned char *buffer, size_t len,
+ unsigned char hash[32])
+{
+ sha256_state md;
+
+ sha256_init(&md);
+ sha256_process(&md, buffer, len);
+ sha256_done(&md, hash);
+}
diff --git a/tboot/string.c b/tboot/string.c
new file mode 100644
index 0000000..d30998e
--- /dev/null
+++ b/tboot/string.c
@@ -0,0 +1,204 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * From: FreeBSD sys/libkern/strlen.c
+ * From: FreeBSD sys/libkern/strcmp.c
+ * From: FreeBSD sys/libkern/strncmp.c
+ * From: FreeBSD sys/libkern/strncpy.c
+ * From: FreeBSD: sys/libkern/index.c
+ */
+/* $FreeBSD: src/sys/libkern/strtoul.c,v 1.6.32.1 2010/02/10 00:26:20 kensmith Exp $ */
+/* $FreeBSD: src/sys/libkern/memcmp.c,v 1.1 2008/09/23 14:45:10 obrien Exp $ */
+
+#include <config.h>
+#include <efibase.h>
+#include <ctype.h>
+#include <string.h>
+
+size_t strlen(str)
+ const char *str;
+{
+ register const char *s;
+
+ for (s = str; *s; ++s);
+ return(s - str);
+}
+
+/*
+ * Compare strings.
+ */
+int strcmp(s1, s2)
+ register const char *s1, *s2;
+{
+ while (*s1 == *s2++)
+ if (*s1++ == 0)
+ return (0);
+ return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
+}
+
+int strncmp(s1, s2, n)
+ register const char *s1, *s2;
+ register size_t n;
+{
+
+ if (n == 0)
+ return (0);
+ do {
+ if (*s1 != *s2++)
+ return (*(const unsigned char *)s1 -
+ *(const unsigned char *)(s2 - 1));
+ if (*s1++ == 0)
+ break;
+ } while (--n != 0);
+ return (0);
+}
+
+/*
+ * Copy src to dst, truncating or null-padding to always copy n bytes.
+ * Return dst.
+ */
+char *strncpy(char * __restrict dst, const char * __restrict src, size_t n)
+{
+ if (n != 0) {
+ register char *d = dst;
+ register const char *s = src;
+
+ do {
+ if ((*d++ = *s++) == 0) {
+ /* NUL pad the remaining n-1 bytes */
+ while (--n != 0)
+ *d++ = 0;
+ break;
+ }
+ } while (--n != 0);
+ }
+ return (dst);
+}
+
+#define ULONG_MAX 0xFFFFFFFFUL
+
+/*
+ * Convert a string to an unsigned long integer.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long strtoul(const char *nptr, char **endptr, int base)
+{
+ const char *s = nptr;
+ unsigned long acc;
+ unsigned char c;
+ unsigned long cutoff;
+ int neg = 0, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ do {
+ c = *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else if (c == '+')
+ c = *s++;
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
+ cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
+ for (acc = 0, any = 0;; c = *s++) {
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = ULONG_MAX;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != 0)
+ *((const char **)endptr) = any ? s - 1 : nptr;
+ return (acc);
+}
+
+/*
+ * index() is also present as the strchr() in the kernel; it does exactly the
+ * same thing as it's userland equivalent.
+ */
+char *index(p, ch)
+ const char *p;
+ int ch;
+{
+ union {
+ const char *cp;
+ char *p;
+ } u;
+
+ u.cp = p;
+ for (;; ++u.p) {
+ if (*u.p == ch)
+ return(u.p);
+ if (*u.p == '\0')
+ return(NULL);
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * Compare memory regions.
+ */
+int memcmp(const void *s1, const void *s2, size_t n)
+{
+ if (n != 0) {
+ const unsigned char *p1 = s1, *p2 = s2;
+
+ do {
+ if (*p1++ != *p2++)
+ return (*--p1 - *--p2);
+ } while (--n != 0);
+ }
+ return (0);
+}
diff --git a/tboot/tb_error.c b/tboot/tb_error.c
new file mode 100644
index 0000000..db9d8c8
--- /dev/null
+++ b/tboot/tb_error.c
@@ -0,0 +1,196 @@
+/*
+ * tb_error.c: support functions for tb_error_t type
+ *
+ * Copyright (c) 2006-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <printk.h>
+#include <compiler.h>
+#include <string.h>
+#include <misc.h>
+#include <uuid.h>
+#include <uuid.h>
+#include <hash.h>
+#include <tb_error.h>
+#include <tb_policy.h>
+#include <tpm.h>
+#include <eficore.h>
+#include <tboot.h>
+#include <txt/config_regs.h>
+
+#define TB_LAUNCH_ERR_IDX 0x20000002 /* launch error index */
+
+static bool no_err_idx;
+
+/*
+ * print_tb_error_msg
+ *
+ * print tb policy error message
+ *
+ */
+void print_tb_error_msg(tb_error_t error)
+{
+ switch( error ) {
+ case TB_ERR_NONE:
+ printk(TBOOT_INFO"succeeded.\n");
+ break;
+ case TB_ERR_FIXED:
+ printk(TBOOT_INFO"previous error has been fixed.\n");
+ break;
+ case TB_ERR_GENERIC:
+ printk(TBOOT_WARN"non-fatal generic error.\n");
+ break;
+ case TB_ERR_TPM_NOT_READY:
+ printk(TBOOT_WARN"TPM not ready.\n");
+ break;
+ case TB_ERR_SMX_NOT_SUPPORTED:
+ printk(TBOOT_WARN"SMX not supported.\n");
+ break;
+ case TB_ERR_VMX_NOT_SUPPORTED:
+ printk(TBOOT_ERR"VMX not supported.\n");
+ break;
+ case TB_ERR_TXT_NOT_SUPPORTED:
+ printk(TBOOT_ERR"TXT not supported.\n");
+ break;
+ case TB_ERR_MODULES_NOT_IN_POLICY:
+ printk(TBOOT_ERR"modules in mbi but not in policy.\n");
+ break;
+ case TB_ERR_MODULE_VERIFICATION_FAILED:
+ printk(TBOOT_ERR"verifying module against policy failed.\n");
+ break;
+ case TB_ERR_POLICY_INVALID:
+ printk(TBOOT_ERR"policy invalid.\n");
+ break;
+ case TB_ERR_POLICY_NOT_PRESENT:
+ printk(TBOOT_WARN"no policy in TPM NV.\n");
+ break;
+ case TB_ERR_SINIT_NOT_PRESENT:
+ printk(TBOOT_WARN"SINIT ACM not provided.\n");
+ break;
+ case TB_ERR_ACMOD_VERIFY_FAILED:
+ printk(TBOOT_WARN"verifying AC module failed.\n");
+ break;
+ case TB_ERR_POST_LAUNCH_VERIFICATION:
+ printk(TBOOT_ERR"verification of post-launch failed.\n");
+ break;
+ case TB_ERR_S3_INTEGRITY:
+ printk(TBOOT_ERR"creation or verification of S3 measurements failed.\n");
+ break;
+ case TB_ERR_FATAL:
+ printk(TBOOT_ERR"generic fatal error.\n");
+ break;
+ case TB_ERR_NV_VERIFICATION_FAILED:
+ printk(TBOOT_ERR"verifying nv against policy failed.\n");
+ break;
+ default:
+ printk(TBOOT_ERR"unknown error (%d).\n", error);
+ break;
+ }
+}
+
+/*
+ * read_tb_error_code
+ *
+ * read error code from TPM NV (TB_LAUNCH_ERR_IDX)
+ *
+ */
+bool read_tb_error_code(tb_error_t *error)
+{
+ uint32_t size = sizeof(tb_error_t);
+
+ if ( error == NULL ) {
+ printk(TBOOT_ERR"Error: error pointer is zero.\n");
+ return false;
+ }
+
+ memset(error, 0, size);
+
+ /* read! */
+ if ( !g_tpm->nv_read(g_tpm, 0, g_tpm->tb_err_index, 0,
+ (uint8_t *)error, &size) ) {
+ printk(TBOOT_WARN"Error: read TPM error: 0x%x.\n", g_tpm->error);
+ no_err_idx = true;
+ return false;
+ }
+
+ no_err_idx = false;
+ return true;
+}
+
+/*
+ * write_tb_error_code
+ *
+ * write error code into TPM NV (TB_LAUNCH_ERR_IDX)
+ *
+ */
+bool write_tb_error_code(tb_error_t error)
+{
+ if ( !g_tpm || no_err_idx )
+ return false;
+
+ if ( !g_tpm->nv_write(g_tpm, g_tpm->cur_loc, g_tpm->tb_err_index, 0,
+ (uint8_t *)&error, sizeof(tb_error_t)) ) {
+ printk(TBOOT_WARN"Error: write TPM error: 0x%x.\n", g_tpm->error);
+ no_err_idx = true;
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * was_last_boot_error
+ * false: no error; true: error
+ */
+bool was_last_boot_error(void)
+{
+ tb_error_t error;
+ txt_errorcode_t txt_err;
+
+ /* check TB_LAUNCH_ERR_IDX */
+ if ( read_tb_error_code(&error) ) {
+ if ( error != TB_ERR_FIXED )
+ return true;
+ }
+
+ /* check TXT.ERRORCODE */
+ txt_err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE);
+ if ( txt_err.valid && txt_err.type > 0 )
+ return true;
+
+ return false;
+}
+
diff --git a/tboot/tboot.c b/tboot/tboot.c
new file mode 100644
index 0000000..a5f773b
--- /dev/null
+++ b/tboot/tboot.c
@@ -0,0 +1,473 @@
+/*
+ * tboot.c: main entry point and "generic" routines for measured launch
+ * support
+ *
+ * Copyright (c) 2006-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Copyright (c) 2017 Assured Information Security.
+ * Ross Philipson <philipsonr@ainfosec.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <compiler.h>
+#include <string.h>
+#include <printk.h>
+#include <uuid.h>
+#include <misc.h>
+#include <processor.h>
+#include <cmdline.h>
+#include <eficore.h>
+#include <eficonfig.h>
+#include <msr.h>
+#include <atomic.h>
+#include <hash.h>
+#include <io.h>
+#include <mutex.h>
+#include <mle.h>
+#include <tpm.h>
+#include <tb_error.h>
+#include <tb_policy.h>
+#include <tboot.h>
+#include <acpi.h>
+#include <txt/acmod.h>
+#include <txt/mtrrs.h>
+#include <txt/vmcs.h>
+#include <txt/config_regs.h>
+#include <txt/heap.h>
+#include <txt/verify.h>
+#include <txt/txt.h>
+
+/* counter timeout for waiting for all APs to exit guests */
+#define AP_GUEST_EXIT_TIMEOUT 0x01000000
+
+__data long s3_flag = 0;
+
+#ifdef EFI_DEBUG
+static void efi_debug_print_d(efi_xen_tboot_data_t *d)
+{
+ const efi_file_t *xen_file = efi_get_xen();
+
+ printk("Xen TBOOT shared data:\n");
+ printk(" xen = %p\n", xen_file->u.buffer);
+ printk(" xen_size = 0x%llx\n", xen_file->size);
+ printk(" kernel = %p\n", d->kernel);
+ printk(" kernel_size = 0x%llx\n", d->kernel_size);
+ printk(" ramdisk = %p\n", d->ramdisk);
+ printk(" ramdisk_size = 0x%llx\n", d->ramdisk_size);
+ printk(" memory_map = %p\n", d->memory_map);
+ printk(" memory_map_size = 0x%llx\n", d->memory_map_size);
+ printk(" memory_desc_size = 0x%llx\n", d->memory_desc_size);
+ printk(" _tboot_shared = %p\n", &_tboot_shared);
+ printk(" shared size = 0x%x\n", sizeof(tboot_shared_t));
+}
+#else
+#define efi_debug_print_d(d)
+#endif
+
+static void store_section_sizes(void)
+{
+ uint64_t mle_start_ref;
+ uint64_t mle_size_ref;
+ uint64_t bss_start_ref;
+ uint64_t bss_size_ref;
+
+ /*
+ * The _mle_start symbol is exactly at the beginning of the .text section.
+ * The _bss_start symbol is exactly at the beginning of the .bss section.
+ * The .text and .bss section sizes are gotten from the PE information but
+ * for a given build, they will always be the same. So that means they can
+ * be put in the MLE and measured.
+ */
+
+ lea_reference(_mle_start, mle_start_ref);
+ lea_reference(_mle_size, mle_size_ref);
+ lea_reference(_bss_start, bss_start_ref);
+ lea_reference(_bss_size, bss_size_ref);
+
+ if ((void*)mle_start_ref != g_text_base) {
+ printk(TBOOT_ERR"_mle_start != g_text_base\n");
+ apply_policy(TB_ERR_FATAL);
+ }
+
+ *((uint64_t*)mle_size_ref) = g_text_size;
+ printk(TBOOT_INFO"_mle_start: 0x%llx _mle_size: 0x%llx\n",
+ mle_start_ref, *((uint64_t*)mle_size_ref));
+
+ if ((void*)bss_start_ref != g_bss_base) {
+ printk(TBOOT_ERR"_bss_start != g_bss_base\n");
+ apply_policy(TB_ERR_FATAL);
+ }
+
+ *((uint64_t*)bss_size_ref) = g_bss_size;
+ printk(TBOOT_INFO"_bss_start: 0x%llx _bss_size: 0x%llx\n",
+ bss_start_ref, *((uint64_t*)bss_size_ref));
+}
+
+static tb_error_t verify_platform(void)
+{
+ return txt_verify_platform();
+}
+
+static bool is_launched(void)
+{
+ if ( supports_txt() == TB_ERR_NONE )
+ return txt_is_launched();
+ else return false;
+}
+
+static bool prepare_cpu(void)
+{
+ return txt_prepare_cpu();
+}
+
+static void copy_s3_wakeup_entry(void)
+{
+ /* TODO deal with S3 later */
+}
+
+void cpu_wakeup(uint32_t cpuid, uint64_t sipi_vec)
+{
+ printk(TBOOT_INFO"cpu %u waking up, SIPI vector=%llx\n", cpuid, sipi_vec);
+
+ /* change to real mode and then jump to SIPI vector */
+ /* TODO _prot_to_real(sipi_vec); */
+}
+
+#define ICR_LOW 0x300
+
+/*static*/ void startup_rlps(void)
+{
+ uint32_t rlp_count = ((cpuid_ecx(1) >> 16) & 0xff) - 1;
+ uint64_t apicbase = rdmsr(MSR_APICBASE) & 0xfffffffffffff000;
+
+ if ( rlp_count == 0 )
+ return;
+
+ /* send init ipi to all rlp -- Dest Shorthand: 11, Delivery Mode: 101 */
+ writel(apicbase + ICR_LOW, 0xc0500);
+}
+
+void launch_racm(void)
+{
+ /* TODO this is gonna do GETSEC[ENTERACCS] */
+ /* This means IA-32e */
+}
+
+static void shutdown_system(uint32_t);
+void check_racm_result(void)
+{
+ txt_get_racm_error();
+ shutdown_system(TB_SHUTDOWN_HALT);
+}
+
+void begin_initial_launch(void)
+{
+ const char *cmdline;
+ const efi_file_t *sinit_file;
+ acm_hdr_t *sinit;
+ tb_error_t err;
+
+ /* always load cmdline defaults */
+ tboot_parse_cmdline(true);
+
+ /* on pre-SENTER boot, copy command line to buffer in tboot image
+ * (so that it will be measured); buffer must be 0 -filled */
+ if ( !is_launched() && !s3_flag ) {
+ memset(g_cmdline, '\0', sizeof(g_cmdline));
+ cmdline = efi_cfg_get_value(EFI_CONFIG_TBOOT_PARSED,
+ SECTION_TBOOT, ITEM_OPTIONS);
+ if (cmdline)
+ strncpy(g_cmdline, cmdline, sizeof(g_cmdline)-1);
+ }
+
+ /* always parse cmdline */
+ tboot_parse_cmdline(false);
+
+ /* initialize all logging targets */
+ printk_init(INIT_PRE_LAUNCH);
+
+ /* DEBUG */
+ print_test_chars();
+
+ printk(TBOOT_INFO"******************* TBOOT *******************\n");
+ printk(TBOOT_INFO" %s\n", TBOOT_CHANGESET);
+ printk(TBOOT_INFO"*********************************************\n");
+
+ printk(TBOOT_INFO"command line: %s\n", g_cmdline);
+
+ /* DEBUG */
+ print_system_values();
+
+ /* if telled to check revocation acm result, go with simplified path */
+ if ( get_tboot_call_racm_check() )
+ check_racm_result(); /* never return */
+
+ /* TODO if (is_launched()) printk(TBOOT_INFO"SINIT ACM successfully returned...\n");*/
+ if ( s3_flag ) printk(TBOOT_INFO"Resume from S3...\n");
+
+ /* clear resume vector on S3 resume so any resets will not use it */
+ /* TODO if ( !is_launched() && s3_flag ) set_s3_resume_vector(&_tboot_shared.acpi_sinfo, 0);*/
+
+ /* we should only be executing on the BSP */
+ if ( !(rdmsr(MSR_APICBASE) & APICBASE_BSP) ) {
+ printk(TBOOT_INFO"entry processor is not BSP\n");
+ apply_policy(TB_ERR_FATAL);
+ }
+ printk(TBOOT_INFO"BSP is cpu %u\n", get_apicid());
+
+ /*
+ * TODO e820 copied here but TBOOT will not be using it. Xen will have to
+ * do e820 fixup work and present it to dom0. We still need to read the
+ * min_ram value from the config that used to happen in that call
+ */
+ get_tboot_min_ram();
+
+ /* make TPM ready for measured launch */
+ if (!tpm_detect())
+ apply_policy(TB_ERR_TPM_NOT_READY);
+
+ /* we need to make sure this is a (TXT-) capable platform before using */
+ /* any of the features, incl. those required to check if the environment */
+ /* has already been launched */
+
+ if (!g_sinit) {
+ sinit_file = efi_get_platform_sinit();
+ if (sinit_file == NULL)
+ apply_policy(TB_ERR_SINIT_NOT_PRESENT);
+ /* check if it is newer than BIOS provided version, then copy it to BIOS reserved region */
+ g_sinit = copy_sinit((const acm_hdr_t*)sinit_file->u.buffer);
+ if (g_sinit == NULL)
+ apply_policy(TB_ERR_SINIT_NOT_PRESENT);
+ if (!verify_acmod(g_sinit))
+ apply_policy(TB_ERR_ACMOD_VERIFY_FAILED);
+ }
+ test_virt_to_phys((uint64_t)g_sinit);
+
+ /* read tboot verified launch control policy from TPM-NV (will use default if none in TPM-NV) */
+ err = set_policy();
+ apply_policy(err);
+
+ /* if telled to call revocation acm, go with simplified path */
+ if ( get_tboot_call_racm() )
+ launch_racm(); /* never return */
+
+ /* need to verify that platform supports TXT before we can check error */
+ /* (this includes TPM support) */
+ err = supports_txt();
+ apply_policy(err);
+
+ /* print any errors on last boot, which must be from TXT launch */
+ txt_get_error();
+
+ /* need to verify that platform can perform measured launch */
+ err = verify_platform();
+ apply_policy(err);
+
+ /*
+ * Check for modules was here but that is not how things work any longer.
+ * Xen will load the other modules and have to tell us about them later.
+ */
+
+ /* prepare_cpu() will be done later */
+
+ /* check for error from previous boot */
+ printk(TBOOT_INFO"checking previous errors on the last boot.\n\t");
+ if ( was_last_boot_error() )
+ printk(TBOOT_INFO"last boot has error.\n");
+ else
+ printk(TBOOT_INFO"last boot has no error.\n");
+
+ if ( !prepare_tpm() )
+ apply_policy(TB_ERR_TPM_NOT_READY);
+
+ /*
+ * Some of the MLE bits can be setup early before we jump off to
+ * the next gig. First setup the MLE header with offest relative to
+ * where we are then build the MLE page tables. Also load RIP
+ * relative addresses for VMCS structures.
+ */
+ txt_init_mle_header();
+
+ if ( !txt_build_mle_pagetable() )
+ apply_policy(TB_ERR_FATAL);
+
+ store_section_sizes();
+
+ /* This is the end of the line for the initial launch. It is time to start
+ * Xen and transfer control. The actual SMX launch will be done in a
+ * callback from Xen after EBS.
+ */
+}
+
+void begin_launch(efi_xen_tboot_data_t *xtd)
+{
+ tb_error_t err;
+
+ /* initialize post EBS logging targets - this must be done first */
+ printk_init(INIT_POST_EBS);
+
+ /* store kernel and ramdisk module information */
+ if ( !efi_store_xen_tboot_data(xtd) )
+ apply_policy(TB_ERR_FATAL);
+
+ /* DEBUG */
+ print_system_values();
+
+ efi_debug_print_d(xtd);
+
+ if ( !efi_scan_memory_map() )
+ apply_policy(TB_ERR_FATAL);
+
+ /* DEBUG */
+ /*dump_page_tables();*/
+
+ /* make the CPU ready for measured launch */
+ if ( !prepare_cpu() )
+ apply_policy(TB_ERR_FATAL);
+
+ /* launch the measured environment */
+ err = txt_launch_environment();
+ apply_policy(err);
+
+ /* TODO have to figure out how to return to Xen when we pop
+ * out elsewhere. Save the ret addr and mock up the function
+ * return.
+ */
+}
+
+void post_launch(void)
+{
+ /* always load cmdline defaults */
+ tboot_parse_cmdline(true);
+
+ /* always parse cmdline */
+ tboot_parse_cmdline(false);
+
+ /* initialize all logging targets */
+ printk_init(INIT_POST_LAUNCH);
+
+ printk(TBOOT_INFO"******************** MLE ********************\n");
+ printk(TBOOT_INFO" %s\n", TBOOT_CHANGESET);
+ printk(TBOOT_INFO"*********************************************\n");
+
+ /* init the bits needed to run APs in mini-VMs */
+ init_vmcs_addrs();
+
+ /* TODO reparse and load configs stored in the MLE */
+
+ /* TODO measure the memory map */
+
+ /* TODO call efi_scan_memory_map again after measured launch to rebuild map */
+
+ /* TODO hash Xen text section before transferring control back to it */
+}
+
+void s3_launch(void)
+{
+ /* TODO deal with later */
+}
+
+static void shutdown_system(uint32_t shutdown_type)
+{
+ static const char *types[] = { "TB_SHUTDOWN_REBOOT", "TB_SHUTDOWN_S5",
+ "TB_SHUTDOWN_S4", "TB_SHUTDOWN_S3",
+ "TB_SHUTDOWN_HALT" };
+ char type[32];
+
+ if ( shutdown_type >= ARRAY_SIZE(types) )
+ snprintf(type, sizeof(type), "unknown: %u", shutdown_type);
+ else
+ strncpy(type, types[shutdown_type], sizeof(type));
+ printk(TBOOT_INFO"shutdown_system() called for shutdown_type: %s\n", type);
+
+ switch( shutdown_type ) {
+ case TB_SHUTDOWN_S3:
+ copy_s3_wakeup_entry();
+ /* write our S3 resume vector to ACPI resume addr */
+ /* TODO handle S3 later set_s3_resume_vector(&_tboot_shared.acpi_sinfo, TBOOT_S3_WAKEUP_ADDR);*/
+ /* fall through for rest of Sx handling */
+ case TB_SHUTDOWN_S4:
+ case TB_SHUTDOWN_S5:
+ machine_sleep(&_tboot_shared.acpi_sinfo);
+ /* if machine_sleep() fails, fall through to reset */
+
+ case TB_SHUTDOWN_REBOOT:
+ if ( txt_is_powercycle_required() ) {
+ /* powercycle by writing 0x0a+0x0e to port 0xcf9 */
+ /* (supported by all TXT-capable chipsets) */
+ outb(0xcf9, 0x0a);
+ outb(0xcf9, 0x0e);
+ }
+ else {
+ /* soft reset by writing 0xfe to keyboard reset vector 0x64 */
+ /* BIOSes (that are not performing some special operation, */
+ /* such as update) will turn this into a platform reset as */
+ /* expected. */
+ outb(0x64, 0xfe);
+ /* fall back to soft reset by writing 0x06 to port 0xcf9 */
+ /* (supported by all TXT-capable chipsets) */
+ outb(0xcf9, 0x06);
+ }
+
+ case TB_SHUTDOWN_HALT:
+ default:
+ while ( true )
+ halt();
+ }
+}
+
+void shutdown(void)
+{
+ /* TODO fill me in */
+}
+
+void handle_exception(void)
+{
+ printk(TBOOT_INFO"received exception; shutting down...\n");
+ _tboot_shared.shutdown_type = TB_SHUTDOWN_REBOOT;
+ shutdown();
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
diff --git a/tboot/tboot.cfg b/tboot/tboot.cfg
new file mode 100644
index 0000000..cdad88a
--- /dev/null
+++ b/tboot/tboot.cfg
@@ -0,0 +1,17 @@
+[tboot]
+options=min_ram=0x2000000 loglvl=all serial=115200,8n1,0x3f8 logging=serial,memory,efi
+xenpath=\EFI\Xen\xen.efi
+
+[acm]
+0=6th_gen_i5_i7_SINIT_71.BIN
+1=5th_gen_i5_i7_SINIT_79.BIN
+2=4th_gen_i5_i7_SINIT_75.BIN
+3=Xeon-E7-8800-4800-2800-SINIT-v1.1.bin
+4=Xeon-5600-3500-SINIT-v1.1.bin
+5=3rd_gen_i5_i7_SINIT_67.BIN
+6=i7_QUAD_SINIT_51.BIN
+7=i5_i7_DUAL_SINIT_51.BIN
+8=Q45_Q43_SINIT_51.BIN
+9=Q35_SINIT_51.BIN
+10=GM45_GS45_PM45_SINIT_51.BIN
+
diff --git a/tboot/tpm.c b/tboot/tpm.c
new file mode 100644
index 0000000..d4e0b08
--- /dev/null
+++ b/tboot/tpm.c
@@ -0,0 +1,911 @@
+/*
+ * tpm.c: TPM-related support functions
+ *
+ * Copyright (c) 2006-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <printk.h>
+#include <misc.h>
+#include <compiler.h>
+#include <processor.h>
+#include <io.h>
+#include <string.h>
+#include <tpm.h>
+#include <sha1.h>
+
+__data struct tpm_if *g_tpm = NULL;
+u16 tboot_alg_list[2] = {TB_HALG_SHA1, TB_HALG_SHA256};
+
+
+
+
+
+
+/* Global variables for TPM status register */
+static tpm20_reg_sts_t g_reg_sts, *g_reg_sts_20 = &g_reg_sts;
+static tpm12_reg_sts_t *g_reg_sts_12 = (tpm12_reg_sts_t *)&g_reg_sts;
+
+uint8_t g_tpm_family = 0;
+
+/* TPM_DATA_FIFO_x */
+#define TPM_REG_DATA_FIFO 0x24
+typedef union {
+ uint8_t _raw[1]; /* 1-byte reg */
+} tpm_reg_data_fifo_t;
+
+typedef union {
+ uint8_t _raw[1];
+} tpm_reg_data_crb_t;
+
+#define TPM_ACTIVE_LOCALITY_TIME_OUT \
+ (TIMEOUT_UNIT * g_tpm->timeout.timeout_a) /* according to spec */
+#define TPM_CMD_READY_TIME_OUT \
+ (TIMEOUT_UNIT * g_tpm->timeout.timeout_b) /* according to spec */
+#define TPM_CMD_WRITE_TIME_OUT \
+ (TIMEOUT_UNIT * g_tpm->timeout.timeout_d) /* let it long enough */
+#define TPM_DATA_AVAIL_TIME_OUT \
+ (TIMEOUT_UNIT * g_tpm->timeout.timeout_c) /* let it long enough */
+#define TPM_RSP_READ_TIME_OUT \
+ (TIMEOUT_UNIT * g_tpm->timeout.timeout_d) /* let it long enough */
+#define TPM_VALIDATE_LOCALITY_TIME_OUT 0x100
+
+#define read_tpm_sts_reg(locality) { \
+if ( g_tpm_family == 0 ) \
+ read_tpm_reg(locality, TPM_REG_STS, g_reg_sts_12); \
+else \
+ read_tpm_reg(locality, TPM_REG_STS, g_reg_sts_20); \
+}
+
+#define write_tpm_sts_reg(locality) { \
+if ( g_tpm_family == 0 ) \
+ write_tpm_reg(locality, TPM_REG_STS, g_reg_sts_12); \
+else \
+ write_tpm_reg(locality, TPM_REG_STS, g_reg_sts_20); \
+}
+
+static void tpm_send_cmd_ready_status(uint32_t locality)
+{
+ /* write 1 to TPM_STS_x.commandReady to let TPM enter ready state */
+ memset((void *)&g_reg_sts, 0, sizeof(g_reg_sts));
+ g_reg_sts.command_ready = 1;
+ write_tpm_sts_reg(locality);
+}
+
+
+static bool tpm_send_cmd_ready_status_crb(uint32_t locality)
+{
+ tpm_reg_ctrl_request_t reg_ctrl_request;
+ tpm_reg_ctrl_sts_t reg_ctrl_sts;
+
+ read_tpm_reg(locality, TPM_CRB_CTRL_STS, &reg_ctrl_sts);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_INFO"1. reg_ctrl_sts.tpmidle: 0x%x\n", reg_ctrl_sts.tpmidle);
+ printk(TBOOT_INFO"1. reg_ctrl_sts.tpmsts: 0x%x\n", reg_ctrl_sts.tpmsts);
+#endif
+
+ if ( reg_ctrl_sts.tpmidle== 1) {
+ reg_ctrl_request._raw[0] = 0;
+ reg_ctrl_request.cmdReady = 1;
+ write_tpm_reg(locality, TPM_CRB_CTRL_REQ, &reg_ctrl_request);
+
+ return true;
+ }
+
+ reg_ctrl_request._raw[0] = 0;
+ reg_ctrl_request.goIdle = 1;
+ write_tpm_reg(locality, TPM_CRB_CTRL_REQ, &reg_ctrl_request);
+
+ uint32_t i = 0;
+ do {
+ read_tpm_reg(locality, TPM_CRB_CTRL_REQ, &reg_ctrl_request);
+ if ( reg_ctrl_request.goIdle == 0)
+ break;
+ else {
+ cpu_relax();
+ read_tpm_reg(locality, TPM_CRB_CTRL_REQ, &reg_ctrl_request);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_INFO"1. reg_ctrl_request.goIdle: 0x%x\n", reg_ctrl_request.goIdle);
+ printk(TBOOT_INFO"1. reg_ctrl_request.cmdReady: 0x%x\n", reg_ctrl_request.cmdReady);
+#endif
+
+ }
+ i++;
+ } while ( i <= TPM_DATA_AVAIL_TIME_OUT);
+
+ if ( i > TPM_DATA_AVAIL_TIME_OUT ) {
+ printk(TBOOT_ERR"TPM: reg_ctrl_request.goidle timeout!\n");
+ return false;
+ }
+
+ read_tpm_reg(locality, TPM_CRB_CTRL_STS, &reg_ctrl_sts);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_INFO"2. reg_ctrl_sts.tpmidle: 0x%x\n", reg_ctrl_sts.tpmidle);
+ printk(TBOOT_INFO"2. reg_ctrl_sts.tpmsts: 0x%x\n", reg_ctrl_sts.tpmsts);
+#endif
+
+ reg_ctrl_request._raw[0] = 0;
+ reg_ctrl_request.cmdReady = 1;
+ write_tpm_reg(locality, TPM_CRB_CTRL_REQ, &reg_ctrl_request);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_INFO"2. reg_ctrl_request.goIdle: 0x%x\n", reg_ctrl_request.goIdle);
+ printk(TBOOT_INFO"2. reg_ctrl_request.cmdReady: 0x%x\n", reg_ctrl_request.cmdReady);
+#endif
+
+ read_tpm_reg(locality, TPM_CRB_CTRL_STS, &reg_ctrl_sts);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_INFO"2. reg_ctrl_sts.tpmidle: 0x%x\n", reg_ctrl_sts.tpmidle);
+ printk(TBOOT_INFO"2. reg_ctrl_sts.tpmsts: 0x%x\n", reg_ctrl_sts.tpmsts);
+#endif
+
+ return true;
+
+}
+
+static bool tpm_check_cmd_ready_status_crb(uint32_t locality)
+{
+ tpm_reg_ctrl_request_t reg_ctrl_request;
+ read_tpm_reg(locality, TPM_CRB_CTRL_REQ, &reg_ctrl_request);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_INFO"3. reg_ctrl_request.goIdle: 0x%x\n", reg_ctrl_request.goIdle);
+ printk(TBOOT_INFO"3. reg_ctrl_request.cmdReady: 0x%x\n", reg_ctrl_request.cmdReady);
+#endif
+
+ if ( reg_ctrl_request.cmdReady == 0)
+ return true;
+ else
+ return false;
+
+}
+
+static bool tpm_check_cmd_ready_status(uint32_t locality)
+{
+ read_tpm_sts_reg(locality);
+#ifdef TPM_TRACE
+ printk(TBOOT_INFO".");
+#endif
+ return g_reg_sts.command_ready;
+}
+
+static void tpm_print_status_register(void)
+{
+ if ( g_tpm_family == 0 )
+ {
+ printk(TBOOT_DETA"TPM: status reg content: %02x %02x %02x\n",
+ (uint32_t)g_reg_sts_12->_raw[0],
+ (uint32_t)g_reg_sts_12->_raw[1],
+ (uint32_t)g_reg_sts_12->_raw[2]);
+ }
+ else
+ {
+ printk(TBOOT_DETA"TPM: status reg content: %02x %02x %02x %02x\n",
+ (uint32_t)g_reg_sts_20->_raw[0],
+ (uint32_t)g_reg_sts_20->_raw[1],
+ (uint32_t)g_reg_sts_20->_raw[2],
+ (uint32_t)g_reg_sts_20->_raw[3]);
+ }
+}
+
+static u16 tpm_get_burst_count(uint32_t locality)
+{
+ read_tpm_sts_reg(locality);
+ return g_reg_sts.burst_count;
+}
+
+static bool tpm_check_expect_status(uint32_t locality)
+{
+ read_tpm_sts_reg(locality);
+#ifdef TPM_TRACE
+ printk(TBOOT_INFO"Wait on Expect = 0, Status register %02x\n", g_reg_sts._raw[0]);
+#endif
+ return g_reg_sts.sts_valid == 1 && g_reg_sts.expect == 0;
+}
+
+static bool tpm_check_da_status(uint32_t locality)
+{
+ read_tpm_sts_reg(locality);
+#ifdef TPM_TRACE
+ printk(TBOOT_INFO"Waiting for DA Flag, Status register %02x\n", g_reg_sts._raw[0]);
+#endif
+ return g_reg_sts.sts_valid == 1 && g_reg_sts.data_avail == 1;
+}
+
+static void tpm_execute_cmd(uint32_t locality)
+{
+ memset((void *)&g_reg_sts, 0, sizeof(g_reg_sts));
+ g_reg_sts.tpm_go = 1;
+ write_tpm_sts_reg(locality);
+}
+
+bool tpm_validate_locality(uint32_t locality)
+{
+ uint32_t i;
+ tpm_reg_access_t reg_acc;
+
+ for ( i = TPM_VALIDATE_LOCALITY_TIME_OUT; i > 0; i-- ) {
+ /*
+ * TCG spec defines reg_acc.tpm_reg_valid_sts bit to indicate whether
+ * other bits of access reg are valid.( but this bit will also be 1
+ * while this locality is not available, so check seize bit too)
+ * It also defines that reading reg_acc.seize should always return 0
+ */
+ read_tpm_reg(locality, TPM_REG_ACCESS, &reg_acc);
+ if ( reg_acc.tpm_reg_valid_sts == 1 && reg_acc.seize == 0)
+ return true;
+ cpu_relax();
+ }
+ if ( i <= 0 )
+ printk(TBOOT_ERR"TPM: tpm_validate_locality timeout\n");
+
+ return false;
+}
+
+bool tpm_validate_locality_crb(uint32_t locality)
+{
+ uint32_t i;
+ tpm_reg_loc_state_t reg_loc_state;
+
+ for ( i = TPM_VALIDATE_LOCALITY_TIME_OUT; i > 0; i-- ) {
+ /*
+ * Platfrom Tpm Profile for TPM 2.0 SPEC
+ */
+ read_tpm_reg(locality, TPM_REG_LOC_STATE, &reg_loc_state);
+ if ( reg_loc_state.tpm_reg_valid_sts == 1 && reg_loc_state.loc_assigned == 1 && reg_loc_state.active_locality == locality) {
+ printk(TBOOT_INFO"TPM: reg_loc_state._raw[0]: 0x%x\n", reg_loc_state._raw[0]);
+ return true;
+ }
+ cpu_relax();
+ }
+
+ printk(TBOOT_ERR"TPM: tpm_validate_locality_crb timeout\n");
+ printk(TBOOT_INFO"TPM: reg_loc_state._raw[0]: 0x%x\n", reg_loc_state._raw[0]);
+ return false;
+}
+
+
+bool tpm_wait_cmd_ready(uint32_t locality)
+{
+ uint32_t i;
+ tpm_reg_access_t reg_acc;
+
+#if 0 /* some tpms doesn't always return 1 for reg_acc.tpm_reg_valid_sts */
+ /* and this bit was checked in tpm_validate_locality() already, */
+ /* so safe to skip the check here */
+ /* ensure the contents of the ACCESS register are valid */
+ read_tpm_reg(locality, TPM_REG_ACCESS, &reg_acc);
+#ifdef TPM_TRACE
+ printk(TBOOT_INFO"TPM: Access reg content: 0x%02x\n", (uint32_t)reg_acc._raw[0]);
+#endif
+ if ( reg_acc.tpm_reg_valid_sts == 0 ) {
+ printk(TBOOT_ERR"TPM: Access reg not valid\n");
+ return false;
+ }
+#endif
+ /* request access to the TPM from locality N */
+ reg_acc._raw[0] = 0;
+ reg_acc.request_use = 1;
+ write_tpm_reg(locality, TPM_REG_ACCESS, &reg_acc);
+
+ i = 0;
+ do {
+ read_tpm_reg(locality, TPM_REG_ACCESS, &reg_acc);
+ if ( reg_acc.active_locality == 1 )
+ break;
+ else
+ cpu_relax();
+ i++;
+ } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT);
+
+ if ( i > TPM_ACTIVE_LOCALITY_TIME_OUT ) {
+ printk(TBOOT_ERR"TPM: FIFO_INF access reg request use timeout\n");
+ return false;
+ }
+
+ /* ensure the TPM is ready to accept a command */
+#ifdef TPM_TRACE
+ printk(TBOOT_INFO"TPM: wait for cmd ready \n");
+#endif
+ i = 0;
+ do {
+ tpm_send_cmd_ready_status(locality);
+ cpu_relax();
+ /* then see if it has */
+
+ if ( tpm_check_cmd_ready_status(locality) )
+ break;
+ else
+ cpu_relax();
+ i++;
+ } while ( i <= TPM_CMD_READY_TIME_OUT );
+#ifdef TPM_TRACE
+ printk(TBOOT_INFO"\n");
+#endif
+
+ if ( i > TPM_CMD_READY_TIME_OUT ) {
+ tpm_print_status_register();
+ printk(TBOOT_INFO"TPM: tpm timeout for command_ready\n");
+ goto RelinquishControl;
+ }
+
+ return true;
+
+RelinquishControl:
+ /* deactivate current locality */
+ reg_acc._raw[0] = 0;
+ reg_acc.active_locality = 1;
+ write_tpm_reg(locality, TPM_REG_ACCESS, &reg_acc);
+
+ return false;
+}
+
+static bool tpm_wait_cmd_ready_crb(uint32_t locality)
+{
+ uint32_t i;
+
+ /* ensure the TPM is ready to accept a command */
+#ifdef TPM_TRACE
+ printk(TBOOT_INFO"TPM: wait for cmd ready \n");
+#endif
+ tpm_send_cmd_ready_status_crb(locality);
+ i = 0;
+ do {
+ if ( tpm_check_cmd_ready_status_crb(locality) )
+ break;
+ else
+ cpu_relax();
+ i++;
+ } while ( i <= TPM_CMD_READY_TIME_OUT );
+
+ if ( i > TPM_CMD_READY_TIME_OUT ) {
+ //tpm_print_status_register();
+ printk(TBOOT_INFO"TPM: tpm timeout for command_ready\n");
+ goto RelinquishControl;
+ }
+
+ return true;
+
+RelinquishControl:
+ /* deactivate current locality */
+ //tpm_reg_loc_ctrl_t reg_loc_ctrl;
+ //reg_loc_ctrl._raw[0] = 0;
+ //reg_loc_ctrl.relinquish = 1;
+ //write_tpm_reg(locality, TPM_REG_LOC_CTRL, &reg_loc_ctrl);
+
+ return false;
+}
+
+bool tpm_submit_cmd(u32 locality, u8 *in, u32 in_size, u8 *out, u32 *out_size)
+{
+ u32 i, rsp_size, offset;
+ u16 row_size;
+ tpm_reg_access_t reg_acc;
+ bool ret = true;
+
+ if ( locality >= TPM_NR_LOCALITIES ) {
+ printk(TBOOT_WARN"TPM: Invalid locality for tpm_write_cmd_fifo()\n");
+ return false;
+ }
+ if ( in == NULL || out == NULL || out_size == NULL ) {
+ printk(TBOOT_WARN"TPM: Invalid parameter for tpm_write_cmd_fifo()\n");
+ return false;
+ }
+ if ( in_size < CMD_HEAD_SIZE || *out_size < RSP_HEAD_SIZE ) {
+ printk(TBOOT_WARN"TPM: in/out buf size must be larger than 10 bytes\n");
+ return false;
+ }
+
+ if ( !tpm_validate_locality(locality) ) {
+ printk(TBOOT_WARN"TPM: Locality %d is not open\n", locality);
+ return false;
+ }
+
+ if ( !tpm_wait_cmd_ready(locality) ) return false;
+
+#ifdef TPM_TRACE
+ {
+ printk(TBOOT_DETA"TPM: cmd size = 0x%x\nTPM: cmd content: ", in_size);
+ print_hex("TPM: \t", in, in_size);
+ }
+#endif
+
+ /* write the command to the TPM FIFO */
+ offset = 0;
+ do {
+ i = 0;
+ do {
+ /* find out how many bytes the TPM can accept in a row */
+ row_size = tpm_get_burst_count(locality);
+ if ( row_size > 0 ) break;
+ else cpu_relax();
+ i++;
+ } while ( i <= TPM_CMD_WRITE_TIME_OUT );
+ if ( i > TPM_CMD_WRITE_TIME_OUT ) {
+ printk(TBOOT_ERR"TPM: write cmd timeout\n");
+ ret = false;
+ goto RelinquishControl;
+ }
+
+ for ( ; row_size > 0 && offset < in_size; row_size--, offset++ ) write_tpm_reg(locality, TPM_REG_DATA_FIFO, (tpm_reg_data_fifo_t *)&in[offset]);
+ } while ( offset < in_size );
+
+ i = 0;
+ do {
+ if ( tpm_check_expect_status(locality) ) break;
+ else cpu_relax();
+ i++;
+ } while ( i <= TPM_DATA_AVAIL_TIME_OUT );
+ if ( i > TPM_DATA_AVAIL_TIME_OUT ) {
+ printk(TBOOT_ERR"TPM: wait for expect becoming 0 timeout\n");
+ ret = false;
+ goto RelinquishControl;
+ }
+
+ /* command has been written to the TPM, it is time to execute it. */
+ tpm_execute_cmd(locality);
+
+ /* check for data available */
+ i = 0;
+ do {
+ if ( tpm_check_da_status(locality) ) break;
+ else cpu_relax();
+ i++;
+ } while ( i <= TPM_DATA_AVAIL_TIME_OUT );
+ if ( i > TPM_DATA_AVAIL_TIME_OUT ) {
+ printk(TBOOT_ERR"TPM: wait for data available timeout\n");
+ ret = false;
+ goto RelinquishControl;
+ }
+
+ rsp_size = 0;
+ offset = 0;
+ do {
+ /* find out how many bytes the TPM returned in a row */
+ i = 0;
+ do {
+ row_size = tpm_get_burst_count(locality);
+ if ( row_size > 0 ) break;
+ else cpu_relax();
+ i++;
+ } while ( i <= TPM_RSP_READ_TIME_OUT );
+ if ( i > TPM_RSP_READ_TIME_OUT ) {
+ printk(TBOOT_ERR"TPM: read rsp timeout\n");
+ ret = false;
+ goto RelinquishControl;
+ }
+
+ for ( ; row_size > 0 && offset < *out_size; row_size--, offset++ ) {
+ if ( offset < *out_size ) read_tpm_reg(locality, TPM_REG_DATA_FIFO, (tpm_reg_data_fifo_t *)&out[offset]);
+ else {
+ /* discard the responded bytes exceeding out buf size */
+ tpm_reg_data_fifo_t discard;
+ read_tpm_reg(locality, TPM_REG_DATA_FIFO, (tpm_reg_data_fifo_t *)&discard);
+ }
+
+ /* get outgoing data size */
+ if ( offset == RSP_RST_OFFSET - 1 ) {
+ reverse_copy(&rsp_size, &out[RSP_SIZE_OFFSET], sizeof(rsp_size));
+ }
+ }
+ } while ( offset < RSP_RST_OFFSET || (offset < rsp_size && offset < *out_size) );
+
+ *out_size = (*out_size > rsp_size) ? rsp_size : *out_size;
+
+#ifdef TPM_TRACE
+ {
+ printk(TBOOT_INFO"TPM: response size = %d\n", *out_size);
+ printk(TBOOT_DETA"TPM: response content: ");
+ print_hex("TPM: \t", out, *out_size);
+ }
+#endif
+
+ tpm_send_cmd_ready_status(locality);
+
+RelinquishControl:
+ /* deactivate current locality */
+ reg_acc._raw[0] = 0;
+ reg_acc.active_locality = 1;
+ write_tpm_reg(locality, TPM_REG_ACCESS, &reg_acc);
+
+ return ret;
+}
+
+
+bool tpm_submit_cmd_crb(u32 locality, u8 *in, u32 in_size, u8 *out, u32 *out_size)
+{
+ uint32_t i;
+
+ bool ret = true;
+
+ //tpm_reg_loc_ctrl_t reg_loc_ctrl;
+ tpm_reg_ctrl_start_t start;
+
+ tpm_reg_ctrl_cmdsize_t CmdSize;
+ tpm_reg_ctrl_cmdaddr_t CmdAddr;
+ tpm_reg_ctrl_rspsize_t RspSize;
+ tpm_reg_ctrl_rspaddr_t RspAddr;
+ uint32_t tpm_crb_data_buffer_base;
+
+ if ( locality >= TPM_NR_LOCALITIES ) {
+ printk(TBOOT_WARN"TPM: Invalid locality for tpm_submit_cmd_crb()\n");
+ return false;
+ }
+ if ( in == NULL || out == NULL || out_size == NULL ) {
+ printk(TBOOT_WARN"TPM: Invalid parameter for tpm_submit_cmd_crb()\n");
+ return false;
+ }
+ if ( in_size < CMD_HEAD_SIZE || *out_size < RSP_HEAD_SIZE ) {
+ printk(TBOOT_WARN"TPM: in/out buf size must be larger than 10 bytes\n");
+ return false;
+ }
+
+ if ( !tpm_validate_locality_crb(locality) ) {
+ printk(TBOOT_WARN"TPM: CRB Interface Locality %d is not open\n", locality);
+ return false;
+ }
+
+ if ( !tpm_wait_cmd_ready_crb(locality) ) {
+ printk(TBOOT_WARN"TPM: tpm_wait_cmd_read_crb failed\n");
+ return false;
+ }
+
+#ifdef TPM_TRACE
+ {
+ printk(TBOOT_DETA"TPM: Before submit, cmd size = 0x%x\nTPM: Before submit, cmd content: ", in_size);
+ print_hex("TPM: \t", in, in_size);
+ }
+#endif
+
+ /* write the command to the TPM CRB buffer 01-04-2016 */
+//copy *in and size to crb buffer
+
+
+
+ CmdAddr.cmdladdr = TPM_LOCALITY_CRB_BASE_N(locality) | TPM_CRB_DATA_BUFFER;
+ CmdAddr.cmdhaddr = 0;
+ RspAddr.rspaddr = TPM_LOCALITY_CRB_BASE_N(locality) | TPM_CRB_DATA_BUFFER;
+ CmdSize.cmdsize = TPMCRBBUF_LEN;
+ RspSize.rspsize = TPMCRBBUF_LEN;
+ tpm_crb_data_buffer_base = TPM_CRB_DATA_BUFFER;
+
+
+ #ifdef TPM_TRACE
+ printk(TBOOT_INFO"CmdAddr.cmdladdr is 0x%x\n",CmdAddr.cmdladdr);
+ printk(TBOOT_INFO"CmdAddr.cmdhaddr is 0x%x\n",CmdAddr.cmdhaddr);
+
+ printk(TBOOT_INFO"CmdSize.cmdsize is 0x%x\n",CmdSize.cmdsize);
+ printk(TBOOT_INFO"RspAddr.rspaddr is 0x%Lx\n",RspAddr.rspaddr);
+ printk(TBOOT_INFO"RspSize.rspsize is 0x%x\n",RspSize.rspsize);
+
+#endif
+
+ write_tpm_reg(locality, TPM_CRB_CTRL_CMD_ADDR, &CmdAddr);
+ write_tpm_reg(locality, TPM_CRB_CTRL_CMD_SIZE, &CmdSize);
+ write_tpm_reg(locality, TPM_CRB_CTRL_RSP_ADDR, &RspAddr);
+ write_tpm_reg(locality, TPM_CRB_CTRL_RSP_SIZE, &RspSize);
+ // write the command to the buffer
+ for ( i = 0 ; i< in_size; i++ ) {
+ write_tpm_reg(locality, tpm_crb_data_buffer_base++, (tpm_reg_data_crb_t *)&in[i]);
+ //tpm_crb_data_buffer_base++;
+ }
+
+ /* command has been written to the TPM, it is time to execute it. */
+ start.start = 1;
+ write_tpm_reg(locality, TPM_CRB_CTRL_START, &start);
+ //read_tpm_reg(locality, TPM_CRB_CTRL_START, &start);
+ printk(TBOOT_INFO"tpm_ctrl_start.start is 0x%x\n",start.start);
+
+ /* check for data available */
+ i = 0;
+ do {
+ read_tpm_reg(locality, TPM_CRB_CTRL_START, &start);
+ //printk(TBOOT_INFO"tpm_ctrl_start.start is 0x%x\n",start.start);
+ if ( start.start == 0 ) break;
+ else cpu_relax();
+ i++;
+ } while ( i <= TPM_DATA_AVAIL_TIME_OUT );
+
+ if ( i > TPM_DATA_AVAIL_TIME_OUT ) {
+ printk(TBOOT_ERR"TPM: wait for data available timeout\n");
+ ret = false;
+ goto RelinquishControl;
+ }
+
+ tpm_crb_data_buffer_base = TPM_CRB_DATA_BUFFER;
+
+ for ( i = 0 ; i< *out_size; i++ ) {
+ read_tpm_reg(locality, tpm_crb_data_buffer_base++, (tpm_reg_data_crb_t *)&out[i]);
+ //tpm_crb_data_buffer_base++;
+ }
+
+
+
+#ifdef TPM_TRACE
+ {
+ printk(TBOOT_INFO"TPM: After cmd submit, response size = 0x%x\n", *out_size);
+ printk(TBOOT_DETA"TPM: After cmd submit, response content: ");
+ print_hex("TPM: \t", out, *out_size);
+ }
+#endif
+
+ //tpm_send_cmd_ready_status_crb(locality);
+
+RelinquishControl:
+ /* deactivate current locality */
+ // reg_loc_ctrl._raw[0] = 0;
+ //reg_loc_ctrl.relinquish = 1;
+ //write_tpm_reg(locality, TPM_REG_LOC_CTRL, &reg_loc_ctrl);
+
+ return ret;
+
+}
+
+
+bool release_locality(uint32_t locality)
+{
+ uint32_t i;
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: releasing locality %u\n", locality);
+#endif
+
+ if ( !tpm_validate_locality(locality) ) return true;
+
+ tpm_reg_access_t reg_acc;
+ read_tpm_reg(locality, TPM_REG_ACCESS, &reg_acc);
+ if ( reg_acc.active_locality == 0 ) return true;
+
+ /* make inactive by writing a 1 */
+ reg_acc._raw[0] = 0;
+ reg_acc.active_locality = 1;
+ write_tpm_reg(locality, TPM_REG_ACCESS, &reg_acc);
+
+ i = 0;
+ do {
+ read_tpm_reg(locality, TPM_REG_ACCESS, &reg_acc);
+ if ( reg_acc.active_locality == 0 )
+ return true;
+ else
+ cpu_relax();
+ i++;
+ } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT );
+
+ printk(TBOOT_INFO"TPM: access reg release locality timeout\n");
+ return false;
+}
+
+bool tpm_relinquish_locality_crb(uint32_t locality)
+{
+ uint32_t i;
+ tpm_reg_loc_state_t reg_loc_state;
+ tpm_reg_loc_ctrl_t reg_loc_ctrl;
+
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: releasing CRB_INF locality %u\n", locality);
+#endif
+
+ if ( !tpm_validate_locality_crb(locality) ) return true;
+ read_tpm_reg(locality, TPM_REG_LOC_STATE, &reg_loc_state);
+ if ( reg_loc_state.loc_assigned == 0 ) return true;
+
+ /* make inactive by writing a 1 */
+ reg_loc_ctrl._raw[0] = 0;
+ reg_loc_ctrl.relinquish = 1;
+ write_tpm_reg(locality, TPM_REG_LOC_CTRL, &reg_loc_ctrl);
+
+ i = 0;
+ do {
+ read_tpm_reg(locality, TPM_REG_LOC_STATE, &reg_loc_state);
+ if ( reg_loc_state.loc_assigned == 0 ) return true;
+ else cpu_relax();
+ i++;
+ } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT );
+
+ printk(TBOOT_INFO"TPM: CRB_INF release locality timeout\n");
+ return false;
+}
+
+
+
+bool is_tpm_crb(void)
+{
+ tpm_crb_interface_id_t crb_interface;
+ read_tpm_reg(0, TPM_INTERFACE_ID, &crb_interface);
+ if (crb_interface.interface_type == TPM_INTERFACE_ID_CRB ) {
+ printk(TBOOT_INFO"TPM: PTP CRB interface is active...\n");
+ if (g_tpm_family != TPM_IF_20_CRB ) g_tpm_family = TPM_IF_20_CRB;
+ return true;
+ }
+ if (crb_interface.interface_type == TPM_INTERFACE_ID_FIFO_20) {
+ printk(TBOOT_INFO"TPM: TPM 2.0 FIFO interface is active...\n");
+ if (g_tpm_family != TPM_IF_20_FIFO) g_tpm_family = TPM_IF_20_FIFO;
+ }
+ return false;
+}
+
+
+bool prepare_tpm(void)
+{
+ /*
+ * must ensure TPM_ACCESS_0.activeLocality bit is clear
+ * (: locality is not active)
+ */
+ if (is_tpm_crb())
+// return release_locality_crb(0);
+ return true;
+ else
+ return release_locality(0);
+}
+
+bool tpm_request_locality_crb(uint32_t locality){
+
+ uint32_t i;
+ tpm_reg_loc_state_t reg_loc_state;
+ tpm_reg_loc_ctrl_t reg_loc_ctrl;
+ /* request access to the TPM from locality N */
+ reg_loc_ctrl._raw[0] = 0;
+ reg_loc_ctrl.requestAccess = 1;
+ write_tpm_reg(locality, TPM_REG_LOC_CTRL, &reg_loc_ctrl);
+
+ i = 0;
+ do {
+ read_tpm_reg(locality, TPM_REG_LOC_STATE, &reg_loc_state);
+ if ( reg_loc_state.active_locality == locality && reg_loc_state.loc_assigned == 1)
+ break;
+ else
+ cpu_relax();
+ i++;
+ } while ( i <= TPM_ACTIVE_LOCALITY_TIME_OUT);
+
+ if ( i > TPM_ACTIVE_LOCALITY_TIME_OUT ) {
+ printk(TBOOT_ERR"TPM: access loc request use timeout\n");
+ return false;
+ }
+
+ return true;
+
+}
+
+bool tpm_workaround_crb(void)
+{
+ tpm_reg_ctrl_cmdsize_t CmdSize;
+ tpm_reg_ctrl_cmdaddr_t CmdAddr;
+ tpm_reg_ctrl_rspsize_t RspSize;
+ tpm_reg_ctrl_rspaddr_t RspAddr;
+ u32 locality = 0;
+
+ if (!tpm_request_locality_crb(locality))
+ return false;
+
+ CmdAddr.cmdladdr = TPM_LOCALITY_CRB_BASE_N(locality) | TPM_CRB_DATA_BUFFER;
+ CmdAddr.cmdhaddr = 0;
+ RspAddr.rspaddr = TPM_LOCALITY_CRB_BASE_N(locality) | TPM_CRB_DATA_BUFFER;
+ CmdSize.cmdsize = TPMCRBBUF_LEN;
+ RspSize.rspsize = TPMCRBBUF_LEN;
+
+ write_tpm_reg(locality, TPM_CRB_CTRL_CMD_ADDR, &CmdAddr);
+ write_tpm_reg(locality, TPM_CRB_CTRL_CMD_SIZE, &CmdSize);
+ write_tpm_reg(locality, TPM_CRB_CTRL_RSP_ADDR, &RspAddr);
+ write_tpm_reg(locality, TPM_CRB_CTRL_RSP_SIZE, &RspSize);
+
+ return true;
+}
+
+bool tpm_detect(void)
+{
+ if (is_tpm_crb()) {
+ printk(TBOOT_INFO"TPM: This is Intel PTT, TPM Family 0x%d\n", g_tpm_family);
+ if (!txt_is_launched()) {
+ if ( tpm_validate_locality_crb(0) )
+ printk(TBOOT_INFO"TPM: CRB_INF Locality 0 is open\n");
+ else {
+ printk(TBOOT_INFO"TPM: CRB_INF request access to Locality 0...\n");
+ if (!tpm_request_locality_crb(0)) {
+ printk(TBOOT_ERR"TPM: CRB_INF Locality 0 request failed...\n");
+ return false;
+ }
+ }
+ }
+ else {
+ if ( tpm_validate_locality_crb(2) )
+ printk(TBOOT_INFO"TPM: CRB_INF Locality 2 is open\n");
+ else {
+ printk(TBOOT_INFO"TPM: CRB_INF request access to Locality 2...\n");
+ if (!tpm_request_locality_crb(2)) {
+ printk(TBOOT_ERR"TPM: CRB_INF Locality 2 request failed...\n");
+ return false;
+ }
+ }
+ }
+ }
+ else {
+ g_tpm = &tpm_12_if; /* Don't leave g_tpm as NULL*/
+ if ( tpm_validate_locality(0) ) printk(TBOOT_INFO"TPM: FIFO_INF Locality 0 is open\n");
+ else {
+ printk(TBOOT_ERR"TPM: FIFO_INF Locality 0 is not open\n");
+ return false;
+ }
+ /* determine TPM family from command check */
+ if ( g_tpm->check() ) {
+ g_tpm_family = TPM_IF_12;
+ printk(TBOOT_INFO"TPM: discrete TPM1.2 Family 0x%d\n", g_tpm_family);
+ }
+ else {
+ g_tpm_family = TPM_IF_20_FIFO;
+ printk(TBOOT_INFO"TPM: discrete TPM2.0 Family 0x%d\n", g_tpm_family);
+ }
+ }
+
+ if (g_tpm_family == TPM_IF_12) g_tpm = &tpm_12_if;
+ if (g_tpm_family == TPM_IF_20_FIFO) g_tpm = &tpm_20_if;
+ if (g_tpm_family == TPM_IF_20_CRB) g_tpm = &tpm_20_if;
+
+ /* if (!txt_is_launched())
+ g_tpm->cur_loc = 0;
+ else
+ g_tpm->cur_loc = 2;
+
+ g_tpm->timeout.timeout_a = TIMEOUT_A;
+ g_tpm->timeout.timeout_b = TIMEOUT_B;
+ g_tpm->timeout.timeout_c = TIMEOUT_C;
+ g_tpm->timeout.timeout_d = TIMEOUT_D;
+*/
+ return g_tpm->init(g_tpm);
+}
+
+void tpm_print(struct tpm_if *ti)
+{
+ if ( ti == NULL )
+ return;
+
+ printk(TBOOT_INFO"TPM attribute:\n");
+ printk(TBOOT_INFO"\t extend policy: %d\n", ti->extpol);
+ printk(TBOOT_INFO"\t current alg id: 0x%x\n", ti->cur_alg);
+ printk(TBOOT_INFO"\t timeout values: A: %u, B: %u, C: %u, D: %u\n", ti->timeout.timeout_a, ti->timeout.timeout_b, ti->timeout.timeout_c, ti->timeout.timeout_d);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/tpm_12.c b/tboot/tpm_12.c
new file mode 100644
index 0000000..6e326d1
--- /dev/null
+++ b/tboot/tpm_12.c
@@ -0,0 +1,1952 @@
+/*
+ * tpm_12.c: TPM1.2-related support functions
+ *
+ * Copyright (c) 2006-2013, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <printk.h>
+#include <misc.h>
+#include <compiler.h>
+#include <processor.h>
+#include <io.h>
+#include <string.h>
+#include <tpm.h>
+#include <sha1.h>
+#include <integrity.h>
+
+/*
+ * return code:
+ * The TPM has five types of return code. One indicates successful operation
+ * and four indicate failure.
+ * TPM_SUCCESS (00000000) indicates successful execution.
+ * The failure reports are:
+ * TPM defined fatal errors (00000001 to 000003FF)
+ * vendor defined fatal errors (00000400 to 000007FF)
+ * TPM defined non-fatal errors (00000800 to 00000BFF)
+ * vendor defined non-fatal errors (00000C00 to 00000FFF).
+ * Here only give definitions for a few commonly used return code.
+ */
+#define TPM_BASE 0x00000000
+#define TPM_NON_FATAL 0x00000800
+#define TPM_SUCCESS TPM_BASE
+#define TPM_BADINDEX (TPM_BASE + 2)
+#define TPM_BAD_PARAMETER (TPM_BASE + 3)
+#define TPM_DEACTIVATED (TPM_BASE + 6)
+#define TPM_DISABLED (TPM_BASE + 7)
+#define TPM_FAIL (TPM_BASE + 9)
+#define TPM_BAD_ORDINAL (TPM_BASE + 10)
+#define TPM_NOSPACE (TPM_BASE + 17)
+#define TPM_NOTRESETABLE (TPM_BASE + 50)
+#define TPM_NOTLOCAL (TPM_BASE + 51)
+#define TPM_BAD_LOCALITY (TPM_BASE + 61)
+#define TPM_READ_ONLY (TPM_BASE + 62)
+#define TPM_NOT_FULLWRITE (TPM_BASE + 70)
+#define TPM_RETRY (TPM_BASE + TPM_NON_FATAL)
+
+typedef uint8_t tpm_locality_selection_t;
+#define TPM_LOC_ZERO 0x01
+#define TPM_LOC_ONE 0x02
+#define TPM_LOC_TWO 0x04
+#define TPM_LOC_THREE 0x08
+#define TPM_LOC_FOUR 0x10
+#define TPM_LOC_RSVD 0xE0
+
+/* ~5 secs are required for Infineon that requires this, so leave some extra */
+#define MAX_SAVESTATE_RETRIES 60
+
+#define TPM_TAG_RQU_COMMAND 0x00C1
+#define TPM_TAG_RQU_AUTH1_COMMAND 0x00C2
+#define TPM_TAG_RQU_AUTH2_COMMAND 0x00C3
+#define TPM_ORD_PCR_EXTEND 0x00000014
+#define TPM_ORD_PCR_READ 0x00000015
+#define TPM_ORD_PCR_RESET 0x000000C8
+#define TPM_ORD_NV_READ_VALUE 0x000000CF
+#define TPM_ORD_NV_WRITE_VALUE 0x000000CD
+#define TPM_ORD_GET_CAPABILITY 0x00000065
+#define TPM_ORD_SEAL 0x00000017
+#define TPM_ORD_UNSEAL 0x00000018
+#define TPM_ORD_OSAP 0x0000000B
+#define TPM_ORD_OIAP 0x0000000A
+#define TPM_ORD_SAVE_STATE 0x00000098
+#define TPM_ORD_GET_RANDOM 0x00000046
+
+#define TPM_TAG_PCR_INFO_LONG 0x0006
+#define TPM_TAG_STORED_DATA12 0x0016
+
+/*
+ * specified as minimum cmd buffer size should be supported by all 1.2 TPM
+ * device in the TCG_PCClientTPMSpecification_1-20_1-00_FINAL.pdf
+ */
+#define TPM_CMD_SIZE_MAX 768
+#define TPM_RSP_SIZE_MAX 768
+
+/*
+ * The _tpm12_submit_cmd function comes with 2 global buffers: cmd_buf & rsp_buf.
+ * Before calling, caller should fill cmd arguements into cmd_buf via
+ * WRAPPER_IN_BUF macro. After calling, caller should fetch result from
+ * rsp_buffer via WRAPPER_OUT_BUF macro.
+ * cmd_buf content:
+ * 0 1 2 3 4 5 6 7 8 9 10 ...
+ * -------------------------------------------------------------
+ * | TAG | SIZE | ORDINAL | arguments ...
+ * -------------------------------------------------------------
+ * rsp_buf content:
+ * 0 1 2 3 4 5 6 7 8 9 10 ...
+ * -------------------------------------------------------------
+ * | TAG | SIZE | RETURN CODE | other data ...
+ * -------------------------------------------------------------
+ *
+ * locality : TPM locality (0 - 4)
+ * tag : The TPM command tag
+ * cmd : The TPM command ordinal
+ * arg_size : Size of argument data.
+ * out_size : IN/OUT paramter. The IN is the expected size of out data;
+ * the OUT is the size of output data within out buffer.
+ * The out_size MUST NOT be NULL.
+ * return : TPM_SUCCESS for success, for other error code, refer to the .h
+ */
+static uint8_t cmd_buf[TPM_CMD_SIZE_MAX];
+static uint8_t rsp_buf[TPM_RSP_SIZE_MAX];
+#define WRAPPER_IN_BUF (cmd_buf + CMD_HEAD_SIZE)
+#define WRAPPER_OUT_BUF (rsp_buf + RSP_HEAD_SIZE)
+#define WRAPPER_IN_MAX_SIZE (TPM_CMD_SIZE_MAX - CMD_HEAD_SIZE)
+#define WRAPPER_OUT_MAX_SIZE (TPM_RSP_SIZE_MAX - RSP_HEAD_SIZE)
+
+static uint32_t _tpm12_submit_cmd(uint32_t locality, uint16_t tag, uint32_t cmd, uint32_t arg_size, uint32_t *out_size)
+{
+ uint32_t ret;
+ uint32_t cmd_size, rsp_size = 0;
+
+ if ( out_size == NULL ) {
+ printk(TBOOT_WARN"TPM: invalid param for _tpm12_submit_cmd()\n");
+ return TPM_BAD_PARAMETER;
+ }
+
+ /*
+ * real cmd size should add 10 more bytes:
+ * 2 bytes for tag
+ * 4 bytes for size
+ * 4 bytes for ordinal
+ */
+ cmd_size = CMD_HEAD_SIZE + arg_size;
+
+ if ( cmd_size > TPM_CMD_SIZE_MAX ) {
+ printk(TBOOT_WARN"TPM: cmd exceeds the max supported size.\n");
+ return TPM_BAD_PARAMETER;
+ }
+
+ /* copy tag, size & ordinal into buf in a reversed byte order */
+ reverse_copy(cmd_buf, &tag, sizeof(tag));
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+ reverse_copy(cmd_buf + CMD_CC_OFFSET, &cmd, sizeof(cmd));
+
+ rsp_size = RSP_HEAD_SIZE + *out_size;
+ rsp_size = (rsp_size > TPM_RSP_SIZE_MAX) ? TPM_RSP_SIZE_MAX: rsp_size;
+ if ( !tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size) ) return TPM_FAIL;
+
+ /*
+ * should subtract 10 bytes from real response size:
+ * 2 bytes for tag
+ * 4 bytes for size
+ * 4 bytes for return code
+ */
+ rsp_size -= (rsp_size > RSP_HEAD_SIZE) ? RSP_HEAD_SIZE : rsp_size;
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(uint32_t));
+ if ( ret != TPM_SUCCESS ) return ret;
+
+ if ( *out_size == 0 || rsp_size == 0 ) *out_size = 0;
+ else
+ *out_size = (rsp_size < *out_size) ? rsp_size : *out_size;
+
+ return ret;
+}
+
+static inline uint32_t tpm12_submit_cmd(uint32_t locality, uint32_t cmd, uint32_t arg_size, uint32_t *out_size)
+{
+ return _tpm12_submit_cmd(locality, TPM_TAG_RQU_COMMAND, cmd, arg_size, out_size);
+}
+
+static inline uint32_t tpm12_submit_cmd_auth1(uint32_t locality, uint32_t cmd,
+ uint32_t arg_size, uint32_t *out_size)
+{
+ return _tpm12_submit_cmd(locality, TPM_TAG_RQU_AUTH1_COMMAND, cmd,
+ arg_size, out_size);
+}
+
+static inline uint32_t tpm12_submit_cmd_auth2(uint32_t locality, uint32_t cmd,
+ uint32_t arg_size, uint32_t *out_size)
+{
+ return _tpm12_submit_cmd(locality, TPM_TAG_RQU_AUTH2_COMMAND, cmd,
+ arg_size, out_size);
+}
+
+typedef struct __packed {
+ uint8_t digest[SHA1_LENGTH];
+} tpm12_digest_t;
+
+#define TPM_NR_PCRS 24
+static bool tpm12_pcr_read(struct tpm_if *ti, uint32_t locality,
+ uint32_t pcr, tpm_pcr_value_t *out)
+{
+ uint32_t ret, out_size = sizeof(*out);
+
+ if ( out == NULL || pcr >= TPM_NR_PCRS) {
+ ti->error = TPM_BAD_PARAMETER;
+ return false;
+ }
+
+ /* copy pcr into buf in reversed byte order */
+ reverse_copy(WRAPPER_IN_BUF, &pcr, sizeof(pcr));
+
+ ret = tpm12_submit_cmd(locality, TPM_ORD_PCR_READ, sizeof(pcr), &out_size);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: Pcr %d Read return value = %08X\n", pcr, ret);
+#endif
+ if ( ret != TPM_SUCCESS ) {
+ printk(TBOOT_DETA"TPM: Pcr %d Read return value = %08X\n", pcr, ret);
+ ti->error = ret;
+ return false;
+ }
+
+ if ( out_size > sizeof(*out) )
+ out_size = sizeof(*out);
+ memcpy((void *)out, WRAPPER_OUT_BUF, out_size);
+
+#ifdef TPM_TRACE
+ {
+ printk(TBOOT_INFO"TPM: ");
+ print_hex(NULL, ((tpm12_digest_t *)out)->digest, out_size);
+ }
+#endif
+
+ return true;
+}
+
+static bool _tpm12_pcr_extend(struct tpm_if *ti, uint32_t locality,
+ uint32_t pcr, const tpm_digest_t* in)
+{
+ uint32_t ret, in_size = 0, out_size;
+ tpm12_digest_t * out = NULL;
+
+ if ( ti == NULL )
+ return false;
+
+ if ( in == NULL || pcr >= TPM_NR_PCRS){
+ ti->error = TPM_BAD_PARAMETER;
+ return false;
+ }
+ if ( out == NULL )
+ out_size = 0;
+ else
+ out_size = sizeof(*out);
+
+ /* copy pcr into buf in reversed byte order, then copy in data */
+ reverse_copy(WRAPPER_IN_BUF, &pcr, sizeof(pcr));
+ in_size += sizeof(pcr);
+ memcpy(WRAPPER_IN_BUF + in_size, (void *)in, sizeof(*(tpm12_digest_t *)in));
+ in_size += sizeof(*(tpm12_digest_t *)in);
+
+ ret = tpm12_submit_cmd(locality, TPM_ORD_PCR_EXTEND, in_size, &out_size);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: Pcr %d extend, return value = %08X\n", pcr, ret);
+#endif
+ if ( ret != TPM_SUCCESS ) {
+ printk(TBOOT_DETA"TPM: Pcr %d extend, return value = %08X\n", pcr, ret);
+ ti->error = ret;
+ return false;
+ }
+
+ if ( out != NULL && out_size > 0 ) {
+ out_size = (out_size > sizeof(*out)) ? sizeof(*out) : out_size;
+ memcpy((void *)out, WRAPPER_OUT_BUF, out_size);
+ }
+
+#ifdef TPM_TRACE
+ {
+ printk(TBOOT_INFO"TPM: ");
+ print_hex(NULL, out->digest, out_size);
+ }
+#endif
+
+ return true;
+}
+
+static bool tpm12_pcr_extend(struct tpm_if *ti, uint32_t locality,
+ uint32_t pcr, const hash_list_t *in)
+{
+ tpm_digest_t digest;
+
+ if ( ti == NULL )
+ return false;
+
+ if ( in == NULL || in->count != 1 ||
+ in->entries[0].alg != TB_HALG_SHA1 ) {
+ ti->error = TPM_BAD_PARAMETER;
+ return false;
+ }
+
+ digest = in->entries[0].hash;
+
+ return _tpm12_pcr_extend(ti, locality, pcr, &digest);
+}
+
+typedef struct __packed {
+ uint16_t size_of_select;
+ uint8_t pcr_select[3];
+} tpm_pcr_selection_t;
+
+/* PCRs lower than 16 are not resetable */
+#define TPM_PCR_RESETABLE_MIN 16
+static bool tpm12_pcr_reset(struct tpm_if *ti, uint32_t locality, uint32_t pcr)
+{
+ uint32_t ret, in_size, out_size = 0;
+ uint16_t size_of_select;
+ tpm_pcr_selection_t pcr_sel = {0,{0,}};
+
+ if ( ti == NULL )
+ return false;
+
+ if ( pcr >= TPM_NR_PCRS || pcr < TPM_PCR_RESETABLE_MIN ) {
+ ti->error = TPM_BAD_PARAMETER;
+ return false;
+ }
+
+ /* the pcr_sel.pcr_select[size_of_select - 1] should not be 0 */
+ size_of_select = pcr / 8 + 1;
+ reverse_copy(&pcr_sel.size_of_select, &size_of_select,
+ sizeof(size_of_select));
+ pcr_sel.pcr_select[pcr / 8] = 1 << (pcr % 8);
+
+ in_size = sizeof(pcr_sel);
+ memcpy(WRAPPER_IN_BUF, (void *)&pcr_sel, in_size);
+
+ ret = tpm12_submit_cmd(locality, TPM_ORD_PCR_RESET, in_size, &out_size);
+ if ( ret != TPM_SUCCESS ) {
+ ti->error = ret;
+ return false;
+ }
+
+ printk(TBOOT_DETA"TPM: Pcr %d reset, return value = %08X\n", pcr, ret);
+
+ return true;
+}
+
+#define TPM_NV_READ_VALUE_DATA_SIZE_MAX (TPM_RSP_SIZE_MAX - 14)
+static bool tpm12_nv_read_value(struct tpm_if *ti, uint32_t locality,
+ uint32_t index, uint32_t offset,
+ uint8_t *data, uint32_t *data_size)
+{
+ uint32_t ret, in_size = 0, out_size;
+
+ if ( ti == NULL )
+ return false;
+
+ if ( data == NULL || data_size == NULL || *data_size == 0 ) {
+ ti->error = TPM_BAD_PARAMETER;
+ return false;
+ }
+ if ( *data_size > TPM_NV_READ_VALUE_DATA_SIZE_MAX )
+ *data_size = TPM_NV_READ_VALUE_DATA_SIZE_MAX;
+
+ /* copy the index, offset and *data_size into buf in reversed byte order */
+ reverse_copy(WRAPPER_IN_BUF, &index, sizeof(index));
+ in_size += sizeof(index);
+ reverse_copy(WRAPPER_IN_BUF + in_size, &offset, sizeof(offset));
+ in_size += sizeof(offset);
+ reverse_copy(WRAPPER_IN_BUF + in_size, data_size, sizeof(*data_size));
+ in_size += sizeof(*data_size);
+
+ out_size = *data_size + sizeof(*data_size);
+ ret = tpm12_submit_cmd(locality, TPM_ORD_NV_READ_VALUE, in_size, &out_size);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: read nv index %08x from offset %08x, return value = %08X\n",
+ index, offset, ret);
+#endif
+ if ( ret != TPM_SUCCESS ) {
+ printk(TBOOT_DETA"TPM: read nv index %08x offset %08x, return value = %08X\n",
+ index, offset, ret);
+ ti->error = ret;
+ return false;
+ }
+
+#ifdef TPM_TRACE
+ {
+ printk(TBOOT_INFO"TPM: ");
+ print_hex(NULL, WRAPPER_OUT_BUF, out_size);
+ }
+#endif
+
+ if ( out_size <= sizeof(*data_size) ) {
+ *data_size = 0;
+ return true;
+ }
+
+ out_size -= sizeof(*data_size);
+ reverse_copy(data_size, WRAPPER_OUT_BUF, sizeof(*data_size));
+ *data_size = (*data_size > out_size) ? out_size : *data_size;
+ if( *data_size > 0 )
+ memcpy(data, WRAPPER_OUT_BUF + sizeof(*data_size), *data_size);
+
+ return true;
+}
+
+#define TPM_NV_WRITE_VALUE_DATA_SIZE_MAX (TPM_CMD_SIZE_MAX - 22)
+static bool tpm12_nv_write_value(struct tpm_if *ti, uint32_t locality,
+ uint32_t index, uint32_t offset,
+ const uint8_t *data, uint32_t data_size)
+{
+ uint32_t ret, in_size = 0, out_size = 0;
+
+ if ( ti == NULL )
+ return false;
+
+ if ( data == NULL || data_size == 0
+ || data_size > TPM_NV_WRITE_VALUE_DATA_SIZE_MAX ) {
+ ti->error = TPM_BAD_PARAMETER;
+ return false;
+ }
+
+ /* copy index, offset and *data_size into buf in reversed byte order */
+ reverse_copy(WRAPPER_IN_BUF, &index, sizeof(index));
+ in_size += sizeof(index);
+ reverse_copy(WRAPPER_IN_BUF + in_size, &offset, sizeof(offset));
+ in_size += sizeof(offset);
+ reverse_copy(WRAPPER_IN_BUF + in_size, &data_size, sizeof(data_size));
+ in_size += sizeof(data_size);
+ memcpy(WRAPPER_IN_BUF + in_size, data, data_size);
+ in_size += data_size;
+
+ ret = tpm12_submit_cmd(locality, TPM_ORD_NV_WRITE_VALUE,
+ in_size, &out_size);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: write nv %08x, offset %08x, %08x bytes, return = %08X\n",
+ index, offset, data_size, ret);
+#endif
+ if ( ret != TPM_SUCCESS ) {
+ printk(TBOOT_DETA"TPM: write nv %08x, offset %08x, %08x bytes, return = %08X\n",
+ index, offset, data_size, ret);
+ ti->error = ret;
+ return false;
+ }
+
+ return true;
+}
+
+#define TPM_CAP_VERSION_VAL 0x1A
+
+typedef uint16_t tpm_structure_tag_t;
+
+typedef struct __packed {
+ uint8_t major;
+ uint8_t minor;
+ uint8_t rev_major;
+ uint8_t rev_minor;
+} tpm_version_t;
+
+typedef struct __packed {
+ tpm_structure_tag_t tag;
+ tpm_version_t version;
+ uint16_t specLevel;
+ uint8_t errataRev;
+ uint8_t tpmVendorID[4];
+ uint16_t vendorSpecificSize;
+ uint8_t vendorSpecific[];
+} tpm_cap_version_info_t;
+
+#define HMAC_BLOCK_SIZE 64
+#define HMAC_OUTPUT_SIZE 20
+
+static bool hmac(const uint8_t key[HMAC_OUTPUT_SIZE], const uint8_t *msg,
+ uint32_t len, uint8_t md[HMAC_OUTPUT_SIZE])
+{
+ uint8_t ipad[HMAC_BLOCK_SIZE], opad[HMAC_BLOCK_SIZE];
+ uint32_t i;
+ SHA_CTX ctx;
+
+ COMPILE_TIME_ASSERT(HMAC_OUTPUT_SIZE <= HMAC_BLOCK_SIZE);
+
+ for ( i = 0; i < HMAC_BLOCK_SIZE; i++ ) {
+ ipad[i] = 0x36;
+ opad[i] = 0x5C;
+ }
+
+ for ( i = 0; i < HMAC_OUTPUT_SIZE; i++ ) {
+ ipad[i] ^= key[i];
+ opad[i] ^= key[i];
+ }
+
+ SHA1_Init(&ctx);
+ SHA1_Update(&ctx, ipad, HMAC_BLOCK_SIZE);
+ SHA1_Update(&ctx, msg, len);
+ SHA1_Final(md, &ctx);
+
+ SHA1_Init(&ctx);
+ SHA1_Update(&ctx, opad, HMAC_BLOCK_SIZE);
+ SHA1_Update(&ctx, md, HMAC_OUTPUT_SIZE);
+ SHA1_Final(md, &ctx);
+
+ return true;
+}
+
+typedef uint16_t tpm_entity_type_t;
+typedef uint32_t tpm_authhandle_t;
+typedef struct __packed {
+ uint8_t nonce[20];
+} tpm_nonce_t;
+
+#define TPM_ET_SRK 0x0004
+#define TPM_KH_SRK 0x40000000
+
+typedef uint32_t tpm_key_handle_t;
+
+typedef tpm12_digest_t tpm_composite_hash_t;
+typedef struct __packed {
+ tpm_structure_tag_t tag;
+ tpm_locality_selection_t locality_at_creation;
+ tpm_locality_selection_t locality_at_release;
+ tpm_pcr_selection_t creation_pcr_selection;
+ tpm_pcr_selection_t release_pcr_selection;
+ tpm_composite_hash_t digest_at_creation;
+ tpm_composite_hash_t digest_at_release;
+} tpm_pcr_info_long_t;
+
+typedef uint8_t tpm_authdata_t[20];
+typedef tpm_authdata_t tpm_encauth_t;
+
+typedef struct __packed {
+ tpm_structure_tag_t tag;
+ tpm_entity_type_t et;
+ uint32_t seal_info_size;
+} tpm_stored_data12_header_t;
+
+typedef struct __packed {
+ tpm_stored_data12_header_t header;
+ uint32_t enc_data_size;
+ uint8_t enc_data[];
+} tpm_stored_data12_short_t;
+
+typedef struct __packed {
+ tpm_stored_data12_header_t header;
+ tpm_pcr_info_long_t seal_info;
+ uint32_t enc_data_size;
+ uint8_t enc_data[];
+} tpm_stored_data12_t;
+
+#define UNLOAD_INTEGER(buf, offset, var) {\
+ reverse_copy(buf + offset, &(var), sizeof(var));\
+ offset += sizeof(var);\
+}
+
+#define UNLOAD_BLOB(buf, offset, blob, size) {\
+ memcpy(buf + offset, blob, size);\
+ offset += size;\
+}
+
+#define UNLOAD_BLOB_TYPE(buf, offset, blob) \
+ UNLOAD_BLOB(buf, offset, blob, sizeof(*(blob)))
+
+#define UNLOAD_PCR_SELECTION(buf, offset, sel) {\
+ UNLOAD_INTEGER(buf, offset, (sel)->size_of_select);\
+ UNLOAD_BLOB(buf, offset, (sel)->pcr_select, (sel)->size_of_select);\
+}
+
+#define UNLOAD_PCR_INFO_LONG(buf, offset, info) {\
+ UNLOAD_INTEGER(buf, offset, (info)->tag);\
+ UNLOAD_BLOB_TYPE(buf, offset, &(info)->locality_at_creation);\
+ UNLOAD_BLOB_TYPE(buf, offset, &(info)->locality_at_release);\
+ UNLOAD_PCR_SELECTION(buf, offset, &(info)->creation_pcr_selection);\
+ UNLOAD_PCR_SELECTION(buf, offset, &(info)->release_pcr_selection);\
+ UNLOAD_BLOB_TYPE(buf, offset, &(info)->digest_at_creation);\
+ UNLOAD_BLOB_TYPE(buf, offset, &(info)->digest_at_release);\
+}
+
+#define UNLOAD_STORED_DATA12(buf, offset, hdr) {\
+ UNLOAD_INTEGER(buf, offset, ((tpm_stored_data12_header_t *)(hdr))->tag);\
+ UNLOAD_INTEGER(buf, offset, ((tpm_stored_data12_header_t *)(hdr))->et);\
+ UNLOAD_INTEGER(buf, offset,\
+ ((tpm_stored_data12_header_t *)(hdr))->seal_info_size);\
+ if ( ((tpm_stored_data12_header_t *)(hdr))->seal_info_size == 0 ) {\
+ UNLOAD_INTEGER(buf, offset,\
+ ((tpm_stored_data12_short_t *)hdr)->enc_data_size);\
+ UNLOAD_BLOB(buf, offset,\
+ ((tpm_stored_data12_short_t *)hdr)->enc_data,\
+ ((tpm_stored_data12_short_t *)hdr)->enc_data_size);\
+ }\
+ else {\
+ UNLOAD_PCR_INFO_LONG(buf, offset,\
+ &((tpm_stored_data12_t *)hdr)->seal_info);\
+ UNLOAD_INTEGER(buf, offset,\
+ ((tpm_stored_data12_t *)hdr)->enc_data_size);\
+ UNLOAD_BLOB(buf, offset,\
+ ((tpm_stored_data12_t *)hdr)->enc_data,\
+ ((tpm_stored_data12_t *)hdr)->enc_data_size);\
+ }\
+}
+
+#define LOAD_INTEGER(buf, offset, var) {\
+ reverse_copy(&(var), buf + offset, sizeof(var));\
+ offset += sizeof(var);\
+}
+
+#define LOAD_BLOB(buf, offset, blob, size) {\
+ memcpy(blob, buf + offset, size);\
+ offset += size;\
+}
+
+#define LOAD_BLOB_TYPE(buf, offset, blob) \
+ LOAD_BLOB(buf, offset, blob, sizeof(*(blob)))
+
+#define LOAD_PCR_SELECTION(buf, offset, sel) {\
+ LOAD_INTEGER(buf, offset, (sel)->size_of_select);\
+ LOAD_BLOB(buf, offset, (sel)->pcr_select, (sel)->size_of_select);\
+}
+
+#define LOAD_PCR_INFO_LONG(buf, offset, info) {\
+ LOAD_INTEGER(buf, offset, (info)->tag);\
+ LOAD_BLOB_TYPE(buf, offset, &(info)->locality_at_creation);\
+ LOAD_BLOB_TYPE(buf, offset, &(info)->locality_at_release);\
+ LOAD_PCR_SELECTION(buf, offset, &(info)->creation_pcr_selection);\
+ LOAD_PCR_SELECTION(buf, offset, &(info)->release_pcr_selection);\
+ LOAD_BLOB_TYPE(buf, offset, &(info)->digest_at_creation);\
+ LOAD_BLOB_TYPE(buf, offset, &(info)->digest_at_release);\
+}
+
+#define LOAD_STORED_DATA12(buf, offset, hdr) {\
+ LOAD_INTEGER(buf, offset, ((tpm_stored_data12_header_t *)(hdr))->tag);\
+ LOAD_INTEGER(buf, offset, ((tpm_stored_data12_header_t *)(hdr))->et);\
+ LOAD_INTEGER(buf, offset, \
+ ((tpm_stored_data12_header_t *)(hdr))->seal_info_size);\
+ if ( ((tpm_stored_data12_header_t *)(hdr))->seal_info_size == 0 ) {\
+ LOAD_INTEGER(buf, offset,\
+ ((tpm_stored_data12_short_t *)hdr)->enc_data_size);\
+ LOAD_BLOB(buf, offset,\
+ ((tpm_stored_data12_short_t *)hdr)->enc_data,\
+ ((tpm_stored_data12_short_t *)hdr)->enc_data_size);\
+ }\
+ else {\
+ LOAD_PCR_INFO_LONG(buf, offset,\
+ &((tpm_stored_data12_t *)hdr)->seal_info);\
+ LOAD_INTEGER(buf, offset,\
+ ((tpm_stored_data12_t *)hdr)->enc_data_size);\
+ LOAD_BLOB(buf, offset,\
+ ((tpm_stored_data12_t *)hdr)->enc_data,\
+ ((tpm_stored_data12_t *)hdr)->enc_data_size);\
+ }\
+}
+
+static uint32_t tpm12_oiap(uint32_t locality, tpm_authhandle_t *hauth,
+ tpm_nonce_t *nonce_even)
+{
+ uint32_t ret, offset, out_size;
+
+ if ( hauth == NULL || nonce_even == NULL )
+ return TPM_BAD_PARAMETER;
+
+ offset = 0;
+
+ out_size = sizeof(*hauth) + sizeof(*nonce_even);
+
+ ret = tpm12_submit_cmd(locality, TPM_ORD_OIAP, offset, &out_size);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: start OIAP, return value = %08X\n", ret);
+#endif
+ if ( ret != TPM_SUCCESS ) {
+ printk(TBOOT_DETA"TPM: start OIAP, return value = %08X\n", ret);
+ return ret;
+ }
+
+#ifdef TPM_TRACE
+ {
+ printk(TBOOT_INFO"TPM: ");
+ print_hex(NULL, WRAPPER_OUT_BUF, out_size);
+ }
+#endif
+
+ offset = 0;
+ LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *hauth);
+ LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, nonce_even);
+
+ return ret;
+}
+
+static uint32_t tpm12_osap(uint32_t locality, tpm_entity_type_t ent_type,
+ uint32_t ent_value, const tpm_nonce_t *odd_osap,
+ tpm_authhandle_t *hauth, tpm_nonce_t *nonce_even,
+ tpm_nonce_t *even_osap)
+{
+ uint32_t ret, offset, out_size;
+
+ if ( odd_osap == NULL || hauth == NULL ||
+ nonce_even == NULL || even_osap == NULL )
+ return TPM_BAD_PARAMETER;
+
+ offset = 0;
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, ent_type);
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, ent_value);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, odd_osap);
+
+ out_size = sizeof(*hauth) + sizeof(*nonce_even) + sizeof(*even_osap);
+ ret = tpm12_submit_cmd(locality, TPM_ORD_OSAP, offset, &out_size);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: start OSAP, return value = %08X\n", ret);
+#endif
+ if ( ret != TPM_SUCCESS ) {
+ printk(TBOOT_DETA"TPM: start OSAP, return value = %08X\n", ret);
+ return ret;
+ }
+
+#ifdef TPM_TRACE
+ {
+ printk(TBOOT_INFO"TPM: ");
+ print_hex(NULL, WRAPPER_OUT_BUF, out_size);
+ }
+#endif
+
+ offset = 0;
+ LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *hauth);
+ LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, nonce_even);
+ LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, even_osap);
+
+ return ret;
+}
+
+static uint32_t _tpm12_seal(uint32_t locality, tpm_key_handle_t hkey,
+ const tpm_encauth_t *enc_auth, uint32_t pcr_info_size,
+ const tpm_pcr_info_long_t *pcr_info, uint32_t in_data_size,
+ const uint8_t *in_data,
+ tpm_authhandle_t hauth, const tpm_nonce_t *nonce_odd,
+ uint8_t *cont_session, const tpm_authdata_t *pub_auth,
+ uint32_t *sealed_data_size, uint8_t *sealed_data,
+ tpm_nonce_t *nonce_even, tpm_authdata_t *res_auth)
+{
+ uint32_t ret, offset, out_size;
+
+ if ( enc_auth == NULL || pcr_info == NULL || in_data == NULL ||
+ nonce_odd == NULL || cont_session == NULL || pub_auth == NULL ||
+ sealed_data_size == NULL || sealed_data == NULL ||
+ nonce_even == NULL || res_auth == NULL ) {
+ printk(TBOOT_WARN"TPM: _tpm12_seal() bad parameter\n");
+ return TPM_BAD_PARAMETER;
+ }
+
+ offset = 0;
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, hkey);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, enc_auth);
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, pcr_info_size);
+ UNLOAD_PCR_INFO_LONG(WRAPPER_IN_BUF, offset, pcr_info);
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, in_data_size);
+ UNLOAD_BLOB(WRAPPER_IN_BUF, offset, in_data, in_data_size);
+
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, hauth);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, nonce_odd);
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, *cont_session);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, pub_auth);
+
+ out_size = WRAPPER_OUT_MAX_SIZE;
+
+ ret = tpm12_submit_cmd_auth1(locality, TPM_ORD_SEAL, offset, &out_size);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: seal data, return value = %08X\n", ret);
+#endif
+ if ( ret != TPM_SUCCESS ) {
+ printk(TBOOT_DETA"TPM: seal data, return value = %08X\n", ret);
+ return ret;
+ }
+
+#ifdef TPM_TRACE
+ {
+ printk(TBOOT_INFO"TPM: ");
+ print_hex(NULL, WRAPPER_OUT_BUF, out_size);
+ }
+#endif
+
+ if ( *sealed_data_size <
+ ( out_size - sizeof(*nonce_even) - sizeof(*cont_session)
+ - sizeof(*res_auth) ) ) {
+ printk(TBOOT_WARN"TPM: sealed blob is too small\n");
+ return TPM_NOSPACE;
+ }
+
+ offset = 0;
+ LOAD_STORED_DATA12(WRAPPER_OUT_BUF, offset, sealed_data);
+ *sealed_data_size = offset;
+ LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, nonce_even);
+ LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *cont_session);
+ LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, res_auth);
+
+ return ret;
+}
+
+static uint32_t _tpm12_unseal(uint32_t locality, tpm_key_handle_t hkey,
+ const uint8_t *in_data,
+ tpm_authhandle_t hauth, const tpm_nonce_t *nonce_odd,
+ uint8_t *cont_session, const tpm_authdata_t *auth,
+ tpm_authhandle_t hauth_d, const tpm_nonce_t *nonce_odd_d,
+ uint8_t *cont_session_d, const tpm_authdata_t *auth_d,
+ uint32_t *secret_size, uint8_t *secret,
+ tpm_nonce_t *nonce_even, tpm_authdata_t *res_auth,
+ tpm_nonce_t *nonce_even_d, tpm_authdata_t *res_auth_d)
+{
+ uint32_t ret, offset, out_size;
+
+ if ( in_data == NULL || nonce_odd == NULL || cont_session == NULL ||
+ auth == NULL || nonce_odd_d == NULL || cont_session_d == NULL ||
+ auth_d == NULL || secret_size == NULL || secret == NULL ||
+ nonce_even == NULL || res_auth == NULL || nonce_even_d == NULL ||
+ res_auth_d == NULL ) {
+ printk(TBOOT_WARN"TPM: _tpm_unseal() bad parameter\n");
+ return TPM_BAD_PARAMETER;
+ }
+
+ offset = 0;
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, hkey);
+ UNLOAD_STORED_DATA12(WRAPPER_IN_BUF, offset, in_data);
+
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, hauth);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, nonce_odd);
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, *cont_session);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, auth);
+
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, hauth_d);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, nonce_odd_d);
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, *cont_session_d);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, auth_d);
+
+ out_size = WRAPPER_OUT_MAX_SIZE;
+
+ ret = tpm12_submit_cmd_auth2(locality, TPM_ORD_UNSEAL, offset, &out_size);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: unseal data, return value = %08X\n", ret);
+#endif
+ if ( ret != TPM_SUCCESS ) {
+ printk(TBOOT_DETA"TPM: unseal data, return value = %08X\n", ret);
+ return ret;
+ }
+
+#ifdef TPM_TRACE
+ {
+ printk(TBOOT_INFO"TPM: ");
+ print_hex(NULL, WRAPPER_OUT_BUF, out_size);
+ }
+#endif
+
+ if ( *secret_size <
+ ( out_size - sizeof(*secret_size) - sizeof(*nonce_even)
+ - sizeof(*cont_session) - sizeof(*res_auth) - sizeof(*nonce_even_d)
+ - sizeof(*cont_session_d) - sizeof(*res_auth_d) ) ) {
+ printk(TBOOT_WARN"TPM: unsealed data too small\n");
+ return TPM_NOSPACE;
+ }
+
+ offset = 0;
+ LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *secret_size);
+ LOAD_BLOB(WRAPPER_OUT_BUF, offset, secret, *secret_size);
+
+ LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, nonce_even);
+ LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *cont_session);
+ LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, res_auth);
+
+ LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, nonce_even_d);
+ LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *cont_session_d);
+ LOAD_BLOB_TYPE(WRAPPER_OUT_BUF, offset, res_auth_d);
+
+ return ret;
+}
+
+#define XOR_BLOB_TYPE(data, pad) {\
+ for ( uint32_t i = 0; i < sizeof(*(data)); i++ ) \
+ ((uint8_t *)data)[i] ^= ((uint8_t *)pad)[i % sizeof(*(pad))];\
+}
+
+static const tpm_authdata_t srk_authdata =
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static const tpm_authdata_t blob_authdata =
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+static uint32_t _tpm12_wrap_seal(uint32_t locality,
+ const tpm_pcr_info_long_t *pcr_info,
+ uint32_t in_data_size, const uint8_t *in_data,
+ uint32_t *sealed_data_size, uint8_t *sealed_data)
+{
+ uint32_t ret;
+ tpm_nonce_t odd_osap, even_osap, nonce_even, nonce_odd;
+ tpm_authhandle_t hauth;
+ tpm_authdata_t shared_secret, pub_auth, res_auth;
+ tpm_encauth_t enc_auth;
+ uint8_t cont_session = false;
+ tpm_key_handle_t hkey = TPM_KH_SRK;
+ uint32_t pcr_info_size = sizeof(*pcr_info);
+ uint32_t offset;
+ uint32_t ordinal = TPM_ORD_SEAL;
+ tpm12_digest_t digest;
+
+ /* skip generate nonce for odd_osap, just use the random value in stack */
+
+ /* establish a osap session */
+ ret = tpm12_osap(locality, TPM_ET_SRK, TPM_KH_SRK, &odd_osap, &hauth,
+ &nonce_even, &even_osap);
+ if ( ret != TPM_SUCCESS )
+ return ret;
+
+ /* calculate the shared secret
+ shared-secret = HMAC(srk_auth, even_osap || odd_osap) */
+ offset = 0;
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &even_osap);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &odd_osap);
+ hmac((uint8_t *)&srk_authdata, WRAPPER_IN_BUF, offset,
+ (uint8_t *)&shared_secret);
+
+ /* generate ecrypted authdata for data
+ enc_auth = XOR(authdata, sha1(shared_secret || last_even_nonce)) */
+ offset = 0;
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &shared_secret);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_even);
+ sha1_buffer(WRAPPER_IN_BUF, offset, (uint8_t *)&digest);
+ memcpy(&enc_auth, &blob_authdata, sizeof(blob_authdata));
+ XOR_BLOB_TYPE(&enc_auth, &digest);
+
+ /* skip generate nonce for nonce_odd, just use the random value in stack */
+
+ /* calculate authdata */
+ /* in_param_digest = sha1(1S ~ 6S) */
+ offset = 0;
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, ordinal);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &enc_auth);
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, pcr_info_size);
+ UNLOAD_PCR_INFO_LONG(WRAPPER_IN_BUF, offset, pcr_info);
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, in_data_size);
+ UNLOAD_BLOB(WRAPPER_IN_BUF, offset, in_data, in_data_size);
+ sha1_buffer(WRAPPER_IN_BUF, offset, (uint8_t *)&digest);
+
+ /* authdata = hmac(key, in_param_digest || auth_params) */
+ offset = 0;
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &digest);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_even);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_odd);
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, cont_session);
+ hmac((uint8_t *)&shared_secret, WRAPPER_IN_BUF, offset,
+ (uint8_t *)&pub_auth);
+
+ /* call the simple seal function */
+ ret = _tpm12_seal(locality, hkey, (const tpm_encauth_t *)&enc_auth,
+ pcr_info_size, pcr_info, in_data_size, in_data,
+ hauth, &nonce_odd, &cont_session,
+ (const tpm_authdata_t *)&pub_auth,
+ sealed_data_size, sealed_data,
+ &nonce_even, &res_auth);
+
+ /* skip check for res_auth */
+
+ return ret;
+}
+
+static uint32_t _tpm12_wrap_unseal(uint32_t locality, const uint8_t *in_data,
+ uint32_t *secret_size, uint8_t *secret)
+{
+ uint32_t ret;
+ tpm_nonce_t odd_osap, even_osap;
+ tpm_nonce_t nonce_even, nonce_odd, nonce_even_d, nonce_odd_d;
+ tpm_authhandle_t hauth, hauth_d;
+ tpm_authdata_t shared_secret;
+ tpm_authdata_t pub_auth, res_auth, pub_auth_d, res_auth_d;
+ uint8_t cont_session = false, cont_session_d = false;
+ tpm_key_handle_t hkey = TPM_KH_SRK;
+ uint32_t offset;
+ uint32_t ordinal = TPM_ORD_UNSEAL;
+ tpm12_digest_t digest;
+
+ /* skip generate nonce for odd_osap, just use the random value in stack */
+
+ /* establish a osap session */
+ ret = tpm12_osap(locality, TPM_ET_SRK, TPM_KH_SRK, &odd_osap, &hauth,
+ &nonce_even, &even_osap);
+ if ( ret != TPM_SUCCESS )
+ return ret;
+
+ /* calculate the shared secret
+ shared-secret = HMAC(auth, even_osap || odd_osap) */
+ offset = 0;
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &even_osap);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &odd_osap);
+ hmac((uint8_t *)&srk_authdata, WRAPPER_IN_BUF, offset,
+ (uint8_t *)&shared_secret);
+
+ /* establish a oiap session */
+ ret = tpm12_oiap(locality, &hauth_d, &nonce_even_d);
+ if ( ret != TPM_SUCCESS )
+ return ret;
+
+ /* skip generate nonce_odd & nonce_odd_d, just use the random values */
+
+ /* calculate authdata */
+ /* in_param_digest = sha1(1S ~ 6S) */
+ offset = 0;
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, ordinal);
+ UNLOAD_STORED_DATA12(WRAPPER_IN_BUF, offset, in_data);
+ sha1_buffer(WRAPPER_IN_BUF, offset, (uint8_t *)&digest);
+
+ /* authdata1 = hmac(key, in_param_digest || auth_params1) */
+ offset = 0;
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &digest);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_even);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_odd);
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, cont_session);
+ hmac((uint8_t *)&shared_secret, WRAPPER_IN_BUF, offset,
+ (uint8_t *)&pub_auth);
+
+ /* authdata2 = hmac(key, in_param_digest || auth_params2) */
+ offset = 0;
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &digest);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_even_d);
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &nonce_odd_d);
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, cont_session_d);
+ hmac((uint8_t *)&blob_authdata, WRAPPER_IN_BUF, offset,
+ (uint8_t *)&pub_auth_d);
+
+ /* call the simple seal function */
+ ret = _tpm12_unseal(locality, hkey, in_data,
+ hauth, &nonce_odd, &cont_session,
+ (const tpm_authdata_t *)&pub_auth,
+ hauth_d, &nonce_odd_d, &cont_session_d,
+ (const tpm_authdata_t *)&pub_auth_d,
+ secret_size, secret,
+ &nonce_even, &res_auth, &nonce_even_d, &res_auth_d);
+
+ /* skip check for res_auth */
+
+ return ret;
+}
+
+static bool init_pcr_info(uint32_t locality,
+ tpm_locality_selection_t release_locs,
+ uint32_t nr_create, const uint8_t indcs_create[],
+ uint32_t nr_release, const uint8_t indcs_release[],
+ const tpm12_digest_t *values_release[],
+ tpm_pcr_info_long_t *pcr_info)
+{
+ uint32_t offset;
+ uint32_t i, blob_size;
+ static tpm_locality_selection_t localities[TPM_NR_LOCALITIES] = {
+ TPM_LOC_ZERO, TPM_LOC_ONE, TPM_LOC_TWO, TPM_LOC_THREE, TPM_LOC_FOUR
+ };
+
+
+ if ( (release_locs & TPM_LOC_RSVD) != 0 )
+ return false;
+ if ( pcr_info == NULL )
+ return false;
+ if ( locality >= TPM_NR_LOCALITIES )
+ return false;
+ if ( indcs_create == NULL )
+ nr_create = 0;
+ if ( indcs_release == NULL || values_release == NULL )
+ nr_release = 0;
+ for ( i = 0; i < nr_create; i++ )
+ if ( indcs_create[i] >= TPM_NR_PCRS )
+ return false;
+ for ( i = 0; i < nr_release; i++ ) {
+ if ( indcs_release[i] >= TPM_NR_PCRS || values_release[i] == NULL )
+ return false;
+ }
+
+ memset(pcr_info, 0, sizeof(*pcr_info));
+ pcr_info->tag = TPM_TAG_PCR_INFO_LONG;
+ pcr_info->locality_at_creation = localities[locality];
+ pcr_info->locality_at_release = release_locs;
+ pcr_info->creation_pcr_selection.size_of_select = 3;
+ for ( i = 0; i < nr_create; i++ )
+ pcr_info->creation_pcr_selection.pcr_select[indcs_create[i]/8] |=
+ 1 << (indcs_create[i] % 8);
+ pcr_info->release_pcr_selection.size_of_select = 3;
+ for ( i = 0; i < nr_release; i++ )
+ pcr_info->release_pcr_selection.pcr_select[indcs_release[i]/8] |=
+ 1 << (indcs_release[i] % 8);
+
+ if ( nr_release > 0 ) {
+ offset = 0;
+ UNLOAD_PCR_SELECTION(WRAPPER_IN_BUF, offset,
+ &pcr_info->release_pcr_selection);
+ blob_size = sizeof(tpm12_digest_t) * nr_release;
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, blob_size);
+ for ( i = 0; i < nr_release; i++ )
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, values_release[i]);
+ sha1_buffer(WRAPPER_IN_BUF, offset,
+ (uint8_t *)&pcr_info->digest_at_release);
+ }
+
+ return true;
+}
+
+static bool tpm12_seal(struct tpm_if *ti, uint32_t locality,
+ uint32_t in_data_size, const uint8_t *in_data,
+ uint32_t *sealed_data_size, uint8_t *sealed_data)
+{
+ const uint8_t pcr_indcs_create[] = {17, 18};
+ const uint8_t pcr_indcs_release[] = {17, 18};
+ const tpm12_digest_t *pcr_values_release[] = {NULL, NULL}; /* TODO {(tpm12_digest_t *)&post_launch_pcr17,
+ (tpm12_digest_t *)&post_launch_pcr18};*/
+ uint32_t pcr_nr_create = ARRAY_SIZE(pcr_indcs_create);
+ uint32_t pcr_nr_release = ARRAY_SIZE(pcr_indcs_release);
+ uint32_t ret;
+ tpm_pcr_info_long_t pcr_info;
+ tpm_locality_selection_t release_locs = 1 << locality;
+
+ if ( ti == NULL )
+ return false;
+
+ if ( locality >= TPM_NR_LOCALITIES ||
+ in_data_size == 0 || in_data == NULL ||
+ sealed_data_size == NULL || sealed_data == NULL ||
+ *sealed_data_size == 0 ) {
+ printk(TBOOT_WARN"TPM: tpm12_seal() bad parameter\n");
+ ti->error = TPM_BAD_PARAMETER;
+ return false;
+ }
+
+ if ( !init_pcr_info(locality, release_locs, pcr_nr_create,
+ pcr_indcs_create, pcr_nr_release, pcr_indcs_release,
+ pcr_values_release, &pcr_info) ) {
+ printk(TBOOT_WARN"TPM: tpm12_seal() bad parameter\n");
+ ti->error = TPM_BAD_PARAMETER;
+ return false;
+ }
+
+ ret = _tpm12_wrap_seal(locality, &pcr_info, in_data_size, in_data,
+ sealed_data_size, sealed_data);
+ if ( ret != TPM_SUCCESS ) {
+ ti->error = ret;
+ return false;
+ }
+
+ return true;
+}
+
+static bool check_sealed_data(uint32_t size, const uint8_t *data)
+{
+ if ( size < sizeof(tpm_stored_data12_header_t) )
+ return false;
+ if ( ((tpm_stored_data12_header_t *)data)->tag != TPM_TAG_STORED_DATA12 )
+ return false;
+
+ if ( ((tpm_stored_data12_header_t *)data)->seal_info_size == 0 ) {
+ tpm_stored_data12_short_t *data12_s;
+
+ if ( size < sizeof(*data12_s) )
+ return false;
+ data12_s = (tpm_stored_data12_short_t *)data;
+ if ( size != sizeof(*data12_s) + data12_s->enc_data_size )
+ return false;
+ }
+ else {
+ tpm_stored_data12_t *data12;
+
+ if ( size < sizeof(*data12) )
+ return false;
+ data12 = (tpm_stored_data12_t *)data;
+ if ( size != sizeof(*data12) + data12->enc_data_size )
+ return false;
+ }
+
+ return true;
+}
+
+static bool tpm12_unseal(struct tpm_if *ti, uint32_t locality,
+ uint32_t sealed_data_size, const uint8_t *sealed_data,
+ uint32_t *secret_size, uint8_t *secret)
+{
+ uint32_t ret;
+
+ if ( ti == NULL )
+ return false;
+
+ if ( sealed_data == NULL ||
+ secret_size == NULL || secret == NULL ) {
+ printk(TBOOT_WARN"TPM: tpm12_unseal() bad parameter\n");
+ ti->error = TPM_BAD_PARAMETER;
+ return false;
+ }
+
+ if ( !check_sealed_data(sealed_data_size, sealed_data) ) {
+ printk(TBOOT_WARN"TPM: tpm12_unseal() blob invalid\n");
+ ti->error = TPM_BAD_PARAMETER;
+ return false;
+ }
+
+ ret = _tpm12_wrap_unseal(locality, sealed_data, secret_size, secret);
+ if ( ret != TPM_SUCCESS ) {
+ ti->error = ret;
+ return false;
+ }
+
+ return true;
+}
+
+static void calc_pcr_composition(uint32_t nr, const uint8_t indcs[],
+ const tpm12_digest_t *values[],
+ tpm_composite_hash_t *composite)
+{
+ uint32_t i, offset, blob_size;
+ tpm_pcr_selection_t sel;
+
+ if ( nr == 0 || indcs == NULL || values == NULL || composite == NULL)
+ return;
+
+ sel.size_of_select = 3;
+ sel.pcr_select[0] = sel.pcr_select[1] = sel.pcr_select[2] = 0;
+ for ( i = 0; i < nr; i++ )
+ sel.pcr_select[indcs[i]/8] |= 1 << (indcs[i] % 8);
+
+ offset = 0;
+ UNLOAD_PCR_SELECTION(WRAPPER_IN_BUF, offset, &sel);
+ blob_size = sizeof(tpm12_digest_t) * nr;
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, blob_size);
+ for ( i = 0; i < nr; i++ )
+ UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, values[i]);
+ sha1_buffer(WRAPPER_IN_BUF, offset, (uint8_t *)composite);
+}
+
+static tpm_composite_hash_t *get_cre_pcr_composite(uint8_t *data)
+{
+ if ( ((tpm_stored_data12_header_t *)data)->seal_info_size == 0 )
+ return NULL;
+ else
+ return &((tpm_stored_data12_t *)data)->seal_info.digest_at_creation;
+}
+
+static bool tpm12_cmp_creation_pcrs(uint32_t pcr_nr_create,
+ const uint8_t pcr_indcs_create[],
+ const tpm12_digest_t *pcr_values_create[],
+ uint32_t sealed_data_size, uint8_t *sealed_data)
+{
+ uint32_t i;
+ tpm_composite_hash_t composite = {{0,}}, *cre_composite;
+
+ if ( pcr_indcs_create == NULL )
+ pcr_nr_create = 0;
+ for ( i = 0; i < pcr_nr_create; i++ ) {
+ if ( pcr_indcs_create[i] >= TPM_NR_PCRS )
+ return false;
+ }
+ if ( !check_sealed_data(sealed_data_size, sealed_data) ) {
+ printk(TBOOT_WARN"TPM: Bad blob.\n");
+ return false;
+ }
+
+ if ( pcr_nr_create > 0 )
+ calc_pcr_composition(pcr_nr_create, pcr_indcs_create,
+ pcr_values_create, &composite);
+
+ cre_composite = get_cre_pcr_composite(sealed_data);
+ if ( cre_composite == NULL )
+ return false;
+ if ( memcmp(&composite, cre_composite, sizeof(composite)) ) {
+ printk(TBOOT_WARN"TPM: Not equal to creation composition:\n");
+ print_hex(NULL, (uint8_t *)&composite, sizeof(composite));
+ print_hex(NULL, (uint8_t *)cre_composite, sizeof(composite));
+ return false;
+ }
+
+ return true;
+}
+
+static bool tpm12_verify_creation(struct tpm_if *ti, uint32_t sealed_data_size,
+ uint8_t *sealed_data)
+{
+ uint8_t pcr_indcs_create[] = {17, 18};
+ tpm12_digest_t pcr17, pcr18;
+ const tpm12_digest_t *pcr_values_create[] = {&pcr17, &pcr18};
+ int i;
+
+ if ( ti == NULL || sealed_data == NULL )
+ return false;
+
+ tpm12_pcr_read(ti, 2, 17, (tpm_pcr_value_t *)&pcr17);
+ tpm12_pcr_read(ti, 2, 18, (tpm_pcr_value_t *)&pcr18);
+
+ /* to prevent rollback attack using old sealed measurements,
+ verify that (creation) PCRs at mem integrity seal time are same as
+ if we extend current PCRs with unsealed VL measurements */
+ /* TBD: we should check all DRTM PCRs */
+ /* TODO
+ for ( i = 0; i < g_pre_k_s3_state.num_vl_entries; i++ ) {
+ if ( g_pre_k_s3_state.vl_entries[i].pcr == 17 )
+ extend_hash((tb_hash_t *)&pcr17,
+ &g_pre_k_s3_state.vl_entries[i].hl.entries[0].hash, TB_HALG_SHA1);
+ else if ( g_pre_k_s3_state.vl_entries[i].pcr == 18 )
+ extend_hash((tb_hash_t *)&pcr18,
+ &g_pre_k_s3_state.vl_entries[i].hl.entries[0].hash, TB_HALG_SHA1);
+ }*/
+ if ( !tpm12_cmp_creation_pcrs(ARRAY_SIZE(pcr_indcs_create),
+ pcr_indcs_create, pcr_values_create,
+ sealed_data_size,
+ sealed_data) ) {
+ printk(TBOOT_WARN"extended PCR values don't match creation values in sealed blob.\n");
+ return false;
+ }
+
+ return true;
+}
+
+typedef uint32_t tpm_capability_area_t;
+
+#define TPM_CAP_NV_INDEX 0x00000011
+
+static uint32_t tpm12_get_capability(uint32_t locality, tpm_capability_area_t cap_area,
+ uint32_t sub_cap_size, const uint8_t *sub_cap,
+ uint32_t *resp_size, uint8_t *resp)
+{
+ uint32_t ret, offset, out_size;
+
+ if ( sub_cap == NULL || resp_size == NULL || resp == NULL ) {
+ printk(TBOOT_WARN"TPM: tpm12_get_capability() bad parameter\n");
+ return TPM_BAD_PARAMETER;
+ }
+
+ offset = 0;
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, cap_area);
+ UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, sub_cap_size);
+ UNLOAD_BLOB(WRAPPER_IN_BUF, offset, sub_cap, sub_cap_size);
+
+ out_size = sizeof(*resp_size) + *resp_size;
+
+ ret = tpm12_submit_cmd(locality, TPM_ORD_GET_CAPABILITY, offset, &out_size);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: get capability, return value = %08X\n", ret);
+#endif
+ if ( ret != TPM_SUCCESS ) {
+ printk(TBOOT_DETA"TPM: get capability, return value = %08X\n", ret);
+ return ret;
+ }
+
+ offset = 0;
+ LOAD_INTEGER(WRAPPER_OUT_BUF, offset, *resp_size);
+ if ( out_size < sizeof(*resp_size) + *resp_size ) {
+ printk(TBOOT_WARN"TPM: capability response too small\n");
+ return TPM_FAIL;
+ }
+ LOAD_BLOB(WRAPPER_OUT_BUF, offset, resp, *resp_size);
+
+ return ret;
+}
+
+typedef struct __packed {
+ tpm_pcr_selection_t pcr_selection;
+ tpm_locality_selection_t locality_at_release;
+ tpm_composite_hash_t digest_at_release;
+} tpm_pcr_info_short_t;
+
+typedef struct __packed {
+ tpm_structure_tag_t tag;
+ uint32_t attributes;
+} tpm_nv_attributes_t;
+
+typedef struct __packed {
+ tpm_structure_tag_t tag;
+ uint32_t nv_index;
+ tpm_pcr_info_short_t pcr_info_read;
+ tpm_pcr_info_short_t pcr_info_write;
+ tpm_nv_attributes_t permission;
+ uint8_t b_read_st_clear;
+ uint8_t b_write_st_clear;
+ uint8_t b_write_define;
+ uint32_t data_size;
+} tpm_nv_data_public_t;
+
+static bool tpm12_get_nvindex_size(struct tpm_if *ti, uint32_t locality,
+ uint32_t index, uint32_t *size)
+{
+ uint32_t ret, offset, resp_size;
+ uint8_t sub_cap[sizeof(index)];
+ uint8_t resp[sizeof(tpm_nv_data_public_t)];
+ uint32_t idx;
+
+ if ( ti == NULL )
+ return false;
+
+ if ( size == NULL ) {
+ printk(TBOOT_WARN"TPM: tpm12_get_nvindex_size() bad parameter\n");
+ ti->error = TPM_BAD_PARAMETER;
+ return false;
+ }
+
+ offset = 0;
+ UNLOAD_INTEGER(sub_cap, offset, index);
+
+ resp_size = sizeof(resp);
+ ret = tpm12_get_capability(locality, TPM_CAP_NV_INDEX, sizeof(sub_cap),
+ sub_cap, &resp_size, resp);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: get nvindex size, return value = %08X\n", ret);
+#endif
+ if ( ret != TPM_SUCCESS ) {
+ printk(TBOOT_DETA"TPM: fail to get public data of 0x%08X in TPM NV\n", index);
+ ti->error = ret;
+ return false;
+ }
+
+#ifdef TPM_TRACE
+ {
+ printk(TBOOT_INFO"TPM: ");
+ print_hex(NULL, resp, resp_size);
+ }
+#endif
+
+ /* check size */
+ if ( resp_size == 0 ) {
+ printk(TBOOT_WARN"TPM: Index 0x%08X does not exist\n", index);
+ ti->error = TPM_BADINDEX;
+ return false;
+ }
+
+ /* check index */
+ offset = sizeof(tpm_structure_tag_t);
+ LOAD_INTEGER(resp, offset, idx);
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: get index value = %08X\n", idx);
+#endif
+
+ if ( idx != index ) {
+ printk(TBOOT_DETA"TPM: Index 0x%08X is not the one expected 0x%08X\n",
+ idx, index);
+ ti->error = TPM_BADINDEX;
+ return false;
+ }
+
+ if ( resp_size != sizeof(resp) ) {
+ printk(TBOOT_WARN"TPM: public data size of Index 0x%08X responsed incorrect\n",
+ index);
+ ti->error = TPM_FAIL;
+ return false;
+ }
+
+ offset = resp_size - sizeof(uint32_t);
+ LOAD_INTEGER(resp, offset, *size);
+
+ return true;
+}
+
+static bool tpm12_get_nvindex_permission(struct tpm_if *ti, uint32_t locality,
+ uint32_t index, uint32_t *attribute)
+{
+ uint32_t ret, offset, resp_size;
+ uint8_t sub_cap[sizeof(index)];
+ uint8_t resp[sizeof(tpm_nv_data_public_t)];
+ uint32_t idx;
+
+ if ( ti == NULL )
+ return false;
+
+ if ( attribute == NULL ) {
+ printk(TBOOT_WARN"TPM: tpm12_get_nvindex_permission() bad parameter\n");
+ ti->error = TPM_BAD_PARAMETER;
+ return false;
+ }
+
+ offset = 0;
+ UNLOAD_INTEGER(sub_cap, offset, index);
+
+ resp_size = sizeof(resp);
+ ret = tpm12_get_capability(locality, TPM_CAP_NV_INDEX, sizeof(sub_cap),
+ sub_cap, &resp_size, resp);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: get nvindex permission, return value = %08X\n", ret);
+#endif
+ if ( ret != TPM_SUCCESS ) {
+ printk(TBOOT_WARN"TPM: fail to get public data of 0x%08X in TPM NV\n", index);
+ ti->error = ret;
+ return false;
+ }
+
+#ifdef TPM_TRACE
+ {
+ printk(TBOOT_INFO"TPM: ");
+ print_hex(NULL, resp, resp_size);
+ }
+#endif
+
+ /* check size */
+ if ( resp_size == 0 ) {
+ printk(TBOOT_WARN"TPM: Index 0x%08X does not exist\n", index);
+ ti->error = TPM_BADINDEX;
+ return false;
+ }
+
+ /* check index */
+ offset = sizeof(tpm_structure_tag_t);
+ LOAD_INTEGER(resp, offset, idx);
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: get index value = %08X\n", idx);
+#endif
+
+ if ( idx != index ) {
+ printk(TBOOT_WARN"TPM: Index 0x%08X is not the one expected 0x%08X\n",
+ idx, index);
+ ti->error = TPM_BADINDEX;
+ return false;
+ }
+
+ if ( resp_size != sizeof(resp) ) {
+ printk(TBOOT_ERR"TPM: public data size of Index 0x%08X responsed incorrect\n",
+ index);
+ ti->error = TPM_FAIL;
+ return false;
+ }
+
+ offset = resp_size - sizeof(uint32_t) - 3 * sizeof(uint8_t) - sizeof(uint32_t);
+ LOAD_INTEGER(resp, offset, *attribute);
+
+ return true;
+}
+
+typedef struct __packed {
+ tpm_structure_tag_t tag;
+ uint8_t disable;
+ uint8_t ownership;
+ uint8_t deactivated;
+ uint8_t read_pubek;
+ uint8_t disable_owner_clear;
+ uint8_t allow_maintenance;
+ uint8_t physical_presence_lifetime_lock;
+ uint8_t physical_presence_hw_enable;
+ uint8_t physical_presence_cmd_enable;
+ uint8_t cekp_used;
+ uint8_t tpm_post;
+ uint8_t tpm_post_lock;
+ uint8_t fips;
+ uint8_t operator;
+ uint8_t enable_revoke_ek;
+ uint8_t nv_locked;
+ uint8_t read_srk_pub;
+ uint8_t tpm_established;
+ uint8_t maintenance_done;
+ uint8_t disable_full_da_logic_info;
+} tpm_permanent_flags_t;
+
+typedef struct __packed {
+ tpm_structure_tag_t tag;
+ uint8_t deactivated;
+ uint8_t disable_force_clear;
+ uint8_t physical_presence;
+ uint8_t phycical_presence_lock;
+ uint8_t b_global_lock;
+} tpm_stclear_flags_t;
+
+#define TPM_CAP_FLAG 0x00000004
+#define TPM_CAP_FLAG_PERMANENT 0x00000108
+#define TPM_CAP_FLAG_VOLATILE 0x00000109
+
+static uint32_t tpm12_get_flags(uint32_t locality, uint32_t flag_id,
+ uint8_t *flags, uint32_t flag_size)
+{
+ uint32_t ret, offset, resp_size;
+ uint8_t sub_cap[sizeof(flag_id)];
+ tpm_structure_tag_t tag;
+
+ if ( flags == NULL ) {
+ printk(TBOOT_WARN"TPM: tpm12_get_flags() bad parameter\n");
+ return TPM_BAD_PARAMETER;
+ }
+
+ offset = 0;
+ UNLOAD_INTEGER(sub_cap, offset, flag_id);
+
+ resp_size = flag_size;
+ ret = tpm12_get_capability(locality, TPM_CAP_FLAG, sizeof(sub_cap),
+ sub_cap, &resp_size, flags);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: get flags %08X, return value = %08X\n", flag_id, ret);
+#endif
+ if ( ret != TPM_SUCCESS )
+ return ret;
+
+ /* 1.2 spec, main part 2, rev 103 add one more byte to permanent flags, to
+ be backward compatible, not assume all expected bytes can be gotten */
+ if ( resp_size > flag_size ) {
+ printk(TBOOT_WARN"TPM: tpm12_get_flags() response size too small\n");
+ return TPM_FAIL;
+ }
+
+ offset = 0;
+ LOAD_INTEGER(flags, offset, tag);
+ offset = 0;
+ UNLOAD_BLOB_TYPE(flags, offset, &tag);
+
+ return ret;
+}
+
+#define TPM_CAP_PROPERTY 0x00000005
+#define TPM_CAP_PROP_TIS_TIMEOUT 0x00000115
+
+static uint32_t tpm12_get_timeout(uint32_t locality,
+ uint8_t *prop, uint32_t prop_size)
+{
+ uint32_t ret, offset, resp_size, prop_id = TPM_CAP_PROP_TIS_TIMEOUT;
+ uint8_t sub_cap[sizeof(prop_id)];
+ uint32_t resp[4];
+
+ if ( (prop == NULL) || (prop_size < sizeof(resp)) ) {
+ printk(TBOOT_WARN"TPM: tpm12_get_timeout() bad parameter\n");
+ return TPM_BAD_PARAMETER;
+ }
+
+ offset = 0;
+ UNLOAD_INTEGER(sub_cap, offset, prop_id);
+
+ resp_size = prop_size;
+ ret = tpm12_get_capability(locality, TPM_CAP_PROPERTY, sizeof(sub_cap),
+ sub_cap, &resp_size, prop);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: get prop %08X, return value = %08X\n", prop_id, ret);
+#endif
+ if ( ret != TPM_SUCCESS )
+ return ret;
+
+ if ( resp_size != prop_size ) {
+ printk(TBOOT_WARN"TPM: tpm_get_property() response size incorrect\n");
+ return TPM_FAIL;
+ }
+
+ offset = 0;
+ LOAD_INTEGER(prop, offset, resp);
+ offset = 0;
+ UNLOAD_BLOB_TYPE(prop, offset, &resp);
+
+ return ret;
+}
+
+/* ensure TPM is ready to accept commands */
+static bool tpm12_init(struct tpm_if *ti)
+{
+ tpm_permanent_flags_t pflags;
+ tpm_stclear_flags_t vflags;
+ uint32_t timeout[4];
+ uint32_t locality;
+ uint32_t ret;
+
+ if ( ti == NULL )
+ return false;
+
+ locality = ti->cur_loc;
+ if ( !tpm_validate_locality(locality) ) {
+ printk(TBOOT_WARN"TPM is not available.\n");
+ return false;
+ }
+
+ /* make sure tpm is not disabled/deactivated */
+ memset(&pflags, 0, sizeof(pflags));
+ ret = tpm12_get_flags(locality, TPM_CAP_FLAG_PERMANENT,
+ (uint8_t *)&pflags, sizeof(pflags));
+ if ( ret != TPM_SUCCESS ) {
+ printk(TBOOT_WARN"TPM is disabled or deactivated.\n");
+ ti->error = ret;
+ return false;
+ }
+ if ( pflags.disable ) {
+ printk(TBOOT_WARN"TPM is disabled.\n");
+ return false;
+ }
+
+ memset(&vflags, 0, sizeof(vflags));
+ ret = tpm12_get_flags(locality, TPM_CAP_FLAG_VOLATILE,
+ (uint8_t *)&vflags, sizeof(vflags));
+ if ( ret != TPM_SUCCESS ) {
+ printk(TBOOT_WARN"TPM is disabled or deactivated.\n");
+ ti->error = ret;
+ return false;
+ }
+ if ( vflags.deactivated ) {
+ printk(TBOOT_WARN"TPM is deactivated.\n");
+ return false;
+ }
+
+ printk(TBOOT_INFO"TPM is ready\n");
+ printk(TBOOT_DETA"TPM nv_locked: %s\n", (pflags.nv_locked != 0) ? "TRUE" : "FALSE");
+
+ /* get tpm timeout values */
+ ret = tpm12_get_timeout(locality, (uint8_t *)&timeout, sizeof(timeout));
+ if ( ret != TPM_SUCCESS ) {
+ printk(TBOOT_WARN"TPM timeout values are not achieved, "
+ "default values will be used.\n");
+ ti->error = ret;
+ } else {
+ /*
+ * timeout_x represents the number of milliseconds for the timeout
+ * and timeout[x] represents the number of microseconds.
+ */
+ ti->timeout.timeout_a = timeout[0]/1000;
+ ti->timeout.timeout_b = timeout[1]/1000;
+ ti->timeout.timeout_c = timeout[2]/1000;
+ ti->timeout.timeout_d = timeout[3]/1000;
+ printk(TBOOT_DETA"TPM timeout values: A: %u, B: %u, C: %u, D: %u\n",
+ ti->timeout.timeout_a, ti->timeout.timeout_b, ti->timeout.timeout_c,
+ ti->timeout.timeout_d);
+ /*
+ * if any timeout values are less than default values, set to default
+ * value (due to bug with some TPMs)
+ */
+ if ( ti->timeout.timeout_a < TIMEOUT_A ) {
+ ti->timeout.timeout_a = TIMEOUT_A;
+ printk(TBOOT_WARN"Wrong timeout A, fallback to %u\n", TIMEOUT_A);
+ }
+ if ( ti->timeout.timeout_b < TIMEOUT_B ) {
+ ti->timeout.timeout_b = TIMEOUT_B;
+ printk(TBOOT_WARN"Wrong timeout B, fallback to %u\n", TIMEOUT_B);
+ }
+ if ( ti->timeout.timeout_c < TIMEOUT_C ) {
+ ti->timeout.timeout_c = TIMEOUT_C;
+ printk(TBOOT_WARN"Wrong timeout C, fallback to %u\n", TIMEOUT_C);
+ }
+ if ( ti->timeout.timeout_d < TIMEOUT_D ) {
+ ti->timeout.timeout_d = TIMEOUT_D;
+ printk(TBOOT_WARN"Wrong timeout D, fallback to %u\n", TIMEOUT_D);
+ }
+ }
+
+ /* init version */
+ ti->major = TPM12_VER_MAJOR;
+ ti->minor = TPM12_VER_MINOR;
+
+ /* init supported alg list */
+ ti->banks = 1;
+ ti->alg_count = 1;
+ ti->algs[0] = TB_HALG_SHA1;
+ ti->extpol = TB_EXTPOL_FIXED;
+ ti->cur_alg = TB_HALG_SHA1;
+
+ /* init NV index */
+ ti->tb_policy_index = 0x20000001;
+ ti->lcp_own_index = 0x40000001;
+ ti->tb_err_index = 0x20000002;
+ ti->sgx_svn_index = 0x50000004;
+
+ return true;
+}
+
+static uint32_t tpm12_save_state(struct tpm_if *ti, uint32_t locality)
+{
+ uint32_t ret, offset, out_size;
+ uint32_t retries = 0;
+
+ if ( ti == NULL )
+ return TPM_BAD_PARAMETER;
+
+ do {
+ offset = 0;
+ out_size = 0;
+
+ ret = tpm12_submit_cmd(locality, TPM_ORD_SAVE_STATE, offset, &out_size);
+ if ( retries == 0 )
+ printk(TBOOT_INFO"TPM: save state, return value = %08X\n", ret);
+ else if ( retries == 1 )
+ printk(TBOOT_INFO"retrying command: .");
+ else
+ printk(TBOOT_INFO".");
+
+ if ( ret != TPM_RETRY )
+ break;
+
+ retries++;
+ delay(100);
+ } while ( retries < MAX_SAVESTATE_RETRIES );
+ if ( retries >= MAX_SAVESTATE_RETRIES )
+ printk(TBOOT_INFO"TIMEOUT!");
+ if ( retries > 0 )
+ printk(TBOOT_INFO"\n");
+
+ return ret;
+}
+
+static bool tpm12_get_random(struct tpm_if *ti, uint32_t locality,
+ uint8_t *random_data, uint32_t *data_size)
+{
+ uint32_t ret, in_size = 0, out_size, requested_size;
+ static bool first_attempt;
+
+ if ( ti == NULL )
+ return false;
+
+ if ( random_data == NULL || data_size == NULL || *data_size == 0 ) {
+ ti->error = TPM_BAD_PARAMETER;
+ return false;
+ }
+
+ first_attempt = true;
+ requested_size = *data_size;
+
+ /* copy the *data_size into buf in reversed byte order */
+ reverse_copy(WRAPPER_IN_BUF + in_size, data_size, sizeof(*data_size));
+ in_size += sizeof(*data_size);
+
+ out_size = *data_size + sizeof(*data_size);
+ ret = tpm12_submit_cmd(locality, TPM_ORD_GET_RANDOM, in_size, &out_size);
+
+#ifdef TPM_TRACE
+ printk(TBOOT_DETA"TPM: get random %u bytes, return value = %08X\n", *data_size, ret);
+#endif
+ if ( ret != TPM_SUCCESS ) {
+ printk(TBOOT_WARN"TPM: get random %u bytes, return value = %08X\n", *data_size, ret);
+ ti->error = ret;
+ return false;
+ }
+
+#ifdef TPM_TRACE
+ {
+ printk(TBOOT_INFO"TPM: ");
+ print_hex(NULL, WRAPPER_OUT_BUF, out_size);
+ }
+#endif
+
+ if ( out_size <= sizeof(*data_size) ) {
+ *data_size = 0;
+ return true;
+ }
+
+ out_size -= sizeof(*data_size);
+ reverse_copy(data_size, WRAPPER_OUT_BUF, sizeof(*data_size));
+ if ( *data_size > 0 )
+ memcpy(random_data, WRAPPER_OUT_BUF + sizeof(*data_size), *data_size);
+
+ /* data might be used as key, so clear from buffer memory */
+ memset(WRAPPER_OUT_BUF + sizeof(*data_size), 0, *data_size);
+
+ /* if TPM doesn't return all requested random bytes, try one more time */
+ if ( *data_size < requested_size ) {
+ printk(TBOOT_WARN"requested %x random bytes but only got %x\n", requested_size,
+ *data_size);
+ /* we're only going to try twice */
+ if ( first_attempt ) {
+ first_attempt = false;
+ uint32_t second_size = requested_size - *data_size;
+ printk(TBOOT_INFO"trying one more time to get remaining %x bytes\n",
+ second_size);
+ if (!tpm12_get_random(ti, locality, random_data + *data_size,
+ &second_size))
+ return false;
+ *data_size += second_size;
+ }
+ }
+
+ return true;
+}
+
+static bool tpm12_cap_pcrs(struct tpm_if *ti, u32 locality, int pcr)
+{
+ bool was_capped[TPM_NR_PCRS] = {false};
+ tpm_pcr_value_t cap_val; /* use whatever val is on stack */
+
+ if ( ti == NULL )
+ return false;
+
+ if (pcr >= 0) {
+ _tpm12_pcr_extend(ti, locality, pcr, &cap_val);
+ return true;
+ }
+
+ /* ensure PCRs 17 + 18 are always capped */
+ _tpm12_pcr_extend(ti, locality, 17, &cap_val);
+ _tpm12_pcr_extend(ti, locality, 18, &cap_val);
+ was_capped[17] = was_capped[18] = true;
+
+ /* also cap every dynamic PCR we extended (only once) */
+ /* don't cap static PCRs since then they would be wrong after S3 resume */
+ /* TODO
+ memset(&was_capped, true, TPM_PCR_RESETABLE_MIN*sizeof(bool));
+ for ( int i = 0; i < g_pre_k_s3_state.num_vl_entries; i++ ) {
+ if ( !was_capped[g_pre_k_s3_state.vl_entries[i].pcr] ) {
+ _tpm12_pcr_extend(ti, locality, g_pre_k_s3_state.vl_entries[i].pcr, &cap_val);
+ was_capped[g_pre_k_s3_state.vl_entries[i].pcr] = true;
+ }
+ }*/
+
+ printk(TBOOT_INFO"cap'ed dynamic PCRs\n");
+ return true;
+}
+
+static bool tpm12_check(void)
+{
+ uint32_t ret, out_size = 0;
+
+ ret = tpm12_submit_cmd(0, 0xFFFFFFFF, 0, &out_size);
+
+ return ( ret == TPM_BAD_ORDINAL );
+}
+
+struct tpm_if tpm_12_if = {
+ .init = tpm12_init,
+ .pcr_read = tpm12_pcr_read,
+ .pcr_extend = tpm12_pcr_extend,
+ .pcr_reset = tpm12_pcr_reset,
+ .nv_read = tpm12_nv_read_value,
+ .nv_write = tpm12_nv_write_value,
+ .get_nvindex_size = tpm12_get_nvindex_size,
+ .get_nvindex_permission = tpm12_get_nvindex_permission,
+ .seal = tpm12_seal,
+ .unseal = tpm12_unseal,
+ .verify_creation = tpm12_verify_creation,
+ .get_random = tpm12_get_random,
+ .save_state = tpm12_save_state,
+ .cap_pcrs = tpm12_cap_pcrs,
+ .check = tpm12_check,
+ .cur_loc = 0,
+ .timeout.timeout_a = TIMEOUT_A,
+ .timeout.timeout_b = TIMEOUT_B,
+ .timeout.timeout_c = TIMEOUT_C,
+ .timeout.timeout_d = TIMEOUT_D,
+};
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/tpm_20.c b/tboot/tpm_20.c
new file mode 100644
index 0000000..87007d0
--- /dev/null
+++ b/tboot/tpm_20.c
@@ -0,0 +1,2406 @@
+/*
+ * tpm_20.c: TPM2.0-related support functions
+ *
+ * Copyright (c) 2006-2013, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <printk.h>
+#include <misc.h>
+#include <compiler.h>
+#include <processor.h>
+#include <io.h>
+#include <string.h>
+#include <tpm.h>
+#include <tpm_20.h>
+#include <sha1.h>
+#include <sha256.h>
+#include <cmdline.h>
+#include <uuid.h>
+#include <mle.h>
+#include <txt/acmod.h>
+
+static u8 cmd_buf[MAX_COMMAND_SIZE];
+static u8 rsp_buf[MAX_RESPONSE_SIZE];
+
+#define reverse_copy_in(out, var) {\
+ _reverse_copy((uint8_t *)(out), (uint8_t *)&(var), sizeof(var));\
+ out += sizeof(var);\
+}
+
+#define reverse_copy_out(var, out) {\
+ _reverse_copy((uint8_t *)&(var), (uint8_t *)(out), sizeof(var));\
+ out += sizeof(var);\
+}
+
+static void reverse_copy_header(u32 cmd_code, TPM_CMD_SESSIONS_IN *sessions_in)
+{
+ u16 tag;
+
+ if (sessions_in == NULL || sessions_in->num_sessions == 0)
+ tag = TPM_ST_NO_SESSIONS;
+ else
+ tag = TPM_ST_SESSIONS;
+
+ reverse_copy(cmd_buf, &tag, sizeof(tag));
+ reverse_copy(cmd_buf + CMD_CC_OFFSET, &cmd_code, sizeof(cmd_code));
+}
+
+static void reverse_copy_pcr_selection_in(void **other, TPML_PCR_SELECTION *pcr_selection)
+{
+ u32 i, k;
+
+ /* Copy count of pcrs to be read. */
+ reverse_copy_in(*other, pcr_selection->count);
+
+ for (i=0; i<pcr_selection->count; i++) {
+ /* Copy alg ID for PCR to be read. */
+ reverse_copy_in(*other, pcr_selection->selections[i].hash);
+
+ /* Copy size of select array. */
+ reverse_copy_in(*other, pcr_selection->selections[i].size_of_select);
+
+ /* Copy bit field of the PCRs selected. */
+ for (k=0; k<pcr_selection->selections[i].size_of_select; k++)
+ reverse_copy_in(*other, pcr_selection->selections[i].pcr_select[k]);
+ }
+}
+
+static void reverse_copy_pcr_selection_out(TPML_PCR_SELECTION *pcr_selection,
+ void **other)
+{
+ u32 i, k;
+
+ if (pcr_selection == NULL)
+ return;
+
+ /* Copy count of pcrs to be read. */
+ reverse_copy_out(pcr_selection->count, *other);
+
+ for (i=0; i<pcr_selection->count; i++) {
+ /* Copy alg ID for PCR to be read. */
+ reverse_copy_out(pcr_selection->selections[i].hash, *other);
+
+ /* Copy size of select array. */
+ reverse_copy_out(pcr_selection->selections[i].size_of_select, *other);
+
+ /* Copy bit field of the PCRs selected */
+ for (k=0; k<pcr_selection->selections[i].size_of_select; k++)
+ reverse_copy_out(pcr_selection->selections[i].pcr_select[k], *other);
+ }
+}
+
+/*
+ * Copy sized byte buffer from source to destination and
+ * twiddle the bytes in the size field.
+ *
+ * This can be used for the any of the following
+ * TPM 2.0 data structures, but is not limited to these:
+ *
+ * ENCRYPTED_SECRET_2B
+ * TPM2B_DIGEST
+ * TPM2B_NONCE
+ * TPM2B_DATA
+ * etc. (any structures consisting of UINT16 followed by a
+ * byte buffer whose size is specified by the UINT16.
+ *
+ * Inputs:
+ *
+ * dest -- pointer to SIZED_BYTE_BUFFER
+ * src -- pointer to SIZED_BYTE_BUFFER
+ *
+ * Outputs:
+ *
+ * number of bytes copied
+ */
+static u16 reverse_copy_sized_buf_in(TPM2B *dest, TPM2B *src)
+{
+ int i;
+
+ if (dest == NULL || src == NULL)
+ return 0;
+
+ reverse_copy(&dest->size, &src->size, sizeof(u16));
+ for (i=0; i<src->size; i++)
+ dest->buffer[i] = src->buffer[i];
+
+ return sizeof(u16) + src->size;
+}
+
+static u16 reverse_copy_sized_buf_out(TPM2B *dest, TPM2B *src)
+{
+ int i;
+
+ if (dest == NULL || src == NULL)
+ return 0;
+
+ reverse_copy(&dest->size, &src->size, sizeof(u16));
+ for (i=0; i<dest->size; i++)
+ dest->buffer[i] = src->buffer[i];
+
+ return sizeof(u16) + dest->size;
+}
+
+static void reverse_copy_digest_out(TPML_DIGEST *tpml_digest, void **other)
+{
+ u32 i;
+
+ if (tpml_digest == NULL)
+ return;
+
+ reverse_copy_out(tpml_digest->count, *other);
+
+ for (i=0; i<tpml_digest->count; i++)
+ *other += reverse_copy_sized_buf_out((TPM2B *)&(tpml_digest->digests[i]),
+ (TPM2B *)*other);
+}
+
+static void reverse_copy_session_data_in(void **other,
+ TPM_CMD_SESSION_DATA_IN *session_data,
+ u32 *session_size)
+{
+ *session_size += sizeof(u32) + sizeof( u16 ) +
+ session_data->nonce.t.size + sizeof( u8 ) +
+ sizeof( u16 ) + session_data->hmac.t.size;
+
+ /* copy session handle */
+ reverse_copy_in(*other, session_data->session_handle);
+
+ /* Copy nonce */
+ *other += reverse_copy_sized_buf_in((TPM2B *)*other, (TPM2B *)&session_data->nonce);
+
+ /* Copy attributes */
+ *((u8 *)*other) = *(u8 *)(void *)&(session_data->session_attr);
+ *other += sizeof(u8);
+
+ /* Copy hmac data */
+ *other += reverse_copy_sized_buf_in((TPM2B *)*other, (TPM2B *)&session_data->hmac);
+}
+
+static void reverse_copy_sessions_in(void **other, TPM_CMD_SESSIONS_IN *sessions_in)
+{
+ int i;
+ u32 session_size = 0;
+ void *session_size_ptr = *other;
+
+ if (sessions_in == NULL)
+ return;
+
+ if (sessions_in->num_sessions != 0) {
+ *other += sizeof(u32);
+ for (i=0; i<sessions_in->num_sessions; i++)
+ reverse_copy_session_data_in(other,
+ &sessions_in->sessions[i], &session_size);
+ }
+
+ reverse_copy(session_size_ptr, &session_size, sizeof(u32));
+}
+
+static void reverse_copy_session_data_out(TPM_CMD_SESSION_DATA_OUT *session_data,
+ void **other)
+{
+ if (session_data == NULL)
+ return;
+
+ /* Copy nonce */
+ *other += reverse_copy_sized_buf_out((TPM2B *)&(session_data->nonce),
+ (TPM2B *)*other);
+
+ /* Copy sessionAttributes */
+ *(u8 *)(void *)&(session_data->session_attr) = *((u8 *)*other);
+ *other += sizeof(u8);
+
+ /* Copy hmac */
+ *other += reverse_copy_sized_buf_out((TPM2B *)&(session_data->hmac),
+ (TPM2B *)*other);
+}
+
+static void reverse_copy_sessions_out(TPM_CMD_SESSIONS_OUT *sessions_out,
+ void *other, u16 rsp_tag,
+ TPM_CMD_SESSIONS_IN *sessions_in)
+{
+ int i;
+
+ if (sessions_in == NULL || sessions_out == NULL || rsp_tag != TPM_ST_SESSIONS)
+ return;
+
+ sessions_out->num_sessions = sessions_in->num_sessions;
+ for (i=0; i<sessions_in->num_sessions; i++)
+ reverse_copy_session_data_out(&sessions_out->sessions[i], &other);
+}
+
+typedef struct {
+ u16 alg_id;
+ u16 size; /* Size of digest */
+} HASH_SIZE_INFO;
+
+HASH_SIZE_INFO hash_sizes[] = {
+ {TPM_ALG_SHA1, SHA1_DIGEST_SIZE},
+ {TPM_ALG_SHA256, SHA256_DIGEST_SIZE},
+ {TPM_ALG_SHA384, SHA384_DIGEST_SIZE},
+ {TPM_ALG_SHA512, SHA512_DIGEST_SIZE},
+ {TPM_ALG_SM3_256, SM3_256_DIGEST_SIZE},
+ {TPM_ALG_NULL,0}
+};
+
+u16 get_digest_size(u16 id)
+{
+ unsigned int i;
+ for(i=0; i<(sizeof(hash_sizes)/sizeof(HASH_SIZE_INFO)); i++) {
+ if(hash_sizes[i].alg_id == id)
+ return hash_sizes[i].size;
+ }
+
+ /* If not found, return 0 size, and let TPM handle the error. */
+ return 0 ;
+}
+
+static void reverse_copy_digest_value_in(void **other, TPML_DIGEST_VALUES *tpml_digest)
+{
+ unsigned int i, k, num_bytes;
+
+ reverse_copy_in(*other, tpml_digest->count);
+
+ for (i=0; i<tpml_digest->count; i++) {
+ reverse_copy_in(*other, tpml_digest->digests[i].hash_alg);
+
+ num_bytes = get_digest_size(tpml_digest->digests[i].hash_alg);
+
+ for (k=0; k<num_bytes; k++) {
+ *((u8 *)*other) = tpml_digest->digests[i].digest.sha1[k];
+ *other += sizeof(u8);
+ }
+ }
+}
+
+static void reverse_copy_digest_values_out(TPML_DIGEST_VALUES *tpml_digest,
+ void **other)
+{
+ unsigned int i, k, num_bytes;
+
+ if (tpml_digest == NULL)
+ return;
+
+ reverse_copy_out(tpml_digest->count, *other);
+
+ for (i=0; i<tpml_digest->count; i++) {
+ reverse_copy_out(tpml_digest->digests[i].hash_alg, *other);
+
+ num_bytes = get_digest_size(tpml_digest->digests[i].hash_alg);
+
+ for (k=0; k<num_bytes; k++) {
+ tpml_digest->digests[i].digest.sha1[k] = *((u8 *)*other);
+ *other += sizeof(u8);
+ }
+ }
+}
+
+/*
+ * Copy public data from input data structure into output data stream
+ * for commands that require it.
+ *
+ * Inputs:
+ *
+ * pointer to pointer to TPM command area to fill in with public data
+ *
+ * pointer to TPM2B_PUBLIC structure
+ *
+ * Outputs:
+ *
+ * otherData pointer points to end byte past command buffer. This allows
+ * caller to set the commandSize field for the command.
+ */
+static void reverse_copy_public_in(void **other, TPM2B_PUBLIC *public)
+{
+ TPMT_KEYEDHASH_SCHEME *scheme;
+ TPMT_RSA_SCHEME *rsa_scheme = &(public->t.public_area.param.rsa.scheme);
+ TPMT_ECC_SCHEME *ecc_scheme = &(public->t.public_area.param.ecc.scheme);
+ TPMT_KDF_SCHEME *kdf = &(public->t.public_area.param.ecc.kdf);
+ TPMT_ASYM_SCHEME *asym_scheme = &(public->t.public_area.param.asym.scheme);
+ void *size_ptr;
+ u16 size;
+
+ size_ptr = *other;
+ *other += sizeof(u16);
+
+ reverse_copy_in(*other, public->t.public_area.type);
+ reverse_copy_in(*other, public->t.public_area.name_alg);
+
+ /* Copy public->t.object_attr */
+ reverse_copy(*other, (void *)&public->t.public_area.object_attr, sizeof(u32));
+ *other += sizeof(u32);
+
+ /* Copy public->t.auth_policy */
+ *other += reverse_copy_sized_buf_in((TPM2B *)*other,
+ (TPM2B *)&public->t.public_area.auth_policy);
+
+ /* Copy public->t.param */
+ switch(public->t.public_area.type) {
+ case TPM_ALG_KEYEDHASH:
+ scheme = &(public->t.public_area.param.keyed_hash.scheme);
+
+ reverse_copy_in(*other, scheme->scheme);
+
+ if(scheme->scheme != TPM_ALG_NULL) {
+ /* copy details */
+ if(scheme->scheme == TPM_ALG_HMAC) {
+ reverse_copy_in(*other, scheme->details.hmac.hash_alg);
+ } else {
+ reverse_copy_in(*other, scheme->details.xor.hash_alg);
+ reverse_copy_in(*other, scheme->details.xor.kdf);
+ }
+ }
+
+ /* Copy public->t.public_area.unique */
+ *other += reverse_copy_sized_buf_in((TPM2B *)*other,
+ (TPM2B *)&public->t.public_area.unique.keyed_hash);
+
+ break;
+
+ case TPM_ALG_SYMCIPHER:
+ reverse_copy_in(*other, public->t.public_area.param.sym.alg);
+
+ if (public->t.public_area.param.sym.alg != TPM_ALG_NULL) {
+ reverse_copy_in(*other, public->t.public_area.param.sym.key_bits.sym);
+
+ reverse_copy_in(*other, public->t.public_area.param.sym.mode.sym);
+ }
+
+ /* Copy public->t.public_area.unique */
+ *other += reverse_copy_sized_buf_in((TPM2B *)*other,
+ (TPM2B *)&public->t.public_area.unique.sym);
+
+ break;
+
+ case TPM_ALG_RSA:
+ /* Copy symmetric fields */
+ reverse_copy_in(*other, public->t.public_area.param.rsa.symmetric.alg);
+
+ if (public->t.public_area.param.rsa.symmetric.alg != TPM_ALG_NULL) {
+ reverse_copy_in(*other, public->t.public_area.param.rsa.symmetric.key_bits.sym);
+
+ reverse_copy_in(*other, public->t.public_area.param.rsa.symmetric.mode.sym);
+ }
+
+ /* Copy scheme */
+ reverse_copy_in(*other, rsa_scheme->scheme);
+ if (rsa_scheme->scheme != TPM_ALG_NULL) {
+ switch (rsa_scheme->scheme) {
+ case TPM_ALG_RSASSA:
+ reverse_copy_in(*other, rsa_scheme->details.rsassa.hash_alg);
+ break;
+
+ case TPM_ALG_RSAPSS:
+ reverse_copy_in(*other, rsa_scheme->details.rsapss.hash_alg);
+ break;
+
+ case TPM_ALG_OAEP:
+ reverse_copy_in(*other, rsa_scheme->details.oaep.hash_alg);
+ break;
+
+ case TPM_ALG_ECDSA:
+ reverse_copy_in(*other, rsa_scheme->details.ecdsa.hash_alg);
+ break;
+
+ case TPM_ALG_SM2:
+ reverse_copy_in(*other, rsa_scheme->details.sm2.hash_alg);
+ break;
+
+ case TPM_ALG_ECDAA:
+ reverse_copy_in(*other, rsa_scheme->details.ecdaa.hash_alg);
+ reverse_copy_in(*other, rsa_scheme->details.ecdaa.count);
+ break;
+
+ case TPM_ALG_ECSCHNORR:
+ reverse_copy_in(*other, rsa_scheme->details.ec_schnorr.hash_alg);
+ break;
+
+ default:
+ reverse_copy_in(*other, rsa_scheme->details.any.hash_alg);
+ break;
+ }
+ }
+
+ /* Copy keybits */
+ reverse_copy_in(*other, public->t.public_area.param.rsa.key_bits);
+
+ /* Copy exponent */
+ reverse_copy_in(*other, public->t.public_area.param.rsa.exponent);
+
+ /* Copy public->t.public_area.unique */
+ *other += reverse_copy_sized_buf_in((TPM2B *)*other,
+ (TPM2B *)&public->t.public_area.unique.rsa);
+
+ break;
+
+ case TPM_ALG_ECC:
+ /* Copy symmetric fields */
+ reverse_copy_in(*other, public->t.public_area.param.ecc.symmetric.alg);
+
+ if (public->t.public_area.param.ecc.symmetric.alg != TPM_ALG_NULL) {
+ reverse_copy_in(*other, public->t.public_area.param.ecc.symmetric.key_bits.sym);
+
+ reverse_copy_in(*other, public->t.public_area.param.ecc.symmetric.mode.sym);
+ }
+
+ /* Copy ECC scheme */
+ reverse_copy_in(*other, ecc_scheme->scheme);
+ if (ecc_scheme->scheme != TPM_ALG_NULL) {
+ switch (ecc_scheme->scheme) {
+ case TPM_ALG_RSASSA:
+ reverse_copy_in(*other, ecc_scheme->details.rsassa.hash_alg);
+ break;
+
+ case TPM_ALG_RSAPSS:
+ reverse_copy_in(*other, ecc_scheme->details.rsapss.hash_alg);
+ break;
+
+ case TPM_ALG_ECDSA:
+ reverse_copy_in(*other, ecc_scheme->details.ecdsa.hash_alg);
+ break;
+
+ case TPM_ALG_SM2:
+ reverse_copy_in(*other, ecc_scheme->details.sm2.hash_alg);
+ break;
+
+ case TPM_ALG_ECDAA:
+ reverse_copy_in(*other, ecc_scheme->details.ecdaa.hash_alg);
+ reverse_copy_in(*other, ecc_scheme->details.ecdaa.count);
+ break;
+
+ case TPM_ALG_ECSCHNORR:
+ reverse_copy_in(*other, ecc_scheme->details.ec_schnorr.hash_alg);
+ break;
+
+ case TPM_ALG_HMAC:
+ reverse_copy_in(*other, ecc_scheme->details.hmac.hash_alg);
+ break;
+
+ default:
+ reverse_copy_in(*other, ecc_scheme->details.any.hash_alg);
+ break;
+ }
+ }
+
+ /* Copy curve_id */
+ reverse_copy_in(*other, public->t.public_area.param.ecc.curve_id);
+
+ /* Copy KDF scheme */
+ reverse_copy_in(*other, kdf->scheme);
+ switch (kdf->scheme) {
+ case TPM_ALG_MGF1:
+ reverse_copy_in(*other, kdf->details.mgf1.hash_alg);
+ break;
+
+ case TPM_ALG_KDF1_SP800_56a:
+ reverse_copy_in(*other, kdf->details.kdf1_SP800_56a.hash_alg);
+ break;
+
+ case TPM_ALG_KDF1_SP800_108:
+ reverse_copy_in(*other, kdf->details.kdf1_sp800_108.hash_alg);
+ break;
+
+ default:
+ /* Copy something bogus and let TPM return error code */
+ *((u16 *)*other) = 0xffff;
+ *other += sizeof(u16);
+ break;
+ }
+
+ /* Copy public->t.public_area.unique */
+ *other += reverse_copy_sized_buf_in((TPM2B *)*other,
+ (TPM2B *)&public->t.public_area.unique.ecc);
+
+ break;
+
+ default:
+ /* Copy symmetric fields */
+ reverse_copy_in(*other, public->t.public_area.param.asym.symmetric.alg);
+
+ if (public->t.public_area.param.asym.symmetric.alg != TPM_ALG_NULL) {
+ reverse_copy_in(*other, public->t.public_area.param.asym.symmetric.key_bits.sym);
+
+ reverse_copy_in(*other, public->t.public_area.param.asym.symmetric.mode.sym);
+ }
+
+ /* Copy scheme */
+ reverse_copy_in(*other, asym_scheme->scheme);
+ if (asym_scheme->scheme != TPM_ALG_NULL) {
+ switch (asym_scheme->scheme) {
+ case TPM_ALG_RSASSA:
+ reverse_copy_in(*other, asym_scheme->details.rsassa.hash_alg);
+ break;
+
+ case TPM_ALG_RSAPSS:
+ reverse_copy_in(*other, asym_scheme->details.rsapss.hash_alg);
+ break;
+
+ case TPM_ALG_OAEP:
+ reverse_copy_in(*other, asym_scheme->details.oaep.hash_alg);
+ break;
+
+ case TPM_ALG_ECDSA:
+ reverse_copy_in(*other, asym_scheme->details.ecdsa.hash_alg);
+ break;
+
+ case TPM_ALG_SM2:
+ reverse_copy_in(*other, asym_scheme->details.sm2.hash_alg);
+ break;
+
+ case TPM_ALG_ECDAA:
+ reverse_copy_in(*other, asym_scheme->details.ecdaa.hash_alg);
+ reverse_copy_in(*other, asym_scheme->details.ecdaa.count);
+ break;
+
+ case TPM_ALG_ECSCHNORR:
+ reverse_copy_in(*other, asym_scheme->details.ec_schnorr.hash_alg);
+ break;
+
+ default:
+ reverse_copy_in(*other, asym_scheme->details.any.hash_alg);
+ break;
+ }
+ }
+
+ break;
+ }
+
+ /* Now calculate and write the inPublic size; don't include size field in the size calc */
+ size = (u8 *)*other - (u8 *)size_ptr - sizeof(u16);
+ reverse_copy(size_ptr, &size, sizeof(u16));
+}
+
+/*
+ * Copy public data from input data structure into output data stream
+ * for commands that require it.
+ *
+ * Inputs:
+ *
+ * pointer to TPM2B_PUBLIC structure for returned data
+ *
+ * pointer to pointer to TPM command byte stream for the returned data
+ *
+ * Outputs:
+ *
+ * public contains the de-canonicalized data extracted from the output data stream
+ */
+static void reverse_copy_public_out(TPM2B_PUBLIC *public, void **other)
+{
+ TPMT_KEYEDHASH_SCHEME *scheme;
+ TPMT_RSA_SCHEME *rsa_scheme = &(public->t.public_area.param.rsa.scheme);
+ TPMT_ECC_SCHEME *ecc_scheme = &(public->t.public_area.param.ecc.scheme);
+ TPMT_KDF_SCHEME *kdf = &(public->t.public_area.param.ecc.kdf);
+ TPMT_ASYM_SCHEME *asym_scheme = &(public->t.public_area.param.asym.scheme);
+
+ if (public == NULL)
+ return;
+
+ reverse_copy_out(public->t.size, *other);
+ reverse_copy_out(public->t.public_area.type, *other);
+ reverse_copy_out(public->t.public_area.name_alg, *other);
+
+ /* Copy public->t.object_attr */
+ reverse_copy((void *)&public->t.public_area.object_attr, *other, sizeof(u32));
+ *other += sizeof(u32);
+
+ /* Copy public->t.auth_policy */
+ *other += reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.auth_policy,
+ (TPM2B *)*other);
+
+ /* Copy public->t.param */
+ switch(public->t.public_area.type) {
+ case TPM_ALG_KEYEDHASH:
+ scheme = &(public->t.public_area.param.keyed_hash.scheme);
+
+ reverse_copy_out(scheme->scheme, *other);
+
+ if(scheme->scheme != TPM_ALG_NULL) {
+ /* copy details */
+ if(scheme->scheme == TPM_ALG_HMAC) {
+ reverse_copy_out(scheme->details.hmac.hash_alg, *other);
+ } else {
+ reverse_copy_out(scheme->details.xor.hash_alg, *other);
+ reverse_copy_out(scheme->details.xor.kdf, *other);
+ }
+ }
+
+ /* Copy public->t.public_area.unique */
+ *other += reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.unique.keyed_hash,
+ (TPM2B *)*other);
+
+ break;
+
+ case TPM_ALG_SYMCIPHER:
+ reverse_copy_out(public->t.public_area.param.sym.alg, *other);
+
+ if (public->t.public_area.param.sym.alg != TPM_ALG_NULL) {
+ reverse_copy_out(public->t.public_area.param.sym.key_bits.sym, *other);
+
+ reverse_copy_out(public->t.public_area.param.sym.mode.sym, *other);
+ }
+
+ /* Copy public->t.public_area.unique */
+ *other += reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.unique.sym,
+ (TPM2B *)*other);
+
+ break;
+
+ case TPM_ALG_RSA:
+ /* Copy symmetric fields */
+ reverse_copy_out(public->t.public_area.param.rsa.symmetric.alg, *other);
+
+ if (public->t.public_area.param.rsa.symmetric.alg != TPM_ALG_NULL) {
+ reverse_copy_out(public->t.public_area.param.rsa.symmetric.key_bits.sym, *other);
+
+ reverse_copy_out(public->t.public_area.param.rsa.symmetric.mode.sym, *other);
+ }
+
+ /* Copy scheme */
+ reverse_copy_out(rsa_scheme->scheme, *other);
+ if (rsa_scheme->scheme != TPM_ALG_NULL) {
+ switch (rsa_scheme->scheme) {
+ case TPM_ALG_RSASSA:
+ reverse_copy_out(rsa_scheme->details.rsassa.hash_alg, *other);
+ break;
+
+ case TPM_ALG_RSAPSS:
+ reverse_copy_out(rsa_scheme->details.rsapss.hash_alg, *other);
+ break;
+
+ case TPM_ALG_OAEP:
+ reverse_copy_out(rsa_scheme->details.oaep.hash_alg, *other);
+ break;
+
+ case TPM_ALG_ECDSA:
+ reverse_copy_out(rsa_scheme->details.ecdsa.hash_alg, *other);
+ break;
+
+ case TPM_ALG_SM2:
+ reverse_copy_out(rsa_scheme->details.sm2.hash_alg, *other);
+ break;
+
+ case TPM_ALG_ECDAA:
+ reverse_copy_out(rsa_scheme->details.ecdaa.hash_alg, *other);
+ reverse_copy_out(rsa_scheme->details.ecdaa.count, *other);
+ break;
+
+ case TPM_ALG_ECSCHNORR:
+ reverse_copy_out(rsa_scheme->details.ec_schnorr.hash_alg, *other);
+ break;
+
+ default:
+ reverse_copy_out(rsa_scheme->details.any.hash_alg, *other);
+ break;
+ }
+ }
+
+ /* Copy keybits */
+ reverse_copy_out(public->t.public_area.param.rsa.key_bits, *other);
+
+ /* Copy exponent */
+ reverse_copy_out(public->t.public_area.param.rsa.exponent, *other);
+
+ /* Copy public->t.public_area.unique */
+ *other += reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.unique.rsa,
+ (TPM2B *)*other);
+
+ break;
+
+ case TPM_ALG_ECC:
+ /* Copy symmetric fields */
+ reverse_copy_out(public->t.public_area.param.ecc.symmetric.alg, *other);
+
+ if (public->t.public_area.param.ecc.symmetric.alg != TPM_ALG_NULL) {
+ reverse_copy_out(public->t.public_area.param.ecc.symmetric.key_bits.sym, *other);
+
+ reverse_copy_out(public->t.public_area.param.ecc.symmetric.mode.sym, *other);
+ }
+
+ /* Copy ECC scheme */
+ reverse_copy_out(ecc_scheme->scheme, *other);
+ if (ecc_scheme->scheme != TPM_ALG_NULL) {
+ switch (ecc_scheme->scheme) {
+ case TPM_ALG_RSASSA:
+ reverse_copy_out(ecc_scheme->details.rsassa.hash_alg, *other);
+ break;
+
+ case TPM_ALG_RSAPSS:
+ reverse_copy_out(ecc_scheme->details.rsapss.hash_alg, *other);
+ break;
+
+ case TPM_ALG_ECDSA:
+ reverse_copy_out(ecc_scheme->details.ecdsa.hash_alg, *other);
+ break;
+
+ case TPM_ALG_SM2:
+ reverse_copy_out(ecc_scheme->details.sm2.hash_alg, *other);
+ break;
+
+ case TPM_ALG_ECDAA:
+ reverse_copy_out(ecc_scheme->details.ecdaa.hash_alg, *other);
+ reverse_copy_out(ecc_scheme->details.ecdaa.count, *other);
+ break;
+
+ case TPM_ALG_ECSCHNORR:
+ reverse_copy_out(ecc_scheme->details.ec_schnorr.hash_alg, *other);
+ break;
+
+ case TPM_ALG_HMAC:
+ reverse_copy_out(ecc_scheme->details.hmac.hash_alg, *other);
+ break;
+
+ default:
+ reverse_copy_out(ecc_scheme->details.any.hash_alg, *other);
+ break;
+ }
+ }
+
+ /* Copy curve_id */
+ reverse_copy_out(public->t.public_area.param.ecc.curve_id, *other);
+
+ /* Copy KDF scheme */
+ reverse_copy_out(kdf->scheme, *other);
+ switch (kdf->scheme) {
+ case TPM_ALG_MGF1:
+ reverse_copy_out(kdf->details.mgf1.hash_alg, *other);
+ break;
+
+ case TPM_ALG_KDF1_SP800_56a:
+ reverse_copy_out(kdf->details.kdf1_SP800_56a.hash_alg, *other);
+ break;
+
+ case TPM_ALG_KDF1_SP800_108:
+ reverse_copy_out(kdf->details.kdf1_sp800_108.hash_alg, *other);
+ break;
+
+ default:
+ /* Copy something bogus and let TPM return error code */
+ *((u16 *)*other) = 0xffff;
+ *other += sizeof(u16);
+ break;
+ }
+
+ /* Copy public->t.public_area.unique */
+ *other += reverse_copy_sized_buf_out((TPM2B *)&public->t.public_area.unique.ecc,
+ (TPM2B *)*other);
+
+ break;
+
+ default:
+ /* Copy symmetric fields */
+ reverse_copy_out(public->t.public_area.param.asym.symmetric.alg, *other);
+
+ if (public->t.public_area.param.asym.symmetric.alg != TPM_ALG_NULL) {
+ reverse_copy_out(public->t.public_area.param.asym.symmetric.key_bits.sym, *other);
+
+ reverse_copy_out(public->t.public_area.param.asym.symmetric.mode.sym, *other);
+ }
+
+ /* Copy scheme */
+ reverse_copy_out(asym_scheme->scheme, *other);
+ if (asym_scheme->scheme != TPM_ALG_NULL) {
+ switch (asym_scheme->scheme) {
+ case TPM_ALG_RSASSA:
+ reverse_copy_out(asym_scheme->details.rsassa.hash_alg, *other);
+ break;
+
+ case TPM_ALG_RSAPSS:
+ reverse_copy_out(asym_scheme->details.rsapss.hash_alg, *other);
+ break;
+
+ case TPM_ALG_OAEP:
+ reverse_copy_out(asym_scheme->details.oaep.hash_alg, *other);
+ break;
+
+ case TPM_ALG_ECDSA:
+ reverse_copy_out(asym_scheme->details.ecdsa.hash_alg, *other);
+ break;
+
+ case TPM_ALG_SM2:
+ reverse_copy_out(asym_scheme->details.sm2.hash_alg, *other);
+ break;
+
+ case TPM_ALG_ECDAA:
+ reverse_copy_out(asym_scheme->details.ecdaa.hash_alg, *other);
+ reverse_copy_out(asym_scheme->details.ecdaa.count, *other);
+ break;
+
+ case TPM_ALG_ECSCHNORR:
+ reverse_copy_out(asym_scheme->details.ec_schnorr.hash_alg, *other);
+ break;
+
+ default:
+ reverse_copy_out(asym_scheme->details.any.hash_alg, *other);
+ break;
+ }
+ }
+
+ break;
+ }
+}
+
+static void reverse_copy_creation_data_out(TPM2B_CREATION_DATA *data, void **other)
+{
+ if (data == NULL)
+ return;
+
+ reverse_copy_out(data->t.size, *other);
+
+ reverse_copy_pcr_selection_out(&data->t.data.pcr_select, other);
+
+ *other += reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.pcr_digest),
+ (TPM2B *)*other);
+
+ *((u8 *)(void *)&data->t.data.locality) = *((u8 *)*other);
+ *other += sizeof(u8);
+
+ reverse_copy_out(data->t.data.parent_name_alg, *other);
+
+ *other += reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.parent_name),
+ (TPM2B *)*other);
+ *other += reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.parent_qualified_name),
+ (TPM2B *)*other);
+ *other += reverse_copy_sized_buf_out((TPM2B *)&(data->t.data.outside_info),
+ (TPM2B *)*other);
+}
+
+static void reverse_copy_ticket_out(TPMT_TK_CREATION *ticket, void **other)
+{
+ if (ticket == NULL)
+ return;
+
+ reverse_copy_out(ticket->tag, *other);
+
+ reverse_copy_out(ticket->hierarchy, *other);
+
+ *other += reverse_copy_sized_buf_out((TPM2B *)&(ticket->digest), (TPM2B *)*other);
+}
+
+static uint32_t _tpm20_pcr_read(u32 locality,
+ tpm_pcr_read_in *in,
+ tpm_pcr_read_out *out)
+{
+ u32 ret;
+ u32 cmd_size, rsp_size;
+ u16 rsp_tag;
+ void *other;
+
+ reverse_copy_header(TPM_CC_PCR_Read, 0);
+
+ other = (void *)cmd_buf + CMD_HEAD_SIZE;
+ reverse_copy_pcr_selection_in(&other, &in->pcr_selection);
+
+ /* Now set the command size field, now that we know the size of the whole command */
+ cmd_size = (u8 *)other - cmd_buf;
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+
+ rsp_size = sizeof(*out);
+
+ if (g_tpm_family == TPM_IF_20_FIFO) {
+ if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+ if (g_tpm_family == TPM_IF_20_CRB) {
+ if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret));
+ if ( ret != TPM_RC_SUCCESS )
+ return ret;
+
+ other = (void *)rsp_buf + RSP_HEAD_SIZE;
+ reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag));
+
+ if (rsp_tag == TPM_ST_SESSIONS)
+ other += sizeof(u32); /* Skip past parameter size field */
+
+ reverse_copy_out(out->pcr_update_counter, other);
+
+ reverse_copy_pcr_selection_out(&out->pcr_selection, &other);
+
+ reverse_copy_digest_out(&out->pcr_values, &other);
+
+ return ret;
+}
+
+static uint32_t _tpm20_pcr_extend(uint32_t locality,
+ tpm_pcr_extend_in *in,
+ tpm_pcr_extend_out *out)
+{
+ u32 ret;
+ u32 cmd_size, rsp_size;
+ u16 rsp_tag;
+ void *other;
+
+ reverse_copy_header(TPM_CC_PCR_Extend, &in->sessions);
+
+ other = (void *)cmd_buf + CMD_HEAD_SIZE;
+ reverse_copy_in(other, in->pcr_handle);
+
+ reverse_copy_sessions_in(&other, &in->sessions);
+
+ reverse_copy_digest_value_in(&other, &in->digests);
+
+ /* Now set the command size field, now that we know the size of the whole command */
+ cmd_size = (u8 *)other - cmd_buf;
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+
+ rsp_size = sizeof(*out);
+
+ if (g_tpm_family == TPM_IF_20_FIFO) {
+ if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+ if (g_tpm_family == TPM_IF_20_CRB) {
+ if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret));
+ if ( ret != TPM_RC_SUCCESS )
+ return ret;
+
+ other = (void *)rsp_buf + RSP_HEAD_SIZE;
+ reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag));
+ if (rsp_tag == TPM_ST_SESSIONS)
+ other += sizeof(u32);
+
+ reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions);
+
+ return ret;
+}
+
+static uint32_t _tpm20_pcr_event(uint32_t locality,
+ tpm_pcr_event_in *in,
+ tpm_pcr_event_out *out)
+{
+ u32 ret;
+ u32 cmd_size, rsp_size;
+ u16 rsp_tag;
+ void *other;
+
+ reverse_copy_header(TPM_CC_PCR_Event, &in->sessions);
+
+ other = (void *)cmd_buf + CMD_HEAD_SIZE;
+ reverse_copy_in(other, in->pcr_handle);
+
+ reverse_copy_sessions_in(&other, &in->sessions);
+
+ other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->data));
+
+ /* Now set the command size field, now that we know the size of the whole command */
+ cmd_size = (u8 *)other - cmd_buf;
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+
+ rsp_size = sizeof(*out);
+
+ if (g_tpm_family == TPM_IF_20_FIFO) {
+ if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+ if (g_tpm_family == TPM_IF_20_CRB) {
+ if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret));
+ if ( ret != TPM_RC_SUCCESS )
+ return ret;
+
+ other = (void *)rsp_buf + RSP_HEAD_SIZE;
+ reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag));
+ if (rsp_tag == TPM_ST_SESSIONS)
+ other += sizeof(u32);
+
+ reverse_copy_digest_values_out(&out->digests, &other);
+
+ reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions);
+
+ return ret;
+}
+
+static uint32_t _tpm20_pcr_reset(uint32_t locality,
+ tpm_pcr_reset_in *in,
+ tpm_pcr_reset_out *out)
+{
+ u32 ret;
+ u32 cmd_size, rsp_size;
+ u16 rsp_tag;
+ void *other;
+
+ reverse_copy_header(TPM_CC_PCR_Reset, &in->sessions);
+
+ other = (void *)cmd_buf + CMD_HEAD_SIZE;
+ reverse_copy(other, &in->pcr_handle, sizeof(u32));
+
+ other += sizeof(u32);
+ reverse_copy_sessions_in(&other, &in->sessions);
+
+ /* Now set the command size field, now that we know the size of the whole command */
+ cmd_size = (u8 *)other - cmd_buf;
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+
+ rsp_size = sizeof(*out);
+ if (g_tpm_family == TPM_IF_20_FIFO) {
+ if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+ if (g_tpm_family == TPM_IF_20_CRB) {
+ if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret));
+ if ( ret != TPM_RC_SUCCESS )
+ return ret;
+
+ other = (void *)rsp_buf + RSP_HEAD_SIZE;
+ reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag));
+ if (rsp_tag == TPM_ST_SESSIONS)
+ other += sizeof(u32);
+
+ reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions);
+
+ return ret;
+}
+
+static uint32_t _tpm20_sequence_start(uint32_t locality,
+ tpm_sequence_start_in *in,
+ tpm_sequence_start_out *out)
+{
+ u32 ret;
+ u32 cmd_size, rsp_size;
+ u16 rsp_tag;
+ void *other;
+
+ reverse_copy_header(TPM_CC_HashSequenceStart, 0);
+
+ other = (void *)cmd_buf + CMD_HEAD_SIZE;
+ other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->auth));
+
+ reverse_copy_in(other, in->hash_alg);
+
+ /* Now set the command size field, now that we know the size of the whole command */
+ cmd_size = (u8 *)other - cmd_buf;
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+
+ rsp_size = RSP_HEAD_SIZE + sizeof(*out);
+ if (g_tpm_family == TPM_IF_20_FIFO) {
+ if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+ if (g_tpm_family == TPM_IF_20_CRB) {
+ if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret));
+ if ( ret != TPM_RC_SUCCESS )
+ return ret;
+
+ other = (void *)rsp_buf + RSP_HEAD_SIZE;
+ reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag));
+ if (rsp_tag == TPM_ST_SESSIONS)
+ other += sizeof(u32);
+
+ reverse_copy_out(out->handle, other);
+
+ return ret;
+}
+
+static uint32_t _tpm20_sequence_update(uint32_t locality,
+ tpm_sequence_update_in *in,
+ tpm_sequence_update_out *out)
+{
+ u32 ret;
+ u32 cmd_size, rsp_size;
+ u16 rsp_tag;
+ void *other;
+
+ reverse_copy_header(TPM_CC_SequenceUpdate, &in->sessions);
+
+ other = (void *)cmd_buf + CMD_HEAD_SIZE;
+
+ reverse_copy_in(other, in->handle);
+
+ reverse_copy_sessions_in(&other, &in->sessions);
+
+ other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->buf));
+
+ /* Now set the command size field, now that we know the size of the whole command */
+ cmd_size = (u8 *)other - cmd_buf;
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+
+ rsp_size = sizeof(*out);
+ if (g_tpm_family == TPM_IF_20_FIFO) {
+ if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+ if (g_tpm_family == TPM_IF_20_CRB) {
+ if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret));
+ if ( ret != TPM_RC_SUCCESS )
+ return ret;
+
+ other = (void *)rsp_buf + RSP_HEAD_SIZE;
+ reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag));
+ if (rsp_tag == TPM_ST_SESSIONS)
+ other += sizeof(u32);
+
+ reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions);
+
+ return ret;
+}
+
+static uint32_t _tpm20_sequence_complete(uint32_t locality,
+ tpm_sequence_complete_in *in,
+ tpm_sequence_complete_out *out)
+{
+ u32 ret;
+ u32 cmd_size, rsp_size;
+ u16 rsp_tag;
+ void *other;
+
+ reverse_copy_header(TPM_CC_EventSequenceComplete, &in->sessions);
+
+ other = (void *)cmd_buf + CMD_HEAD_SIZE;
+
+ reverse_copy_in(other, in->pcr_handle);
+ reverse_copy_in(other, in->seq_handle);
+
+ reverse_copy_sessions_in(&other, &in->sessions);
+
+ other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->buf));
+
+ /* Now set the command size field, now that we know the size of the whole command */
+ cmd_size = (u8 *)other - cmd_buf;
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+
+ rsp_size = sizeof(*out);
+ if (g_tpm_family == TPM_IF_20_FIFO) {
+ if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+ if (g_tpm_family == TPM_IF_20_CRB) {
+ if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret));
+ if ( ret != TPM_RC_SUCCESS )
+ return ret;
+
+ other = (void *)rsp_buf + RSP_HEAD_SIZE;
+ reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag));
+ if (rsp_tag == TPM_ST_SESSIONS)
+ other += sizeof(u32);
+
+ reverse_copy_digest_values_out(&out->results, &other);
+
+ reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions);
+
+ return ret;
+}
+
+static uint32_t _tpm20_nv_read(uint32_t locality,
+ tpm_nv_read_in *in,
+ tpm_nv_read_out *out)
+{
+ u32 ret;
+ u32 cmd_size, rsp_size;
+ u16 rsp_tag;
+ void *other;
+
+ reverse_copy_header(TPM_CC_NV_Read, &in->sessions);
+
+ other = (void *)cmd_buf + CMD_HEAD_SIZE;
+ reverse_copy_in(other, in->handle);
+ reverse_copy_in(other, in->index);
+
+ reverse_copy_sessions_in(&other, &in->sessions);
+
+ reverse_copy_in(other, in->size);
+ reverse_copy_in(other, in->offset);
+
+ /* Now set the command size field, now that we know the size of the whole command */
+ cmd_size = (u8 *)other - cmd_buf;
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+
+ rsp_size = sizeof(*out);
+
+ if (g_tpm_family == TPM_IF_20_FIFO) {
+ if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+ if (g_tpm_family == TPM_IF_20_CRB) {
+ if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret));
+ if ( ret != TPM_RC_SUCCESS )
+ return ret;
+
+ other = (void *)rsp_buf + RSP_HEAD_SIZE;
+ reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag));
+ if (rsp_tag == TPM_ST_SESSIONS)
+ other += sizeof(u32);
+
+ other += reverse_copy_sized_buf_out((TPM2B *)&(out->data), (TPM2B *)other);
+
+ reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions);
+
+ return ret;
+}
+
+static uint32_t _tpm20_nv_write(uint32_t locality,
+ tpm_nv_write_in *in,
+ tpm_nv_write_out *out)
+{
+ u32 ret;
+ u32 cmd_size, rsp_size;
+ u16 rsp_tag;
+ void *other;
+
+ reverse_copy_header(TPM_CC_NV_Write, &in->sessions);
+
+ other = (void *)cmd_buf + CMD_HEAD_SIZE;
+ reverse_copy_in(other, in->handle);
+ reverse_copy_in(other, in->index);
+
+ reverse_copy_sessions_in(&other, &in->sessions);
+
+ other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->data));
+
+ reverse_copy_in(other, in->offset);
+
+ /* Now set the command size field, now that we know the size of the whole command */
+ cmd_size = (u8 *)other - cmd_buf;
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+
+ rsp_size = sizeof(*out);
+
+ if (g_tpm_family == TPM_IF_20_FIFO) {
+ if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+ if (g_tpm_family == TPM_IF_20_CRB) {
+ if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret));
+ if ( ret != TPM_RC_SUCCESS )
+ return ret;
+
+ other = (void *)rsp_buf + RSP_HEAD_SIZE;
+ reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag));
+ if (rsp_tag == TPM_ST_SESSIONS)
+ other += sizeof(u32);
+
+ reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions);
+
+ return ret;
+}
+
+static uint32_t _tpm20_nv_read_public(uint32_t locality,
+ tpm_nv_read_public_in *in,
+ tpm_nv_read_public_out *out)
+{
+ u32 ret;
+ u32 cmd_size, rsp_size;
+ u16 rsp_tag;
+ void *other;
+
+ reverse_copy_header(TPM_CC_NV_ReadPublic, 0);
+
+ other = (void *)cmd_buf + CMD_HEAD_SIZE;
+ reverse_copy_in(other, in->index);
+
+ /* Now set the command size field, now that we know the size of the whole command */
+ cmd_size = (u8 *)other - cmd_buf;
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+
+ rsp_size = sizeof(*out);
+
+ if (g_tpm_family == TPM_IF_20_FIFO) {
+ if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+ if (g_tpm_family == TPM_IF_20_CRB) {
+ if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret));
+ if ( ret != TPM_RC_SUCCESS )
+ return ret;
+
+ other = (void *)rsp_buf + RSP_HEAD_SIZE;
+ reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag));
+ if (rsp_tag == TPM_ST_SESSIONS)
+ other += sizeof(u32);
+
+ reverse_copy_out(out->nv_public.t.size, other);
+ reverse_copy_out(out->nv_public.t.nv_public.index, other);
+ reverse_copy_out(out->nv_public.t.nv_public.name_alg, other);
+ reverse_copy((void *)&(out->nv_public.t.nv_public.attr), other, sizeof(u32));
+ other += sizeof(u32);
+ other += reverse_copy_sized_buf_out((TPM2B *)&(out->nv_public.t.nv_public.auth_policy),
+ (TPM2B *)other);
+ reverse_copy_out(out->nv_public.t.nv_public.data_size, other);
+
+ other += reverse_copy_sized_buf_out((TPM2B *)&(out->nv_name), (TPM2B *)other);
+
+ return ret;
+}
+
+static uint32_t _tpm20_get_random(uint32_t locality,
+ tpm_get_random_in *in,
+ tpm_get_random_out *out)
+{
+ u32 ret;
+ u32 cmd_size, rsp_size;
+ u16 rsp_tag;
+ void *other;
+
+ reverse_copy_header(TPM_CC_GetRandom, 0);
+
+ other = (void *)cmd_buf + CMD_HEAD_SIZE;
+ reverse_copy_in(other, in->bytes_req);
+
+ /* Now set the command size field, now that we know the size of the whole command */
+ cmd_size = (u8 *)other - cmd_buf;
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+
+ rsp_size = sizeof(*out);
+
+ if (g_tpm_family == TPM_IF_20_FIFO) {
+ if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+ if (g_tpm_family == TPM_IF_20_CRB) {
+ if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret));
+ if ( ret != TPM_RC_SUCCESS )
+ return ret;
+
+ other = (void *)rsp_buf + RSP_HEAD_SIZE;
+ reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag));
+ if (rsp_tag == TPM_ST_SESSIONS)
+ other += sizeof(u32);
+
+ other += reverse_copy_sized_buf_out((TPM2B *)&(out->random_bytes), (TPM2B *)other);
+
+ return ret;
+}
+
+static uint32_t _tpm20_shutdown(uint32_t locality, u16 type)
+{
+ u32 ret;
+ u32 cmd_size, rsp_size;
+ void *other;
+
+ reverse_copy_header(TPM_CC_Shutdown, 0);
+
+ other = (void *)cmd_buf + CMD_HEAD_SIZE;
+ reverse_copy_in(other, type);
+
+ /* Now set the command size field, now that we know the size of the whole command */
+ cmd_size = (u8 *)other - cmd_buf;
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+
+ rsp_size = RSP_HEAD_SIZE;
+
+ if (g_tpm_family == TPM_IF_20_FIFO) {
+ if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+ if (g_tpm_family == TPM_IF_20_CRB) {
+ if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret));
+ return ret;
+}
+
+static __data u32 handle2048 = 0;
+static const char auth_str[] = "test";
+static uint32_t _tpm20_create_primary(uint32_t locality,
+ tpm_create_primary_in *in,
+ tpm_create_primary_out *out)
+{
+ u32 ret;
+ u32 cmd_size, rsp_size;
+ u16 rsp_tag;
+ u16 sensitive_size;
+ void *sensitive_size_ptr;
+ void *other;
+
+ reverse_copy_header(TPM_CC_CreatePrimary, &in->sessions);
+
+ other = (void *)cmd_buf + CMD_HEAD_SIZE;
+ reverse_copy_in(other, in->primary_handle);
+
+ reverse_copy_sessions_in(&other, &in->sessions);
+
+ /* Copy inSensitive */
+ sensitive_size_ptr = other;
+ other += sizeof(u16);
+ other += reverse_copy_sized_buf_in((TPM2B *)other,
+ (TPM2B *)&(in->sensitive.t.sensitive.user_auth));
+ other += reverse_copy_sized_buf_in((TPM2B *)other,
+ (TPM2B *)&(in->sensitive.t.sensitive.data));
+ sensitive_size = (u8 *)other - (u8 *)sensitive_size_ptr - sizeof(u16);
+ reverse_copy(sensitive_size_ptr, &sensitive_size, sizeof(u16));
+
+ /* Copy inPublic */
+ reverse_copy_public_in(&other, &in->public);
+
+ /* Copy outsideInfo */
+ other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->outside_info));
+
+ /* Copy creationPCR */
+ reverse_copy_pcr_selection_in(&other, &in->creation_pcr);
+
+ /* Now set the command size field, now that we know the size of the whole command */
+ cmd_size = (u8 *)other - cmd_buf;
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+
+ rsp_size = sizeof(*out);
+
+ if (g_tpm_family == TPM_IF_20_FIFO) {
+ if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+ if (g_tpm_family == TPM_IF_20_CRB) {
+ if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret));
+ if ( ret != TPM_RC_SUCCESS )
+ return ret;
+
+ other = (void *)rsp_buf + RSP_HEAD_SIZE;
+
+ /* Save objHandle */
+ reverse_copy_out(out->obj_handle, other);
+
+ reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag));
+ if (rsp_tag == TPM_ST_SESSIONS)
+ other += sizeof(u32);
+
+ /* Save outPublic */
+ reverse_copy_public_out(&out->public, &other);
+
+ /* Save creationData */
+ reverse_copy_creation_data_out(&(out->creation_data), &other);
+
+ /* Save creationHash */
+ other += reverse_copy_sized_buf_out((TPM2B *)&(out->creation_hash),
+ (TPM2B *)other);
+
+ /* Save creationTicket */
+ reverse_copy_ticket_out(&(out->creation_ticket), &other);
+
+ other += reverse_copy_sized_buf_out((TPM2B *)&(out->name), (TPM2B *)other);
+
+ reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions);
+
+ return ret;
+}
+
+
+static uint32_t _tpm20_create(uint32_t locality,
+ tpm_create_in *in,
+ tpm_create_out *out)
+{
+ u32 ret;
+ u32 cmd_size, rsp_size;
+ u16 rsp_tag;
+ u16 sensitive_size;
+ void *sensitive_size_ptr;
+ void *other;
+
+ reverse_copy_header(TPM_CC_Create, &in->sessions);
+
+ other = (void *)cmd_buf + CMD_HEAD_SIZE;
+ reverse_copy_in(other, in->parent_handle);
+
+ reverse_copy_sessions_in(&other, &in->sessions);
+
+ /* Copy inSensitive */
+ sensitive_size_ptr = other;
+ other += sizeof(u16);
+ other += reverse_copy_sized_buf_in((TPM2B *)other,
+ (TPM2B *)&(in->sensitive.t.sensitive.user_auth));
+ other += reverse_copy_sized_buf_in((TPM2B *)other,
+ (TPM2B *)&(in->sensitive.t.sensitive.data));
+ sensitive_size = (u8 *)other - (u8 *)sensitive_size_ptr - sizeof(u16);
+ reverse_copy(sensitive_size_ptr, &sensitive_size, sizeof(u16));
+
+ /* Copy inPublic */
+ reverse_copy_public_in(&other, &in->public);
+
+ /* Copy outsideInfo */
+ other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->outside_info));
+
+ /* Copy creationPCR */
+ reverse_copy_pcr_selection_in(&other, &in->creation_pcr);
+
+ /* Now set the command size field, now that we know the size of the whole command */
+ cmd_size = (u8 *)other - cmd_buf;
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+
+ rsp_size = sizeof(*out);
+
+ if (g_tpm_family == TPM_IF_20_FIFO) {
+ if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+ if (g_tpm_family == TPM_IF_20_CRB) {
+ if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret));
+ if ( ret != TPM_RC_SUCCESS )
+ return ret;
+
+ other = (void *)rsp_buf + RSP_HEAD_SIZE;
+ reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag));
+ if (rsp_tag == TPM_ST_SESSIONS)
+ other += sizeof(u32);
+
+ /* Save outPrivate */
+ other += reverse_copy_sized_buf_out((TPM2B *)&(out->private), (TPM2B *)other);
+
+ /* Save outPublic */
+ reverse_copy_public_out(&out->public, &other);
+
+ /* Save creationData */
+ reverse_copy_creation_data_out(&(out->creation_data), &other);
+
+ /* Save creationHash */
+ other += reverse_copy_sized_buf_out((TPM2B *)&(out->creation_hash),
+ (TPM2B *)other);
+
+ /* Save creationTicket */
+ reverse_copy_ticket_out(&(out->creation_ticket), &other);
+
+ reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions);
+
+ return ret;
+}
+
+static uint32_t _tpm20_load(uint32_t locality,
+ tpm_load_in *in,
+ tpm_load_out *out)
+{
+ u32 ret;
+ u32 cmd_size, rsp_size;
+ u16 rsp_tag;
+ void *other;
+
+ reverse_copy_header(TPM_CC_Load, &in->sessions);
+
+ other = (void *)cmd_buf + CMD_HEAD_SIZE;
+ reverse_copy_in(other, in->parent_handle);
+
+ reverse_copy_sessions_in(&other, &in->sessions);
+
+ other += reverse_copy_sized_buf_in((TPM2B *)other, (TPM2B *)&(in->private));
+
+ reverse_copy_public_in(&other, &in->public);
+
+ /* Now set the command size field, now that we know the size of the whole command */
+ cmd_size = (u8 *)other - cmd_buf;
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+
+ rsp_size = sizeof(*out);
+
+ if (g_tpm_family == TPM_IF_20_FIFO) {
+ if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+ if (g_tpm_family == TPM_IF_20_CRB) {
+ if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret));
+ if ( ret != TPM_RC_SUCCESS )
+ return ret;
+
+ other = (void *)rsp_buf + RSP_HEAD_SIZE;
+
+ reverse_copy_out(out->obj_handle, other);
+
+ reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag));
+ if (rsp_tag == TPM_ST_SESSIONS)
+ other += sizeof(u32);
+
+ other += reverse_copy_sized_buf_out((TPM2B *)&(out->name), (TPM2B *)other);
+
+ reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions);
+
+ return ret;
+}
+
+static uint32_t _tpm20_unseal(uint32_t locality,
+ tpm_unseal_in *in,
+ tpm_unseal_out *out)
+{
+ u32 ret;
+ u32 cmd_size, rsp_size;
+ u16 rsp_tag;
+ void *other;
+
+ reverse_copy_header(TPM_CC_Unseal, &in->sessions);
+
+ other = (void *)cmd_buf + CMD_HEAD_SIZE;
+ reverse_copy_in(other, in->item_handle);
+
+ reverse_copy_sessions_in(&other, &in->sessions);
+
+ /* Now set the command size field, now that we know the size of the whole command */
+ cmd_size = (u8 *)other - cmd_buf;
+ reverse_copy(cmd_buf + CMD_SIZE_OFFSET, &cmd_size, sizeof(cmd_size));
+
+ rsp_size = sizeof(*out);
+
+ if (g_tpm_family == TPM_IF_20_FIFO) {
+ if (!tpm_submit_cmd(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+ if (g_tpm_family == TPM_IF_20_CRB) {
+ if (!tpm_submit_cmd_crb(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size))
+ return TPM_RC_FAILURE;
+ }
+
+ reverse_copy(&ret, rsp_buf + RSP_RST_OFFSET, sizeof(ret));
+ if ( ret != TPM_RC_SUCCESS )
+ return ret;
+
+ other = (void *)rsp_buf + RSP_HEAD_SIZE;
+ reverse_copy(&rsp_tag, rsp_buf, sizeof(rsp_tag));
+ if (rsp_tag == TPM_ST_SESSIONS)
+ other += sizeof(u32);
+
+ other += reverse_copy_sized_buf_out((TPM2B *)&(out->data), (TPM2B *)other);
+
+ reverse_copy_sessions_out(&out->sessions, other, rsp_tag, &in->sessions);
+
+ return ret;
+}
+
+TPM_CMD_SESSION_DATA_IN pw_session;
+static void create_pw_session(TPM_CMD_SESSION_DATA_IN *ses)
+{
+ ses->session_handle = TPM_RS_PW;
+ ses->nonce.t.size = 0;
+ *((u8 *)((void *)&ses->session_attr)) = 0;
+ ses->hmac.t.size = 0;
+}
+
+#define SET_PCR_SELECT_BIT( pcr_selection, pcr ) \
+ (pcr_selection).pcr_select[( (pcr)/8 )] |= ( 1 << ( (pcr) % 8) );
+static bool tpm20_pcr_read(struct tpm_if *ti, uint32_t locality,
+ uint32_t pcr, tpm_pcr_value_t *out)
+{
+ tpm_pcr_read_in read_in;
+ tpm_pcr_read_out read_out;
+ u32 ret;
+
+ if ( ti == NULL || out == NULL )
+ return false;
+
+ read_in.pcr_selection.count = 1;
+ read_in.pcr_selection.selections[0].hash = ti->cur_alg;
+ read_in.pcr_selection.selections[0].size_of_select = 3;
+ read_in.pcr_selection.selections[0].pcr_select[0] = 0;
+ read_in.pcr_selection.selections[0].pcr_select[1] = 0;
+ read_in.pcr_selection.selections[0].pcr_select[2] = 0;
+ SET_PCR_SELECT_BIT( read_in.pcr_selection.selections[0], pcr );
+
+ ret = _tpm20_pcr_read(locality, &read_in, &read_out);
+ if (ret != TPM_RC_SUCCESS) {
+ printk(TBOOT_WARN"TPM: Pcr %d Read return value = %08X\n", pcr, ret);
+ ti->error = ret;
+ return false;
+ }
+
+ copy_hash(out,
+ (tb_hash_t *)&(read_out.pcr_values.digests[0].t.buffer[0]),
+ ti->cur_alg);
+
+ return true;
+}
+
+static bool tpm20_pcr_extend(struct tpm_if *ti, uint32_t locality,
+ uint32_t pcr, const hash_list_t *in)
+{
+ tpm_pcr_extend_in extend_in;
+ tpm_pcr_extend_out extend_out;
+ u32 ret, i;
+
+ if ( ti == NULL || in == NULL )
+ return false;
+
+ extend_in.pcr_handle = pcr;
+ extend_in.sessions.num_sessions = 1;
+ extend_in.sessions.sessions[0] = pw_session;
+
+ extend_in.digests.count = in->count;
+ for (i=0; i<in->count; i++) {
+ extend_in.digests.digests[i].hash_alg = in->entries[i].alg;
+ copy_hash((tb_hash_t *)&extend_in.digests.digests[i].digest,
+ &in->entries[i].hash, in->entries[i].alg);
+ }
+
+ ret = _tpm20_pcr_extend(locality, &extend_in, &extend_out);
+ if ( ret != TPM_RC_SUCCESS ) {
+ printk(TBOOT_WARN"TPM: Pcr %d extend, return value = %08X\n", pcr, ret);
+ ti->error = ret;
+ return false;
+ }
+
+ return true;
+}
+
+static bool tpm20_pcr_reset(struct tpm_if *ti, uint32_t locality, uint32_t pcr)
+{
+ tpm_pcr_reset_in reset_in;
+ tpm_pcr_reset_out reset_out;
+ u32 ret;
+
+ reset_in.pcr_handle = pcr;
+ reset_in.sessions.num_sessions = 1;
+ reset_in.sessions.sessions[0] = pw_session;
+
+ ret = _tpm20_pcr_reset(locality, &reset_in, &reset_out);
+ if (ret != TPM_RC_SUCCESS) {
+ printk(TBOOT_WARN"TPM: Pcr %d Reset return value = %08X\n", pcr, ret);
+ ti->error = ret;
+ return false;
+ }
+
+ return true;
+}
+
+static bool tpm20_hash(struct tpm_if *ti, u32 locality, const u8 *data,
+ u32 data_size, hash_list_t *hl)
+{
+ tpm_sequence_start_in start_in;
+ tpm_sequence_start_out start_out;
+ tpm_sequence_update_in update_in;
+ tpm_sequence_update_out update_out;
+ tpm_sequence_complete_in complete_in;
+ tpm_sequence_complete_out complete_out;
+ TPM2B_MAX_BUFFER buffer;
+ u32 ret, i, j, chunk_size;
+
+ if ( ti == NULL || data == NULL || data_size == 0 )
+ return false;
+
+ start_in.auth.t.size = 2;
+ start_in.auth.t.buffer[0] = 0;
+ start_in.auth.t.buffer[1] = 0xff;
+ start_in.hash_alg = TPM_ALG_NULL;
+
+ ret = _tpm20_sequence_start(locality, &start_in, &start_out);
+ if (ret != TPM_RC_SUCCESS) {
+ printk(TBOOT_WARN"TPM: HashSequenceStart return value = %08X\n", ret);
+ ti->error = ret;
+ return false;
+ }
+
+ update_in.sessions.num_sessions = 1;
+ update_in.sessions.sessions[0] = pw_session;
+ update_in.sessions.sessions[0].hmac = start_in.auth;
+ update_in.handle = start_out.handle;
+
+ complete_in.pcr_handle = TPM_RH_NULL;
+ complete_in.seq_handle = start_out.handle;
+ complete_in.sessions.num_sessions = 2;
+ create_pw_session(&complete_in.sessions.sessions[0]);
+ complete_in.sessions.sessions[1] = pw_session;
+ complete_in.sessions.sessions[1].hmac = start_in.auth;
+
+ for( i=0; i<data_size; i+=chunk_size ) {
+ if( (data_size-i) > MAX_DIGEST_BUFFER ) {
+ chunk_size = 1024;
+ } else {
+ chunk_size = data_size - i;
+ }
+
+ buffer.t.size = chunk_size;
+ memcpy( &(buffer.t.buffer[0]), &(data[i] ), chunk_size );
+
+ if( chunk_size == 1024 ) {
+ update_in.buf = buffer;
+ ret = _tpm20_sequence_update(locality, &update_in, &update_out);
+ if (ret != TPM_RC_SUCCESS) {
+ printk(TBOOT_WARN"TPM: SequenceUpdate return value = %08X\n", ret);
+ ti->error = ret;
+ return false;
+ }
+ } else {
+ complete_in.buf = buffer;
+ ret = _tpm20_sequence_complete(locality, &complete_in, &complete_out);
+ if (ret != TPM_RC_SUCCESS) {
+ printk(TBOOT_WARN"TPM: EventSequenceComplete return value = %08X\n", ret);
+ ti->error = ret;
+ return false;
+ }
+ }
+ }
+
+ hl->count = complete_out.results.count;
+ for ( j=0; j<hl->count; j++ ) {
+ hl->entries[j].alg = complete_out.results.digests[j].hash_alg;
+ memcpy(&hl->entries[j].hash, &complete_out.results.digests[j].digest,
+ sizeof(hl->entries[j].hash));
+ }
+
+ return true;
+}
+
+static bool tpm20_nv_read(struct tpm_if *ti, uint32_t locality,
+ uint32_t index, uint32_t offset,
+ uint8_t *data, uint32_t *data_size)
+{
+ tpm_nv_read_in read_in;
+ tpm_nv_read_out read_out;
+ u32 ret;
+
+ if ( ti == NULL || data_size == NULL || *data_size == 0 )
+ return false;
+
+ if ( *data_size > MAX_NV_INDEX_SIZE )
+ *data_size = MAX_NV_INDEX_SIZE;
+
+ read_in.handle = index;
+ read_in.index = index;
+ read_in.sessions.num_sessions = 1;
+ read_in.sessions.sessions[0] = pw_session;
+ read_in.offset = offset;
+ read_in.size = *data_size;
+
+ ret = _tpm20_nv_read(locality, &read_in, &read_out);
+ if ( ret != TPM_RC_SUCCESS ) {
+ printk(TBOOT_WARN"TPM: read NV index %08x from offset %08x, return value = %08X\n",
+ index, offset, ret);
+ ti->error = ret;
+ return false;
+ }
+
+ *data_size = read_out.data.t.size;
+ if( *data_size > 0 )
+ memcpy(data, &read_out.data.t.buffer[0], *data_size);
+
+ return true;
+}
+
+static bool tpm20_nv_write(struct tpm_if *ti, uint32_t locality,
+ uint32_t index, uint32_t offset,
+ const uint8_t *data, uint32_t data_size)
+{
+ tpm_nv_write_in write_in;
+ tpm_nv_write_out write_out;
+ u32 ret;
+
+ if ( ti == NULL || data == NULL || data_size == 0
+ || data_size > MAX_NV_INDEX_SIZE )
+ return false;
+
+ write_in.handle = index;
+ write_in.index = index;
+ write_in.sessions.num_sessions = 1;
+ write_in.sessions.sessions[0] = pw_session;
+ write_in.offset = offset;
+ write_in.data.t.size = data_size;
+ memcpy(&write_in.data.t.buffer[0], data, data_size);
+
+ ret = _tpm20_nv_write(locality, &write_in, &write_out);
+ if ( ret != TPM_RC_SUCCESS ) {
+ printk(TBOOT_WARN"TPM: write NV %08x, offset %08x, %08x bytes, return value = %08X\n",
+ index, offset, data_size, ret);
+ ti->error = ret;
+ return false;
+ }
+
+ return true;
+}
+
+static bool tpm20_get_nvindex_size(struct tpm_if *ti, uint32_t locality,
+ uint32_t index, uint32_t *size)
+{
+ tpm_nv_read_public_in public_in;
+ tpm_nv_read_public_out public_out;
+ u32 ret;
+
+ if ( ti == NULL || size == NULL )
+ return false;
+
+ public_in.index = index;
+
+ ret = _tpm20_nv_read_public(locality, &public_in, &public_out);
+ if ( ret != TPM_RC_SUCCESS ) {
+ printk(TBOOT_WARN"TPM: fail to get public data of 0x%08X in TPM NV\n", index);
+ ti->error = ret;
+ return false;
+ }
+
+ if (index != public_out.nv_public.t.nv_public.index) {
+ printk(TBOOT_WARN"TPM: Index 0x%08X is not the one expected 0x%08X\n",
+ index, index);
+ ti->error = TPM_RC_FAILURE;
+ return false;
+ }
+
+ *size = public_out.nv_public.t.nv_public.data_size;
+
+ return true;
+}
+
+static bool tpm20_get_nvindex_permission(struct tpm_if *ti, uint32_t locality,
+ uint32_t index, uint32_t *attribute)
+{
+ if ( ti == NULL || locality >= TPM_NR_LOCALITIES
+ || index == 0 || attribute == NULL )
+ return false;
+
+ return true;
+}
+
+static bool tpm20_seal(struct tpm_if *ti, uint32_t locality,
+ uint32_t in_data_size, const uint8_t *in_data,
+ uint32_t *sealed_data_size, uint8_t *sealed_data)
+{
+ tpm_create_in create_in;
+ tpm_create_out create_out;
+ u32 ret;
+
+ create_in.parent_handle = handle2048;
+ create_in.sessions.num_sessions = 1;
+ create_in.sessions.sessions[0] = pw_session;
+ create_in.sessions.sessions[0].hmac.t.size = 2;
+ create_in.sessions.sessions[0].hmac.t.buffer[0] = 0x00;
+ create_in.sessions.sessions[0].hmac.t.buffer[1] = 0xff;
+
+ create_in.public.t.public_area.type = TPM_ALG_KEYEDHASH;
+ create_in.public.t.public_area.name_alg = ti->cur_alg;
+ create_in.public.t.public_area.auth_policy.t.size = 0;
+ *(u32 *)&create_in.public.t.public_area.object_attr = 0;
+ create_in.public.t.public_area.object_attr.userWithAuth = 1;
+ create_in.public.t.public_area.object_attr.noDA = 1;
+ create_in.public.t.public_area.param.keyed_hash.scheme.scheme = TPM_ALG_NULL;
+ create_in.public.t.public_area.unique.keyed_hash.t.size = 0;
+
+ create_in.sensitive.t.sensitive.user_auth.t.size = sizeof(auth_str) - 1;
+ memcpy(&(create_in.sensitive.t.sensitive.user_auth.t.buffer[0]),
+ auth_str, sizeof(auth_str)-1);
+ create_in.sensitive.t.sensitive.data.t.size = in_data_size;
+ memcpy(&(create_in.sensitive.t.sensitive.data.t.buffer[0]),
+ in_data, in_data_size);
+
+ create_in.outside_info.t.size = 0;
+ create_in.creation_pcr.count = 0;
+
+ ret = _tpm20_create(locality, &create_in, &create_out);
+ if ( ret != TPM_RC_SUCCESS ) {
+ printk(TBOOT_WARN"TPM: Create return value = %08X\n", ret);
+ ti->error = ret;
+ return false;
+ }
+ *sealed_data_size = sizeof(create_out);
+ memcpy(sealed_data, &create_out, *sealed_data_size);
+
+ return true;
+}
+
+static bool tpm20_unseal(struct tpm_if *ti, uint32_t locality,
+ uint32_t sealed_data_size, const uint8_t *sealed_data,
+ uint32_t *secret_size, uint8_t *secret)
+{
+ tpm_load_in load_in;
+ tpm_load_out load_out;
+ tpm_unseal_in unseal_in;
+ tpm_unseal_out unseal_out;
+ u32 ret;
+
+ if ( ti == NULL || locality >= TPM_NR_LOCALITIES
+ || sealed_data_size == 0 || sealed_data == NULL )
+ return false;
+
+ /* For TPM 2.0, the object will need to be loaded before it may be used.*/
+ load_in.parent_handle = handle2048;
+ load_in.sessions.num_sessions = 1;
+ load_in.sessions.sessions[0] = pw_session;
+ load_in.sessions.sessions[0].hmac.t.size = 2;
+ load_in.sessions.sessions[0].hmac.t.buffer[0] = 0x00;
+ load_in.sessions.sessions[0].hmac.t.buffer[1] = 0xff;
+ load_in.private = ((tpm_create_out *)sealed_data)->private;
+ load_in.public = ((tpm_create_out *)sealed_data)->public;
+
+ ret = _tpm20_load(locality, &load_in, &load_out);
+ if ( ret != TPM_RC_SUCCESS ) {
+ printk(TBOOT_WARN"TPM: Load return value = %08X\n", ret);
+ ti->error = ret;
+ return false;
+ }
+
+ unseal_in.sessions.num_sessions = 1;
+ unseal_in.sessions.sessions[0] = pw_session;
+ unseal_in.sessions.sessions[0].hmac.t.size = sizeof(auth_str) - 1;
+ memcpy(&(unseal_in.sessions.sessions[0].hmac.t.buffer[0]),
+ auth_str, sizeof(auth_str)-1);
+ unseal_in.item_handle = load_out.obj_handle;
+
+ ret = _tpm20_unseal(locality, &unseal_in, &unseal_out);
+ if ( ret != TPM_RC_SUCCESS ) {
+ printk(TBOOT_WARN"TPM: Unseal return value = %08X\n", ret);
+ ti->error = ret;
+ return false;
+ }
+
+ *secret_size = unseal_out.data.t.size;
+ memcpy(secret, &(unseal_out.data.t.buffer[0]), *secret_size);
+
+ return true;
+}
+
+static bool tpm20_verify_creation(struct tpm_if *ti, uint32_t sealed_data_size, uint8_t *sealed_data)
+{
+ if ( ti == NULL || sealed_data_size == 0 || sealed_data == NULL )
+ return false;
+
+ return true;
+}
+
+static bool tpm20_get_random(struct tpm_if *ti, uint32_t locality,
+ uint8_t *random_data, uint32_t *data_size)
+{
+ tpm_get_random_in random_in;
+ tpm_get_random_out random_out;
+ u32 ret, out_size, requested_size;
+ static bool first_attempt;
+
+ if ( random_data == NULL || data_size == NULL || *data_size == 0 )
+ return false;
+
+ first_attempt = true;
+ requested_size = *data_size;
+
+ random_in.bytes_req = *data_size;
+
+ ret = _tpm20_get_random(locality, &random_in, &random_out);
+ if ( ret != TPM_RC_SUCCESS ) {
+ printk(TBOOT_WARN"TPM: get random 0x%x bytes, return value = %08X\n", *data_size, ret);
+ ti->error = ret;
+ return false;
+ }
+
+ out_size = random_out.random_bytes.t.size;
+ if (out_size > 0)
+ memcpy(random_data, &(random_out.random_bytes.t.buffer[0]), out_size);
+ *data_size = out_size;
+
+ /* if TPM doesn't return all requested random bytes, try one more time */
+ if ( out_size < requested_size ) {
+ printk(TBOOT_WARN"requested 0x%x random bytes but only got 0x%x\n", requested_size, out_size);
+ /* we're only going to try twice */
+ if ( first_attempt ) {
+ first_attempt = false;
+ uint32_t second_size = requested_size - out_size;
+ printk(TBOOT_WARN"trying one more time to get remaining 0x%x bytes\n", second_size);
+ random_in.bytes_req = second_size;
+
+ ret = _tpm20_get_random(locality, &random_in, &random_out);
+ if ( ret != TPM_RC_SUCCESS ) {
+ printk(TBOOT_WARN"TPM: get random 0x%x bytes, return value = %08X\n",
+ *data_size, ret);
+ ti->error = ret;
+ return false;
+ }
+
+ out_size = random_out.random_bytes.t.size;
+ if (out_size > 0)
+ memcpy(random_data+*data_size,
+ &(random_out.random_bytes.t.buffer[0]), out_size);
+ *data_size += out_size;
+ }
+ }
+
+ return true;
+}
+
+static uint32_t tpm20_save_state(struct tpm_if *ti, uint32_t locality)
+{
+ u32 ret;
+
+ if ( ti == NULL )
+ return false;
+
+ ret = _tpm20_shutdown(locality, TPM_SU_STATE);
+ if ( ret != TPM_RC_SUCCESS ) {
+ printk(TBOOT_WARN"TPM: Shutdown, return value = %08X\n", ret);
+ ti->error = ret;
+ }
+
+ return ret;
+}
+
+#define TPM_NR_PCRS 24
+#define TPM_PCR_RESETABLE_MIN 16
+static bool tpm20_cap_pcrs(struct tpm_if *ti, u32 locality, int pcr)
+{
+ bool was_capped[TPM_NR_PCRS] = {false};
+ hash_list_t cap_val; /* use whatever val is on stack */
+
+ if ( ti == NULL || locality >= TPM_NR_LOCALITIES || pcr == 0 )
+ return false;
+
+ cap_val.count = ti->banks;
+ for (unsigned int i=0; i<ti->banks; i++)
+ cap_val.entries[i].alg = ti->algs_banks[i];
+
+ if (pcr >= 0) {
+ tpm20_pcr_extend(ti, locality, pcr, &cap_val);
+ return true;
+ }
+
+ /* ensure PCRs 17 + 18 are always capped */
+ tpm20_pcr_extend(ti, locality, 17, &cap_val);
+ tpm20_pcr_extend(ti, locality, 18, &cap_val);
+ was_capped[17] = was_capped[18] = true;
+
+ /* also cap every dynamic PCR we extended (only once) */
+ /* don't cap static PCRs since then they would be wrong after S3 resume */
+ /* TODO
+ memset(&was_capped, true, TPM_PCR_RESETABLE_MIN*sizeof(bool));
+ for ( int i = 0; i < g_pre_k_s3_state.num_vl_entries; i++ ) {
+ if ( !was_capped[g_pre_k_s3_state.vl_entries[i].pcr] ) {
+ tpm20_pcr_extend(ti, locality, g_pre_k_s3_state.vl_entries[i].pcr, &cap_val);
+ was_capped[g_pre_k_s3_state.vl_entries[i].pcr] = true;
+ }
+ }*/
+
+ printk(TBOOT_INFO"cap'ed dynamic PCRs\n");
+ return true;
+}
+
+static bool alg_is_supported(u16 alg)
+{
+ for (int i=0; i<2; i++) {
+ if (alg == tboot_alg_list[i])
+ return true;
+ }
+
+ return false;
+}
+
+static bool tpm20_init(struct tpm_if *ti)
+{
+ u32 ret;
+ unsigned int i;
+ tpm_info_list_t *info_list = get_tpm_info_list(g_sinit);
+
+ if ( ti == NULL )
+ return false;
+/* TODO
+ if (!txt_is_launched())
+ ti->cur_loc = 0;
+ else
+ ti->cur_loc = 2;
+*/
+
+ /* init version */
+ ti->major = TPM20_VER_MAJOR;
+ ti->minor = TPM20_VER_MINOR;
+
+ /* init timeouts value */
+ ti->timeout.timeout_a = TIMEOUT_A;
+ ti->timeout.timeout_b = TIMEOUT_B;
+ ti->timeout.timeout_c = TIMEOUT_C;
+ ti->timeout.timeout_d = TIMEOUT_D;
+
+ /* get pcr extend policy from cmdline */
+ /* TODO get_tboot_extpol(); */
+ if (info_list->capabilities.tpm_nv_index_set == 0){
+ /* init NV index */
+ ti->tb_policy_index = 0x1200001;
+ ti->lcp_own_index = 0x1400001;
+ ti->tb_err_index = 0x1200002;
+ ti->sgx_svn_index = 0x01800004;
+ }
+ else {
+ ti->tb_policy_index = 0x01c10131;
+ ti->lcp_own_index = 0x01c10106;
+ ti->tb_err_index = 0x01c10132;
+ ti->sgx_svn_index = 0x01c10104;
+ }
+ /* create one common password sesson*/
+ create_pw_session(&pw_session);
+
+ /* init supported alg list for banks */
+ tpm_pcr_event_in event_in;
+ tpm_pcr_event_out event_out;
+ event_in.pcr_handle = 16;
+ event_in.sessions.num_sessions = 1;
+ event_in.sessions.sessions[0] = pw_session;
+ event_in.data.t.size = 4;
+ event_in.data.t.buffer[0] = 0;
+ event_in.data.t.buffer[1] = 0xff;
+ event_in.data.t.buffer[2] = 0x55;
+ event_in.data.t.buffer[3] = 0xaa;
+ ret = _tpm20_pcr_event(ti->cur_loc, &event_in, &event_out);
+ if (ret != TPM_RC_SUCCESS) {
+ printk(TBOOT_WARN"TPM: PcrEvent not successful, return value = %08X\n", ret);
+ ti->error = ret;
+ return false;
+ }
+ ti->banks = event_out.digests.count;
+ printk(TBOOT_INFO"TPM: supported bank count = %d\n", ti->banks);
+ for (i=0; i<ti->banks; i++) {
+ ti->algs_banks[i] = event_out.digests.digests[i].hash_alg;;
+ printk(TBOOT_INFO"TPM: bank alg = %08x\n", ti->algs_banks[i]);
+ }
+
+ /* init supported alg list */
+ ti->alg_count = 0;
+ for (i=0; i<ti->banks; i++) {
+ if (alg_is_supported(ti->algs_banks[i])) {
+ ti->algs[ti->alg_count] = ti->algs_banks[i];
+ ti->alg_count++;
+ }
+ }
+ printk(TBOOT_INFO"TPM: supported alg count = %08X\n", ti->alg_count);
+ for (unsigned int i=0; i<ti->alg_count; i++)
+ printk(TBOOT_INFO"\t\t %08X\n", ti->algs[i]);
+
+ if (handle2048 != 0)
+ goto out;
+
+ /* create primary object as parent obj for seal */
+ tpm_create_primary_in primary_in;
+ tpm_create_primary_out primary_out;
+ primary_in.primary_handle = TPM_RH_NULL;
+ primary_in.sessions.num_sessions = 1;
+ primary_in.sessions.sessions[0].session_handle = TPM_RS_PW;
+ primary_in.sessions.sessions[0].nonce.t.size = 0;
+ primary_in.sessions.sessions[0].hmac.t.size = 0;
+ *((u8 *)((void *)&primary_in.sessions.sessions[0].session_attr)) = 0;
+
+ primary_in.sensitive.t.sensitive.user_auth.t.size = 2;
+ primary_in.sensitive.t.sensitive.user_auth.t.buffer[0] = 0x00;
+ primary_in.sensitive.t.sensitive.user_auth.t.buffer[1] = 0xff;
+ primary_in.sensitive.t.sensitive.data.t.size = 0;
+
+ primary_in.public.t.public_area.type = TPM_ALG_RSA;
+ primary_in.public.t.public_area.name_alg = ti->cur_alg;
+ *(u32 *)&primary_in.public.t.public_area.object_attr = 0;
+ primary_in.public.t.public_area.object_attr.restricted = 1;
+ primary_in.public.t.public_area.object_attr.userWithAuth = 1;
+ primary_in.public.t.public_area.object_attr.decrypt = 1;
+ primary_in.public.t.public_area.object_attr.fixedTPM = 1;
+ primary_in.public.t.public_area.object_attr.fixedParent = 1;
+ primary_in.public.t.public_area.object_attr.noDA = 1;
+ primary_in.public.t.public_area.object_attr.sensitiveDataOrigin = 1;
+ primary_in.public.t.public_area.auth_policy.t.size = 0;
+ primary_in.public.t.public_area.param.rsa.symmetric.alg = TPM_ALG_AES;
+ primary_in.public.t.public_area.param.rsa.symmetric.key_bits.aes= 128;
+ primary_in.public.t.public_area.param.rsa.symmetric.mode.aes = TPM_ALG_CFB;
+ primary_in.public.t.public_area.param.rsa.scheme.scheme = TPM_ALG_NULL;
+ primary_in.public.t.public_area.param.rsa.key_bits = 2048;
+ primary_in.public.t.public_area.param.rsa.exponent = 0;
+ primary_in.public.t.public_area.unique.keyed_hash.t.size = 0;
+ primary_in.outside_info.t.size = 0;
+ primary_in.creation_pcr.count = 0;
+
+ printk(TBOOT_DETA"TPM:CreatePrimary creating hierarchy handle = %08X\n", primary_in.primary_handle);
+ ret = _tpm20_create_primary(ti->cur_loc, &primary_in, &primary_out);
+ if (ret != TPM_RC_SUCCESS) {
+ printk(TBOOT_WARN"TPM: CreatePrimary return value = %08X\n", ret);
+ ti->error = ret;
+ return false;
+ }
+ handle2048 = primary_out.obj_handle;
+
+ printk(TBOOT_DETA"TPM:CreatePrimary created object handle = %08X\n", handle2048);
+out:
+ tpm_print(ti);
+ return true;
+}
+
+struct tpm_if tpm_20_if = {
+ .init = tpm20_init,
+ .pcr_read = tpm20_pcr_read,
+ .pcr_extend = tpm20_pcr_extend,
+ .hash = tpm20_hash,
+ .pcr_reset = tpm20_pcr_reset,
+ .nv_read = tpm20_nv_read,
+ .nv_write = tpm20_nv_write,
+ .get_nvindex_size = tpm20_get_nvindex_size,
+ .get_nvindex_permission = tpm20_get_nvindex_permission,
+ .seal = tpm20_seal,
+ .unseal = tpm20_unseal,
+ .verify_creation = tpm20_verify_creation,
+ .get_random = tpm20_get_random,
+ .save_state = tpm20_save_state,
+ .cap_pcrs = tpm20_cap_pcrs,
+};
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/txt.c b/tboot/txt.c
new file mode 100644
index 0000000..3f7dcf1
--- /dev/null
+++ b/tboot/txt.c
@@ -0,0 +1,755 @@
+/*
+ * txt.c: Intel(r) TXT support functions, including initiating measured
+ * launch, post-launch, AP wakeup, etc.
+ *
+ * Copyright (c) 2003-2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <stdbool.h>
+#include <types.h>
+#include <tb_error.h>
+#include <msr.h>
+#include <compiler.h>
+#include <string.h>
+#include <misc.h>
+#include <page.h>
+#include <processor.h>
+#include <printk.h>
+#include <atomic.h>
+#include <mutex.h>
+#include <tpm.h>
+#include <uuid.h>
+#include <eficore.h>
+#include <eficonfig.h>
+#include <tboot.h>
+#include <mle.h>
+#include <hash.h>
+#include <cmdline.h>
+#include <acpi.h>
+#include <txt/txt.h>
+#include <txt/config_regs.h>
+#include <txt/mtrrs.h>
+#include <txt/heap.h>
+#include <txt/acmod.h>
+#include <txt/smx.h>
+#include <txt/verify.h>
+#include <txt/vmcs.h>
+#include <io.h>
+
+/* counter timeout for waiting for all APs to enter wait-for-sipi */
+#define AP_WFS_TIMEOUT 0x01000000
+
+/* MLE/kernel shared data page (in boot.S) */
+void apply_policy(tb_error_t error);
+void print_event(const tpm12_pcr_event_t *evt);
+void print_event_2(void *evt, uint16_t alg);
+
+__data struct acpi_rsdp g_rsdp;
+
+/*
+ * this is the structure whose addr we'll put in TXT heap and
+ * it needs to be within the MLE pages, so force it to the .text section.
+ * It is filled in at runtime with set values that don't change and
+ * are based of the relocated fixed physical base address of the TBOOT
+ * EFI RT memory region.
+ */
+__text mle_hdr_t g_mle_hdr = {
+ uuid : MLE_HDR_UUID,
+ length : sizeof(mle_hdr_t),
+ version : MLE_HDR_VER,
+ entry_point : 0, /* Linear virt. offset to the EP, used by ACM */
+ first_valid_page : 0,
+ mle_start_off : 0, /* Offset from TBOOT base, used by SW */
+ mle_end_off : 0, /* Offset from TBOOT base, used by SW */
+ capabilities : { MLE_HDR_CAPS },
+ cmdline_start_off : 0, /* Offset from TBOOT base, used by SW */
+ cmdline_end_off : 0 /* Offset from TBOOT base, used by SW */
+};
+
+/*
+ * counts of APs going into wait-for-sipi
+ */
+/* count of APs in WAIT-FOR-SIPI */
+atomic_t ap_wfs_count;
+
+static __data uint8_t *g_mle_pt;
+
+__data uint32_t g_using_da = 0;
+
+static __data event_log_container_t *g_elog = NULL;
+static __data heap_event_log_ptr_elt2_t *g_elog_2 = NULL;
+
+static void print_file_info(void)
+{
+ printk(TBOOT_DETA"file addresses:\n");
+ printk(TBOOT_DETA"\t RTMEM start=%p\n", g_rtmem_base);
+ printk(TBOOT_DETA"\t RTMEM end=%p\n", g_rtmem_base + g_image_size + TBOOT_RTMEM_SIZE);
+ printk(TBOOT_DETA"\t IMAGE start=%p\n", g_image_base);
+ printk(TBOOT_DETA"\t IMAGE end=%p\n", g_image_base + g_image_size);
+ printk(TBOOT_DETA"\t MLE start=%p\n", g_text_base);
+ printk(TBOOT_DETA"\t MLE end=%p\n", g_text_base + g_text_size);
+ /*printk(TBOOT_DETA"\t &_post_launch_entry=%p\n", &_post_launch_entry);
+ printk(TBOOT_DETA"\t &_txt_wakeup=%p\n", &_txt_wakeup);*/
+ printk(TBOOT_DETA"\t &g_mle_hdr=%p\n", &g_mle_hdr);
+}
+
+static void print_mle_hdr(const mle_hdr_t *mle_hdr)
+{
+ printk(TBOOT_DETA"MLE header:\n");
+ printk(TBOOT_DETA"\t uuid="); print_uuid(&mle_hdr->uuid);
+ printk(TBOOT_DETA"\n");
+ printk(TBOOT_DETA"\t length=%x\n", mle_hdr->length);
+ printk(TBOOT_DETA"\t version=%08x\n", mle_hdr->version);
+ printk(TBOOT_DETA"\t entry_point=%08x\n", mle_hdr->entry_point);
+ printk(TBOOT_DETA"\t first_valid_page=%08x\n", mle_hdr->first_valid_page);
+ printk(TBOOT_DETA"\t mle_start_off=%x\n", mle_hdr->mle_start_off);
+ printk(TBOOT_DETA"\t mle_end_off=%x\n", mle_hdr->mle_end_off);
+ printk(TBOOT_DETA"\t cmdline_start_off=%x\n", mle_hdr->cmdline_start_off);
+ printk(TBOOT_DETA"\t cmdline_end_off=%x\n", mle_hdr->cmdline_end_off);
+ print_txt_caps("\t ", mle_hdr->capabilities);
+}
+
+#if 0
+static void print_mle_pagetable(void)
+{
+ uint32_t mle_size, mle_off;
+ void *pg_dir_ptr_tab, *pg_dir, *pg_tab;
+ uint64_t *pte;
+ int i = 0;
+
+ mle_size = g_mle_hdr.mle_end_off - g_mle_hdr.mle_start_off;
+ pg_dir_ptr_tab = g_mle_pt;
+ pg_dir = pg_dir_ptr_tab + PAGE_SIZE;
+ pg_tab = pg_dir + PAGE_SIZE;
+
+ printk(TBOOT_DETA"MLE Page Tables:\n");
+ printk(" pg_dir_ptr_tab=%016llx pg_dir_ptr_tab[0]=%016llx pg_dir_ptr_tab[1]=%016llx\n",
+ (uint64_t)pg_dir_ptr_tab, *(uint64_t *)pg_dir_ptr_tab, *(uint64_t *)(pg_dir_ptr_tab + 8));
+
+ printk(" pg_dir=%016llx pg_dir[0]=%016llx pg_dir[1]=%016llx\n",
+ (uint64_t)pg_dir, *(uint64_t *)pg_dir, *(uint64_t *)(pg_dir + 8));
+
+ pte = pg_tab;
+ mle_off = 0;
+ printk(" pg_tab=%016llx\n", (uint64_t)pg_tab);
+ for (i = 0; mle_off < mle_size; i++, pte++, mle_off += PAGE_SIZE)
+ printk(" pte[%d]=%016llx\n", i, *pte);
+}
+#endif
+
+void txt_init_mle_header(void)
+{
+ uint64_t ple;
+
+ lea_reference(post_launch_entry, ple);
+
+ g_mle_hdr.entry_point = (uint32_t)(ple - (uint64_t)g_text_base);
+ g_mle_hdr.mle_start_off = (uint32_t)((uint64_t)g_text_base -
+ (uint64_t)g_rtmem_base);
+ g_mle_hdr.mle_end_off = (uint32_t)((uint64_t)g_text_base +
+ (uint64_t)g_text_size -
+ (uint64_t)g_rtmem_base);
+ g_mle_hdr.cmdline_start_off = (uint32_t)((uint64_t)g_cmdline -
+ (uint64_t)g_rtmem_base);
+ g_mle_hdr.cmdline_end_off = (uint32_t)((uint64_t)g_cmdline +
+ CMDLINE_SIZE - 1 -
+ (uint64_t)g_rtmem_base);
+ print_mle_hdr(&g_mle_hdr);
+}
+
+/* page dir/table entry is phys addr + P + R/W + PWT */
+#define MAKE_PDTE(addr) (((uint64_t)(unsigned long long)(addr) & PAGE_MASK) | 0x01)
+
+/* we assume/know that our image is <2MB and thus fits w/in a single */
+/* PT (512*4KB = 2MB) and thus fixed to 1 pg dir ptr and 1 pgdir and */
+/* 1 ptable = 3 pages and just 1 loop loop for ptable MLE page table */
+/* can only contain 4k pages */
+
+/* pgdir ptr + pgdir + ptab = 3 */
+
+bool txt_build_mle_pagetable(void)
+{
+ uint32_t mle_start, mle_size;
+ void *ptab_base;
+ uint32_t ptab_size, mle_off;
+ void *pg_dir_ptr_tab, *pg_dir, *pg_tab;
+ uint64_t *pte;
+
+ /* page tables start at the phys addr of the MLE base and cover MLE */
+ mle_start = g_mle_hdr.mle_start_off + (uint32_t)(uint64_t)g_rtmem_base;
+ mle_size = g_mle_hdr.mle_end_off - g_mle_hdr.mle_start_off;
+
+ /* place PTs in 3 page before the TBOOT image */
+ g_mle_pt = g_rtmem_base + TBOOT_PLEPT_SIZE;
+
+ printk(TBOOT_DETA"MLE start=0x%x, end=0x%x, size=0x%x\n",
+ mle_start, mle_start+mle_size, mle_size);
+ if ( mle_size > 512*PAGE_SIZE ) {
+ printk(TBOOT_ERR"MLE size too big for single page table\n");
+ return false;
+ }
+
+ /* should start on page boundary */
+ if ( mle_start & ~PAGE_MASK ) {
+ printk(TBOOT_ERR"MLE start is not page-aligned\n");
+ return false;
+ }
+
+ /* place ptab_base below MLE */
+ ptab_size = TBOOT_MLEPT_SIZE;
+ ptab_base = g_mle_pt; /* already zeroed */
+ printk(TBOOT_DETA"ptab_size=%x, ptab_base=%p\n", ptab_size, ptab_base);
+
+ pg_dir_ptr_tab = ptab_base;
+ pg_dir = pg_dir_ptr_tab + PAGE_SIZE;
+ pg_tab = pg_dir + PAGE_SIZE;
+
+ /* only use first entry in page dir ptr table */
+ *(uint64_t *)pg_dir_ptr_tab = MAKE_PDTE(pg_dir);
+
+ /* only use first entry in page dir */
+ *(uint64_t *)pg_dir = MAKE_PDTE(pg_tab);
+
+ pte = pg_tab;
+ mle_off = 0;
+ do {
+ *pte = MAKE_PDTE(mle_start + mle_off);
+
+ pte++;
+ mle_off += PAGE_SIZE;
+ } while ( mle_off < mle_size );
+
+ /* DEBUG print_mle_pagetable();*/
+
+ return true;
+}
+
+/* should be called after os_mle_data initialized */
+static void *init_event_log(void)
+{
+ os_mle_data_t *os_mle_data = get_os_mle_data_start(get_txt_heap());
+ g_elog = (event_log_container_t *)&os_mle_data->event_log_buffer;
+
+ memcpy((void *)g_elog->signature, EVTLOG_SIGNATURE,
+ sizeof(g_elog->signature));
+ g_elog->container_ver_major = EVTLOG_CNTNR_MAJOR_VER;
+ g_elog->container_ver_minor = EVTLOG_CNTNR_MINOR_VER;
+ g_elog->pcr_event_ver_major = EVTLOG_EVT_MAJOR_VER;
+ g_elog->pcr_event_ver_minor = EVTLOG_EVT_MINOR_VER;
+ g_elog->size = sizeof(os_mle_data->event_log_buffer);
+ g_elog->pcr_events_offset = sizeof(*g_elog);
+ g_elog->next_event_offset = sizeof(*g_elog);
+
+ return (void *)g_elog;
+}
+
+static void init_evtlog_desc(heap_event_log_ptr_elt2_t *evt_log)
+{
+ unsigned int i;
+ os_mle_data_t *os_mle_data = get_os_mle_data_start(get_txt_heap());
+
+ switch (g_tpm->extpol) {
+ case TB_EXTPOL_AGILE:
+ for (i=0; i<evt_log->count; i++) {
+ evt_log->event_log_descr[i].alg = g_tpm->algs_banks[i];
+ evt_log->event_log_descr[i].phys_addr =
+ (uint64_t)(os_mle_data->event_log_buffer + i*4096);
+ evt_log->event_log_descr[i].size = 4096;
+ evt_log->event_log_descr[i].pcr_events_offset = 0;
+ evt_log->event_log_descr[i].next_event_offset = 0;
+ }
+ break;
+ case TB_EXTPOL_EMBEDDED:
+ for (i=0; i<evt_log->count; i++) {
+ evt_log->event_log_descr[i].alg = g_tpm->algs[i];
+ evt_log->event_log_descr[i].phys_addr =
+ (uint64_t)(os_mle_data->event_log_buffer + i*4096);
+ evt_log->event_log_descr[i].size = 4096;
+ evt_log->event_log_descr[i].pcr_events_offset = 0;
+ evt_log->event_log_descr[i].next_event_offset = 0;
+ }
+ break;
+ case TB_EXTPOL_FIXED:
+ evt_log->event_log_descr[0].alg = g_tpm->cur_alg;
+ evt_log->event_log_descr[0].phys_addr =
+ (uint64_t)os_mle_data->event_log_buffer;
+ evt_log->event_log_descr[0].size = 4096;
+ evt_log->event_log_descr[0].pcr_events_offset = 0;
+ evt_log->event_log_descr[0].next_event_offset = 0;
+ break;
+ default:
+ return;
+ }
+}
+
+static void init_os_sinit_ext_data(heap_ext_data_element_t* elts)
+{
+ heap_ext_data_element_t* elt = elts;
+ heap_event_log_ptr_elt_t *evt_log;
+
+ if ( g_tpm->major == TPM12_VER_MAJOR ) {
+ evt_log = (heap_event_log_ptr_elt_t *)elt->data;
+ evt_log->event_log_phys_addr = (uint64_t)init_event_log();
+ elt->type = HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR;
+ elt->size = sizeof(*elt) + sizeof(*evt_log);
+ } else if ( g_tpm->major == TPM20_VER_MAJOR ) {
+ g_elog_2 = (heap_event_log_ptr_elt2_t *)elt->data;
+
+ if ( g_tpm->extpol == TB_EXTPOL_AGILE )
+ g_elog_2->count = g_tpm->banks;
+ else if ( g_tpm->extpol == TB_EXTPOL_EMBEDDED )
+ g_elog_2->count = g_tpm->alg_count;
+ else
+ g_elog_2->count = 1;
+
+ init_evtlog_desc(g_elog_2);
+
+ elt->type = HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR_2;
+ elt->size = sizeof(*elt) + sizeof(u32) +
+ g_elog_2->count * sizeof(heap_event_log_descr_t);
+ }
+
+ elt = (void *)elt + elt->size;
+ elt->type = HEAP_EXTDATA_TYPE_END;
+ elt->size = sizeof(*elt);
+}
+
+/*
+ * sets up TXT heap
+ */
+static txt_heap_t *init_txt_heap(void *ptab_base, acm_hdr_t *sinit)
+{
+ txt_heap_t *txt_heap;
+ txt_caps_t sinit_caps;
+ txt_caps_t caps_mask = { 0 };
+ uint64_t *size;
+ uint64_t min_lo_ram, max_lo_ram, min_hi_ram, max_hi_ram;
+ const efi_file_t *lcp_file;
+ struct acpi_rsdp *rsdp;
+
+ txt_heap = get_txt_heap();
+
+ /*
+ * BIOS data already setup by BIOS
+ */
+ if ( !verify_txt_heap(txt_heap, true) )
+ return NULL;
+
+ /*
+ * OS/loader to MLE data
+ */
+ os_mle_data_t *os_mle_data = get_os_mle_data_start(txt_heap);
+ size = (uint64_t *)((uint64_t)os_mle_data - sizeof(uint64_t));
+ *size = sizeof(*os_mle_data) + sizeof(uint64_t);
+ memset(os_mle_data, 0, sizeof(*os_mle_data));
+ os_mle_data->version = 3;
+ os_mle_data->saved_misc_enable_msr = rdmsr(MSR_IA32_MISC_ENABLE);
+
+ /*
+ * OS/loader to SINIT data
+ */
+ /* check sinit supported os_sinit_data version */
+ uint32_t version = get_supported_os_sinit_data_ver(sinit);
+ if ( version < MIN_OS_SINIT_DATA_VER ) {
+ printk(TBOOT_ERR"unsupported OS to SINIT data version(%u) in sinit\n",
+ version);
+ return NULL;
+ }
+ if ( version > MAX_OS_SINIT_DATA_VER )
+ version = MAX_OS_SINIT_DATA_VER;
+
+ os_sinit_data_t *os_sinit_data = get_os_sinit_data_start(txt_heap);
+ size = (uint64_t *)((uint64_t)os_sinit_data - sizeof(uint64_t));
+ *size = calc_os_sinit_data_size(version);
+ memset(os_sinit_data, 0, *size);
+ os_sinit_data->version = version;
+
+ /* this is phys addr */
+ os_sinit_data->mle_ptab = (uint64_t)ptab_base;
+ os_sinit_data->mle_size = g_mle_hdr.mle_end_off - g_mle_hdr.mle_start_off;
+ /* this is linear addr (offset from MLE base) of mle header */
+ os_sinit_data->mle_hdr_base = (uint64_t)&g_mle_hdr - (uint64_t)g_text_base;
+
+ /* VT-d PMRs */
+ if ( !efi_get_ram_ranges(&min_lo_ram, &max_lo_ram, &min_hi_ram, &max_hi_ram) )
+ return NULL;
+
+ set_vtd_pmrs(os_sinit_data, min_lo_ram, max_lo_ram, min_hi_ram,
+ max_hi_ram);
+
+ /* LCP owner policy data */
+ lcp_file = efi_get_lcp();
+ if (lcp_file) {
+ /* copy to heap */
+ if ( lcp_file->size > sizeof(os_mle_data->lcp_po_data) ) {
+ printk(TBOOT_ERR"LCP owner policy data file is too large (%u)\n",
+ lcp_file->size);
+ return NULL;
+ }
+ memcpy(os_mle_data->lcp_po_data, lcp_file->u.buffer, lcp_file->size);
+ os_sinit_data->lcp_po_base = (unsigned long long)&os_mle_data->lcp_po_data;
+ os_sinit_data->lcp_po_size = lcp_file->size;
+ }
+
+ sinit_caps = get_sinit_capabilities(sinit);
+ caps_mask.rlp_wake_getsec = 1;
+ caps_mask.rlp_wake_monitor = 1;
+ caps_mask.pcr_map_da = 1;
+ os_sinit_data->capabilities._raw = MLE_HDR_CAPS & ~caps_mask._raw;
+ if ( sinit_caps.rlp_wake_monitor )
+ os_sinit_data->capabilities.rlp_wake_monitor = 1;
+ else if ( sinit_caps.rlp_wake_getsec )
+ os_sinit_data->capabilities.rlp_wake_getsec = 1;
+ else { /* should have been detected in verify_acmod() */
+ printk(TBOOT_ERR"SINIT capabilities are incompatible (0x%x)\n",
+ sinit_caps._raw);
+ return NULL;
+ }
+ /* capabilities : require MLE pagetable in ECX on launch */
+ /* TODO: when SINIT ready
+ * os_sinit_data->capabilities.ecx_pgtbl = 1;
+ */
+ os_sinit_data->capabilities.ecx_pgtbl = 0;
+
+ /* Always true for us: if (is_loader_launch_efi(lctx)){ */
+ /* we were launched EFI, set efi_rsdt_ptr */
+ rsdp = (struct acpi_rsdp*)efi_get_rsdp();
+ if (rsdp != NULL){
+ if (version < 6){
+ /* rsdt */
+ /* NOTE: Winston Wang says this doesn't work for v5 */
+ os_sinit_data->efi_rsdt_ptr = (uint64_t) rsdp->rsdp1.rsdt;
+ } else {
+ /* rsdp */
+ memcpy((void *)&g_rsdp, rsdp, sizeof(struct acpi_rsdp));
+ os_sinit_data->efi_rsdt_ptr = (uint64_t)&g_rsdp;
+ }
+ } else {
+ /* per discussions--if we don't have an ACPI pointer, die */
+ printk(TBOOT_ERR"Failed to find RSDP for EFI launch\n");
+ return NULL;
+ }
+
+ /* capabilities : choose DA/LG */
+ os_sinit_data->capabilities.pcr_map_no_legacy = 1;
+ if ( sinit_caps.pcr_map_da && get_tboot_prefer_da() )
+ os_sinit_data->capabilities.pcr_map_da = 1;
+ else if ( !sinit_caps.pcr_map_no_legacy )
+ os_sinit_data->capabilities.pcr_map_no_legacy = 0;
+ else if ( sinit_caps.pcr_map_da ) {
+ printk(TBOOT_INFO
+ "DA is the only supported PCR mapping by SINIT, use it\n");
+ os_sinit_data->capabilities.pcr_map_da = 1;
+ }
+ else {
+ printk(TBOOT_ERR"SINIT capabilities are incompatible (0x%x)\n",
+ sinit_caps._raw);
+ return NULL;
+ }
+ g_using_da = os_sinit_data->capabilities.pcr_map_da;
+
+ /* PCR mapping selection MUST be zero in TPM2.0 mode
+ * since D/A mapping is the only supported by TPM2.0 */
+ if ( g_tpm->major >= TPM20_VER_MAJOR ) {
+ os_sinit_data->flags = (g_tpm->extpol == TB_EXTPOL_AGILE) ? 0 : 1;
+ os_sinit_data->capabilities.pcr_map_no_legacy = 0;
+ os_sinit_data->capabilities.pcr_map_da = 0;
+ g_using_da = 1;
+ }
+
+ /* Event log initialization */
+ if ( os_sinit_data->version >= 6 )
+ init_os_sinit_ext_data(os_sinit_data->ext_data_elts);
+
+ print_os_sinit_data(os_sinit_data);
+
+ /*
+ * SINIT to MLE data will be setup by SINIT
+ */
+
+ return txt_heap;
+}
+
+bool txt_is_launched(void)
+{
+ txt_sts_t sts;
+
+ sts._raw = read_pub_config_reg(TXTCR_STS);
+
+ return sts.senter_done_sts;
+}
+
+tb_error_t txt_launch_environment(void)
+{
+ os_mle_data_t *os_mle_data;
+ txt_heap_t *txt_heap;
+
+ /* print some debug info */
+ print_file_info();
+
+ /* MLE page table already setup earlier */
+
+ /* initialize TXT heap */
+ txt_heap = init_txt_heap(g_mle_pt, g_sinit);
+ if ( txt_heap == NULL )
+ return TB_ERR_TXT_NOT_SUPPORTED;
+
+ /* save MTRRs before we alter them for SINIT launch */
+ os_mle_data = get_os_mle_data_start(txt_heap);
+ save_mtrrs(&(os_mle_data->saved_mtrr_state));
+
+ /* set MTRRs properly for AC module (SINIT) */
+ if ( !set_mtrrs_for_acmod(g_sinit) )
+ return TB_ERR_FATAL;
+
+ /* deactivate current locality */
+ if (g_tpm_family == TPM_IF_20_CRB ) {
+ printk(TBOOT_INFO"Relinquish CRB localility 0 before executing GETSEC[SENTER]...\n");
+ if (!tpm_relinquish_locality_crb(0)){
+ printk(TBOOT_INFO"Relinquish CRB locality 0 failed...\n");
+ apply_policy(TB_ERR_TPM_NOT_READY) ;
+ }
+ }
+
+ /* Left behind commented out mess */
+
+ printk(TBOOT_INFO"executing GETSEC[SENTER]...\n");
+ /* (optionally) pause before executing GETSEC[SENTER] */
+ if ( g_vga_delay > 0 )
+ delay(g_vga_delay * 1000);
+
+ /* SINIT has be (and is) located below 4G for SENTER */
+ __getsec_senter((uint32_t)(uint64_t)g_sinit, (g_sinit->size)*4);
+
+ printk(TBOOT_INFO"ERROR--we should not get here!\n");
+
+ return TB_ERR_FATAL;
+}
+
+bool txt_prepare_cpu(void)
+{
+ unsigned long cr0;
+ uint64_t mcg_cap, mcg_stat, msr_efer, rflags;
+
+ /* must be running at CPL 0 => this is implicit in even getting this far */
+ /* since our bootstrap code loads a GDT, etc. */
+
+ msr_efer = rdmsr(MSR_EFER);
+
+ /* must be in IA-32e 16b sub-mode */
+ if ( !( msr_efer & (1 << _EFER_LMA) ) ) {
+ printk(TBOOT_ERR"ERR: not in IA-32e 16bit sub- mode\n");
+ return false;
+ }
+
+ cr0 = read_cr0();
+
+ /* cache must be enabled (CR0.CD = CR0.NW = 0) */
+ if ( cr0 & CR0_CD ) {
+ printk(TBOOT_INFO"CR0.CD set\n");
+ cr0 &= ~CR0_CD;
+ }
+ if ( cr0 & CR0_NW ) {
+ printk(TBOOT_INFO"CR0.NW set\n");
+ cr0 &= ~CR0_NW;
+ }
+
+ /* native FPU error reporting must be enabled for proper */
+ /* interaction behavior */
+ if ( !(cr0 & CR0_NE) ) {
+ printk(TBOOT_INFO"CR0.NE not set\n");
+ cr0 |= CR0_NE;
+ }
+
+ write_cr0(cr0);
+
+ /* cannot be in virtual-8086 mode (EFLAGS.VM=1) */
+ rflags = read_rflags();
+ if ( rflags & X86_EFLAGS_VM ) {
+ printk(TBOOT_INFO"EFLAGS.VM set\n");
+ write_rflags(rflags | ~X86_EFLAGS_VM);
+ }
+
+ printk(TBOOT_INFO"IA32_EFER, CR0 and EFLAGS OK\n");
+
+ /*
+ * verify that we're not already in a protected environment
+ */
+ if ( txt_is_launched() ) {
+ printk(TBOOT_ERR"already in protected environment\n");
+ return false;
+ }
+
+ /*
+ * verify all machine check status registers are clear (unless
+ * support preserving them)
+ */
+
+ /* no machine check in progress (IA32_MCG_STATUS.MCIP=1) */
+ mcg_stat = rdmsr(MSR_MCG_STATUS);
+ if ( mcg_stat & 0x04 ) {
+ printk(TBOOT_ERR"machine check in progress\n");
+ return false;
+ }
+
+ getsec_parameters_t params;
+ if ( !get_parameters(&params) ) {
+ printk(TBOOT_ERR"get_parameters() failed\n");
+ return false;
+ }
+
+ /* check if all machine check regs are clear */
+ mcg_cap = rdmsr(MSR_MCG_CAP);
+ for ( unsigned int i = 0; i < (mcg_cap & 0xff); i++ ) {
+ mcg_stat = rdmsr(MSR_MC0_STATUS + 4*i);
+ if ( mcg_stat & (1ULL << 63) ) {
+ printk(TBOOT_ERR"MCG[%u] = %Lx ERROR\n", i, mcg_stat);
+ if ( !params.preserve_mce )
+ return false;
+ }
+ }
+
+ if ( params.preserve_mce )
+ printk(TBOOT_INFO"supports preserving machine check errors\n");
+ else
+ printk(TBOOT_INFO"no machine check errors\n");
+
+ if ( params.proc_based_scrtm )
+ printk(TBOOT_INFO"CPU support processor-based S-CRTM\n");
+
+ /* all is well with the processor state */
+ printk(TBOOT_INFO"CPU is ready for SENTER\n");
+
+ return true;
+}
+
+bool txt_is_powercycle_required(void)
+{
+ /* a powercycle is required to clear the TXT_RESET.STS flag */
+ txt_ests_t ests = (txt_ests_t)read_pub_config_reg(TXTCR_ESTS);
+ return ests.txt_reset_sts;
+}
+
+#define ACM_MEM_TYPE_UC 0x0100
+#define ACM_MEM_TYPE_WC 0x0200
+#define ACM_MEM_TYPE_WT 0x1000
+#define ACM_MEM_TYPE_WP 0x2000
+#define ACM_MEM_TYPE_WB 0x4000
+
+#define DEF_ACM_MAX_SIZE 0x8000
+#define DEF_ACM_VER_MASK 0xffffffff
+#define DEF_ACM_VER_SUPPORTED 0x00
+#define DEF_ACM_MEM_TYPES ACM_MEM_TYPE_UC
+#define DEF_SENTER_CTRLS 0x00
+
+bool get_parameters(getsec_parameters_t *params)
+{
+ unsigned long long cr4;
+ uint32_t index, eax, ebx, ecx;
+ int param_type;
+
+ /* sanity check because GETSEC[PARAMETERS] will fail if not set */
+ cr4 = read_cr4();
+ if ( !(cr4 & CR4_SMXE) ) {
+ printk(TBOOT_ERR"SMXE not enabled, can't read parameters - cr4: %llx\n", cr4);
+ return false;
+ }
+
+ memset(params, 0, sizeof(*params));
+ params->acm_max_size = DEF_ACM_MAX_SIZE;
+ params->acm_mem_types = DEF_ACM_MEM_TYPES;
+ params->senter_controls = DEF_SENTER_CTRLS;
+ params->proc_based_scrtm = false;
+ params->preserve_mce = false;
+
+ index = 0;
+ do {
+ __getsec_parameters(index++, &param_type, &eax, &ebx, &ecx);
+ /* the code generated for a 'switch' statement doesn't work in this */
+ /* environment, so use if/else blocks instead */
+
+ /* NULL - all reserved */
+ if ( param_type == 0 )
+ ;
+ /* supported ACM versions */
+ else if ( param_type == 1 ) {
+ if ( params->n_versions == MAX_SUPPORTED_ACM_VERSIONS )
+ printk(TBOOT_WARN"number of supported ACM version exceeds "
+ "MAX_SUPPORTED_ACM_VERSIONS\n");
+ else {
+ params->acm_versions[params->n_versions].mask = ebx;
+ params->acm_versions[params->n_versions].version = ecx;
+ params->n_versions++;
+ }
+ }
+ /* max size AC execution area */
+ else if ( param_type == 2 )
+ params->acm_max_size = eax & 0xffffffe0;
+ /* supported non-AC mem types */
+ else if ( param_type == 3 )
+ params->acm_mem_types = eax & 0xffffffe0;
+ /* SENTER controls */
+ else if ( param_type == 4 )
+ params->senter_controls = (eax & 0x00007fff) >> 8;
+ /* TXT extensions support */
+ else if ( param_type == 5 ) {
+ params->proc_based_scrtm = (eax & 0x00000020) ? true : false;
+ params->preserve_mce = (eax & 0x00000040) ? true : false;
+ }
+ else {
+ printk(TBOOT_WARN"unknown GETSEC[PARAMETERS] type: %d\n",
+ param_type);
+ param_type = 0; /* set so that we break out of the loop */
+ }
+ } while ( param_type != 0 );
+
+ if ( params->n_versions == 0 ) {
+ params->acm_versions[0].mask = DEF_ACM_VER_MASK;
+ params->acm_versions[0].version = DEF_ACM_VER_SUPPORTED;
+ params->n_versions = 1;
+ }
+
+ return true;
+}
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/verify.c b/tboot/verify.c
new file mode 100644
index 0000000..ee5d00d
--- /dev/null
+++ b/tboot/verify.c
@@ -0,0 +1,601 @@
+/*
+ * verify.c: verify that platform and processor supports Intel(r) TXT
+ *
+ * Copyright (c) 2003-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <msr.h>
+#include <compiler.h>
+#include <string.h>
+#include <atomic.h>
+#include <misc.h>
+#include <processor.h>
+#include <page.h>
+#include <printk.h>
+#include <uuid.h>
+#include <tb_error.h>
+#include <eficore.h>
+#include <tboot.h>
+#include <acpi.h>
+#include <mle.h>
+#include <hash.h>
+#include <integrity.h>
+#include <cmdline.h>
+#include <txt/txt.h>
+#include <txt/smx.h>
+#include <txt/mtrrs.h>
+#include <txt/config_regs.h>
+#include <txt/heap.h>
+#include <txt/verify.h>
+
+/*
+ * CPUID extended feature info
+ */
+static unsigned int g_cpuid_ext_feat_info;
+
+/*
+ * IA32_FEATURE_CONTROL_MSR
+ */
+static unsigned long g_feat_ctrl_msr;
+
+
+static bool read_processor_info(void)
+{
+ unsigned long long f1, f2;
+ /* eax: regs[0], ebx: regs[1], ecx: regs[2], edx: regs[3] */
+ uint32_t regs[4];
+
+ /* is CPUID supported? */
+ /* (it's supported if ID flag in RFLAGS can be set and cleared) */
+ asm("pushfq\n\t"
+ "pushfq\n\t"
+ "popq %0\n\t"
+ "movq %0,%1\n\t"
+ "xorq %2,%0\n\t"
+ "pushq %0\n\t"
+ "popfq\n\t"
+ "pushfq\n\t"
+ "popq %0\n\t"
+ "popfq\n\t"
+ : "=&r" (f1), "=&r" (f2)
+ : "ir" (X86_EFLAGS_ID));
+ if ( ((f1^f2) & X86_EFLAGS_ID) == 0 ) {
+ g_cpuid_ext_feat_info = 0;
+ printk(TBOOT_ERR"CPUID instruction is not supported.\n");
+ return false;
+ }
+
+ do_cpuid(0, regs);
+ if ( regs[1] != 0x756e6547 /* "Genu" */
+ || regs[2] != 0x6c65746e /* "ntel" */
+ || regs[3] != 0x49656e69 ) { /* "ineI" */
+ g_cpuid_ext_feat_info = 0;
+ printk(TBOOT_ERR"Non-Intel CPU detected.\n");
+ return false;
+ }
+ g_cpuid_ext_feat_info = cpuid_ecx(1);
+
+ /* read feature control msr only if processor supports VMX or SMX instructions */
+ if ( (g_cpuid_ext_feat_info & CPUID_X86_FEATURE_VMX) ||
+ (g_cpuid_ext_feat_info & CPUID_X86_FEATURE_SMX) ) {
+ g_feat_ctrl_msr = rdmsr(MSR_IA32_FEATURE_CONTROL);
+ printk(TBOOT_DETA"IA32_FEATURE_CONTROL_MSR: %08lx\n", g_feat_ctrl_msr);
+ }
+
+ return true;
+}
+
+static bool supports_vmx(void)
+{
+ /* check that processor supports VMX instructions */
+ if ( !(g_cpuid_ext_feat_info & CPUID_X86_FEATURE_VMX) ) {
+ printk(TBOOT_ERR"ERR: CPU does not support VMX\n");
+ return false;
+ }
+ printk(TBOOT_INFO"CPU is VMX-capable\n");
+
+ /* and that VMX is enabled in the feature control MSR */
+ if ( !(g_feat_ctrl_msr & IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_IN_SMX) ) {
+ printk(TBOOT_ERR"ERR: VMXON disabled by feature control MSR (%lx)\n",
+ g_feat_ctrl_msr);
+ return false;
+ }
+
+ return true;
+}
+
+static bool supports_smx(void)
+{
+ /* check that processor supports SMX instructions */
+ if ( !(g_cpuid_ext_feat_info & CPUID_X86_FEATURE_SMX) ) {
+ printk(TBOOT_ERR"ERR: CPU does not support SMX\n");
+ return false;
+ }
+ printk(TBOOT_INFO"CPU is SMX-capable\n");
+
+ /*
+ * and that SMX is enabled in the feature control MSR
+ */
+
+ /* check that the MSR is locked -- BIOS should always lock it */
+ if ( !(g_feat_ctrl_msr & IA32_FEATURE_CONTROL_MSR_LOCK) ) {
+ printk(TBOOT_ERR"ERR: IA32_FEATURE_CONTROL_MSR_LOCK is not locked\n");
+ /* this should not happen, as BIOS is required to lock the MSR */
+#ifdef PERMISSIVE_BOOT
+ /* we enable VMX outside of SMX as well so that if there was some */
+ /* error in the TXT boot, VMX will continue to work */
+ g_feat_ctrl_msr |= IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_IN_SMX |
+ IA32_FEATURE_CONTROL_MSR_ENABLE_VMX_OUT_SMX |
+ IA32_FEATURE_CONTROL_MSR_ENABLE_SENTER |
+ IA32_FEATURE_CONTROL_MSR_SENTER_PARAM_CTL |
+ IA32_FEATURE_CONTROL_MSR_LOCK;
+ wrmsrl(MSR_IA32_FEATURE_CONTROL, g_feat_ctrl_msr);
+ return true;
+#else
+ return false;
+#endif
+ }
+
+ /* check that SENTER (w/ full params) is enabled */
+ if ( !(g_feat_ctrl_msr & (IA32_FEATURE_CONTROL_MSR_ENABLE_SENTER |
+ IA32_FEATURE_CONTROL_MSR_SENTER_PARAM_CTL)) ) {
+ printk(TBOOT_ERR"ERR: SENTER disabled by feature control MSR (%lx)\n",
+ g_feat_ctrl_msr);
+ return false;
+ }
+
+ return true;
+}
+
+bool use_mwait(void)
+{
+ return get_tboot_mwait() &&
+ (g_cpuid_ext_feat_info & CPUID_X86_FEATURE_XMM3);
+}
+
+tb_error_t supports_txt(void)
+{
+ capabilities_t cap;
+
+ /* processor must support cpuid and must be Intel CPU */
+ if ( !read_processor_info() )
+ return TB_ERR_SMX_NOT_SUPPORTED;
+
+ /* processor must support SMX */
+ if ( !supports_smx() )
+ return TB_ERR_SMX_NOT_SUPPORTED;
+
+ if ( use_mwait() ) {
+ /* set MONITOR/MWAIT support (SENTER will clear, so always set) */
+ uint64_t misc;
+ misc = rdmsr(MSR_IA32_MISC_ENABLE);
+ misc |= MSR_IA32_MISC_ENABLE_MONITOR_FSM;
+ wrmsr(MSR_IA32_MISC_ENABLE, misc);
+ }
+ else if ( !supports_vmx() ) {
+ return TB_ERR_VMX_NOT_SUPPORTED;
+ }
+
+ /* testing for chipset support requires enabling SMX on the processor */
+ write_cr4(read_cr4() | CR4_SMXE);
+ printk(TBOOT_INFO"SMX is enabled\n");
+
+ /*
+ * verify that an TXT-capable chipset is present and
+ * check that all needed SMX capabilities are supported
+ */
+
+ cap = __getsec_capabilities(0);
+ if ( cap.chipset_present ) {
+ if ( cap.senter && cap.sexit && cap.parameters && cap.smctrl &&
+ cap.wakeup ) {
+ printk(TBOOT_INFO"TXT chipset and all needed capabilities present\n");
+ return TB_ERR_NONE;
+ }
+ else
+ printk(TBOOT_ERR"ERR: insufficient SMX capabilities (%x)\n", cap._raw);
+ }
+ else
+ printk(TBOOT_ERR"ERR: TXT-capable chipset not present\n");
+
+ /* since we are failing, we should clear the SMX flag */
+ write_cr4(read_cr4() & ~CR4_SMXE);
+
+ return TB_ERR_TXT_NOT_SUPPORTED;
+}
+
+static bool reserve_vtd_delta_mem(uint64_t min_lo_ram, uint64_t max_lo_ram,
+ uint64_t min_hi_ram, uint64_t max_hi_ram)
+{
+ uint64_t base, length;
+ (void)min_lo_ram; (void)min_hi_ram;/* portably suppress compiler warning */
+
+ txt_heap_t* txt_heap = get_txt_heap();
+ os_sinit_data_t *os_sinit_data = get_os_sinit_data_start(txt_heap);
+
+ if ( max_lo_ram != (os_sinit_data->vtd_pmr_lo_base +
+ os_sinit_data->vtd_pmr_lo_size) ) {
+ base = os_sinit_data->vtd_pmr_lo_base + os_sinit_data->vtd_pmr_lo_size;
+ length = max_lo_ram - base;
+ printk(TBOOT_INFO"reserving 0x%Lx - 0x%Lx, which was truncated for VT-d\n",
+ base, base + length);
+ if ( !efi_add_resmap_entry(base, length) )
+ return false;
+ }
+ if ( max_hi_ram != (os_sinit_data->vtd_pmr_hi_base +
+ os_sinit_data->vtd_pmr_hi_size) ) {
+ base = os_sinit_data->vtd_pmr_hi_base + os_sinit_data->vtd_pmr_hi_size;
+ length = max_hi_ram - base;
+ printk(TBOOT_INFO"reserving 0x%Lx - 0x%Lx, which was truncated for VT-d\n",
+ base, base + length);
+ if ( !efi_add_resmap_entry(base, length) )
+ return false;
+ }
+
+ return true;
+}
+
+static bool verify_vtd_pmrs(txt_heap_t *txt_heap)
+{
+ os_sinit_data_t *os_sinit_data, tmp_os_sinit_data;
+ uint64_t min_lo_ram, max_lo_ram, min_hi_ram, max_hi_ram;
+
+ os_sinit_data = get_os_sinit_data_start(txt_heap);
+
+ /*
+ * make sure the VT-d PMRs were actually set to cover what
+ * we expect
+ */
+
+ /* calculate what they should have been */
+ /* no memory table on S3 resume, so use saved (sealed) values */
+ if ( s3_flag ) {
+ min_lo_ram = g_pre_k_s3_state.vtd_pmr_lo_base;
+ max_lo_ram = min_lo_ram + g_pre_k_s3_state.vtd_pmr_lo_size;
+ min_hi_ram = g_pre_k_s3_state.vtd_pmr_hi_base;
+ max_hi_ram = min_hi_ram + g_pre_k_s3_state.vtd_pmr_hi_size;
+ }
+ else {
+ if ( !efi_get_ram_ranges(&min_lo_ram, &max_lo_ram,
+ &min_hi_ram, &max_hi_ram) )
+ return false;
+
+ /* if vtd_pmr_lo/hi sizes rounded to 2MB granularity are less than the
+ max_lo/hi_ram values determined from the e820 table, then we must
+ reserve the differences in e820 table so that unprotected memory is
+ not used by the kernel */
+ if ( !reserve_vtd_delta_mem(min_lo_ram, max_lo_ram, min_hi_ram,
+ max_hi_ram) ) {
+ printk(TBOOT_ERR"failed to reserve VT-d PMR delta memory\n");
+ return false;
+ }
+ }
+
+ /* compare to current values */
+ memset(&tmp_os_sinit_data, 0, sizeof(tmp_os_sinit_data));
+ tmp_os_sinit_data.version = os_sinit_data->version;
+ set_vtd_pmrs(&tmp_os_sinit_data, min_lo_ram, max_lo_ram, min_hi_ram,
+ max_hi_ram);
+ if ( (tmp_os_sinit_data.vtd_pmr_lo_base !=
+ os_sinit_data->vtd_pmr_lo_base) ||
+ (tmp_os_sinit_data.vtd_pmr_lo_size !=
+ os_sinit_data->vtd_pmr_lo_size) ||
+ (tmp_os_sinit_data.vtd_pmr_hi_base !=
+ os_sinit_data->vtd_pmr_hi_base) ||
+ (tmp_os_sinit_data.vtd_pmr_hi_size !=
+ os_sinit_data->vtd_pmr_hi_size) ) {
+ printk(TBOOT_ERR"OS to SINIT data VT-d PMR settings do not match:\n");
+ print_os_sinit_data(&tmp_os_sinit_data);
+ print_os_sinit_data(os_sinit_data);
+ return false;
+ }
+
+ if ( !s3_flag ) {
+ /* save the verified values so that they can be sealed for S3 */
+ g_pre_k_s3_state.vtd_pmr_lo_base = os_sinit_data->vtd_pmr_lo_base;
+ g_pre_k_s3_state.vtd_pmr_lo_size = os_sinit_data->vtd_pmr_lo_size;
+ g_pre_k_s3_state.vtd_pmr_hi_base = os_sinit_data->vtd_pmr_hi_base;
+ g_pre_k_s3_state.vtd_pmr_hi_size = os_sinit_data->vtd_pmr_hi_size;
+ }
+
+ return true;
+}
+
+void set_vtd_pmrs(os_sinit_data_t *os_sinit_data,
+ uint64_t min_lo_ram, uint64_t max_lo_ram,
+ uint64_t min_hi_ram, uint64_t max_hi_ram)
+{
+ printk(TBOOT_DETA"min_lo_ram: 0x%Lx, max_lo_ram: 0x%Lx\n", min_lo_ram, max_lo_ram);
+ printk(TBOOT_DETA"min_hi_ram: 0x%Lx, max_hi_ram: 0x%Lx\n", min_hi_ram, max_hi_ram);
+
+ /*
+ * base must be 2M-aligned and size must be multiple of 2M
+ * (so round bases and sizes down--rounding size up might conflict
+ * with a BIOS-reserved region and cause problems; in practice, rounding
+ * base down doesn't)
+ * we want to protect all of usable mem so that any kernel allocations
+ * before VT-d remapping is enabled are protected
+ */
+
+ min_lo_ram &= ~0x1fffffULL;
+ uint64_t lo_size = (max_lo_ram - min_lo_ram) & ~0x1fffffULL;
+ os_sinit_data->vtd_pmr_lo_base = min_lo_ram;
+ os_sinit_data->vtd_pmr_lo_size = lo_size;
+
+ min_hi_ram &= ~0x1fffffULL;
+ uint64_t hi_size = (max_hi_ram - min_hi_ram) & ~0x1fffffULL;
+ os_sinit_data->vtd_pmr_hi_base = min_hi_ram;
+ os_sinit_data->vtd_pmr_hi_size = hi_size;
+}
+
+tb_error_t txt_verify_platform(void)
+{
+ txt_heap_t *txt_heap;
+ tb_error_t err;
+
+ /* check TXT supported */
+ err = supports_txt();
+ if ( err != TB_ERR_NONE )
+ return err;
+
+ /* check is TXT_RESET.STS is set, since if it is SENTER will fail */
+ txt_ests_t ests = (txt_ests_t)read_pub_config_reg(TXTCR_ESTS);
+ if ( ests.txt_reset_sts ) {
+ printk(TBOOT_ERR"TXT_RESET.STS is set and SENTER is disabled (0x%02Lx)\n",
+ ests._raw);
+ return TB_ERR_SMX_NOT_SUPPORTED;
+ }
+
+ /* verify BIOS to OS data */
+ txt_heap = get_txt_heap();
+ if ( !verify_bios_data(txt_heap) )
+ return TB_ERR_TXT_NOT_SUPPORTED;
+
+ return TB_ERR_NONE;
+}
+
+static bool verify_saved_mtrrs(txt_heap_t *txt_heap)
+{
+ os_mle_data_t *os_mle_data;
+ os_mle_data = get_os_mle_data_start(txt_heap);
+
+ return validate_mtrrs(&(os_mle_data->saved_mtrr_state));
+}
+
+tb_error_t txt_post_launch_verify_platform(void)
+{
+ txt_heap_t *txt_heap;
+
+ /*
+ * verify some of the heap structures
+ */
+ txt_heap = get_txt_heap();
+
+ if ( !verify_txt_heap(txt_heap, false) )
+ return TB_ERR_POST_LAUNCH_VERIFICATION;
+
+ /* verify the saved MTRRs */
+ if ( !verify_saved_mtrrs(txt_heap) )
+ return TB_ERR_POST_LAUNCH_VERIFICATION;
+
+ /* verify that VT-d PMRs were really set as required */
+ if ( !verify_vtd_pmrs(txt_heap) )
+ return TB_ERR_POST_LAUNCH_VERIFICATION;
+
+ return TB_ERR_NONE;
+}
+
+bool verify_memory_map(sinit_mdr_t* mdrs_base, uint32_t num_mdrs)
+{
+ sinit_mdr_t* mdr_entry;
+ sinit_mdr_t tmp_entry;
+ uint64_t base, length;
+ uint32_t i, j, pos;
+
+ if ( (mdrs_base == NULL) || (num_mdrs == 0) )
+ return false;
+
+ /* sort mdrs */
+ for( i = 0; i < num_mdrs; i++ ) {
+ memcpy(&tmp_entry, &mdrs_base[i], sizeof(sinit_mdr_t));
+ pos = i;
+ for ( j = i + 1; j < num_mdrs; j++ ) {
+ if ( ( tmp_entry.base > mdrs_base[j].base )
+ || (( tmp_entry.base == mdrs_base[j].base ) &&
+ ( tmp_entry.length > mdrs_base[j].length )) ) {
+ memcpy(&tmp_entry, &mdrs_base[j], sizeof(sinit_mdr_t));
+ pos = j;
+ }
+ }
+ if ( pos > i ) {
+ memcpy(&mdrs_base[pos], &mdrs_base[i], sizeof(sinit_mdr_t));
+ memcpy(&mdrs_base[i], &tmp_entry, sizeof(sinit_mdr_t));
+ }
+ }
+
+ /* verify e820 map against mdrs */
+ /* find all ranges *not* in MDRs:
+ if any of it is in e820 as RAM then set that to RESERVED. */
+ i = 0;
+ base = 0;
+ while ( i < num_mdrs ) {
+ mdr_entry = &mdrs_base[i];
+ i++;
+ if ( mdr_entry->mem_type > MDR_MEMTYPE_GOOD )
+ continue;
+ length = mdr_entry->base - base;
+ if ( (length > 0) && (!efi_add_resmap_entry(base, length)) )
+ return false;
+ base = mdr_entry->base + mdr_entry->length;
+ }
+
+ /* deal with the last gap */
+ length = (uint64_t)-1 - base;
+ return efi_add_resmap_entry(base, length);
+}
+
+static void print_mseg_hdr(mseg_hdr_t *mseg_hdr)
+{
+ printk(TBOOT_DETA"MSEG header dump for 0x%llx:\n", (uint64_t)mseg_hdr);
+ printk(TBOOT_DETA"\t revision_id = 0x%x\n", mseg_hdr->revision_id);
+ printk(TBOOT_DETA"\t smm_monitor_features = 0x%x\n", mseg_hdr->smm_mon_feat);
+ printk(TBOOT_DETA"\t gdtr_limit = 0x%x\n", mseg_hdr->gdtr_limit);
+ printk(TBOOT_DETA"\t gdtr_base_offset = 0x%x\n", mseg_hdr->gdtr_base_offset);
+ printk(TBOOT_DETA"\t cs_sel = 0x%x\n", mseg_hdr->cs_sel);
+ printk(TBOOT_DETA"\t eip_offset = 0x%x\n", mseg_hdr->eip_offset);
+ printk(TBOOT_DETA"\t esp_offset = 0x%x\n", mseg_hdr->esp_offset);
+ printk(TBOOT_DETA"\t cr3_offset = 0x%x\n", mseg_hdr->cr3_offset);
+}
+
+static bool are_mseg_hdrs_equal(void *mseg_base1, void *mseg_base2)
+{
+ mseg_hdr_t *mseg_hdr1, *mseg_hdr2;
+
+ mseg_hdr1 = (mseg_hdr_t *)mseg_base1;
+ mseg_hdr2 = (mseg_hdr_t *)mseg_base2;
+
+ print_mseg_hdr(mseg_hdr1);
+ print_mseg_hdr(mseg_hdr2);
+
+ if ( mseg_hdr1->revision_id != mseg_hdr2->revision_id ) {
+ printk(TBOOT_ERR"revision id is not consistent.\n");
+ return false;
+ }
+
+ if ( (mseg_hdr1->smm_mon_feat & 0xfffffffe)
+ || (mseg_hdr2->smm_mon_feat & 0xfffffffe) ) {
+ printk(TBOOT_ERR"bits 1:31 of SMM-monitor features field should be zero.\n");
+ return false;
+ }
+
+ if ( mseg_hdr1->smm_mon_feat != mseg_hdr2->smm_mon_feat ) {
+ printk(TBOOT_ERR"SMM-monitor features are not consistent.\n");
+ return false;
+ }
+
+ if ( (mseg_hdr1->gdtr_limit != mseg_hdr2->gdtr_limit)
+ || (mseg_hdr1->gdtr_base_offset != mseg_hdr2->gdtr_base_offset)
+ || (mseg_hdr1->cs_sel != mseg_hdr2->cs_sel)
+ || (mseg_hdr1->eip_offset != mseg_hdr2->eip_offset)
+ || (mseg_hdr1->esp_offset != mseg_hdr2->esp_offset)
+ || (mseg_hdr1->cr3_offset != mseg_hdr2->cr3_offset) ) {
+ printk(TBOOT_ERR"states for SMM activation are not consistent.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool verify_mseg(uint64_t smm_mon_ctl)
+{
+ txt_heap_t *txt_heap = get_txt_heap();
+ sinit_mle_data_t *sinit_mle_data = get_sinit_mle_data_start(txt_heap);
+ void *mseg_base, *txt_mseg_base;
+
+ /* opt-out */
+ if ( !(smm_mon_ctl & MSR_IA32_SMM_MONITOR_CTL_VALID) ) {
+ printk(TBOOT_INFO"\topt-out\n");
+ return true;
+ }
+
+ if ( !sinit_mle_data->mseg_valid ) {
+ printk(TBOOT_INFO"\topt-out\n");
+ return true;
+ }
+
+ /* opt-in */
+ printk(TBOOT_INFO"\topt-in ");
+ mseg_base = (void *)(unsigned long long)
+ MSR_IA32_SMM_MONITOR_CTL_MSEG_BASE(smm_mon_ctl);
+ txt_mseg_base = (void *)(uint64_t)read_pub_config_reg(TXTCR_MSEG_BASE);
+
+ if ( are_mseg_hdrs_equal(mseg_base, txt_mseg_base) ) {
+ printk(TBOOT_INFO"and same MSEG header\n");
+ return true;
+ }
+
+ printk(TBOOT_ERR"but different MSEG headers\n");
+ return false;
+}
+
+bool verify_stm(unsigned int cpuid)
+{
+ static uint64_t ilp_smm_mon_ctl;
+ uint64_t smm_mon_ctl, apicbase;
+
+ smm_mon_ctl = rdmsr(MSR_IA32_SMM_MONITOR_CTL);
+ apicbase = rdmsr(MSR_APICBASE);
+ if ( apicbase & APICBASE_BSP ) {
+ ilp_smm_mon_ctl = smm_mon_ctl;
+ printk(TBOOT_DETA"MSR for SMM monitor control on BSP is 0x%Lx.\n",
+ ilp_smm_mon_ctl);
+
+ /* verify ILP's MSEG == TXT.MSEG.BASE */
+ printk(TBOOT_INFO"verifying ILP is opt-out "
+ "or has the same MSEG header with TXT.MSEG.BASE\n\t");
+ if ( !verify_mseg(ilp_smm_mon_ctl) ) {
+ printk(TBOOT_ERR" : failed.\n");
+ return false;
+ }
+ printk(TBOOT_INFO" : succeeded.\n");
+ }
+ else {
+ printk(TBOOT_DETA"MSR for SMM monitor control on cpu %u is 0x%Lx\n",
+ cpuid, smm_mon_ctl);
+
+ /* verify ILP's SMM MSR == RLP's SMM MSR */
+ printk(TBOOT_INFO"verifying ILP's MSR_IA32_SMM_MONITOR_CTL with cpu %u\n\t",
+ cpuid);
+ if ( smm_mon_ctl != ilp_smm_mon_ctl ) {
+ printk(TBOOT_ERR" : failed.\n");
+ return false;
+ }
+ printk(TBOOT_INFO" : succeeded.\n");
+
+ /* since the RLP's MSR is the same. No need to verify MSEG header */
+ }
+
+ return true;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/vga.c b/tboot/vga.c
new file mode 100644
index 0000000..8ddc2f5
--- /dev/null
+++ b/tboot/vga.c
@@ -0,0 +1,140 @@
+/*
+ * vga.c: fns for outputting strings to VGA display
+ *
+ * Copyright (c) 2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <string.h>
+#include <misc.h>
+#include <io.h>
+#include <vga.h>
+
+static uint16_t * const screen = (uint16_t * const)VGA_BASE;
+static __data uint8_t cursor_x, cursor_y;
+static __data unsigned int num_lines;
+uint8_t g_vga_delay = 0; /* default to no delay */
+
+static inline void reset_screen(void)
+{
+ memset(screen, 0, SCREEN_BUFFER);
+ cursor_x = 0;
+ cursor_y = 0;
+ num_lines = 0;
+
+ outb(CTL_ADDR_REG, START_ADD_HIGH_REG);
+ outb(CTL_DATA_REG, 0x00);
+ outb(CTL_ADDR_REG, START_ADD_LOW_REG);
+ outb(CTL_DATA_REG, 0x00);
+}
+
+static void scroll_screen(void)
+{
+ for ( long long y = 1; y < MAX_LINES; y++ ) {
+ for ( long long x = 0; x < MAX_COLS; x++ )
+ writew(VGA_ADDR(x, y-1), readw(VGA_ADDR(x, y)));
+ }
+ /* clear last line */
+ for ( long long x = 0; x < MAX_COLS; x++ )
+ writew(VGA_ADDR(x, MAX_LINES-1), 0x720);
+}
+
+static void __putc(uint8_t x, uint8_t y, int c)
+{
+ screen[(y * MAX_COLS) + x] = (COLOR << 8) | c;
+}
+
+static void vga_putc(int c)
+{
+ bool new_row = false;
+
+ switch ( c ) {
+ case '\n':
+ cursor_y++;
+ cursor_x = 0;
+ new_row = true;
+ break;
+ case '\r':
+ cursor_x = 0;
+ break;
+ case '\t':
+ cursor_x += 4;
+ break;
+ default:
+ __putc(cursor_x, cursor_y, c);
+ cursor_x++;
+ break;
+ }
+
+ if ( cursor_x >= MAX_COLS ) {
+ cursor_x %= MAX_COLS;
+ cursor_y++;
+ new_row = true;
+ }
+
+ if ( new_row ) {
+ num_lines++;
+ if ( cursor_y >= MAX_LINES ) {
+ scroll_screen();
+ cursor_y--;
+ }
+
+ /* (optionally) pause after every screenful */
+ if ( (num_lines % (MAX_LINES - 1)) == 0 && g_vga_delay > 0 )
+ delay(g_vga_delay * 1000);
+ }
+}
+
+void vga_init(void)
+{
+ reset_screen();
+}
+
+void vga_puts(const char *s, unsigned int cnt)
+{
+ while ( *s && cnt-- ) {
+ vga_putc(*s);
+ s++;
+ }
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/vmac.c b/tboot/vmac.c
new file mode 100644
index 0000000..be234ed
--- /dev/null
+++ b/tboot/vmac.c
@@ -0,0 +1,1228 @@
+/* --------------------------------------------------------------------------
+ * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai.
+ * This implementation is herby placed in the public domain.
+ * The authors offers no warranty. Use at your own risk.
+ * Please send bug reports to the authors.
+ * Last modified: 17 APR 08, 1700 PDT
+ * ----------------------------------------------------------------------- */
+/*
+ * Portions copyright (c) 2010, Intel Corporation
+ */
+
+//#include "vmac.h"
+//#include <string.h>
+//#include <stdio.h>
+/* start for tboot */
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <vmac.h>
+/*#define UINT64_C(x) x##ULL*/
+/* end for tboot */
+
+/* Enable code tuned for 64-bit registers; otherwise tuned for 32-bit */
+#ifndef VMAC_ARCH_64
+#define VMAC_ARCH_64 (__x86_64__ || __ppc64__ || _M_X64)
+#endif
+
+/* Enable code tuned for Intel SSE2 instruction set */
+#if ((__SSE2__ || (_M_IX86_FP >= 2)) && ( ! VMAC_ARCH_64))
+#define VMAC_USE_SSE2 1
+#include <emmintrin.h>
+#endif
+
+/* Native word reads. Update (or define via compiler) if incorrect */
+#ifndef VMAC_ARCH_BIG_ENDIAN /* Assume big-endian unless on the list */
+#define VMAC_ARCH_BIG_ENDIAN \
+ (!(__x86_64__ || __i386__ || _M_IX86 || \
+ _M_X64 || __ARMEL__ || __MIPSEL__))
+#endif
+
+/* ----------------------------------------------------------------------- */
+/* Constants and masks */
+
+const uint64_t p64 = UINT64_C(0xfffffffffffffeff); /* 2^64 - 257 prime */
+const uint64_t m62 = UINT64_C(0x3fffffffffffffff); /* 62-bit mask */
+const uint64_t m63 = UINT64_C(0x7fffffffffffffff); /* 63-bit mask */
+const uint64_t m64 = UINT64_C(0xffffffffffffffff); /* 64-bit mask */
+const uint64_t mpoly = UINT64_C(0x1fffffff1fffffff); /* Poly key mask */
+
+/* ----------------------------------------------------------------------- *
+ * The following routines are used in this implementation. They are
+ * written via macros to simulate zero-overhead call-by-reference.
+ * All have default implemantations for when they are not defined in an
+ * architecture-specific manner.
+ *
+ * MUL64: 64x64->128-bit multiplication
+ * PMUL64: assumes top bits cleared on inputs
+ * ADD128: 128x128->128-bit addition
+ * GET_REVERSED_64: load and byte-reverse 64-bit word
+ * ----------------------------------------------------------------------- */
+
+/* ----------------------------------------------------------------------- */
+#if (__GNUC__ && (__x86_64__ || __amd64__))
+/* ----------------------------------------------------------------------- */
+
+#define ADD128(rh,rl,ih,il) \
+ asm ("addq %3, %1 \n\t" \
+ "adcq %2, %0" \
+ : "+r"(rh),"+r"(rl) \
+ : "r"(ih),"r"(il) : "cc");
+
+#define MUL64(rh,rl,i1,i2) \
+ asm ("mulq %3" : "=a"(rl), "=d"(rh) : "a"(i1), "r"(i2) : "cc")
+
+#define PMUL64 MUL64
+
+#define GET_REVERSED_64(p) \
+ ({uint64_t x; \
+ asm ("bswapq %0" : "=r" (x) : "0"(*(uint64_t *)(p))); x;})
+
+/* ----------------------------------------------------------------------- */
+#elif (__GNUC__ && __i386__)
+/* ----------------------------------------------------------------------- */
+
+#define GET_REVERSED_64(p) \
+ ({ uint64_t x; \
+ uint32_t *tp = (uint32_t *)(p); \
+ asm ("bswap %%edx\n\t" \
+ "bswap %%eax" \
+ : "=A"(x) \
+ : "a"(tp[1]), "d"(tp[0])); \
+ x; })
+
+/* ----------------------------------------------------------------------- */
+#elif (__GNUC__ && __ppc64__)
+/* ----------------------------------------------------------------------- */
+
+#define ADD128(rh,rl,ih,il) \
+ asm volatile ( "addc %1, %1, %3 \n\t" \
+ "adde %0, %0, %2" \
+ : "+r"(rh),"+r"(rl) \
+ : "r"(ih),"r"(il));
+
+#define MUL64(rh,rl,i1,i2) \
+{ uint64_t _i1 = (i1), _i2 = (i2); \
+ rl = _i1 * _i2; \
+ asm volatile ("mulhdu %0, %1, %2" : "=r" (rh) : "r" (_i1), "r" (_i2));\
+}
+
+#define PMUL64 MUL64
+
+#define GET_REVERSED_64(p) \
+ ({ uint32_t hi, lo, *_p = (uint32_t *)(p); \
+ asm volatile ("lwbrx %0, %1, %2" : "=r"(lo) : "b%"(0), "r"(_p) ); \
+ asm volatile ("lwbrx %0, %1, %2" : "=r"(hi) : "b%"(4), "r"(_p) ); \
+ ((uint64_t)hi << 32) | (uint64_t)lo; } )
+
+/* ----------------------------------------------------------------------- */
+#elif (__GNUC__ && (__ppc__ || __PPC__))
+/* ----------------------------------------------------------------------- */
+
+#define GET_REVERSED_64(p) \
+ ({ uint32_t hi, lo, *_p = (uint32_t *)(p); \
+ asm volatile ("lwbrx %0, %1, %2" : "=r"(lo) : "b%"(0), "r"(_p) ); \
+ asm volatile ("lwbrx %0, %1, %2" : "=r"(hi) : "b%"(4), "r"(_p) ); \
+ ((uint64_t)hi << 32) | (uint64_t)lo; } )
+
+/* ----------------------------------------------------------------------- */
+#elif (__GNUC__ && (__ARMEL__ || __ARM__))
+/* ----------------------------------------------------------------------- */
+
+#define bswap32(v) \
+({ uint32_t tmp,out; \
+ asm volatile( \
+ "eor %1, %2, %2, ror #16\n" \
+ "bic %1, %1, #0x00ff0000\n" \
+ "mov %0, %2, ror #8\n" \
+ "eor %0, %0, %1, lsr #8" \
+ : "=r" (out), "=&r" (tmp) \
+ : "r" (v)); \
+ out;})
+
+/* ----------------------------------------------------------------------- */
+#elif _MSC_VER
+/* ----------------------------------------------------------------------- */
+
+#include <intrin.h>
+
+#if (_M_IA64 || _M_X64) && \
+ (!defined(__INTEL_COMPILER) || __INTEL_COMPILER >= 1000)
+#define MUL64(rh,rl,i1,i2) (rl) = _umul128(i1,i2,&(rh));
+#pragma intrinsic(_umul128)
+#define PMUL64 MUL64
+#endif
+
+/* MSVC uses add, adc in this version */
+#define ADD128(rh,rl,ih,il) \
+ { uint64_t _il = (il); \
+ (rl) += (_il); \
+ (rh) += (ih) + ((rl) < (_il)); \
+ }
+
+#if _MSC_VER >= 1300
+#define GET_REVERSED_64(p) _byteswap_uint64(*(uint64_t *)(p))
+#pragma intrinsic(_byteswap_uint64)
+#endif
+
+#if _MSC_VER >= 1400 && \
+ (!defined(__INTEL_COMPILER) || __INTEL_COMPILER >= 1000)
+#define MUL32(i1,i2) (__emulu((uint32_t)(i1),(uint32_t)(i2)))
+#pragma intrinsic(__emulu)
+#endif
+
+/* ----------------------------------------------------------------------- */
+#endif
+/* ----------------------------------------------------------------------- */
+
+#if __GNUC__
+/*#define ALIGN(n) __attribute__ ((aligned(n)))*/
+#define NOINLINE __attribute__ ((noinline))
+#define FASTCALL
+#elif _MSC_VER
+#define ALIGN(n) __declspec(align(n))
+#define NOINLINE __declspec(noinline)
+#define FASTCALL __fastcall
+#else
+#define ALIGN(n)
+#define NOINLINE
+#define FASTCALL
+#endif
+
+/* ----------------------------------------------------------------------- */
+/* Default implementations, if not defined above */
+/* ----------------------------------------------------------------------- */
+
+#ifndef ADD128
+#define ADD128(rh,rl,ih,il) \
+ { uint64_t _il = (il); \
+ (rl) += (_il); \
+ if ((rl) < (_il)) (rh)++; \
+ (rh) += (ih); \
+ }
+#endif
+
+#ifndef MUL32
+#define MUL32(i1,i2) ((uint64_t)(uint32_t)(i1)*(uint32_t)(i2))
+#endif
+
+#ifndef PMUL64 /* rh may not be same as i1 or i2 */
+#define PMUL64(rh,rl,i1,i2) /* Assumes m doesn't overflow */ \
+ { uint64_t _i1 = (i1), _i2 = (i2); \
+ uint64_t m = MUL32(_i1,_i2>>32) + MUL32(_i1>>32,_i2); \
+ rh = MUL32(_i1>>32,_i2>>32); \
+ rl = MUL32(_i1,_i2); \
+ ADD128(rh,rl,(m >> 32),(m << 32)); \
+ }
+#endif
+
+#ifndef MUL64
+#define MUL64(rh,rl,i1,i2) \
+ { uint64_t _i1 = (i1), _i2 = (i2); \
+ uint64_t m1= MUL32(_i1,_i2>>32); \
+ uint64_t m2= MUL32(_i1>>32,_i2); \
+ rh = MUL32(_i1>>32,_i2>>32); \
+ rl = MUL32(_i1,_i2); \
+ ADD128(rh,rl,(m1 >> 32),(m1 << 32)); \
+ ADD128(rh,rl,(m2 >> 32),(m2 << 32)); \
+ }
+#endif
+
+#ifndef GET_REVERSED_64
+#ifndef bswap64
+#ifndef bswap32
+#define bswap32(x) \
+ ({ uint32_t bsx = (x); \
+ ((((bsx) & 0xff000000u) >> 24) | (((bsx) & 0x00ff0000u) >> 8) | \
+ (((bsx) & 0x0000ff00u) << 8) | (((bsx) & 0x000000ffu) << 24)); })
+#endif
+#define bswap64(x) \
+ ({ union { uint64_t ll; uint32_t l[2]; } w, r; \
+ w.ll = (x); \
+ r.l[0] = bswap32 (w.l[1]); \
+ r.l[1] = bswap32 (w.l[0]); \
+ r.ll; })
+#endif
+#define GET_REVERSED_64(p) bswap64(*(uint64_t *)(p))
+#endif
+
+/* ----------------------------------------------------------------------- */
+
+#if (VMAC_PREFER_BIG_ENDIAN)
+# define get64PE get64BE
+#else
+# define get64PE get64LE
+#endif
+
+#if (VMAC_ARCH_BIG_ENDIAN)
+# define get64BE(ptr) (*(uint64_t *)(ptr))
+# define get64LE(ptr) GET_REVERSED_64(ptr)
+#else /* assume little-endian */
+# define get64BE(ptr) GET_REVERSED_64(ptr)
+# define get64LE(ptr) (*(uint64_t *)(ptr))
+#endif
+
+
+/* --------------------------------------------------------------------- *
+ * For highest performance the L1 NH and L2 polynomial hashes should be
+ * carefully implemented to take advantage of one's target architechture.
+ * Here these two hash functions are defined multiple time; once for
+ * 64-bit architectures, once for 32-bit SSE2 architectures, and once
+ * for the rest (32-bit) architectures.
+ * For each, nh_16 *must* be defined (works on multiples of 16 bytes).
+ * Optionally, nh_vmac_nhbytes can be defined (for multiples of
+ * VMAC_NHBYTES), and nh_16_2 and nh_vmac_nhbytes_2 (versions that do two
+ * NH computations at once).
+ * --------------------------------------------------------------------- */
+
+/* ----------------------------------------------------------------------- */
+#if VMAC_ARCH_64
+/* ----------------------------------------------------------------------- */
+
+#define nh_16(mp, kp, nw, rh, rl) \
+{ int i; uint64_t th, tl; \
+ rh = rl = 0; \
+ for (i = 0; i < nw; i+= 2) { \
+ MUL64(th,tl,get64PE((mp)+i )+(kp)[i ],get64PE((mp)+i+1)+(kp)[i+1]);\
+ ADD128(rh,rl,th,tl); \
+ } \
+}
+#define nh_16_2(mp, kp, nw, rh, rl, rh1, rl1) \
+{ int i; uint64_t th, tl; \
+ rh1 = rl1 = rh = rl = 0; \
+ for (i = 0; i < nw; i+= 2) { \
+ MUL64(th,tl,get64PE((mp)+i )+(kp)[i ],get64PE((mp)+i+1)+(kp)[i+1]);\
+ ADD128(rh,rl,th,tl); \
+ MUL64(th,tl,get64PE((mp)+i )+(kp)[i+2],get64PE((mp)+i+1)+(kp)[i+3]);\
+ ADD128(rh1,rl1,th,tl); \
+ } \
+}
+
+#if (VMAC_NHBYTES >= 64) /* These versions do 64-bytes of message at a time */
+#define nh_vmac_nhbytes(mp, kp, nw, rh, rl) \
+{ int i; uint64_t th, tl; \
+ rh = rl = 0; \
+ for (i = 0; i < nw; i+= 8) { \
+ MUL64(th,tl,get64PE((mp)+i )+(kp)[i ],get64PE((mp)+i+1)+(kp)[i+1]);\
+ ADD128(rh,rl,th,tl); \
+ MUL64(th,tl,get64PE((mp)+i+2)+(kp)[i+2],get64PE((mp)+i+3)+(kp)[i+3]);\
+ ADD128(rh,rl,th,tl); \
+ MUL64(th,tl,get64PE((mp)+i+4)+(kp)[i+4],get64PE((mp)+i+5)+(kp)[i+5]);\
+ ADD128(rh,rl,th,tl); \
+ MUL64(th,tl,get64PE((mp)+i+6)+(kp)[i+6],get64PE((mp)+i+7)+(kp)[i+7]);\
+ ADD128(rh,rl,th,tl); \
+ } \
+}
+#define nh_vmac_nhbytes_2(mp, kp, nw, rh, rl, rh1, rl1) \
+{ int i; uint64_t th, tl; \
+ rh1 = rl1 = rh = rl = 0; \
+ for (i = 0; i < nw; i+= 8) { \
+ MUL64(th,tl,get64PE((mp)+i )+(kp)[i ],get64PE((mp)+i+1)+(kp)[i+1]);\
+ ADD128(rh,rl,th,tl); \
+ MUL64(th,tl,get64PE((mp)+i )+(kp)[i+2],get64PE((mp)+i+1)+(kp)[i+3]);\
+ ADD128(rh1,rl1,th,tl); \
+ MUL64(th,tl,get64PE((mp)+i+2)+(kp)[i+2],get64PE((mp)+i+3)+(kp)[i+3]);\
+ ADD128(rh,rl,th,tl); \
+ MUL64(th,tl,get64PE((mp)+i+2)+(kp)[i+4],get64PE((mp)+i+3)+(kp)[i+5]);\
+ ADD128(rh1,rl1,th,tl); \
+ MUL64(th,tl,get64PE((mp)+i+4)+(kp)[i+4],get64PE((mp)+i+5)+(kp)[i+5]);\
+ ADD128(rh,rl,th,tl); \
+ MUL64(th,tl,get64PE((mp)+i+4)+(kp)[i+6],get64PE((mp)+i+5)+(kp)[i+7]);\
+ ADD128(rh1,rl1,th,tl); \
+ MUL64(th,tl,get64PE((mp)+i+6)+(kp)[i+6],get64PE((mp)+i+7)+(kp)[i+7]);\
+ ADD128(rh,rl,th,tl); \
+ MUL64(th,tl,get64PE((mp)+i+6)+(kp)[i+8],get64PE((mp)+i+7)+(kp)[i+9]);\
+ ADD128(rh1,rl1,th,tl); \
+ } \
+}
+#endif
+
+#define poly_step(ah, al, kh, kl, mh, ml) \
+{ uint64_t t1h, t1l, t2h, t2l, t3h, t3l, z=0; \
+ /* compute ab*cd, put bd into result registers */ \
+ PMUL64(t3h,t3l,al,kh); \
+ PMUL64(t2h,t2l,ah,kl); \
+ PMUL64(t1h,t1l,ah,2*kh); \
+ PMUL64(ah,al,al,kl); \
+ /* add 2 * ac to result */ \
+ ADD128(ah,al,t1h,t1l); \
+ /* add together ad + bc */ \
+ ADD128(t2h,t2l,t3h,t3l); \
+ /* now (ah,al), (t2l,2*t2h) need summing */ \
+ /* first add the high registers, carrying into t2h */ \
+ ADD128(t2h,ah,z,t2l); \
+ /* double t2h and add top bit of ah */ \
+ t2h = 2 * t2h + (ah >> 63); \
+ ah &= m63; \
+ /* now add the low registers */ \
+ ADD128(ah,al,mh,ml); \
+ ADD128(ah,al,z,t2h); \
+}
+
+/* ----------------------------------------------------------------------- */
+#elif VMAC_USE_SSE2
+/* ----------------------------------------------------------------------- */
+
+// macros from Crypto++ for sharing inline assembly code between MSVC and GNU C
+#if defined(__GNUC__)
+ // define these in two steps to allow arguments to be expanded
+ #define GNU_AS2(x, y) #x ", " #y ";"
+ #define GNU_AS3(x, y, z) #x ", " #y ", " #z ";"
+ #define GNU_ASL(x) "\n" #x ":"
+ #define GNU_ASJ(x, y, z) #x " " #y #z ";"
+ #define AS2(x, y) GNU_AS2(x, y)
+ #define AS3(x, y, z) GNU_AS3(x, y, z)
+ #define ASS(x, y, a, b, c, d) #x ", " #y ", " #a "*64+" #b "*16+" #c "*4+" #d ";"
+ #define ASL(x) GNU_ASL(x)
+ #define ASJ(x, y, z) GNU_ASJ(x, y, z)
+#else
+ #define AS2(x, y) __asm {x, y}
+ #define AS3(x, y, z) __asm {x, y, z}
+ #define ASS(x, y, a, b, c, d) __asm {x, y, _MM_SHUFFLE(a, b, c, d)}
+ #define ASL(x) __asm {label##x:}
+ #define ASJ(x, y, z) __asm {x label##y}
+#endif
+
+static void NOINLINE nh_16_func(const uint64_t *mp, const uint64_t *kp, size_t nw, uint64_t *rh, uint64_t *rl)
+{
+ // This assembly version, using MMX registers, is just as fast as the
+ // intrinsics version (which uses XMM registers) on the Intel Core 2,
+ // but is much faster on the Pentium 4. In order to schedule multiplies
+ // as early as possible, the loop interleaves operations for the current
+ // block and the next block. To mask out high 32-bits, we use "movd"
+ // to move the lower 32-bits to the stack and then back. Surprisingly,
+ // this is faster than any other method.
+#ifdef __GNUC__
+ __asm__ __volatile__
+ (
+ ".intel_syntax noprefix;"
+#else
+ AS2( mov esi, mp)
+ AS2( mov edi, kp)
+ AS2( mov ecx, nw)
+ AS2( mov eax, rl)
+ AS2( mov edx, rh)
+#endif
+ AS2( sub esp, 12)
+ AS2( movq mm6, [esi])
+ AS2( paddq mm6, [edi])
+ AS2( movq mm5, [esi+8])
+ AS2( paddq mm5, [edi+8])
+ AS2( add esi, 16)
+ AS2( add edi, 16)
+ AS2( movq mm4, mm6)
+ ASS( pshufw mm2, mm6, 1, 0, 3, 2)
+ AS2( pmuludq mm6, mm5)
+ ASS( pshufw mm3, mm5, 1, 0, 3, 2)
+ AS2( pmuludq mm5, mm2)
+ AS2( pmuludq mm2, mm3)
+ AS2( pmuludq mm3, mm4)
+ AS2( pxor mm7, mm7)
+ AS2( movd [esp], mm6)
+ AS2( psrlq mm6, 32)
+ AS2( movd [esp+4], mm5)
+ AS2( psrlq mm5, 32)
+ AS2( sub ecx, 2)
+ ASJ( jz, 1, f)
+ ASL(0)
+ AS2( movq mm0, [esi])
+ AS2( paddq mm0, [edi])
+ AS2( movq mm1, [esi+8])
+ AS2( paddq mm1, [edi+8])
+ AS2( add esi, 16)
+ AS2( add edi, 16)
+ AS2( movq mm4, mm0)
+ AS2( paddq mm5, mm2)
+ ASS( pshufw mm2, mm0, 1, 0, 3, 2)
+ AS2( pmuludq mm0, mm1)
+ AS2( movd [esp+8], mm3)
+ AS2( psrlq mm3, 32)
+ AS2( paddq mm5, mm3)
+ ASS( pshufw mm3, mm1, 1, 0, 3, 2)
+ AS2( pmuludq mm1, mm2)
+ AS2( pmuludq mm2, mm3)
+ AS2( pmuludq mm3, mm4)
+ AS2( movd mm4, [esp])
+ AS2( paddq mm7, mm4)
+ AS2( movd mm4, [esp+4])
+ AS2( paddq mm6, mm4)
+ AS2( movd mm4, [esp+8])
+ AS2( paddq mm6, mm4)
+ AS2( movd [esp], mm0)
+ AS2( psrlq mm0, 32)
+ AS2( paddq mm6, mm0)
+ AS2( movd [esp+4], mm1)
+ AS2( psrlq mm1, 32)
+ AS2( paddq mm5, mm1)
+ AS2( sub ecx, 2)
+ ASJ( jnz, 0, b)
+ ASL(1)
+ AS2( paddq mm5, mm2)
+ AS2( movd [esp+8], mm3)
+ AS2( psrlq mm3, 32)
+ AS2( paddq mm5, mm3)
+ AS2( movd mm4, [esp])
+ AS2( paddq mm7, mm4)
+ AS2( movd mm4, [esp+4])
+ AS2( paddq mm6, mm4)
+ AS2( movd mm4, [esp+8])
+ AS2( paddq mm6, mm4)
+
+ ASS( pshufw mm0, mm7, 3, 2, 1, 0)
+ AS2( psrlq mm7, 32)
+ AS2( paddq mm6, mm7)
+ AS2( punpckldq mm0, mm6)
+ AS2( psrlq mm6, 32)
+ AS2( paddq mm5, mm6)
+ AS2( movq [eax], mm0)
+ AS2( movq [edx], mm5)
+ AS2( add esp, 12)
+#ifdef __GNUC__
+ ".att_syntax prefix;"
+ :
+ : "S" (mp), "D" (kp), "c" (nw), "a" (rl), "d" (rh)
+ : "memory", "cc"
+ );
+#endif
+}
+#define nh_16(mp, kp, nw, rh, rl) nh_16_func(mp, kp, nw, &(rh), &(rl));
+
+static void poly_step_func(uint64_t *ahi, uint64_t *alo, const uint64_t *kh,
+ const uint64_t *kl, const uint64_t *mh, const uint64_t *ml)
+{
+ // This code tries to schedule the multiplies as early as possible to overcome
+ // the long latencies on the Pentium 4. It also minimizes "movq" instructions
+ // which are very expensive on the P4.
+
+#define a0 [eax+0]
+#define a1 [eax+4]
+#define a2 [ebx+0]
+#define a3 [ebx+4]
+#define k0 [ecx+0]
+#define k1 [ecx+4]
+#define k2 [edx+0]
+#define k3 [edx+4]
+
+#ifdef __GNUC__
+ uint32_t temp;
+ __asm__ __volatile__
+ (
+ "mov %%ebx, %0;"
+ "mov %1, %%ebx;"
+ ".intel_syntax noprefix;"
+#else
+ AS2( mov ebx, ahi)
+ AS2( mov edx, kh)
+ AS2( mov eax, alo)
+ AS2( mov ecx, kl)
+ AS2( mov esi, mh)
+ AS2( mov edi, ml)
+#endif
+
+ AS2( movd mm0, a3)
+ AS2( movq mm4, mm0)
+ AS2( pmuludq mm0, k3) // a3*k3
+ AS2( movd mm1, a0)
+ AS2( pmuludq mm1, k2) // a0*k2
+ AS2( movd mm2, a1)
+ AS2( movd mm6, k1)
+ AS2( pmuludq mm2, mm6) // a1*k1
+ AS2( movd mm3, a2)
+ AS2( movq mm5, mm3)
+ AS2( movd mm7, k0)
+ AS2( pmuludq mm3, mm7) // a2*k0
+ AS2( pmuludq mm4, mm7) // a3*k0
+ AS2( pmuludq mm5, mm6) // a2*k1
+ AS2( psllq mm0, 1)
+ AS2( paddq mm0, [esi])
+ AS2( paddq mm0, mm1)
+ AS2( movd mm1, a1)
+ AS2( paddq mm4, mm5)
+ AS2( movq mm5, mm1)
+ AS2( pmuludq mm1, k2) // a1*k2
+ AS2( paddq mm0, mm2)
+ AS2( movd mm2, a0)
+ AS2( paddq mm0, mm3)
+ AS2( movq mm3, mm2)
+ AS2( pmuludq mm2, k3) // a0*k3
+ AS2( pmuludq mm3, mm7) // a0*k0
+ AS2( movd esi, mm0)
+ AS2( psrlq mm0, 32)
+ AS2( pmuludq mm7, mm5) // a1*k0
+ AS2( pmuludq mm5, k3) // a1*k3
+ AS2( paddq mm0, mm1)
+ AS2( movd mm1, a2)
+ AS2( pmuludq mm1, k2) // a2*k2
+ AS2( paddq mm0, mm2)
+ AS2( paddq mm0, mm4)
+ AS2( movq mm4, mm0)
+ AS2( movd mm2, a3)
+ AS2( pmuludq mm2, mm6) // a3*k1
+ AS2( pmuludq mm6, a0) // a0*k1
+ AS2( psrlq mm0, 31)
+ AS2( paddq mm0, mm3)
+ AS2( movd mm3, [edi])
+ AS2( paddq mm0, mm3)
+ AS2( movd mm3, a2)
+ AS2( pmuludq mm3, k3) // a2*k3
+ AS2( paddq mm5, mm1)
+ AS2( movd mm1, a3)
+ AS2( pmuludq mm1, k2) // a3*k2
+ AS2( paddq mm5, mm2)
+ AS2( movd mm2, [edi+4])
+ AS2( psllq mm5, 1)
+ AS2( paddq mm0, mm5)
+ AS2( movq mm5, mm0)
+ AS2( psllq mm4, 33)
+ AS2( psrlq mm0, 32)
+ AS2( paddq mm6, mm7)
+ AS2( movd mm7, esi)
+ AS2( paddq mm0, mm6)
+ AS2( paddq mm0, mm2)
+ AS2( paddq mm3, mm1)
+ AS2( psllq mm3, 1)
+ AS2( paddq mm0, mm3)
+ AS2( psrlq mm4, 1)
+ AS2( punpckldq mm5, mm0)
+ AS2( psrlq mm0, 32)
+ AS2( por mm4, mm7)
+ AS2( paddq mm0, mm4)
+ AS2( movq a0, mm5)
+ AS2( movq a2, mm0)
+#ifdef __GNUC__
+ ".att_syntax prefix;"
+ "mov %0, %%ebx;"
+ : "=m" (temp)
+ : "m" (ahi), "D" (ml), "d" (kh), "a" (alo), "S" (mh), "c" (kl)
+ : "memory", "cc"
+ );
+#endif
+
+
+#undef a0
+#undef a1
+#undef a2
+#undef a3
+#undef k0
+#undef k1
+#undef k2
+#undef k3
+}
+
+#define poly_step(ah, al, kh, kl, mh, ml) \
+ poly_step_func(&(ah), &(al), &(kh), &(kl), &(mh), &(ml))
+
+/* ----------------------------------------------------------------------- */
+#else /* not VMAC_ARCH_64 and not SSE2 */
+/* ----------------------------------------------------------------------- */
+
+#ifndef nh_16
+#define nh_16(mp, kp, nw, rh, rl) \
+{ uint64_t t1,t2,m1,m2,t; \
+ int i; \
+ rh = rl = t = 0; \
+ for (i = 0; i < nw; i+=2) { \
+ t1 = get64PE(mp+i) + kp[i]; \
+ t2 = get64PE(mp+i+1) + kp[i+1]; \
+ m2 = MUL32(t1 >> 32, t2); \
+ m1 = MUL32(t1, t2 >> 32); \
+ ADD128(rh,rl,MUL32(t1 >> 32,t2 >> 32),MUL32(t1,t2)); \
+ rh += (uint64_t)(uint32_t)(m1 >> 32) + (uint32_t)(m2 >> 32); \
+ t += (uint64_t)(uint32_t)m1 + (uint32_t)m2; \
+ } \
+ ADD128(rh,rl,(t >> 32),(t << 32)); \
+}
+#endif
+
+static void poly_step_func(uint64_t *ahi, uint64_t *alo, const uint64_t *kh,
+ const uint64_t *kl, const uint64_t *mh, const uint64_t *ml)
+{
+
+#if VMAC_ARCH_BIG_ENDIAN
+#define INDEX_HIGH 0
+#define INDEX_LOW 1
+#else
+#define INDEX_HIGH 1
+#define INDEX_LOW 0
+#endif
+
+#define a0 *(((uint32_t*)alo)+INDEX_LOW)
+#define a1 *(((uint32_t*)alo)+INDEX_HIGH)
+#define a2 *(((uint32_t*)ahi)+INDEX_LOW)
+#define a3 *(((uint32_t*)ahi)+INDEX_HIGH)
+#define k0 *(((uint32_t*)kl)+INDEX_LOW)
+#define k1 *(((uint32_t*)kl)+INDEX_HIGH)
+#define k2 *(((uint32_t*)kh)+INDEX_LOW)
+#define k3 *(((uint32_t*)kh)+INDEX_HIGH)
+
+ uint64_t p, q, t;
+ uint32_t t2;
+
+ p = MUL32(a3, k3);
+ p += p;
+ p += *(uint64_t *)mh;
+ p += MUL32(a0, k2);
+ p += MUL32(a1, k1);
+ p += MUL32(a2, k0);
+ t = (uint32_t)(p);
+ p >>= 32;
+ p += MUL32(a0, k3);
+ p += MUL32(a1, k2);
+ p += MUL32(a2, k1);
+ p += MUL32(a3, k0);
+ t |= ((uint64_t)((uint32_t)p & 0x7fffffff)) << 32;
+ p >>= 31;
+ p += (uint64_t)(((uint32_t*)ml)[INDEX_LOW]);
+ p += MUL32(a0, k0);
+ q = MUL32(a1, k3);
+ q += MUL32(a2, k2);
+ q += MUL32(a3, k1);
+ q += q;
+ p += q;
+ t2 = (uint32_t)(p);
+ p >>= 32;
+ p += (uint64_t)(((uint32_t*)ml)[INDEX_HIGH]);
+ p += MUL32(a0, k1);
+ p += MUL32(a1, k0);
+ q = MUL32(a2, k3);
+ q += MUL32(a3, k2);
+ q += q;
+ p += q;
+ *(uint64_t *)(alo) = (p << 32) | t2;
+ p >>= 32;
+ *(uint64_t *)(ahi) = p + t;
+
+#undef a0
+#undef a1
+#undef a2
+#undef a3
+#undef k0
+#undef k1
+#undef k2
+#undef k3
+}
+
+#define poly_step(ah, al, kh, kl, mh, ml) \
+ poly_step_func(&(ah), &(al), &(kh), &(kl), &(mh), &(ml))
+
+/* ----------------------------------------------------------------------- */
+#endif /* end of specialized NH and poly definitions */
+/* ----------------------------------------------------------------------- */
+
+/* At least nh_16 is defined. Defined others as needed here */
+#ifndef nh_16_2
+#define nh_16_2(mp, kp, nw, rh, rl, rh2, rl2) \
+ nh_16(mp, kp, nw, rh, rl); \
+ nh_16(mp, ((kp)+2), nw, rh2, rl2);
+#endif
+#ifndef nh_vmac_nhbytes
+#define nh_vmac_nhbytes(mp, kp, nw, rh, rl) \
+ nh_16(mp, kp, nw, rh, rl)
+#endif
+#ifndef nh_vmac_nhbytes_2
+#define nh_vmac_nhbytes_2(mp, kp, nw, rh, rl, rh2, rl2) \
+ nh_vmac_nhbytes(mp, kp, nw, rh, rl); \
+ nh_vmac_nhbytes(mp, ((kp)+2), nw, rh2, rl2);
+#endif
+
+/* ----------------------------------------------------------------------- */
+
+void vhash_abort(vmac_ctx_t *ctx)
+{
+ ctx->polytmp[0] = ctx->polykey[0] ;
+ ctx->polytmp[1] = ctx->polykey[1] ;
+ #if (VMAC_TAG_LEN == 128)
+ ctx->polytmp[2] = ctx->polykey[2] ;
+ ctx->polytmp[3] = ctx->polykey[3] ;
+ #endif
+ ctx->first_block_processed = 0;
+}
+
+/* ----------------------------------------------------------------------- */
+static uint64_t l3hash(uint64_t p1, uint64_t p2,
+ uint64_t k1, uint64_t k2, uint64_t len)
+{
+ uint64_t rh, rl, t, z=0;
+
+ /* fully reduce (p1,p2)+(len,0) mod p127 */
+ t = p1 >> 63;
+ p1 &= m63;
+ ADD128(p1, p2, len, t);
+ /* At this point, (p1,p2) is at most 2^127+(len<<64) */
+ t = (p1 > m63) + ((p1 == m63) && (p2 == m64));
+ ADD128(p1, p2, z, t);
+ p1 &= m63;
+
+ /* compute (p1,p2)/(2^64-2^32) and (p1,p2)%(2^64-2^32) */
+ t = p1 + (p2 >> 32);
+ t += (t >> 32);
+ t += (uint32_t)t > 0xfffffffeu;
+ p1 += (t >> 32);
+ p2 += (p1 << 32);
+
+ /* compute (p1+k1)%p64 and (p2+k2)%p64 */
+ p1 += k1;
+ p1 += (0 - (p1 < k1)) & 257;
+ p2 += k2;
+ p2 += (0 - (p2 < k2)) & 257;
+
+ /* compute (p1+k1)*(p2+k2)%p64 */
+ MUL64(rh, rl, p1, p2);
+ t = rh >> 56;
+ ADD128(t, rl, z, rh);
+ rh <<= 8;
+ ADD128(t, rl, z, rh);
+ t += t << 8;
+ rl += t;
+ rl += (0 - (rl < t)) & 257;
+ rl += (0 - (rl > p64-1)) & 257;
+ return rl;
+}
+
+/* ----------------------------------------------------------------------- */
+
+void vhash_update(unsigned char *m,
+ unsigned int mbytes, /* Pos multiple of VMAC_NHBYTES */
+ vmac_ctx_t *ctx)
+{
+ uint64_t rh, rl, *mptr;
+ const uint64_t *kptr = (uint64_t *)ctx->nhkey;
+ int i;
+ uint64_t ch, cl;
+ uint64_t pkh = ctx->polykey[0];
+ uint64_t pkl = ctx->polykey[1];
+ #if (VMAC_TAG_LEN == 128)
+ uint64_t ch2, cl2, rh2, rl2;
+ uint64_t pkh2 = ctx->polykey[2];
+ uint64_t pkl2 = ctx->polykey[3];
+ #endif
+
+ mptr = (uint64_t *)m;
+ i = mbytes / VMAC_NHBYTES; /* Must be non-zero */
+
+ ch = ctx->polytmp[0];
+ cl = ctx->polytmp[1];
+ #if (VMAC_TAG_LEN == 128)
+ ch2 = ctx->polytmp[2];
+ cl2 = ctx->polytmp[3];
+ #endif
+
+ if ( ! ctx->first_block_processed) {
+ ctx->first_block_processed = 1;
+ #if (VMAC_TAG_LEN == 64)
+ nh_vmac_nhbytes(mptr,kptr,VMAC_NHBYTES/8,rh,rl);
+ #else
+ nh_vmac_nhbytes_2(mptr,kptr,VMAC_NHBYTES/8,rh,rl,rh2,rl2);
+ rh2 &= m62;
+ ADD128(ch2,cl2,rh2,rl2);
+ #endif
+ rh &= m62;
+ ADD128(ch,cl,rh,rl);
+ mptr += (VMAC_NHBYTES/sizeof(uint64_t));
+ i--;
+ }
+
+ while (i--) {
+ #if (VMAC_TAG_LEN == 64)
+ nh_vmac_nhbytes(mptr,kptr,VMAC_NHBYTES/8,rh,rl);
+ #else
+ nh_vmac_nhbytes_2(mptr,kptr,VMAC_NHBYTES/8,rh,rl,rh2,rl2);
+ rh2 &= m62;
+ poly_step(ch2,cl2,pkh2,pkl2,rh2,rl2);
+ #endif
+ rh &= m62;
+ poly_step(ch,cl,pkh,pkl,rh,rl);
+ mptr += (VMAC_NHBYTES/sizeof(uint64_t));
+ }
+
+ ctx->polytmp[0] = ch;
+ ctx->polytmp[1] = cl;
+ #if (VMAC_TAG_LEN == 128)
+ ctx->polytmp[2] = ch2;
+ ctx->polytmp[3] = cl2;
+ #endif
+ #if VMAC_USE_SSE2
+ _mm_empty(); /* SSE2 version of poly_step uses mmx instructions */
+ #endif
+}
+
+/* ----------------------------------------------------------------------- */
+
+uint64_t xvhash(unsigned char m[],
+ unsigned int mbytes,
+ uint64_t *tagl,
+ vmac_ctx_t *ctx)
+{
+ uint64_t ch, cl, rh, rl, *mptr;
+ #if (VMAC_TAG_LEN == 128)
+ uint64_t ch2, cl2, rh2, rl2;
+ #endif
+ const uint64_t *kptr = (uint64_t *)ctx->nhkey;
+ int i, remaining;
+ (void)tagl;
+
+ remaining = mbytes % VMAC_NHBYTES;
+ i = mbytes-remaining;
+ mptr = (uint64_t *)(m+i);
+ if (i) vhash_update(m,i,ctx);
+
+ ch = ctx->polytmp[0];
+ cl = ctx->polytmp[1];
+ #if (VMAC_TAG_LEN == 128)
+ ch2 = ctx->polytmp[2];
+ cl2 = ctx->polytmp[3];
+ #endif
+
+ if (remaining) {
+ #if (VMAC_TAG_LEN == 128)
+ nh_16_2(mptr,kptr,2*((remaining+15)/16),rh,rl,rh2,rl2);
+ rh2 &= m62;
+ #else
+ nh_16(mptr,kptr,2*((remaining+15)/16),rh,rl);
+ #endif
+ rh &= m62;
+ if (i) {
+ poly_step(ch,cl,ctx->polykey[0],ctx->polykey[1],rh,rl);
+ #if (VMAC_TAG_LEN == 128)
+ poly_step(ch2,cl2,ctx->polykey[2],ctx->polykey[3],rh2,rl2);
+ #endif
+ } else {
+ ADD128(ch,cl,rh,rl);
+ #if (VMAC_TAG_LEN == 128)
+ ADD128(ch2,cl2,rh2,rl2);
+ #endif
+ }
+ }
+
+ #if VMAC_USE_SSE2
+ _mm_empty(); /* SSE2 version of poly_step uses mmx instructions */
+ #endif
+ vhash_abort(ctx);
+ remaining *= 8;
+#if (VMAC_TAG_LEN == 128)
+ *tagl = l3hash(ch2, cl2, ctx->l3key[2], ctx->l3key[3],remaining);
+#endif
+ return l3hash(ch, cl, ctx->l3key[0], ctx->l3key[1],remaining);
+}
+
+uint64_t vhash(unsigned char m[],
+ unsigned int mbytes,
+ uint64_t *tagl,
+ vmac_ctx_t *ctx)
+{
+ uint64_t rh, rl, *mptr;
+ const uint64_t *kptr = (uint64_t *)ctx->nhkey;
+ int i, remaining;
+ uint64_t ch, cl;
+ uint64_t pkh = ctx->polykey[0];
+ uint64_t pkl = ctx->polykey[1];
+ #if (VMAC_TAG_LEN == 128)
+ uint64_t ch2, cl2, rh2, rl2;
+ uint64_t pkh2 = ctx->polykey[2];
+ uint64_t pkl2 = ctx->polykey[3];
+ #endif
+ (void)tagl;
+
+ mptr = (uint64_t *)m;
+ i = mbytes / VMAC_NHBYTES;
+ remaining = mbytes % VMAC_NHBYTES;
+
+ if (ctx->first_block_processed)
+ {
+ ch = ctx->polytmp[0];
+ cl = ctx->polytmp[1];
+ #if (VMAC_TAG_LEN == 128)
+ ch2 = ctx->polytmp[2];
+ cl2 = ctx->polytmp[3];
+ #endif
+ }
+ else if (i)
+ {
+ #if (VMAC_TAG_LEN == 64)
+ nh_vmac_nhbytes(mptr,kptr,VMAC_NHBYTES/8,ch,cl);
+ #else
+ nh_vmac_nhbytes_2(mptr,kptr,VMAC_NHBYTES/8,ch,cl,ch2,cl2);
+ ch2 &= m62;
+ ADD128(ch2,cl2,pkh2,pkl2);
+ #endif
+ ch &= m62;
+ ADD128(ch,cl,pkh,pkl);
+ mptr += (VMAC_NHBYTES/sizeof(uint64_t));
+ i--;
+ }
+ else if (remaining)
+ {
+ #if (VMAC_TAG_LEN == 64)
+ nh_16(mptr,kptr,2*((remaining+15)/16),ch,cl);
+ #else
+ nh_16_2(mptr,kptr,2*((remaining+15)/16),ch,cl,ch2,cl2);
+ ch2 &= m62;
+ ADD128(ch2,cl2,pkh2,pkl2);
+ #endif
+ ch &= m62;
+ ADD128(ch,cl,pkh,pkl);
+ mptr += (VMAC_NHBYTES/sizeof(uint64_t));
+ goto do_l3;
+ }
+ else /* Empty String */
+ {
+ ch = pkh; cl = pkl;
+ #if (VMAC_TAG_LEN == 128)
+ ch2 = pkh2; cl2 = pkl2;
+ #endif
+ goto do_l3;
+ }
+
+ while (i--) {
+ #if (VMAC_TAG_LEN == 64)
+ nh_vmac_nhbytes(mptr,kptr,VMAC_NHBYTES/8,rh,rl);
+ #else
+ nh_vmac_nhbytes_2(mptr,kptr,VMAC_NHBYTES/8,rh,rl,rh2,rl2);
+ rh2 &= m62;
+ poly_step(ch2,cl2,pkh2,pkl2,rh2,rl2);
+ #endif
+ rh &= m62;
+ poly_step(ch,cl,pkh,pkl,rh,rl);
+ mptr += (VMAC_NHBYTES/sizeof(uint64_t));
+ }
+ if (remaining) {
+ #if (VMAC_TAG_LEN == 64)
+ nh_16(mptr,kptr,2*((remaining+15)/16),rh,rl);
+ #else
+ nh_16_2(mptr,kptr,2*((remaining+15)/16),rh,rl,rh2,rl2);
+ rh2 &= m62;
+ poly_step(ch2,cl2,pkh2,pkl2,rh2,rl2);
+ #endif
+ rh &= m62;
+ poly_step(ch,cl,pkh,pkl,rh,rl);
+ }
+
+do_l3:
+ #if VMAC_USE_SSE2
+ _mm_empty(); /* SSE2 version of poly_step uses mmx instructions */
+ #endif
+ vhash_abort(ctx);
+ remaining *= 8;
+#if (VMAC_TAG_LEN == 128)
+ *tagl = l3hash(ch2, cl2, ctx->l3key[2], ctx->l3key[3],remaining);
+#endif
+ return l3hash(ch, cl, ctx->l3key[0], ctx->l3key[1],remaining);
+}
+
+/* ----------------------------------------------------------------------- */
+
+uint64_t vmac(unsigned char m[],
+ unsigned int mbytes,
+ unsigned char n[16],
+ uint64_t *tagl,
+ vmac_ctx_t *ctx)
+{
+#if (VMAC_TAG_LEN == 64)
+ uint64_t *in_n, *out_p;
+ uint64_t p, h;
+ int i;
+ (void)tagl;
+
+ #if VMAC_CACHE_NONCES
+ in_n = ctx->cached_nonce;
+ out_p = ctx->cached_aes;
+ #else
+ uint64_t tmp[2];
+ in_n = out_p = tmp;
+ #endif
+
+ i = n[15] & 1;
+ #if VMAC_CACHE_NONCES
+ if ((*(uint64_t *)(n+8) != in_n[1]) ||
+ (*(uint64_t *)(n ) != in_n[0])) {
+ #endif
+
+ in_n[0] = *(uint64_t *)(n );
+ in_n[1] = *(uint64_t *)(n+8);
+ ((unsigned char *)in_n)[15] &= 0xFE;
+ aes_encryption(in_n, out_p, &ctx->cipher_key);
+
+ #if VMAC_CACHE_NONCES
+ ((unsigned char *)in_n)[15] |= (unsigned char)(1-i);
+ }
+ #endif
+ p = get64BE(out_p + i);
+ h = vhash(m, mbytes, (uint64_t *)0, ctx);
+ return p + h;
+#else
+ uint64_t tmp[2];
+ uint64_t th,tl;
+ aes_encryption(n, (unsigned char *)tmp, &ctx->cipher_key);
+ th = vhash(m, mbytes, &tl, ctx);
+ th += get64BE(tmp);
+ *tagl = tl + get64BE(tmp+1);
+ return th;
+#endif
+}
+
+/* ----------------------------------------------------------------------- */
+
+void vmac_set_key(unsigned char user_key[], vmac_ctx_t *ctx)
+{
+ uint64_t in[2] = {0}, out[2];
+ unsigned i;
+ aes_key_setup(user_key, &ctx->cipher_key);
+
+ /* Fill nh key */
+ ((unsigned char *)in)[0] = 0x80;
+ for (i = 0; i < sizeof(ctx->nhkey)/8; i+=2) {
+ aes_encryption((unsigned char *)in, (unsigned char *)out,
+ &ctx->cipher_key);
+ ctx->nhkey[i ] = get64BE(out);
+ ctx->nhkey[i+1] = get64BE(out+1);
+ ((unsigned char *)in)[15] += 1;
+ }
+
+ /* Fill poly key */
+ ((unsigned char *)in)[0] = 0xC0;
+ in[1] = 0;
+ for (i = 0; i < sizeof(ctx->polykey)/8; i+=2) {
+ aes_encryption((unsigned char *)in, (unsigned char *)out,
+ &ctx->cipher_key);
+ ctx->polytmp[i ] = ctx->polykey[i ] = get64BE(out) & mpoly;
+ ctx->polytmp[i+1] = ctx->polykey[i+1] = get64BE(out+1) & mpoly;
+ ((unsigned char *)in)[15] += 1;
+ }
+
+ /* Fill ip key */
+ ((unsigned char *)in)[0] = 0xE0;
+ in[1] = 0;
+ for (i = 0; i < sizeof(ctx->l3key)/8; i+=2) {
+ do {
+ aes_encryption((unsigned char *)in, (unsigned char *)out,
+ &ctx->cipher_key);
+ ctx->l3key[i ] = get64BE(out);
+ ctx->l3key[i+1] = get64BE(out+1);
+ ((unsigned char *)in)[15] += 1;
+ } while (ctx->l3key[i] >= p64 || ctx->l3key[i+1] >= p64);
+ }
+
+ /* Invalidate nonce/aes cache and reset other elements */
+ #if (VMAC_TAG_LEN == 64) && (VMAC_CACHE_NONCES)
+ ctx->cached_nonce[0] = (uint64_t)-1; /* Ensure illegal nonce */
+ ctx->cached_nonce[1] = (uint64_t)0; /* Ensure illegal nonce */
+ #endif
+ ctx->first_block_processed = 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+
+#if VMAC_RUN_TESTS
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+
+unsigned prime(void) /* Wake variable speed cpu, get rough speed estimate */
+{
+ volatile uint64_t i;
+ volatile uint64_t j=1;
+ unsigned cnt=0;
+ volatile clock_t ticks = clock();
+ do {
+ for (i = 0; i < 500000; i++) {
+ uint64_t x = get64PE(&j);
+ j = x * x + (uint64_t)ticks;
+ }
+ cnt++;
+ } while (clock() - ticks < (CLOCKS_PER_SEC/2));
+ return cnt; /* cnt is millions of iterations per second */
+}
+
+int main(void)
+{
+ ALIGN(16) vmac_ctx_t ctx, ctx_aio, ctx_inc1, ctx_inc2;
+ uint64_t res, tagl;
+ void *p;
+ unsigned char *m;
+ ALIGN(4) unsigned char key[] = "abcdefghijklmnop";
+ ALIGN(4) unsigned char nonce[] = "\0\0\0\0\0\0\0\0bcdefghi";
+ unsigned int vector_lengths[] = {0,3,48,300,3000000};
+ #if (VMAC_TAG_LEN == 64)
+ ALIGN(4) char *should_be[] = {"2576BE1C56D8B81B","2D376CF5B1813CE5",
+ "E8421F61D573D298","4492DF6C5CAC1BBE",
+ "09BA597DD7601113"};
+ #else
+ ALIGN(4) char *should_be[] = {"472766C70F74ED23481D6D7DE4E80DAC",
+ "4EE815A06A1D71EDD36FC75D51188A42",
+ "09F2C80C8E1007A0C12FAE19FE4504AE",
+ "66438817154850C61D8A412164803BCB",
+ "2B6B02288FFC461B75485DE893C629DC"};
+ #endif
+ unsigned speed_lengths[] = {16, 32, 64, 128, 256, 512, 1024, 2048, 4096};
+ unsigned i, j, *speed_iters;
+ clock_t ticks;
+ double cpb;
+ const unsigned int buf_len = 3 * (1 << 20);
+
+ j = prime();
+ i = sizeof(speed_lengths)/sizeof(speed_lengths[0]);
+ speed_iters = (unsigned *)malloc(i*sizeof(speed_iters[0]));
+ speed_iters[i-1] = j * (1 << 12);
+ while (--i) speed_iters[i-1] = (unsigned)(1.3 * speed_iters[i]);
+
+ /* Initialize context and message buffer, all 16-byte aligned */
+ p = malloc(buf_len + 32);
+ m = (unsigned char *)(((size_t)p + 16) & ~((size_t)15));
+ memset(m, 0, buf_len + 16);
+ vmac_set_key(key, &ctx);
+
+ /* Test incremental and all-in-one interfaces for correctness */
+ vmac_set_key(key, &ctx_aio);
+ vmac_set_key(key, &ctx_inc1);
+ vmac_set_key(key, &ctx_inc2);
+
+
+ /*
+ for (i = 0; i <= 512; i++) {
+ vhash_update(m,(i/VMAC_NHBYTES)*VMAC_NHBYTES,&ctx_inc1);
+ tagh = vmac(m+(i/VMAC_NHBYTES)*VMAC_NHBYTES, i%VMAC_NHBYTES,
+ nonce, &tagl, &ctx);
+ vhash_update(m,(i/VMAC_NHBYTES)*VMAC_NHBYTES,&ctx_inc1);
+ for (j = 0; j < vector_lengths[i]; j++)
+ m[j] = (unsigned char)('a'+j%3);
+
+ }
+ */
+
+ /* Generate vectors */
+ for (i = 0; i < sizeof(vector_lengths)/sizeof(unsigned int); i++) {
+ for (j = 0; j < vector_lengths[i]; j++)
+ m[j] = (unsigned char)('a'+j%3);
+ res = vmac(m, vector_lengths[i], nonce, &tagl, &ctx);
+ #if (VMAC_TAG_LEN == 64)
+ printf("\'abc\' * %7u: %016llX Should be: %s\n",
+ vector_lengths[i]/3,res,should_be[i]);
+ #else
+ printf("\'abc\' * %7u: %016llX%016llX\nShould be : %s\n",
+ vector_lengths[i]/3,res,tagl,should_be[i]);
+ #endif
+ }
+
+ /* Speed test */
+ for (i = 0; i < sizeof(speed_lengths)/sizeof(unsigned int); i++) {
+ ticks = clock();
+ for (j = 0; j < speed_iters[i]; j++) {
+ #if HASH_ONLY
+ res = vhash(m, speed_lengths[i], &tagl, &ctx);
+ #else
+ res = vmac(m, speed_lengths[i], nonce, &tagl, &ctx);
+ nonce[7]++;
+ #endif
+ }
+ ticks = clock() - ticks;
+ cpb = ((ticks*VMAC_HZ)/
+ ((double)CLOCKS_PER_SEC*speed_lengths[i]*speed_iters[i]));
+ printf("%4u bytes, %2.2f cpb\n", speed_lengths[i], cpb);
+ }
+ return 1;
+}
+
+#endif
diff --git a/tboot/vmcs.c b/tboot/vmcs.c
new file mode 100644
index 0000000..3aa0259
--- /dev/null
+++ b/tboot/vmcs.c
@@ -0,0 +1,603 @@
+/*
+ * vmcs.c: create and manage mini-VT VM for APs to handle INIT-SIPI-SIPI
+ *
+ * Copyright (c) 2003-2010, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <msr.h>
+#include <tb_error.h>
+#include <compiler.h>
+#include <string.h>
+#include <misc.h>
+#include <page.h>
+#include <processor.h>
+#include <printk.h>
+#include <uuid.h>
+#include <mutex.h>
+#include <atomic.h>
+#include <eficore.h>
+#include <eficonfig.h>
+#include <mle.h>
+#include <tboot.h>
+#include <txt/txt.h>
+#include <txt/vmcs.h>
+
+
+/* no vmexit on external intr as mini guest only handle INIT & SIPI */
+#define MONITOR_PIN_BASED_EXEC_CONTROLS \
+ ( PIN_BASED_NMI_EXITING )
+
+/* no vmexit on hlt as guest only run this instruction */
+#define MONITOR_CPU_BASED_EXEC_CONTROLS \
+ ( CPU_BASED_INVDPG_EXITING | \
+ CPU_BASED_MWAIT_EXITING )
+
+#define MONITOR_VM_EXIT_CONTROLS \
+ ( VM_EXIT_ACK_INTR_ON_EXIT )
+
+/* Basic flags for VM-Entry controls. */
+#define MONITOR_VM_ENTRY_CONTROLS 0x00000000
+
+#define EXCEPTION_BITMAP_BP (1 << 3) /* Breakpoint */
+#define EXCEPTION_BITMAP_PG (1 << 14) /* Page Fault */
+#define MONITOR_DEFAULT_EXCEPTION_BITMAP \
+ ( EXCEPTION_BITMAP_PG | \
+ EXCEPTION_BITMAP_BP )
+
+#define load_TR(n) __asm__ __volatile__ ("ltr %%ax" : : "a" ((n)<<3) )
+/* TODO deal with
+extern char gdt_table[];
+#define RESET_TSS_DESC(n) gdt_table[((n)<<3)+5] = 0x89 */
+#define RESET_TSS_DESC(n)
+
+/* lock that protects APs against race conditions on wakeup and shutdown */
+struct mutex ap_lock;
+
+/* counter for APs entering/exiting wait-for-sipi */
+atomic_t ap_wfs_count;
+
+/* flag for (all APs) exiting mini guest (1 = exit) */
+uint32_t aps_exit_guest;
+
+/* MLE/kernel shared data page (in boot.S) */
+tboot_shared_t _tboot_shared;
+
+/* Address references */
+static uint64_t idle_pg_table_ref;
+static uint64_t host_vmcs_ref;
+static uint64_t ap_vmcs_ref;
+static uint64_t _mini_guest_ref;
+static uint64_t vmx_asm_vmexit_handler_ref;
+
+static uint32_t vmcs_rev_id;
+static uint32_t pin_based_vm_exec_ctrls;
+static uint32_t proc_based_vm_exec_ctrls;
+static uint32_t vm_exit_ctrls;
+static uint32_t vm_entry_ctrls;
+
+static void init_vmx_ctrl(uint32_t msr, uint32_t ctrl_val, uint32_t *ctrl)
+{
+ uint32_t lo, hi;
+ uint64_t val;
+
+ val = rdmsr(msr);
+ lo = (uint32_t)(val & 0xffffffffUL);
+ hi = (uint32_t)(val >> 32);
+ *ctrl = (ctrl_val & hi) | lo;
+
+ /* make sure that the conditions we want are actually allowed */
+ if ( (*ctrl & ctrl_val) != ctrl_val )
+ apply_policy(TB_ERR_FATAL);
+}
+
+static void init_vmcs_config(void)
+{
+ uint64_t val;
+
+ val = rdmsr(MSR_IA32_VMX_BASIC_MSR);
+ vmcs_rev_id = (uint32_t)(val & 0xffffffffUL);
+
+ init_vmx_ctrl(MSR_IA32_VMX_PINBASED_CTLS_MSR,
+ MONITOR_PIN_BASED_EXEC_CONTROLS, &pin_based_vm_exec_ctrls);
+
+ init_vmx_ctrl(MSR_IA32_VMX_PROCBASED_CTLS_MSR,
+ MONITOR_CPU_BASED_EXEC_CONTROLS, &proc_based_vm_exec_ctrls);
+
+ init_vmx_ctrl(MSR_IA32_VMX_EXIT_CTLS_MSR,
+ MONITOR_VM_EXIT_CONTROLS, &vm_exit_ctrls);
+
+ init_vmx_ctrl(MSR_IA32_VMX_ENTRY_CTLS_MSR,
+ MONITOR_VM_ENTRY_CONTROLS, &vm_entry_ctrls);
+}
+
+/* build a 1-level identity-map page table [0, _end] on AP for vmxon */
+static void build_ap_pagetable(void)
+{
+#define PTE_FLAGS 0xe3 /* PRESENT+RW+A+D+4MB */
+ uint64_t pt_entry = PTE_FLAGS;
+ uint64_t *pte = (uint64_t*)idle_pg_table_ref;
+
+ while ( pt_entry <= (uint64_t)(g_image_base + g_image_size) + PTE_FLAGS ) {
+ *pte = pt_entry;
+ /* Incriments 4MB page at a time */
+ pt_entry += 1 << FOURMB_PAGE_SHIFT;
+ pte++;
+ }
+}
+
+static bool start_vmx(unsigned int cpuid)
+{
+ struct vmcs_struct *vmcs;
+ static bool init_done = false;
+
+ write_cr4(read_cr4() | CR4_VMXE);
+
+ vmcs = (struct vmcs_struct *)host_vmcs_ref;
+
+ /* TBD: it would be good to check VMX config is same on all CPUs */
+ /* only initialize this data the first time */
+ if ( !init_done ) {
+ /*printk(TBOOT_INFO"one-time initializing VMX mini-guest\n");*/
+ memset(vmcs, 0, PAGE_SIZE);
+
+ init_vmcs_config();
+ vmcs->vmcs_revision_id = vmcs_rev_id;
+
+ /* enable paging as required by vmentry */
+ build_ap_pagetable();
+
+ init_done = true;
+ }
+
+ /*printk(TBOOT_INFO"per-cpu initializing VMX mini-guest on cpu %u\n", cpuid);*/
+
+ /* enable paging using 1:1 page table [0, _end] */
+ /* addrs outside of tboot (e.g. MMIO) are not mapped) */
+ write_cr3(idle_pg_table_ref);
+ write_cr4(read_cr4() | CR4_PSE);
+ write_cr0(read_cr0() | CR0_PG);
+
+ if ( __vmxon((unsigned long long)vmcs) ) {
+ write_cr4(read_cr4() & ~CR4_VMXE);
+ write_cr4(read_cr4() & ~CR4_PSE);
+ write_cr0(read_cr0() & ~CR0_PG);
+ printk(TBOOT_ERR"VMXON failed for cpu %u\n", cpuid);
+ return false;
+ }
+
+ printk(TBOOT_DETA"VMXON done for cpu %u\n", cpuid);
+ return true;
+}
+
+static void stop_vmx(unsigned int cpuid)
+{
+ struct vmcs_struct *vmcs = NULL;
+
+ if ( !(read_cr4() & CR4_VMXE) ) {
+ printk(TBOOT_DETA"stop_vmx() called when VMX not enabled\n");
+ return;
+ }
+
+ __vmptrst((unsigned long long)vmcs);
+
+ __vmpclear((unsigned long long)vmcs);
+
+ __vmxoff();
+
+ write_cr4(read_cr4() & ~CR4_VMXE);
+
+ /* diable paging to restore AP's state to boot xen */
+ write_cr0(read_cr0() & ~CR0_PG);
+ write_cr4(read_cr4() & ~CR4_PSE);
+
+ printk(TBOOT_DETA"VMXOFF done for cpu %u\n", cpuid);
+}
+
+/* consturct guest/host vmcs:
+ * make guest vmcs from physical environment,
+ * so only one binary switch between root and non-root
+ */
+static void construct_vmcs(void)
+{
+ struct __packed {
+ uint16_t limit;
+ uint32_t base;
+ } xdt;
+ unsigned long long cr0, cr3, cr4, rflags, rsp;
+ unsigned int tr;
+ union vmcs_arbytes arbytes;
+ uint16_t seg;
+
+ __vmwrite(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_ctrls);
+ __vmwrite(VM_EXIT_CONTROLS, vm_exit_ctrls);
+ __vmwrite(VM_ENTRY_CONTROLS, vm_entry_ctrls);
+ __vmwrite(CPU_BASED_VM_EXEC_CONTROL, proc_based_vm_exec_ctrls);
+
+ /* segments selectors. */
+ __asm__ __volatile__ ("mov %%ss, %0\n" : "=r"(seg));
+ __vmwrite(HOST_SS_SELECTOR, seg);
+ __vmwrite(GUEST_SS_SELECTOR, seg);
+
+ __asm__ __volatile__ ("mov %%ds, %0\n" : "=r"(seg));
+ __vmwrite(HOST_DS_SELECTOR, seg);
+ __vmwrite(GUEST_DS_SELECTOR, seg);
+
+ __asm__ __volatile__ ("mov %%es, %0\n" : "=r"(seg));
+ __vmwrite(HOST_ES_SELECTOR, seg);
+ __vmwrite(GUEST_ES_SELECTOR, seg);
+
+ __asm__ __volatile__ ("mov %%fs, %0\n" : "=r"(seg));
+ __vmwrite(HOST_FS_SELECTOR, seg);
+ __vmwrite(GUEST_FS_SELECTOR, seg);
+
+ __asm__ __volatile__ ("mov %%gs, %0\n" : "=r"(seg));
+ __vmwrite(HOST_GS_SELECTOR, seg);
+ __vmwrite(GUEST_GS_SELECTOR, seg);
+
+ __asm__ __volatile__ ("mov %%cs, %0\n" : "=r"(seg));
+
+ __vmwrite(GUEST_CS_SELECTOR, seg);
+ __vmwrite(GUEST_RIP, _mini_guest_ref);
+
+ __vmwrite(HOST_CS_SELECTOR, seg);
+ __vmwrite(HOST_RIP, vmx_asm_vmexit_handler_ref);
+
+ /* segment limits */
+#define GUEST_SEGMENT_LIMIT 0xffffffff
+ __vmwrite(GUEST_ES_LIMIT, GUEST_SEGMENT_LIMIT);
+ __vmwrite(GUEST_SS_LIMIT, GUEST_SEGMENT_LIMIT);
+ __vmwrite(GUEST_DS_LIMIT, GUEST_SEGMENT_LIMIT);
+ __vmwrite(GUEST_FS_LIMIT, GUEST_SEGMENT_LIMIT);
+ __vmwrite(GUEST_GS_LIMIT, GUEST_SEGMENT_LIMIT);
+ __vmwrite(GUEST_CS_LIMIT, GUEST_SEGMENT_LIMIT);
+
+ /* segment AR bytes, see boot.S for details */
+ arbytes.bytes = 0;
+ arbytes.fields.seg_type = 0x3; /* type = 3 */
+ arbytes.fields.s = 1; /* code or data, i.e. not system */
+ arbytes.fields.dpl = 0; /* DPL = 0 */
+ arbytes.fields.p = 1; /* segment present */
+ arbytes.fields.default_ops_size = 1; /* 32-bit */
+ arbytes.fields.g = 1;
+
+ arbytes.fields.null_bit = 0; /* not null */
+ __vmwrite(GUEST_ES_AR_BYTES, arbytes.bytes);
+ __vmwrite(GUEST_SS_AR_BYTES, arbytes.bytes);
+ __vmwrite(GUEST_DS_AR_BYTES, arbytes.bytes);
+ __vmwrite(GUEST_FS_AR_BYTES, arbytes.bytes);
+ __vmwrite(GUEST_GS_AR_BYTES, arbytes.bytes);
+
+ arbytes.fields.seg_type = 0xb; /* type = 0xb */
+ __vmwrite(GUEST_CS_AR_BYTES, arbytes.bytes);
+
+ /* segment BASE */
+ __vmwrite(GUEST_ES_BASE, 0);
+ __vmwrite(GUEST_SS_BASE, 0);
+ __vmwrite(GUEST_DS_BASE, 0);
+ __vmwrite(GUEST_FS_BASE, 0);
+ __vmwrite(GUEST_GS_BASE, 0);
+ __vmwrite(GUEST_CS_BASE, 0);
+
+ __vmwrite(HOST_FS_BASE, 0);
+ __vmwrite(HOST_GS_BASE, 0);
+
+ /* Guest LDT and TSS */
+ __vmwrite(GUEST_LDTR_SELECTOR, 0);
+ __vmwrite(GUEST_LDTR_BASE, 0);
+ __vmwrite(GUEST_LDTR_LIMIT, 0xffff);
+
+ __asm__ __volatile__ ("str (%0) \n" :: "a"(&tr) : "memory");
+ if ( tr == 0 )
+ printk(TBOOT_ERR"tr is 0 on ap, may vmlaunch fail.\n");
+ __vmwrite(GUEST_TR_SELECTOR, tr);
+ __vmwrite(GUEST_TR_BASE, 0);
+ __vmwrite(GUEST_TR_LIMIT, 0xffff);
+
+ __vmwrite(HOST_TR_SELECTOR, tr);
+ __vmwrite(HOST_TR_BASE, 0);
+
+
+ /* tboot does not use ldt */
+ arbytes.bytes = 0;
+ arbytes.fields.s = 0; /* not code or data segement */
+ arbytes.fields.seg_type = 0x2; /* LDT */
+ arbytes.fields.p = 1; /* segment present */
+ arbytes.fields.default_ops_size = 0; /* 16-bit */
+ arbytes.fields.g = 1;
+ __vmwrite(GUEST_LDTR_AR_BYTES, arbytes.bytes);
+
+ /* setup a TSS for vmentry as zero TR is not allowed */
+ arbytes.bytes = 0;
+ arbytes.fields.s = 0; /* not code or data seg */
+ arbytes.fields.seg_type = 0xb; /* 32-bit TSS (busy) */
+ arbytes.fields.p = 1; /* segment present */
+ arbytes.fields.default_ops_size = 0; /* 16-bit */
+ arbytes.fields.g = 1;
+ __vmwrite(GUEST_TR_AR_BYTES, arbytes.bytes);
+
+ /* GDT */
+ __asm__ __volatile__ ("sgdt (%0) \n" :: "a"(&xdt) : "memory");
+ __vmwrite(GUEST_GDTR_BASE, xdt.base);
+ __vmwrite(GUEST_GDTR_LIMIT, xdt.limit);
+
+ __vmwrite(HOST_GDTR_BASE, xdt.base);
+
+ /* IDT */
+ __asm__ __volatile__ ("sidt (%0) \n" :: "a"(&xdt) : "memory");
+ /*printk(TBOOT_INFO"idt.base=0x%x, limit=0x%x.\n", xdt.base, xdt.limit);*/
+ __vmwrite(GUEST_IDTR_BASE, xdt.base);
+ __vmwrite(GUEST_IDTR_LIMIT, xdt.limit);
+
+ __vmwrite(HOST_IDTR_BASE, xdt.base);
+
+ /* control registers. */
+ cr0 = read_cr0();
+ cr3 = read_cr3();
+ cr4 = read_cr4();
+ __vmwrite(HOST_CR0, cr0);
+ __vmwrite(HOST_CR4, cr4);
+ __vmwrite(HOST_CR3, cr3);
+
+ __vmwrite(GUEST_CR0, cr0);
+ __vmwrite(CR0_READ_SHADOW, cr0);
+ __vmwrite(GUEST_CR4, cr4);
+ __vmwrite(CR4_READ_SHADOW, cr4);
+ __vmwrite(GUEST_CR3, cr3);
+
+ /* debug register */
+ __vmwrite(GUEST_DR7, 0);
+
+ /* rflags & rsp */
+ rflags = read_rflags();
+ __vmwrite(GUEST_RFLAGS, rflags);
+
+ __asm__ __volatile__ ("mov %%rsp,%0\n\t" :"=r" (rsp));
+ __vmwrite(GUEST_RSP, rsp);
+ __vmwrite(HOST_RSP, rsp);
+
+ /* MSR intercepts. */
+ __vmwrite(VM_EXIT_MSR_LOAD_ADDR, 0);
+ __vmwrite(VM_EXIT_MSR_STORE_ADDR, 0);
+ __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0);
+ __vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0);
+ __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0);
+
+ __vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0);
+
+ __vmwrite(CR0_GUEST_HOST_MASK, ~0UL);
+ __vmwrite(CR4_GUEST_HOST_MASK, ~0UL);
+
+ __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0);
+ __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0);
+
+ __vmwrite(CR3_TARGET_COUNT, 0);
+
+ __vmwrite(GUEST_ACTIVITY_STATE, GUEST_STATE_ACTIVE);
+
+ __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
+ __vmwrite(VMCS_LINK_POINTER, ~0UL);
+
+ __vmwrite(VMCS_LINK_POINTER_HIGH, ~0UL);
+
+ __vmwrite(EXCEPTION_BITMAP, MONITOR_DEFAULT_EXCEPTION_BITMAP);
+
+ /*printk(TBOOT_INFO"vmcs setup done.\n");*/
+}
+
+static bool vmx_create_vmcs(unsigned int cpuid)
+{
+ char *ap_vmcs = (char *)ap_vmcs_ref;
+ struct vmcs_struct *vmcs = (struct vmcs_struct *)&ap_vmcs[cpuid];
+
+ memset(vmcs, 0, PAGE_SIZE);
+
+ vmcs->vmcs_revision_id = vmcs_rev_id;
+
+ /* vir addr equal to phy addr as we setup identity page table */
+ __vmpclear((unsigned long long)vmcs);
+
+ __vmptrld((unsigned long long)vmcs);
+
+ construct_vmcs();
+
+ return true;
+}
+
+static void launch_mini_guest(unsigned int cpuid)
+{
+ unsigned long error;
+
+ printk(TBOOT_DETA"launching mini-guest for cpu %u\n", cpuid);
+
+ /* this is close enough to entering wait-for-sipi, so inc counter */
+ atomic_inc((atomic_t *)&_tboot_shared.num_in_wfs);
+
+ __vmlaunch();
+
+ /* should not reach here */
+ atomic_dec(&ap_wfs_count);
+ atomic_dec((atomic_t *)&_tboot_shared.num_in_wfs);
+ error = __vmread(VM_INSTRUCTION_ERROR);
+ printk(TBOOT_ERR"vmlaunch failed for cpu %u, error code %lx\n", cpuid, error);
+ apply_policy(TB_ERR_FATAL);
+}
+
+static void print_failed_vmentry_reason(unsigned int exit_reason)
+{
+ unsigned long exit_qualification;
+
+ exit_qualification = __vmread(EXIT_QUALIFICATION);
+ printk(TBOOT_ERR"Failed vm entry (exit reason 0x%x) ", exit_reason);
+ switch ( (uint16_t)exit_reason )
+ {
+ case EXIT_REASON_INVALID_GUEST_STATE:
+ printk(TBOOT_ERR"caused by invalid guest state (%ld).\n",
+ exit_qualification);
+ break;
+ case EXIT_REASON_MSR_LOADING:
+ printk(TBOOT_ERR"caused by MSR entry %ld loading.\n", exit_qualification);
+ break;
+ case EXIT_REASON_MACHINE_CHECK:
+ printk(TBOOT_ERR"caused by machine check.\n");
+ break;
+ default:
+ printk(TBOOT_ERR"reason not known yet!");
+ break;
+ }
+}
+
+/* Vmexit handler for physical INIT-SIPI-SIPI from the BSP
+ * Do not use printk in this critical path as BSP only
+ * wait for a short time
+ */
+void vmx_vmexit_handler(void)
+{
+ unsigned int apicid = get_apicid();
+
+ unsigned int exit_reason = __vmread(VM_EXIT_REASON);
+ /*printk("vmx_vmexit_handler, exit_reason=%x.\n", exit_reason);*/
+
+ if ( (exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY) ) {
+ print_failed_vmentry_reason(exit_reason);
+ stop_vmx(apicid);
+ atomic_dec(&ap_wfs_count);
+ atomic_dec((atomic_t *)&_tboot_shared.num_in_wfs);
+ apply_policy(TB_ERR_FATAL);
+ }
+ else if ( exit_reason == EXIT_REASON_INIT ) {
+ __vmwrite(GUEST_ACTIVITY_STATE, GUEST_STATE_WAIT_SIPI);
+ __vmresume();
+ }
+ else if ( exit_reason == EXIT_REASON_SIPI ) {
+ /* even though standard MP sequence is INIT-SIPI-SIPI */
+ /* there is no need to wait for second SIPI (which may not */
+ /* always be delivered) */
+ /* but we should expect there to already have been INIT */
+ /* disable VT then jump to xen code */
+ unsigned long exit_qual = __vmread(EXIT_QUALIFICATION);
+ uint32_t sipi_vec = (exit_qual & 0xffUL) << PAGE_SHIFT;
+ /* printk("exiting due to SIPI: vector=%x\n", sipi_vec); */
+ stop_vmx(apicid);
+ atomic_dec(&ap_wfs_count);
+ atomic_dec((atomic_t *)&_tboot_shared.num_in_wfs);
+ cpu_wakeup(apicid, sipi_vec);
+
+ /* cpu_wakeup() doesn't return, so we should never get here */
+ printk(TBOOT_ERR"cpu_wakeup() failed\n");
+ apply_policy(TB_ERR_FATAL);
+ }
+ else if ( exit_reason == EXIT_REASON_VMCALL ) {
+ stop_vmx(apicid);
+ atomic_dec(&ap_wfs_count);
+ atomic_dec((atomic_t *)&_tboot_shared.num_in_wfs);
+ /* spin */
+ while ( true )
+ __asm__ __volatile__("cli; hlt;");
+ }
+ else {
+ printk(TBOOT_ERR"can't handle vmexit due to 0x%x.\n", exit_reason);
+ __vmresume();
+ }
+}
+
+/* Launch a mini guest to handle the physical INIT-SIPI-SIPI from BSP */
+void handle_init_sipi_sipi(unsigned int cpuid)
+{
+ if ( cpuid >= NR_CPUS ) {
+ printk(TBOOT_ERR"cpuid (%u) exceeds # supported CPUs\n", cpuid);
+ apply_policy(TB_ERR_FATAL);
+ mtx_leave(&ap_lock);
+ return;
+ }
+
+ /* setup a dummy tss as vmentry require a non-zero host TR */
+ load_TR(3);
+
+ /* clear the tss busy flag to avoid blocking other APs */
+ RESET_TSS_DESC(3);
+
+ /* prepare a guest for INIT-SIPI-SIPI handling */
+ /* 1: setup VMX environment and VMXON */
+ if ( !start_vmx(cpuid) ) {
+ apply_policy(TB_ERR_FATAL);
+ mtx_leave(&ap_lock);
+ return;
+ }
+
+ /* 2: setup VMCS */
+ if ( vmx_create_vmcs(cpuid) ) {
+ mtx_leave(&ap_lock);
+
+ /* 3: launch VM */
+ launch_mini_guest(cpuid);
+ }
+
+ printk(TBOOT_ERR"control should not return here from launch_mini_guest\n");
+ apply_policy(TB_ERR_FATAL);
+ return;
+}
+
+void force_aps_exit(void)
+{
+ aps_exit_guest = 1;
+}
+
+void init_vmcs_addrs(void)
+{
+ lea_reference(idle_pg_table, idle_pg_table_ref);
+ lea_reference(host_vmcs, host_vmcs_ref);
+ lea_reference(ap_vmcs, ap_vmcs_ref);
+ lea_reference(_mini_guest, _mini_guest_ref);
+ lea_reference(vmx_asm_vmexit_handler, vmx_asm_vmexit_handler_ref);
+
+ printk(TBOOT_DETA"VMCS addrs:\n");
+ printk(TBOOT_DETA" idle_pg_table = %llx\n", idle_pg_table_ref);
+ printk(TBOOT_DETA" host_vmcs = %llx\n", host_vmcs_ref);
+ printk(TBOOT_DETA" ap_vmcs = %llx\n", ap_vmcs_ref);
+ printk(TBOOT_DETA" _mini_guest = %llx\n", _mini_guest_ref);
+ printk(TBOOT_DETA" vmx_asm_vmexit_handler = %llx\n", vmx_asm_vmexit_handler_ref);
+}
+
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tboot/vsprintf.c b/tboot/vsprintf.c
new file mode 100644
index 0000000..a100cc0
--- /dev/null
+++ b/tboot/vsprintf.c
@@ -0,0 +1,465 @@
+/*
+ * vsprintf.c: provides string formatting fns
+ *
+ * Copyright (c) 2010-2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <config.h>
+#include <efibase.h>
+#include <types.h>
+#include <stdbool.h>
+#include <string.h>
+#include <misc.h>
+#include <compiler.h>
+
+static bool div64(uint64_t num, uint32_t base, uint64_t *quot, uint32_t *rem)
+{
+ /* check exceptions */
+ if ( (quot == NULL) || (rem == NULL) || (base == 0) )
+ return false;
+
+ uint32_t high = num >> 32;
+ uint32_t low = (uint32_t)num;
+ if ( high == 0 ) {
+ *quot = low / base;
+ *rem = low % base;
+ }
+ else {
+ uint64_t hquo = high / base; \
+ uint32_t hrem = high % base;
+ uint32_t lquo;
+ /*
+ * use "divl" instead of "/" to avoid the link error
+ * undefined reference to `__udivdi3'
+ */
+ __asm__ __volatile__ ( "divl %4;"
+ : "=a"(lquo), "=d"(*rem)
+ : "a"(low), "d"(hrem), "r"(base));
+ *quot = (hquo << 32) + lquo;
+ }
+
+ return true;
+}
+
+/*
+ * write the character into the buffer
+ * return the position of the buffer after writting
+ */
+static unsigned long write_char_to_buffer(char *buf, size_t buf_len,
+ unsigned long buf_pos, char ch)
+{
+ /* check buffer overflow? */
+ if ( buf_pos >= buf_len )
+ return 0;
+
+ *(buf + buf_pos) = ch;
+ return buf_pos + 1;
+}
+
+/*
+ * write pad_len pads into the buffer
+ * return the position of the buffer after writting
+ */
+static unsigned long write_pads_to_buffer(char *buf, size_t buf_len,
+ unsigned long buf_pos, char pad,
+ size_t pad_len)
+{
+ for ( unsigned int i = 0; i < pad_len; i++ )
+ buf_pos = write_char_to_buffer(buf, buf_len, buf_pos, pad);
+
+ return buf_pos;
+}
+
+/* %[flags][width][.precision][length]specifier */
+typedef struct {
+ /* flag */
+#define LEFT_ALIGNED (1 << 0) /* '-' */
+#define SIGNED (1 << 1) /* '+' */
+#define SPACE (1 << 2) /* ' ' */
+#define PREFIX (1 << 3) /* '#' */
+#define ZERO_PADDED (1 << 4) /* '0' */
+ int flag;
+ /* width & precision */
+ unsigned int width, precision;
+ /* length */
+ enum {NORM, LONG, LONGLONG} flag_long;
+ /* specifier */
+ int base;
+ bool cap;
+ bool sign;
+ bool digit;
+} modifiers_t;
+
+/*
+ * write the string into the buffer regarding flags
+ * return the position of the buffer after writing
+ */
+static unsigned long write_string_to_buffer(char *buf, size_t buf_len,
+ unsigned long buf_pos,
+ const char* str, size_t strlen,
+ modifiers_t *mods)
+{
+ unsigned int i;
+ if (mods->precision > 0)
+ strlen = (strlen > mods->precision) ? mods->precision : strlen;
+ mods->width = ( mods->width > strlen ) ? mods->width - strlen : 0;
+ if ( mods->flag & LEFT_ALIGNED ) { /* left align */
+ for ( i = 0; i < strlen; i++ )
+ buf_pos = write_char_to_buffer(buf, buf_len, buf_pos, str[i]);
+ buf_pos = write_pads_to_buffer(buf, buf_len, buf_pos, ' ', mods->width);
+ }
+ else { /* right align */
+ /* if not digit, don't considering pad '0' */
+ char pad = ( mods->digit && (mods->flag & ZERO_PADDED) ) ? '0' : ' ';
+
+ buf_pos = write_pads_to_buffer(buf, buf_len, buf_pos, pad, mods->width);
+ for ( i = 0; i < strlen; i++ )
+ buf_pos = write_char_to_buffer(buf, buf_len, buf_pos, str[i]);
+ }
+
+ return buf_pos;
+}
+
+/* convert a integer to a string regarding flags, qualifier, specifier, etc. */
+static size_t int2str(long long val, char *str, size_t strlen,
+ const modifiers_t *mods)
+{
+ unsigned int i;
+ size_t length = 0, number_length = 0;
+ unsigned long number_start = 0;
+ const char hexdig_lowercase[] = "0123456789abcdef";
+ const char hexdig_uppercase[] = "0123456789ABCDEF";
+ unsigned long long nval;
+
+ /* check, we support octal/decimal/hex only */
+ if ( (mods->base != 8) && (mods->base != 10) && (mods->base != 16) )
+ return 0;
+
+ if ( str == NULL || strlen == 0 )
+ return 0;
+
+ if ( mods->flag & PREFIX ) {
+ if ( mods->base == 8 )
+ *(str + length++) = '0'; /* add prefix 0 for octal */
+ else if ( mods->base == 16 ) {
+ if ( strlen < 2 )
+ return 0;
+
+ /* add prefix 0x/0X for hex */
+ *(str + length++) = '0';
+ *(str + length++) = ( mods->cap ) ? 'X' : 'x';
+ }
+ }
+
+ /*
+ * if it is shown as signed decimal(%d), we consider to add -/+/' '
+ * but, if it is an unsigned number, no need to add -/+/' '
+ */
+ if ( mods->base == 10 && mods->sign ) {
+ if ( val < 0 ) { /* negative */
+ *(str + length++) = '-';
+ val = -val;
+ }
+ else { /* positive */
+ if ( mods->flag & SIGNED )
+ *(str + length++) = '+';
+ else if ( mods->flag & SPACE )
+ *(str + length++) = ' ';
+ }
+ }
+
+ /* truncate to unsigned long or unsigned int if type of val is */
+ if ( mods->flag_long == LONGLONG )
+ nval = (unsigned long long)val;
+ else if ( mods->flag_long == LONG )
+ nval = (unsigned long long)(unsigned long)val;
+ else
+ nval = (unsigned long long)(unsigned int)val;
+
+ /* convert */
+ number_start = length;
+ do {
+ /* overflow? */
+ if ( length >= strlen )
+ break;
+
+ uint32_t rem = 0;
+ if ( !div64(nval, mods->base, (uint64_t*)&nval, &rem) )
+ return 0;
+ *(str + length) = ( mods->cap ) ?
+ hexdig_uppercase[rem] : hexdig_lowercase[rem];
+ length++;
+ number_length++;
+ } while ( nval );
+
+ /* handle precision */
+ while ( number_length < mods->precision ) {
+ /* overflow? */
+ if ( length >= strlen )
+ break;
+
+ *(str + length) = '0';
+ length++;
+ number_length++;
+ }
+
+ /* reverse */
+ for ( i = 0; i < number_length/2; i++ ) {
+ char ch;
+
+ ch = *(str + number_start + i);
+ *(str + number_start + i)
+ = *(str + number_start + (number_length - i - 1));
+ *(str + number_start + (number_length - i - 1)) = ch;
+ }
+
+ return length;
+}
+
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list ap)
+{
+ unsigned int buf_pos = 0; /* return value doesn't count the last '\0' */
+ const char *fmt_ptr;
+ modifiers_t mods;
+
+ /* check buf */
+ if ( (buf == NULL) || (size == 0) )
+ return 0;
+
+ /* check fmt */
+ if ( fmt == NULL )
+ return 0;
+
+ memset(&mods, 0, sizeof(mods));
+
+ while ( buf_pos < size ) {
+ bool success;
+
+ /* handle normal characters */
+ while ( *fmt != '%' ) {
+ buf_pos = write_char_to_buffer(buf, size, buf_pos, *fmt);
+ if ( *fmt == '\0' )
+ return buf_pos - 1;
+ fmt++;
+ }
+
+ /* handle %: %[flags][width][.precision][length]specifier */
+ /*
+ * start to parse the syntax of %, save the position of fmt
+ * in case that append the string to the buffer if % substring
+ * doesnot match the syntax
+ */
+ fmt_ptr = fmt + 1; /* skip '%' */
+ success = true; /* assume parsing % substring would succeed */
+
+ /* parsing flags */
+ while ( true ) {
+ switch ( *fmt_ptr ) {
+ case '-':
+ mods.flag |= LEFT_ALIGNED;
+ break;
+ case '+':
+ mods.flag |= SIGNED ;
+ break;
+ case ' ':
+ mods.flag |= SPACE;
+ break;
+ case '#':
+ mods.flag |= PREFIX;
+ break;
+ case '0':
+ mods.flag |= ZERO_PADDED;
+ break;
+ default:
+ goto handle_width;
+ }
+ fmt_ptr++;
+ }
+
+ /* parsing width */
+handle_width:
+ if ( *fmt_ptr == '*' ) {
+ mods.width = va_arg(ap, int);
+ fmt_ptr++;
+ }
+ else
+ mods.width = strtoul(fmt_ptr, (char **)&fmt_ptr, 10);
+
+ if ( *fmt_ptr == '.' ) {
+ /* skip . */
+ fmt_ptr++;
+
+ /* parsing precision */
+ if ( *fmt_ptr == '*' ) {
+ mods.precision = va_arg(ap, int);
+ fmt_ptr++;
+ }
+ else
+ mods.precision = strtoul(fmt_ptr, (char **)&fmt_ptr, 10);
+ }
+
+ /* parsing qualifier: h l L;
+ * h is ignored here, and 'L' and 'j' are treated as 'll'
+ */
+ mods.flag_long = NORM;
+ if ( *fmt_ptr == 'L' || *fmt_ptr == 'j' ) {
+ mods.flag_long = LONGLONG;
+ fmt_ptr++;
+ }
+ else if ( *fmt_ptr == 'l' && *(fmt_ptr + 1) == 'l' ) {
+ mods.flag_long = LONGLONG;
+ fmt_ptr += 2;
+ }
+ else if ( *fmt_ptr == 'l' ) {
+ mods.flag_long = LONG;
+ fmt_ptr++;
+ }
+
+#define write_number_to_buffer(__buf, __size, __buf_pos, __mods) \
+({ \
+ char __str[32]; \
+ size_t __real_strlen; \
+ if ( __mods.flag_long == LONGLONG ) { \
+ long long __number = 0; \
+ __number = va_arg(ap, long long); \
+ __real_strlen = int2str(__number, __str, sizeof(__str), &__mods); \
+ } \
+ else if ( __mods.flag_long == LONG ) { \
+ long __number = 0; \
+ __number = va_arg(ap, long); \
+ __real_strlen = int2str(__number, __str, sizeof(__str), &__mods); \
+ } \
+ else { \
+ int __number = 0; \
+ __number = va_arg(ap, int); \
+ __real_strlen = int2str(__number, __str, sizeof(__str), &__mods); \
+ } \
+ __mods.digit = true; \
+ write_string_to_buffer( \
+ __buf, __size, __buf_pos, __str, __real_strlen, &__mods); \
+})
+
+ /* parsing specifier */
+ mods.base = 10;
+ mods.cap = mods.sign = false;
+ switch ( *fmt_ptr ) {
+ case 'c':
+ {
+ char str[1];
+
+ str[0] = (char)va_arg(ap, int);
+ mods.digit = false;
+ buf_pos = write_string_to_buffer(
+ buf, size, buf_pos, str, strlen(str), &mods);
+ break;
+ }
+ case 's':
+ {
+ char *str;
+
+ str = va_arg(ap, char *);
+ mods.digit = false;
+ buf_pos = write_string_to_buffer(
+ buf, size, buf_pos, str, strlen(str), &mods);
+ break;
+ }
+ case 'o':
+ mods.base = 8;
+ buf_pos = write_number_to_buffer(buf, size, buf_pos, mods);
+ break;
+
+ case 'X':
+ mods.cap = true;
+ mods.base = 16;
+ buf_pos = write_number_to_buffer(buf, size, buf_pos, mods);
+ break;
+
+ case 'p':
+ mods.flag |= PREFIX; /* print prefix 0x for %p */
+ mods.flag_long = LONG;
+ case 'x':
+ mods.base = 16;
+ buf_pos = write_number_to_buffer(buf, size, buf_pos, mods);
+ break;
+
+ case 'i':
+ case 'd':
+ mods.sign = true;
+ buf_pos = write_number_to_buffer(buf, size, buf_pos, mods);
+ break;
+
+ case 'u':
+ buf_pos = write_number_to_buffer(buf, size, buf_pos, mods);
+ break;
+ case 'e':
+ case 'E':
+ /* ignore */
+ break;
+ case '%':
+ buf_pos = write_char_to_buffer(buf, size, buf_pos, '%');
+ break;
+ default:
+ success = false;
+ break;
+ } /* switch for specifier */
+
+ fmt_ptr++; /* skip the above character */
+ if ( success )
+ fmt = fmt_ptr;
+ else
+ /* parsing % substring error, treat it as a normal string */
+ /* *fmt = '%' */
+ buf_pos = write_char_to_buffer(buf, size, buf_pos, *fmt++);
+ } /* while */
+
+ buf[buf_pos - 1] = '\0'; /* if the buffer is overflowed. */
+ return buf_pos - 1;
+}
+
+int snprintf(char *buf, size_t size, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int count = vscnprintf(buf, size, fmt, ap);
+ va_end(ap);
+ return count;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/series b/xen/series
new file mode 100644
index 0000000..86adc04
--- /dev/null
+++ b/xen/series
@@ -0,0 +1,2 @@
+xen-efi-build.patch
+xen-tboot-launch.patch
diff --git a/xen/xen-efi-build.patch b/xen/xen-efi-build.patch
new file mode 100644
index 0000000..b6c091b
--- /dev/null
+++ b/xen/xen-efi-build.patch
@@ -0,0 +1,54 @@
+Index: xen-4.7.1/xen/Makefile
+===================================================================
+--- xen-4.7.1.orig/xen/Makefile
++++ xen-4.7.1/xen/Makefile
+@@ -20,6 +20,8 @@ export XEN_ROOT := $(BASEDIR)/..
+ MAKEFLAGS += -rR
+
+ EFI_MOUNTPOINT ?= $(BOOT_DIR)/efi
++EFI_VENDOR=xenefi
++LD_EFI ?= $(LD)
+
+ ARCH=$(XEN_TARGET_ARCH)
+ SRCARCH=$(shell echo $(ARCH) | sed -e 's/x86.*/x86/' -e s'/arm\(32\|64\)/arm/g')
+Index: xen-4.7.1/xen/arch/x86/Makefile
+===================================================================
+--- xen-4.7.1.orig/xen/arch/x86/Makefile
++++ xen-4.7.1/xen/arch/x86/Makefile
+@@ -168,20 +168,20 @@ endif
+
+ $(TARGET).efi: prelink-efi.o efi.lds efi/relocs-dummy.o $(BASEDIR)/common/symbols-dummy.o efi/mkreloc
+ $(foreach base, $(VIRT_BASE) $(ALT_BASE), \
+- $(guard) $(LD) $(call EFI_LDFLAGS,$(base)) -T efi.lds -N $< efi/relocs-dummy.o \
++ $(guard) $(LD_EFI) $(call EFI_LDFLAGS,$(base)) -T efi.lds -N $< efi/relocs-dummy.o \
+ $(BASEDIR)/common/symbols-dummy.o -o $(@D)/.$(@F).$(base).0 &&) :
+ $(guard) efi/mkreloc $(foreach base,$(VIRT_BASE) $(ALT_BASE),$(@D)/.$(@F).$(base).0) >$(@D)/.$(@F).0r.S
+ $(guard) $(NM) -pa --format=sysv $(@D)/.$(@F).$(VIRT_BASE).0 \
+ | $(guard) $(BASEDIR)/tools/symbols $(all_symbols) --sysv --sort >$(@D)/.$(@F).0s.S
+ $(guard) $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).0r.o $(@D)/.$(@F).0s.o
+ $(foreach base, $(VIRT_BASE) $(ALT_BASE), \
+- $(guard) $(LD) $(call EFI_LDFLAGS,$(base)) -T efi.lds -N $< \
++ $(guard) $(LD_EFI) $(call EFI_LDFLAGS,$(base)) -T efi.lds -N $< \
+ $(@D)/.$(@F).0r.o $(@D)/.$(@F).0s.o -o $(@D)/.$(@F).$(base).1 &&) :
+ $(guard) efi/mkreloc $(foreach base,$(VIRT_BASE) $(ALT_BASE),$(@D)/.$(@F).$(base).1) >$(@D)/.$(@F).1r.S
+ $(guard) $(NM) -pa --format=sysv $(@D)/.$(@F).$(VIRT_BASE).1 \
+ | $(guard) $(BASEDIR)/tools/symbols $(all_symbols) --sysv --sort >$(@D)/.$(@F).1s.S
+ $(guard) $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).1r.o $(@D)/.$(@F).1s.o
+- $(guard) $(LD) $(call EFI_LDFLAGS,$(VIRT_BASE)) -T efi.lds -N $< \
++ $(guard) $(LD_EFI) $(call EFI_LDFLAGS,$(VIRT_BASE)) -T efi.lds -N $< \
+ $(@D)/.$(@F).1r.o $(@D)/.$(@F).1s.o $(note_file) -o $@
+ if $(guard) false; then rm -f $@; echo 'EFI support disabled'; fi
+ rm -f $(@D)/.$(@F).[0-9]*
+Index: xen-4.7.1/xen/arch/x86/efi/Makefile
+===================================================================
+--- xen-4.7.1.orig/xen/arch/x86/efi/Makefile
++++ xen-4.7.1/xen/arch/x86/efi/Makefile
+@@ -6,7 +6,7 @@ create = test -e $(1) || touch -t 199901
+
+ efi := y$(shell rm -f disabled)
+ efi := $(if $(efi),$(shell $(CC) $(filter-out $(CFLAGS-y) .%.d,$(CFLAGS)) -c check.c 2>disabled && echo y))
+-efi := $(if $(efi),$(shell $(LD) -mi386pep --subsystem=10 -o check.efi check.o 2>disabled && echo y))
++efi := $(if $(efi),$(shell $(LD_EFI) -mi386pep --subsystem=10 -o check.efi check.o 2>disabled && echo y))
+ efi := $(if $(efi),$(shell rm disabled)y,$(shell $(call create,boot.init.o); $(call create,runtime.o)))
+
+ extra-$(efi) += boot.init.o relocs-dummy.o runtime.o compat.o
diff --git a/xen/xen-efi-tboot-launch.patch b/xen/xen-efi-tboot-launch.patch
new file mode 100644
index 0000000..9fb99c1
--- /dev/null
+++ b/xen/xen-efi-tboot-launch.patch
@@ -0,0 +1,284 @@
+Index: xen-4.7.1/xen/arch/x86/efi/efi-tboot.h
+===================================================================
+--- /dev/null
++++ xen-4.7.1/xen/arch/x86/efi/efi-tboot.h
+@@ -0,0 +1,35 @@
++#ifndef __EFITBOOT_H__
++#define __EFITBOOT_H__
++
++/* Shared RT variable between TBOOT and Xen */
++#define EFI_TBOOT_XEN_GUID \
++ { 0xf112e6cb, 0xce01, 0x4573, {0xa0, 0x52, 0xfb, 0xdb, 0x6c, 0xc0, 0xc7, 0xcb} }
++
++#define EFI_TBOOT_XEN_REV 1
++#define EFI_TBOOT_XEN_NAME L"TbootXenVar"
++
++static EFI_GUID __initdata TbootXenGuid = EFI_TBOOT_XEN_GUID;
++
++typedef void (*post_launch_t)(void *ets);
++
++typedef struct __packed efi_xen_tboot_data {
++ void *kernel;
++ uint64_t kernel_size;
++ void *ramdisk;
++ uint64_t ramdisk_size;
++ void *memory_map;
++ uint64_t memory_map_size;
++ uint64_t memory_desc_size;
++ uint64_t post_launch_cb;
++} efi_xen_tboot_data_t;
++
++typedef void (*begin_launch_t)(struct efi_xen_tboot_data *xtd);
++
++typedef struct __packed efi_tboot_xen_var {
++ uint64_t revision;
++ const char *xen_config;
++ uint64_t xen_config_size;
++ uint64_t begin_launch_cb;
++} efi_tboot_xen_var_t;
++
++#endif /* __EFITBOOT_H__ */
+Index: xen-4.7.1/xen/common/efi/boot.c
+===================================================================
+--- xen-4.7.1.orig/xen/common/efi/boot.c
++++ xen-4.7.1/xen/common/efi/boot.c
+@@ -79,6 +79,7 @@ static size_t wstrlen(const CHAR16 * s);
+ static int set_color(u32 mask, int bpp, u8 *pos, u8 *sz);
+ static bool_t match_guid(const EFI_GUID *guid1, const EFI_GUID *guid2);
+
++static const EFI_SYSTEM_TABLE *__initdata efi_st;
+ static const EFI_BOOT_SERVICES *__initdata efi_bs;
+ static UINT32 __initdata efi_bs_revision;
+ static EFI_HANDLE __initdata efi_ih;
+@@ -98,6 +99,14 @@ static CHAR16 __initdata newline[] = L"\
+ #define PrintStr(s) StdOut->OutputString(StdOut, s)
+ #define PrintErr(s) StdErr->OutputString(StdErr, s)
+
++/* TBOOT specific definitions */
++#include "efi-tboot.h"
++
++static struct efi_tboot_xen_var __initdata txv;
++static struct efi_xen_tboot_data __initdata xtd;
++static void* __initdata xtd_memmap;
++extern void *g_efi_tboot_shared;
++
+ /*
+ * Include architecture specific implementation here, which references the
+ * static globals defined above.
+@@ -580,6 +589,7 @@ static char *__init get_value(const stru
+ static void __init efi_init(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
+ {
+ efi_ih = ImageHandle;
++ efi_st = SystemTable;
+ efi_bs = SystemTable->BootServices;
+ efi_bs_revision = efi_bs->Hdr.Revision;
+ efi_rs = SystemTable->RuntimeServices;
+@@ -839,6 +849,95 @@ static void __init efi_variables(void)
+ }
+ }
+
++#if 0
++static void __init efi_debug_pause(void)
++{
++ EFI_STATUS status;
++ EFI_INPUT_KEY key;
++
++ PrintStr(L"Pause...");
++ efi_st->ConIn->Reset(efi_st->ConIn, FALSE);
++ while ((status = efi_st->ConIn->ReadKeyStroke(efi_st->ConIn, &key)) == EFI_NOT_READY);
++}
++#endif
++
++static void __init efi_xen_tboot_variable(void)
++{
++ EFI_STATUS status;
++ UINTN size = 0;
++
++ status = efi_rs->GetVariable(EFI_TBOOT_XEN_NAME,
++ &TbootXenGuid,
++ NULL,
++ &size,
++ NULL);
++
++ /* No TBOOT/Xen variable */
++ if ( EFI_ERROR(status) && status != EFI_BUFFER_TOO_SMALL )
++ return;
++
++ if (size != sizeof(struct efi_tboot_xen_var)) {
++ PrintStr(L"Warning: TBOOT/Xen shared variable, wrong size: ");
++ DisplayUint(size, 0);
++ PrintStr(newline);
++ return;
++ }
++
++ status = efi_rs->GetVariable(EFI_TBOOT_XEN_NAME,
++ &TbootXenGuid,
++ NULL,
++ &size,
++ &txv);
++ if ( EFI_ERROR(status) )
++ blexit(L"Unable to get TBOOT-Xen runtime variable");
++}
++
++static bool_t __init tboot_present(void)
++{
++ return (txv.revision == EFI_TBOOT_XEN_REV);
++}
++
++static void __init tboot_get_config(struct file *file)
++{
++ EFI_STATUS status;
++
++ file->addr = min(1UL << (32 + PAGE_SHIFT),
++ HYPERVISOR_VIRT_END - DIRECTMAP_VIRT_START);
++ status = efi_bs->AllocatePages(AllocateMaxAddress, EfiLoaderData,
++ PFN_UP(txv.xen_config_size), &file->addr);
++ if ( EFI_ERROR(status) )
++ blexit(L"Unable to allocate memory for TBOOT provided config");
++
++ memcpy(file->ptr, txv.xen_config, txv.xen_config_size);
++ file->size = txv.xen_config_size;
++}
++
++static void __init tboot_post_launch(void *ets)
++{
++ g_efi_tboot_shared = ets;
++
++ efi_arch_post_exit_boot();
++ for( ; ; ); /* not reached */
++}
++
++static void __init tboot_begin_launch(void)
++{
++ xtd.kernel = kernel.ptr;
++ xtd.kernel_size = kernel.size;
++ xtd.ramdisk = ramdisk.ptr;
++ xtd.ramdisk_size = ramdisk.size;
++ xtd.memory_map = xtd_memmap;
++ xtd.memory_map_size = efi_memmap_size;
++ xtd.memory_desc_size = efi_mdesc_size;
++ xtd.post_launch_cb = (uint64_t)tboot_post_launch;
++
++ __asm__ __volatile__ (
++ "call *%%rax\n\t"
++ :
++ : "a" (txv.begin_launch_cb), "c" (&xtd));
++ /* no return */
++}
++
+ static void __init efi_set_gop_mode(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, UINTN gop_mode)
+ {
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info;
+@@ -893,6 +992,9 @@ static void __init efi_exit_boot(EFI_HAN
+ if ( EFI_ERROR(status) )
+ PrintErrMesg(L"Cannot exit boot services", status);
+
++ /* Save unadjusted memmap pointer for Xen/TBOOT data */
++ xtd_memmap = efi_memmap;
++
+ /* Adjust pointers into EFI. */
+ efi_ct = (void *)efi_ct + DIRECTMAP_VIRT_START;
+ #ifdef USE_SET_VIRTUAL_ADDRESS_MAP
+@@ -924,7 +1026,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SY
+ static EFI_GUID __initdata shim_lock_guid = SHIM_LOCK_PROTOCOL_GUID;
+ EFI_LOADED_IMAGE *loaded_image;
+ EFI_STATUS status;
+- unsigned int i, argc;
++ unsigned int i, argc = 0;
+ CHAR16 **argv, *file_name, *cfg_file_name = NULL, *options = NULL;
+ UINTN gop_mode = ~0;
+ EFI_SHIM_LOCK_PROTOCOL *shim_lock;
+@@ -945,7 +1047,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SY
+
+ efi_arch_load_addr_check(loaded_image);
+
+- if ( use_cfg_file )
++ if ( use_cfg_file && !tboot_present() )
+ {
+ argc = get_argv(0, NULL, loaded_image->LoadOptions,
+ loaded_image->LoadOptionsSize, NULL);
+@@ -1004,6 +1106,9 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SY
+
+ efi_arch_relocate_image(0);
+
++ /* Find the Xen/TBOOT RT variable if booted through TBOOT */
++ efi_xen_tboot_variable();
++
+ if ( use_cfg_file )
+ {
+ EFI_FILE_HANDLE dir_handle;
+@@ -1021,7 +1126,9 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SY
+ dir_handle = get_parent_handle(loaded_image, &file_name);
+
+ /* Read and parse the config file. */
+- if ( !cfg_file_name )
++ if ( tboot_present() )
++ tboot_get_config(&cfg);
++ else if ( !cfg_file_name )
+ {
+ CHAR16 *tail;
+
+@@ -1055,6 +1162,9 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SY
+ name.s = get_value(&cfg, "global", "chain");
+ if ( !name.s )
+ break;
++ /* Chain loaded configs not OK in TBOOT land */
++ if ( tboot_present() )
++ break;
+ efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size));
+ cfg.addr = 0;
+ if ( !read_file(dir_handle, s2w(&name), &cfg, NULL) )
+@@ -1147,6 +1257,10 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SY
+
+ efi_exit_boot(ImageHandle, SystemTable);
+
++ /* Do the measured launch, end up back here if it fails. */
++ if ( tboot_present() )
++ tboot_begin_launch();
++
+ efi_arch_post_exit_boot();
+ for( ; ; ); /* not reached */
+ }
+Index: xen-4.7.1/xen/arch/x86/tboot.c
+===================================================================
+--- xen-4.7.1.orig/xen/arch/x86/tboot.c
++++ xen-4.7.1/xen/arch/x86/tboot.c
+@@ -18,6 +18,9 @@
+ static unsigned long __initdata opt_tboot_pa;
+ integer_param("tboot", opt_tboot_pa);
+
++/* Global pointer to shared data passed by EFI boot code. */
++void *g_efi_tboot_shared;
++
+ /* Global pointer to shared data; NULL means no measured launch. */
+ tboot_shared_t *g_tboot_shared;
+
+Index: xen-4.7.1/xen/include/asm-x86/tboot.h
+===================================================================
+--- xen-4.7.1.orig/xen/include/asm-x86/tboot.h
++++ xen-4.7.1/xen/include/asm-x86/tboot.h
+@@ -78,6 +78,13 @@ typedef struct __packed {
+ uint64_t kernel_s3_resume_vector;
+ } tboot_acpi_sleep_info_t;
+
++#define TB_RESMEM_BLOCKS 128
++
++typedef struct __packed {
++ uint64_t addr;
++ uint64_t length;
++} reserve_map_t;
++
+ typedef struct __packed {
+ /* version 3+ fields: */
+ uuid_t uuid; /* {663C8DFF-E8B3-4b82-AABF-19EA4D057A08} */
+@@ -102,6 +109,10 @@ typedef struct __packed {
+ uint32_t flags;
+ uint64_t ap_wake_addr; /* phys addr of kernel/VMM SIPI vector */
+ uint32_t ap_wake_trigger; /* kernel/VMM writes APIC ID to wake AP */
++ /* version 7+ fields */
++ /* reserve mem blocks to adjust dom0 E820 */
++ uint64_t reserve_map_count;
++ reserve_map_t reserve_map[TB_RESMEM_BLOCKS];
+ } tboot_shared_t;
+
+ #define TB_SHUTDOWN_REBOOT 0
diff --git a/xen/xen.cfg b/xen/xen.cfg
new file mode 100755
index 0000000..90ed897
--- /dev/null
+++ b/xen/xen.cfg
@@ -0,0 +1,7 @@
+[global]
+default=xenefi
+
+[xenefi]
+options=console=vga,com1 com1=115200,8n1,pci vga=current loglvl=debug noreboot
+kernel=vmlinuz-4.8.10-300.fc25.x86_64 root=UUID=4ccca39c-b9a3-4426-a171-30cf173bd274 ro rhgb console=hvc0
+ramdisk=initramfs-4.8.10-300.fc25.x86_64.img