From 4c87a1868835d05f1cadae7b8ad6a7c95d9d9c0e Mon Sep 17 00:00:00 2001 From: Ross Philipson Date: Tue, 14 Mar 2017 15:40:33 -0400 Subject: Initial commit of EFI TBOOT work from internal project. Signed-off-by: Ross Philipson --- README | 167 +++ tboot/Makefile | 49 + tboot/README | 213 ++++ tboot/acmod.c | 991 ++++++++++++++++ tboot/acpi.c | 482 ++++++++ tboot/bits.S | 166 +++ tboot/cmdline.c | 606 ++++++++++ tboot/com.c | 134 +++ tboot/efiboot.c | 613 ++++++++++ tboot/eficonfig.c | 299 +++++ tboot/eficore.c | 534 +++++++++ tboot/efimemmap.c | 276 +++++ tboot/errors.c | 285 +++++ tboot/genlds.sh | 19 + tboot/hash.c | 193 ++++ tboot/heap.c | 818 +++++++++++++ tboot/include/acpi.h | 518 +++++++++ tboot/include/atomic.h | 181 +++ tboot/include/cmdline.h | 76 ++ tboot/include/com.h | 311 +++++ tboot/include/compiler.h | 52 + tboot/include/config.h | 133 +++ tboot/include/ctype.h | 103 ++ tboot/include/efibase.h | 46 + tboot/include/eficonfig.h | 109 ++ tboot/include/eficore.h | 134 +++ tboot/include/hash.h | 123 ++ tboot/include/integrity.h | 106 ++ tboot/include/io.h | 91 ++ tboot/include/lcp3.h | 282 +++++ tboot/include/lcp3_hlp.h | 117 ++ tboot/include/misc.h | 95 ++ tboot/include/mle.h | 96 ++ tboot/include/msr.h | 90 ++ tboot/include/mutex.h | 58 + tboot/include/page.h | 66 ++ tboot/include/paging.h | 122 ++ tboot/include/pci_cfgreg.h | 73 ++ tboot/include/printk.h | 79 ++ tboot/include/processor.h | 340 ++++++ tboot/include/rijndael.h | 58 + tboot/include/sha1.h | 77 ++ tboot/include/sha256.h | 30 + tboot/include/string.h | 73 ++ tboot/include/tb_error.h | 89 ++ tboot/include/tb_policy.h | 388 +++++++ tboot/include/tboot.h | 197 ++++ tboot/include/tpm.h | 521 +++++++++ tboot/include/tpm_20.h | 1503 ++++++++++++++++++++++++ tboot/include/txt/acmod.h | 195 ++++ tboot/include/txt/config_regs.h | 240 ++++ tboot/include/txt/errorcode.h | 105 ++ tboot/include/txt/heap.h | 377 ++++++ tboot/include/txt/mtrrs.h | 149 +++ tboot/include/txt/smx.h | 171 +++ tboot/include/txt/txt.h | 76 ++ tboot/include/txt/verify.h | 57 + tboot/include/txt/vmcs.h | 346 ++++++ tboot/include/types.h | 104 ++ tboot/include/uuid.h | 82 ++ tboot/include/vga.h | 87 ++ tboot/include/vmac.h | 168 +++ tboot/launch.S | 484 ++++++++ tboot/misc.c | 455 ++++++++ tboot/mtrrs.c | 624 ++++++++++ tboot/pci_cfgreg.c | 173 +++ tboot/policy.c | 879 ++++++++++++++ tboot/printk.c | 195 ++++ tboot/rijndael.c | 1270 +++++++++++++++++++++ tboot/sha1.c | 265 +++++ tboot/sha256.c | 242 ++++ tboot/string.c | 204 ++++ tboot/tb_error.c | 196 ++++ tboot/tboot.c | 473 ++++++++ tboot/tboot.cfg | 17 + tboot/tpm.c | 911 +++++++++++++++ tboot/tpm_12.c | 1952 +++++++++++++++++++++++++++++++ tboot/tpm_20.c | 2406 +++++++++++++++++++++++++++++++++++++++ tboot/txt.c | 755 ++++++++++++ tboot/verify.c | 601 ++++++++++ tboot/vga.c | 140 +++ tboot/vmac.c | 1228 ++++++++++++++++++++ tboot/vmcs.c | 603 ++++++++++ tboot/vsprintf.c | 465 ++++++++ xen/series | 2 + xen/xen-efi-build.patch | 54 + xen/xen-efi-tboot-launch.patch | 284 +++++ xen/xen.cfg | 7 + 88 files changed, 29224 insertions(+) create mode 100644 README create mode 100644 tboot/Makefile create mode 100644 tboot/README create mode 100644 tboot/acmod.c create mode 100644 tboot/acpi.c create mode 100644 tboot/bits.S create mode 100644 tboot/cmdline.c create mode 100644 tboot/com.c create mode 100644 tboot/efiboot.c create mode 100644 tboot/eficonfig.c create mode 100644 tboot/eficore.c create mode 100644 tboot/efimemmap.c create mode 100644 tboot/errors.c create mode 100755 tboot/genlds.sh create mode 100644 tboot/hash.c create mode 100644 tboot/heap.c create mode 100644 tboot/include/acpi.h create mode 100644 tboot/include/atomic.h create mode 100644 tboot/include/cmdline.h create mode 100644 tboot/include/com.h create mode 100644 tboot/include/compiler.h create mode 100644 tboot/include/config.h create mode 100644 tboot/include/ctype.h create mode 100644 tboot/include/efibase.h create mode 100644 tboot/include/eficonfig.h create mode 100644 tboot/include/eficore.h create mode 100644 tboot/include/hash.h create mode 100644 tboot/include/integrity.h create mode 100644 tboot/include/io.h create mode 100644 tboot/include/lcp3.h create mode 100644 tboot/include/lcp3_hlp.h create mode 100644 tboot/include/misc.h create mode 100644 tboot/include/mle.h create mode 100644 tboot/include/msr.h create mode 100644 tboot/include/mutex.h create mode 100644 tboot/include/page.h create mode 100644 tboot/include/paging.h create mode 100644 tboot/include/pci_cfgreg.h create mode 100644 tboot/include/printk.h create mode 100644 tboot/include/processor.h create mode 100644 tboot/include/rijndael.h create mode 100644 tboot/include/sha1.h create mode 100644 tboot/include/sha256.h create mode 100644 tboot/include/string.h create mode 100644 tboot/include/tb_error.h create mode 100644 tboot/include/tb_policy.h create mode 100644 tboot/include/tboot.h create mode 100644 tboot/include/tpm.h create mode 100644 tboot/include/tpm_20.h create mode 100644 tboot/include/txt/acmod.h create mode 100644 tboot/include/txt/config_regs.h create mode 100644 tboot/include/txt/errorcode.h create mode 100644 tboot/include/txt/heap.h create mode 100644 tboot/include/txt/mtrrs.h create mode 100644 tboot/include/txt/smx.h create mode 100644 tboot/include/txt/txt.h create mode 100644 tboot/include/txt/verify.h create mode 100644 tboot/include/txt/vmcs.h create mode 100644 tboot/include/types.h create mode 100644 tboot/include/uuid.h create mode 100644 tboot/include/vga.h create mode 100644 tboot/include/vmac.h create mode 100644 tboot/launch.S create mode 100644 tboot/misc.c create mode 100644 tboot/mtrrs.c create mode 100644 tboot/pci_cfgreg.c create mode 100644 tboot/policy.c create mode 100644 tboot/printk.c create mode 100644 tboot/rijndael.c create mode 100644 tboot/sha1.c create mode 100644 tboot/sha256.c create mode 100644 tboot/string.c create mode 100644 tboot/tb_error.c create mode 100644 tboot/tboot.c create mode 100644 tboot/tboot.cfg create mode 100644 tboot/tpm.c create mode 100644 tboot/tpm_12.c create mode 100644 tboot/tpm_20.c create mode 100644 tboot/txt.c create mode 100644 tboot/verify.c create mode 100644 tboot/vga.c create mode 100644 tboot/vmac.c create mode 100644 tboot/vmcs.c create mode 100644 tboot/vsprintf.c create mode 100644 xen/series create mode 100644 xen/xen-efi-build.patch create mode 100644 xen/xen-efi-tboot-launch.patch create mode 100755 xen/xen.cfg 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 + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 \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 \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 \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 \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(¶ms) ) { + 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(¶ms) ) { + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * + * 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 + +#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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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=[/][,[,[,[,[,]]]]] */ + { "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><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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 (< ) RAM region of at least 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; icount; 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 + * Copyright (c) 2005 Marco Peereboom + * + * 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 +#include +#include + +/* 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 + * + * 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 +#include +#include + +#include +#include + +#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 + * + * 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 + * + * 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 +#include + +/* + * 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 + * 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 + * 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 +#include + +#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 + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * 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 + */ + +#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 +#include + +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 +#include +#include +#include + +/* 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 +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 +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 +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 +typedef u16 TPM_SU; + +#define TPM_SU_CLEAR (TPM_SU)(0x0000) +#define TPM_SU_STATE (TPM_SU)(0x0001) + +// Table 21 -- TPM_CAP Constants +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 +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 +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 +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 +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 +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 +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 +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 +typedef struct { + u16 hash_alg; + TPMU_HA digest; +} TPMT_HA; + +// Table 68 -- TPM2B_DIGEST Structure +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 +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 +typedef TPM2B_DIGEST TPM2B_NONCE; + +// Table 71 -- TPM2B_AUTH Types +typedef TPM2B_DIGEST TPM2B_AUTH; + +// Table 73 -- TPM2B_EVENT Structure +typedef struct { + u16 size; + u8 buffer[1024]; +} EVENT_2B; + +typedef union { + EVENT_2B t; + TPM2B b; +} TPM2B_EVENT; + +// Table 74 -- TPM2B_MAX_BUFFER Structure +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 +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 +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 +typedef struct { + u16 hash; + u8 size_of_select; + u8 pcr_select[PCR_SELECT_MAX]; +} TPMS_PCR_SELECTION; + +// Table 84 -- TPMT_TK_CREATION Structure +typedef struct { + u16 tag; + u32 hierarchy; + TPM2B_DIGEST digest; +} TPMT_TK_CREATION; + +// Table 86 -- TPMT_TK_HASHCHECK Structure +typedef struct { + u16 tag; + u32 hierarchy; + TPM2B_DIGEST digest; +} TPMT_TK_HASHCHECK; + +// Table 88 -- TPMS_ALG_PROPERTY Structure +typedef struct { + u16 alg; + TPMA_ALGORITHM alg_pro; +} TPMS_ALG_PROPERTY; + +// Table 95 -- TPML_DIGEST Structure +typedef struct { + u32 count; + TPM2B_DIGEST digests[8]; +} TPML_DIGEST; + +// Table 96 -- TPML_DIGEST_VALUES Structure +typedef struct { + u32 count; + TPMT_HA digests[HASH_COUNT]; +} TPML_DIGEST_VALUES; + +// Table 98 -- TPML_PCR_SELECTION Structure +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 +typedef struct { + u32 count; + TPMS_ALG_PROPERTY alg_pros[MAX_CAP_ALGS]; +} TPML_ALG_PROPERTY; + +// Table 103 -- TPMU_CAPABILITIES Union +typedef union { + TPML_ALG_PROPERTY algs; +} TPMU_CAPABILITIES; + +// Table 104 -- TPMS_CAPABILITY_DATA Structure +typedef struct { + u32 capability; + TPMU_CAPABILITIES data; +} TPMS_CAPABILITY_DATA; + +// Table 122 -- TPMU_SYM_KEY_BITS Union +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 +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 +typedef struct { + u16 alg; + TPMU_SYM_KEY_BITS key_bits; + TPMU_SYM_MODE mode; +} TPMT_SYM_DEF_OBJECT; + +// Table 126 -- TPM2B_SYM_KEY Structure +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 +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 +typedef struct { + TPM2B_AUTH user_auth; + TPM2B_SENSITIVE_DATA data; +} TPMS_SENSITIVE_CREATE; + +// Table 131 -- TPM2B_SENSITIVE_CREATE Structure +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 +typedef struct { + u16 hash_alg; +} TPMS_SCHEME_SIGHASH; + +// Table 134 -- HMAC_SIG_SCHEME Types +typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_HMAC; + +// Table 135 -- TPMS_SCHEME_XOR Structure +typedef struct { + u16 hash_alg; + u16 kdf; +} TPMS_SCHEME_XOR; + +// Table 136 -- TPMU_SCHEME_KEYEDHASH Union +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 +typedef struct { + u16 scheme; + TPMU_SCHEME_KEYEDHASH details; +} TPMT_KEYEDHASH_SCHEME; + +// Table 138 -- RSA_SIG_SCHEMES Types +typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_RSASSA; +typedef TPMS_SCHEME_SIGHASH TPMS_SCHEME_RSAPSS; + +// Table 139 -- ECC_SIG_SCHEMES Types +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 +typedef struct { + u16 hash_alg; + u16 count; +} TPMS_SCHEME_ECDAA; + +// Table 141 -- TPMU_SIG_SCHEME Union +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 +typedef struct { + u16 hash_alg; +} TPMS_SCHEME_OAEP; + +// Table 145 -- TPMS_SCHEME_MGF1 Structure +typedef struct { + u16 hash_alg; +} TPMS_SCHEME_MGF1; + +// Table 146 -- TPMS_SCHEME_KDF1_SP800_56a Structure +typedef struct { + u16 hash_alg; +} TPMS_SCHEME_KDF1_SP800_56a; + +// Table 147 -- TPMS_SCHEME_KDF2 Structure +typedef struct { + u16 hash_alg; +} TPMS_SCHEME_KDF2; + +// Table 148 -- TPMS_SCHEME_KDF1_SP800_108 Structure +typedef struct { + u16 hash_alg; +} TPMS_SCHEME_KDF1_SP800_108; + +// Table 149 -- TPMU_KDF_SCHEME Union +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 +typedef struct { + u16 scheme; + TPMU_KDF_SCHEME details; +} TPMT_KDF_SCHEME; + +// Table 152 -- TPMU_ASYM_SCHEME Union +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 +typedef struct { + u16 scheme; + TPMU_ASYM_SCHEME details; +} TPMT_RSA_SCHEME; + +// Table 158 -- TPM2B_PUBLIC_KEY_RSA Structure +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 +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 +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 +typedef struct { + TPM2B_ECC_PARAMETER x; + TPM2B_ECC_PARAMETER y; +} TPMS_ECC_POINT; + +// Table 166 -- TPMT_ECC_SCHEME Structure +typedef struct { + u16 scheme; + TPMU_SIG_SCHEME details; +} TPMT_ECC_SCHEME; + +// Table 176 -- TPMU_PUBLIC_ID Union +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 +typedef struct { + TPMT_KEYEDHASH_SCHEME scheme; +} TPMS_KEYEDHASH_PARMS; + +// Table 178 -- TPMS_ASYM_PARMS Structure +typedef struct { + TPMT_SYM_DEF_OBJECT symmetric; + TPMT_ASYM_SCHEME scheme; +} TPMS_ASYM_PARMS; + +// Table 179 -- TPMS_RSA_PARMS Structure +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 +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 +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 +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 +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 +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 +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 +typedef struct { + u16 size; + u8 buffer[sizeof(_PRIVATE)]; +} PRIVATE_2B; + +typedef union { + PRIVATE_2B t; + TPM2B b; +} TPM2B_PRIVATE; + +// Table 195 -- TPMA_NV Bits +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 +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 +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 +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 +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 + +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 + +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 + +#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 +#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 +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 + * + * 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 +#include +#include +#include + +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * Copyright (c) 2000, Michael Smith + * Copyright (c) 2000, BSDi + * Copyright (c) 2004, Scott Long + * 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 +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define PRINT printk +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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; icount; i++) { + for (unsigned int j=0; jentries[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; kentries[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; icount; 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 | */ + /* where 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; ialg_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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * 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 +//#include + +//#include +#include +#include +#include +#include + +#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 + */ + +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + +/* 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 +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +__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, ®_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, ®_ctrl_request); + + return true; + } + + reg_ctrl_request._raw[0] = 0; + reg_ctrl_request.goIdle = 1; + write_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); + + uint32_t i = 0; + do { + read_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_ctrl_request); + if ( reg_ctrl_request.goIdle == 0) + break; + else { + cpu_relax(); + read_tpm_reg(locality, TPM_CRB_CTRL_REQ, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_acc); + + i = 0; + do { + read_tpm_reg(locality, TPM_REG_ACCESS, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_acc); + + i = 0; + do { + read_tpm_reg(locality, TPM_REG_ACCESS, ®_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, ®_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, ®_loc_ctrl); + + i = 0; + do { + read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_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, ®_loc_ctrl); + + i = 0; + do { + read_tpm_reg(locality, TPM_REG_LOC_STATE, ®_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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; icount; 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; kselections[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; icount; 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; kselections[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; isize; 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; isize; 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; icount; 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; inum_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; inum_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; icount; 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; kdigests[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; icount; 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; kdigests[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; icount; 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 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; jcount; 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; ibanks; 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; ibanks; 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; ibanks; 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; ialg_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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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; icount; 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; icount; 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(¶ms) ) { + 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++, ¶m_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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +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 +//#include +/* start for tboot */ +#include +#include +#include +#include +/*#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 +#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 + +#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 +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* 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 +#include +#include +#include +#include +#include +#include + +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 -- cgit v1.2.3