tboot-1.8.0/.hg_archival.txt0000644000000000000000000000017212272416301014061 0ustar 00000000000000repo: cedd93279188334eb41d248d5eb70a41a2bc70ca node: f9bc5388f99f88d69d41fcf42acac18add9b9c98 branch: default tag: v1.8.0 tboot-1.8.0/.hgignore0000644000000000000000000000135112272416301012576 0ustar 00000000000000.*\.a$ .*\.cmi$ .*\.cmo$ .*\.d$ .*\.o$ .*\.o.*$ .*\.opic$ .*\.pyc$ .*\.so$ .*\.ko$ .*\.so\..*$ .*\.tar\.bz2$ .*\.tar\.gz$ .*~$ \#*\#$ .*\.flc$ .*\.orig$ .*\.rej$ .*/a\.out$ .*/Modules\.symvers$ .*/cscope\..*$ ^cscope.*$ ^[^/]*\.bz2$ ^\.config$ ^\.pc ^TAGS$ ^tags$ ^build-.*$ ^dist/.*$ ^tboot/common/tboot.lds$ ^tboot/tboot$ ^tboot/tboot-syms$ ^tboot/tboot.gz$ ^lcptools/tpmnv_defindex$ ^lcptools/tpmnv_getcap$ ^lcptools/tpmnv_lock$ ^lcptools/tpmnv_relindex$ ^lcptools/lcp_crtpconf$ ^lcptools/lcp_crtpol$ ^lcptools/lcp_mlehash$ ^lcptools/lcp_readpol$ ^lcptools/lcp_writepol$ ^lcptools/lcp_crtpol2$ ^lcptools/lcp_crtpolelt$ ^lcptools/lcp_crtpollist$ ^lcptools/trousers_dep$ ^tb_polgen/tb_polgen$ ^utils/acminfo$ ^utils/txt-stat$ ^utils/parse_err$ tboot-1.8.0/.hgtags0000644000000000000000000000067012272416301012254 0ustar 00000000000000dc19897ffffaca8f90aa3234c4eb85e12cfdedf8 v1.7.2-rc1 b911c1cdd9f294d8be5e716c5b3f55bccd977fbe v1.7.2 0000000000000000000000000000000000000000 v1.7.2 bd086f9ac6abcc4403a4fd32ce2604882025bc2c v1.7.2 221ec0974a31576ce197aa9ce793925b1cca0cfc v1.7.3-rc1 feeb4cc736710d1b6abbb6561a31737f19d10021 v1.7.3 794e9c2ef61a9a8911b9b58b2f3f3724bf3873be v1.7.4 794e9c2ef61a9a8911b9b58b2f3f3724bf3873be v1.7.4 5dabe616dbdcb6a138eaf1c00ce8c980993fc545 v1.7.4 tboot-1.8.0/CHANGELOG0000644000000000000000000003734212272416301012216 0ustar 0000000000000020140130: v1.8.0 Update README for TPM2 support tpm2 support Adding sha256 algorithm implementation Update README for TPM NV measuring Update README for EFI support Fix typo in tboot/Makefile Increase the supported maximum number of cpus from 256 to 512 Extend tboot policy supporting measuring TPM NV EFI support via multiboot2 changes Fix typo in common/hash.c Fix verification for extended data elements in txt heap 20130705: v1.7.4 Fix possible empty submenu block in generated grub.cfg Add a call_racm=check option for easy RACM launch result check Fix type check for revocation ACM. 20121228: v1.7.3 Update README with updated code repository url. Fix grub2 scripts to be compatible with more distros. Update README for RACM launch support Add a new option "call_racm=true|false" for revocation acm(RACM) launch Fix potential buffer overrun & memory leak in crtpconf.c Fix a potential buffer overrun in lcptools/lock.c Print cmdline in multi-lines Optional print TXT.ERRORCODE under level error or info Fix side effects of tboot log level macros in tools Update readme for the new detail log level Classify all logs into different log levels Add detail log level and the macros defined for log level Fix acmod_error_t type to correctly align all bits in 4bytes 20120929: v1.7.2 Add Makefile for docs to install man pages. Add man pages for tools Add grub-mkconfig helper scripts for tboot case in GRUB2 Fix for deb build in ubuntu Fix S3 issue brought by c/s 308 Fix a S4 hang issue and a potential shutdown reset issue Fix build with new zlib 1.2.7. Initialize event log when S3 Update README to change upstream repo url from bughost.org to sf.net. 20120427: v1.7.1 Fix cmdline size in tb_polgen Add description for option min_ram in README. new tboot cmdline option "min_ram=0xXXXXXX" Update test-patches/tpm-test.patch to fit in latest code. 20120115: v1.7.0 Print version number while changeset info unavailable Document DA changes in README Add event log for PCR extends in tboot Follow details / authorities PCR mapping style in tboot Support details / authorities PCR mapping Support TPM event log fix build issue for txt-stat in 64 bit environment. update README for mwait AP wakeup mechanism tboot: provide a new AP wakeup way for OS/VMM - mwait then memory write Original txt-stat.c doesn't display TXT heap info by default. Add command line options to display help info and optionally enable displaying heap info. Fix a shutdown issue on heavily throttled large server Adjust mle_hdr.{mle|cmdline}_{start|end}_off according to CS285,286 changes to give lcp_mlehash correct info to produce hash value. Fix boot issue caused by including mle page table into tboot memory Fix for possible overwritting to mle page table by GRUB2 Add PAGE_UP() fn that rounds things up/donw to a page. Update get_mbi_mem_end() with a accurate, safer calculating way ACPI fix and sanity check Add some sanity check before using mods_count in a count-down loop TPM: add waiting on expect==0 before issue tpmGo txt-stat: Don't show heap info by default. Exchange definitions for TBOOT_BASE_ADDR & TBOOT_START Add const qualifier for suibable parms of all possible fns. fix possible mbi overwrite issue for Linux with grub2 enhance print_mbi() to print more mbi info for debug purpose Fix for GRUB2 loading elf image such as Xen. Move apply_policy() call into txt_post_launch() Don't zap s3_key in tboot shared page if sealing failed due to tpm unowned Update the explanation of signed lists to make it clearer. tboot: add a fall back for reboot via keyboard reset vector tboot: revise README to explain how to configure GRUB2 config file for tboot tboot: rewrite acpi reg access fns to refer to bit_width instead of access_width tboot: change reboot mechanism to use keyboard reset vector tboot: handle mis-programmed TXT config regs and TXT heap gracefully tboot: add warning when TPM timeout values are wrong all PM1_CNT accesses should be 16bit. Enlarge NR_CPUS from 64 to 256 Add support for SBIOS policy element type (LCP_SBIOS_ELEMENT) to lcp_crtpolelt Fix processor id list matching between platform and acmod Make lcp_crtpollist support empty lists (i.e. with no elements) print a bit more error reasons in txt-stat Fix segmentation fault in txt-stat on some systems 20110429: v1.5.0 Fix build errors under Fedora 15 Various cleanups to output and checks to make it more readable Removed PAGE_SIZE/PAGE_SHIFT requirements from utils/* Added definitions of PAGE_SIZE and PAGE_SHIFT to acminfo.c Fix display of TXT.ERRORCODE values Added Developer's Certificate of Origin 1.1 to README Add support for TXT heap extended data elements and BiosData version 4 Removed some fields and changed names for some TXT configuration space registers Add support for AC Module chipset info table version 4 (ProcessorIDList) Separate AC Module subtype field from type field in ACM header Fixed error in description of what is extended to PCRs 17, 18, and 19. Fix tboot Makefile to make object files explicit in order to avoid incorrect ordering Removed no_usb command line parameter and SMI disabling Fixed bug with PCONF elements not displaying correctly Support MAXPHYADDR > 36b Reversed and rewrote c/s 225 for wrapping tboot policy in LCP custom element to store tb policy in the LCP PO index. Added the log level support. Clean up build Trigger TB_ERR_S3_INTEGRITY and don't call verify_integrity() if a measured launch is not performed on S3 resume. Then the policy decides whether to continue unmeasured S3 launch or not. verify_integrity() should be called after TXT is launched on S3 resume. Continue to fix the error message "response size incorrect". Add checking whether a given index exists by its public data in TPM NV, because the original "response size incorrect" is not clear to describe the error message. Make default parameter values for command line parameters consistent with the default initialized values. Fixed to support offsetof definition for gcc 3.X and below. Moved utility binaries (lcptools/*, tb_polgen, utils/*) to /usr/sbin to conform to convention for non-critical system utilities Re-licensing tboot/include/printk.h to BSD Fixed a bug in txt-stat. In tboot_log_t, char *buf will occupy 4 bytes on 32bit system and 8 bytes on 64bit. Both sizeof(*log) and offsetof(tboot_log_t, buf) cannot get the accurate position of the log memory, which might cause some characters missing in the log printed by running "txt-stat". Removed end-of-line CRs from README file Moved definitions of tpm_pcrvalue_t and tpm_pcr_composite_t from lcp2.h back to pconf_elt.c, sinc they are only needed by pconf_elt.c Fixed the bug in pconf creation. Pause when transferring to VMM/kernel and SINIT by GETSEC[SENTER]. Again, clean the code and fix to see the first few lines of tboot output and sync-up serial port output with vga output when pause. Fix the compile error for c/s 225 Use LCP_POLELT_TYPE_CUSTOM to wrap tboot policy, so tboot policy is allowed to be stored in the LCP index and be signed, etc. Additionally tboot code unwraps the policy from the PO index. Change to use time-based timeout instead of counter-based timeout for tpm_save_state(). Fixed option values in tb_polgen Fix build error in lcptools on systems that don't support 'ehco -e' Change serial command line option back to original format Removed htobeXX() fns because not supported in older glibc Fix build error (on some systems) in lcptools Fix print_mbi() to have more useful and properly-formatted output Disable legacy USB SMIs by default Fixed bug in creation of LCP_PCONF_ELEMENT Fix build errors with gcc v4.1.2 Add timeout ot comc_setup() and don't re-initialize serial on shutdown Added additional compiler warnings and cleaned up code to build cleanly Merge Fixes support for PCI serial cards Fixed buffer overrun errors in lcptools/ and compilation error on some systems in utils/ Fix build error Improve efficiency of div64() All non-BSD compatible files rmeoved and functionality replaced by BSD compatible code Fix bug where some e820 configurations would case recent USB-related fix code to reserve too much memory Fix S3 resume path to not call copy_e820_table() Remove SINITs and LCP policy data files from module list before modules are verified and measured Fix issue where tboot would appear to hang after SENTER on some BIOSes (due to DMA protecting legacy USB buffers) Fixed build inconsistencies Always extend PCRs on S3 integrity creation/verification Added support for 'vga_delay' command line option Fix bug in TXT.VER.EMIF/FSBIF handling Fixed debug chipset detection Fix for changed defn. of is_acmod() Add support for choosing correct SINIT ACM from multiple loaded modules This patch is to clean up the code by clearing all blank spaces at the end of This patch changes VMAC_NHBYTES from the standard 128 to 4K in order to improve the performance of MACing. This patch adds pae paging support into tboot for tboot to access >4GB memory during S3 MACing. Walkaround for pvops to read public config registers. Explicitly link lcp_mlehash with libz Don't write to tboot's launch error index if it doesn't exist Merge TPM timeout workaround Workaround for TPMs with incorrect timeout values This patch reimplements memory reading by lseek()/read() in order to fix mmap() issue which causes dom0 hangs under pvops. Added dependency to give "friendly" error if trousers is not installed Fix build error Add support for LCP v2, as defined in December 2009 MLE Developers Guide chapt. 3 and Appendix E Moved acminfo and txt-stat from txt-test to (new) utils directory and added parse_err utility Removed trousers sub-project Update for latest TXT data structures and GETSEC[PARAMETERS] type Handle case where BSP does not have APIC ID 0 Support TPMs that return TPM_RETRY for TPM_SaveState command Fix one more '&' to '&&' ocurrence. Fix bug with '&' instead of '&&'. Fixed a timeout bug in 163 Added text that repo chnages are sent to tboot-changelog@lists.sourceforge.net mailing list. Updated README about e820 table memory types used. Updated README with the fact that TXT support is now part of the 2.6.32 kernel. add gzip lib to fix build errors Fixed "Handle page table addr in ECX", some SINITs are not fully ready for this. Fixed overflow check in folder txt-test. Add MSEG verification. Continue to fix build warning on ubuntu 4.3.2 Fix the build warning with gcc 4.3.2 on ubuntu 4.3.2 Check the return values from some functions. Check overflow for uint32_t, and some other types. Before checking bios data, check TXT supported Read real TIMEOUT values from TPM and set timeout Handle page table addr in ECX Fix the potential segmentation fault in find_mle_hdr, Changed mechanism for initializing VMCS controls; changed license to BSD Copy LCP owner policy data (if present) to buffer in os_mle_data Create common fn to determine end addr of tboot; don't set boot_params->tboot_shared_addr if launching Linux w/o TXT Fix locking for AP wakeup and WFS If APIC ID of AP exceeds NR_CPUS, put AP into hlt loop Increase NR_CPUS to allow for discontiguous APIC IDs on some systems Update spinlock.h with latest Xen code Reserved tboot's memory as E820_RESERVED if launching Linux; fix tboot image size Clear key from memory even when seal/unseal fails Fix bug in tpm_write_cmd_fifo() when tracing TPM data Ensure that memory region chosen for initrd is large enough Changed passing of shared page for Linux to use new field in boot_params This is a test. Fix bug with calling verify_modules() on S3 resume patch Added -Wformat-security to Config.mk to catch additional errors and fixed resulting warnings; also fixed some warnings that are generated by gcc v4.4 Fixed bug in tpm_seal() with setting of localityAtCreation and added fallback for tpm_get_random() Remove SINIT and LCP data modules from mbi structure when not doing measured launch Do TPM_SaveState as last TPM command 20090330: Added s3_key and num_in_wfs fields to tboot_shared_t and rev'ed version to 5 Use VMAC as S3 integrity MAC algo Changed tboot load/start addr to 0x800000 (8MB) Fixed support for newer Linux kernels Support TB_SHUTDONW_WFS shutdown type for APs Misc. fixes 20090130: Fixed build issues with newer versions of gcc (e.g. in Fedora 9) Increased CPU/core/thread support to 32 CPUs/cores/threads Simpified tboot build process to be that of standard ELF binary Enhanced logging support (see README) Include tboot command line in its hash; support for including command line in hash added to lcp_mlehash Always extend measurement of module 0 to PCR 18 Added verification of memory layout on launch Set VT-d PMR protections to cover all usable RAM Misc. fixes 20081008: Fixed build error in lcptools/ 20081007: Updated README and doc/* files Fixed support for in-memory serial log Fixes and enhancements to txt-stat Changed policy format (see doc/policy.txt for new command syntax) Added support for launching Linux kernels >= 2.6.20 (Linux kernel patches will be available on LKML) Fixed build errors under gcc v4.3.0+ 20080609: Removed support for Technology Enabling Platform (TEP) Removed support for SINIT AC module versions <16 (i.e. <= 20070910) Updated per changes in May 2008 Intel(R) TXT MLE Developer's Manual: Updated to MLE (header) version 2.0 Updated OsSinitData, SinitMleData structs Updated AC module InfoTable struct Support Capabilities fields Support MONITOR-based RLP wakeup Added acminfo app to parse and display AC module information Updated for v3 of BiosData struct Reduced TPM-related serial output Fixed sealing of hashes for restoring PCRs after S3 resume Misc. fixes and code cleanup 20080523: Updated TrouSerS version to 0.3.1 and to download it from its SF site Fixed several items regarding TPM: call TPM_SaveState in case launching kernel that does not, so that S3 resume will restore SRTM PCRs support for TPMs with an Idle state fixed timeout values per TCG spec enforce that TPM is activated and enabled (or fail launch) misc. fixes Fixed failure paths to apply policy Enhancements to and cleanup of policy support Cap PCRs on exit Added txt-stat app to display TXT config registers and status info S3 fixes Added 'loglvl' command line option to control serial output Handle unordered and overlapping e820 tables Misc. fixes and code cleanup 20071128: Added '-f' command line option to lcptools/tpmnv_getcap to display the TPM_PERMANENT_FLAGS and TPM_STCLEAR_FLAGS contents Revised the docs/policy.txt steps Code and build re-factoring and cleanup (default target is now 'build') Make memory logging build-time optional and disable by default Support >2 cores/threads Move tboot to load and execute at 16MB (this also now protects it from dom0 access since it's memory type can be E820_UNUSABLE now) *** this requires a patch to Xen *** The Xen command line shoudl have 'no-real-mode' removed and 'vtd=1' added (as indicated in the updated docs/tboot-info.txt) setting 'vtd=1' is optional but some systems fail to boot dom0 otherwise *** setting 'vtd=1' will cause S3 resume to fail *** Updated trousers sub-directory to download 0.3.1 version from TrouSerS SourceForge site and build it 20071029: Moved build_tools target into top-level Makefile Put 'tboot=0x1234' (where 1234 is the addr of the tboot_shared data) on VMM/kernel command line, per latest Xen feedback Changed TB_LAUNCH_ERR_IDX to 0x20000002 Made TPM detailed debug ouput conditional Changes TBOOT_S3_WAKEUP_ADDR to 0x8a000 to ensure no conflicts 20071026: Initial version. tboot-1.8.0/COPYING0000644000000000000000000000027412272416301012031 0ustar 00000000000000Files which do not contain any copyright information are assumed to be copyrighted by Intel Corporation. All other files contain their copyright and license at the beginning of the file. tboot-1.8.0/Config.mk0000644000000000000000000000370312272416301012534 0ustar 00000000000000# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # global build settings # # supported targets .PHONY: all build install dist clean distclean mrproper # Default target all : build # debug build debug ?= n # for dist targets ifdef DESTDIR DISTDIR = $(DESTDIR) else DISTDIR ?= / endif DESTDIR ?= $(ROOTDIR)/dist dist : DISTDIR=$(DESTDIR) # # tools and flags for components built to run on build (host) # # cc-option: Check if compiler supports first option, else fall back to second. # Usage: cflags-y += $(call cc-option,$(CC),-march=winchip-c6,-march=i586) cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \ /dev/null 2>&1`"; then echo "$(2)"; else echo "$(3)"; fi ;) CFLAGS_WARN = -Wall -Wformat-security -Werror -Wstrict-prototypes \ -Wextra -Winit-self -Wswitch-default -Wunused-parameter \ -Wwrite-strings \ $(call cc-option,$(CC),-Wlogical-op,) \ -Wno-missing-field-initializers \ -D_FORTIFY_SOURCE=2 AS = as LD = ld CC = gcc CPP = cpp AR = ar RANLIB = ranlib NM = nm STRIP = strip OBJCOPY = objcopy OBJDUMP = objdump ifeq ($(debug),n) INSTALL_STRIP = -s endif INSTALL = install INSTALL_DIR = $(INSTALL) -d -m0755 -p INSTALL_DATA = $(INSTALL) -m0644 -p INSTALL_PROG = $(INSTALL) $(INSTALL_STRIP) -m0755 -p # # tools and flags for components built to run on target # TARGET_ARCH ?= $(shell uname -m | sed -e s/i.86/x86_32/ -e s/i86pc/x86_32/) CFLAGS += $(CFLAGS_WARN) -fno-strict-aliasing -std=gnu99 # due to bug in gcc v4.2,3,? CFLAGS += $(call cc-option,$(CC),-Wno-array-bounds,) ifeq ($(debug),y) CFLAGS += -g -DDEBUG else CFLAGS += -O2 endif ifeq ($(TARGET_ARCH),x86_64) LIBDIR := lib64 CFLAGS += -m64 else LIBDIR := lib CFLAGS += -m32 -march=i686 endif # common dummy rule to force execution .PHONY: FORCE FORCE : @: # do nothing tboot-1.8.0/Makefile0000644000000000000000000000442012272416301012433 0ustar 00000000000000# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # Grand Unified Makefile for tboot # # define ROOTDIR export ROOTDIR=$(CURDIR) # import global build config include Config.mk # (txt-test is not included because it requires pathing to Linux src) SUBDIRS := tboot lcptools tb_polgen utils docs # # build rules # # # manifest # .PHONY: manifest manifest : build lcptools/lcp_mlehash tboot/tboot.gz > mle_file lcptools/lcp_crtpol -t 0 -m mle_file -o policy_file # # install # install : @set -e; for i in $(SUBDIRS); do \ $(MAKE) install-$$i; \ done install-% : $(MAKE) -C $* install # # build # build : @set -e; for i in $(SUBDIRS); do \ $(MAKE) build-$$i; \ done build-% : $(MAKE) -C $* build # # dist # dist : $(patsubst %,dist-%,$(SUBDIRS)) [ -d $(DISTDIR) ] || $(INSTALL_DIR) $(DISTDIR) $(INSTALL_DATA) COPYING $(DISTDIR) $(INSTALL_DATA) README $(DISTDIR) dist-% : $(MAKE) -C $* dist # # world # # build tboot and tools, and place them in the install directory. # 'make install' should then copy them to the normal system directories .PHONY: world world : $(MAKE) clean $(MAKE) dist # # clean # clean : rm -f *~ include/*~ docs/*~ @set -e; for i in $(SUBDIRS); do \ $(MAKE) clean-$$i; \ done clean-% : $(MAKE) -C $* clean # # distclean # distclean : @set -e; for i in $(SUBDIRS); do \ $(MAKE) distclean-$$i; \ done distclean-% : $(MAKE) -C $* distclean # # mrproper # # Linux name for GNU distclean mrproper : distclean # # help # .PHONY: help help : @echo 'Installation targets:' @echo ' install - build and install everything' @echo ' install-* - build and install the * module' @echo '' @echo 'Building targets:' @echo ' dist - build and install everything into local dist directory' @echo ' world - clean everything' @echo '' @echo 'Cleaning targets:' @echo ' clean - clean sboot and tools' @echo ' distclean - clean and local downloaded files' @echo '' @echo ' uninstall - attempt to remove installed tools' @echo ' (use with extreme care!)' # # uninstall # # Use this target with extreme care! .PHONY: uninstall uninstall : D=$(DESTDIR) uninstall : rm -rf $(D)/boot/tboot* tboot-1.8.0/README0000644000000000000000000004441312272416301011661 0ustar 00000000000000****************************************************************************** * This version of tboot will not work with Xen versions < 3.4 (c/s < 19115) * ****************************************************************************** Trusted Boot (tboot) is an open source, pre-kernel/VMM module that uses Intel(R) Trusted Execution Technology (Intel(R) TXT) to perform a measured and verified launch of an OS kernel/VMM. This version of tboot supports Intel (both retail and Software Development Platforms (SDPs)) and OEM systems that are Intel TXT-capable. This version of tboot only supports both the Xen virtual machine monitor (versions >= 3.4) and Linux kernel versions >= 2.6.33. The mercurial source code repository for this project is located at: http://hg.code.sf.net/p/tboot/code. Updates to the mercurial repository are automatically sent to the mailing list tboot-changelog@lists.sourceforge.net. Overview of Tboot Functionality: -------------------------------- o Measured Launch. If the processor is detected as being TXT-capable and enabled then the code will attempt to perform a measured launch. If the measured launch process fails (processor is not capable, TXT is not enabled, missing SINIT, corrupted data, etc.)) then it will fall-through to a non-TXT boot. o Teardown of measured environment. When the system is shutdown, the measured environment will be torn down properly. This support S3/S4/S5 sleep states. o Reset data protection. Intel TXT hardware prevents access to secrets if the system is reset without clearing them from memory (as part of a TXT teardown). This code will support this by setting the flag indicating that memory should be so protected during the measured launch and clearing the flag just before teardown. o Protection of TXT memory ranges. Intel TXT reserves certain regions of RAM for its use and also defines several MMIO regions. These regions (excluding the TXT public configuration space) are protected from use by any domains (including dom0). o Intel TXT Launch Control Policy (LCP) tools. The lcptools project contains a set of tools (and basic documentation) that can be used to create and provision TXT Launch Control policies. LCP uses TPM non-volatile storage (TPM NV) to hold a launch policy, which the SINIT AC module reads and uses to enforce which measured launched environments (MLEs) (e.g. tboot) can be launched (based on a SHA-1 hash). These tools require a TPM Software Stack (TSS) that supports the Tspi_NV_* API. Versions of the TrouSerS project >0.3.0 support them. o Verified Launch. Tboot will extend verifcation from the MLE to the VMM and dom0, using policies similar to the LCP and also stored in TPM NV. These policies can be created and managed by the tb_polgen tool and provisioned into TPM NV using the lcptools. Instructions for Building: ------------------------- o The trousers sub-project has been removed (it was using an out-of-date version and was often problematic to build). Instead, the trosuers and trousers-devel packages must already be installed in order to build the lcptools sub-project. Most distrubtions either provide these packages by default or optionally; otherwise they can be found on various package sites and manually installed. Instructions for Use: -------------------- o The new tboot module must be added as the 'kernel' in the grub.conf file. The existing 'kernel' entry should follow as a 'module'. The SINIT AC module must be added to the grub.conf boot config as the last module, e.g.: title Xen w/ Intel(R) Trusted Execution Technology root (hd0,1) kernel /tboot.gz logging=serial,vga,memory module /xen.gz iommu=required dom0_mem=524288 com1=115200,8n1 module /vmlinuz-2.6.18-xen root=/dev/VolGroup00/LogVol00 ro module /initrd-2.6.18-xen.img module /Q35_SINIT_17.BIN GRUB2 does not pass the file name in the command line field of the multiboot entry (module_t::string). Since the tboot code is expecting the file name as the first part of the string, it tries to remove it to determine the command line arguments, which will cause a verification error. The "official" workaround for kernels/etc. that depend on the file name is to duplicate the file name in the grub.config file like below: menuentry 'Xen w/ Intel(R) Trusted Execution Technology' { recordfail insmod part_msdos insmod ext2 set root='(/dev/sda,msdos5)' search --no-floppy --fs-uuid --set=root 4efb64c6-7e11-482e-8bab-07034a52de39 multiboot /tboot.gz /tboot.gz logging=vga,memory,serial module /xen.gz /xen.gz iommu=required dom0_mem=524288 com1=115200,8n1 module /vmlinuz-2.6.18-xen /vmlinuz-2.6.18-xen root=/dev/VolGroup... module /initrd-2.6.18-xen.img /initrd-2.6.18-xen.img module /Q35_SINIT_17.BIN } o The appropriate SINIT AC Module can be downloaded from the tboot SourceForge project site. The current version of tboot (both in the repository and .tar.gz) requires version 17 or greater of the SINIT AC module. It will not work with some previous SINIT ACMs nor will it work on the TEP. o For Xen: newer versions of Xen support the 'iommu=required' command line option, which causes Xen to fail to run if there is any error in programming the VT-d engines. This is the most secure configuration. Older versions of Xen used the param 'vtd=1' or 'iommu=1', which enables VT-d but does not fail if it cannot be enabled. o For Linux: the 'intel_iommu=on' command line option will enable VT-d and the TXT code in Linux will force this if it is not specified. Support is now part of the 2.6.32 kernel. o Progress of the launch process is indicated via debug printk's using three different logging methods: serial - logging is traced over a COM/serial port to a remote console vga - logging is traced to the local screen memory - logging is traced to a memory location These three methods are not mutually exclusive - any combination can be enabled. Logging is enabled with command line parameters to tboot. The first parameter enables or disables logging levels (note that the default is all); any combination of "err", "warn", "info", "detail" can be used: loglvl=err,warn,info,detail|all|none The next parameter is used to configure the various logging targets; any combination can be used (note that when the parameter is not set, serial is the default): logging=vga,serial,memory If vga logging is set, the vga_delay parameter can be used to specify the number of seconds to pause after every screenful of output. It is specified as: vga_delay= If serial logging is set, the serial port settings can be configured with the following parameters: serial=[/][,[,[,[, [,]]]]] The default values for these are: serial=115200,8n1,0x3f8. o tboot will attempt to seal the module measurements using the TPM so that if it is put into S3 it can restore the correct PCR values on resume. In order for this to work, the TPM must be owned and the SRK auth must be set to all 0s. This can be done using the '-z' flag to tpm_takeownership. If the tboot policy being used is 'nonfatal' and the seal operation fails, tboot will continue the boot. However, for 'continue' or 'halt' policy types, tboot will halt the boot. o tboot provides a better AP wakeup mechanism based on cpu MWAIT feature for OS/VMM. This mechanism is defaultly disabled, and could be enabled with tboot command line option: ap_wake_mwait=true|false Once this mechanism is enabled, system will boot faster and will NOT require VT to be enabled. But before enabling this option, please make sure the OS/VMM has already support it, otherwise system can never boot up. Confirm it via finding lines like below in the OS/VMM booting log: TBOOT: found shared page at .... ... flags: 0x0000000x o tboot support a new PCR usage called Details / Authorities PCR Mapping(DA). DA can be enabled by below tboot command line option (note: default is legacy): pcr_map=da|legacy With DA PCR Mapping enabled it separates detailed measurements, stored in PCR17, from authorities measurements stored in PCR18. "Details" measurements include hashes of all components participating in establishing of trusted execution environment and due to very nature of hash algorithm change of any component entail change of final PCR17 value. "Authorities" measurements include hashes of some unique identifying properties of signing authorities such as public signature verification keys. This enables authority issue an update of component without affecting of final PCR18 value, because updated component is signed in the same way as old one. o Previously tboot tried to avoid including any reserved e820 region (in 1M ~4GB) into PMR low region to avoid possible SMM hang. So all e820 RAM regions after the first reserved one(above 1MB) will be discarded. It was found that some platforms reserve low memory regions to mitigate some hardware issues. Including such kind of reserved e820 regions into PMR low region does not cause SMM hang. Below tboot command line option can be used to mitigate the cases that large amount of RAM(sometime > 3GB) marked as reserved(discarded from OS/VMM usable RAM size) by tboot because some reserved e820 regions occurred in very low memory(notes: default is 0, means no mitigation for unwanted memory losing): min_ram=0xXXXXXXXX During 1MB~4GB, only the first RAM region with size less than byte and all following RAM regions will be discarded. The min_ram option gives a way to do fine-grain tuning on specific platforms. A suggested practical value for min_ram is 32M(0x2000000). o Tboot provides support to launch Revocation ACM (RACM) to revoke old buggy SINIT version if following command line option is used (default vaule is false): call_racm=true|false|check RACM is also loaded into memory via bootload like grub or syslinux, and is launched with getsec[ENTERACCS] instruction. Below is a example GRUB entry for RACM launch: title RACM Launch root (hd0,1) kernel /tboot.gz logging=serial,vga,memory call_racm=true module /racm.bin Tboot will always warm reset platform after RACM was launched & executed. Whether RACM launch has succeeded or not could be checked via doing a tboot launch with "call_racm=check" right after the warm reset. This tboot launch will end with halt right after the RACM launch result was output, and the system need manually reset. o Tboot support EFI boot via grub2 multiboot2 protocol. In Fedora 18/19, the OS should be installed and booted in EFI mode first, then: Under tboot code root folder: make; make install Copy appropriate SINIT for platform into /boot. Run: grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg Create directory /boot/efi/EFI/fedora/x86_64-efi, and copy multiboot2.mod and relocator.mod from /usr/lib/grub/x86_64-efi into it. Reboot to choose tboot grub option for TXT launch. Linux launch works already. Xen for trad BIOS still work and Xen EFI is not going to work until we can get a version with Daniel Kiper's multiboot2 changes in it -- and then we'll need to make some trivial changes to the 20_xen_tboot file. Grub2 is required for all of this. o Tboot support TPM NV measuring via extended Verified Launch Tboot Policy. This works only for TPM1.2 by far. TPM NV measuring is defaultly disabled, need below cmdline option to enable: measure_nv=true When NV measuring is enabled, it will get all NV measuring policy entry from the tboot policy structure. Every NV policy entry will specify: nv_index: TPM NV index to measure and verify pcr: PCR to be extended with the NV measurement mod_num: Tell how to measure the nv = TB_POL_MOD_NUM_NV: hash then extend, no size limitation on NV index = TB_POL_MOD_NUM_NV_RAW: extend w/o hash, size should equal hash size hash_type: = any: no verification needed = image: need verify per hashs list. hashs: hash list. optional. There is one default NV policy entry, which will try to read NV 0x40000010 and extend it into pcr 22 without hashing. The nv_index to be measured must be defined with OWNERWRITE permission, otherwise the verification will fail, and nothing will be extended into pcr. o Tboot provides support to TPM2 module, and following command line option is used to select TPM2 extend policy. extpol=agile|embedded|sha1|sha256|sm3|... When "agile" policy is selected, ACM will use specific TPM2 commands to compute hashes and extend all existing PCR banks at the expense of possible performance loss. For "embedded" policy, ACM will use algorithms supported by tboot to compute hashes and then will use TPM2_PCR_Extend commands to extend them into PCRs. If PCRs utilizing hash algorithms not supported by SW are discovered, they will be capped with "1" value. This policy when selected will ensure maximum possible performance at the expense of possible capping of some of the PCRs. Other policy, like "sha1", "sha256", etc., only represent one single algorithm. It means tboot will use this algorithm to compute hash and use TPM2_PCR_Extend to extend it into PCRs. PCR Usage: --------- o Legacy PCR mapping PCR 17 : It will be extended with the following values (in this order): - The values as documented in the MLE Developers Manual - SHA-1 hash of: tboot policy control value (4 bytes) | SHA-1 hash of tboot policy (20 bytes) : where the hash of the tboot policy will be 0s if TB_POLCTL_EXTEND_PCR17 is clear PCR 18 : It will be extended with the following values (in this order): - SHA-1 hash of tboot (as calculated by lcp_mlehash) - SHA-1 hash of first module in grub.conf (e.g. Xen or Linux kernel) PCR * : tboot policy may specify modules' measurements to be extended into PCRs specified in the policy The default tboot policy will extend, in order, the SHA-1 hashes of all modules (other than 0) into PCR 19. o Details / Authorities PCR Mapping(DA) PCR 17 (Details): It will be extended with the following values (in this order): - The values as documented in the MLE Developers Manual - SHA-1 hash of: tboot policy control value (4 bytes) | SHA-1 hash of tboot policy (20 bytes) : where the hash of the tboot policy will be 0s if TB_POLCTL_EXTEND_PCR17 is clear - SHA-1 hash of first module in grub.conf (e.g. Xen or Linux kernel) PCR 18 (Authorities): It will be extended with the following values (in this order): - The values as documented in the MLE Developers Manual - SHA-1 hash of: tboot policy control value (4 bytes) | SHA-1 hash of tboot policy (20 bytes) : where the hash of the tboot policy will be 0s if TB_POLCTL_EXTEND_PCR17 is clear PCR * : tboot policy may specify modules' measurements to be extended into PCRs specified in the policy The default tboot policy will extend, in order, the SHA-1 hashes of all modules (other than 0) into PCR 17. Interesting Items of Note: -------------------------- o A Xen or Linux version that does not support tboot can still be launched by tboot, however it will not protect any of the TXT memory nor tboot itself. And it will hang on reboot/shutdown. Aside from this, it will behave normally. o Tboot will copy and alter the e820 table provided by GRUB to "reserve" its own memory plus the TXT memory regions. These are marked as E820_UNUSABLE or E820_RESERVED so that the patched Xen code can prevent them from being assigned to dom0. The e820 table is not altered if the measured launch fails for any reason. o Tboot is always built 32bit and runs in protected mode without PAE or paging enabled. Tboot loads and executes at 0x800000 (8MB). o The code requires that VT be enabled as well as TXT. This is because the mechanism for bringing up the APs uses VMX to create a mini-VM in order to trap on INIT-SIPI-SIPI. If OS/VMM support tboot's new AP wakeup mechanism based on MWAIT, then VT is not required to be enabled. o The tools/txt-stat project is a Linux application that reads some of the TXT registers and will display the tboot boot log if tboot was run with 'logging=memory'. Contributing to the project: --------------------------- Contributions to any files in this project require the contributor(s) to certify the following: Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. If the above can be certified by the contributor(s), then he/they should include a signed-off-by line along with the changes that indicate this: Signed-off-by: John Developer tboot-1.8.0/docs/Makefile0000644000000000000000000000071612272416301013367 0ustar 00000000000000# Copyright (c) 2012, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # docs makefile # ROOTDIR ?= $(CURDIR)/.. include $(ROOTDIR)/Config.mk MANPATH ?= $(DISTDIR)/usr/share/man # # universal rules # build : dist : install install : [ -d $(MANPATH)/man8 ] || $(INSTALL_DIR) $(MANPATH)/man8 $(INSTALL_DATA) -t $(MANPATH)/man8 man/*.8* clean : mrproper : clean distclean : clean # # dependencies # # # implicit rules # tboot-1.8.0/docs/man/acminfo.80000644000000000000000000000061412272416301014204 0ustar 00000000000000.\" .TH ACMINFO 8 "2011-12-31" "tboot" "User Manuals" .SH NAME acminfo \- display the header info of a TXT ACM .SH SYNOPSIS .B acminfo .I acm-file-name .SH DESCRIPTION .B acminfo is used to display the header information for a TXT Authenticated Code Module (ACM) and match it with the current system. .SH OPTIONS .TP .I acm-file-name ACM file name .SH EXAMPLES \fBacminfo \fIi7_QUAD_SINIT_20.BIN tboot-1.8.0/docs/man/lcp_crtpconf.80000644000000000000000000000141212272416301015241 0ustar 00000000000000.\" .TH LCP_CRTPCONF 8 "2011-12-31" "tboot" "User Manuals" .SH NAME lcp_crtpconf \- create a platform configuration measurement for v1 policies .SH SYNOPSIS .B lcp_crtpconf .B \-p .IR PCR-index1,PCR-index2,...,PCR-indexN .RB [\| \-f .IR file-name \|] .RB [\| \-h \|] .SH DESCRIPTION .B lcp_crtpconf is used to create a platform configuration measurement. The produced platform configuration measurement will be appended to the input file in binary mode. .SH OPTIONS .TP .BI \-p\ PCR-index1,PCR-index2,...,PCR-indexN Index values can be 0-23. .TP .BI \-f\ file-name File name to which the measurement is appended. .TP .B \-h Print out the help message .SH EXAMPLES \fBlcp_crtpconf \-p \fI0,1,2,3 \fB \-f \fIpconf-file .SH "SEE ALSO" .BR lcp_writepol (8), .BR lcp_crtpol (8). tboot-1.8.0/docs/man/lcp_crtpol.80000644000000000000000000000454312272416301014736 0ustar 00000000000000.\" .TH LCP_CRTPOL 8 "2011-12-31" "tboot" "User Manuals" .SH NAME lcp_crtpol \- create a TXT v1 Launch Control Policy .SH SYNOPSIS .B lcp_crtpol .B \-t .I policy-type .RB [\| \-a .IR hashalg \|] .RB [\| \-v .IR version \|] .RB [\| \-sr .IR SINIT-revocation-counter \|] .RB [\| \-s .IR srtm-file \|] .RB [\| \-m .IR mle-file \|] .RB [\| \-o .IR policy-file \|] .RB [\| \-b .IR policy-data-file \|] .RB [\| \-pcf .IR policy-control-field \|] .RB [\| \-h \|] .SH DESCRIPTION .B lcp_crtpol is used to create a TXT v1 LCP policy (and optionally policy data), which can later be written to the TPM. The policy created are for platforms produced before 2009 (Weybridge, Montevina, McCreary). .SH OPTIONS .TP .BI \-t\ policy-type Policy type can be UINT8 or string. 5 strings are supported for the reserved LCP policy types. Strings and default policy type values for each string are: .RS .TP 0 or "hashonly" .TP 1 or "unsigned" .TP 2 or "signed" .TP 3 or "any" .TP 4 or "forceowner" .RE .TP .BI \-a\ hashalg Hash algorithm. Currently we only support SHA-1 algorithm: 0 OR 'sha1'. .TP .BI \-v\ version Version number. Currently it can be set to 0 or 1 if specified. The default value is 0. .TP .BI \-sr\ SINIT-revocation-counter The default sinit revocation counter is 0. .TP .BI \-s\ srtm-file File name of platform configuration data, as produced by .BR lcp_crtpconf. .TP .BI \-m\ mle-file File name of file containing the MLE hash values. This is a text file that contains one SHA-1 hash per line. The value of the hash must be hexadecimal values, specified either a single un-deliminated set or as space-delimited two-character (i.e. one byte) values. This can be produced by the .BR lcp_mlehash command. .TP .BI \-o\ policy-file File name to store the output policy. .TP .BI \-b\ policy-data-file File name to store the LCP Policy data. .TP .BI \-pcf\ policy-control-field The default policy control field value is 0. .TP .B \-h Print out the help message .SH EXAMPLES \fBlcp_crtpol \-t \fI0 \fB \-m \fImle-file \fB \-o \fIpolicy-hashonly-file .PP \fBlcp_crtpol \-t \fI1 \fB \-m \fImle-file \fB \-s \fIpconf-file \fB \-b \fI policy-data-file .PP \fBlcp_crtpol \-t \fIunsigned \fB \-a \fIsha1 \fB \-m \fImle-file \fB \-s \fIpconf-file \fB \-o \fIpolicy-unsigned-file \fB \-b \fIpolicy-data-file .SH "SEE ALSO" .BR lcp_readpol (8), .BR lcp_writepol (8), .BR lcp_mlehash (8), .BR lcp_crtpconf (8). tboot-1.8.0/docs/man/lcp_crtpol2.80000644000000000000000000000320112272416301015006 0ustar 00000000000000.\" .TH LCP_CRTPOL2 8 "2011-12-31" "tboot" "User Manuals" .SH NAME lcp_crtpol2 \- create an Intel(R) TXT policy (and policy data file) .SH SYNOPSIS .B lcp_crtpol2 .I COMMAND .RI [ OPTION ] .SH DESCRIPTION .B lcp_crtpol2 is used to create an Intel(R) TXT policy (and policy data file) for platforms produced after 2008. .SH OPTIONS .TP .B \-\-create Create an TXT policy. The following options are available: .RS .TP \w'\fR[\fB\-\-rev\ \fIctr1\fR[,\fIctrN\fR]'u+1n \fB\-\-type\ \fIany\||\|list\fR type .TP \fB\-\-pol\ \fIfile\fR policy file .TP \fR[\fB\-\-ver\ \fIversion\fR] version .TP \fR[\fB\-\-minver\ \fIver\fR] SINITMinVersion .TP \fR[\fB\-\-rev\ \fIctr1\fR,\fIctrN\fR] revocation values (comma separated, no spaces) .TP \fR[\fB\-\-ctrl\ \fIpol-ctrl\fR] policy control .TP \fR[\fB\-\-data\ \fIfile\fR] policy data file .TP \fR[\fIfile\fR]... policy list files .RE .TP .B \-\-show Show the content of policy file or policy data file. Available options are: .RS .TP \w'\fR[\fB\-\-rev\ \fIctr1\fR[,\fIcrtN\fR]'u+1n \fR[\fB\-\-brief\fR] breif format output .TP \fR[\fIpolicy-file\fR] policy file .TP \fR[\fIpolicy-data-file\fR] policy data file .RE .TP .B \-\-help Print out the help message. .TP .B \-\-verbose Enable verbose output; can be specified with any command. .SH EXAMPLES Assuming a policy list file .I list-unsig.lst has been created by the command .B lcp_crtpolist(8). The following example will create a policy and policy data file. .PP \fBlcp_crtpol2\ \-\-create\ \-\-type \fIlist \fB\-\-pol \fIlist.pol \fB\-\-data \fIlist.data\ list-unsig.lst .SH "SEE ALSO" .BR lcp_crtpol (8), .BR lcp_mlehash (8), .BR lcp_crtpolelt (8), .BR lcp_crtpollist (8). tboot-1.8.0/docs/man/lcp_crtpolelt.80000644000000000000000000000516412272416301015443 0ustar 00000000000000.\" .TH LCP_CRTPOLELT 8 "2011-12-31" "tboot" "User Manuals" .SH NAME lcp_crtpolelt \- create an Intel(R) TXT policy element of specified type. .SH SYNOPSIS .B lcp_crtpolelt .I COMMAND .RI [ OPTION ] .SH DESCRIPTION .B lcp_crtpolelt is used to create an Intel(R) TXT policy element of specified type. .SH OPTIONS .TP \fB\-\-create create an policy element .RS .TP \w'\fR[\fB\-\-ctrl\ \fIpol-elt-ctr1\fR]'u+1n \fB\-\-type\ \fItype\fP type of element; must be first option; see below for type strings and their options .TP \fB\-\-out\ \fIfile\fP output file name .TP \fR[\fB\-\-ctrl\ \fIpol-elt-ctr1\fR]\fP PolEltControl field (hex or decimal) .RE .TP \fB\-\-show\ \fIfile\fP show policy element .TP \fB\-\-verbose\fP enable verbose output; can be specified with any command .TP \fB\-\-help\fP print out the help message .SS "Available type options:" .TP \fBmle\ \fR[\fB\-\-minver\ \fIver\fR]\fP minimum version of SINIT .TP \fBmle\ \fR[\fIfile1\fR][\fIfile2\fR]...\fP one or more files containing MLE hash(es); each file can contain multiple hashes .TP \fBpconf\ \fR[\fIfile1\fR][\fIfile2\fR]...\fP one or more files containing PCR numbers and the desired digest of each; each file will be a PCONF .TP \fBcustom\ \fR[\fB\-\-uuid\ \fIUUID\fR]\fP UUID in format: {0xaabbccdd, 0xeeff, 0xgghh, 0xiijj, {0xkk 0xll, 0xmm, 0xnn, 0xoo, 0xpp}} or "--uuid tboot" to use default .TP \fBcustom\ \fR[\fIfile\fR]\fP file containing element data .SH EXAMPLES .SS "Create an MLE element: .TS tab (@); l lx. 1@T{ \fBlcp_mlehash \-c \fI"logging=serial,vga,memory" /boot/tboot.gz \fR> \fImle-hash T} 2@T{ \fBlcp_crtpolelt \fB\-\-create \-\-type \fImle \fB\-\-ctrl \fI0x00 \fB\-\-minver \fI17 \fB\-\-out \fImle.elt mle-hash T} .TE .SS "Create a PCONF element: .TS tab (@); l lx. 1@T{ \fBcat \fI/sys/devices/platform/tpm_tis/pcrs \fR| \fBgrep \-e \fIPCR-00 \fB\-e \fIPCR-01 \fR> \fIpcrs T} 2@T{ \fBlcp_crtpolelt \-\-create \-\-type \fIpconf \fB\-\-out \fIpconf.elt pcrs T} .TE .SS "Create an SBIOS element: .TS tab (@); l lx. 1@T{ Create hash file containing BIOS hash(es), e.g. named \fIsbios-hash T} 2@T{ \fBlcp_crtpolelt \-\-create \-\-type \fIsbios \fB\-\-out \fIsbios.elt sbios-hash T} .TE .SS "Create a CUSTOM element: .TS tab (@); l lx. 1@T{ Create or determine the UUID that will identify this data format (e.g. using \fBuuidgen\fR(1)). T} 2@T{ Create the data file that will be placed in this element (e.g. the policy file from \fBtb_polgen\fR(8)). T} 3@T{ \fBlcp_crtpolelt \-\-create \-\-type \fIcustom \fB\-\-out \fIcustom.elt \fB\-\-uuid \fIuuid-value data-file T} .TE .SH "SEE ALSO" .BR lcp_crtpol2 (8), .BR lcp_mlehash (8), .BR lcp_crtpollist (8), .BR uuidgen (1), .BR tb_polgen (8). tboot-1.8.0/docs/man/lcp_crtpollist.80000644000000000000000000000560612272416301015633 0ustar 00000000000000.\" .TH LCP_CRTPOLLIST 8 "2011-12-31" "tboot" "User Manuals" .SH NAME lcp_crtpollist \- create an Intel(R) TXT policy list .SH SYNOPSIS .B lcp_crtpollist .I COMMAND .RI [ OPTION ] .SH DESCRIPTION .B lcp_crtpollist is used to create an Intel(R) TXT policy list. .SH OPTIONS .TP .B \-\-create Create an TXT policy list. The following options are available: .RS .TP \w'\fR[\fB\-\-priv\ \fIkey-file\fR]'u+1n \fB\-\-out\ \fIfile\fP policy list file .TP \fR[\fB\-\-ver\ \fIversion\fR]\fP version .TP \fR[\fIfile\fR]...\fP policy element files .RE .TP .B \-\-sigh Sign an TXT policy list. .RS .TP \w'\fR[\fB\-\-priv\ \fIkey-file\fR]'u+1n \fB\-\-pub \fIkey-file\fP PEM file of public key .TP \fB\-\-out\ \fIfile\fP policy list file .TP \fR[\fB\-\-priv \fIkey-file\fR]\fP PEM file of private key .TP \fR[\fB\-\-rev \fIrev-ctr\fR]\fP revocation counter value .TP \fR[\fB\-\-nosig\fR]\fP don't add SigBlock .RE .TP .B \-\-addsig .RS .TP \w'\fR[\fB\-\-priv\ \fIkey-file\fR]'u+1n \fB\-\-sig\ \fIfile\fP file containing signature (big-endian) .TP \fB\-\-out\ \fIfile\fP policy list file .RE .TP \fB\-\-show \fIfile\fP policy list file .TP .B \-\-help Print out the help message. .TP .B \-\-verbose Enable verbose output; can be specified with any command. .SH EXAMPLES .SS "Create policy list:" Assuming there have been two element file .I mle.elt and .I pconf.elt generated by .BR lcp_crtpolelt (8) The following example can create an unsigned policy list: .PP \fBlcp_crtpollist \-\-create \-\-out \fIlist-unsig.lst mle.elt pconf.elt .SS "Sign policy list:" Unsigned policy list can be signed by the command .BR lcp_crtpollist (8) or .BR openssl (1). The .BR openssl (1) signing is supported for cases where the signing environment is separate from the policy creation environment and the software allowed to run there is strictly controlled and already supports .BR openssl (1). .PP The following example uses .BR openssl (1) to sign the list: .TS tab (@); l lx. 1@T{ \fBopenssl rsa \-pubout \-in \fIprivkey.pem \fB\-out \fIpubkey.pem T} 2@T{ \fBcp \fIlist-unsig.lst list-sig.lst T} 3@T{ \fBlcp_crtpollist \-\-sigh \-\-pub \fIpubkey.pem \fB\-\-nosig \-\-out \fIlist-sig.lst T} 4@T{ \fBopenssl genrsa \-out \fIprivkey.pem 2048 T} 5@T{ \fBopenssl dgst \-sha1 \-sign \fIprivkey.pem \fB\-out \fIlist.sig list-sig.lst T} 6@T{ \fBlcp_crtpollist \-\-addsig \-\-sig \fIlist.sig \fB\-\-out \fIlist-sig.lst T} .TE .B lcp_crtpollist can also be used to sigh a policy list. The following example are intended to be mutually exclusive with the preceding example. .TS tab (@); l lx. 1@T{ \fBopenssl genrsa \-out \fIprivkey.pem 2048 T} 2@T{ \fBopenssl rsa \-pubout \-in \fIprivkey.pem \fB\-out \fIpubkey.pem T} 3@T{ \fBcp \fIlist-unsig.lst list-sig.lst T} 4@T{ \fBlcp_crtpollist \-\-sign \-\-pub \fIpubkey.pem \fB\-\-priv \fIprivkey.pem \fB\-\-out \fIlist-sig.lst T} .TE .SH "SEE ALSO" .BR lcp_crtpol2 (8), .BR lcp_crtpolelt (8), .BR lcp_crtpollist (8), .BR openssl(1). tboot-1.8.0/docs/man/lcp_mlehash.80000644000000000000000000000242212272416301015046 0ustar 00000000000000.\" .TH LCP_MLEHASH 8 "2011-12-31" "tboot" "User Manuals" .SH NAME lcp_mlehash \- generate a SHA-1 hash of a TXT MLE binary file suitable for use in a TXT launch control policy .SH SYNOPSIS .B lcp_mlehash .RB [\| \-v \|] .RB [\| \-c .IR cmdline \|] .RB [\| \-h \|] .I mle-file .SH DESCRIPTION .B lcp_mlehash is used to generate a SHA-1 hash of the portion of an executable file that contains the IntelĀ® TXT measured launched environment (MLE). In the MLE binary file, the portion of the file to be used as the MLE is specified in the MLE header structure. If verbose mode is not used, the output is suitable for use as the mle-file to the .B lcp_crtpol and .B lcp_crtpolelt commands. .SH OPTIONS .TP .I mle-file File name of the MLE binary. If it is a gzip file then it will be un-ziped before hashing. .TP .B \-v Verbose mode, display progress indications. .TP .BI \-c\ cmdline Specify quote-delimited command line. It is important to specify the command line that is used when launching the MLE or the hash will not match what is calculated by SINIT. .TP .B \-h Print out the help message. .SH EXAMPLES \fBlcp_mlehash \-c \fI"logging=memory,serial,vga" \fI/boot/tboot.gz \fB> \fImle-hash .SH "SEE ALSO" .BR lcp_readpol (8), .BR lcp_writepol (8), .BR lcp_crtpol (8), .BR lcp_crtpolelt (8). tboot-1.8.0/docs/man/lcp_readpol.80000644000000000000000000000250712272416301015057 0ustar 00000000000000.\" .TH LCP_READPOL 8 "2011-12-31" "tboot" "User Manuals" .SH NAME lcp_readpol \- read the contents of an LCP policy index .SH SYNOPSIS .B lcp_readpol .B \-i .I index-value .RB [\| \-f .IR policy-file \|] .RB [\|\-s .IR size \|] .RB [\|\-p .IR passwd \|] .RB [\| \-h \|] .SH DESCRIPTION .B lcp_readpol is used to read the contents of an LCP policy index. Any index can be specified but the output will be parsed as if it contained a policy. .SH OPTIONS .TP .BI \-i\ index-value Designate the index for reading. Index can be UINT32 or string. 3 strings are supported for the reserved LCP indices. Strings and default index values for each string are: .RS .IP default 0x50000001(INDEX_LCP_DEF) .IP owner 0x40000001(INDEX_LCP_OWN) .IP aux 0x50000002(INDEX_LCP_AUX) .RE .TP .BI \-f\ policy-file File name to write the policy data to. If no file name is specified then the contents will be displayed. .TP .BI \-s\ size Value size to read from NV store. If no size inputted, read by length as this index defined. .TP .BI \-p\ password The TPM owner password .TP .B \-h Print out the help message .SH EXAMPLES \fBlcp_readpol \-i \fIdefault \fB \-f \fIpolicy-file .PP \fBlcp_readpol \-i \fI0x00011101 \fB \-s \fI10 .PP \fBlcp_readpol \-i \fI0x00011101 \fB \-f \fIpolicy-file \fB \-p \fI123456 .SH "SEE ALSO" .BR lcp_writepol (8), .BR lcp_crtpol (8). tboot-1.8.0/docs/man/lcp_writepol.80000644000000000000000000000237512272416301015301 0ustar 00000000000000.\" .TH LCP_WRITEPOL 8 "2011-12-31" "tboot" "User Manuals" .SH NAME lcp_writepol \- write LCP policy into a TPM NV index .SH SYNOPSIS .B lcp_writepol .B \-i .I index-value .RB [\| \-f .IR policy-file .RB |\ \-e \|] .RB [\| \-p .IR passwd \|] .RB [\| \-h \|] .SH DESCRIPTION .B lcp_writepol is used to write LCP policy into a (previously-defined) TPM NV index. It also supports writing arbitrary data into a specified index. .SH OPTIONS .TP .BI \-i\ index-value Designate the index for writing. Index can be UINT32 or string. 3 strings are supported for the reserved LCP indices. Strings and default index values for each string are: .RS .IP default 0x50000001(INDEX_LCP_DEF) .IP owner 0x40000001(INDEX_LCP_OWN) .IP aux 0x50000002(INDEX_LCP_AUX) .RE .TP .BI \-f\ policy-file File name where the policy data is stored. .TP .BI \-e Write 0 length data to the index. This is useful for special indices, such as those permission is WRITEDFINE. .TP .BI \-p\ password The TPM owner password .TP .B \-h Print out the help message .SH EXAMPLES \fBlcp_writepol \-i \fIdefault \fB \-f \fIpolicy-file .PP \fBlcp_writepol \-i \fI0x00011101 \fB \-e .PP \fBlcp_writepol \-i \fI0x00011101 \fB \-f \fIpolicy-file \fB \-p \fI123456 .SH "SEE ALSO" .BR lcp_readpol (8), .BR lcp_crtpol (8). tboot-1.8.0/docs/man/tb_polgen.80000644000000000000000000000610512272416301014542 0ustar 00000000000000.\" .TH TB_POLGEN 8 "2011-12-31" "tboot" "User Manuals" .SH NAME tb_polgen \- manage tboot verified launch policy .SH SYNOPSIS .B tb_polgen .I COMMAND .RI [ OPTION ] .SH DESCRIPTION .B tb_polgen is used to manage tboot verified launch policy. .SH COMMANDS .TP .B \-\-create Create an empty tboot verified launch policy file. .RS .TP \fB\-\-type \fInonfatal \fR|\fI continue \fR|\fI halt\fR Nonfatal means ignoring all non-fatal errors and continuing. Continue means ignoring verification errors and halting otherwise. Halt means halting on any errors. .TP \fR[\fB\-\-ctrl \fIpolicy-control-value\fR] The default value 1 is to extend policy into PCR 17. .TP \fIpolicy-file\fR .RE .TP .B \-\-add Add a module hash entry into a policy file. .RS .TP \fB\-\-num \fImodule-number \fR|\fI any\fR The module-number is the 0-based module number corresponding to modules loaded by the bootloader. .TP \fB\-\-pcr \fITPM-PCR-number \fR|\fI none\fR The TPM-PCR-number is the PCR to extend the module's measurement into. .TP \fB\-\-hash \fIany \fR|\fI image\fR .TP \fR[\fB\-\-cmdline \fIcommand-line\fR] The command line is from grub.conf, and it should not include the module name (e.g. "/xen.gz"). .TP \fR[\fB\-\-image \fIimage-file-name\fR] .TP \fIpolicy-file\fR .RE .TP .B \-\-del Delete a module hash entry from a policy file. .RS .TP \fB\-\-num \fImodule-number \fR|\fI any\fR The module-number is the 0-based module number corresponding to modules loaded by the bootloader. .TP \fR[\fB\-\-pos \fIhash-number\fR] The hash-number is the 0-based index of the hash, within the list of hashes for the specified module. .TP \fIpolicy-file\fR .RE .TP .B \-\-unwrap Extract the tboot verified launch policy from a TXT LCP element file. .RS .TP \fB\-\-elt \fIelt-file\fR .TP \fIpolicy-file\fR .RE .TP \fB\-\-show \fIpolicy-file\fR Show the policy information in a policy file. .TP .B \-\-help Print out the help message. .TP .B \-\-verbose Enable verbose output; can be specified with any command. .SH EXAMPLES \fBtb_polgen \-\-create \-\-type \fInonfatal vl.pol\fR .PP \fBtb_polgen \-\-add \-\-num \fI0 \fB\-\-pcr \fInone \fB\-\-hash \fIimage \fB\-\-cmdline \fI"cmdline" \fB\-\-image \fI/boot/xen.gz vl.pol\fR .PP \fBtb_polgen \-\-add \-\-num \fI1 \fB\-\-pcr \fI19 \fB\-\-hash \fIimage \fB\-\-cmdline \fI"cmdline" \fB\-\-image \fI/boot/vmlinuz-2.6.18.8-xen vl.pol\fR .PP \fBtb_polgen \-\-add \-\-num \fI2 \fB\-\-pcr \fI19 \fB\-\-hash \fIimage \fB\-\-cmdline \fI"" \fB\-\-image \fI/boot/initrd-2.6.18.8-xen.img vl.pol\fR .PP \fBtb_polgen \-\-del \-\-num \fI1 vl.pol\fR .PP \fBtb_polgen \-\-show \-\-verbose \fIvl.pol\fR .SS "Note1:" It is not necessary to specify a PCR for module 0, since this module's measurement will always be extended to PCR 18. If a PCR is specified, then the measurement will be extended to that PCR in addition to PCR 18. .SS "Note2:" --unwrap is not implemented correctly. There should be a defined UUID for this and that should be checked before copying the data. There should be a wrap or similar command to generates an element file for a policy. .SH "SEE ALSO" .BR lcp_crtpol (8), .BR lcp_crtpol2 (8), .BR lcp_crtpolelt (8). tboot-1.8.0/docs/man/txt-stat.80000644000000000000000000000100412272416301014352 0ustar 00000000000000.\" .TH TXT-STAT 8 "2011-12-31" "tboot" "User Manuals" .SH NAME txt-stat \- display the status of TXT .SH SYNOPSIS .B txt-stat .RB [\| \-\-heap \|] .RB [\| \-h \|] .SH DESCRIPTION .B txt-stat is used to display various information about the status of Intel(R) TXT. It will display the TXT configuration registers status and TBOOT log by default. .SH OPTIONS .TP .B \-\-heap Print out the BiosData structure from the TXT heap. .TP \fB\-h\fR, \fB\-\-help Print out this help message. .SH EXAMPLES \fBtxt-stat \-\-heap tboot-1.8.0/docs/policy_v1.txt0000644000000000000000000000643712272416301014403 0ustar 00000000000000**************************************************************************** *** *** *** Launch Control Policy v1 *** *** *** **************************************************************************** This document describes Launch Control Policies for platforms produced before 2009 (Weybridge, Montevina, McCreary). These are some example instructions for creating and provisioning both an Intel(R) TXT Launch Control Policy (LCP) and a Verified Launch policy. These steps assume that all referenced binaries have already been built and paths are relative to the tboot/ directory: Create LCP policy: ----------------- 1. lcptools/lcp_mlehash -c "the command line for tboot from grub.conf" /boot/tboot.gz > mle_hash 2. lcptools/lcp_crtpol -t hashonly -m mle_hash -o lcp.pol Note: The '-c' parameter to lcp_mlehash is used to specify tboot's command line, as it would appear in grub.conf. It can be omitted if no command line parameters are specified in grub.conf (or it can be empty). It should not include the module name (e.g. "/tboot.gz"). Create Verified Launch policy: ----------------------------- 1. tb_polgen/tb_polgen --create --type nonfatal vl.pol 2. tb_polgen/tb_polgen --add --num 0 --pcr none --hash image --cmdline "the command line for xen from grub.conf" --image /boot/xen.gz vl.pol 3. tb_polgen/tb_polgen --add --num 1 --pcr 19 --hash image --cmdline "the command line for dom0 from grub.conf" --image /boot/vmlinuz-2.6.18.8-xen vl.pol 4. tb_polgen/tb_polgen --add --num 2 --pcr 19 --hash image --cmdline "" --image /boot/initrd-2.6.18.8-xen.img vl.pol Note: The command lines should not include the module name (e.g. "/xen.gz"). This is a change from the previous version of policy support and was done because a module's measurement should only depend on its content and not on its location. Note 2: It is not necessary to specify a PCR for module 0, since this module's measurement will always be extended to PCR 18. If a PCR is specified, then the measurement will be extended to that PCR in addition to PCR 18. Take ownership of the TPM: ------------------------- 1. modprobe tpm_tis (you may need 'force=1 interrupts=0') 2. tcsd 3. tpm_takeownership -z - choose password for TPM Note: When taking ownership of the TPM it is important to set the SRK auth to all 0s so that tboot will be able to seal/unseal the measurements. The '-z' flag to tpm_takeownership will do this. Define tboot error TPM NV index: ------------------------------- 1. lcptools/tpmnv_defindex -i 0x20000002 -s 8 -pv 0 -rl 0x07 -wl 0x07 -p TPM-password Define LCP and Verified Launch policy indices: --------------------------------------------- 1. lcptools/tpmnv_defindex -i owner -p TPM-password-from-taking-ownership 2. lcptools/tpmnv_defindex -i 0x20000001 -s 256 -pv 0x02 -p TPM-password Write LCP and Verified Launch policies to TPM: --------------------------------------------- (modprobe tpm_tis; tcsd;) 1. lcptools/lcp_writepol -i owner -f lcp.pol -p TPM-password 2. lcptools/lcp_writepol -i 0x20000001 -f vl.pol -p TPM-password tboot-1.8.0/docs/policy_v2.txt0000644000000000000000000000621412272416301014375 0ustar 00000000000000**************************************************************************** *** *** *** Launch Control Policy v2 *** *** *** **************************************************************************** This document describes Launch Control Policies for platforms produced after 2008. These are some example instructions for creating and provisioning both an Intel(R) TXT Launch Control Policy (LCP) and a Verified Launch policy. These steps assume that all referenced binaries have already been built and paths are relative to the tboot/ directory: Create LCP policy: ----------------- o See the file lcptools/lcptools2.txt for instructions on creating policies and policy data files using the new tools. Create Verified Launch policy: ----------------------------- 1. tb_polgen/tb_polgen --create --type nonfatal vl.pol 2. tb_polgen/tb_polgen --add --num 0 --pcr none --hash image --cmdline "the command line for xen from grub.conf" --image /boot/xen.gz vl.pol 3. tb_polgen/tb_polgen --add --num 1 --pcr 19 --hash image --cmdline "the command line for dom0 from grub.conf" --image /boot/vmlinuz-2.6.18.8-xen vl.pol 4. tb_polgen/tb_polgen --add --num 2 --pcr 19 --hash image --cmdline "" --image /boot/initrd-2.6.18.8-xen.img vl.pol Note: The command lines should not include the module name (e.g. "/xen.gz"). This is a change from the previous version of policy support and was done because a module's measurement should only depend on its content and not on its location. Note 2: It is not necessary to specify a PCR for module 0, since this module's measurement will always be extended to PCR 18. If a PCR is specified, then the measurement will be extended to that PCR in addition to PCR 18. Take ownership of the TPM: ------------------------- 1. modprobe tpm_tis (you may need 'force=1 interrupts=0') 2. tcsd 3. tpm_takeownership -z - choose password for TPM Note: When taking ownership of the TPM it is important to set the SRK auth to all 0s so that tboot will be able to seal/unseal the measurements. The '-z' flag to tpm_takeownership will do this. Define tboot error TPM NV index: ------------------------------- 1. lcptools/tpmnv_defindex -i 0x20000002 -s 8 -pv 0 -rl 0x07 -wl 0x07 -p TPM-password Define LCP and Verified Launch policy indices: --------------------------------------------- 1. lcptools/tpmnv_defindex -i owner -s 0x36 -p TPM-owner-password 2. lcptools/tpmnv_defindex -i 0x20000001 -s 256 -pv 0x02 -p TPM-owner-password Write LCP and Verified Launch policies to TPM: --------------------------------------------- (modprobe tpm_tis; tcsd;) 1. lcptools/lcp_writepol -i owner -f list.pol -p TPM-password 2. lcptools/lcp_writepol -i 0x20000001 -f vl.pol -p TPM-password Modify grub.conf to load the policy data file: --------------------------------------------- 1. Edit grub.conf and add the following: module /list.data where you should use the path to this file. tboot-1.8.0/docs/txt-info.txt0000644000000000000000000000124312272416301014234 0ustar 00000000000000Intel's technology for safer computing, Intel(R) Trusted Execution Technology (Intel(R) TXT), defines platform-level enhancements that provide the building blocks for creating trusted platforms. Intel(R) TXT was formerly known by the code name LaGrande Technology (LT). Intel(R) TXT in Brief: ---------------------- o Provides dynamic root of trust for measurement (DRTM) o Data protection in case of improper shutdown o Verification and enforcement of launched environment For more information, see http://www.intel.com/technology/security/. This site also has a link to the Intel(R) TXT MLE Developers Manual, which has been updated for the new released platforms. tboot-1.8.0/include/config.h0000644000000000000000000001003512272416301014033 0ustar 00000000000000/* * 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__ /* * build/support flags */ /* address tboot will load and execute at */ #define TBOOT_START 0x0804000 /* start address of tboot MLE page table, also the beginning of tboot memory */ #define TBOOT_BASE_ADDR 0x0800000 /* address that tboot will do s3 resume at */ /* (must be in lower 1MB (real mode) and less than Xen trampoline @ 0x8c000) */ #define TBOOT_S3_WAKEUP_ADDR 0x8a000 /* these addrs must be in low memory so that they are mapped by the */ /* kernel at startup */ /* address/size for memory-resident serial log (when enabled) */ #define TBOOT_SERIAL_LOG_ADDR 0x60000 #define TBOOT_SERIAL_LOG_SIZE 0x08000 /* address/size for modified e820 table */ #define TBOOT_E820_COPY_ADDR (TBOOT_SERIAL_LOG_ADDR + \ TBOOT_SERIAL_LOG_SIZE) #define TBOOT_E820_COPY_SIZE 0x01800 /* address/size for modified VMM/kernel command line */ #define TBOOT_KERNEL_CMDLINE_ADDR (TBOOT_E820_COPY_ADDR + \ TBOOT_E820_COPY_SIZE) #define TBOOT_KERNEL_CMDLINE_SIZE 0x0400 #ifndef NR_CPUS #define NR_CPUS 512 #endif #ifdef __ASSEMBLY__ #define ENTRY(name) \ .globl name; \ .align 16,0x90; \ name: #else extern char _start[]; /* start of tboot */ extern char _end[]; /* end of tboot */ #endif #define COMPILE_TIME_ASSERT(e) \ { \ struct tmp { \ int a : ((e) ? 1 : -1); \ }; \ } #define __data __attribute__ ((__section__ (".data"))) #define __text __attribute__ ((__section__ (".text"))) #define __mlept __attribute__ ((__section__ (".mlept"))) #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: */ tboot-1.8.0/include/elf_defns.h0000644000000000000000000001164112272416301014517 0ustar 00000000000000/* * elf_defns.h: ELF file type 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 __ELF_DEFNS_H__ #define __ELF_DEFNS_H__ /* Elf header */ typedef struct { unsigned char e_ident[16]; uint16_t e_type; uint16_t e_machine; uint32_t e_version; uint32_t e_entry; uint32_t e_phoff; uint32_t e_shoff; uint32_t e_flags; uint16_t e_ehsz; uint16_t e_phentsize; uint16_t e_phnum; uint16_t e_shentsize; uint16_t e_shnum; uint16_t e_shstrndx; } elf_header_t; /* e_ident[] Identification Indexes */ #define EI_MAG0 0 /* File identification */ #define EI_MAG1 1 /* File identification */ #define EI_MAG2 2 /* File identification */ #define EI_MAG3 3 /* File identification */ #define EI_CLASS 4 /* File class */ #define EI_DATA 5 /* Data encoding */ #define EI_VERSION 6 /* File version */ #define EI_PAD 7 /* Start of padding bytes */ #define EI_NIDENT 8 /* Size of e_ident[] */ /* Magic number */ #define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ #define ELFMAG1 'E' /* e_ident[EI_MAG1] */ #define ELFMAG2 'L' /* e_ident[EI_MAG2] */ #define ELFMAG3 'F' /* e_ident[EI_MAG3] */ /* e_ident[EI_CLASS] */ #define ELFCLASSNONE 0 /* Invalid class */ #define ELFCLASS32 1 /* 32-bit objects */ #define ELFCLASS64 2 /* 64-bit objects */ /* e_ident[EI_DATA] */ #define ELFDATANONE 0 /* Invalid data encoding */ #define ELFDATA2LSB 1 /* Least significant byte */ #define ELFDATA2MSB 2 /* Most significant byte */ /* e_type */ #define ET_NONE 0 /* No file type */ #define ET_REL 1 /* Relocatable file */ #define ET_EXEC 2 /* Executable file */ #define ET_DYN 3 /* Shared object file */ #define ET_CORE 4 /* Core file */ #define ET_LOPROC 0xff00 /* Processor-specific */ #define ET_HIPROC 0xffff /* Processor-specific */ /* e_machine */ #define ET_NONE 0 /* No machine */ #define EM_M32 1 /* At&t We 32100 */ #define EM_SPARC 2 /* SPARC */ #define EM_386 3 /* Intel architecture */ #define EM_68K 4 /* Motorola 68000 */ #define EM_88K 5 /* Motorola 88000 */ #define EM_860 7 /* Intel 80860 */ #define EM_MIPS 8 /* MIPS RS3000 Big-Endian */ #define EM_MIPS_RS4_BE 10 /* MIPS RS4000 Big-Endian */ /* e_version */ #define EV_NONE 0 /* Invalid version */ #define EV_CURRENT 1 /* Current version */ /* Program header */ typedef struct { uint32_t p_type; uint32_t p_offset; uint32_t p_vaddr; uint32_t p_paddr; uint32_t p_filesz; uint32_t p_memsz; uint32_t p_flags; uint32_t p_align; } elf_program_header_t; /* p_type */ #define PT_NULL 0 #define PT_LOAD 1 #define PT_DYNAMIC 2 #define PT_INTERP 3 #define PT_NOTE 4 #define PT_SHLIB 5 #define PT_PHDR 6 #define PT_LOPROC 0x70000000 #define PT_HIPROC 0x7fffffff /* multiboot magic */ #define MB_MAGIC 0x2badb002 #endif /* __ELF_DEFNS_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/include/hash.h0000644000000000000000000001014512272416301013513 0ustar 00000000000000/* * 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 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]; uint8_t sha512[SHA512_LENGTH]; } tb_hash_t; static inline const char *hash_alg_to_string(uint16_t hash_alg) { if ( hash_alg == TB_HALG_SHA1 ) 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_SHA256"; else if ( hash_alg == TB_HALG_SHA512 ) return "TB_HALG_SHA256"; 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 ) 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; } extern bool are_hashes_equal(const tb_hash_t *hash1, const tb_hash_t *hash2, uint16_t hash_alg); extern bool hash_buffer(const unsigned char* buf, size_t size, tb_hash_t *hash, uint16_t hash_alg); extern bool extend_hash(tb_hash_t *hash1, const tb_hash_t *hash2, uint16_t hash_alg); extern void print_hash(const tb_hash_t *hash, uint16_t hash_alg); extern 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: */ tboot-1.8.0/include/lcp.h0000644000000000000000000000762312272416301013355 0ustar 00000000000000/* * Copyright 2001 - 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 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_LCP_H__ #define __TXT_LCP_H__ #ifndef __packed #define __packed __attribute__ ((packed)) #endif /*--------- LCP UUID ------------*/ #define LCP_POLICY_DATA_UUID {0xab0d1925, 0xeee7, 0x48eb, 0xa9fc, \ {0xb, 0xac, 0x5a, 0x26, 0x2d, 0xe}} /*--------- LCP Policy Algorithm ------------*/ #define LCP_POLHALG_SHA1 0 /*--------- LCP Policy Type ------------*/ #define LCP_POLTYPE_HASHONLY 0 #define LCP_POLTYPE_UNSIGNED 1 #define LCP_POLTYPE_SIGNED 2 #define LCP_POLTYPE_ANY 3 #define LCP_POLTYPE_FORCEOWNERPOLICY 4 /*--------- LCP Policy List type ------------*/ #define LCP_POLDESC_MLE_UNSIGNED 0x0001 #define LCP_POLDESC_PCONF_UNSIGNED 0x0002 /*--------- LCP reserved Indices------------*/ #define INDEX_LCP_DEF 0x50000001 #define INDEX_LCP_OWN 0x40000001 #define INDEX_AUX 0x50000002 /*------ Default Permission, size and locality for reserved Indices--------*/ #define PERMISSION_DEF 0x00002000 #define PERMISSION_OWN 0x00000002 #define PERMISSION_AUX 0x0 #define DATASIZE_POL 34 #define DATASIZE_AUX 64 #define LOCALITY_DEFAULT 0x1f #define WR_LOCALITY_AUX 0x18 /*--------- Other data structures of LCP Policy ------------*/ #define SHA1_LENGTH 20 #define SHA256_LENGTH 32 typedef union { uint8_t sha1[SHA1_LENGTH]; uint8_t sha256[SHA256_LENGTH]; } lcp_hash_t; typedef struct __packed { uint8_t version; uint8_t hash_alg; /* one of LCP_POLHALG_* */ uint8_t policy_type; /* one of LCP_POLTYPE_* */ uint8_t sinit_revocation_counter; uint32_t policy_control; uint16_t reserved[3]; lcp_hash_t policy_hash; } lcp_policy_t; typedef struct __packed { uint8_t version; uint8_t count; union{ lcp_hash_t* hashes; TPM_PCR_INFO_SHORT* pcrs; }; } lcp_unsigned_list_t; typedef struct __packed { uint16_t type; /* One of LCP_POLDESC_* */ lcp_unsigned_list_t unsigned_list; } lcp_policy_list_t; typedef struct __packed { uint8_t version; uint8_t policy_data_listsize; lcp_policy_list_t policy_data_list[]; } lcp_unsigned_policy_data_t; typedef struct __packed { uuid_t uuid; lcp_unsigned_policy_data_t unsigned_data; } lcp_policy_data_t; #endif /* __TXT_LCP_H__ */ tboot-1.8.0/include/lcp2.h0000644000000000000000000001344212272416301013433 0ustar 00000000000000/* * Copyright 2001 - 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 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_H__ #define __TXT_LCP2_H__ #ifndef __packed #define __packed __attribute__ ((packed)) #endif /*--------- 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 Algorithm ------------*/ #define LCP_POLHALG_SHA1 0 /*--------- LCP Policy Type ------------*/ #define LCP_POLTYPE_LIST 0 #define LCP_POLTYPE_ANY 1 /*--------- LCP reserved TPM NV Indices ------------*/ #define INDEX_LCP_DEF 0x50000001 #define INDEX_LCP_OWN 0x40000001 #define INDEX_AUX 0x50000002 /*------ Default Permission, size and locality for reserved Indices --------*/ #define PERMISSION_DEF 0x00002000 #define PERMISSION_OWN 0x00000002 #define PERMISSION_AUX 0x0 #define DATASIZE_POL 54 #define DATASIZE_AUX 64 #define LOCALITY_DEFAULT 0x1f #define WR_LOCALITY_AUX 0x18 /*--------- Other data structures of LCP Policy ------------*/ #define SHA1_LENGTH 20 #define SHA256_LENGTH 32 #define SHA384_LENGTH 48 #define SHA512_LENGTH 64 #define SM3_LENGTH 32 typedef union { uint8_t sha1[SHA1_LENGTH]; uint8_t sha256[SHA256_LENGTH]; uint8_t sha384[SHA384_LENGTH]; uint8_t sha512[SHA512_LENGTH]; uint8_t sm3[SM3_LENGTH]; } lcp_hash_t; #define LCP_DEFAULT_POLICY_VERSION 0x0202 #define LCP_DEFAULT_POLICY_CONTROL 0x00 #define LCP_MAX_LISTS 8 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; #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_DEFAULT_POLICY_LIST_VERSION 0x0100 typedef struct __packed { uint16_t version; 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; /*--------- LCP Element sub-types ------------*/ #define LCP_POLELT_TYPE_MLE 0 typedef struct __packed { uint8_t sinit_min_version; uint8_t hash_alg; uint16_t num_hashes; lcp_hash_t hashes[]; } lcp_mle_element_t; #define LCP_POLELT_TYPE_PCONF 1 /* clients that will use this type need a proper defintion of TPM_PCR_INFO_SHORT */ #ifndef TPM_PCR_INFO_SHORT #define TPM_PCR_INFO_SHORT uint8_t #endif typedef struct __packed { uint16_t num_pcr_infos; TPM_PCR_INFO_SHORT pcr_infos[]; } lcp_pconf_element_t; #define LCP_POLELT_TYPE_SBIOS 2 typedef struct __packed { uint8_t hash_alg; uint8_t reserved1[3]; lcp_hash_t fallback_hash; uint16_t reserved2; uint16_t num_hashes; lcp_hash_t hashes[]; } lcp_sbios_element_t; #define LCP_POLELT_TYPE_CUSTOM 3 typedef struct __packed { uuid_t uuid; uint8_t data[]; } lcp_custom_element_t; #endif /* __TXT_LCP2_H__ */ tboot-1.8.0/include/lcp_hlp.h0000644000000000000000000000504512272416301014214 0ustar 00000000000000/* * Copyright 2001 - 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 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_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_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_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_signature_size(get_signature(pollist)); return size; } #endif /* __TXT_LCP2_HELPER_H__ */ tboot-1.8.0/include/mle.h0000644000000000000000000000611612272416301013350 0ustar 00000000000000/* * 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: */ tboot-1.8.0/include/tb_error.h0000644000000000000000000000713612272416301014414 0ustar 00000000000000/* * 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; extern void print_tb_error_msg(tb_error_t error); extern bool read_tb_error_code(tb_error_t *error); extern bool write_tb_error_code(tb_error_t error); extern 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: */ tboot-1.8.0/include/tb_policy.h0000644000000000000000000003156512272416301014565 0ustar 00000000000000/* * 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: */ tboot-1.8.0/include/tboot.h0000644000000000000000000001471312272416301013724 0ustar 00000000000000/* * 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 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; typedef struct __packed { /* version 3+ fields: */ uuid_t uuid; /* {663C8DFF-E8B3-4b82-AABF-19EA4D057A08} */ uint32_t version; /* currently 0.6 */ 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 */ } 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 }} /* * used to log tboot printk output */ typedef struct { uuid_t uuid; uint32_t max_size; uint32_t curr_pos; char buf[]; } tboot_log_t; /* {C0192526-6B30-4db4-844C-A3E953B88174} */ #define TBOOT_LOG_UUID {0xc0192526, 0x6b30, 0x4db4, 0x844c, \ {0xa3, 0xe9, 0x53, 0xb8, 0x81, 0x74 }} extern tboot_shared_t *g_tboot_shared; static inline bool tboot_in_measured_env(void) { return (g_tboot_shared != NULL); } 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); } #endif /* __TBOOT_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/include/uuid.h0000644000000000000000000000522412272416301013540 0ustar 00000000000000/* * 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: */ tboot-1.8.0/lcptools/Linux_LCP_Tools_User_Manual.doc0000644000000000000000000061600012272416301020574 0ustar 00000000000000ŠĻą”±į>ž’ ‰‹ž’’’…†‡ˆ’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ģ„Į#` ųæĆ8bjbjm„m„ õĻϰ0’’’’’’¤č1č1č1č1č1č1č1ü1ŒiŒiŒi8Äiģ°jlü1GŪü(kŲmmmm onxq“,r\ĘŚČŚČŚČŚČŚČŚČŚ$CŽh«ąģŚč1$učnčn"$u$uģŚč1č1mmčŪōxōxōx$ulč1mč1mĘŚōx$uĘŚōxōx*ļĢ;č1č1ā×mk °9–»12ČŒivč*ÓR‚ŚDŪ0GŪ|Óf;āxw$;ā¤ā×;āč1ā× ˆr®6s|ōx²sdtˆrˆrˆrģŚģڜxXˆrˆrˆrGŪ$u$u$u$uü1$ 2$D2DˆPü1 2D2ˆPü1ü1ü1č1č1č1č1č1č1’’’’  Intel® Trusted Execution Technology – Launch Control Policy Linux Tools User Manual Updated 11/28/07 Information in this document is provided in connection with Intel® products. No license, express or implied, by estoppels or otherwise, to any intellectual property rights is granted by this document. Except as provided in Intel’s Terms and Conditions of Sale for such products, Intel assumes no liability whatsoever, and Intel disclaims any express or implied warranty, relating to sale and/or use of Intel products including liability or warranties relating to fitness for a particular purpose, merchantability, or infringement of any patent, copyright or other intellectual property right. Intel products are not intended for use in medical, life saving, or life sustaining applications. Intel may make changes to specifications and product descriptions at any time, without notice. The API and software may contain design defects or errors known as errata which may cause the product to deviate from published specifications. Current characterized errata are available on request. This document and the software described in it are furnished under license and may only be used or copied in accordance with the terms of the license. The information in this document is furnished for informational use only, is subject to change without notice, and should not be construed as a commitment by Intel Corporation. Intel Corporation assumes no responsibility or liability for any errors or inaccuracies that may appear in this document or any software that may be provided in association with this document. Except as permitted by such license, no part of this document may be reproduced, stored in a retrieval system, or transmitted in any form or by any means without the express written consent of Intel Corporation. Contact your local Intel sales office or your distributor to obtain the latest specifications and before placing your product order. Copies of documents which have an ordering number and are referenced in this document or other Intel literature may be obtained by calling 1-800-548-4725 or by visiting Intel’s website at  HYPERLINK "http://www.intel.com" http://www.intel.com. Contents  TOC \o "1-3" \h \z \u  HYPERLINK \l "_Toc176025230" 1 Introduction  PAGEREF _Toc176025230 \h 4  HYPERLINK \l "_Toc176025231" 2 Commands  PAGEREF _Toc176025231 \h 5  HYPERLINK \l "_Toc176025232" 2.1 Pre-requisites  PAGEREF _Toc176025232 \h 5  HYPERLINK \l "_Toc176025233" 2.2 tpmnv_defindex  PAGEREF _Toc176025233 \h 6  HYPERLINK \l "_Toc176025234" 2.3 tpmnv_relindex  PAGEREF _Toc176025234 \h 8  HYPERLINK \l "_Toc176025235" 2.4 tpmnv_lock  PAGEREF _Toc176025235 \h 9  HYPERLINK \l "_Toc176025236" 2.5 tpmnv_getcap  PAGEREF _Toc176025236 \h 10  HYPERLINK \l "_Toc176025237" 2.6 lcp_crtpconf  PAGEREF _Toc176025237 \h 11  HYPERLINK \l "_Toc176025238" 2.7 lcp_crtpol  PAGEREF _Toc176025238 \h 12  HYPERLINK \l "_Toc176025239" 2.8 lcp_writepol  PAGEREF _Toc176025239 \h 14  HYPERLINK \l "_Toc176025240" 2.9 lcp_readpol  PAGEREF _Toc176025240 \h 15  HYPERLINK \l "_Toc176025241" 2.10 lcp_mlehash  PAGEREF _Toc176025241 \h 16  Introduction In order for Intel® Trusted Execution Technology (Intel® TXT) Launch Control Policy (LCP) to function, the Platform Owner needs the ability to establish a policy on the platform. The LCP Tools described in this document allow end-users to create policies and provision a TPM with the policies. This document does not describe the Intel® TXT Launch Control Policy functionality. That will be provided in a separate specification to be released shortly. Commands Pre-requisites In order to run the tpmnv_* commands, a TPM driver and TSS (TPM Software Stack) must be loaded. On Linux versions after 2.6.17, the tpm_tis v1.2 TPM driver should be available. It should be loaded as ‘modprobe tpm_tis’, but in some cases that does not work and it is required to be loaded as ‘modprobe tpm_tis force=1 interrupts=0’. The TSS used does not need to be fully v1.2 compliant but it must at least support the TPM NV (TPM non-volatile memory) commands (Tspi_NV_*). The latest (CVS) version of the TrouSerS TSS has this support. tpmnv_defindex Function: This command is used to define the TPM NV index where the LCP policies are stored. This command can also be used to define non-LCP TPM NV indices. Usage: tpmnv_defindex -i index [-s size] [-pv permission_value] [-p password] [-av authentication_value] [-wl write_locality] [-rl read_locality] [-h] Options: -i index: UINT32 or String, the index value to define 3 strings are supported for the reserved LCP indices. Strings and default index values for each string are: “default”: 0x50000001 (INDEX_LCP_DEF), ”owner”: 0x40000001 (INDEX_LCP_OWN), “aux”: 0x50000002 (INDEX_LCP_AUX) -pv permission: UINT32, the permission value of the index Default permission value for indices: INDEX_LCP_DEF: 0x00002000; INDEX_LCP_OWN: 0x00000002; INDEX_LCP_AUX: 0x00000000. This is optional for the above indices but required for others. -s data size: UNIT32, the size of the index Default value for indices: INDEX_LCP_DEF: 34 bytes; INDEX_LCP_OWN: 34 bytes; NDEX_LCP_AUX: 64 bytes. This is optional for the above indices but required for others. -av auth value: string, the authentication value for this index Authentication value for the defined index; it is the password for the NV if the permission is AUTHWRITE or AUTHREAD. -p password: string, the TPM owner password -wl write_locality: UINT8, the write locality attributes for this index -rl read_locality: UINT8, the read locality attributes for this index -h help, print help message Examples: tpmnv_defindex –i 0x00011101 –pv 0x4 –s 34 –av 123456 –p 123456 tpmnv_defindex –i aux tpmnv_relindex Function: This command is used to release a previously-defined index. This command only can be used by TPM owner. Usage: tpmnv_relindex -i index -p passwd [-h] Options: -i index: UINT32 or String, the index value for releasing 3 strings are supported for the reserved LCP indices. Strings and default index values for each string are: “default”: 0x50000001 (INDEX_LCP_DEF), ”owner”: 0x40000001 (INDEX_LCP_OWN), “aux”: 0x50000002 (INDEX_LCP_AUX) -p password: string, the TPM owner password -h help, print help message Examples: tpmnv_reldndex –i 0x00011101 –p 123456 tpmnv_defindex –h tpmnv_lock Function: This command will lock the TPM NV. This command is specifically used by platform manufacturers once the platform personalization process is complete. TPM NV lock is a one-way operation: after locking the TPM NV cannot be unlocked. Usage: tpmnv_lock [-f] [-h] Options: -f force Lock the TPM NV without warning. -h help Print out the help message. Examples: tpmnv_lock –f tpmnv_getcap Function: Display the either the list of defined TPM NV indices or the attributes and contents of a specified index. Usage: tpmnv_getcap [-i index_value] [-f password] [-h] Options: -i index value: UINT32 or String 3 strings are supported for the reserved LCP indices. Strings and default index values for each string are: “default”: 0x50000001(INDEX_LCP_DEF), ”owner”: 0x40000001(INDEX_LCP_OWN), “aux”: 0x50000002(INDEX_LCP_AUX) If this option is specified, then the public data of the index will be displayed. -f password: String Display the TPM_PERMANENT_FLAGS and TPM_STCLEAR_FLAGS contents -h help Print out the help message. Examples: tpmnv_getcap –i 0x00011101 tpmnv_getcap lcp_crtpconf Function: Create a platform configuration measurement. The produced platform configuration measurement will be appended to the input file in binary mode. Usage: lcp_crtpconf -p PCR_index1,PCR_index2,...,PCR_indexn [-f filename] [-h] Options: -p PCR_index1,PCR_index2,...,PCR_indexN Index values can be 0-23. -f file_name: string File name to which the measurement is appended. -h help Print out the help message. Examples: lcp_crtpconf –p 0,1,2,3 –f pconf_file lcp_crtpol Function: The command is used to create an LCP policy (and optionally policy data), which can later be written to the TPM. Usage: lcp_crtpol -t policy_type [-a hashalg] [-v version] [-sr SINIT revocation_counter] [-s srtm_file] [-m mle_file] [-o policyfile] [-b policydata_file] [-pcf Policy_Control_Field] [-h] Options: -t Policy type: UINT8 or string 5 strings are supported for the reserved LCP Policy Types. Strings and default policy type values for each string are: “hashonly”: 0 (POLTYPE_HASHONLY) “unsigned”: 1 (POLTYPE_ UNSIGNED) ”any”: 3 (POLTYPE_ ANY) ”forceowner”: 4 (POLTYPE_ FORCEOWNERPOLICY) -a Algorithm: UINT8 or string Currently we only support SHA-1 algorithm: POLHALG_SHA1(0 or “sha1”). -v Version: UINT8 Version number. Currently it must be set to 0 if specified. -s PConf file name: String File name of the Platform Configuration data, as produced by lcp_crtpconf. -m MLE file name: String File name of file containing MLE hash values. This is a text file that contains one SHA-1 hash per line. The values of the hash must be hexadecimal values, specified either a single un-deliminated set or as space-delimited two-character (i.e. one byte) values. This can be produced by the lcp_mlehash command. -o policy file name: String File name to store the output policy. -b policy_data file name: String File name to store the LCP Policy data. -sr SINIT Revocation count number: UINT8 -pcf policy control field: UINT32 -h help. Print out the help message. Examples: lcp_crtpol –t 0 –r 0,0,0 –m mle_file –o policy_hashonly_file lcp_crtpol –t 1 –m mle_file –s pconf_file –o policy_unsigned_file –b policy_data_file lcp_crtpol –t 3 –o policy_any_file lcp_crtpol –t unsigned –a sha1 –m mle_file –s pconf_file –o policy_unsigned_file –b policy_data_file lcp_writepol Function: The command is used to write LCP Policy into a (previously-defined) TPM NV index. It also supports writing arbitrary data into a specified index. Usage: lcp_writepol -i index_value [-f policy_file] [-p passwd] [-e] [-h] Options: -i index: UINT32 or String. Index for writing 3 strings are supported for the reserved LCP indices. Strings and default index values for each string are: “default”: 0x50000001(INDEX_LCP_DEF), ”owner”: 0x40000001(INDEX_LCP_OWN), “aux”: 0x50000002(INDEX_LCP_AUX) -f file_name: string File name of where the policy data is stored. Mutually exclusive with –e option. -p password: string, the TPM owner password -e: write 0 length data to the index This is useful for special indices, such as those whose permission is WRITEDFINE. Mutually exclusive with –f option. -h help Print out the help message. Examples: lcp_writepol –i default –f policy_file lcp_writepol –i 0x00011101 –e lcp_writepol –i 0x00011101 –f policy_file –p 123456 lcp_readpol Function: The command is used to read the contents of an LCP policy index. Any index can be specified but the output will be parsed as if it contained a policy. Usage: lcp_readpol -i index_value [-f output_file] [-s size] [-p passwd] [-h] Options: -i index: UINT32 or String. Index for reading 3 strings are supported for the reserved LCP indices. Strings and default index values for each string are: “default”: 0x50000001(INDEX_LCP_DEF), ”owner”: 0x40000001(INDEX_LCP_OWN), “aux”: 0x50000002(INDEX_LCP_AUX) -f file_name: string File name to write the policy data to. If no file name is specified then the contents will be displayed. -s size to read: UINT32 Value size to read from NV store. If no size inputted, read by length as this index defined. -p password: string, the TPM owner password -h help Print out the help message. Examples: lcp_readpol –i default –f policy_file lcp_readpol –i 0x00011101 –s 10 lcp_readpol –i 0x00011101 –f policy_file –p 123456 lcp_mlehash Function: The command is used to generate a SHA-1 hash of the portion of an executable file that contains the Intel® TXT measured launched environment (MLE). In the MLE binary file, the portion of the file to be used as the MLE is specified in the MLE header structure. If verbose mode is not used, the output is suitable for use as the mle_file to the lcp_crtpol command. Usage: lcp_mlehash [-h] [-v] mle_file Options: mle_file: string File name of the MLE binary. If it is a gzip file then it will be un-zip’ed before hashing. -v Verbose mode. -h help Print out the help message. Examples: lcp_mlehash sboot.gz        FQXYZ\lmĶĪ+ , ‰ Š ė ģ T U ¶ · ~  Ü Ż < = „ ¦  ] ^ ¼ ½ ļįϻϩ•©Ž†~vmcmcmcmcmcmcmcmcmcmcmcmcmchŽ\h™-ĻaJo(hŽ\h™-ĻaJh™-ĻCJ$aJ$h² >CJaJh² >CJ$aJ$ hyg&h™-Ļ&hZ@h™-Ļ5B*CJ(\aJ(o(ph’#hZ@h™-Ļ5B*CJ(\aJ(ph’&hZ@hć8:5B*CJ(H*\aJ(ph’#hZ@hć8:5B*CJ(\aJ(ph’h™-ĻB*CJ(aJ(o(ph’ hō_’h™-ĻB*CJ(aJ(o(ph’&AYZ[\ F P$©”Ŗa¶óóóóóå×ĪÉÉĮ»»»»µ°®®¬8gd™H$gd™H$gdǁ$a$gd² >gdǁ„Z`„ZgdZ@ $„ZWD–`„Za$gdǁ $„ZWD–`„Za$gdZ@ „XH$WD–`„XgdZ@°8Ā8żż½  OP€ßą…†defˆ‰ŠžŸ ”Ø©Ŗ«ĀĆÄÅ÷ķ÷ķ÷ķ÷ķ÷ķ÷ķ÷ēŚ÷ŹŚæŚ÷¶®§ ŠxŠeWhŅ#-h™0JmHnHu$jhŅ#-h™0JUmHnHu"hųYCJKHOJQJaJnHtH+jhųYCJKHOJQJUaJnHtH h™h™-Ļ h™hć8:h™hć8:o(h™h™-ĻaJhŽ\h™-Ļ0JaJjhŽ\h™-ĻUaJjhŽ\h™-ĻUaJ h™-ĻaJhŽ\h™-ĻaJo(hŽ\h™-ĻaJÅįāćäåęņóō234567?@A[öč̹čŸč”…”t…i…¹Ÿ¹čöčM¹čŸč”…”6jÅh™h™>*B* UaJmHnHph`ØuhĄ4mHnHu jHh™UmHnHujh™UmHnHuh™mHnHu2h™B*CJOJPJQJaJmHnHph’tHu$jhŅ#-h™0JUmHnHu6jĖh™h™>*B* UaJmHnHph`ØuhŅ#-h™0JmHnHuh™mHnHu[\]^_`abc€‚…†”•–°±²³“µ¶·øŌÕļąÕąĀØĀš‘šuĀšØšjąjYąÕąĀØĀš‘š j<h™UmHnHuh™mHnHu6jæh™h™>*B* UaJmHnHph`Øuh™mHnHuhŅ#-h™0JmHnHu2h™B*CJOJPJQJaJmHnHph’tHu$jhŅ#-h™0JUmHnHuhĄ4mHnHujh™UmHnHu jBh™UmHnHuÕÖ׌Ūéźė     )*+,/0>?@ZäŃƩƞž~sŃ©ŃĆjĆNŃƩƞž6j³h™h™>*B* UaJmHnHph`Øuh™mHnHuhĄ4mHnHu j6h™UmHnHujh™UmHnHuh™mHnHu2h™B*CJOJPJQJaJmHnHph’tHuhŅ#-h™0JmHnHu$jhŅ#-h™0JUmHnHu6j¹h™h™>*B* UaJmHnHph`Øu¶ `±Y«’R¦ØµÜ{„“óᯱĄĖ^żżżżżżżżżõģēēāŻŲŲŲŲŻĖĀ„C^„Cgdǁ „¤„X^„¤`„XgdZ@gdǁgd™gdZ@gdǁ„`„gdZ@ & FgdǁZ[\]^_`ab~€„…‘«¬­®Æ°±²³ĻŠļąÕąĀØĀš‘šuĀšØšjąjYąÕąĀØĀš‘š j*h™UmHnHuh™mHnHu6j­h™h™>*B* UaJmHnHph`Øuh™mHnHuhŅ#-h™0JmHnHu2h™B*CJOJPJQJaJmHnHph’tHu$jhŅ#-h™0JUmHnHuhĄ4mHnHujh™UmHnHu j0h™UmHnHuŠŃŅÕÖāćäž’#$%&)*678RäŃƩƞž~sŃ©ŃĆjĆNŃƩƞž6j”h™h™>*B* UaJmHnHph`Øuh™mHnHuhĄ4mHnHu j$h™UmHnHujh™UmHnHuh™mHnHu2h™B*CJOJPJQJaJmHnHph’tHuhŅ#-h™0JmHnHu$jhŅ#-h™0JUmHnHu6j§h™h™>*B* UaJmHnHph`ØuRSTVWXYZ[wxyz}~ˆ‰Š¤„¦Ø©Ŗ«¬­ÉŹļąÕąĀØĀš‘šuĀšØšjąjYąÕąĀØĀš‘š j h™UmHnHuh™mHnHu6j›h™h™>*B* UaJmHnHph`Øuh™mHnHuhŅ#-h™0JmHnHu2h™B*CJOJPJQJaJmHnHph’tHu$jhŅ#-h™0JUmHnHuhĄ4mHnHujh™UmHnHu jh™UmHnHuŹĖĢĻŠÜŻŽųłśüżž’ #$/01KäŃƩƞž~sŃ©ŃĆjĆNŃƩƞž6j h™h™>*B* UaJmHnHph`Øuh™mHnHuhĄ4mHnHu j h™UmHnHujh™UmHnHuh™mHnHu2h™B*CJOJPJQJaJmHnHph’tHuhŅ#-h™0JmHnHu$jhŅ#-h™0JUmHnHu6j• h™h™>*B* UaJmHnHph`ØuKLMOPQRSTpqrswxƒ„…Ÿ ”£¤„¦§ļąÕąĀØĀš‘šuĀšØšjąjYąÕąĀØA/jhųY@ˆCJKHOJQJUaJnHtH j h™UmHnHuh™mHnHu6j‰ h™h™>*B* UaJmHnHph`Øuh™mHnHuhŅ#-h™0JmHnHu2h™B*CJOJPJQJaJmHnHph’tHu$jhŅ#-h™0JUmHnHuhĄ4mHnHujh™UmHnHu j h™UmHnHu§ØµĒČęģķó5ANPgiw¢„ŪÜ{‚ƒųōåÕåʶĘå¢å“å„å“å“¢q¢qa“Q“MIhÄ"h±hÄ"hÄ"CJH*OJQJaJh™-ĻCJOJQJaJnHtH$hÄ"hÄ"CJOJQJaJnHtHhÄ"hķ#gCJOJQJaJhÄ"hÄ"CJOJQJaJ'hÄ"h™-ĻCJOJQJaJnHo(tHhÄ"hć8:CJH*OJQJaJhÄ"hć8:CJOJQJaJhÄ"h™-ĻCJH*OJQJaJhÄ"h™-ĻCJOJQJaJh™-Ļh™-ĻnHtHƒ„‡ˆ’·¹ŗĘćń¹ŃŲŁŚŽąį®°±·¼½æĄŹĖŅ *J\^elnostŸ§©«ČÉōųłüųōķųéōéōéōųåųåųōųåįåŻÖĻÖŻĒæ»å»å»å»·ĒŖ›Ŗ›ŽŖ„Ŗ›„Ŗ›Ŗ›ŖhĒ'üB*aJphh"Åh °B*aJphh"Åhb NB*aJo(phh"Åhb NB*aJphh"Åh—@ŌhC :hC :5hC :hb N5 h™hb£ h™hb Nhb Nh™hĒ'üh3G¶ h™hÄ"h4;hÄ"hK+4^e­ßł9¦ĪōRy–³Š?[uņåŲŲņ˾¾¾¾Ė±¾¾¾ØĖ±¾„Z`„ZgdZ@ „H„Z^„H`„ZgdZ@ „ģ„Z^„ģ`„ZgdZ@ „;„Z^„;`„ZgdZ@ „„Z^„`„ZgdZ@ „¤„Z^„¤`„ZgdZ@ „¤„X^„¤`„XgdZ@ł89Pm|ƒŽ£¤„¦§®Æ°±»¼½ŹĖĪĻŌÕįāćšńōõųł.1RSZe‡ˆ‰¤„¦ĮĆ÷óļóźåźįŁźŁŃŹĘåĘŹåŹļåæåŹĘåĘŹļåæåŹ“Ø“•Ø“؝ŽóŽŃŹŃŹóŃŹóŃŹó hhJĒh"ÅhĒ'ümH sH h°‚h"ÅmH sH h°‚h°‚mH o(sH h°‚h°‚mH sH  hb Nh°‚h°‚ hb Nh"Åhb Nh"Åo(hb NhõZ o(hõZ h°‚o( hõZ o(hĒ'üh"ÅhC :hb N58ĆÅĢĶĪĻŠŲż?@ijklmsuƒ…†ŒŽœŸ„§«¬±×éźģ,0:EIVWX[ ”¼Īė2\gxy€ƒ…łõłķõčćߌßćõŅĖŅõŅĘŅõłõĘõłĖõĖŅĖõčćßćßćõæ·æ·æ³·³·æõčõ¬õ¬õ¬õ¤Ÿ¤õ h"Å5h8(ėh"Å5 h‚{qh"ÅhĄ4hjhåh"Åo( hjhåh"Å hzi!o( hÆXóh"ÅhÆXóh"Åo( hĒ'üo(hĒ'ü hÉR‘o( h"Åo(hb Nh"Åo(h"Å hb Nh"Å=u¬ģ,£Ļ]yƒÅŻķ÷_gŽ˜ÕņņåŲņŲŲŲŲĻĘĘĮĻøĻ«ĻŲ „¤„Z^„¤`„ZgdZ@„C^„Cgdǁgd™„Z`„ZgdZ@„X`„XgdZ@ „;„Z^„;`„ZgdZ@ „H„Z^„H`„ZgdZ@ „ģ„Z^„ģ`„ZgdZ@…‹ĒĶŁÜŽģķ÷$^_gnpquˆŽ—˜ÓīćÖŅĶÉÅĮ¹ŅµŅŧ–ƒpƒ–ƒ_SIDŅ h±o(hžc›h±5o(h„Pæh‚{q5mHsH!h„Pæh‚{qB*aJmHphsH$h„Pæhß@B*aJmHo(phsH$h„Pæh±B*aJmHo(phsH!h„Pæh±B*aJmHphsHh„Pæh±5mHo(sHhĒ'üh‚{qh‚{q5h±h‚{qh™ hk"€o(h"Åh"Åh"ÅB*aJphh„Pæh"ÅmHsH!h„Pæh"ÅB*aJmHphsHÓŌÕ  * ? A B C J L M W X Y f g j k p q } ~  Œ   ‘ ” ” ¢ £ ° ± “ Ķ ß ź ū ü !!!!!!!!!śöńķåńåŽķńķńŽŚńŽńŽķńķŽŚńŽńŽĻĆĻ»ĆĻĆĻöśö“ö¬§¬ö–ƒ–ƒ–$h„Pæh"ÅB*aJmHo(phsH!h„Pæh"ÅB*aJmHphsH h"Å5h8(ėh"Å5 h‚{qh"Åh“F1mH sH h°‚h°‚mH o(sH h°‚h°‚mH sH h“F1 hb Nh°‚hb Nh°‚o(h°‚ h°‚o(h"Å h"Åo(1ÕB j  “ ą ü !/!C!O!Y!B"J"_"h"q"“"›"ø"ņņņņååÜÓÓĪÜÅÜøÜø«ø« „H„Z^„H`„ZgdZ@ „ß„Z^„ß`„ZgdZ@„Ž^„Žgdǁgd™„Z`„ZgdZ@„X`„XgdZ@ „;„Z^„;`„ZgdZ@ „ģ„Z^„ģ`„ZgdZ@!1!7!B!D!E!O!Y!Ź!Ł!" ","/"@"B"J"P"Q"V"X"Y"Z"_"h"i"p"q"u"ˆ""‘"›"œ"¶"·"ø"æ"Ą"Ā"É"Ź"Ī"Ļ"Š"Ņ"Ž"õčäąÜÕĶÉÅÉĮÉĮɽ³½¬¤¬¤¬¤³½Ÿ½˜“‹“½˜‹˜½ƒ~ƒ½¬¤ą½ązhįi£ hQNW5h8(ėhQNW5h-ģhQNWo( hQNWo( h-ģhQNW h“F1o(hłhQNWo( hłhQNWh s=hQNW5o(hQNWh“F1h7&Yhūh s=hQNW5 h‡:ęh‡:ęhłh™h"Åh"Åh"ÅB*aJphh„Pæh"ÅmHsH.ø"Ā"Ń"ß"é"T#\##–#·#$$K$p$“$å$ł$8%A%öéäöŪöéöĪĮĮĮĮ“§š§ „H„Z^„H`„Zgd² > „h„Z^„h`„Zgd² > „H„Z^„H`„ZgdZ@ „ģ„Z^„ģ`„ZgdZ@ „;„Z^„;`„ZgdZ@„Ž^„Žgdǁgd™ „ß„Z^„ß`„ZgdZ@„X`„XgdZ@Ž"ß"é"š"õ"S#T#\#b#i#k#z#ˆ##–#¬#·#ś#$ $!$#$$$%$,$.$/$9$:$G$H$K$L$Q$R$^$_$l$m$p$q$t$$‚$$$“$„$®$ä$å$%8%?%@%A%B%üōšģšåŪģåģå×åŪåÓĪŹĀĪĀ»ŹĪŹĪ»Ī»Ī»ŹĪʻλλ°¤°¤°¤°ģšģ×–åŽåhåjWhÓ. o( h² >h² > h-ģhÓ. h°‚h°‚mH o(sH h°‚h°‚mH sH  hb Nh°‚hb Nh°‚o(h°‚ h°‚o(hF1h² >h8(ėhÓ. 5o( håjWhÓ. hÓ. h“F1h8(ėhÓ. 5h‡:ę8B%\%]%d%e%g%m%t%ˆ%Ž%%•%—%œ%%§%­%Æ%6&7&8&?&D&F&L&N&O&Z&d&i&†&‡&&’&“&ž&Ø&¬&·&ø&¹&ŗ&Š&Ó&Ō&÷ščćčßŲßŲŌĶÅĶĮ¹µ°µØ”—ˆµµµµ—µµµ„µµ„xph-ģhhbņo( h-ģhhbņ hhbņo(h“F1hł 3hhbņo( hł 3hhbņhė6éhhbņ5o( håjWhhbņhåjWhhbņo( hµc o(hhbņhė6éhhbņ5håjWhåjWh±o( håjWh±h™ håjWhÓ. hÓ. hÓ. 5h8(ėhÓ. 5 h-ģhÓ. h-ģhÓ. o(,A%]%g%‚%%%§%8&?&‡&&ŗ&Ō&é&'#'@'J'q'}'‡'ų'’'R(ņéÜÜ×éĪéÜéÜņÜņÜņéÜ×éĪéÜ„Ž^„Žgdǁgd™ „ß„Z^„ß`„ZgdZ@„X`„XgdZ@ „H„Z^„H`„ZgdZ@Ō&č&é&ó&''$'>'?'@'G'H'J'K'P'R'X'Y'['\']'^'_'b'p'r'w'y'z'|'}'‡'ˆ'“'›'ž'Ÿ'„'Ø'²'÷'ų'’'((( (Q(ü÷šüšģäšģÜ×ÜģŠČŠģĆüĆüĆüģæø°ø°¬¤ › › ›ü ü—†~†~†hāGthŁ?³o( hāGthŁ?³hė6éhŁ?³5o(hŁ?³ hµc o(hµc hė6éhŁ?³5h”+Źh”+Źh±o( h”+Źh±h™ h$Ļo(hł 3hhbņo( hł 3hhbņ hhbņ5h8(ėhhbņ5h-ģhhbņo(hhbņ h-ģhhbņ hhbņo(h“F1/Q(R(”(•(µ(¶(æ(Ō(Ž(ß(').)9)?)T)U)Z)[)\)d)e)f)g)h)j)z){)|))‚)Š)‹)Œ))Ž))˜)™)”)¢)£)Ø)©)¬)­)®)°)±)³)»)¼)æ)Ą)Į)Ę)Ē)Ń)śļćÜŌŹĘĮƼø¼°¼°©¼ø¼ø©¤©¼¼•©ø¼ø©¤©¼Ž¼•©ø¼ø©¤©¼Ž¼•©ø¼ hø hø hēNyhŁ?³o( hēNyhø  h qÆo( hēNyhŁ?³hb Nhø o(hø  hø o( h“F1o(hŁ?³hė6éhŁ?³5o(hXRhŁ?³o( hāGthŁ?³h„Pæh°‚mHo(sHh„PæhŁ?³mHsH h°‚o(8R(•(¶(æ(ß([)|)£)Į)ņ)*V*h*¤*æ* +#+\,y,Ÿ,Ą,č,ņņéÜϵµµÜµÜµÜĻÜĻÜĻÜĻ „H„Z^„H`„ZgdZ@ „„Z^„`„ZgdZ@ „ģ„Z^„ģ`„ZgdZ@ „ß„Z^„ß`„ZgdZ@„X`„XgdZ@ „±„Z^„±`„ZgdZ@Ń)Ņ)Ó)Ō)Õ)×)ß)ą)š)ń)ņ)****9*M*N*R*S*U*V*]*g*h*x*£*¤*¾*æ*Š*Ż*ę*ė*+ +"+#+%+[,\,y,{,˜,,ž,Æ,æ,Ą,ē,č, ----:-<->-X-Z-a-b-d-üõšõėäŻäėÕŃĢŃäüėüėüėÄŃĄŃõĄŃĄŃõѼõ¼õ¼Ńõ¼õŃõ¼õ¼Ń¼ŃõÕѵѵѰŃÕõØ£Ø hŁ?³5h8(ėhŁ?³5 hŁ?³o( hķkŠhŁ?³hšf¶h“F1hēNyhø o( h“F1o(hŁ?³hēNyhŁ?³o( hø hø  hēNyhø  hø o( h qÆo( hēNyhŁ?³hø >č,-3-=-Z-d-”-ē-ų-.G...š.-/4/w/€/®/0B0ņååŲĻååĀåņؽϓĻņĻņŲŲ„Ž^„Žgdǁgd™ „'„Z^„'`„ZgdZ@„X`„XgdZ@ „ģ„Z^„ģ`„ZgdZ@ „ß„Z^„ß`„ZgdZ@ „¤„Z^„¤`„ZgdZ@d-i-k-l-n-o-t-u-}-”-¦-Ø-©-«-¬-ų-ż-’-.... .".#.%.&.).1.5.9.€.‚.‡.‹.Œ.Ž..˜.™.š.›.¦.®.·.».Ē.É.Ž.ä.å.ę.ź.ė./,/-/3/4/łńłńłķéäķłńłńłķłńłńłķłńłńłķßķßķŪŌĢŌĢČĄ»·³®³®³®³Ŗ®³Ŗ³„Ŗ”“»hžc›h±5o(h‰zhÆSÅ h‰zo(hšf¶ hµc o(hµc h“Rŗ h±o(h‚{qh“Rŗ5h8›h8›h±o( h8›h±h™ h qÆo( hæxo(hæxhŁ?³hāGthŁ?³o( hāGthŁ?³:4/9/=/>/@/A/r/v/w/x//€/œ/¢/­/®/ń/ų/00000#0$0%0&00010>0?0B0C0H0I0U0V0c0d0g0h0k0x0y0†0‡0Š0Œ0ž0Ÿ0«0±0Ė0łńłńķłńéį×įÓĖÓĘĮ½µĮµ®½Į½®Į®Į®Į®½Į½®Į®Į®£—£—£—£Ó“ÓŒ„ŒhēNyhŁ?³o( hēNyhŁ?³hÆSÅh°‚h°‚mH o(sH h°‚h°‚mH sH  hb Nh°‚hb Nh°‚o(h°‚ h°‚o( hŁ?³o(hŠ[hŁ?³o(hŁ?³hó ŻhŁ?³5o(hó ŻhŁ?³5h±h.%=h“Rŗh±o( h“Rŗh±4B0g0Š0Ÿ0ń01B1¹1Į1Ž1č12-2a2n2y233_3h3ņņåŲĖåņåņµµµ°Ā§ĀåĀ„Ž^„Žgdǁgd™ „ß„Z^„ß`„ZgdZ@„X`„XgdZ@ „;„Z^„;`„ZgdZ@ „H„Z^„H`„ZgdZ@ „¤„Z^„¤`„ZgdZ@ „ģ„Z^„ģ`„ZgdZ@Ė0š0ń0 111%1A1B1Q1U1s1t1z1…1ø1¹1Ā1Ü1Ż1Ž1å1ę1č1ķ1ń1ņ1ō1õ1ų1’1222222-222627292:2`2b2g2j2k2m2n2w2x2y2üųōļōčüčüįüįüįüįųŁįŌĢĒĢĄøĄø“ųÆųĄøĄø“ųĄøĄø“ų«¤œ¤œ˜‹‡hZ*É hZ*Éo(h‚{qhZ*É5hŽ+öhŽ+öh±o( hŽ+öh±h™ hk"€o(h:M×h“Rŗh:M×o( h“Rŗh:M× hŁ?³5h8(ėhŁ?³5 hŁ?³o(hēNyhŁ?³o( hēNyhŁ?³ hŁ vhŁ?³ h.%=o(h.%=hŁ?³hÆSÅ4y2z2„2Œ2”2Ø2«2¬2­2³233333 3!3#3$33343B3C3D3M3N3O3X3Y3Z3^3_3h3„3Š33•3–3Ł3ą3ė34444 4 4444&4'4łńķńéķńéńéłßŚÓĖÓĖĒÓĖÓĖÓĆ»ĖÓĖĆĖ·­©”驚•‘‰•‰‚‘•‘•‚•‚• hb Nh°‚hb Nh°‚o(h°‚ h°‚o( hŠ[h‡oOhŠ[h‡oOo(h‡oOh[(Th‡oO5o(hŠ[hZ*Éh5[.o(h5[.h‰zhZ*Éh±o( hZ*Éh± h±o(hžc›h±5o(hØ1ƒhŃ+Ģh[(ThŃ+Ģo( h[(ThŃ+Ģ3h3–34*4O4r4‡4š45e5‘5™5¶5Ą5ę5696F6Q6¾7ņååååŲåŲåĖŲ¾µŲŲŲ°µ§„Ž^„Žgdǁgd™„X`„XgdZ@ „H„Z^„H`„ZgdZ@ „;„Z^„;`„ZgdZ@ „ß„Z^„ß`„ZgdZ@ „ģ„Z^„ģ`„ZgdZ@ „¤„Z^„¤`„ZgdZ@'4*4+4042434=4>4K4L4O4P4S4`4a4n4o4r4†4‡4‘4¬4®4¾4ļ4š455*5+5d5e5~55ž5“5µ5¶5½5¾5Ą5Å5Č5É5Ė5Ļ5Ö5łõšõšłšłšłåŁåŁåŁåÕŃŹÕŃÅÕ½ÕŃŹ¹“¬Ń§ŃŸŹ˜‹„|„|Ńw hk"€o(hZ*Éh‡oOo( hZ*Éh‡oO h‡oO5h8(ėh‡oO5 hb£h‡oOhĪÜh‡oOo( h‡oOo(h>{Śh‡oOo( h>{Śo(h>{ŚhoT+h‡oOo( hoT+o( hĪÜh‡oOh‡oOhØ1ƒh°‚h°‚mH o(sH h°‚h°‚mH sH  h°‚o(h°‚ hb Nh°‚.Ö5ę5ė5ī5ļ5ń56 666686:6F6O6P6Q6R6\6d6h6U7½7¾7Ä7Å7É7Š7Ń7ć7ä7ķ7ń7ž78Z8[8]8^8k8l8y888‘8˜8™8›8Ÿ8üõķõķüõķõķüéåŻŲåŃÉåÉÅĮŃ·Ų°ÅåÅå¦ÅåŸÅ—ÅåĮÅ叟ˆ€{€° h{#?5h8(ėh{#?5 hb£h{#?hĪÜh{#?o(hoT+h{#?o( hĪÜh{#?h[(Th{#?5o( hZ*Éh{#?hžc›h{#?5o(hųYh„Pæh[(Th{#?o( h[(Th{#? h{#?o(h‚{qh{#?5h{#?h™hZ*Éh‡oOo( hZ*Éh‡oOh‡oO0¾7Å7ä7ķ7ž7[8^8l8t8‘8›8°8²8³8µ8¶8ø8¹8»8öéöÜϹܬöÜ£”£”£”£„Z`„ZgdZ@ „H„Z^„H`„ZgdZ@„ó^„ógd„Pæ „;„Z^„;`„ZgdZ@ „ģ„Z^„ģ`„ZgdZ@ „ß„Z^„ß`„ZgdZ@ „¤„Z^„¤`„ZgdZ@„X`„XgdZ@Ÿ8Æ8°8±8³8“8¶8·8¹8ŗ8¼8¾8æ8Į8Ā8Ć8üųšģšģšģšģčŲčģųjh™UmHnHtHuh™hH+jhH+Uh{#?hųY»8¼8½8¾8Ą8Į8Ā8Ć8żōōėōżŽ „ß„Z^„ß`„ZgdZ@„Z`„ZgdZ@„Z`„ZgdZ@:&P182P:pć8:°Š/ °ą=!°"°# $ %°°R°ā ©`!šLeƽb ŒŌŌ«/d×ÄŻaµ•bfM(ÄģėežxŚģ½Ėrcɒ –UӚ8‚ĶŲģdŅāŒF5Vٲ"Īēą lŌeIܛsė‘S¬{»®ŅŹ($‰dņ ° 0 £Ģ““i„å|€>B m“×GČ“—If2i!4ņg„Gœs@棺o«›‘Ińōšššp÷šˆųäQļŃ£æ—ż—Ÿ>śžĻš~¾€’’üļ’£GO}süō·Ó£§ĒÉĮw_÷żįŃ,łO!ķų’/äļ~š¦üóļĀ’’ėS’żO°µO~ɱC’ęÓ°½Oż;š÷ÓO°6ü“’Éææ’Cų’śo’-ēüo0ń“?łō“Gæ^\¾Zl.NēöžÕæYż“G’Żūææžą’žÆžĒ/ž”ėüTŹ’cjńŃ£’žŚüäÓO’£ć·ėĶāźŃ#ĢūčŃŽ£žčæĘŗż[ųłÆ®’‰Ąō÷čļ’õ D’ާĆOžõ'ųé~ś?žæż}ĀĻ?ō)`Ą~ō蒔ϟ=ś_?ł_>łģ›cÄŪӛÅüźłå"yv¼z±Yüœ¼ī§?õ÷××'ėł«EBæĪ/’Įśåźõõü|‘lļ0ņ¬OnĻ?ƒŖJĪ.N7”ĻE>_œ_,±&H9y¾zsņ&KR®ŹE½•Ø [ždigĢ“ŃHą8_.N6/'˜z{³H^Ģ/× ­ęśäōņā:ˆ;˜&[”ö6Y¼9})µĆ÷7ī»~¹‰r¼>ówż½õfu}½8K–«Ö‰ķmnnOwÉžā µaģōÕTŒ1o1ŠĶ8¹K­7qŃ Ē/>c> f̧æ`{ʐڒä“(üżÆ?AŚēų>ĘĀŌž'Ÿ~ś©ŒRo›š 3)\­`®®å4¹¹¼XbDš%HDO²,ē& ür³bó’š ćÓlÓ nų7KęggįX‡]†ž^¢ƒż¦‘g}ū<±³ĒN8L;»xÕń¶HP|·/®ƒŅ~~ćŪ·pI»W·—\Īuīē·¾1 „4b ¶m Pps3_®/ē›…kK« æ€ć»d›&n§2Åņ¬æ‡kRĆ’üž§ōŁ?}züÅälõ|ńE±Ÿ&@3üŠ’ģ³`‡›ÕĶ— „&O./o׊8D}žżć¤¦<“'õ‰äūŻāf}±Z~™dŁ~J‰3,üł×ūO÷“^.žĻo/7£ļÉĮźźz¾|ū²’p±¹\@‹åfqyrsžü$KÓżÅõś±ÕBĒæL†ƒ¬¤4õe9J&ß@†éźvyv±<Ÿ®Ž|I]G¾9AŹÆ/¾_¬[’³ż"KĖdTķŅ 3®NoÆĖĶӛÕéb½>X]®nÖ_&oēĖä`öĖĶ<łżāņrõ:™^ĪO6EŽoÆÆ//gŠŅźöJ™\C-ėņ±wr¹xµøĢO&OŹ$ŪĻDĻā³üꛓ_ŻĢĻ. &HNćdŖĄyrp@-Šõż¢5›&i­=ß).aIÕ-©ė—sÄŌP+@PŁÉģār£z5ß$Ć}Š+®ß®.@~ęč'ĖÓĖŪ³ÅS@ŌāŒĄ^cĀč„>/6ØŠ”Aėß’jjqž„ļēϾ‡e“:#’Óc¢·Š<^\Ļ9Ŗ‚Z |Žh9\¼ŗ‚L‰Ļųاß]cĚ UH tĘš·¬v¾ČšŸĻÖü„Ÿó¤H†ŌĢÓ§‡ŲDĪéUš KHĶ%ÖQ’ē$āļ‡ÅÕ5Īr"Ų2Ū/“¢ŽĻÓ,¾H^Ź÷EQdūY=„Ŗņ²Ų/‡ć:0ČYY%E‘īgE:ä2žŲÆ.ÆæLž0fx2›ńhOn6Ē ĆŹsšę¹Rqņ÷·—‹›ß./6€ŹŌ•˜]ĪqX-nč7gųa~s¾Ųą,¹¼Ż·ØSIśööźėłŪÅ Ó2–ļ®ĖVæ#辨«d<ĘÖóˆæ)k }Ź+Ŗ}” sß–ĆRZĪķ§@t߯\€öåy|1¤iĮ$ł«›‹3O‘£<©ł¾_›’cżĒ'ŠŁĶf±ˆG'?¼¼½z¾œ_\B “ü‹fׄ?ą\sؼ¶õėśdśvƒ3Öū~Ŗ Ēųūą@c‹’¦¦§ā(i©ŖĀ\€” c®ŖĀ\U5›ić1ę1Ļ~°ōxŒ¹ĘcĢ…Ÿš7ę:8Ą\XņąS0Ļl†©³YUaéŁ Óg3.Ć3¼ ·Č©XRÓ @;žĘ\Ų'ü¹°OŚSNĆįõ=ĀßŲoÅ—Å>įoü†=ĀßXć‰kĘįoģ7žÅXģ¶ÉŲäö1ö cžŁ ćt|rĘ1c‘±„æ¹$÷œ”gŲ6n!×1Ņüƒ¹°ųkāä^sžÅ\Ų?aĘ —Åžįoü†½ćńĒß 9ĘąoĢ…żĆß<ŠL%ŒWn[T@ȕ~tĢ>Ę:ęb¼)^øē =BĪpq»\³ŽēŠ̃½SŹÄŽaiī5§b’š7ębśĘž1Nø,žĘ<Ų»žgJŁ:wsÜS·Ņ°ŅŠRBΔ“ óBĒ”ńĪŠ1Ö¹]ĘB®#¢}cŲ1—¶ĪµsyNē†œg&S39ć†k˜ŃÓÆŸķ\¦’™ĪV?³Ožö™ŗ•ī=żaiOC:Óż(+–ż8 DŠI,ķ±”°*¼Ś.×Ė%³,„üĖ\1“Ÿ<ē’—†Cžī’ņO’³²ä’—F#žī’ņO]ó÷ŗÖ¶kł™L8Å’åŸé”æūæüÓ’ģšcü_ž9:āļž/’¤ī‡ł9Žžęqåļś’B’ņįĮ°œĪŸļųFę°:œĶ&cü?×Ɖ|†ų#ų[OĘ££ŃQQU>ņ9„0Ņ’!:,Ņ|VNŹI=¬‡PFt2•XS±Ģ•ćæī?•b .łŒu! åa؇;ŚIŻ#—ć(Ģ©éœ‡ėEŖ˜Ķźa9Ég.æ@iūR—ŒĮ †zXĆĢöO 8,*ÄB™r 14żĻ°žŃŌZϳ’1µ¹œņ7Ÿa=CÄĮ¬.”ö#ź·ą‰q4‘Ģf¦„Ch©6aiź'µĶõbļf‡9¤iŠāZ"L„ƒ±–` ;^£#ȟaE©ŠsķEŹt”µßåb VnOņ•R§ąk,0|‡rEÉmµäQˇTpSTŌ×±ū&5Ē ¦‘Ī  g?Xz4AĘ!ϐóćŲćč9ö iaƒŠā{“¹}¦‚<—ž”Ų @žs;Ēu ~eč‡q‚­–ø„1ŒĖ*¢ƒ!ĶRčmF#«=ŅZa¦TŒW„f‰Œ Œ÷ŃĢźś3¦jœa?¶å°ĀāˆqBķ œ”:ųb„ŲŒ ĻĄ#ÄŅÉdŒ³”ā^Ųž`~¦8¢ą*ź Չó >•ø~ČČĖČażˆ÷ŗäśqžÖ%ŒÜĢĮ¤cŚ’ŒzPūyuNeDÜøåS†)ŸŃ¬‡±£fŽ£UWxИj1ViØ=źĒLē#õc,Č|#<Žcśa ˜łļ’ęR,my¢“‡µÕ!OĖmļh¶—œo;‡;cžłLņײ*ŒÜ,(±Ķ–•ė(݌ó|īŠR$ĀIņP)Ś–<ł9Fš•ŗnījģ7b#¹> å*ī¢UÅGj‘lŽĀ }Ģ,½Äėq)ś‰fĀŌR?Ā…|ź9’ōŠg°r)žŌ7‡#Z½eē8ķ S]‘RiŹÅp"Ž9'Ɔö»@9öAĒ[sĮ¬8™‡ķT2ēŲ¤9vä)ltäÖ£*Ä%s ĢóŒqī!ņ8‡ńlbrbĒ©0Ń+U:Ģ<“G–3q¦mĖq0GĪ-9Zž3c~$t>RŲ\#]™‘6yī;ī3!ŁĶR£ŸŸc/ķ0÷X®Ä˜Ŗ½ü¤cS”<{o–ĻCŗÅŅ_„+p»±āĪq§RǤ‰;^K<%øŚ2°’•ņČ’PjŹRjĄ džjiõgłFĒ:­ĶJtĶēOĢt­.RCL©‡ŒS[®ń’Hg“剸! £#ŸSg 3ŃAmÖć€/ Ö#“X<“Xt¼ĶKŪV:>’ŗb®8R.ģi“g qkIõNĪhÖ įČķsy—Ó•Čžē~3.ƒŁ\Y„ŗ ›ŗ"²Ü`“…;ĘųŌ1GŖTžÆ£4#CčÖ ·ö`išÉµ§j­īā„–ĪĒŗ†5±§6r%Ć4ӕČKRRŹ`ĻÉ G,Ż Lžó†s/ļSŗ Źp>”5”¤=åہęyö‘—Pˆ·LüšG’Tsæ.ŽēłZ“ū”¤‚śœJH\Iś¤é*äJ—œYH/©XjÄŗ˜Bi¬¾“ƒ †Ķ攕Ös»²f›¦PśQTRž›;lę`;Ł›SåŠLS¹_c 1[w±,ź¼ņ‹­;°Ė æE}vx4ęõ“’ŁgGĖ3ÜēåO«+Üa_ėšÓ›Õåź\æ©«Č}ž"{Ž3¦įˆ“ 'Ž8Ž$å~š|…“<9ŗŗ½$æ‡ĒPÜ{ęH}”3Ķēép„ƒqń8ł³¬®ßŽ\œæÜ@Ņē“l\¾ČĘćJŲ+s½Y,–³˜…Ū=·U°ō~=æ|±Y-?¼½^Q;ŽKa‰ŪÅņō­ć½až<Ź’+·ūŹ”Quzl@*ʼnõVé(K‡/’¬Ā˜sźKi»Q’Ė²¦øD˜’#ğÖę—;•ķ:ÓósĒĪt&i¢‡ż,sōĄå8Š(ō{Ė4qsB Į­baPq˜z:JāĀUćv,³iļøOŽÅ_ĒåātóbÕQƒ&FˆĆ„–Źą7·Īl˜“–ŅĒp…¹š’¼ŠŖBöNŽę>É0bä<š¬ĶÕäv܂_Œ÷@?sØõK[¾)ķ'bRŌš9Æ#-Mņoý€ķĶ—oiMżŠ ‰G’§Érѐ¶Ö›sĢ}ާ€öĀ)i!ó› ”mµ‹g_Ū—7«Ūó—\±k'1šŁ²fŚ®®¬®½Z_l[½ŠŪQÜ®TNļNÅōöŌ9€(’EŽŖņ»¢rpśv¾ü*ٽŠxW쇒U²«3šł-9ė•ģźšę}Žż_%»ś)YżĄ‚ų¾ĘL°”•p|Ś¶Ō £Ź’œ’į$»ÆS že2ŗ†cßI¤\%‚tMÕ&÷ŗµKsČąŚbæ~«]žź›ÄBxŹ„"õ1mS‡ƒ¼Œ«_P{|wÅŹhžq·ĖHń¤EŖ‘ķøš+ÜzžoĻØk@ŠŖ…®;ė’ō79žåź9N _ė1¹x:_Æ”Üzå9Ÿü `į¤*ć5PBAŌzopņāāņņųOk_Æ6‡Ś;Lŗ™_]w$-6‚YĪX®čī.ĻzD4,:‹ÓŸaZ±ųß\w˜s0óG†ĒāźžQsī”ĖĒĶż"­pĻöÕZ ˜³'2…SĒ·a},žbė&6“K„ļ!–A8“P^E/*l““•oāZ®č„ q1<=¦oŠ{’æšÄŽürD@˜ˆėób ž„ĮdH/F»øz{Ģ|»×«qŅQ{Oē7WkŠ;”PD…˜j”ń9¦2Lį—Ģ.ó\z Dx`Ŗƒeb²Įąänśļæ›_@ŽH}(ÄąQ‹šU_GՑæ[L7jUeWō"%ןøÄ²†IcZö..–®ŚÉėU7¤ŲżÄWl¤¶«·ß»5ĶjŒ¬H“}ņś%0,:µ-”@w’hY§?wK“ć(ŠSŸ—<ÕŹ˜Ŗ Š®ƒD#r;õ؍(ĶrĢøŠh2±N³,X—¤ć*F¼zĢ‚šaX-h±Į¦Ņ³¬“\˜$HąHŽÉČ/™‘Āø%œāŌŌ|3'nf˜_-āT=C°&‚)V"°”“ƒąŪ7Į·ßß~CߌaįnHp¶>Yž¬ȼ51<ƒM‘ØłNó=,– ŹFhˆ"™ĮQlŠSCģš NĪ֛ä͵ķ’öČtÅ÷AßŪĶØ@ČYˆ©1:ŸgĪ›ĖÅņ|ó²Dųw{NĆ~©ÄŚĮܛ©oBŒæ1ƒń&Ø7ńH¾i ¶)®_ÄĆÜ3<‡g]‘tl–—A4‹bW&K?4Jzż.,prz:¹ĮćlåW§ęņŅ„ZÖÓ=Ļ­öįxĪ#šĒ›Õ5S å:޼½\ˆ‘ 9Ņž.pœjc¤8ģY[i³Cńr4Qpż;UŅRÄķ5 ¶Ü#žmkÉžB‘*yD°SŁĻĪfƆXK²ēķ•cؘPĻÕ&UņE®Õ>Ŗ¢@y+®™~Ā«%įC€ńBĮąÄĪEȉ)ó¬ēģū8ö\–Y&.ŒJRē‰ĢQ·¦Jµœ®|$+±pÕ<Ū’įĚź„ŸŌbõ¶§”Ö“8Vmu}eųHēĀ}+VģŹJ.ŻžajP ž2`„>[Ü RŠ`Dh•)¶§rTœ R6ĶFéGĄ°ø›KXåAõs udĻŪ³+—g”P@¢Ā΁ö{q Ҳ•n5>E`•_ˆŃ­®bžrĢŹ˜ć™r~ĆfZ‘”öˆ‘h³gJŠīø`[QT““@µJ/µŁ~“č”ŃÕįxHĄ=NæŻ’dŪ)Ā·M֖¹ŚóŌäH "/²w”4(UūÉĒ‚RŲr”fH–vDĢłFĢīgA¼*õāę½  –²™Xҹ?2،L ‘—¶$Wœņ' ż1veśžŻ«k³*‚įlŚ5:ęÓ}Źo>tJõ䚙hHjė¤źžUae®6;½Ü.c€‚hfõ4ē$Eвż…ę—N1]7æÓŹMøOŹ: ™Żz ŌNŽ•UCÅļ2Ż|zj Čž…ŃT“AU`żųĒuńę–D”¶høC!pZņ’/¤łĒĆÕ3:`€“@r›ß-‰QU6‰Å…ĶæD+*˜>ĘöžŖčdFØ÷;} z±œ?æ\œ_­V›—Ē/ēg+Ū÷P”•÷ĆT×F«9ĮØUŅ~—³MčD>·ęó*Ō lĶåÆśŌĢㆨ§cūr±n±»™DOq’āśmA3ųz†R“™j¶RCq—¹jzKU«4ÉF’CŸ^ōį¬[j3=VhŪķcm>b$jóš?±Ž–ķnI ƒŗš€Nƒé”¶½^¬ēGŠ~¬éŖ¾­„-Öż%6¶HtĆ ńÖąšķć;c"#0F īq={F|līH Æ¢%1lė.Śŗ 7YФ~r¶8]-¾]Ż\õž„IöU£ŃOHłHzϲ$•”H) ,e~‘RŁĄKÜüŻŲķDeŠ.+Q[?ć¹u±<¼Xo€Į-œ]Ü*-q=·gv¾`‡#&ž¾Ø×(Źm ~ŠīüĪ:öK¹‰]ĀŪfI`B–L*„+OŪĢØ“Ļ$–„C¹ūÓó˜v25†*ū†ż†$jz±Y? ·Õ–ø{)ńæ^ąž¢~ūó‹³ĶĖ qŲĘĮ¦”ŽĄPœYC±ōKXE0ņNißRŃ©&ćø€‰ilphu}'Jo[}Ąz!}L*šĘµQÖJėĶśĶ¬+7y(u³,“ĻjŸ¾ Ģ-½Šō`¬“ź”ā8Š\ټgV.Źq5㨷±ĮŃ8ßzFÓvZ‰•0§<Ōž6F”ī 4īDcŖėķÄŗÕN ‹^_ųpęūĀēĘäAąÉ­Š„.’`袙HµA­ķ“󣎄ĮŒ)c™k¤oų"b8¶,* 6³b.-+Ӓ!놖(ZIC0‹S„)*÷°a“Ōą[pZ9UģÄÕø»F*3D—.Έś½{ üf£n.Fxō¢eCeźŅ>yTž‘ oPž; 2Ö©CėV,6āõ‘ ¬³Ģ‡hŲ²¹cpāWŽ$Š>“€R¦ŪĘ1ńjynŖ-Ļd¾<ūS³¶ś“SÖĒŖł§¦ų˜8ŽbŒsĻ_‹”wf·é%sŁ öÜ}Ø>5`ˆ¾7m˜śˆąå ^©Ū•n³Ģ¹%‹±­‡‰ÆŻLXl5E/×,ŠV~ą~|p9ǘLµ›Xs6ņ5÷²“­n³ŽF½§30.?ŗīęĶāAūÜ£Œq{:Ś€ńĆØ ¤"hwŲŚīčžvėŻķVmķęA»Ek»Õ=ķŽv·[¶µ[ŽSgµ»Īa[U=ūŸŪ’Ļū]Ē2‰=¾rהAš«—NTä;Oš; ¬Ņ»MfgŌɒó ļRC goš¦zZ·ž=æ\ˆĶź'w”Å섇Ęąä MžŁVr¶öƒōd7P¦†½{ÜŻ 3MZūÖ.ēdxČ ńA5éߖž#¢ų—”Ü96…īŃæÉ:G${ąˆdFÄźśģa£Ć^¼&‹WŹķ@“ZŲü.{l= |·ä2†ć/ŲõLĶsæŹŻGœU{üJF‘8Bn˜ÓēßSžcĖȍ2~ūTöķq¬¹¹³óŠFŪ©qŚaū;q®üއ#¶ž5ķƒvww»×{w”·z~|ļ¶—CÓ{Xõ/ēĖåā’ķz¾ćīTšvJ§äZŹŁŠŻs ’N¬ų"Ņ;ŻzŽS¾éLł}gŹoŚR4±)Ź’Mń¾”ō8§NK ü94ŁŻ[a¬Š‘āé%ū•›Ęźƒe=u‡‹Ķ.¦” =·œa&D¬Ų“lI(ZE½Ķ)"5IćŲĆČIOz‘ŚŁŅc™|Ī€„{Bˆėqą+Œ¬J.‡qM‡Gæ^¼Źē’!23›4{½æø]ܼåé‚_}Īļ§›ķ~lĪF}‡§˜›«³ŪSHSCćģÆk;ŠÓÖĀ“ ‰_oµ½“sĪ3÷iķ>»OĻŻ§é֏Œ\ä;¤ž$oĪ4o›o„äR&Ām£µ_ž”õ_Ė k{ĄŚåä NC©, ĮlŸĪ2ęĪ<āt’7(ŻJJm3žaŗ]¢qjkÆj»yˆĪĻtåŠė†]Źŗš7Č©?Wä]ŠĻŅ]ć–2£§µÖų¾µńҤ§Ötę½õ¼{²·ƒašAų0IvĶĖĖ2ÉĖ*į›żTzi±,ÉŖBéī ~A.Hć{§×Ćh=_ÜWŃ\S–H³Bč8P$Ü5j]ćQx:Ŗ -üĪ+~ū-WÄ×Ož’V¼×Āč ćצ Ā՚šę*Аs‘„ķ"4ų|…{>ĒŽvYŁMĄ­ź^JVB‘–)±xz¬d¦’õK:ŽĀ ė ‚– Ā¹Ė9Å“&ļ`”Į;pMéXĆMƒƒéiŌŹōTtIŚń‰K:h™“xŸ»s-Ž×F§ÕķśåōŲ{ב»;‘Wt\ĢŽyGĒQK…æ½A'«Æ4HĶņõš<īį9[ģSņąäPō-w”Ówjé=‚źŅʖŖ•÷ 0F­^4żgœĀŌўUBSŃ’ävbƒĻØńH‘8§Ą¦W ^˜AW1©Ŗ\¬1ol†'óœAMް6ś ¤³¢+“,†Šą\Ōb…/7f9ajÖŃZ'~ąšŒ¾ē Ł$0« oՒ'ĒX1Ó÷äįl<Üehö+p5ó}#ŗ³õPr¶/FœČ LUńĶ]—SDä}“÷Õ¶‹uŌ_3 yŽéń‡~äóKd^3ēēĖNڰźåf¾żõ…›moĢgį×— Ó&M^ų”™>y…nš¦—qÓL!;ļ bēÆd`ˆĄ‰µÅ5óÜ‚ś ¬”V”µ&ÉĘÜ«“ƓƹŒe2ż 2 ­½Ž¹Īåö~J ČTI2ӕ&KˆÜ[sŌż^,?»ņ\™ķūÉdŃÕ~¶”tp÷€5uø-®ó$„"nĻŻ>ŌŠiŒŠ©¢ĀģDŲ;“ą~ĄžŪHS»į’j/ĢivÓźś[kTņ«Y€lnĘ$„õ„£ć™“Kаz‹Wn¼=×Ńśtܽك,8:½ńµ(G°śģ‰cVü£°b\åņټ15ÅϘH0ž‹ąź Ī4ŻhÆdĀ:qT2[qŌžDo=³nYHe õ„ą`}°KévĀ]|ąƒ‰š„@Ø2ĘąņU6¹ŽžH8NģR§«R*ļųåāņrmL &’': GóʝÉ¢CiZĶ:\•æŚĪvÄy\U‰õć=źtńÊö_Z«±:źĄgڲ~ĄŻ‘ƒ`ū÷Gģnśī˜ūÜ#9®ܓCš\:•ÄD E˜Ę¼ę4šN»jDłÓVˆßM}† ŒtY ĶöŃjĖō/¤Ó)Øbnę&ILČė;’Ū[[ógńąŽG¼tZė¼¾€\¬_®.Ū*†9Ŗ4Mā^¬ŻÕÉ÷ŌŌ–1+›ž®–x3óYŚę54wūœw±¾ūMB¦‡¾°O—¤p5/n…÷’ •ļ²0ˆ•0‘ÅjŗZˆ·äOĄ÷¼É…ĮbŠpūÜDQ!eŠ%6˜‰T;×EB…ÖŽ4bÖ5ē+sząfeoƒI“T 82uP©QĖÅy˜Ūh8§—+¼1ž[k»ĄĪ-ƒ1VŠĀn.ōø7gåĆKøŻÖųÉó·Ä AŚĄm½mēł¼šxžķ‚p¹œ„lŅƳ±QȊ‚ļ Jŗ uöwB0qņ‘‚č čMYŸÜ‘q Ćl”3ī뚰_8—ē=ćŚōĆÕõ»WUŽĆŗ\Wß½Ŗ, «rh|×ŖźŹŻüŠåŅ?@Ōbd ŅU_’6øxŃČ µG™³83éœĢO_]ų„ VgļīļégĀŽÉõśŚåłI?Øoś®»wžĒ-.œkńu÷Ö#¦żā’ö[’Ū/żļ¾ńæżĀ’Żöon$ ÆsjeūwøžŹFŌĖxĪē.™mXądßeo'ß¹›Ž[JyƒāŽįā:¶zåK½ŪE~äÉ”‘'٦wŪŠlE6.’lĮĘķēĻn—§ė YĪĆޚŽ,qu»åR“Ż&¾£ļiĀŁ 7Æę—ĪG#ūE ń8“ †Ć~Ń¢<*¢¢•>ü½ēĢyd¢š\§ėā‡ ēϟ,ż÷v™N€>ÓĖ[Č#n-ŲP‡Ż¶Č·m‘?7#²wøöäč¼¼]u£pĒ|VWó ÆÉˆs®ćAÓ S’`h4éˆP ^ģßgŃ~ęąčĶ=õžY Wśżi/.ÄĆÜYC3“RlķL>cAjŠ7£”üé>"4÷ZnŅB¾BäĪõėƒH\ŁÕ»ÓyPņ=ˆ]Ź3­?„īµ7_ƒÄp)‡Y‡’–IQüݤųč“Āqr?=īøyą†‘†žm#ĘOœ8~Ø©®`ę°c£nMˆ„ļžHæ$W{»ē^ļ3ÖĮ­æ^ Y5ObēHćøŗ+nk9Vų{“/,ļĶ’ī<ļ’«»z®_Žīä·Ēg3‹y€—‡ōP/Gö• ü|ĀO*Ļ Cu]5ūč±ķĖŚEŃp…pXȤ²m»fś$8bäĪ YKįLÖ:VįÓ%!Ō^Ä’˜wĪį$•ł-³—ģńaāžģČśöįYÆžõ4ĪŖøm]×Ķ]||ĪŹ”ȟØbYĢ™<ö”—Į§ÉaĪŽy$»ōų¢ĄļŌ×:\$½·¬^ŹÅ7 ”^½§•W:Žc·AT;Š¢ lČT冖åuš-s“Õy"-o3ĆķP›ŪŗÆz‰ ę>»x%Hhc=­lpŻĮÆT‹ž¤ées9²hĖķŽœ÷·f™/żŒššpĀQ7ÅÆ”U8t=&[ė¼/Ģ /•» ŻŃŠ©»E2—Ū’#ėzńŠŁæ‘ÓvEW#£¤Ó6~1‡—”ˆyz|/oŪzŅR½[&øZ·“„§øbó„s?޼ȔÓe¢JŚļDķŗģŌÜuj—TįE]W†Ē$]B‚µÅ<ċČsźs“)’¾]Dģ»čø2“Ó]÷…~ōJŪ›klmwŻjZ£špäžó{ĪB>ą-‰Ö‡$Āć(­ĻJܵ=øąlŠv¹r>·ńź°{,V_ņM†mL]Ļ;Dą&Ö¹BjY<~žĄ?~ŠŚĀ°»?ÕĪžöń`ē[ÖgÆŲ6^spКøąudūlƒÅ^tč3Fa8ZĖEō<†¹žˆi·ķ¹’®›gĶė¶VŚsÓź½ķ8õŁcל{/™»{Ļ÷ĘZŽ ³üŖķ„U÷šFĒĖZv@vL’– Ü}…n–7g¶9ēŃzĪōCŒvž½’xčG?›Ųyńžsˆ8÷ž·ąŒ‚Üt¶Z†šŽ …ń®½ĻŒqī}Ž»Žl;NjéÄ&D*½ÖJÆ}½mFнą5ŹčŸlb¦„gµ53DI:Ė=ä“DJ„§-Ź«ūKtTĀxB±×7Įózīx˜&‹?īĶpĪĮģr6‡/Ÿ§4’4­Ūj>’f~ƒ÷a†'ŹPäŃu‡ó9@YŹHy[ž_ɋįó/nn€-č;(> ó&ĄĪ ÜČ‘u½‰Ļń/ć{ā“~ĒǚwšŁŅ÷,ÄÅģtµ<o-ŖŪPŅm½ •ø¾ńüÅ NŽß¼ŲCöÅ:`­M9 ŁžĒ]KgŖ ’ ŽŽM©ƒ“šĆ->ć[»£'©óT NˆĢ-܃m¼‘§všŽHˆĘŁ={…Ę­8J¢Gö²šL3Īč37åįXqél¦JÖEa|/Ó„ŽŻ"Ź(½Żø“K/ü’)ž ŽzŒČHąžņŁav†ó2øų-; Ś÷|]†BĘäy,ŁäüēeķĘQöėźĮŽŠTՀ˜ń?Ų@LF¦’%jwjĀ/PłĄ `œ¤:jæD—¬’ņKŌoōž_fDT¹łčµ·[ ÆAø§†©63Q5]÷«śūov‚¼ź/:ĄīĖl¹XGn%ą&ń£acīŗ[«“µÜ’¹ó\y ’ąņ·c/dT˜Īˆ’Ž”üĮ¢"ø+&ßüĆx†ź8"~ĮCI¹įĆOœĘ,’Žäś?±ł‡Ķ°w›`^Oī0µł~‰+ņ0ĀUKgxˆ)‰t#×č"p5—óĻkņŌTQ0p!m;Øg–2jFtį²nČ>¬#Gē(Ćämdļ9W-\7ć²)‹†Ś2Ł;ĢW’łā O)Oņ½8²š‚¼³÷ ½æ³ķ;K§¹BsŖĖ¢õDƒ¾B®ćÜč€n1Svęųʂߚć€s”ĶīØrp;jc,ĀŽ°{å_öŹ{±WŻ‹½Ń½Ų«ß{~õ÷+Jcį/I ÷œtOæ*rń–UÄÉZ‹Č"ČŁœ%Ļē¢KŌzD«Į2Ŗ±uśuö ß;äęÕŚV§«ė{äÅŽ<EMלžź–ĖŻ…ää=&—3z„W-s»²ĪŽÄ‚G ż”Į­2Q7īltŽvŪ³ė[§p6Š;yóhņšW]u²4sūKßłæéĢ’Mkžßwę’}kžßtę’M”æ«—|BēvÓžjł;ÓMĖKYŽK ŒõÉO¾P&=Öģõ1Ū÷Æą ¬ ś «Öč-QĪČīVWg&øķgĘӀ€Ž] ßDŸŻæŽÉ-ØQGžīu$~~4Ŗ+>ØŗÄO±FĶĆ÷©y—CV£…ņc·° QÕ/ŲX?%F%=·Ć¹M(t™€2ģņČæ÷ü½kbr2&6Ł/…ėÉņJ³ųœæųjé BJZ«atmŅ9mu½¹øĀSĮ­i֔*‡"æ—Ó‘ŌŽ8xńąė du¾Ę“q%qµÓ’ˆG#˜> :tgOG’ySjŲ/‰¬#ŗ.½¹V·E€«/'Ż “*Łqł9“Ėŗx$9z„ŗ#O·¾EoO"öt rĖfZĘóÉķ·>ć2)=£ I®/|{€Ąj83Į°ßXŽõP²ßęmy틿׀¢č48‹ÄS×ō¬óžžpęóĶj¢!a1Üoks©”žFīlH,€źźŠ#T’¤MHźQ8)÷ÜÕķ ÆÕ`ІjƒœyŲ,µƒ’¾³ŌŒ¬©ĪīŽ kJų ėŹ*1ĢNŽLØĀęA³Įó[)šöAāх:vą¼'¶ŚåüŻ­ö³ģ ŲŪ[{Μ‹3’vy?“’ņŗS|HĶ“—H‹3 {¬$ōIģttO–?k ¶»¾C5⦫'¢Ü”"Ē4ōr“°!k†Ē‰”†a‹3»·ŽŃ×Ęøć›E;øs7»Fīź?³iän²ˆāķa£J¦tܐMøA[KóR.ރAkm °vQ鄎[0@ņNɀ¶J^½IŻć¾ĢæT5ÆõXcąÆęŠf“œéكą¼(nµčüäæńŖčU š)Jē^X#ęf‡"«ė+ŗhmö+Wː܅§ųȓŅĻfXoy&¼#°TŻ«ŒOĘč„ai¾“w­Żō}χ&Šds¼Ų|ÉO<œP³$(ŸLžTI¶_$©}‘”-“»oļø'oY°ß,¹X’čuOo=±·»#SlĶ®:“„…ū[Į•÷[}œInĒgšR²Ō It ~"Ū]wIxŸ:€‡Ž+\„Ż× ^“ī‘ˆmļČ74/[@ŻYƒk$Ję ģé-…‹×ų²H✬ł‚¶Ó¬“Ū&¾Žd^Q,{ķūHońq89ż·,ųÖ *>Ó•ĮC¬ė ęłķ ųܐur¾¹8ē{@ō.<(yõöē ž›Ķ,Ć6źĒ'G$šv›Ę‰ŃĆg9]įe& ω|ŽO®ŲXv3=@K‰–3ćO/Ž,.M4 āÆų¢Jūē ³¾Œ#…Šæz>Šk“wvq¹3Mo_¼XÜdm‘y[dF¢öž4*Ā;6`ŸŚ ’ÉńĖĀF‡\æ¾XoĢÕvČŹ§•9æŅøš,ŁFOnÜmwĶJ؃ÓķU£ž‘ĶÓŌ½Fzß릦Œ÷4‹8v€½3}fCŪūAäE• Õ¤Ń¦•Fz®PŖÅ@āŌKlzk„y½0bx ō’·Ń2ȇ’}²ŻŪ%†šciīØÄÜeMģłNé'vß6E¢—4gŚ7MäŚÄك>ÜRÓürƂŌd.Œ“’ŗFćĮ+Shy{Å"š4o„é©:†iÆ% īė¼Ę,…‘3šsŸ:󇆛eļ²pį–ŁŚ­\;` ˜’Ćžˆ>“ō«°)ö”½ö*=aĻ/ /­ĘńݬœĘdŠ”peĒūĄĘ͒ҜQ§7QZšį5+8Ö>æŪ¾vķé)‚å¢åU斾ćZ]æćŽū¶’Ģ|'A826SFÉXĪū©Ū;é(¢Ų¤Š£‰‡[·Ģ‡ŲóÕ7H6ćØ1>‹fšs“–-Ģn䕿ōĢtŌ[”½1!%3ēÜ»:©Õu½;OkĻGgé¾]ĮU²5Å-µ©6ML„H,õä{f‘mŃ7ÓØ{ŲZ·æy@*ѲļLA›i˜÷š=ßys¶ƒởŪx–ŒÖdi=®äȞ®7L? ™°ļĘm^ÖEüš™.q™'}AÜdå—‹ÜŁššR5m5a/:6Żß²¤ēģL¢(Ł6Š5l=“i—W²3č½:ņ ]°|ėči"UNo­é›w˜KSƒ£ģlaj4JnļoÖ>÷Šē×חoµÖįŽĪ½S»Cl#lŹDɹr~q}Ēõō“ƒįõüņg `1ąR|Æ)ašæ$„™–½ęrėŒs½^Ńs• 8{=X6ˆs'zü7€ )]9ß Ō0jŲ Ž?ĀeAėč8šŻ¼žF“&=.“$Bˆ·”{ęß˱ŪĻtq…FŃs/Æ.>†ĶŌ±', “ƒ¦A[4ŒŚ ŌĘq¾Q4Ŗ/=žo¤ųE½7‚¹ń0šHTßöī5FŠ»‰Ęœ™ZAŽdöŗé#wd4QĻ÷DȊ“sCAtˆ|(“l0xmŠB™k Ģń1Ž`¦[ŹrCūFµN†Żü­³Q=/å©%ń¤"i¾™aNĮw<Éō¾'ėŗÜ’ÅvĆ­łLę8]d»$tėŪē|¬Ń¦»ڳi^C6®1ew¶łßm›DęL ]Ŗ ļZ¶u­qSY`¬ĶTŒS-±0ūMķeųRSĮŚ;T Œ#0wžšŽŻmÅĖÅ'Y½—Ą”Ė6†ŲśŁ8\œŻĢ_;<–Ļ/Rh©ķī!{OB߆ö‘7ŚÆŖ¦“Öo%Æ­YL ¬ņ(ŗIØĘŽ…—‹{U¦žƒ4‹TWīt|G³"o¢kĮK¬É¹WSw“=OÆWRʦ¦L sÓŠšńšQ(’q0%ŽEFQp4dö̘ƒ‘Bā7ĶāȬ“6b>2Ų-óĶYĶĒūlÜ׏¼VršÅ`_%|.Z`¢„ćy€DŚś:}u“äi†žÓžFŪgֆåŠ{¶'×V×ēžÜżD¦wIU?% ÕĀ ż4L[ī‹3Ó.[}gŚwœ6ö©v–­@¤XĒ=͇'Ńż8ųéć& żÕ'Wbn×q3ć. Åł=³6é޶ń¹Xŗź OøŹ«dĄeĢm» ½‘ąĪfž>Ę`£Yõa\:&4BQķ»·Ó 䚫ܘ®,¾‘ŠæĄżŠ­3B1ćĆRV3“äŲ Ö†i'?DĢėA#ĄĽŽ‰‰%dHwŪ ļCŠŅ r×aģxÆ&6ķ?wĘźd-1—‹Eްq݌o6ī’všrZ  «Ę(PL Ż’$å=ģW-€”Õf\P²Eh5ܳ·dzčŃł;€DąÓ'ŃB3’µH©ŲH›ŃČŚž“Eiō¢f<ģŻ«„ŹG »|  ”īŽ^dm „$ĒĶčˆJ¼Ä»%©mwņH|Ł }Z üf¹Ÿ?nC\$txŒp-Ķ1J½ŅÖQć%—ŗKr ·0{=“i/šÜ9‹*äüųä[`XO„Ž]¤XēÖd |YBwŁĢz¹»¤Q6~}±n(,ü¼WŠTŌś‚”­‡9†8 ‘ōz½.2vāG’ĖkQä§d½r¬īćĄüBØ„‘3ŒĢŠVsŚ/ę!¢Īźqeķ³a§ZRbnģ&eRRw ™#l.w]Ɏ éDoL½É~P²żüāŌÅ;’äDkZłń×D‰*£AauRŪY…ĻjQZÉĮĆ vy{‘§WˆnKķ.%œHkż@‡!K‰õķ}(aÉĮˆ=~ļš‚nŻł¬JE™šŹ*ėdšŒ6ö’ qų~”7ŻTŗI?jŲė#Aå5Iā§‹‹Kz.ƒ®š¼kf‹:¢Qh5°žˆ ž|{ÖĖ0ØÜŗsb™ŠĆ҉"ĘŃ“ī.›Ž,±•Mžč!éė¹YĢĻ^.Žč[CĄĻń`G©F‘¦(`ąEZŠ5~˜Ż½ŁŽŅDtšłgAŚ9} Šėb~ƒ’‡Øe Ų`r|šäI]Ź>Ō“Y܀$pšC£0‘ ©A€A"=¼-ż·Ż÷‹ÕõOƒZy e'Š9,’ÆŻ¹¼”„].›M#ltK¾œ—ćą6N#&Ć,ń÷Ū‘ŒčÓ ’6’Öv¦ŽŸČM_ÜņÕK_½öæLH}\lÄ]’Éåå- {õæ+Å_’³Ļ~øŲ\BęĻ)Wbr%Ÿ’8łŲiźż4™įŖ­]®ĪCAIśŅÕt#Š&6¬°ŒŁx<| 2#¦®®ßŽ ‹‚¤Ļ'Łø}é5Ɨ“éu<‰ws½BkŻY2æĒBėśµøyµ8{¬nņzlÆĶŁ…ų”@Ōń“WČč³,ēx}õf—ŗĮÉW¤#xäN«ą+­ß«„~½~±ēÄ×z•Ō “‚“?„‰SW—sq朜­šv3łzśB“½JQ`ƒ~g®7ޟœ.:¾i‹»śyÕæ¹2O§ļ ä!©ćĶüf³÷lo°H“Į ‚’+ųæĄ£­ų:/üæH÷~ JaBŽĘ .2ū?*§ž¾ƒ“õĖ‹|(Õó7T稽ō±§>örAĻ ų¢†Öpwńjó&ŒXƒ¦Sż³4×z^¾½~¹X&ŸńX"^¬–zė-5“õéĀyģsŌį¢ųźsŌ÷+„Åäģ@£šp¼ŽYż1śĄŽł×ƒĒĻ”>­-Š“ģY†O’q̆ųÕ":€€).¾mOIx-ļjŌõrsćÓńŗ²$÷GKG/Č@‹—0˜1žĘ3Óē‡7žĪųƒ’|š=¾™“'ŗŗF6é£Ļ_ųSŠ÷ĮŃŗĆķ…s ⨋ ÄźE0›Aų6uƃŗ×Ķŗ×qŻA‰Õ:Ø{mė¾F0ƒ3`nYi#®#Ź|qe«~q~ ¾®ƒ¬ė0-Ģzaæ\®čvGźĮ×Óšt "äōęāŚŪĖWfBĀ—·ęĖėēęĖ©Ķfęčó‹ ’“m¢"Ø & b~^¼J¹§{\”ucœ”ųꌮCšŁž“,Ļ6¾Ÿś˜#|f ŠīøÆÅÖķR.ēo7t¤łNrÆÄ\Ćwä(z„ž“ˆD/ĖÆ,=-ÆQt2MHĢōv3ĆCØĶ”ÆēA,^“9[ݼ<|Ÿ¹gŃ ĻœŻ—™ocć£{ķ'÷ā­G÷¼Ŗg÷‹voĒƇŚNęd ¾^«Ó+æÅÅ+½OTŠQI”¾•6<Ū—4ņ±±syjomRŪ¤œ ̌W>¬™0²”ܖ°evk±ļ<6ČwžčŻ®ń!B@e°šīɞw2&lwā*|%qÆ ģ=ōß÷wy%‰_B‰vzdėž;Ā"”©čåśõHžĀÆI,œ%›6Ԉ#ŃŽN"¦¤nN ³%ü*# ±ó0Óü-»‡Ü%§įyĪWEj· =JpOˆ,@ ‘,ć#T†Č“ķ6Č|‡JošoķĪ[·½ ½ĆÆŖż˜Ų\ó7j“ö>„Že×ī˜Xw›öLJ Ie ČĪå•ß>įŖYA”›T{óśysŚ(u”j‘°©ŪH|Š»mņŠ?„&īõk%‰4©’B P+ѰŌßó@nký”8©<€„¾§Pį†Ļ—«cźµÜøŠkŠāņäļ…v‡čx‘Ąé&ėø*u—t'ā‘bWdö Ī›5›”7WQƒą ż°ŗ¾ŪlÖfōļ/¦¤%·®˜‹G²­øĪ÷‰æŖ[ŖĄē`‡ŁŌ±Ł„8ŽKn3”ɑ‘ģfRĻ£NDH FFw¢Ćā¶2(¾āč“Z<Ūäł=Ēo@“ änźŁA<†v܀ŗŲīķ$ ”ˆ˜ :;$żéœāĪSœ?DS|ķ§ųH§8Öč§ųõēč&1?÷×Ö5{’nĘ6gl×Dż€ ˆ$…åØ ælŻZņŅøŽįé×m@]ƒØé„Aż '§kš[<ėh^\µÜD¹;¦#v&ć+śMEÅJgį4}Ļf®/nwLžż¼$q†/¢ÆŽ~wź…ÆG{±Ų0œóL#eO¶OÕŅis€ørŹ\:¬¬ŽÅ˜LQœ"^¹ŒŽŽaXX¬LŇ%lń·\\Fŗ‘’÷˜Åęn§Ah¾Æ1Éę»ā|žSӅ%ŲiķŚu xļÖ»ėwč ä}×>B‘‡v²F=U œaŸa|ĻękžĻŲ‰/TŃIĀE®3N“‚²hv“LźCŠžųŠųiāOēnN~#ŃW Y^^ĄMym +tū©ßóś·$ÆŠÅŹĶ’ć×ü—˜×æÜ!±ßŅź+&oķ–Z½3³äcõ[~ėę&’—k%ēYeÜk(wrŹ]ķŒRē·”õĢ)£v¦/°oõŪģ”`ʳ&×/•b’ėc–v_ŚKŲ+ ×Ņ1‡Žėį‚ŃŽĆŁŽ¾ņJĀń»vvża]ßߣõC:{¼£³ėØ³Ēš0}@g¹Ÿ³Ä¦¦’ĒæpļŅ÷鎾?ś>Մ?'.ė;kgīŸīéū°üōē®G_{é’ŽlV·žüÖü‹¶!-‚Ŗ‘|’Ŗ5ŸŽÖdżÓ[Ÿ—_А}µ‡śÓߌœübx”³Ń¦Ć½mņPÖiWńkßĆ?żs’ł?g¤_$D<܀5Ķrh¾;#G;E„Z:ܳķņŅ-}vVµz®_®^ÓŽ ½üĶkŁ§ŗō²$ąī>•–^FßĶŗŠ{ö_iCKUÆ]lIü”Xj”ŗ¾ćŌFWŌy.* ’ 5yöŃń“ń\06[ßv÷®r ,3ĪøR°pĒų)ž$bRWk˜7Ł[*Ül:+gµ” °”Ł ˆøĒ…×nł¹†Į+`“„Å, Ł Żåøtü ·æ|özZ‡;n^Xe¾äź ÖÖ;g-ƅhė<Ł„bą€üĒ+5®Ģ:(ōņÕé5Čń‡F"Ī8_ĄLC,‰=Aš“Žš“¶x⬦֭˜Z߇)©© Wki”˜¾Ń,w·„[¶Pˆ/Ł2ǰ9+ō]xVZeƤčhY|Hėä‹aØ pž€ö8=ņ‰ś°„*@„±ŗyĻ×ßĢYńc@ėæE4ńį2 T({Uü‘q‚7mKE+®’nīģ˜;m cŃźśMŒž-¦¼IT4®pŽzCSp““ąū8ƒ{ēJłbŽqb“y*ü7Īdh°3“omėHė±å¢ŁĢ0„¹B[Sūł—īŻĻU½›7{7‰ ~óå’öÆÅeŁ;=ڵ$±GåVo–¹ck™½ AqųCŪńÉM¶-^‹“QƒfÅĄįÕ83īĪVč=[mĪóMQ„{~ā÷¦žzŠŹfu}½8c Ųg›ōF9rŸD=>, £Ös×7‹¢~ø‚6|m=Ōā>”דا¬x÷¦I\ŅŽ“ņĪ“RIÖ(ķīŚķŖƒŻn„|{鬄¼Ś®šÜ’Ānk=iC\=l›NŻm„tā Zћ8”8l:Ž×3%JŽpŽĆćõaU Œ9»å®Ā"BįgHā®~§—‹łÄZŗčÅzń$ōGŃĒ3[(’|Üō É.Z4x …™Zˆ(¹q¹~|n²učĀs øƒĘ»rß!×.Ū–źe2ų¤Ądp ņu2˜%ƒēÉ`Źž&]ŪÜŃŽģŽ]Ž6×ńņ_ØĮ7ÉGǹ† ¦Ļń¾Ož8m$žƒ““B§y®’mDœ&iʼL¶C“ƒ^Hłś9»K³j8rīäjńńbYjŗžłgxF€N–~ł£åÅ|GćDś0›Ö|O‘=qā_ȑŌŽD„Č?4#—žŽÆ›„ćĶ×tźńżĘf¹ķŃnńČl^Ė2ćä—Į×ä*`K"yÉUÜß‹6g¢ŻŻĄ±ńŒŽ™č£ĪśĒß3‚#ąĄŪÓłåb³Yųq³Å¾½ę —ūäŪÕņ)jZĄģ`ØYĘt;¹Ž‹cHžɋō~eš‚ē=OkŹk”ļų”uų=}C’ ÷õĢļ½CCųƜĻ)č ī|“CHŗóādlßÓĄO®½Ė–,n_ŌŸ¶V9…Ly#“%x\VVĖĖ·4’4›|ŚŃų‡-Pc‘ūžwė:8~Šŗ’ļ§ImŽ‹’ł °;—cŪÉwr¶iżxļ3«ėūSāZAtJ<äÅ wēxH¼ś„‰s'³a“jŠqØÖ#i\ 8„vŹF’š Ų»šjÖŻrÖˆ-Ąģ›+²~)ź…KĘŗRĻŗ\D§ž^H%'?UāĮC›ƒ„ęxŃe;ÓQÉEzP©ż3VT7?ō"@™6{.q‰ŌE^ŠdłƎt_Ė1(ƒr²N#ó|hóäe.yšRÉŖÕēQõUjŃØ\ń.åŠóŲ4Y¾Ł/Š÷Ϝp£«•5üź$n©ĮŪ%Ÿ`Zj <,U( fś+Šłš[åøöēėĒņÄōPOKš%óö¬œÜŖ#—<Ņõ9Xōå%—åņURŗņä·T_h(ĻѺƶż­ĄT™męž4ł `tÜģ„1„nŪĪqšģļń‘3>Šę7˜³r|ŗŒOI†DWńųXa{›ļrœ0<(’&ĶĆę†ļLĻBÉĄŪŽUĪ:fĶĆķõć}bį”ǽ‡õ Å;K,ĢÉJƒųD©?ż=²§>¢*2‚#I‡_FCü×zšŃƒĀ'ž‚ļįŒ‚v-ŲĮ¹×$č”ļØĶŒų‹bWö0·”čn KZJ>DōYæ¤KDN&Oź$ŪOļ¹/§NŽ9?^’ƒµD·ä¤m·ädł  Ę£{nɽ³d¬­į3æ‘d„üó>é(ĄCzŒäļj³ÅI)H8#œļõ¾Y¬_&¶wézóŃÜš¹•f„ljŠBŅX²½ēØ~pėŗ»ō>Nmó’T.Ļāo’ĢXöYĮŽSÆwPDĖĖł“Cī²»,Ų€ŒÆ`žŌ˜tD8”Ćg1“8ŻY—‚ėī_Ņn£”Łó­Ę5zĻ !‚pću¬g¤ęr…¦ŃĘÖ_‚h;Ä^ńr[āÄŽ|٬ü-ŪNwtē¾^‡YįŸÜA~r¾8)Ņ,ŻĻҊnøˆX_­V›—ĖÅZ_^vōī§iJ®Ó>§ŌūõūÆäź:ó&Ńł‚ī,YߜŖ•#¾Q²ń¤­-ś8Ut/\\ӕøŠy‘ĘĄ0ń5¹;öńbŻrÉ­6¢7Ļu¼Šė wśģŅ3~į“ž’¤ż%L‡›=nė²ļóĆn–µd™™{ŠšäŚƦkŽ*9§å‚Z$v“5’ōØ:L˜]ĪĻ%Ž”tąĮkŹ…—›ĒWĪ`üµæf °½Q§|{āŚ]j³Ž“DńHūŠ6+ĢGĪ'¾6;Øŗ’R3øm;Č`u}ØrériI bfcJCŪŗę Š4CąÄ½µ’”æ$ßÜ;īo¬wČ ŠE⊢Ø×ŗķąŅ“®RoŽC½µˆ±y“ģĪS¦ļ¶Ņƒ™üšvsv=TeUĶ&3œ:²eˆw.ß>ĒūĆŪļÜXjm[ŖéōjI§7ø¦Ö»µ¬iv+2 \Ćqõį&Z›tѤĶöw3ka}6‹HK ¼yY“蔌n¾ou’ ßäÓ²F6äÓóF:`iš ķ-łŒE#£„{Ū= Že®>‚½ĆQīäGÜĻP%ņö`nm ÷žFd<Āqˆ^[o°8rMž¦ą‘špųĘSŅē,•³ų!\’¬‰ŽīBbźņ‘ę’…8ķn{²z³ż6{']™„1nO_ŻXĒE¾Ł‹ü»ż%bųłNÓ\=ē¶ˆ¬’G;vcų9ƒĖÕy_vfŽ›Ūė¾ßĄ‹ĖÉ؊¦»+N€G›ÅŻčĖŽRQ*,§ ! Ÿ·ųŁJŗbøu#Āz[ģČŠzĆnūMʓ_}sĖÓnĘŁ*'OāJĆējv5o7Be{ÖĻšvŽ#»8[Üōw»ÕōĶG*‰£Kå¼”õ&ė{)õÉÓĖ[HśÕĶźöśÉņÅŖ/»kO琹—ß-ŸāÅ9ӛŪ52‹Õåć$Ģ I\ &Žllīm@Žīś}EļU÷ˆŲų.āõˋӶź[Ņ];]ew68»œKpuŠW÷wgÉćSBe”a’«¼„ÄīŽ^=_]^¬Æ|Å&ƾ"` @,>[»jų«ģė‹W¹»²Ć);~h)öh L`umŠčbp§äĻē7×]Õ"t(9VŽo/ŠĮRµ¼øÖ5F7röŪ½-wLœ<™.M²r‘/“Ļ»Ä÷Ī’s‰zÜoFĮRT&Ó³ž³žæč§e* £Ģ”oVųnUV&tVWüPh©ś~ÜB:4”蚎@’=ąŲśĆ2M¦‡Óƒét:™Ž§õt4­¦åt8-¦ł4Ģ&G“ĆÉĮd:ĮŸń¤žŒ&Õ¤œ 'Å$Ÿd“t<A8Œ§ćÉxÜ×ćŃø‚Pއćbœ³q:NėY}TŌÓjØĒu]źŖ.! ė¢Īė B:šŽF‡FÓ“3źŃØ?ŖQ9B(F9„ °;ƒpTB8Øąj-B¶ Źj”Ør!įˆĀayŲ/Jča ½(Hj/”T‰?C„BGmįĀ!„ Š’!toXcč 8ltHå‡üSPČ%č°Ļ\82įŠ–ƒĢ„B|ĆPøŠŒš@1żF4‡’Bü݆ŠB#¾o}hŒĆHB#„ļ’4ŌAhʍabC_>L%DɝaŚhXŅöŸģĮ!śéŖš½«ģ·÷*Mč·žĄŸ~¤@Ć2;ųąphC?üśįįćUxÄ”Æ>VųČҰ 3ą{pĀ8ćXåŲęŲĢ!0ÓY™Z]XmlwHLø†\kž›>ž}TĪ€grąėCąÕU˜}Ė °ž)°CX`Q€e-ƒ%¢ Ž\Š0‚5$XM¦Ą?pu9Ķź”VœÖdą%¬E£>,I5,Mø@M‰ĮĀ’5«g°|erXĢ ął%-nXg=Ɵ ¬{S`>‡p%œMRŁ$ėĆY@ĄÅ› —4¬–Ń1-§°āĖ9„pa6™MS„œB06„«?„„Vč¬ÓØé)Õ3ÕåW‡.™0ó†(Æ£0Ž&;Üϧ;ĀĮ½į0żf„£‡YśĶ(Šō]C?ŠČ>,Ą° “ĻN¦7øÜ€|…ĀS0ŽØ,v„‰„qX¾/TŌŹĘ®@Ęqqč0łŖĘAØw ŠTŲUō~y>Ŗ¬­Ė”šÉł¼Ęk'¦)H]é!„£tF‹M–å0BC «ld Ó| 2Łav”Ķņ4ĻņD½ĻM„ Rt©č"/ ĖxX1*ją'˜ą ō3=»la–žAö…;6łcμQX£aŒ†-z¦čb_8b®¼PįT™ ±ĄÜ±?f}a{GÄīrātĢåź>1ø)±¶#bjČŠUÄ»ĘÄÆˆ71rÖĖÄ(r£ĢšÓ>@č/ ĆHB%”ģSŃįQŃŗų äQŠAÖŪ# ‡‡żĆĒQ'ē‚G*†&XéŁW†”Ļ4Ņȑ ‡Ķdš“@ņ…‘ź‹XJā^“Ļ­NHOQp=(Ō ż{2Œß5ō;&ļśQÄōCC_>Ėf)KG@c°:O@~؉Š™t‘S"ĀC¢¾ ŃŅYIT…””ĢśB%L5)W%)~8äéN ?‹t|Ņšū-*¾SšEæ7Ś=éö‡¢Ż{Ż^5{Šėū¤Ų³ZOJ½hō…ÓęD“G=¾&=¾>#ż5÷RŚIaļ“¶>$==# żˆtó)éå5)ć%©ąłU„l„IG˜v„ƒ8ōåĆaG8ź³ö§}X?ŚBÖŗ~ }’‘°#””ŠC_>Œ:B HZ1Fū"eDĢ‚bŚŽ‚3z8˜µ #*JZØżg į7}÷qhĖcMŌūŸš[&*)üōåK˜Ą1”n>3AV (zi®ßÉĘīó„œ&N-F04g‘˜™Ą€qˆķ‹-_uĆņåģ^}cö: ©5³×ˆ&ŲČŁ¹†8É €#V-\銹4EżÕ&vF}y$2Ƒm rĀ2ČĶ"€ć*|HŖ* ØWŒ‰ Ą*¢K¤Ł)½OƑ:šbJRŗ;ŅØÜČś„A1ˆ'¤÷ļ‘Mhfٰ&¼£dČ2!Ņ€—CieAœ$’ˆ"`IĀŠ~‡}’ūPźc™%>–÷PŚCe˜E=óPČcøÅ»™ˆv(ŲÕ}QuAŖ D:čXœCaŽE9äIsU1Ž„8X @‚ė‹—‘6Ŗ" p(¾ĶČYµÆ& Ū–¢£ƒ`3ƒõ©€uŖ„õjthużÖ1”Ÿ¦(TįŹXhŪ@śgöT "Š“ŗL°?G&XCIj‚aĄ}®½Eąd‘SCiB„‘ €Ī¾“BĒ&LL°x ŪYŠÜOž[ŠåńŖaW†&Ą¼ļĻJ • "Ü]; łHjēØ#;ǁŚ9Čґͨ”ƒĶJŽĪZ9¼ĆŪ7J¢ŖJĢjҘ:3* @j)ĮÕŠĶÖj5)×Īž;% łČ 1„E&'ń{(YõIbÆI†'Z$ sÄčØ&tÕ?ĘndyyŌÜńˆžgŪō?P,‹„²ž‡Še±TÖ’P±,–Źś»Ä2Ś 9¢•bJ«DM DI . )-‡“š20źÓĄüŸY’‘0}`ųVä=+%eŖ)Ēc`GĄćŸ±’"q7ęū‡wcŻą¼‰ĀŻļĘw€ķ¾¬øŪŗb˜8ԁXIpĘ0ł{ŁØIŠÅ0ŠTśžŖ}ČR1‰ˆ^€U Tm’1āĄz3]^šŪTŠŖ2 é€L+f“̦“Ōę“+Ēūt•Ų„kgn™:“ Īx² õIb±eHk2‰W“2{3 ‡C GbįĄRs!†k}²Šp &ˈ=zp8t{iŃ1Zõ‘÷{ŚLŠż{Œ„j°Ūe¶«ģĘ»ŻpF!Ž/ZwÅĆ­yØŠÉ("„Żv›ÜŖŻF7»'яŒnÅ;™Żt'āČY݊žūŽdLo¼äö#Ó[Ńe|“%µÅt䤸ƒPŽė;AŽ…7Ž„õ»0~ÕÜ<ÕxS‹ˆœĶmŗŹF_ü &ām ”–0r”r”ta(”p!ļ»ķ ÆIzĀUk’Ū]š¶5ŁeaHśōĒ’Ō.Œ$T.”. ](\=•¾Ńkiźbö„tWøĒčJ’ąhG8ÜZś-²;ģŽj7Xī·lē#€ŗÕ% #ōN*ų¾é÷+-Oć:Š=̧.ÉĖ·:Œ„scāYGLYƒß‡(ÉJF0HBGD‘‰5iꇤē¤ƒ£>F­›ōmš€ėŽj”ņā­ō|gŲż#Ćߏ{BÕśīćhgØw#BŖCĆO‡āō ž©)؈Ā"¹‘øyu(®1føa3s|&¾29łĖā3Ć~3%‰­‰®ų‡e¢‰8Ó@č‹Óš)¶˜é® 뙳AåāmSˆŌT:{”śŽŒŠĻ“¦¾ļšK}/ėHæĖ<Ņ¢„?Č6Ņo7޼æmI=µÖ™żźœ ęhuPP£“:)d¤e«ĀČčŲSvY8d×qgÉÅua(Ä­TŹzöŌiŚGNÓĪH³bŻ “«~ l£’E*–Q°¼z„ŗUØYy½ µŖ¼Q9/T„2"L$ıčOhēF BŠ“Τ6nŌ–PWBć$ØIØ$õÅA5$ŌX;b݈5#Ջ¬uWZ±”Z}`Ō”Éß żĪ“gĪš2SŖFD¢•ųMdLŹÕwščuFōz@›ż§Ē4)GĆ}"^õ”ĪHg“ö”xRoźŚm'©Wµn*¹Į¾ŁLyŸ© 7ąfUągļćMšvöþ3¤LĖIźrŌüĻPżH2qß8"kīģš×$‰’3ØŻœ(C‹ .¾lÄ“VčsĒĮT ‚¬ŸÖÄkHĆNƒŠ#ņ™1q&gݔޑÖ4d8`rVd“SÄķPCøÉ”Ł+qaē½»#ā#HCČDŠQ ”͹¾šļŽœd(¾ē“+ēø‰ē'cšæŹSdŽģÓ> 2ŗėĘöæĀl“ŗ 6æµVč.§]?ŌÆ!¶ÜžżŻ č¼-l%aG(;BĖOŸ~:BŻĘģ7żjŅӎŠq¦  <ÆśęĖQk˜µ‡.ĻĀž(ė]®F˜cé¼}=ž9§AöĻ(Ž¢_Ū©Ų»ĢBL„}gĻōMoÓT«¦·kŖesb¬Ūjݤå·ø]«c”·rz;§®ĒŽÖ©ÖNoļōÅäŁķ€ĘŲ"8²Ąz_ƒ4ŲœÆŁ :1Ž×~3²0žÖ¼ 9 M?#6’ąņ‡Ę ĄcĀ< •yÖńK¶ąd˜““łńxÓŽ>¤6F L-ņ1Y`Ü}d3J÷‡%ę@t‹„Ų/F©1†|@l╳įhį1ŠV,Ä4*m `\ÖźśļRĻ.³Č»P¤3’”BGD嬮7šdÅć~šLś·Ņä_BĖH²äu2L¾Ižż”&gūć÷ż/†y5Ś/˜\Õ>ŅvrqY=܇eĪÄ~ijż|#’µ)ßēK/ Œļś|™G&—zü8«­÷«bģA€¶āč֕#Ė}PŪ1n“ĖŹHā`‚d‰bErŠēč1Øō\&h÷Aūŗ’‚āGūY1’ō(j6*Bōx'¶Ō- ėœsĖa&ŃÕ~Yę9简Å%œ·yŃ“ ‘D¢G€®p¦” K™d…u5ćJÓ<-“Vp¤ćż¢ØąX÷cŒ†»b$ŃĄÖĪ[ć_Ōā•㤠ķP± Ń©āa<Ւ7YMS޵҆ Xų~óą•ūčįCat•;¢cT£Ėqu™k$tƒź­`FĘfćRŠ×š]²fĆј#«”+5ļį +V°†U.±Y>’*J4īr¬ Ā Gę9P¬VdͧJėl(Œė\#OY•®ü0«$¹‰ę,“ż˜_;^Ø[f] yę9ÓĘf0%1P“VTE6ځ\ÅYӔ(,ĻŖ}ąćcĪ9*ˆĀ8ŗä1·¬!Ļ Dsš—˜dA© ēUĀłŹQVp$äJ­Ć}PXP깂į.9ļ”_ŠĢ÷kž ‰3+ȁІ;.¤- V¹Ņ,Y¤Y- āŌņˆdn‰ƒć†i&•¦Š4FfĆ sF.   Dv8.ˆŲRØj\HŽQ•YŽĘĀIŠŠ*Ż/ J(" śŠtLż¤§5×ZzÓ”D3!‹tp—7F|š#Sf-h™•Dˆ˜Ś\¾„ÉGŌ±ÄxX«ż“Yr ¾–ÜuAKøIk·,r]*rG ¼fĒ„0 Ø7•ėu]ƒb ß«/x¼³Ō­ŽĄz‘øĄž°ŽhER¼ Kr¦£Z"SB%!UtU„ā{ µ)ŗÜśā°ā0źēČ #µ}˜S—vę¬ M1ę¹5„©ćE,žTųĄhȂG„ČĄ"Ļ×2ąŠ—B"G)ó®ō@ŲP^×K̘#«4"ØqnIĪ*Śå¶tģMČ*HÓ|,y!—ōŖY 9+ęŠŲUP]ĆóGBKåĄMėqĮ¹ńøRĀ̘8c¶käxTJ2G‰,«©ę-³t$yA/)Āqø‘k „ÕRY,HAcMFĀI ®f:¦¹Čó+sK=F:1/&sqTŹTĄÜ©¹7ŽÉ¶Z„+nµpk?ųjxUEøńyQŽcĀ^«qō¦Ü ® “•™šżīp a=`śO{6ļ/ü®s'–4š¬åęP©w;×:@g±haxN“)gž½œ“5ÓéHWI~”Ŗč3¤•dŲ¤o‹³ł+ō3:~«Åüö½3ØÜP8 ŁµÆrĶxQćēŗ›#fė÷Tņ…÷Ż;óO‹5Ś nŹ.ŻČ†¹ŃoŖIÖü=w…_‡š‡§D3ŃĀ©æ©ÉĻ|ąÜ ÆlŽ4éŲ5”Åv€ßéöEśilę°ņŸ›æĘläg¹tE:qŲ[ÜŖ5ųĆ*#7å‚éoęē geȞ[¾@ˆxŚZnW¤2=»nģÖ&żqTR†œA梢#ßÄ­ŃģGŒÄ„„ȏńt”¼QćYøæŲ@aØŽĀ’p™Ļ‚»»…}’m•udæąU†7jZ&‡Ü‰šMó9Sucüw^ sv¾iD@³XÜhŠ?µõ{:ē±Īźˆs1ÜĒpéZŹĮL8  %vóųv„&<ÄFƒs-†ØF æß°CØBhIœtD n[?Ģi 3ōųL½ozB.>1PWż#l®ˆV ķ䁫ĪćeŽĄ3Fu²§)ßrņtyą·qZh`[Ģ4CZdr×ɏēgx:äPedåģÄl‡BpöŘճū”Joyf#‹ó•öąIšVD‹N·ŹEX"_)~žģŌ“ wx8’j ÓżŒZ†‘Vęā°±Ž0GĀŚ,¹8=ĮzKō¹.«!ÕRbāp5M‘Quó śåĶy™|üĢ Ó5Ū‰ÓÜĶY/ߗ‰S-'źĖĻv}–nüŽ|wŧ„Zއ_žlxśĶ!°\Y0įšBŽEuMŪqŁgå0·ŻŖ”'E“Ķ °–\ŗ3’§bLÓ83¦7Ęé'c5eī”®øö#4ößŲo&ÄõjĖ21®rbŽ6ư®Ģ+ž¾T08wnJt>}ĶSŪĘą”kšĶ,Č óølDRұž)Üōj{t2ր…/ęąń Œg_åÅwU¬f™5š)x`9¦ąéA§:“"ĀjBĖč„£ĮLč×Bä:˜ųH³–+/„<]-yĢu¤ˆé1”+Vh’‹}¾#p•»,Ķø©qOO®k…›Č=a±„?Tó-lʵ©Ķ¦¼Ę'ćÕ®œ÷(łŠÜ‚ī ·AŽą«­q'Ū^Ó·>õß>īÆž?+ķ‰Õļśļ;Żp[5'Ļz“¬ć…ÕQ ¶ß–rQ”!Ēöcz'óöŅdĀ=¹-õ‹ Äā±q‚ŸŲ^!{kłŠ2!¢ŲvŸ… e§‚„hŃŗ#€cārLŒm@™Č±ØŠho¤0v=zW7^†LėAFtļĖ$ü Ēɳtą{1o7ļLG'~µÄ%­…>X“2¾‘~d9Qځ°}¤3‚†–¼Ł›k8Ļ›ģe[ō; Қ+4Ī6Ė|p-·śķė'ćŅÜ>:tõ•’Ü_Ļ’Ę-ŒėČ÷õ#ŻM—jUöŽW>ē8śč¢?évŲ#󁿅ß{bBųBzÜö®8„Ŗ„Žū}™§ižm^^““·ėwžõ±Ū&ß­ėĄnL+”MŚØ–Į"¤Ą=Ēņ­#f…C˜ó¶čzr~ä`–hĄ\Ē”›ųņ'g©›°Pč:ƒ¢ö‘ąg+įÅ¢“šjž¹Ģ°’§5„4^›ņ]+‘Ti¼ż¹°c"ź¹cĢ‹ūŃrÜF“ėĄ?‚fīóOKڟé#½@ˆ4‹Gsļ÷37ĘöŃ$#gē¢Ię;Č4³SbFŚ[QäŅŌÅVŠ=įŹ¶‰sœ¬„1Ü`qłg}@ˆ•24­]Üł²°ģ÷mA61*ö¦R7“-?GÓæmż+·QƑ`ŗMAZ‰DX­W ¦]éīKņ< Oc° ¼ėĘ{ż|~ŁĮpž‰Yv­4ÄøDwBĄÜ¦øĄe÷I榠×%Åš\–Zø +'C»ž²œpˆåĢĶā!½Å4aĖooLW›‘¹Yt9›ć©%šV…€JŪE™/H&čȶ†±.ڤ–yS'¢bī™ū…ß?k¦0.–˜ySbz–š`Š« Ō<9QtčUEóT,µŹ~†`犨­U'b©gjŽ&Žrža«y€§»rš,¶8˜»kāČb÷ø*²ūr7 |æœLN3»!žKȇžŹÉŹ fU…ƬlĘüźŠÜ a?VY7ó@A¬ČJ~ěР#+į2“>Ū%«Īū}r]‘¢™“;įŁgß|Zž•ł¶AÆži‚šŚŽ«Ž²_°æ<ŅqöˆphM&. Ūńv>Fö )&¬1*ŻjD:…Ųø=Ü J ĻŹ=–#õ,ōÖ™(‹[¾_ŃKŸ 'ø‰™)<˜}d3±d—-®)шßb³Ć ÷Öh8˜üȅUņ¼?Ņ=?jU­ī¾@Yk>jį£Lvę\Ā1`9šĄĢ4&Ó,Fµ}Ą÷{r!.Ž='ŸŌ1Ž‘cZ®”bŃĀŹYAҧlPAG(Ųæ >WV@ó¾ģ /³³Ģ­€Gæƒ˲>c`rŪ-’9%¶Z³ņʈ‹l†Öž ł-²°LŒ”Is%EŠŲt}ų¬Ffj_½<œn*Åj[ń FųŒżŹ—…‘üjˆČ]ę°čB˜9LÓµX~B™±ß鯷F‘–=%d‘Tb¢Õ(KcŠW ūčé(s “LĖ B`ʔkØ–č'®5VĆō*ÄS9lcÄōŽm¦ÓŒŃōHśO,9óC3ļ.Næ“ÆĒē/’C‹’ Eu›!ÕglŸ³n×KüöQlÉ$łūPV÷Bv~žgtåuaŻ””g¾}źÓŠ8+<³š-›Šķ»pķ ĒĢJÓÄä™.gn¤Œg½Ź)žķīZ5a;Ļ&­Ą=n~¦&ŪęŠ`ß°:†Ā*ØŃ⯛ŖRĘVž”ēŚ¢8Ń~b4³ źfbFČ»|=c)ø=œø§Į2NF×ŪŚbʧyŽÕl«ĢcVī’‰Gx<ķéž&F!5&6Ö¾8¶ø­‰‹Åŏ"ļÜeȄx¶]Ō¢y£š”“Čgž‰)ĻLEŻqŲ£½Ņ>ƒģAÖęŲ*€×ŪĘąāBe†˜„Ÿ× —iK£Ņl’XtÅŖu1;}!aĀÄ;“GęģJŒ:9K±®ž½VŠĒæBY6§_eIœ{bĀř¦Ö?¹š.µ.źYhŻ{˜‚£Xč^hŅO¬ĶÉTźÅ5&ėH˰DŌµĻė586°µ¹šū^óY˜!dƒØ9(ŌhmŻ—^1ŽpĘ{ģM“ŲS¦ēØS“ČźT‹øMNbÓūk¤ćū*ˆ¬SūؑĪ*PzuOĀ“ćÉ»“bi*Ō3žü™KĢ”k'o»ļ f5<&“Zy, ™ŁĒ¶“˜J|ÖvZXń”V¹²,ū&*[Ÿ!äü·Lc FtÖ*‹Ć|”øL`½{ŃĄž?^.ė³Ž?ą;ÅMĆÕĆÅķ{ŽŁU„ÆõĒńõ³W«Gųy’„\7dG¢źRfEd~ž wF¢Bk*™!» ģ¼}Ė ęjŅĀĢ'Gę™)V)ņĖ8HW‹2o$øw†Ķ2+ ©d×*5ÖDŖĀ %įék¦rčųūVƧ\˜Å >×3?r‰ZŹ„¬’MÜN^•ÅÜE#¦ ½ā †*ƖĪņL„Ä؀²tŒĶr-'“i Ž}™%ĢŽh¬“aņÉ;Ä£0ż„¬šĄżIĘ«3“cGcÖ]&žœį]°Ÿ#ćģėū¹¬–ņsKøpŽįōz.,X±†R…°Ū:AĢHübüĶkP»Źb>6Ė÷ČYŒż˜ßwā5V¢PYۃz[O×[ZrØūņŖĆ„%ƄŽyLo×q‰),ó…0ßBµ› ŪE¹”/ūÅJ¤Å _æŒ%铗{æ?ŁÄ#1=N5bīG­"~BÕšł³cR[Ą„ØŁüŠĄ§p6̽½įaŗwÖ°åB{b3®iY‘‚GŲvE=C¾€ķ  &Fõję­kBę‘ä3§`.›møÕ«Ų²ÕE,uŒ*hį6šędv²° ŁBåDæüē(m«Q«ņ±[Uń{ĖLńL÷wŖˆ?ŖóJdk‡°ö©ŖC60T]dvõ(Ł“źūuzjž*¤š>«nĢ›‰…3šü†©ł&Ž|:TÖh‚č}ŁīĻóĀ4ˆu`·ģæšBŌų6$™ĆƬ>£‘’µŻs.±VŽ1Š<]¼3čMG¤”D Ė‘ųåśĆ^58Ģd±WE”ĀėW~¼ģŌéķ©Ŗökųżnķg«1ŗuŸ§7ėÅQšį÷ /ˆ„zļÆoćIc…įgmņāIĆ;°ÉCX;GŽ„Ŗ†EÕ-'~jÅŃ #¶—¹D"—”[ÖŹ_œ3čVÄ_7aźP›D¤š­­Āø²äž•OW!öÄ>"—»÷9+Q ՏļÆš40X' źÓ¼;ŽOOŃ`ĢĖjQ9Éc™ēļ.ś¬gѰB‡8óp„g%¢m+Ź„H·˜zYŃÕkOjš—Æ3DŹĶŠi\…6.•GT3³µ±RIˆö²ĀģM 1'4ŗ Ļ„b¬‘ŃbbD¼¬ ¦³6e”Į„eńU:$Ķ—„Ö՛ iš€Ja")yDm) f„źa]a³œr[ZˆŠ€‡tUOebIĘ<*ń,“7L·å”O9’3Ķ;ŽJz[[•K`šS‹©I\.gX˜.Žtō_ ~ņ’°ü×uU›Ādµ@Փy×qµ&—Š51Ē© Bֆ½†~)ۃ+r_l­l iS…W””óIÓlōÉŁ—"ūŲ o™ēkønĘ%kžõS•EŁ™&䉌5&QL†Ęž_JÓŖ…†Õ©œµ/Ģä–ņš­NĖ8źąŹEzhŃY¼+įŪg³§Ą¬*<¼ «//ųsį …æ^ŹźĪšzČym–C†źąÉ¬Ņ; /¼żX—dõćQdIž€’šh’€s Ŗ•yōŸŖ·7ü=9ŪŠ ķ¼K©•12ŽA-vsĻm˜½Ed·v¦ēŲ“µf]ȗ“w„Éė ½*ĻÖkųwB{ŁjYĒĒŪģAĻ;ž+ØQ^½YĪõōńÖd¹Qa°Ą&ÜŅ ™4d^ ĪC$Ū„)1Ü$*]åG>³/.Ģ—øš±ŗĀß’µ¼éO·ÆS±DŽPł(d@“ŽōOŚ Ē¹œØd­ņäŪØ§™Łj4že)–moĪK>ĮO%ā$Ģ[ņæm})p¾YŃĀ=¦šE`ÅÓ”+…s ’LŸö,Ė#ˆ-`²MW†CxįM€ĶJarÓRĻQ ”»¤ßavł˜Ka„ĻŚ/ō2ńlČ÷ :ÕSjø™^1b;fÕ9¾PP!†žcqš„ų}T Xˆõµ_,,܊{6,Ž&礩¢ęćÓøX’Bŗ&¬”µŠ”¾6{ŒfŗjĢ”Œę"­õŲ¼-²-6ßu[R“³”« $&NĀŖr ŲįŗUĖ:’¶o…a^ūŠ'×Qš:SмXZ›P.^sSóo=ŽŪLĒ"F:ĀĢ2®›™åś»xĘ1īōeČŖ²“„KaĄļ%$³»s§ńXBF£¹¾ŗ żxą–˜^öąx‡ 3Q&Śe™›,±’® cśUvuŸ ’–²°n$³Z½Ōu€LĢKīĀŲC­¬õž:—%»“iÉÓc±w:å*4—ee¾ŲÕĒK‰0“ī‘Å+@@…CVö8ė-„šˆęjm"=²« Ó“^łm9*‹–“-«3€¦Ė.Χ9Āl”źnCn-®õeŽöŸÆwܛNäU/Q›<„,©N(Éź!$Dé‚ ƒyLń}øW†Õiąc<©6ź.˜4é3sLwˆŸõ@ėȦ㠹 ©Q‰‡„ßgĪĻķƒūåU,Ē/ŻwÓņ 2%}RfČVśŹ©«öƒgfŽn aĀ™g¹•°b‚®ćŗĒČčÖA—oJeTOųŪ+G‘*mwežĪbõĘ ­ą¦ŽUšį›øŽ®–ŅŽö‡5 =ĄģÕŖDH„XīČy?kżŠ¢Ģt2Ėŗ×É•ö P!Ė&¢%ĻtźéRq ½‰–FuH(y~čÆUj27×A;°ĮJ‹T1”?a  ĄŽŽ·•ųI~±¬Į¼:@„¾8Ļgšp #éQēņ¹Dž= @W¾\“Śi±h’-ąó€©ŃN\hYr]#ŠĖTńp?Įū=Ē’€Kęg5a}ļ’כņ)äĀc\OŒ‡xŹŚA6¤ #8h7ē\Ģ §…•ųó4i¬5ōŖID–VĆ-Y—­§ė¼I¾,“"X‰ćZʤJB?Y  Ļ~čż@ŒsCcó›įi™€õ¼pa-†ŅMœ6ŹZÖŅčż6W.~Oģū³­UĖLœ3nS@Yæąˆ²ZL@Ķ“Øįe&ęZCVĒł L”g&¾<–ÆB¢R(žļæ1÷wó³käŒe’ŽÜ?<-lūŽĮDåOķŖĆRŌ‰²§Ņ;„صĆf3™½3”ó ³„…0Y‰»ŹÅ„‰čFdĆ}B™ŸßOlßÄ8N»½¶ÉŹN3r'3ķūŗžFµ)ō pŪ/ķž£ózhęī.]0$Š‹,‘éO¶•ˆ`AŌ֮Ē.¾—Ķ2Ŗ¾éÄvŒ>¤%»Q&WdlŚ…&]Ø.°ŗ†v,[†ń܌žłśmß]ł5²?•…_™r@ņm>éŽ"P@»±ĄĖā'hČ/1 ‘¹ÕK‰Tł„gF˜‘£Ųėbødi+.lfDsRWü4G99oq x»““Ēr&‹@ęÅä½ģa^ J¬¢>ŅCāšИsž3Ł`$ī ޶¾5…¾…ĮMŲ)$”ē×¾üT>üš¶'Į¢™×£Ć½46ģ9č!DÆ ³Ž~å—V9$[åĢę=cPĪp 6‡A­&: ›v ž»üžk³?5o®aÜp ąlją]2įč,؝5 źš šA”÷øɃ )>v€¾+ō9£Pģā*Ą’6Ōµ:Lˆó³ ŁŸl3īĒ·×ÆĆŽŸŹ¤h5Ż„Y¹_”²ššBcŸČzµØŖjćŌ{ś³Q7ÓMMoµ4õjącX”…X‰BŅwŠQķ QW”Ų™n²¢ŒŖƒš’Ÿ©Ķżf¦ •<…õļēĢE†[øČl\^H%š Մ”“c:¢'©_ehż£gĮ_Õų*p|~żéÕ§fŁ/Ś>^ÖÄ.P§ΘĪW!…ĶżWu ­Üu5ĘŽ(_——Ÿõ'TīÖŹ†½zžbALēšß»p²e/!6|÷$·„Š`T¬Źmæ hžüÓūjåŸLŹC€1[d·#Į3łM~ęĪĢĻT±‰‰˜ĒS Ÿy`ˆūɎ«ŒQŪ K,u¶juä¼5p‘6:ū…³…ßWÖÜ:“ω½įźó$jJpx2'Ī×ęAkžž™ ¦’&>J5ÄĖāńśØ)±“^‡ž¦²ó/Ų;ę9 pMR¬A¦ĮßļĶR’¹2Oä~˜rž*@`@“vź ģŃQ8/€Ÿü}ÖŁģ1Dä·vęė@!±4½ńD†BcĘūµ M ”sėX޳Ą<ŚRĒX®ß#_ē Æg»2ÜdKŪžŪs–ˆ·Ź"·E•ž”@³ž²ŚĻ6 ²eŅnƒ%Ō¦“Ŗ±‹Õ1qaŠ'.ø¦äĖ…dż×·]šˆ#ׇšAŻ4Üj˜šĮ±ÓY—·ģ¹*?ģ×vĻÜ`$¬°žŽ%n·˜÷'Sßķā’Øą~l—ŗˆ%³NÓk‘Ž%¦»^8S>a‹-āūįģü¹ņ”+ųųģŽ­~č»6HĘaz¤Y¬ļŒ#ļS4ÕšØÆŖdsķņĀTźĄų>aS&¾ «óEīAĖp£Ro±Ā2¾Ąd“Wßü„ėYdX«ł“ś”4H†ĄosŲ4ļo%JĮ –į™ĢEmGĀßāŁ²¬Œ“Ļ®¢>½Œ½X¼YlCŁuõžZ,zø‡r Q@ČG¾Y4˜eqõ}}i—ź<Šžö·„­zޤQ²‹j©J ”s*ÆŅ{6œ<&FĮoÖel²ÆŽ~-Ÿ[FĖgÓ§˜ąŒÉ*QäQa”¢øė«•…gŗ¾H‘ļ“ŌŌzūnĖž čušYїłsŽ!€‰‘N!ÅÖ64aO…üV,³,>0)üßžū ¾‡ €0gp0œ„ŁÆż".«-P1&ōÄufimÓՒ²@ā¶ÜŠ&ĶC!!tQgk ą/ƀIdCÜ6„pø`hŒ‘š,¤a8[“@jYĒ¢ĻBķ\;ßZ]TģlH³H…„GĶ,ą:ē!ŚäWCÜŲž ‡Æõ  ˆń|©»Ä9ā§90" ųC\?z®ŁCö—]2®K£Ģü  £7½"óŪw+™kˆG½Ńl‰"¹™į—5!€Äö©Eņ™Fżę¢_ĒūŠ8Q<±æ.ŖŸZmŸ WŪRśē„w9)9§Y¢P’pWtmuŗ†ą[ŪĒ1”ŗµĻ‰żb¹ž x%›8sƒפzh.Ģ,¬ˆüGø„/>EB3QPę$‡M <ųĻÅVŚ‹ÆÆ?Ečmų` ”N?ĘįĻg_=…‹>~ŽĢ³DNn’'1#„“NI1•Įä-\†hŻļ+ąko+!‹ƒVhŃļoī^ä†:O J “CØžFĀī7q%¹"T‘ 5œQŽSĀN˜ŒČ’K3w4ŻzE/É×/8kšf‘¤1]ہX;i'ÉĶčšYžųž£;ё)øüįüX“ś_¼’ēa‚ÜK'+2³]œIQ† '¦ś8ĶO“®!2œ}L¼ ÷ L8m)²Ī" (»™»ü=ŻÜęók™ļÖ6ļ‹/ą§y_āÓ E!ę]Rh5­ķüĒ£;|3Óųs›Cm~|’§ø¼„gŃ:9ń©r8U¬„„‰™ļŸ’äC$·sƔRź7¹ĪrcOĄÓé>7…ÜVcLŻĻ씚øˆ, ŖźÄ›"VŁQeČß÷E•ćzq+ēu;R©h'8>I«fb”L&ŸcBŌ„ģ‹^Ęb¾°R¶ €,›«ń@-Y/ßä“Q3OüJL„%zæżM6ž,8Ī'é„¶Ü`Iś‡ĒÜY¤ēÕ-ŹŃ} ō$\»­­^Uńn§¾`Pˆ[(h¬ ƒ,Ó-µO6tVœ1E.O“T'eM»*ģf;LL'ļM¹>E>Æ}8‹ ƒF>jĄąÓ'ž±ZX5æ¤Fœ¤*Žt’µĘ¤Ž¬ĪľZl *'ķ€Ž“É%ųóŹĒvÅ`2‰j$Q¦“Ž}ÖöNł.”eȃȌ$€²%Ģ•ÆÄt–/U˜›¹++5˜#’“¹«ī'Ēø®'õžõ) ’‘Śtö0Ą,5ŠkĖć*Ō—¢ņŻV°Xœ‹äOōö”WYXżƒĘ"”ˆ-Ö8œŌPT>EÆęś%iÕTM‡/G@_é¤q1IĮÖs:8ßōbQ+2F*U'Ÿ…WxŠČ„ž”ö„a(6©tłöŠR؋v©‚ąkŖ'SEĖ&¬;ņr\&ŹĆM\n)p"Č~…\BŸ.ꔐu3!æŚüÕæšóCń ¬ uO”:˜Pėāą{!oÆ ü’ÖIȔŅA³!M©šń’W&&2D½ō‚@ŌplŹL{¤*›ķÄ­¶ŠˆŚ ūžQéWνēx‹µdDŽŸĄÅų~ė×uäŚ=™%Ęøˆ$ė«ūh2N`Š”†+ĘŽ?؃ŸBO÷ćV:¬ņ dS4YÉ+rjš2)Ū’eąæ'%Ķyb”€'ŒĒˆ£ĀĖņEiU›Dą¼ģĦZWÉIgH®…ō–ž-ņFq䫳I™,MHh®,’¢!б/2gŠ”ó`ˆM)ŠŻ}®"žķJæ6”ÄķU(ąA±“‰ļą„[q¦‡0wżZžęOł‘¼¹®ą`sŚŽ„-ŪÖ'"7źzqV–ƒ¢žŹzjkwxērˆ‹ÉW’–x”“ M°?1„ ©ļ(»"»V÷¬%ż*!ΊÕtlÉfrńVa&4/"#­+pø¢²nžć[ؼ§ 0ƒœŒū–«£/1­Ž¾„®Y÷S (ćK‘šI¾N‹ė"lą˜¹VĀ” ˜šõ³Üośz`ń½Ųö©ńčĒó\śżJTåQ‚øAMi£0ŁČu°Č°õ‚ƒhÄvЭ͵Ģ9 |b®{ųg\ȵÖU:8ź1×ü<{ƒÕŖœ°ĄO8'ź%|É0Ę9ż#±c“Ėkø&1Ńėɋ6ŠĀ u¦ –Aj×ōHÜ…Dr]l’;€ ŽĄ[Čl›1®7¾ €źą ćӇāN»”°:ĻIא¶€‰OjśÜķ Ąōŗ 8Fü,^U»~ßƱlĒ%”ė”|ū=*”‡v”u€Ŗ©µZ~Ÿ‘ ē£M’īzĘ8ü·#RÅ“.*Kć'čWlY Ņnńš7!`^Uę£ tf –£*t6yČjvĄŸĀva֖aÆ!ž="¬Ļ–N–W틦Pź–%gb„² ņĶźHö$>{ūf(µOÉŠ÷äÕ?²Ü¦ć@ŁܾšĮ„ē9±Ełōń™Å8¦ §h˜éU–ø<Ē!»ķÖ·ØIŅ3ŅUļdķāžļęELSiZ_L öh2=Ā8« ·Gńl" š™¼]ąÄ›§Ń>>q¶PįŃo*āņŲU0ČĪr»æ ”°ü<0å=³›°`«Qײr įŸ9Ēxüg¦@ќ0£‰?øÕĆ©Jėhø—ā ҐĆ>‰-€ĀaÆ21Aob›ą"jŻ$}©HĄ¶7!#ՖQ”0•ŅÅ ;Սiƒ ė­`ž6,柋ėŗaæ`Y0 ~BCby?Ź5 Į€bQ bwTSē-óš.ŅbN‘x\ĀFzkÆ1'‚Äż:»½ntOŅčn)D•TÖH|5į”Ż^b„tå ‹ƒŽ.„.zį-”ąņA?„”ŌūA)ŠˆŸ/UfrŠa”“¦Dh¼ƒsčš§é²‹ 9=Ņž?蒮@÷ˬdÓöcˆĢ¢Øóż”Żø1­u\ÕR[b_‰19™×į¤ƒ >į U”ö+mœöĪ^DZM»‹±ßÓBF½œ˜õĆ;Ī×ų˜łįū œDõ>uĢøqŹ›¦“N®ĮĶ&Ķ}S%“æI2¶ÕĆ„[rŠK\Õ,ĪK’Ęü>7F3Éøg-·t“^ĆŃ”ÕĄŹB…+ä:Ō]S¦O'6¢>  ‹čš;6A\ ń4/Ģoõī'Ķ|ŅĀ,æ³Čxˆ“}jƞĖ13ŃR•;cēĮŒįpU9$÷…Ų“ŠTŸĪ¤åų=+›l–”ņmug™n–ÄĻņZ{zoP8ābqā‰ā –ĪTłūĆZrHY ¢x…]ę})Ü­^C§óٲ+ģegŽä.0°[b Öõ©S# ®łó¦#Ž Œ7ˆé”ĮM’É+eĒ˜ >DÉh³ŠFfn»Kś &'n¹²‰Ƌ²“»=A¹kŸ“ļīXĘõųdc ęīlā??÷Œ=īÖ|6éÆżŠ4r2ŁŚ 2W4P™Ž»Õē ›5„eig„yh€ÓR-ÓQcėčI°ir’§¹'"‚-čn[?ŪĢŲ”óV%Ģ­]¦ł¤+/‹¾œŻ•‹·„ĢžZē“U2’²NuR-ש@0óÕ«lĒ»Eæ>‘sož0£WhĢ0õ#):˜X:ēō„ ¤ė.ĄņkR^X•Wב;˜JŖŹlįČū™*e?½ŚKAs9ĖNe‡pD5ry‚yĻźVø©ØČĘ-,F–ĪbŹ`r)'ä|Ęԃpœź¶Õƒ)üŌ&—|B mĀ’ÄO|‹¹¬Õ–žĮö#„Øśš” źßcūU.–ŹZą”čt#éŃKhæØĘŪg g׃„7†öTē4ļb6ĄdÖrź‰Eēīé^Ā‹ķH¬Ō¹ Rē!XŽ ÄrŹJ‡Č‘ŖœKÅŁ/рŃ|*t6ö- Å2†3jvÜ^DÅāPÅu}X„Œ B؉ "’ ZŸ"źēą*•UbæĆį„“˜A ß|UÄYgÓBæ<{XO#ƒ½D6.sš,*JS°”LšœéDšéI*‚&÷ču!•Te¤‰Ž®j¬S.õ `&daNM¼8U­:(ŸpšŠa=˜võ×&ƒŸ×`ėøW€Š…5šŽpšÄŅTQīź [g² ’4Ó ˆ23YéĮÆI;¦†ĻIøD˜•øāoÓ*«įįåK£æž›yÕ.¾;ÆŹŗõģ;Ūäl¼:–Æ”iQ§)æk¼ Gj²Ž/UQŃO$į[ųH4\T›J¬M]‹ŠOTş' ŗč5ŗĘĄóīų± Ģņ•95Škń„˜Pé}h¹“t n9­n\’S ß<”50XRÖN%žČ¹~ŚÉö(`ž‹²Imb`üX) ō£$ņŪ|řķV:)ÕąŠ×l"Ž{øĀä_‰€£³øā#ø|Χ%GLŽ n…œW!@ihxg+e%Ų¶Č¤XS9[‘ÖņŽļŠÅżŖU·Ēj„-„צķ£åČ|Wö4õ¤ ń”œĮ¶®Jč:éC…ūŲ D$Y°#ŗs˜`Õәä퉼^?‰Éе˜p² ”Q^+G_ŽÕšóc ·£UŽŌ,² ،—āłŹS÷s®8ņź•ŹdA/DŻ,0ļ•%«ūĢč[ݹ‚‚gÜz»Ų(æ EŌ^ĄÆ‹cHä1ū½>‹Ä+„JWƂ/ģ"0G« Š—sNłĆņqŻ™›>+¬`ļšü½Ņ–ŖœVu¹»:€Ļł7VéF½F—Ŗø|!Š !>ąRW™’ÄqČŹŗ€"”J‹ŻdЬž_4Įk{%Ӕf¤g»ŠŸˆ”R@ÆWüµJĶ*RW[œ¼hč°„#“ž"š`&c™ųčU”­Ā˜›}i§Yt“ęŖPb;cU'd;c•°AīˆčSųŠ/}éÖ-gełńR‘ƒē*f Ó9_DģhĶ©@é:dIĮX„ hĶ`'1?†—"Ūe4±dę$¶O,2.źåw0±˜”+0^ߒ½,‹ƒ ĢøõŹīvj'Lc ąķÅ»:©MD-źń/ģ  E:oB”[_£\Ī…*‡ę/)¾T…1aĻnOtäMN8w°h‹0p,ę‰!ꚣ³›ō¾š¢ē”žx•biy Śŗ)ī–—ō°¦ŠižŅwŪ”pń±Ō»śˆĒ)¤dA÷ü]5šD³1Ī®L¬óŖ"øÄ>ēš£Œ„Lōœ¦jō Ś HV.É|²5Ьv«šŹ<‹śņ„’ āDĀm"Ėåń»NĄĀ_śe!½äcB•Ą‰Cļ7őĮ“‡ü€łŗC¬ ¦‘€f†ī±Õd3ѱGŌ€æ'ŠE•~”/‹DoÜO“•EB…ŹJsn܉õA_Q=ŒÖKŠź!­/<ŲÉQϲż:@1=SE0ŪŗšĢåßu‰^[T[§³Cō å¾€?¦4ĢrÄ\Ä ¤Š>ćĆ 1•,ü6ėTĒēĮ‚oę>—'Yœs(Ā(3„ÓĻr ›>»KŸ`ńŒĆŁJ®Ō;ŹÄō Ų5ekƒe™¦¤)šœ;kß}s…73wÅx³"ٌžŲ²łŗ ŸDŲVO×[nŌ/ 9ǽŃJ~õƒ¤dā½ŚGS6 ŌŌ: §`nq~VQe³y”  Iē*VxŠ`‰” c'!ń>Xa%ļ °=]djÄh6tžD]æ!}4­Ė*8)Ąi)\–£Ę€eŒy“Ž‘™“®ódĄü’įI„¶·MŖ„ų°“U!_ĘĢbÜõó&KēŅ,‘h³!Uˆ±•iV7C[ÖĄ.”žq÷¼H©Īérœ 4Ėģ&ŠYŚĢÖ-ĀĢIE…4>!¦½TāĘzĆ4–©C*eN—Nڵµe°©÷ˆĶĖŁ>;ūĄŅ;oµ5Ł„&©fäĆń•#P ¼jø—³ĄńĆ7`Š‰ŚŸ5PuĻuv¶OžŒ®¾BÄ 1¹ØŠ€RMX°kU,œ2bažäŖEķ3Ÿ\ō¬,ą|üžå Ę(•œ¦ Ū=\ į%c~ÖĢ%g{>źłel€gW9%ÓEšyUP’f Ao8åsŠzW Él¶ „+ä””Ó — ­A~ß½īē'4%į[9“ģd”±­œY¦aʧRŁ1/fįbų:ĪE‘“3µŠ‹“²\ņb1nzD.læÆøbWR„‰ĪIĒl‹;,łÕ™=@Z>ÖF?ł‚”Įsęh‚ĢøT 8@Ū\ˆ «3_‘Õxp2¹¤ rÜYø¢OJ€ŃĢ“˜:LŖ„ēoĆ!æ™ĄĮjß„&DHłū‚{¦“Ä4Ķ""*“QĆv¢uĢÄC.ÖŪÓKŌäĀLCt‡€Xū‰‚}²ć“ ߥ³`L¬āĘMCĪ Tj³¼©k$Ģ WČ`9øĘiž®pZŁLD²śūÅ«Gæt!ĀEс’Ņ«'LŚ‚!ir—¦-;@ėž,4gFoE2qÖł¬{g¾it× /xĆ(FŁīj`@¤“evŠl6­c­ćGJß]ex°BŒČNLƒUś¼3ÓįĢśXĮÖÄ­KNÜSP`ƗKŠ<‡øŲ慅ĀŒį>.#@gņž'Œ ķ…™9©ŅōĀąųŹøŪŒņdįPœ‰y‰ÉV/š‰ż xƃ…·'“`üVxŻ`żx#Ž•ˆ"`˜ 6›„mß@ Ē—Qg,QŽłö‘cŽmČšˆ$Ėåėł£ł›NR`BČč7÷x‰čߒhLY8‡ÄqĀ™GR‹¶*唊™ņ›/ȳų»1č§ĖģAśnŸžu“'‰C"}ŃŹ¤X5ĘĄĮAāLĪ*N}lŖ}P(åŽ/¤ƒ[ ŠŃRĖ8Ģ©Ķ8©sJČŌ¦ Wœ–š{',±śÉøb‘Ŗœ*ļ}äõp:ŚfHŽ”œTÆČ£ūŖB˜Žž§H­/płuؔ†< Æ4ėS&×Oˇ-ʤ²ZŻč{ƒųø™Æ›’ČÅż^®`påŌ¤¤ŖžU“@³ŲōŽ0w!_Ųiņ£ \7 2óMøŚ˜Ÿ6ŠXM\ø(\"d³[—½:‹\'~Rŗ}Q" u5;ŌĶŃJŅSéd40…¤Ø*æÕF“>ü¶©&vF§m¤ė8++VΦT®ŁŚ@thŒF>}A!Ʌõ* ’bÉÖp’ P4.póZ§ZšŌ„¢[½2 <‹°É>µņĘ”›Ł¾IīąÄd!*ŻC“4ö©J˜`ÄȖ5Or4¤Ŗøc•h#ŖØŅ©Ø¬«»²(8x[Ōņ£«•#,kK0H#FIɎ¼±y„5Æ$LT½m©!cļƤ;ZoĪŽ7ˆ©ž×«ĆvQŅIˆū&I=Y¶IsY’mŪ…R L¶ ( WČuh+nho Bš›Łƒƒ€Ē{ĖįY™ńW$Zšü” s¶'•,į[‹ Ō-Å£Ž#dŹ]ĮŻj2zXŹIģö~Éį)žMÉg$ċnītœGœ£J§ ˆ*š ‹)Åö$šąo5ĒÄ<ārD,߀ur*ŃĖ{6£Š‰ļ`Ą“'_…Ą¤'ē¬ ÆL†œŹw`Āxvfn'€ģ!ŽŹJŌ„„½©¬Žéšč~Lx|są<ņWép@63GqF—;"˜ sĘ[X >7Kˆkk[ęDQšnO®AĶÜq©Ų€bŠPJb5gę£ńƄ«hf>æß2eńčĖ÷OA)·7ńóTż”ė+CĄŻˆ!&TōŠ•&6Ą=ÖĪ„2nŠj !+˜ŪE™nāĶP„»ß fÖce`ĮWg×ˊ°·lÄgļϳŗÄ¾i:&WšG¾*”®¹ā®°QŽMT« z£xŸŲĪEóh÷2!OĄFn3²ŗģĆ8¶[•#*å#Ż:CŻžÓŪĻ@v›}ĢōøŌ ß_yR¹ÄW1ź_©ō™0)ŲY 6~|=ö‰a¹24\#)ē bŽY5J‘(ī™›·®ĆĘå\EZŒ 3‡@iÖžūĀ·]µSGŅW|h3ŻĢ²DģŁ„lĄšÜ]/æ#MȔPV ~w‚6¤ ßåC{Ķ?FĻ› ;cēĖW±EŖĄĶźļGĆč³ÜčŅ€?ń˜ļŗn z6&Ŗėiņī5EĒ `©cüēĪk‘<`mÆ4±`ĖY®[ ¶Øv±GķāÄLüė”MJ,Äh RœU±³ätĄ}80Īƒ×ˆÕ‰^żĪąŌsŽ+¾ÖĻFJrĮ\.;{ö”Į)`B\aS>VĀ-ŖŃųó“Zī±_’صė) ĄfŚņ?@’ēIf&Å]Z–Bŗqƒ.—L<^ĀĒķOņN’cÉŸzœ¹U @0!gś†…euÕpķGżŅ“‰E¾ŗjS,Ÿ‰VĶW=®Ģœ{ėÖ6‹ßØ-5„U•kX좋›vŹĘŒ“aū…¹Ŗ*Bėńī›ųh¬H+¾³K&<xõ¤šXÉ%+XFMFå4®†åĘ„S¤HÆ|»3ą³ŹµÕŅoĀĆ,pėM,xeŖĢ«D%(ļÓf<>øÓ×I2“Õanž §Ž×š/&€ĄÉęm.=7åć Č­qt ?ģ€Ī\d›æ¶˜€¹+ņ“Ļ\5ž“ؾ2v'`„y6Né”O!½ŹÜ` ?BbtXéžęļ›”<åŌ›˜yĖ=š.xRūłn^* 'æ„ńlŒ!Å«®(mø“ŽŪ„* ę–³ßOÆ* Óy6TULKŅ„Ŗ%æ¶Éo¹ÓU3cb¦(w"‡XäŒč‡ó”K{īĒī L± @yœ"S3(Øź³ įÉćX‚š§ócĄåh’((‘ĢüŠŁ” p‡&K¹×ß8gNDåVш*URP'žsµ¾Ér0vąÄøŲŸy«ć ģ'B"’ļo2݇÷"Ņc²zą^V¶;ŖĖ w]ś3¬1ņFąēd¹s!µ`äjämÅ>ųB\ ÆĀUŲ;æŠė &x¬"õt@_“õ¶®ż=”±fHÓü9ĮĖscżē‹ŻŖÄ‰]K–„ŃRnwÓ©e'<,V$’š€”­°āØ{ć?Ųlę©U…µW„?J%ŖĘM_é&Ƈč ŃI‹‚{˜‰ÄÅ&Dxß`ņNˆ Ɣ,Æź āIĢ&d‘¹^±Z”!±wƉŗV1‰x“¢€ŠÕs!+””5ōųT‰šy>„‚ÖģŃu†ą>ŚC= _Œ`Å nŃöÅ«3¼jŚu“Õ§ŲBb”—oŠsł£B°-ąVIŪŽŅ{]2ŠT6“Ŗ|½f ’.Üœ’Ńcā<üi¾„į9ē”žAÉ >?”čŚé©ŸÓ”Y,Œ°ŁźUŪŲåNÓjæ]Hœ‚1x¾Ć:²ŽŹl“;&ņ?®× TŪÅ[ŸĀĻ a&ޤ€3®ćĶ)ĖóĒĆĮłŹ«śµ8³×ī¶8—޼g?l>ŚÕ'‚†N†ŠüŌ®Dō4ĆaF€1Ē¢˜A Ā;[N"£'H€ļē`ß1/Ķ Ÿ{ T_æ»qüömėwÕ±Hœ©fųģ¼Ü|>u‹f¬†ŻtŌ‚5dS’B ›ę3ʍf¬ É1ō™žGw+øOó ’ł>‡y5 Ę=ćü{08ėXk‘ cģåb,ĆŻŚ‘źÆ…±FėAnRüŹśĄsbĀ€÷52ržTӑæĄĘ-ś)+ÅO…oĀėMĮå"3’ł‘Ą”tźø‚°v ¹2LHZēäWRGü¬„]ļė G<€ü¢Æ­®­£j2KÄ ŗ8dę)é¤įT.}x1ÉÆ¹2ķōhµ±W_°'ߘšėæ×¼ˆBPNøg“ƹoÉ^‹qUøTīēr ŪLZ?gضbn;dy7ÆV®,eMłĀķĖĪŲ”ģEć26ϊõģŠ—/Cǰ¹Šč÷‹k CށØTv6æÅKčŃē?–~Ą)4'gīCwū”²ė÷•B|ėn ”…;¤e~o¢~AØmW}šÉöֆ§+_$WņfĘĶz=Å .NńÅ¢s£ĘĘ1½&żo]ÜGŒH®r±Yėč1WĘQ oö ™C#×óły‰Ū‘0‚ģęļ™$Ć>01¹K~½^±ŽU™jŲ]Q¹ļĀPS;j$’ĻžŅ÷ĢE:™s¢WøšIÓŪ©·šGĮöю£«Šķ±re’‡³•ćoŒšooĢu?³ˆy¬Ę˜‚1¢ł;ym R,šÕˆµį3ŲjŽū¾]]¬ˆŖE4įžELń[ƒ©‚Ö⭘˜ ģ×z;„}ø×5¦>¾ųŖ|Ļ =ę!-‹CjÉ@®&‘K„Ćŗ_ßÉÄmūŲĶ>!,o_ZÕ’ÉŹ^YßļĻ6®7¶£87jŌ¹²›Æ¢YhŒĮßdĄś½ŗ*Å=·øń"•D’ńć{øĮ¶>U֖܋;§®ÜņŖ#äjʉČüBļ”łTÆŠ‰}Ćå×d‡ŖP³`CŽŚ‰]¹ …Ą×ó «ähó"vģ¤-^ÄŻ8Ų{wfŻĆ„ģ£DāĮRū^IŪc¹ütbÖn«O’Kœhęż#Åßf /3—Ē!RW‘˜\õ÷óaČuŌՇpiŗä3ņڃĢ;‚ų62@’Gž(ŗ5y˜Tk ń|dÕ°ÕÕdīƒĢń%’N:­•Ś$ŻL$5ņ,qSŽ„"ĖŹC×sŠŁHŅŻ–$”՟ĄCešhgõF8Š}Å$¾ėÕ¤Š/äGPē`6š¹\śŅĢį¬ÕŅ_UóĀ”G¶hŽČį'cZ—ŸäC9épS”²źóa¾ 88’nr‘ä\YwV_#baŚł¦Ū}!„ŗ5Ä2+:…½š„\yÕgäPŪxœ0 •āx¼ sóv cz}Ŗ&_” ›$›ƒŪ10ē\=PO6^p6鼎FyPՄƒŚÕįø11·j!øYV¬Ėö+•ļ§]g   F+…v–𑺼*åŁŹ%‹ĢŗS­Č‹“• Kkų!½źõŠ•×끬4‘ģ×JZį÷-Ų½­·ÄW(2ŪŌbxÓ8õć(2ʇ©ŚÄF, gIŽĆŃŹĀĶ'bēFĘÆćÕ‹īŹ‘‰tZ*ķ,oķWŠeLPɆ‘ą5š×›j„;ŻŽ5"äģ zčuDÕąū˜[ņdxG9–a3 "Rgł„•CÉW,æ/į³ø‚^“Q/`YŽmf9ņÄWņźuq3_€€ųžŲU$eų•Oä{¶ÓŖąEfˆ ™3 \(T±ś©ÖW„¶Ųo‘$ėöŒ>¹»¾ FŅz|¹6öæN)éCäŪ³ŃtčgY¼Ģ¦*Rõ,Č¢Æ›ÉĮeŲØN§rkc¬Õ3Ü P f0Ł“¹ńÄš  ;0‚ÖĀ“nī}łČöeh““=n”O¬ā‚Ćr1_‰č×ŅčųCMgØõļ(år!¼£ńÜbłD±‚ˆDÓ°ŗE|¶2Āj„C(EĒ#±?Łqd“Žtp ޾Ŗ(lsļPTÓÜcŽ€»V~Ō‰–õ…z\\M„v%“Ć–ē:5XĀRTŌrPÉčØēeōÓŁÕŲĄŠ1eUŽ·t0ņ”ÆćfAÕä:pĖ–q¹Ŗ3 —jņNtšcįRE$“¤G€¢{•®ÉE/ˁéČXŅžŌ…|9Ēͱ£‘ŻÖaøŽ¶Ģ¢ō’/wÆ Z3(½\4;„\š|śĖtHhy–ß©ļ `ī\žī×}ƒš‡½ī²ŚĘ!’ ”ģōhĀÕ8Y ˜łĢO4c½³ŠĢPĢpnöhÜĪXšHŚu”īS@}J)ę¦'ńīAŲ°×e2K •±]Ś+ϳOĢ»¹}äŻä¬(‡³bGJ&`Q…°nŠŗ¦Œp‹©ŠĻ·]4ŽĀ īb[ŲĢ7ac`ĶKz”Ų?1-:”œŲTm(ƒ‰ Φ §†e p½7…ų÷ŁM5&+jwŲ"7įĪCÆ…¬[4Ų¼Ę$‡ƒnź#0ČØ “œŅÆn•uŲ“‘ł·.²ƒ°ŹÉˆ˜AÖz17ȱ‘ˆČbÅS’Ų±NČaÉ\,D½!8<0^Z\®ėźX]¤ĮduóĄ"wŃnsp?SׂęxœyOSä­&;ä­ßņ;5!iǁVC„ZM¬ōūŚėY Ā]Ó(±|¦±`Ü͇zŠRĄ=Ą€˜-O5‡ˆóāC)%7s[™hS›ėŸ® ū=ŅĪw`ąJ#f ؈ŒµIØ-øS#µE8ŸoZę>ÖA}…i.tåEŃF•×&CÄ}^t'l5Ŗ(•1ØX~7ÉąaŸŗ!*·öžq¬ƒäŪMˆ1D ½9 eĘ÷a =r e2ŸÄ“}£õ‹½ ¹«|{‹Y5GÕgl>Ļ: ^‡uLÕaüp˜3‡óÓĒŲræs>eT;¼Kļ2¬xˆ—,-Ó6v“0ņy9ĆĻ׍¾n')į³xē}ˆZRt* $—č=ٵćpR˜‹Wޤzt Vf–q! ķ҉+čĢzH{é²¹ąbĮ.¾vžģö…t”<Ž©;  Ć©[Ŗ ‘qLY¾|"īyƌī.ŠĻ€™7!])ŹŲš7=ư±ž?+ŠpR>w":‡“”öl³ŽÅy?µ@¶Šf6QÆ­¦;^-Łƒubчų™é/§ØŻĄXnŗ.õœ®IV·,Ö`¬}™/@"“Ø9’|“ą³^_Č=źg} PV¶ŗ» ‰i1ś©s]ł±VłØóŽé]–M…’N^Y8™'Łć‹ ^,CÉ'‰™‘žhe:ā•¢”lĘSZ2å‰I§kF!^,"lĖ{XŒƒ ŅIšøŸ¼ćó®:„G“L€\䉏Ŗj4Ū‡ĖŚ±q‘³öÕŃ.Łk¼YķXšÄø{‹•-֩œ[wiņ÷,vÜÖŌÄUd½¬YC0tū”pj|+sŚ 'xW0ÆjØpk­ĶævRur×_h %ž¾qŪˆhžØė@],a)śū'ß¾°ÄāÜA^\(öXĮйø×t«ÄkĮ‚ą¬N”ŒMÕėXā jÖ”5ń)3pĒ ‚UĢ“UPœÕ„ÜĻn!=ʌŖīA ­®HĄAīKē—"=łėõU.)ĖÓĢg¹¼3苪ā%šütŠ'ĢłVęZØXŹq>īĆÅjŖ X½|4EŅ)īÜ"X–¢›s¬ßnÖā,U8œ¢Ö@”ūQB“”œįY†l Tįōtpµ • Æ_P0¹*1,_‘·TåĆĪC«ź0ÉĀz: {ł(„©^y‰Šd{ŽéŪ+įĘՎ÷ģ æ‡‰cSµƒ¶„ (ZNbŸ9 &”T±‡®÷T~Ś©)89H‡įŃ­p^ŪW)™\·ö`]Y$åדlkéVłipˆsĒyŪĻ»Q=œ¾Š IÄ ;1 "NśŽĶŖ‰‡btņé:“sV.o9¼,‚Ś©y”e’ø8ńQF•3A”²/RźApē}āÜKE‘÷ćvO¢Į³1‚Iœ Éī¼_ßzÆĒ‚ Ōµ°Z`M%VLōм0æ~ū8 źŻÖ‰"^(ōłÜĢ+sōmAum,©Ćkr¼ī܁ĀcĮ„}kä “Łlģw’˜Gė#Ą–ŌLGK¬€ŗ&+‹3)ŗ÷IMߎaŝb©~Ą†”™u€¶ĄYē•"€]ŁŖkHwf᢫ŠO€¾g5Ø"“Ós½K°xi_0HūPž{ ŁQ&zV«]Õ'›ŌŠ7ōÕ¾a²r§ßĒ}MB%Żöžüˆ½ÅŹ|j·Šę¼[T“›T ƒä*,÷aEØ£FŃŁĄ’/ė@žLVaµņ>eé`§,ĀņŲļr>OJQ 6¢ŸBłj81SB.D*`R%‡AA%šEžtń‹łĄtŲ`±G‰:µIšēĀBéBł:[+j³ˆļTŽ‹ šŠ„(BÕ^'æšTåī³>öI7wMzÄZ[ˆqf m ŸlŹ)WĪńłvA2k“ż?uÉ»]+]ŲeĪ#{~·Č aO_ u īŲÄĢ6įÄ[żAuØä^Y›U°ė[©ļūĄ—˜YÕ“CßĒŠŌ ) ¹.ø’|z¤]­'H#r(0żŃŪf‰ aį3×śØ©Ėlsbi5Ž(©Ę©“3©ŹĀÓŅKhĘwĪØugG“®b żµ°†žR øJ†R›LÅģlą¤6™R@!Š©Ōt!ßAåäĄ Ŗ(: ŖĄrŚ„?%fŪ+χųXųbĻIā©Y"nÉé²ĘŠ@\$»Ź U¼%­}gʓŅ2'ļ93D™ģŁĀd³c„¤:éNu`°ĄµO|ia›ø0ÕįāE@™ZŪd>ĢéhŲ2³©-'蕘XŹėo)QĀH$*ķėC+txSVø†@1eßkX&ń!Xbź»-ˆIē+ ĄācüXGŗ>Ąæˆ¶ˆ0£Ó ®,»"ˆĪu“[ZŖ4Ó@vō¬TN¢B©ś½}’Å)43^ļ•+äŹ^Čd!9°EŠk Ēs¬`īĻ.į™iwųó÷—ŗÜŌWĮo”ˆ¹lÓ8qśŅÆæ/’ĻU®ā“l“«Ø§÷A°@m’k­‰JMš’ yk#LϟY,@’ĪXŁ'ÄČ«¦|WԢ߯ō8Ł„M'É!gnicÅuŻhÄų`ĆłčāF͐Q¼öūXäŸ:ŃłŚ=ÕxņQ?öŲ+śr‹;,&>‰;!޳F6L37ŅgFžż¶õ/^€‹ōĆ{V.£‡œłŽŪtč4²ųI}›m®=f–ē~7–.ō‹% Q»ƒ4ĒD”»‹­&ŽĆ7ރI-ßžü „aü šæß›ƒŽ³VćbAȉĆ=ƒ]X«f»rT–gņÉh±V•0D2Zć²R*‡ßølĄyģOõä÷[ĮEq_ 'nņŖ–­„‚£/7Ū•‚QņÅb¶ē;„žffŗ IįŃqšŲ°ērńGÅfÕ£‡å6ŽÖzŅQ?vĖr8žźoķ4ЇM•Ķõ1aµę…½Ōu.ŠH:~Eųœ\½£ń5›Ąų¦ t u"ÉšfÅĒׇį Hņėż"ˆŁ Œ}ØhxĄ„oČ@6Ÿ78pÆBqTų××½©Héą1ˆ~Ōßu6 3Ża?ä © ämU½ØW…\W&D„5…åŠ×}C,zödėC9žŗŠBąYT‚‘®8ł,Ģōs< ĢŁPN÷׏?³ó4š¦ĶŁIJŽBqtą“)X½%>YWŽ^·©Xrą`•łČKv.OÄĆģˉāŸœ¾T4ģŠžė ‚ņ`?R@) /:·w9pĄ™ę{æßDCYm}*‘«†/Ą„Cģ'å÷š¾hĆæ³ąJ»ē÷¼Cš&qĘwTVxQu%Ļ2ŅM£üzāOńBėIyVź šĮŃķ ‹ÆÉœŃ#Ž×^½©·Lī+‘ŌÅī"%ēķ"xROGa­4ĢWų„ų:ŌqY}UR²x7-ļ‹ˆ_ūҶ¢4(ń;c-UÖÖSdć℆Ņū÷„ FĀJŠßYOŻžV9•Ļ…ō®,½½nƒ7åĻ–ŲŌųwŅOMœAiY%FUcŠm€ō_` śc³\ńKg}šHĮ«ĘõcÜĪCńĪdźµ®ŚTę¦ę"1šĖf¹{¦¼$%ršß!&i œT:ĄįÕżųÅj­oÉGś±i~cUJ‰`Ę;}”DŲ‚©GŅVŽĆ–g–’lŠW?ƈhY^¼C±\ė„ē{r$”j(į;«µKØLšŗÄ,p@··@?¬ÕI㣶Ārłų—:†Ŗą#›Å&ĘųW÷½‚IīcĄ3y£Ģ~čī7Żr¾–Ķg[ĮQę¾øĘOóņ ±»lęßį„ ŹŖ¼ČfuwXTĒ68åč%#×Čž½É·T4Ź@˜ōŖ ūäbnŗ¾w u ½å—J·æKŽł&ĻåÉÜ?Œé)]Yč$G7^[“,Åüōi`OVS“³Ē;ŽYau-+OŲJüįŖĪĒĀʜ-1šōžŃ’x8pÓ»@>“f]šD>9SŽÉNöµ²ˆÉŲV…łõ ųe_~' Z%-ŻŸĄ„ŋʸ“²0|#t…OqŻĪdgƒ®ė»ćŽc6W ųO H€u/Äńų EĆiäß^·ń¦ł¤;8Ÿķ…ń™Š$<¬5+×¼Žā^k7ß% Ų3żAPHõ¼Ūžńņżæ4„^į8ąt€Sš¶õ=g}slO–Š&N-Ą:yjžģTęT"3żf!æģĢń­^Ź®Į4½2˜rŚ,±l§f0Įqó™Ńļę—*Y¬”4®Ė!üŅvmDuOōŁ.anUž,+lŻ7‚tąĄX{ŻČ›¦‡(:5pM8=Lņ¼”Ćr „³ˆēµÓ oY‡Šp\» ī dĶu*ųįP©Šķ"dmW/?ģZ-±ŠæHöńĪø}j˜ć~;Ē›${̓ÅĻėpȾµóA13m?<ĢIÅ~½ųå§ż n ¦ž¤¼Ó½4˜“ī”ŚśŠ8ß;ŒQÅäWś–Įać^<¶łéż³ƒRہ§©ŌHO{£4öa¢%œC:4적ļ ĢĀ«šÅŖ'*2sØ:rĀ“dĖqžŸźķ©O¢žäŒ*Ś9Ĥ"ƒń‡7É`“āŗyH>ĘšōČfęņ}ŪOõā\¦ˆ}’ć÷õLRµ«Ōė§“ųk»|abµ¾ū«VŅļŹoI¢Œ>:#ÜÜé(×ö¬=Ļ^źBēzėÆ#6/_Ļ~Md9’¹÷Y³8’‰c,™c׏‰€æhćM•: lH÷ŗ7éó1:¼Vdņ–ņŽźóĖ‘kóöŗi¾SŒÓąųü BY6%žåĮœ!G @ĄBdyÄQ"°Gvݰ +K™eæ ¢w ˜béķEwńµ±Ą±DŽ;¤%vväPŠj»˜” `BQŻ“eĮ„»Š9<źµ1.óÉd@[p–1jZµŖĪ£D ū bņ Füŗ0JT±˜x…Nø{5KŗRsĆØO­*§®ä}1!Kkäš²ęEЉZUż„äĀ2pĄ6Šć,øĆkQ<ŖŲ„Œę”ćQ3ń“„©”ĀÖ"’š¬0kµ¦x˜ō\¦~Ļ8SØÓrŪÅŲ„“KßżĢl Kį 7’ĖŠ4?Ø µ<h7„dłBF«J÷“³vVµ;š¶°„%KÕø |$+ĪT‹*ƒ’Ģ–Zµ6Sd…²õd±īÖ¦ž՛!¹pŻ T6a“ƛ³EĮsp…½Q¼ČNBš:DĀfź~D,M8hś%ķNåĮ9V"D ŽĶ*ß­‡)3’Fńķ6Ēeƒx·œßx£·Y7”x²¢·¢Łµ09ʶL<°źŠrż[–’) ÉyR¹ ‘mW‘¼(Å®§ŚESŗ€S’hŲU6ć±0Čéé®1„ »hŃn`ߍZ …Xū¬XD¶Ŗa”š‚ÄļmŠcŽ* ą@l“¤£«žz³=°X/ĒgR"ń"MH³m*“­ū¢{;8>õdPՀö`»y‘#¬B1¬ėb®›f«Õ“dR‘©U‚ūŲ¢ĆˈHņˆŗX¤@¾ikeÕ尀ųŽ83C¾ 71Ē-Ųu07ݹé*…ēVq…’ķr͟Y؝1ņVŲ`żšt,;¦ĢO]×+rfūAU;w,z;¦Ą ŹīWZŌ¶Æ×ą;ĻJņ[³fĆ.±ĮĄ+ÓĪjQT˜øˆ·­’GnzŲbŽ~¹_ūĶ•ü',Ķqҽ’ŃIRÅŗ›#i-„܈Y(_Ū娀lšfeĶ×m… ?{–ŒŃ9øāB8€3’"“5@6Ūü;=ž. TV˜»fggR˜ŗPdĻ[ž›ÆŻ„ī—‰æÜR$ó;ؔg%ŽÕ¬å˜•“ņŻ’ķwšž]X@؇s0#­ńE·~Ŗæ8Ā,6k”Zģ/ČP Ł+BUŽ›HĢ/9š0±*SŌĮP …•MD6¤©ŒLsŒU5oč÷Q S—lļŗ­L|P¼xłŁSŠŻ~”ŖW{eģĘM>Œ±ļ·×mą“-—³pŸu;ńŽ)V\¦GҘehö&NųØ'j§„Š ūXŌŅŽ_ŖŹoēy£iä’Ś³§K½@7œī•dā­źŹ'NQŹG( ‹¼åLȋ 76p7 n‹,éżKöæ{(ž£ÓĮ ō3(OŠ‘ e›ē!¹§)8J4 vhr‹T]‹Ėæ}ĄŗœćŒš¦HTŠ3õį#|ž(ķ‹Zje‹“ņ¼Cˆ [ĆŪąF3ńBm‰²:Šd—IĖ=t:ÆO„į>V@–µ}‡T ]˽Ł{ ąā öäyXm"īšŪ©…&žT¾h‹5Qw“ŹT^ĘL³UŗØŃ %éŚĆƒÜĪĪ€õʧćŌ ļĖˆǧœÓ"ōŅæDĀkā3Į}'6Š7魑Ié{‚qN꣛”hUI‡MŽ’^³§Š×¼©Ÿ\`,y©x¹÷N.F–UķõaļwRĘ{ĄœĢÓ“$L(&zTģ}m–ļkRśėĘq\E®Ž[3Čāód•|zńŗsˆ®_ėÄß'ė5ŗŻY«©ČqS|ķŽTwępUUF܋ć¬ņÜįeĀ“ōI˜ż&fR“r¦’|RžėDqUŗ×‰ĢčrÅū±OŻĢƒxŌ•Ŗ Ó^멱ų¾ž(~m öĮŲCē÷ńń K”xraķ ^6rZ’Ō [?»īLt`PŒ /°¾O![å³}óŖÓэ¬|ŠĖ¼CĢź‡ćć²\2¹Ć: šP4 kōX|mö|6kRŹ„ęF¶&šÆZ 1ͧ4Œāčҽ]ó/_öS½ų8Źģ ( h\Ø+†6 ½ ×Q¹ ŃæłŠÆSś'XF,„÷Ė;Ģ8ҬŌ[ć3ęØ$PŽ&󌸧5ß^7Ķw.qźÕ[ćŚWžķQB4¦7\rŚ”Čn6²ŲŌ(łóWMgćų’śzŖD6ōA!2<-ęRĀŃwĘ=«Õ…Ų©gö?h9śeā Õpm‘ÉX:Ž„AŲō‡čķ ¹X0»Ó@ü¦ N3ØōYń$xWńė9cIÖMˆ,;„éÄŚ$¦“×g$ژ”ævĢģ­²Õ*Ųżļē6S×ÉjcŅ(Ó]{@qq†Ņ-Cxē¦L|7Ō&„bū¹02KG¢l€_0¢rsÕ2gžeŠDŲ ްGø`GĄ5L ™ÆYMĻ“€8ōŃZ&Ō«‚ŃÖ/}“*¾³żõõ\°ķ?CŪha\ŹTa%ńĘujdÖ!Ą‘ąŹ“˜«õhŅ(/%ēÄ¢ŖD‚ŖÉØžlKŃĶ~앺Ī2ˆ}zśĶ«N56įšb"WĖ‡&õjģVŪĒč ó©33ˆ Īķµ!2÷M’!†²±…§ęBb)ńō’ŅžEń“0SļĖ‹Šü¤ā1ō!ĆŽÆĢ腓öžDtŗ®¢`Ó±‡¾ö€Ų¤YšT 7°IĖ„X¹Mœ˜¢Ļ²ĮQtVę4¾h—/<<†č,0TĀHz ehCYÅĪk>yNeŠg¢¼|z6fŁ%®¼D>{ˆ-ĀbŪu!<} †Z!†3 z£Õחgó¾°UKsyńį‡tVƀ'2.Fwll+¦|†Ć%žŻ˜± =!¬°vńéζó­š[Āŗ¼ģĮ_-p¼šŠs{$œ< v€N¹x;ŚązęV£Txl»“~ŸkÅ 9²F¹FM¦ k¤£-GØ7‡® K°’„Š®jśrt»Ļ$zån-zQ)öی^5Õ—Ę”ōŗ¢ƒūĘCä¤/qĀ–ēĄ°Z-~^Ķ9Y!6jb曊ˆBXŒ°6F„¬ų~+ŒŚ¼ҳƒBčęĪųU1¬īŠ%£vŻo_•4]mśćå*śĖVŸ•'NnLwBĒen©ˆ ĒbdY¹Š¹‰W•<+źļüY³ĘĻÕ#ā€NćÓ1 š†ā•ƒń‘)ųF£Ł†³!ŅrJ‘„cÕ2źĘ ”ļŽŸčĄœqiņjĢ“#ó·ĢĪn¶źyžŃ–ū³‘ÅćāeR0! ¤.÷Nœ1Ģ!”8©‰Wꆰņ”q®–—ćżĻ“›AńTbÜmK„ŗ!ō‚µ.½÷›Ž{"Dˆkģńv.ŹyOĪ8ņ ±pŸZ®·Ä”®na“_ś!Ź‚J?ģęl IüŚŹj,‰/Cš—Ü°)MXž¾7}č†ńq:|¼ Q<ˆyŒń¦‰n®Ļ”G.~Œt¬ŗ„ƒĢ`• G®Ē¢3¶9¾pœßó(N–Āż4š‡?Ž;ćßA‚²™p.†žfÄD+”ŗa(ĻΉóېy>› [x ;žķń쐼 ‡żIģ«”Õ@é]āP&\8…U²}õ;Ņ0š•ļŒ¬­d4NųżŌā„÷"ś::VLÕļż:tYPÄ`½»Ÿ•ÆOµaŠ:æ}nīžy¾ēõ»[ź<– g „½4ątÅ!œeń3G:£æššG8Óµ‰RfŠō`¬Zü~:õ–­gœ”QĶō%ü¦}pöÜcŹĻŚóćśū~ö„ za+§¤ęOėo_ ؃„l`j„x-x|ÖYÕĪfcBć{_<Āw意žœģ!¬Ļd¹AčUHēś…¶ygćr ÓR¦©Ē˜„ ‡¶E›¼Ę¬ˆ}°į¼t”[8P?'d~Ž„¬ŖßļɳǛ…°sf[˜J‰˜G#Õļ1€PsgÅ„ó¤°óVj­` OĆbą°ŗĆŁ„ĘXÄŁö2˜öÄ79aZ4`ŽiŽ5{*{Śfµ„¶9ĶĪļtxąų}ģµų€VŁ€Ó0Å»,Zż·xv×Ģ›}QŗŽ#0”Åi‰c»}y×£A­”Æ«(]x6Ł8zeĢ„.Ņ8 !b'ØkTyldćLŲC>Z­śrżõ۷ϾlõŪ¼čķĖļśv 8“9?ĪąV8φšØ,žĻŃĄ ¼0 «7Zrj¬¼žø/fģÕŌ~Yøb>­®æūķŪ•ųjÉ~³ŗ-ķ—ē&­Žē¬äŠ/—p”0żS _¦•ųZc 8ü.ėFĶūļĢHĒ‘ ³å•ųļ 04W#= oQvé0ÖŠ(”9xü«ņ cĘȆĖVC6³Ū/ÜĮųķ ¤0n$8“Ż5ēąsŽ@Y1öĖSC+Ģ–’=ƗÓŗŚ„ŻŅwśåŪūé¾½//÷õ©ķXŁĆŽ­R÷„%gMzżœxjŒ—·‘h¶yhģé¦ĘUŽ= i8ģ#Ļ.~žŗ4J0o™ŠŻųž*P-Åē§€xċ7T6@¦ĖŖ · “”róŪ¬ų½×qÅļ5œģÜĶB~–M .F¾/Į½ĀłēšLAŁi ó¶uÕ¢42( GĘ*rN™³+éŠģ‘—nkxÉķOĘļ~ —9xl:øw A›»hĆ*č±Ų~į’)0 #ļŠuå„oŲE¶£3ęŪ•cŽq)܌„GP“šag”Ę{öcFę_¼9JEo=k ×\-3^ę©«čėn.…:Æ[zĮų¦Y9K碷),ņiõŸ0ĘźhA Ÿ»ŚÄ¢ tęÄ%»õS•бŹ5gBWŗcż×™ćUåŲ Cżz<Ś8z.œ9hø<ę: •_0F¤ė¬ ·ŠW ¹Qk “†5ÅKĪy}ńós”ģ=„N\Āēó@ÄON¾’™ŚEæ’Ūc!Äłź£¦ń€-§LŅÅć™{:¦ā’±2‡•ę\“JžŽs½]YT<?ņĒVä*ė;Ŗ1F§Z‰l5„ķéĄÄ2ūābł»æĢ5ēųBsvnU:#6—²¦TY£›&*t®™­+å²åRŽĮMnéu®Ņ ¦ė$ĒüĆŹĪŅWFåĮūé~żĖŸžÆˆŅ®æ8Jk©O£^śŹ3¶–ö!£ā·bć,ė¦Ņ¼}häńÕȟŃ'ÓZ|š„kMŸ¶"¦g¢Ü;U>żeqڹWŽœ°åįe”Ć ha.Ž4FlĆtĀ?čB‡uį£gøŚćāp»ؓ=a Ø·Z¼Óeq‹»¬€‹Ÿū0‡x™joB³¢MĖtŗ¾„ZuČļÅf.1¶†dm²&lš89¾·G\Xm»ŠõˆhĄy”m9;pöŒ!°ÓoACõńųćC&ܑ²śˆ„4„ž•eiī‘Rā²e6]Glł”#ŽæĢŅrŽ×Ÿķ—¢ärBµ›9&,įQpaEÄ8ÄĆ ®CĶN•½2B¹š79 |Ģø‰Č½L]{ņg#>öa™øŠJ£ĪƒŁĄ&,Ł„#ā$.ō“ŠG6ˆhąF@T˜†e˜.vCŃeyśqņȵ&„µŗ~jp" q1ölńÅb¤māŃpNŗNCĒķIøÆ“¹tų~ÆÄˆgh9VŒU\箽-spś x’‹}\L‡„ sŲ6oaėŅ #ÉYKHŻ" a,kGŻŽ”Č&‹s üŽ5 6ąE,+‘ ŸÉ5C9‚dÆ*nNŗÉ¤‡Ó ÓCć0Š"č‡Ęt3ŻŹ0Ž#ÜEöUŪÕKCIK0 «Ā„Q—īĀZ+– _Ķ!tŅHzdLįŽ½ėŻĪ)¼+,TdM$¤X­ą“YS_ą¾>ēP°ķcĆéfŸ‚© ƉcĶ·ręĄÓt]\`g%Ó8x28jaeŁ·Xfо`x:‡Ć€U|lÄ;ģ  VėĘ)„@vˆŻ[źāضwa8Ž;Įc\!tWCą“³ üØv±£hŎs!†—Ū…ŽžGīŠ92#Ć|Kį³;ö\yń½½×žxUKC x#Nķ¼ŲĄ\w‰óUG¹»’Ł€˜.ör䏇F w ¦b×=ø“‚,;yD,ĪĒø ģ®č‡ž·ĻYL؊-€ ų²Œ…ÜqŲuW< Æv>!lUē«ćÕ7cĻÄp”ē²ā„N\G–±pČ;1„kįˆoY²ˆŌ'qņ0öd“YVė®/ƈÓ|£%P⣁0/±2®ƒ¹°݃BϧóŃv€ŽGHȲƒÕKn]÷VJ@r!“ŻtĀqł¹©ä ±—! š7Ź—±śĘĶ'§ kŖŗ=3֜'łåķ$+—pQšõÄB“wrśµh×ķ×<ö«>®£°}QSŹKæŪĖiVØ=ōĄ U ;aõ؊aŖü‚” 2`,łg…ak{vq:ML;JÅ£PjēĖžŒß{¾† żDoJŌŖ bŇ9Ą¦ ŸCp„PĆBK&Ž ŖeN}*½Š]—&œ øĀWĮ°’·ŠLsķgĶÆm;&q[ńó³ģ–ć_Ęt÷ĻŖwFOčAD|LčŚ\ŽC®‡5Č1;ĒÄῌńJ­F‚_LBŁP®;ėŠ7[<»Cµ3āĪÜŁ[w„ų2+”Ųē’z8…}y…’×ݳ!,§lŹ:›g6Ėc 3M’ŻŖ–µö\Mé‡ēū¶OĮTł²)ßūvß[ż¶õµķæ9"^'/žļ©o“Gß7ĒäĖ#õåįūĶAżņPyüsU|s«¼ŗ~¾¹Ŗ^\k//Ąo.Ė—ėĖ+ų›ėśåÕžšRax©\|£†|£²¼To^(Bß(M5qš…0ٚ įJ¼Ä}8\čÉŪæp_ļĮvĆŪēĀ®ŲŌW\äAøp褮‘‹ć‡r­™öcĪü.‡öüƒ“śå©žźü’ę®ųī^yq}s[}s³½ø__—/o֗wš7÷õ7wū -ąį•rńR y”±š -ī *G³ŒßŌüøŻę fv~ü+ŪÆsśžŪ·ó’r„|³Ŗ^®Ą—kõ›użr|³[¾1G^˜.ß9ßD/Œ§—fÖ·&ŁKóķ„”÷Õ(üĪ€|ei¾2Jæ3`_šŗßšÅ/MčW¶öK³ü« ’±’Ź1š½į…»įµgā„ć„»ć[×ČK7ŹK‡ĖKēLeØ9rŠ3~ē2įŻ‰ūGŲœ·Ą5v’‹yŸM°ØŗĆe\Š 2Īį¼’æ ExĒ|ψó™pL¦{§rō“Ŗ «4xŒCģŠ)įŸŚ%¾`2e ńŠwaõSĢ=q‹s€õ æbž1ƒ_ą4[QÆ ; T9­He±<€Č@öį›1YUÄ’ĻÜ»­Ś¶-ŁB_0’a¾ś²©÷Ėć9 ”)Š "r™Ž`ģ‡ćß„DmcōØsCĪLMīµ2v­·ŽZ½D(TńŌ¬4Ž«įļÄY«,Œ ö³DéҐv") A4 +lO?;—½®¬Žˆ‰Ź¶y$H‘TŌV³]`›<« ĆbhÅū0h.6Æ`&FH‡Ą…u½±eų8›““2£Ļ\Œ1LųŁNÖæI‚ĆoßĮåÓV ×įČ»Tœ–'ŒŠ–Öć—ņﻓ21v3‰:¶õ³Šr“ Ėb5<äO`Ś&JXXć~n\xH…\偔šĒ×ūģQgā >KJ£*/ ±åƍ÷e• ž IFē½į“„Ɩ£W 1hCر­Z&”†o|crFͳÖƒŅ“• jXT×ß«/js5B“_Ā‚¹ĪC3Å/bZ‚o^<Ż)žė™V0±’ŖŸ!Ųt5#ńTŗ÷XO«=C2ŚÉĖvK×V! &U#łõئ‰ØÜLÖY(D7ģD»ĻÄÕÆj±xööćW÷;hP=Š pĪņ ×Ӆ‚©…ķ“ÅH½©m|±5¬gŽ;å g©‡f *šĖ†š ®Ņ0ų”“÷ <†ø|Rf˜^ƐTĄŖä+0#^ɘö¦—jĀņ%ā®–æ­ó÷k)čR’n$ĀRR1–šqŠ’ŽÉ¬Xķ¢r¦0šs"ÕJ²@¬6;łš‡ «īŖŪ"’.0‘s³S¾ĻLkNÆyTBQP·?WE†ōŽŖćÅ3ö±%˵ó470†v÷ó&˜嬒pÆå (Žlžéa cHÉĢ§eįö÷‚ó!ZW4+<ŁNc@„‹”tē±ĖwŌ×½sĪg\|zó3 ŅŽņ9įd€ģÓ¼$5\ģxó"qJ,O›=‚ģÄ'ń‚eV’IõÖϚ›¤”ŗ—Ų(×héż>\É\Ī–½Ķ5Ō‚VmŃ»µå%+Œ?Įa—žÅHōä6dPśĶīŲŲ×$ģU¢ ©ŹżŪJ˜•ŚmÆ@Šm­"ØÓ\ߋÉ&®}Y”BŽĄ6²@~šõc¾Ąā¹Ž¼FĆ„ā… ė“éØ}~æųžt¼0F²œoPųßēpå|c×k‹mPEބܫ õu›±—MÜ©ž‘“oŠ5d9‰ĖI‚r&1¾_ö©w3Į pSö l%Š`ķ8‘ėå8ą$ٱa\į>aė[JA<¶‰X3‘½ļ‚"ŠR,—‘z~ī±SYfK$zā#œØ$ź§ŚK¬Óėm’Kj¾-AP $ßĪPļNZį?ŁļÕ ‘)3•‘`J™­²łf±#}&_‚ģ5Ō]³a”ćc»@£"C"ĪX^ģņžæ,…•¤öNä˜~ņS Ų½ćūS{Œ,^T«Ū> QĖv0“ ńpł "a(. éŌ°Ē.L˜ÕzhŚ™Ó`« p¼Ę?$įĄiÄólbö#Óhā„˜}d ĻĆX©‚Ē# C¦'sĢü7ć]I¬ģŒŌ»S&÷2¾~¤Üž~ŲĄCā:ø€ä%©³±4øyĀÜÓW¢aŠō–äEÖĻ\ŌgYs €wĶjĘ„Q:³§es^jE(7/Ļn•E”TĪR ķŁęMūD‚|°h¹ƒ2‘>ŁŖ•æōõ7D -kB‡p’ łeõķł•ö$ō^QaAĀv;¦©ģ¼{£ ¢ßž|śDĶ&TĪR“„¢³‘ĖF±|²”]`˜ž¢õaL*0W­m^،A%«Ō,½‡“°-(Ą‚§Ć%é>VJš<ģ͜ƒžU ŽÄeŁYĶ³‹lÕ~»@% _ĀVūĖVi_™¬¦•{`'µKĀ FÉ„ ä“Ϝa‰we•0»Œˆ6ćĒd„Ä*{ūóŖ®o!ųšį5—„ŲHxˆÓŠų7Ž”Ü6hįŚYõaī”\Aą`ĢˆĆ‚Ā£āžŽ/HgYŌ0ś“°ą`v0p–ąbõR»+vĮlNž”•j¤‹µ2¾­ä~™M€ķüŅrąƒŗŠY}`8ŗF|Š“ °ŗ„ō2ķ°¬l{Q·k?K“6C·Šźƒ²Q“{$\[fĄDU$œ !½|1S_īäA[aD±N•YŃĘ ŌD”Ž“C” üMŪĢ"NW‰AUä·«Ūi‘TĆ@fˆœ,xŚŲPĖ™ĪÓ P°ÖQÖ¦Ž8pwĶ]ĘLĻ®WŹć00é8BŚØ¤7Ņ>½«Ī2Nք…ŖöÄ_‡øFüéX}Ö7Ń*‘;÷G 6»€2ųnøś·fKÕ”Ŗßؙd3įŃÖ׆ `}†#ihü}ż ¢ą1æRębҾąłĀ2Nh†·Ŗ%”}|~ø‚rž ė6ķė‚ŒäŪuśėŚŽ†æ>±Ēy`=Ķąca¾Ze¼M¼ƒÓ‚¬8E«Š#†ŚS\«Ļ ²@łõw(—UĀ«2+ŠĶD11\„ŪņlQ¶°­"ßł”Ē ©5<ÅÉ §öĄė]B¬mĻēłébų„ÆÆl„Å+=čØĖ偾nvDēo1ڹ2$p&«²šYˆkķ+4šŅµ}ģ€mŒˆ<Šnkxõ!ŖĶŠgOQd¶ĮŸ®NÆĢé—AƒO¬·AĶ1°9¬cw LdŌ ?–:Ģ¢Ö~Ŗ+8Ōī«es8ˆ˜«Š/…}p—‚IČø$Wķ7Ń^•§2 ¢Į`ų'jō°nX©ņ`¹3(uäTš^Ųm+B`Ā£³ $_>šŃs-h}öC}Ń`kZ,ü 0%; £y%p157³Ÿ€½I4²ķ!͹ C³Žø=oC éņ¶ĢšĄ wųœü ö Ö¤ŸÄΤ* hėb{«ź%L|²ƒ&E<Ŗf&¤T+±‰5ל˰2eōt®HÄm¼\`(0Š A–³Ń¦ģV”–ØŸ5ŗĀ.¹üt­“>–źnĻŚqŸxŚŻ8ą<-d$é”ÄUė’6a©{˜ČĢ×'‹}%5ĒźwjJÕ§¬¼ –Œ|6ńk‰īKGˆ {ÉGŽ}i Ø„§†ž­\~¹ęŠ;°ĀĪ'7¦Ł`³Ldn–NmEńO¶‚&BĄõɁA5³cČ™Ė äōʧ™• żŽÉ¼”°„ü(vnģ©iŠ(ļ$£Õ Ü›‡äćĢ0óyŠ f{¶…((ZƒšŠ±¾®1’`aM’5hUo >ˆXŸĘC!BŁ{ ŸµŸ2 ō Am jP­ēmß—y2djāüŲPˆEŌ¶®æö7DtŅ‚ ɒ՝X äm‚“Ÿ›ø½&3ų®ķ‚āŅ ļl Ÿ FŖū€ n/łäLa¹j™\0ˆŁŲ¶Œéź–‹iŽ4ė{>šŪĮ@¹xėkŪė!&{šœ ¬= KÖ5G6[ŽČ{Ķ…<ųd ›ąŒ6c&*$Įu}̤|yN`Ø:QŅ]čV Ģ2ٚ?riy=ī–†y;öh¹q…ĄæQa[V¾ēĻĄ²Ö‹ūj„ūć@’7o»wŠ••DŁi Ūߋ Q!Ä8‚¤č†Rˆ‹ēÉAö(Ó`<Ø"‘ŽĘī‘£(š(5tBf=Pä8B//h–#2Q( LĆÖ}(šrÄW`3Ż4ԾϔRµČ‚ä@źmķLŌOĖś eø/Žŗ:2#7&jDÅ­Æ©gĢ^,@¶i°;źIžŁ„±€; Å"}5”øśnm„œl'& ˆ·XI` 3įn©R*½ī½1Ūf”T\M,PęS®©É@dös!“%Aƒ÷ęd?Ūī`³nšóõĖ®mZšŁÓÄWõ\\żĒ.` 7­Œ„y€Äˊāõ`…Ų[€P”yɗö`ĒŲ©Ģs3ą2ń÷j€fĻ ā¶*Jŗ¼yKRŻĢĻf¢ā»MĆ f¼…"iśIՁ_”Gø Óś™ł\‰•š5…ry|&6" T_+ĮdGr9ķś.—G–¤lwĄž|6÷3 š­/±N=XģÓĄŻŚĮ’µ^ŅzżÆ<ś±JŒõŁī ›±ž]P`żč ²»•?'ņhßl*恬¾A(V¬Ģ;gFź"V’ցģ˜ųŲ”„±źŠļ/ĢVŽlvO0ĶłŃŪė™+”lLTźß†»Óžš¼*§ŅóŠ(_¶MX¶AĒŹ¼¬iš[¼ Õßuͧ˜˜Iȝču¾H†i;¹j‡ų’)Čś©SL. mŪ­0Ē£dc¦ƒĻmŽH&µ¦ĮŒ3›”­± {kGåż‰±(¶Į©3ČöŽ+¼ I ČC:g Ž£<ˆ™P«Ÿŗė7ž<Œ&ńA;!ćoČ>¢Ō+ I†¹ђʰIv’žäŗ†#’ ²¹›åž'Łz'i#IĶZrÕ#‹ ü¶&,CF!ĻBž‘LJ-ĄŅŌ¼<<ėīÆįcÄZ½ƒ‘-K«ĆN“„n&iŠĘkņYī®āO‚”^žīa»…­ƒ|›­Å|Ģģ Ął1[Ņ`ÄÜy’ĻČ7AD ¤/ 6,»įĒaćåƒaF'pƒbfpénB²»2yYāÉ4ētD¾‹Xu’ÜlŠüƒžp®Š,Ŗhw,–ŖŃ[W¬X'-kć%K ¢Ä+=ʇ“,ąThŸd:‘hln‹µ”Ł>ģ8PšŒ‰I“4߆%øŪ ®õp$‚­Ī¢²īłÉIaą † 5wCšZēG r%W•™ŽĻ2«āGmTĖ&Ėdq/)Ļuh-斘06ŽĖ¢ZaŠ•¢„]?Lń|Xžøk«Šo#Ŗ"a“(™N’–µyx£v(+V&–š ņČA $ļ"SųR‚|UÜ­Č.@ÜA\±ÜŗóņX&;4‚ruA;œ E6ƒźj/>B0æ ĀN“éT'!ģo %h4³ž…F¢Nv»0r°EĻcń³\ŸW'5\]÷v5’ÓKqžŁrø\IO®Ó±Th¾Œ,ö[Ցb«yę¹}‹•ƒ· ĄµÖń¾#> 6 éS;:Ł­ķ¼‡e%/šK.„e•œ¼L‚ŁPUĆōüea«SšNĻĆ»µRt[鬓?°%āØTŚ` üæį׹ŹGčR›`LŽ”čL›pžsw¦œōƒq€j71¢4I%÷Ś„Q jį£Ó°įDE˜Ē‚ķ#Y•1˜w«Šy>pŸČv͊ŒäęŅŁłSd¤až3/ĄŪxRRdd§õ ±ZŸėųM¬Y(“Ґ7¹r±?·Ó2d5øķL§GåVņR3Ś€ŒāŖˆ&¢“S‚łdø3Ó^”°ÜŠ  ‚„µŽŖ Éw īŠ†+Ī‹Wu÷ °lÓ^É­ł/3l¹Ö$˜Ąƒs„'…$Ź,Y)^[d=¬Ø 1}¶ĮŪ'Ī3 ¤"4œIŠh"”EVŌƒ§˜J¢ä©ņƒ-šµņ“‘M ’u»ä0¤’‡čĒ©:w3™ü×É®@Ź-U€æĮ¤ę`VBčĘqČåIÖź„Ņź¢t~g7Šą\ū\`?#įL>Ģ”dl[B˜ ÜåzH˽x<0ĖD Ā(z~EAŠr Ļ%1'0‹zzŪų(KAĀ8JAā5Ģč™,•“'V2$ŠŌ©nA²Š3ėPŌ!Oę5Sx¬M¹ą³Ö£¶õ 6*Å«6ŻÜ¾y—e)²ōGŁ7–fɤ3L•u’e/Zp C VœõĢŲ¶“‚X…(pL‘bÖ`V­ÕP†!¤żĮ?Ź(fķI¢ŃB¢ŽFæ˜ĄS"”³š ģž¶Odé|ĻēYŸEø³¬Ōéģba³.Æ(×¼ˆ7ā•ÓäĪ ]tóHėš––Ž€õ°ąDYiŗĒ›FēDÕ ņœfYÆÅ\Ē—µŗœų5Ū!U<Ąµg‰Ü"^JÖ»/}1”Hś¤³Yxi—ŅõEĀä+5ó>± åĖ«ó,ī¤7ņėš-īxg(ģ7ž¼•ČfŽ@r›ēå § § IИ‹¢łŹÅµ0üB.ą•7r C6bČ\ YŽ!ņĀ y–!#3fo†LϘzį†\Ӑ•XC®kȊ½hß©¶%÷ŹŽ ™¾'ų¾pßYÉsĢvyŃuČ·™Ł1‹;d|ĒÜš <äœGäōĒQŽÆÜųGrīCvž…ɲž/ś”–@Ø;č\• BՃP!ŅRub…†«šC(ü)D„j”ņÄE£ā¢gj_*EP}#PéøźyŚ”JČEQ$T¹č”\4Mż“P)墪)°J-œKØśźĆÄR2ęLØMsѱ 5oBuœ‹’NØŗźóÄR>՟P(Ņ u‡b…¢«šQ |j$]õ”Bķ„w‘¦‹žSØżhD]Ō¤Bå©P£ź¢gj_…*Y”žVؼ•žhtÅŚ^”X¬vQ •ČBͲ‹¾Y؅‰¦]ōÕ"-¶Pµķ¦šŖĮ…ŗqW¹@.T®»ØÜ…Šx”vŽUg/Ōä Ōū.JUĄ@?š¢5źF †µĆX1ŌP Õ#YĘPæń¢õxх $CµÉ‹2eØaź]†Ś˜”ŠęWÅĶ/ž{XW#”ĪXŃó¢žyQ 4E/ś£”ViØjzQ@ÅRCUÕP5Tk u]/°‘^lØ,{S” kCmŪ‹nؙŖėĘB¼‘foØī{^ŁČ‘©]Zōn֊P-t÷-į—Ö8§”ńf-O”Ö›}Ž$o•Ŗµ*s‹Ąz‘Ņ›ŲĮ ž×žżü·”xßi"Ÿ?~C) É'¢J@i Ø/šĢ…RCRāīMDŲ ©=! ($ …䢐†3–.䦀u”L…ōŖˆR¶BrWD»PĘbzYHD»ÖB‚[H…»Šę.»Œ÷B’_H¼PCšaHH¼qšć‘'/Dː’Ņ7Y»5Ŗ§5@8hŠ@Ż5d«F¼Ö 6ęĖ†ĢŚ+ 7dģÜŽ 8ä ‡ģ☈|į,ģę :dM‡üꐉr¶Cv÷… ~a‡üņ‹ņÖ#†ū… ēC†ż…2÷/’Pࢪ „Š”zAØspŃDøč'J U†PĮ!Ōzˆu!B ‰Xmā¢LqQ±ō..Ś7Hp#”ęUGŃ”œt¤;}•Ø~e=ܛ§£'—Ÿ ¹š–iU§¬z7ņV4Ö°mī Õ\,€|/æ`–TX –^žį‚$Ā6¦*ĄF‹½©Tcµ4żźĆ³qón+öO=†§N“Ņž¬xłQĀ%ŃŻXr”öXŽ“Į•¦»?D®ķyk)€\č}„°xÖ9:)†3\}Y(]{ ³&ĻĪŚ×(8Zøƒ„bŗMEڃ¢v–•čæ;½Tƒi“ƹĄ.…ÅÖĪÅĄ ÜDmе¬²dm3جJ½*=õn®×/q¤RŲŽÆ ”3ō“§ptT†ŖŪ“ ģ,óŖl”Æ…½-Yź>  L½±ź"óō ēZ=lē…×uPsžĶ˜Ź-YBVÖ g‚'Ūs£Æ#+lĮēÚē²Ļ³>YØTŗ°~#9ó{g’큦ł£hĘO‘ rķY:éyVį|”FęcŒcdlŸ“ĶŹm„™=®žن0øPØr_«,žŠƒ³¼@»ÖĻ1)Ų0ąU£»£Ą(ń$P0ȜeĒĀŽä[‹dźV •ö ^m}x/÷#ĆŚœ#Ž'šČ:„€‚żƒZŲ gž«ĶžÉ'ŁīŖŠ³`Ȃ÷żŠ±9Ų|%[¼Yv2ūšż¦{i­“$c‚fća•™&ņ¦–agƅ uh³ØŅĒņÆÆN>oł-x\x#½¶¢`āļA’ké V ćł/ĀŽ$ō°T4–sōawļnœŁŸx„×’ƒøÖ¼‚zƒÕ/ †ä6ŗ:iŅ;ēŲM‚ÜōŸˆFŃŅķŸØØK36eģŁ$ßK/ׇ¼ K°Åk‚Fz]€JŪ@™]7čī»-Źgż± B,.ĶŅŗgź&»Įł5ś:pŗß{O·Vѕм”@8ø€&-AÅ*0ŃŹ,Vœ· aÕĖ¢-Y% ‹;äJj®gÄUlą¾4ˆĪT¤iJäĖk­¹ŗ$SQä5_#/ż”cŠnßžaĄķ¹WÉæ^Ķ'=t瀨ĘėŒÄž;»’Q/hZ׊Ü×÷y”ēōƒN<•“ījZļ7p~LQÄN‘ŗØĪ‡¦?i “gČńžė?äĶ- &¶ķ¼Ÿ¦A–&ģeØĀą+8kx4 …mˆr – •Å%„¬†äŽ€lv™ŠŅžĻ©ńˆ$®Ó˜WœÄO»ŁTIäÖ@šœ(ä„aė¦IŲŽÆ`‚£½9w¬A”p«vōĄĶHݾlt"“Ž=C¾Ŗ`ÖL0×k‘ūD‚ZRŚŌ5×t8.£§Z n0¶>? äYF!“Z¦ŚH~į°žX 6r7Å“M@©:U“ģLĪ|}$h‚—Ź#r­>mØVG”TFSJ.¢~,A+,˜ˆ]u-S6„¶CJ|ļweBœdY|ʬ^ ’NiKæk9cdf½+ Ńyą/čBŒ(>ŖšjuŽ%2)k”B6O_P-ń“š_‚ü°r<‘#$°Ŗ yćJ¢Ū›KӉĀaŻ0+ᔣėtS}ÖM” "Śå«L/F•Ē˜ ŹouŻ€„–Ÿ¼WĆ[+½¼Rš2FõŃ×Ö÷jŸm¶6Zł| §9¹c? ž«Rj­+L”īz\ļńł„ »M·ņµZó ƒŅ“½Ļ,BRˆ‘1a„,…,WŽæS…ČŽ~”ĻeŲĖ܈hyĢ„ņSTė­ФUh£ŻŌ¹WˆŒ¾!±•Åfߔ @ŹÓąwąßŪj˜—‹cœęm^ÄéØę.%Eʜļ‹Ś±†pŌ§…L)IW^TeF?1ĒŅš…ÆŸ\޶œ‘•]€ü]aÕ.ö¦ĆiµĘŗ®”l {Q• hC­Ś‹®ķE7TĖ •uCŽ@®÷¢ģ{Sõ‚/ŚĀqØX|Q7•CĶ䋾ņE‹9TmžC5čP7ś¢1}Ń£•«æ©\óHD“śn›²®ø¤ĶNßļ+Ņs¹ņ£4³d”~2lcOfAÅr3É^Y“åŖŌš# 3åüŗIœ‚Ģ, 3N ¦Q5ó¹¦)jåGKŽp›ŠjSdV&k|K§·“"‚ÄMz^g„ ²™¤Å6ģPŖĀH¼ ‹ J|S«2£•·µYōąAІ Ā,¤}Ė%ģķ>žnk˜«yMC šiēY˜ŅÉ9pØĄKm˜B³”I *y,ØHøŲ‚ÓDÆx°’…7Śš «Ś¤īcW’lB6˜‰ŽÖ ŖX¾L5嗹Ŗ­Tą…±ĄJEP),Ģ…@8)\Øļh¹¼ÜɘŠ;Ōą€ćQć©N€z)?x€Ėīvŗ˜“ī`ŒÕ†oįńФąŌ裠«ü'‹SyĆ6cEb=£ĖD°kĻ^‡Ęs÷(v:-īłŃžd½üR «ha½ķR› ėxaÅļR +‰—šcXŸģ†G³²ē.„Č”»įū¬‰e¼Ī|®ŸŽ}u ™€ńa.Q)$¢æUµc¾¶zŌÉ|bš°N—Ī…{QµB9½Ķć ž…™Ļąe”wY}ēģĄćYmQj?@§O! Ś“×ąŖ«%\Š“a!3,yŽĖ£©T—k+yc–łÕ8å}<&ˆū3f¢G>ÖvæNÕa-Q^ÅZ!ÄMžP_*Üq@ż\+Dc9~ßŗĖrź¹Vödq’“A~¤†É č¤Sébckąū/xü<•HXČt}¢Ķƒ جÅʏ(ضƫ›Jl,8m©>™åiø£!ÕŲĢÕ KµnóāŃ`.®–0vŗ‘ź>)|'A’ƵeĘēšJ>‘ļ Ż òjNH#,Øźć.Rš{Ų¤Ō‡£Ķ-KĖ*]jy®”ŅŽeŸŻ”š052øę&*`5Ń(ģūhõ£"įKˆˆK&&ņ °I5Š®I-yivņ'4T]ķ8DfXBĀ }ŖYIƒ“;€^€¼nŹ©ü ēĄZŖrÄy͹grŸ|²h’Mw£āœCĒŚv?Ղd_‡V_GÉāĖ0<Õą!"s‚Š®ÕœĆźÜYĘÆ’°ņ¶ŖėäĹō¢9¬Ń8—šĄ;i` h°łXWކ wŻŁŁŠ•¶6ITq“ w]iŖbƒ ńŗŅ¶5ˆÄž1  N؃Ļ.AU!Ātä4 ¢ī\„čŻN—5QzŒ^Õ§ęFšÆæE…•ˆ](üŚø.g=S÷ÅŌ]o Ū"µ*Ø8„Č›µ¾£WŻćaó;ü˦>DsXAŪŌ!6!a56L$Œ:{²ƒZ¬5:×&¾L©©ć¦ūBź28łŁTŠĖó¹,œ‰ų4ĻUҠ†‘~G9ąĀbH6Ų_ĮJ2 GƐfM ³ fMϳ¾R¬,(®Ż*¬2¾|µ‹{ĮØBĘü+ĄkÖŪIßÅAż(’}ÅĘŲE—wäw”Ķ܂ šsÓp«®•DÅO!$>¦µe$EĀĀ.CjŃ蜿Ķ0ü“Æ’ •ś°ńå%,•źÅ)¬ƒ ģ<ƒmōłŲ·›Ž>”w$×ń tė² !O%čĄŃ¤m˜s‚ĪE²x¦y°† é[Y:Ī#Af¶įȧXXŲi]!Į¼± é8tzKädĆJЁn¾ć‰ź_#ĮĆ$Ā4Ų eĮYßNvž‘^ēn…_ÖØDŒKæŖnÕhÜŖ8ŲEGi —Ķ‚/žž~ņpuž×p:·uŪń’“¦x0“ ĮŹōļtĒ+®Ų ¤ķGƹ’2,Įż˜BÆl¹‚¬ŠQiyžēe׏3„(—øäqŽf3—Ģ'Ģ’Ā|ź’{]ņ“0£»doyb˜O›>ł+ščœ‚i©X»&ŸĄŪ.’'=ähT}žøŽĄp¬¾k*Ē­Ü0ŲX_•`jų²öŖjĢW$b£Ņ)B¾ĢšvB!D=Go‹ŸŻ)]'†'ūļóöóĒuއ«ĮŪŹAŒ 0„"G@c!”Eeē ¤$w0.ąü ŪF=Īā”ų5\’ēż'œß'0Šdę‡z(ėV̐°9čü­³2ʌU¦_¢“¶#›|-DZ†tYwŃ4“;'f¤2n ©(Į5³‹G2ŸÜɲZ/qØģlźö¤qX'š8ܓ‡[wTo "«™žž€ņńō“­- Ä2Öŗ?nŪr\Ķ?Ć'ųG6‰ >ؓ\8č|Ō@IŌd[ ’-“0„bLĀæ"®ØŚą.Ó ŅNŅzÖ“ rZīA«įģĀ †R²_ė w³ŽĮcJ¾c>ѐ§ xv›aiž[X”å6OgP’tķq žh\…©Āeņ°(k_0 ųC”ø€*.ŒŖĄ:ža~Qī_ZOtŪŻ(©æÅ` ¢›*øŪ]Æ …„9ķ\Œ¬«Ģ˜Ī ø…Ҥšé4@‹*ķ™å–J1b×oa+!l:ÜėėļŪĶē[Ź&gŃjś»•7\£æ®ēø…Ź™÷;@ITź³§“‚UL‹ƒō$ŃÜŚĀ@Õ-ŖČėęH ųuĒ w×xž¾gŸó-Y’Dx7–ŌfrÖ.\Ą—³ŽŒßŪ°OŒ¹ŽŻĄ„'IĖŽø±’Ž"Ū £ā0ŒA@æ CüXÖŁ:öŽ:ˆ°ŅĘŽžé:i6ŽĀc²˜‹‡}ö¤æ·óĘålžbŽNĻąw°Źa5C\§ĄiŃL“6½†›„¦’liŃŌ’L2ŻÜł²µ!©T<ٶZŖ >ļńp=ęŅ\ ·ÅGHLśözÄ{ā“D÷ üœ©.§Æ·“Śģń؀d 1e!öŲČŁŠ¢E')Uż Źś­¬j(ĮеFŗ®r(“³€Š£?6u4“hP?ņ°”&MÜ“ŠŅ ¦ŚĒA*?/חƕż • 5pL­Ī‹^«šJSoU‰„A-.ļ7} ŖĀ™ŻųŹ„’ CčqČ©;9ėŪŠS_G²ĮŽ!ĀüČs§Ó9 ©Ā²Ļ„Ÿģ?ėQŻß'õcʋaž !ü>łØ‘ĘĀŽ”ļzćH¢¼kė€Č©§›[«`ūXtˆ»\¤‹c=“Oī’æ³ė+#ŒWŹ|?2,ō#>,>;(š‘x8‡†+yØéŽky˜R‹+c'ט„ėŚarlA[³ÜŌŃhĶܲŖƒ‡äŲ“°f ŅŒŅäŒK{‚ķŠ/Ż‹įL+ąöq‘Qü±ą^¬XG€š€0w”<’a¼kŠüĆwš,’¾•·?F­KJįĆ““Ō i¢Ą®;ŠĶėŻ@TR“+ö\ēšōƒFYL‚åŪjTM ŗĄŹĮ҆ˆ` Ū_ė†ŅolÆ’†„ް(«Łā¢ūėBg öV~WāæµĀĘĮ÷&«ĪM“ˆäh«mߚ«ō{³pÖåĖ_ž[a˜Óēß ?…Q‘œT(=iT]ä¬"髛HV(؉oŻdŗ"EƋųW v—{— …Ź.¢f”Z ”v‘T»ČƅBmQ·@.”Š»ŹŹÅt”X]¬kJą…by±°^(ĀČõ]¤ż.2€”`ąE\0" % uĆP1–L¼Č+^¤CŃĘPą1ƒ e#Æ“±e(\‰\†‚˜”tęEf3”伈w^„>CQŠ@>ō"5ŗÜn;»²՜Q®_ć2yˆ?’½bĄ^Ż—bą“Z0¶µ 5Ś"ĻĘsµŸKÕØ½P¶Ł™3Ŗųv°ķ4[&eW8Źžżl.˜÷ĮtŸuw|s·šź±™+n³NGĪĀœŚEē:é7Üz} 梦vw1³PųUV ʆż¼“Īš~®Tl7°IL=Ł}1Ū4żīfndėv>īÜŹ¢B½ŖŠ‡ūŒWc‰JŠųŁųLbl¶ƒ:ٌVLŌįļÄIķobžĢäĘ]¹·u押¦g{CUnŌŽ`ś¤³osQD/'å(T;R[@ ņœ=͑Ă&ölC*U¬•|тgĖRY¬hüĪē²’až¬cŅ*ŗį©BsŠ–Ŗ=ŲaöG˜]p³“‡,A•’Fps­KYEśŗĮ»f\3 PUĖZo$Ÿō1+$XL/q X‚Ö‰• ū»ķfŹ&Ą’i#^]‚ĢsŪń›_F䶙Fµن€ź’pMÜw„“%j $ ³šEØg£ā„ļĻą¢]YAÉÅĮł*­ÉGꋝkØLHšHøALU‚­±E­Ė/PQ(¶%ńŖ~¾åŸsö–£R)iõ +~¤U[&āIs|斗Ū[Ž”é&Ią2įUšåA“4Ūļc¢:‡_ #O_k ōZ3äč7¬ ³Ņ> gÆjvP«CBéLŠķN·4}(®&’ Ó¾­øņ|ī§57cf ¬ĒŗDGÕ¼į2>Œźł#ĶHõp)[˜Šp~ö,DŃĖęéĀ+hrP:ŖŁŌ•3ŁömŠs¤Ō_„g—žŽ*kˆīT¬ŸM”¬VȰӗķ ī ¤g:ČŪ&ųš¤ĘCQ2Ś/.Š‚¬?H (d[ ;2؇µ~vŪį=ÓØFæ,­‰ ĻTÉŅqžvÉĄµOŌ)¾š)»‘U[„Š •āäi¬‡ Ų/ü/ąkX §‹7’K9ƒ\ėįW2ćŁnå.8Iü4'”Ő„lU]hbhjEZI Mm (AÓmŅ~Iä:ƒ™ż8éǦrŌ5]»¤vļ9`œ-^Ė  ŅU¾nJņõuRž©ŖOś’µ\¾żĆH1oĄĻWŒGˆ¹*‚…źa‘ĢŲE‘Ģ6kf[O&˜%"+qG°€ß@B°Į˜@gĮåōźŌŻūgr÷W|×JP:”d)x ’ŗōäÆfs ĻGǽmGėXčījŽBpwEM‰š{ķ„…©'܃(ī»—ęć¶ę ’>80ż[YA°Ų'%‹Ī\Ū8 ø9ŲŁ4ļ_‰h9‚©µ4øŲuu7]ō-A'ĄtŽlTo¾īßĮ€CČš \üˆü©ĒׇėEų"ĀWvy½įPø šŪ‹c0l/C|ł2%«3ßžĢ<^*-ė7Cā2|öķ>A‘o«ŲēėŠ®—u4ZpĆu9Z‡¬āŌ­|ꀗōTÆóļUŽóć‹üžĮ:°X-(aźOÅŖ$]“Źš ›ŒŠé@ßœ@a×|«Ÿ bPčŁ A~ Éā\aćÖd' é $|‘:B÷ŽzęŖū[ȃ+˜‡č½ā¤¼2Ÿų·K.ÓŃ]ÅéNø0ƒöPq¹IŸ+ĖĻær²² C:ŲE¤¢OAo„Åņ½×%Œ•(;†F‚p/Š FlņĄAe®/p šQģSķæˆXŹ&BĀa‘ҵč<žī’ˆ`ɃĆU›,›o¶Ģq0[Z…3ĄpŠ—/„Ī;RÉ\>4ž Čߨ]Ž#ĢŲj,_°h1Š'Dü¼Cƒ.(¢ ā(Ą&]pLĢSˆŽŗ ©śfў¢ŽÕuYdhĄŅ½#!ņŖNXƒ|„µ£Ē8­5×!i I{ˆ|ŽÅg”WD.Ŗ[©^‚•Ād+™Įā¢žIķēĄ\S ¾Xƒ_7‹é+Włš]/ųćĒU[8T!~S,žĄŖņ PÄ⫲‚e*Ū5ŚAfZG Š[Ø®p-„É#ư2D9ż3²Ė‘JĒ‘×z;*%KhŻŠ—¹X…Ń’nŌ1qPøJˆĻŒ°žFlN›ńD•-Ļ–kµ:å/ƒ|ˆn VńW‚wŪbožsoóĪseóĪ‘ĢÓР“[ö zõ#|²^47h–¹’?pÉ (ŖZ›®ģ 2×Z6ä\˜pÓł˜āēŖ…d¹żF;k„dA‹2łķh“ā°ü.’“ó;Ā‚§’żUj½*HĮ‚­öē¼§v>Žöß&ž•\bH\jbøJÅSļ­Kų±ĢADłĢŁ_MgL‰ĆmĀ}!W>jµģØ“B`šŅŌ‚ÓąćÅßøź‹#X ļPœ~ĻÖŽWsQ yBłI ŹS–Bqnćń †Ex{‘$[®CL¦ŁgŖč †—­”eĮ>¼ų’ó‘Ń$A&Ū<°ąv؍9 Ć™XuGĘ35&0cĄÜ÷¤¦Ł”¢ źŁ^'uĀäAyFįŅ,B¢8ķźc’£tj,Öž R’§Æ ņ‡U»+™BæJ»Ó²ō.†7N] ĮJ -/ŚxyŠ~Ęy设V̹”٤Bø¬iÕAńnol1˜ ŪRRŁõkŌ‰Ž¼ŚŠ’Ėå`Y¾"ń–Edżƒ"`˱FŽøP āÄ,’5c5Ō“Ķ{0“ežV@“.löGc˜ ’ę3/“īnˆ]Ż©wŸģ“Š,Ił¦£³|åęŪż±¹»ź‰AŪ©F<ųf»*Ø{‹Īœ|}āi`Q¾jć9×Ü+Mx«ńĪB„:<œsP™4•/걕Mcb3.Ü.kŅyĢòš•Ź½i”nPĀŲżb–ŚŖæY°“E@6 cLåķ§_;£I QŗiõCäJ.Ö ˜wČpėp(g ¢P)IŻĀņ^ z-äy.— Į’xŠŽ¢ŌŚ)öA [Ÿaa÷õ”æ6ėb9ČM·U ‰g?.§ņj÷ŁČ+ĒĘiŽjÓŽĒ‘·o„dA2u“'šĀajŖ‡¶tĢt©p/śŚ~*Šŗ¹į`®j}>Œ`vgiuYœŹ»oęŚ ¤¾K„Sc<”„Ē/"å” y(}~‘IÕCéõ‹Lū›¼ūU>ęoRō”l}(qŠį_„óC‘żPŽ’*Ż’®ņŚ\­›Šąb^„–_ݾõ©Ōt@¾¢L·I‹™įĀI&i6S\˜d.® .Ā6`ØsIē?rØÜ3¬8ÖÉĶ5 QÕåŹ“nˆĘR6ģńM.:”–$Ø/bÕŻ Ӑ!5äqröRƒ`’™'½Ń”tÅż² j›0}oMÕmKÖæķ†[yc h\`xY–ļõ’34«R!Ķm| ‡$*a’ ‡ńąU~C|@Ó!¼ś ÅžZ¾Œ­{nŽņ1¹ėŒą”™ż(“ uFd®(.oz“Įü gzš8-<“æÓ,ĢĖ5Ņļä!ŠžóĒ”Ā÷ļP’ˆ.dƒ 1! 0„T‡€q'.4‹˜‘R7.4×0ąć UŒuĮź‘ƒ—ŃwXhÕJn6žėĖņš”Ūリói ț"©> ‹L‰éżÖm„ t0“„®Ŗ…wŠ'‰Š%vŠĪå`–šķĘFdāąwė\éįŌ·ę#·Œ‡ä 4&/°¦B~Յ‹ņ¶"†×… vcŽ…³r×n,·˜²ēBžŻ…“GÅŲ(UlĢ/2Yʾ²sŗĪź¼µ“JʐŲ$‡ ž}A²Ó¬(ĮWx”£Mž[ƒ\mšY¼Ų ’­Y¢Jf5„͹{õEv+c¾ƒ~˜ÕOńk 4ˆéš`KŌģ? ūJnœ*9q}" ėk9qU×ČĶF“WMł÷ʽŹoØ|„?ET©/|ż€`u%cUЦ¦{󟩇^ó¬ųˇFĘ<3ĢÜ]*.P÷ ø¹„éO·{‘«€§ŗ(õŽ#x^iOKłūF’v=¾‡/ä)D<єV=Z~’aŠ—ł(¶&¢żTü–T± Ą¤hR+S“łĢå%wB…ß.ŠÆ*³æQ¤µkc[C*+‡ĶtŠō¶Ģ3FŌsķØØØčļ£)&aĖ¤Ōą¾ßołŽ!*_µ˜ŻęPįłNYŒč!2$M²W¤į½ļ‰"Øi‹OņZ¾ ƒ'mą;lž“ž8“FĪS~”GA½£ŖU]‚DD§wQ `@·Q|¼½…ó"dą“™*/—šÕŌä7«dJb°y‚NĻo@ļēųÉī˜€Ž»5HZńķ!>ĶKBŲąßqÆf¤GźV/°¢dŠ@H&ø.$…€Īp”>,‰N0/Ž2i""C¦;59Ź”¹‹bMŽŁh޾iR^ō+„Ė‹*fØ jm^ż!ś?ä „œ‚L0¹¶ ;¹uŁjƒæį4ü‡ˆ)qgU¼nmŅ&Ø©PmSōż>_š›pė'Ā­O׿Ō~¹¼õ±|Ʋ_Ƨ3†ŻŻ†ÆC…)Œ†(&邌ŃįØ&xe  6¼*G’+8Į+īDuƒ0ßąĪ.ś+(Ćž>™E”…›e4u{†–ķ IIå2‰4&żTrßĶŚ²f©V!Āą·|‹€›qaq„ŒPg7Tä Ō{Ę|z;B¢Ÿ$å“-wč‘*`ĶWQLĮž°f•|›VĖ€5ÜŹ łž¬Žź q=9öüžʦŌF5ąEöō7©”˜ź¢żŽęaß1D<„“ĒĄó H=“‡Š÷ Lž©Į÷ >¼ģ­aėp›'-–u‡ćč)ü&Īū‰psŅ(3ł~åfĖ@ļĪØ4LqąŁ%&°¢½ūC«NaļÆSqī^e&^øv«“8WńŃ×Xh,Va„L/ĀÕ#-(įXy;pūåŠFͬ}9—«Zź@zqq€×Š ĢꬫŻ@ĪSu5µ9ȉā­ī˜;N¼P@E‚Ü»ž„ąŹ )j–aĮó2U|Ž‚›J+ńx¾™-åW’:Õ³ßń¬7(D‡tµ¢D2i›ņtĀ{d˜‚KGÖó\`£`׬ox[rĢŖAĘ”3W›Ę첐XŻ$axĻYåØ71ĖŁ}¢llBkU£z7GSäzo»½mӎ–€©‹"˜ ”Ū×:’ū.Ąūƒ:LÜxw5 ²&Œ¾Y 5…Š9pā3=īĒÆ°Ņœ ŻĻééü®ŹF¢Yagߊńę”>K:ęw6fśų¢ĆĻĖÓCä)Ų-½žīÅłŅŻĮŪ0)ğĀ€šŠH2?€H<‚Īc«¹]lu±u×L\äHK@!ėOĶźCŽč•WĶĒHo© ±‡Ģbœ4Ł3µAŠ*JĘfį<”䩌DOę~“q“ ŗB'}–Ē1Ų–Õj9ŃtÉAvV‚K,qŁĻĀD•å¦ęŠŽ± Nm€|+UōŖSÕėεEśZކ£¦p=>ÕūAŗ ŖÜ Ķö| ræAÓČ»£wÅóŲæ%xŲĆ„xE4čĒ&yAT†č˧yĮt†ųĻ)zA•^Ø!Võ‚k}ĒĄ†hٲ6Dį†xŻ+¶7Äˆį ŗų‚DŽ Ė!ŗ9DB‡˜é ¾:Äb‡Øķß"Į/˜ń ¾<Ä¢æ£Ö/÷ āęčÕo`Z ėžš¢N’_¶a([ŒQĮ(ü «+"€…L±+«,` …\µ Æ-äĄd¹ Æī¼¹wał…ŒĄ;xį^8‰oÜÅ Ė1dD†ÜÉ Ļ2äd^Ų›¦gĄ č£¦iČJų«®kĢ‹ “¶mČĢ 9¼¾oD 9ľqČMYĢWĘsčū8Än2~šUŅ5ńõ2Ÿ³£¼Õ »*?Ī¢£ø(ŅüŠ ėō!V&’œ.aĆ`Ł¤ęšµS-‡Õö‰ >¦+?Ėo"ņ|²© ?;Ź+Ēi“ד0^ŗq †ĀČrM€÷Ē÷|¶rŖ”A„Ö>^•ÖLē†Ą ņį`AĪßau%siŻ1žg6ł®Ź'Éā†ž‡{?sčČéBˆĆ“C|Qą“Ų~ŃÆ?ąńėfóĆ“ĘĶ'Öw¦ęžź… ŒĒō©-LąEł7ŸĆa&Ņ8¾Ń,ŗA Zuw[=æń¦Ir“ \†ÆXszćdŲæń •éįŠr·“° Ņåw„†«*6šƒ[œ»Ģ©°¶C t [‚gųך5ž2½I³›¦¶"/ÕP‚šXģķö ‰Ō9ā?0cKn寿O‚Šļ?ę¬+9¦@½É=‰™¢ųĒfśƒ|z•ņ  ×ķ(ķō±®u&1„ ¦oąń|T齊‹OÖūOVę\ō$I<Śó -%Č=sXĶ’§ !ŻWų‹6ŸÕnģ^\+ŽŖzršY4~9ō3­§’Ŗ=¼P¶¼2žžkž?u;æfZ.õɃ%š¼Gõ^ķĪūu ²*<,µ&I‰żX£ĖŃŌ­Õąr¢ēŻĮŸ7ŗS|¶ł³ ŽÅe‡æłķ<ķ¼™'ņ?&øģf“ÕÅĻĖÕ BI–7įĄ”]č«ßĮ ¦NV¼Œ?8ōØ{ćH/©Ž&FßƋ‹‡Ęåš0ŻÄ§Ń%āż6®Ł™·<¦ątuWå€gžéŸņ^uāš±PiVų$øøłĖOH•ƒĮ8©ņs9l–ć8ę™R·®Ók½tĆEĮ`0p!dеYČ_‘īę8Æ`fjJĮŸRŌ®•ÅfŌLTĶ•ą"2q&r9$Œ¦‹ŒŒN-#n½7®P­+’õ Ą|ŒæóŅ?\9ģ!Ūżß‚ާo⠟’O?]T¾’yÖ»—š¾Ć_HI<«æ‰}й: $D.ģēĀ=~m§iČLŚ]†Õor#pr ųƤ/oX榿єy9Ā6ėćø›ģW:›äō?±:A S üæ3²ŗ™^öX+­‹ķVhŠu1ó ŁØ!o5äøĒņ$ku[p¹,³ž8ʓZ²!Ė–VŽ6F»Po‡'$ˆ£Am {w21Qø.8ō™™ūŃ9|MSRŠr§ų»|L# Ž6Qõ˜¼ƒ×”‚?a؁ŒĻ”²dŁĢ'śłz’æ¼`ÅÅ ,°<Ģ×åĖ6å’éßR¹Ęē*ķŌEżøp_HÖ3VNv+@¬ŒĮ›g†ńwˆÖØz¤¾Ćf°¾5œˆ+~9V–•ąī>ņ>R‰nMg¹}“xW¢ś`P… œ(mĆXv0Ś’åGę„‹ˆQīRÉæč““Ē‘"+?„rpŠ)g 2y,cOŗb8- ƒN FaÉDi &2Ć“½¹Ą”BÆ[č֎¤ Kڃ½icÜt4"ĮH›#Ōńø(~„ź ”’ČEs$Ō'¹h™Ŗ'W5†P¹!ŌxxӃų#ї÷qE †p £õ2²/³ œ/ŃŌŹ¾6 ß7 ņov8 ‚éL­§DÅ·Õ’?äd7ӐU†Ķ­ģäŪ›ĘBØĒ*7\UćĻŠ"ōb'Z„of¦“¬?Å œ³Šē3e†9—ąėTSY˜ą/ēE9Ł'’9UĖM™±™œ?ø…ß7÷&ܒ.Ū×e« 7ÅĖl¶į¶|ŁĀ/Ū}˜„ID˜p„©IĘüIfłžVŁ8 G@8V¢qźĘÖ»›ŽŠŅ74’½6 8"ŗ4Ķ‘Ug¾Ŗpļµ6¦"ą°=ĪB±JöÜ2M‚5ń\éÕł2x\Ɇb pY; ƝÉJi$…IŠpJ%CĘ ™ĆI[żV÷ւ‡8¼±ż%ų)ž‡74Ŗ6+P”7s y“ÅķŠÜGĀĘŃŅö“uaeČ@ā1ZžhG{ūEŸ?®?>|L×GŚL›Dę’šń]ō÷wņ5q"ՏPä"%ŹŽ„%W1ˆäé1 Cv>Š›ąŒH0 .š*Į;hī=ó<ėƒU-?6”2W Äw@—ÉNĖp ‡Óż²0\‘Ą—<ō/æK³gBLƇ6™|ˆ'P¦¢T„øįn©>üN!"Ō’ˆt'Š#ōŗĻ¦JaUļbĢM½'Tś¹h]ōƒØ#Ź‹„ViåŪÆz{„¶ķ½’O„÷ä$ Rśµ8˜”lēė£W}Pj2sƒu±ė¢ó Ļ5¢z*-õ<ŃC"¬’ØŁńJ˜éē•€šS©£)ļõōČĀ”õEPé&¾Ź4ŒNį †ŚU%”N EV.‚,86nź¶…ą8³6li“«T:žķrA6ĪŖŖĮø„Ž‘Ć$6Īč|H×uīž ·B¦tJI¾w9›Wé›X#'”ÓhUžźĒųtC/ÖŌµąp,­Ņ²éĒNE-™É³ĄzŁä ¹…O'¶ŗś$iŒ^eųÉż“0 D;ØūéšŲTy2Š:²špEžī/‡Äōę‹"?š”"§J²›ė*X°š#L®TÆķųÜ>}²±ŸŗlhŸNœ »ńņLg_öF¦ĖTo,h]»ė.zŁqƒ½łm!ūų³¼ė}J}žøź!…ŹI•„X)TnŗØ<S(œl׉ł>‡ĆÉ~]ĀEäūJó¶ ż dioŅ唅ä]Ÿķ$ŚD—[m:d¢UØ.{Ń=›a{ć*ˆĘ†ņ²W)ŚP¶6ø Åp#ŻÜP`÷"Ęė“Ō›¶½śW0ćq£Å[P‰ęåC‚†‚+««3MWóµ^‚¬x6ėqY°= Ē¶‡Usy†ƒ„­fųÓĶ«}ó¼Ń—`ķ £{"/l³f«åU{µńÓā,d“$ÜŅÄ£ŃwocsjMóE¶`GK{Ų±‰¬Kš•Ą”(Į±¦ólŽņ™U0æzœÓµČf†é9KĪC·ģązV’Ø„„ÆZxDmK? b~ņW*RlqÉįj+r»1rĶJG2±2Z“”5ļWšķ{$äŽDäf`qĖf äµÄ·«ƒ ¼œƒ©N”i‘r“†³m7õY“ó™“©Óa Ü4„A„wm&޼r³ źO²ČAŹ/SĒ^UŠ(Ł£›‰)‘KŻģ”kŹ2XkäZjŒ‡żŗ@6@‘*ÓPĄUŸöE…ę7Š5‘“M¤‚só!‹æ E}üøŠJ…ņSoRU4T ½œC×ēŠ!ŗū©NīĄ­OĒęžDīĮ»Z•žx@>žš%=TNŃ»™l‡~Ü”s÷Ćåū«6ßqüŻĮCńļ–ćpFEeTÉŅ…†ē”©gJU'µŲ(ł€:éāՈ„6OQƒŹ?Ŗ6ĶG¬J™œÓ%»¾`°Ņ-qĶņ²eQpm­^Ū²© X>4”¼õZUE3qFRy½A¦2$Q,LUdįVD–°åŅÖ@–©ź_„ 0ĶeU½®|•Nځ‹›A. ÕD(nG†bu)?Ł!=T’~“n‰ü¦ĆÅL‚>¤Ü€ņ=Ķ7•ķĻæQäµ»’õu¾’WżŽÉü-u4Zö,é.;ŚQ’¬Šķņ ’Zq7’‹,{7Ī‰vßlJpuKHźdńŽe%FęŒÖŽoå°T;^`Ūa|-'£+w3³YŸźˆ ’śW1|”Ÿ›‰"@³]ŸW".µ€‡Š7I[ŅY(|]Ŗl÷^– 8Œ„ēvŸĢö$ų ﲉ7˜•fÄŠ¤|ą&»ėRć¤A-)„„į«Q’‘z@ŗC{ń Wśłć7®Łė›„ĄĒßČ „Ā›Ąķęā‹sńŠ żvBgž‡”ĻĆħł³,?²āv_)R §ćJå©§£¢P ?['¾k˜ōĪł ī=ĄĖ7Ū«ĻW‹¬ŠLėb¼št…v^±óWhډ]¬ĒB›²ŠŠ,4? Ņ.–j×2Ä÷ŠEXŚOül+_”Ē{:ĀĄzę|ŁN? H‚pC{|ä‚§ŗngZ²­Ķ^®Ö4jO÷o„S›®æ¶“€ü+ŽŹGd{ūą(pXø:pYœr v# %ø™`Ė™ PŪMŒ–N’,…#’¶/}Ü.Žo’śīpŅ{Ą†f;‘'OhŽsײ·Ņv5ŃŖiææFHŁR{ß†PŻÓ{…‹…`“Ļ?£ż±9Ń5ēŽz±ŸŚ‹żĶgƒk¾u‚å×Ųž³÷_­’õæüū?żū’ų’üß’Ē÷žÓśē’ųw žūžß’Ļæ ’ē’Ćß’ž>’łŸ~jō'Ā’Åōóß½žü'żüƦŸ’×Ļü󒿣~ž7?’ē’%żü§Wōśļµā,šģb>³FvŽžˆżzĘŖń_ē/ß#žw×/’o_’'’É?ķŸ8hą‚ĆpnübŪ¢%üE›O ō¼#žÉG¤Õ÷+øŲÆ×£4Ź«„ E:ōGDVņ‡¦wŚ­õų į¤$żrµ%:łģ+ŁļPäRŃO·ų°²?ķβč+iJzQŠņ%ˆOv«z9CWzĪĘ"&WmrÖ •(*ć^śŃv«RÕ¼,Uv7d¦4ˆ_„\`Ł~%XŚćļ5YÖĒE„eĶėG{ćŸ[ēŖh)ļÜž·§× Ļp<=Śń5ŌŗšT²‰ļ¦ņv” Õ@¤Š`si Kæ7ń}J>؏¼¹÷;ųĖoM{?xŗä“¶„•Üޚm—ņYīŹ•URĮ=ė÷WٲŗNɟėŅš+ž2> ‘#*ų’«ĖHų܅-B0LŁNuMļŗ½(ūģĄgįcWķ¼ł owĄTĄ’óOŅæ5®šÉ˜žv¼5ŁŚRķ}‚‹­ėö„d<ž"Ē[Į‘:ģ¹V [~ł|ämĄ\ߦ … w|7|uć•PŽ0™T:ւĘ{ÕÆ¢4«ü×2€ė*“ wPųe BÆąŁ'›"įRł6Iøž{mQXó›įUģ¢Ī2nr+ņĄ‹ü‹ōłŚŪŪkšÉ’°ŗńąŹ‹æ—ŅT­™Ŗœ~R½fųu »_cā¬ĄÓ¬•Ź1²ńUĒĢB.PŽäķ¼")yݚ|^kŲŗ,¹žßĄ€[CQ# ³YÕiżß†ŅcŒµ…Kx5WĀ\²›ÕńÓĀØG~²ę ½—“‰ŗØ¾;įÓC@÷•ņś!\V/ÜUķl«£¬Z "Ó}hiI“ŽśŲg,ų:¦į£TG”śĢažbłżČ?Ć;ą­m[\픹š£„sńyģo{ŽŌ\œšž2Š€ńm@CN‚cį³<¤¼ßĮ¹µT9ó=Ź[k™{ÆĪ•_?¾^'›ß ®\|µ.~ß¾÷!ņ‰uįU²ł“įTż-·4hk„Žj‚AgwłŌÄ]«“Į ōÅÜT!”—ö3g™:¶4.’ģĢß¶2¹×Éœģ›€ėŖL-2Å^Sć — ‘āœ÷zś¾"ܙ<+„Œ|v7?-ֆü\ĮyŽå™öĖŲĖy]ÆńX–) Ū&7Ēķ{ˆĀvAń=ĻśĻćĪė}ųŻ!‘éÆÉ昻»‡Øŗa¬Ģ£ßp%Wk 됀¹’ؘt(}P/–ŚŪL–½˜6F•Õŗ ’yš£”`õ [ߖ«£(Ń®«ķ~ ŠDÄ7łž?ƹ-3W°T×äo:E 젌§• z¤Æø¹>Li֖æBĖ™Ü˜ŁŠ.P.°—UO'åg²aŠAŅ‚ę~ ==V9-rp)1Į/ļ6Ł–ųõØ$µŽ–ÖĻx×/Ą¤\@Üō Ūš:]oŠg ścéŪc¼MŻŪp&UŲā³z0†ü½āFOfƧŃ\”2\¬Żj? ŚyS”gt£€‰üśŖ"Oėšæfö Ćķ™Žõ¤»¼Š=ø SAŗw³A²ĖāøŃDZ-§§Õ Ļ„øŗ÷'+O±ō“ąb*£gn›]¦ gg r¼fνźłįĀÆ±Į„ļ2cQM‚²ķØTÕ¹rAUū®…ɐK=/ąVll¶Óø}Me思ūöĻ6q£dū\m½ģɺݤ„ “P•É“`Ć‰Æ¹`jī~ŠŹą¬½¢ŸmPeŚņTiŽ{~<¬•4¶iäūHBózW&ĮĆWIāŸéŲH¾¹ūi‰c"t;ZpįĒ7Z†0Ąß‚+~aÅŽZc[žsé±ė?üČ ¹õĒž3ŽĶ ŻśłlnŠ’{Ē6H…Ə½Õ7ž½ē·óķPÓ¬R…‚™&€Ż˜ĄŅ§Xrh/ZŃnė¬ēlö壕ĒfЇ4shż[Ŗüžz0'y»³O†'߀[ˆµŖ+V«1ē©Įū~<ų+č%WĶäTĶ•ąęš¢UEž¶Œ©Ó¬ČĻrņŅĀ-zø’(ßņ·ŁVs[(eZ £łSė‰ĮŗO¶Ć“d³ņ >»x„ ņż±'r¶ZUbÉEĀ…y‚ į 2Šł¤ĖkĒ©ŒBMņüš}Œä5¾Sr“ 2_4Ų醹~c8ĒŹ:ą›²Ā¶?6Ģ¢>|°^A<šŸbļ+œŠ`Kt™~īæĶ7å÷;ĄĆ$Ko|ŹRų#vé•~–GU ŸM,CPŒX>Y¹DiÅmiˆĀæŻÅrŲĢ,ģOŠ-įżĪō;=G1‡ lĶŗ”æ˜FO®öŠÓż_ļdJ×6”ā©Ļī"cpVC{³ēå1ķµjcE„±ķÕkpø\ž†Ģš^¶»e×jžĀĀofl kOäįłeŠ×ś]ų"ŽĄR)‹cŚiĮ¾ŪŪ ’¦\„ņĢ8£Ś¶9†ēŗĆÖ\ yM˜J¼€’ -\ųŃ2 O——u’ón×䟟ąąÖŅm  Üf„ŖqJ{ւ ĶĘ@ cX­’Ā, CA‘’ hnŠžęg9S»’Q/„—«üł×œc4O<»©ś_{>ęē¶ę…Ł€xCŠO±ēt¼Očąų¦äŲ!‰SŽÓA‘ēē%=šĀLĻS7­ė¶ąŸR%/Š6+ĮŖ.§:+× źģ‰'‚AQäØžŻŅ_Ö`•švŗāŸ‚¦¾ Ćb2Ūn‚<†§ŌķQEōŒ~W†Ō¹Ÿš`3†9ÖÆ»˜2õy]S„²³võą"³6«Vœō󱂑å1-Śå9Œ}äė©ļ¢Š"ŸE×Ŗ¶Ņ‚Z98‡P·!”b­n&Į̧Qq³Įį^9xb‘hćL`gHījłZD÷Bd]Żš[ī^XųYøTŃĪń<ėóPŹŁ''{ļ!»ńŗčzzNäĪ‘BōŹØœŃŚ~& „,G“ą-+õ‚z²ų²®Īdž_røł,i „ÉĘćv%ūuuī}IÅÖh{”U¹īŖŽR.ٵ.“=Ōy÷7Į\xć{ a¬ݼT  ‰ŖŅéō½‚ģ"Œ§bjöCĀpūLQŪܼś+Ėm„üÖr“;@R7(¶¦ĮÄf°Ėؾķ¤ÜĄ¤YōM"rŸŻ¹ŸČ Ä+«ā—ÖĻčŖų6ń­ņb„–$?!œj`t;šYr:ė£d‹ŖYaoōµ@(Ā«;*ĖD³Ā1Ō0›5¶÷Py£Z fķ57`Ź9d³Ē8ņōæÆÓ‹bȘgóÖMwƒŲŁžŃ­šĖ œ>7YI³Ałõłŗ±ƒ,6HL™Ŗ¹ĻC;œ\g÷śb§H¦^Ą?©P[ŠßęĘ7!4“ČF l¹|”ƒ%\¹Õ®āF6*‰6ķt€®WH}įŸŻØ+v³½ń^ETĄöŲå`j ų5ö£š ˆńāß»‘Īō’ĮxŌ%ÕĒ÷4ē+ąŽQ|ģ3‹ j&‚b•™NqĢJ}阐·ĀqbPA£Hź|”^|ūGKŠāŸ5<}6ņN®ø®FįÉĪA„ĖډćŠtß4HQßā‡ńĄŁˆ±\›ų¬!\ŌĄDL$Œsfŗ·6ņ$t0'.w¼X Ö ×M>EZsä“TŖK/ftćJR™E|×§PÅdo €¬ĄoOK¤bRć_z2*£¼}ÓĖ.O=²ŸŠē¹ĄDÅ¼“¢ē–voO #;ĆłÖņ¶NņDT GēŻĒOzüe®•­óA–G^U8~Å×8o(u snęÅ™Ó ŠŗŁ7ŽĘ#"…Óā¬+ÄgēD‚™šĀ†,ńżŪ¹iŒ:Péq¤U¬<Ś#·’…šY^”ōéįĘv‘oćŃ2Čč ½ļC™Ūˆäm6a<¬ūÖ¼O‡'agU9Ÿó^ģ…WęÉ5Óäņ Š|øĪĒrا17¹tLGā÷³“6x%7•¹žī‘ÆķčI7äLż&'*OUyZ;u—ĪÄėN.\ĻąŚ0Ł|{„x¶"—k~?‹Ū¢ŪµŠ’柟éē,ųŽż†“pe§™,$¹€ƒ’Ī[O››égż@Cų£\5³õLóøU¼²ōl–Æā«ä™ö«x!äŌžå“żąE¹ŖÆśH_łzVV„>¤ŽKźv¬™)O•X^Hfgm Ŗ*õGAĻXŽGśjOhŠŁK ;ež%Ēbąų­üūՈ%¢‹Ą’CŠž¶5K°¶ļ•…Õ~å=‰9ä‘ÜŸ5] -”ŠŌŪh‡¶‡VŚš&īęŠaÆ?)4’-ü8ƏAßZłZ8¾Ŗ<ĄĄłP¶ÖWŲ UUy_ß§8§U¾ąm)¼Õk»Ań)Cź©łŒĻ”˜s_iS|ܬ,« Čzk‰ØĖ|ƒn QŌ{,!+‘_ĘGYTL…N1D=$ ‡Ž+j’ģ W¤ĪźgýD+ńŌ”Æ½; ·isг£!ō7‰‡­©”oݚb ~Yåi›æK\J#Ē$Eé¶o•Ÿeݤ[ Ų‚²—°ĀS§°‡żŲŖF©æHŁqŲ O³JĆ!.ŠiˆPß÷ų PyžõķbĖ—Ö[TĢw[åkYGĶn^¼x;|iP?ZŻŹy{Ļ~`ŃĘ„P#¾sÕ^ć”>Lk9š}˜l ­»§cWõķ!ˆśä8†ąĖKĒž4X8+Ęz¤×Uce‘r›ūr§³Į„[?"iŖ‚ąä]9N}ĘĻ}aZČg ‡ŗLķéĒ©Å#­lŃM@ŅĪ%#yéw½½Š­Ā‰lq;bļmŲ„ø±{6,;üōvT¢^Æ31Fg„ēĪŸd]āԜļ.„ÅļÆ ńŁōóæ øĪ|ÉV\¼uœā·Ÿ5‡« Ģķ•ĪĮ.ųYKæhŹéueģDBĆń€hĪCĪ¬o°²m?½OŪY-—›-Ä~ńFg—ī€ó5ČnvŁx2Łń¹ØQžĢ¤xA²ÓĒŒN¬ ¹b֕`7m Ińv6̜·VcĆnņż„ÕBāĮDÓL‚Å*ķ+‡w€[{_ęČa<5"ėdi+»¾­w‡½sšĒ"'ų, ®Æx€¶@æ Z?|Ķ‚?ßĆ`&½ž’Ń?ŪgšYļ*ń°…»Æ)wųŁóeĻą·œżĆV±ÆsJęĻ8‰“*p¾ØĖ-N¤“5€·‹ą,)“×ĶÓ®’»?I‘õr²¢-~ńӋü§šMŁi÷ē1¾V2gæ]×~ŽJ]UB\t;¦QĢJå łÅ°×ż7­ņõęEp]|”hø'ŌµŅų w®»Ī/S õγź“4 įuéē’›yAžÖX,X>/5Sjf!›ŗ|’ x÷ŗøūźķ1Õ~į~_ėĢä®fāmrٶÆydó§I£i°ŃŁ]ĀģqB. §•ö„ė'A6ļŃuĖ’RĖ—]ƒÖ ÕŅ÷—śóŗī>ņÆiĻó銲Uē»oŚFāxä_®]˜›ću4ŖBš¾’ī\²‹Ęs§£ģ}yT÷±{Ŗ5Ć"½čؤęā‰ķ4Ų—ÉĆó=>^n† V)«æ„üDpŽI¶i¦BčA®u}ø*}ŗśqßøxśYOĶ]Āo;QkŲßš&Ńż¼@xU .ß3j>īS±UÉŽh{‘|=+‡•C?%œ€T¹Ræ‘āt  3ćA\¤ŻģƓ 0`$8;/ZpĶ mpClāiŲGp6˜©H z—®˜ģŪ„8¶Ø2y™ł ¦æ*y§ųóå‡ĪįzœŖj˜kÓhü|8©č܉¦a›¬­&źņ¤Efƒ„ÆęĻ2‹v ”8ü¦?ĄQ5;ÆmžÖźÕdŹĖ/-S}¦Ē/ps‘*_v ¹Ķ’4`ŽØpqļŌę:Ų UėjēJöāŠCŽ”`$h”-ĮVY”Vy0īśĢÜxBʆõ›~A—q8VŻi²Śu5LtĮNX\ZDWc2¬`؟•s>ĘąĢ†u<¤\æ@ē8¤ƒVJD|Ė=Ē£q‘óµ·³«„Ņc„Ó½dj–‰ ‰#³u@P™ćģŁ¬½īõ ł©{YjyŲ]® Ņxä;I°ģoG–½Jüˆ{ęŖė®ņĖOĆRqŠˆdNÄŁ—’‚^88”Vņ Š!¬DrŁ—¦GŪŃĄ{:Ė©ŃƒŽ7 =œvĪG%žēYß^)EI*Pž_QAŖčęÅ/`ÕD~«;–Õ ö²nÆ2É7;ÉīżMÆģ®É—ĀvĻłęfĆpŅXp8Žhø–ŽfēAQ¢=ü> NĄgēKauĶ“ŽčŃ"ķāĶIÆs Č(zž‹`YžDösEØ8‚ü—_Ög«AxO_ŗO[ˆ‚XnóŗēŸ…ā…HÖŽNõf9F²Y ’ƒ5ŸĘy"OXĆ>åyČYf}ó.×uęĒ×ļeu  ?K1‰ę$Ŗ½”ÓźŒŸ†…ųgM÷öńč)lŃ ŚĻ"(/°ż «©±-eē˜@-”žtÅéRĒOØ5ĄŽŖ‡[‰Æ}XAv'‡ÕńXL—£Ye’Šć »ł0˜½ßxl'©„d ¦žž;pY‡‰éы» s…fśń62ĪS˜bY@;ʹ1ļg£3› ¤ƒ““ć=¼Ļ”į’Æ¼«‹±ėŗŹē8±„Ü“%)¤Ŗ(§.vĄ™óæĻń_±Ēq”ę:žŚ.qSÅęz|;žęΌ¹;I”“FT‰'„(­‚hŠPķ/„T~$ B¢ā”ā©ü $*AŌ²Yߌk­sīńø”Ä/±½=³×Łg’½×Ž{ķµÖWYįĪN‰MFŃ#öLę2ŪÄåāÅ‚#&ļŪó¢ŠNŖĪGÆąyU÷®?Ä1sÖ37H³›˜™góĀ!V‚ Śąź|@Ó ŌA °ó «' Ócę=ŒńDuϾ5U›«Rg­ģpŚ4ÅE’.¤UŹR—opmµ=a«Ķ@/ź{]X‰š°Ōg¶7kĶ‚X/*@.ķ8/¢L4=ć¶N•œūęŠĖbŁÖģWņZw’Ż“µIćÄū[˜ĖM‡»§ī)d. Õ1R®\"ĻjĢTėFŃ#‚Ė;£/ݜµ=õ̦Ŗģˆd37š_F“³Bļ¬. ń"†ą£š–:ügbŃ7±Ós3Āž‚ 2mk5ÆżŅ“§Ė8ėčūYSWs‡Tā]N×%±‡Hz™€K0=x¦N·Ųś½€K&:§UĄėLĄBßļ "į~·igšŃŁé“—y”•aS;«ßĖIU[Ų­Š«ōŌ¬PgZ4YÕĮµę™īäE=‰ā©ž侌S¶Ķ¼”ž!ą22GŌØėEG¬i«ūĀRoF™\čņÉ †"O(3Ó®MUų‘gŖ4-¾‡·‘!©p)×}a©YYŚ0ój>T²™6•Ŗ$ }•Ķąc§'_uņž-Åuõ˜ĖYėįr=[Šü’‡Øm½ŲŽp‡q›ŠÓuµĮTxČvöę“+PŚd4V¹]‹?¤b²ÖÄoX0Ö ŁP×m¹7±.:«ÕT„gݶ“®žu|MŒĶC¦®š¹yܦ‹V³€Nm@k¦ ¬ėSq_m*ėÆ­™H»óÖ6ƒ*ˆ¬½ ŹU¢•µįŅTNȵ¦V¹6@Ō—1£ŗJu"Ŭ1mż:øs t¶,Š:”•.8fūˆ“Żõ‘n&3ĮRé "Š=ƒÕańÓčŸõymķ’ %I%©.ÜæKωfO­ŹIį;WvĻVTVF[¦åĢ­>÷³œójÕĘę¢j͵zį;7v~,tLuk„ņJŒŌZ7œN•ū™l†Ÿ,Š“y‘›N[+Ć'Ł 1ŌāØ1ö4dwšUt™„Ż­ą£(1‚«ƒģßą6Ķå—}©<CĖdgb„W˜¦4ň‘¢eYŪ¦CnķĢņ¼rw–ŠĢrR]t½Ėé–ĆĻłšń›Ŗķ"ߢ‘É2ĖDŪ³ŹķpEĢ"5‹ É“4ų2ĶwŹ@-ŻDŖ«4&dLµ5ūšŅģ0Ž4Ģ,‹™æM#Ł”ó™KÆ2ē ¶6™Ŗŗ`ĢņNņTmzuCÆ÷`…t,¶“ś ]f\·6’OĘ=xRk{I]y\oU6·x/-u_ƒ|(änQ,ZY›ƒ*÷s™ę¦Ņmę@L¶āX+p(ä²Ö­§Š÷®"掩ōŒ1Š*]fL™Wkq_ęLj‡˜Y9»³Ųŗ ‘Ż@‹\˜7óÓ5E8ĢTéŽTĶ8µ1Z“ÄDÓ«ÆJ)¢rهB–”č™9Õķć͉čŗ9ƒ£xėqSxiuYUk&B,SƒMœk–¶·?Fŗ |QŪ„Si k†`m(®O\8u+tZ“éŹl=#®ÅBƒe¹FZ¦Ó)Õ¬Ķ3õ ›ö¢ś²pĮ¾`§U¶“VÖ9… EŚVhئ•īõ®…ŗGµ»* żŻČēÉ «č¦ėäņ°±–Q*HqĆtĮ]3P“ü™½.5#Õ»lq\+Ͱŀն•Ģ’Ų¾¾#Ć9ĶY%;…8 U³«°¢4ÉŹĢˆ.ƒ»xY%œbęe¹mž:̼Ŗ²-¬“A®uó¬{¶¢-=`/?®šz­^Ō+²vQ™ĻW§ŖEˆĻ¶ń­•U ¢ 6A>E…H6¶ DgWt|ó¢čaßu”ĪvÜĪP1Ó\[å:ÜKe.(Ņ„ŹŽ9µŠ$Łō¾ß²īe­­U- ą^ ‹vj"Ą0«r~ 8LūŒ|&¹Źq^ō}]b\O„õjre!r„Œ“y¦SRVļoĪśn&>pƒVGļ‰+C§ÖžŪp™Žż“Y#9³®ŗ²½?nl_ N#g“Ę”nÅ~ꀲ ģö•2ØPĶJļZ‰łj ·*0ś›ÜF0M­4XŻ*„Ä.ķLP}Üæ[ąq¬ė¢ŒĘœ/ŁļQµn Ž¢—&Æ½2,‚,äÉF+= ²`y­qZr¾G·Ł(ń®ŒB<m„tós¾½`/ Ē[^¾¾vfc“7?É>Ø^ŃBåö'ēĻ…}su®.'‚ļ>ąz~„č‚”mzqĄ…9Ģ/„Ą#8ĄR4eįZ†Ęé&\NXŠ&ŲĀYļ•”­…ä`µœk†BÖk_…õ¦,CūŲ“ƒRœX±;rāZļ•­“üēĄp4'zes|„¶Ņ‡!|ü5M—ƒĘūķcŠÕBr°Zεķ“ļĒFr„@®ĀłJ2†“JaP Ɛz# s-D_ŽĪś‹»ķ† —›ĀśµĄxHYȉؙ&Ø[‡»0ıu@„ Æ`Wеæ NéDÅ„J~$gAKIĮ”Ŗīŗq¬čOųbÕųrųÄYŁOAb H„ŌmŗK)ŲčĮOĮŸØ¬³0Dp’ƒ}æ-÷Œ+X÷8E%OsŒi6‹čĶP‹7•Œq£€MržUŻ—3c¹7‡Ł—»6gĶ(šźļBƒ+˜qaöÄ uŠj< céDMĮŗ"½xX¦ūo°ĆÅ~Š"ģó-ެŁ7@)tzhy(EkĮń“Nz“‹ćœ·¤—BŪNSŲõćü!·ōĪ$,‚ų›%Ē®2—`³,č˧Ōy8ÆéŒÄ”SŁćmH)ćx»“1iq&ß»4ZŸ›ŽV't^¹6ŗ1NFėėXoĘWéI²2_ŪܘŽ“kW6ž…^Ńä,eøųŲdrOēӋ”{²°9ž®­®SÉŹx3?7^¾7¤¼vetyu}…R5;¤Z„dā±5*ŠÖŪ'|ōŌÅG§”Łx}s‡œ–QēžOĘ7ʓü–•Ž»÷‘Ó'ћ£ĄM߯ ī½zõ"w’tĖąŽh?w“+Š£üū›¢„čŌŁ„÷dél²xzxśĢ‰GN&GčYLį0bŠüg[X1b*E;ž¹‡Ā+ņŚ=?ń¹čnśy ¾ū5,ń ¾µ+”Iy»£ŻōsOŒÜ~…B³{WōCŃŽč+ŃüļF_ōæNįé÷¢ßń“č·ü…č7üŁčWżćŃ'ż£Ń‹ždō“ž½ŃČæ/:㟊NR8źOEūÅč)$ś°?½@?‰āŸņ§£ßö£ßó×¢?šæ}Åæż©’³čż×£?ņ’}ÉßŃ?ŽĀ/ūāOłW¢ĻҳĻ{ŌåńQ.~Ųæ7~—??č4~³0~£æ+¾Ē’kt’›č^’åč>’Łč­ž“Ń;üóŃCč÷wūߤų—¢ż_GųoDßėæMį-ńž]ńŪ|’ ?ļó'ćŅ?§š>śż¢?OüBü,…›žPü¢4~Ī/ķÉų‚*>Ķõ¹Ócc’ü÷;>Fī–rūcåķįߟ£wŸö÷Å«Ö=ŹüĻčI*ē<•÷’ĻŃ)żŖĒˆž]¦wFžˆö-zö „ł/J‹w^Ļ<ā‡e&¼%ś5źOSÆ|†v/Q½D=õ}/pø@»™óžó“Ky™z’Ó4+^äp“vē=Ž=ó”ĻpOŽM=9ˆŽI”ŠĢń{|F;4>L;”ƒō³”xMōŅW -Åż=?DéZJߊ{xæŠ+J[Ó;ŽŽ=H?Sü(ŃßCiŽśƒ?Hōƒō¼”tHßÄG¼ė…*>4Ź™pÄB1—‹Pr¾5åUSŽ(§”ŠRü ”7jJƒPQz„r&“D;Č”¦ßCh|čŁČĘhˆļ²/ܝ*¢č.ž2’ ēĪåéĖDŠÉźyłŗĪŒ‚ŖK© http://www.intel.comąÉźyłŗĪŒ‚ŖK© ,http://www.intel.com/}DŠÉźyłŗĪŒ‚ŖK© _Toc176025230}DŠÉźyłŗĪŒ‚ŖK© _Toc176025230}DŠÉźyłŗĪŒ‚ŖK© _Toc176025231}DŠÉźyłŗĪŒ‚ŖK© _Toc176025231}DŠÉźyłŗĪŒ‚ŖK© _Toc176025232}DŠÉźyłŗĪŒ‚ŖK© _Toc176025232}DŠÉźyłŗĪŒ‚ŖK© _Toc176025233}DŠÉźyłŗĪŒ‚ŖK© _Toc176025233}DŠÉźyłŗĪŒ‚ŖK© _Toc176025234}DŠÉźyłŗĪŒ‚ŖK© _Toc176025234}DŠÉźyłŗĪŒ‚ŖK© _Toc176025235}DŠÉźyłŗĪŒ‚ŖK© _Toc176025235}DŠÉźyłŗĪŒ‚ŖK© _Toc176025236}DŠÉźyłŗĪŒ‚ŖK© _Toc176025236}DŠÉźyłŗĪŒ‚ŖK© _Toc176025237}DŠÉźyłŗĪŒ‚ŖK© _Toc176025237}DŠÉźyłŗĪŒ‚ŖK© _Toc176025238}DŠÉźyłŗĪŒ‚ŖK© _Toc176025238}DŠÉźyłŗĪŒ‚ŖK© _Toc176025239}DŠÉźyłŗĪŒ‚ŖK© _Toc176025239}DŠÉźyłŗĪŒ‚ŖK© _Toc176025240}DŠÉźyłŗĪŒ‚ŖK© _Toc176025240}DŠÉźyłŗĪŒ‚ŖK© _Toc176025241}DŠÉźyłŗĪŒ‚ŖK© _Toc176025241†œL`ń’L ² >Normal¤Č CJOJPJQJ_HmH sH tH t`At ² > Heading 14$$$ & Fd¼ż¤ą¤<&d@&PĘ’56B* CJ,ph`Ø\`A\ ² > Heading 2 $$ & Fd¬ž¤¤<@&5B* CJph`Ø\`A\ ² > Heading 3 $$ & FdŌž¤h¤<@&5B* CJph`ØX`AX ² > Heading 4$$ & Fdüž¤,@&5B* CJph`Ød`Ad ² > Heading 5($$ & F Ęd’¤,¤d@&5B* CJph`ØH`AH ² > Heading 6$$ ʤ,@&5f`Af ² >Heading 7,(Do Not Use)$$ ʤ,¤<@&5h`Ah ² >Heading 8,(Do Not Use-)$$ ʤ,¤<@&5` `A` ² >Heading 9,(Do Not Use ) $$¤,¤<@&5DA`ņ’”D ² >Default Paragraph FontRi@ó’³R  Table Normalö4Ö l4Öaö (k ō’Į(² >No List @"`A@ %² >ūCaption,fig and tbl,fighead2,Table Caption,fighead21,fighead22,fighead23,Table Caption1,fighead211,fighead24,Table Caption2,fighead25,fighead212,fighead26,Table Caption3,fighead27,fighead213,Table Caption4,fighead28,fighead214,fighead29,Table Caption5#$ Ę@„üd$’¤š¤x`„ü 5B* ph`Ø>`A> ² >TOC 1 Ęš „ģś¤Œ¤<`„ģśJ`AJ ² >TOC 2% Ƽ𠄼„Dż¤¤^„¼`„DżZ`Z² >TOC 3! Ęš „„øü¤^„`„øü^JaJmHnHuFU`¢1F ² > Hyperlink>*B* CJOJQJaJph`ØTžOBT ™-Ļ 2LevelBullet  & F¤x@ˆū’CJKHaJtH PžOARP ™-Ļ2Level sub-bullet & F Ę hhžOh ™-Ļ BodyFirst„Šd¤x1$^„Š#CJKHOJPJQJ^JaJhtH TžO¢qT ™-ĻBodyFirst CharCJOJQJ_HhmH sH tH H™ ‚H ² > Balloon TextCJOJQJ^JaJNY A’N ² > Document Map-D MĘ ’€OJQJB' ¢”B ² >Comment ReferenceCJaJD ²D ² > Comment Text¤ CJOJQJB`AĀB ² >Header ĘąĄ!¤ 56CJ4 `AŅ4 ² >Footer  ĘšĀCJF`AF ² >TOC 4! ĘŲ š „Ų „@ü¤^„Ų `„@üZ AZ² >TOC 5! ĘH š „H „Pū¤^„H `„PūOJQJmHnHu: A: ² >TOC 6 „ ž¤^„ žOJQJ: A: ² >TOC 7!„č¤^„čOJQJ: A: ² >TOC 8"„°¤^„°OJQJ: A: ² >TOC 9#„x¤^„xOJQJ.žo. ² >Body$ B*phVžo¢QV ² > Char Char1(5B* CJOJQJ_HmH ph`ØsH tH J( ¢aJ ² >Line Number,(Do Not Use>)@žor@ ² >CellHeadingLeft'$a$xžoA‚x ² >CellHeadingCenter,($$$„(„(d`’¤x¤x]„(^„(a$5B* CJph`ØXžoA’X ² >DocTitle)$„D„Œū.„Ū/„Ū]„D^„Œū5B* CJ,ph`ØhžoĮ¢h ² >CellBodyBullet$* & F Ę“ŠĄ„¤<¤<]„ B*CJph’vžoA²v ² > CellBodyLeft@+$ ĘšąŠĄ° €@@@@@@@@„„d8’¤<¤<]„^„CJDžoAĀD ² >Bullet, & F„h„˜ž¤x^„h`„˜žRžo”ŅR ² >CellBodyBulletSub- & F ƓФtžoń’āt ² >Classification .„Œū^„Œū45B*CJOJPJQJ^J_HaJ(mH phņsH tH :žoAņ: ² >Spacer/ & F¤@&CJ @. @ ² > TOA Heading 0¤š¤x5;DžoĮD ² > Bullet Sub1 & F Ęl¤Hžo"H ² >Register Summary2 Ƽ ¤DžoA2D ² >Code3 Ę`Ph X€@@@@@¤OJQJTžoAT ² >Caution+4 & F Ę„„üd’¤^„`„ü>žoAR> ² >Legal5„ģś¤¤P^„ģśCJh`žoAb` ² >DocType'6„D„Œū¤&dPĘ’]„D^„Œū5B* CJph`Ø^žoAr^ ² > DateTitlePage7„D„Œū¤]„D^„Œū56B* CJph`؊žoAŠ ² >Heading (TOC,RevHistory),8$„ģśd¼ż¤ą¤<&dPĘ’^„ģś56B* CJ,ph`Øfžo’f ² >NotesTable (Numbered List)9 & F ¤@&G$CJNžoAN ² >Note+: & F Ę„„xżd$’¤^„`„xżžoA² ² > FigureSpace`;$„2„(¤$d%d&d'dNĘ’OĘ’PĘ’QĘ’]„2^„(a$TžoAT ² >Warning+< & F Ę„„;üd$’¤^„`„;ü\# A\ ² >Table of Figures!= Ƅ𠄐„pž¤^„`„pžJžo±āJ ² > CellBitClear> & FdL’¤¤>žoįņ> ² > CellBitSet? & F ĘŠRžoR ² >zHeading_1_Appendix@ & F Ęzžoz ² >zHeading_2_Appendix/A$ & F ĘHd¬ž¤&dPĘ’ 6CJ ]ržor ² >zHeading_3_Appendix'B$ & FdŌž¤h&dPĘ’ 6CJ]Xžo2X ² >List (Numbered_List)C & F* Ęh@¤<vžov ² >zHeading_4_Appendix+D$ & Fdüž¤,¤&dPĘ’ 6CJ]vžov ² >zHeading_5_Appendix+E$ & Fd’¤,¤d&dPĘ’ 6CJ]8žoqb8 ² > NotesTable F & F @žor@ ² > NoteTableG & F ¤x@&CJ|žo±‚| ² >CellBodyCenter5H$ ʰś ūü€żpž`’P@„„]„^„a$^JhmH sH pžo’p² >Heading (LOT,LOF)I„ģśd¬ž¤š¤š^„ģś5B* CJmHnHph`Øu.) ¢”. ² > Page NumberNžo¢±N ² >Cross-Reference>*B* CJOJQJph`ØFV`¢ĮF ² >FollowedHyperlink >*B* ph€€:žo¢Ń: ² > Code Font@ˆö’CJOJ QJ @j ±²@ ² >Comment SubjectN5\@+ ņ@ ² > Endnote TextO CJOJQJ\`A\ ² > Footnote TextP Ę@@„@dL’¤^„@ CJOJQJ`žoA` ² >Formula,Q Ęp@ ą°„Čd螤ܤÜ^„Č CJOJQJ@žoA"@ ² >HiddenR<B*CJOJQJph’F``2F ² > HTML AddressS6CJOJQJ]Ne`BN ² >HTML PreformattedTCJOJ QJ ^J F `F ² >Index 1U„Č„8’^„Č`„8’ CJOJQJF F ² >Index 2V„„8’^„`„8’ CJOJQJF F ² >Index 3W„X„8’^„X`„8’ CJOJQJF F ² >Index 4X„ „8’^„ `„8’ CJOJQJF F ² >Index 5Y„č„8’^„č`„8’ CJOJQJF F ² >Index 6Z„°„8’^„°`„8’ CJOJQJF F ² >Index 7[„x„8’^„x`„8’ CJOJQJF F ² >Index 8\„@„8’^„@`„8’ CJOJQJF F ² >Index 9]„„8’^„`„8’ CJOJQJL! RL ² > Index Heading^5CJOJQJ\^Jt- ń’ņt ² > Macro Text&_ Ę ąĄ €` @ ą¤Č OJ PJQJ ^J _HmH sH tH D^`D ² > Normal (Web)`CJOJQJaJ>`> ² > Normal Indent a„Š^„Šzš ³#z ² > Table Grid?:VbÖ0’’’’’’jÖ4b¤ČPJ`, ` ² >Table of Authoritiesc„Č„8’^„Č`„8’ CJOJQJ*žoņ’A* ² >Italic6]\žoņ’Q\ ² > Superscript-6>*@ˆB*CJH*OJQJ]^JaJphTžoņ’aT ² > Helvetica8'>*@ˆB*CJH*OJQJ^JaJph:žor: ² > Bullet+auto g & F$L`$ ² >Datehzžoz j² > Pseudocode<i Ę 7SnŠ„ĮÜų  @@@@@@@@@@¤x¤x*$7$8$H$m$CJOJ QJ ^JRžo¢”R i² >Pseudocode CharOJ QJ ^J_HmH sH tH <žo¢±< ² >codefont@ˆö’OJ QJ ^J o(@žo¢Į@ ² > registerfontOJQJ^Jo(FžoŅF ² > tablecell m¤(¤CJOJQJaJ@& ¢į@ ² >Footnote ReferenceH*JžoAņJ ² >Reg_Fig (bit#)o¤ B*CJph’HžońH ² >Reg_Fig (field)p$¤d¤da$>?`> ² >Closing q„ą^„ą CJOJQJ<[`"< ² >E-mail Signaturerp$`2p ² >Envelope Address!s„@ „ü’„ō’„š&€+D¼/„“^„@ CJOJQJ^JaJJ%`BJ ² >Envelope ReturntCJOJQJ^J4/`R4 ² >Listu„h„˜ž^„h`„˜žD2`bD ² >List 2v„Š„˜ž^„Š`„˜ž CJOJQJD3`rD ² >List 3w„8„˜ž^„8`„˜ž CJOJQJD4`‚D ² >List 4x„ „˜ž^„ `„˜ž CJOJQJD5`’D ² >List 5y„„˜ž^„`„˜ž CJOJQJV0`¢V ² > List Bulletz Ęh„h„˜ž^„h`„˜ž CJOJQJbžo²b ² >List Bullet 1,lb1,Lb1{„h„˜ž^„h`„˜ž CJOJQJv6`Āv ² >List Bullet 2,lb2,lb21,lb22| ĘŠ„Š„˜ž^„Š`„˜ž CJOJQJZ7`ŅZ ² > List Bullet 3} Ę8„8„˜ž^„8`„˜ž CJOJQJZ8`āZ ² > List Bullet 4~ Ę „ „˜ž^„ `„˜ž CJOJQJZ9`ņZ ² > List Bullet 5 Ę„„˜ž^„`„˜ž CJOJQJND`N ² > List Continue€„h¤x^„h CJOJQJRE`R ² >List Continue 2„Фx^„Š CJOJQJRF`"R ² >List Continue 3‚„8¤x^„8 CJOJQJRG`2R ² >List Continue 4ƒ„ ¤x^„  CJOJQJRH`BR ² >List Continue 5„„¤x^„ CJOJQJV1`RV ² > List Number… Ęh„h„˜ž^„h`„˜ž CJOJQJZ:`bZ ² > List Number 2† ĘŠ„Š„˜ž^„Š`„˜ž CJOJQJZ;`rZ ² > List Number 3‡ Ę8„8„˜ž^„8`„˜ž CJOJQJZ<`‚Z ² > List Number 4ˆ Ę „ „˜ž^„ `„˜ž CJOJQJZ=`’Z ² > List Number 5‰ Ę„„˜ž^„`„˜ž CJOJQJ4O`4 ² > Note HeadingŠVžo²V ² >numbered$‹$ ĘT„®„˜ž¤^„®`„˜ža$OJQJ@Z`Ā@ ² > Plain TextŒCJOJ QJ ^J NJ`ŅN ² >Subtitle$¤<@&a$CJOJQJ^JaJV>`āV ² >TitleŽ$¤š¤<@&a$5CJ KHOJQJ\^JaJ Ć0’’’’Ä0š0€€€€Ä0š0€€€€AYZ[\ FP$©”Ŗ a ¶ ` ±  Y « ’ R ¦ Ø µ Ü {„“óᯱĄĖ^e­ßł9¦ĪōRy–³Š?[u¬ģ,£Ļ]yƒÅŻķ÷_gŽ˜ÕBj“ąü/COYBJ_hq“›øĀŃßéT\–·$Kp“åł8A]g‚§8?‡ŗŌé#@Jq}‡ų’R • ¶ æ ß [!|!£!Į!ņ!"V"h"¤"æ" ###\$y$Ÿ$Ą$č$%3%=%Z%d%”%ē%ų%&G&&&š&-'4'w'€'®'(B(g(Š(Ÿ(ń()B)¹)Į)Ž)č)*-*a*n*y*++_+h+–+,*,O,r,‡,š,-e-‘-™-¶-Ą-ę-.9.F.Q.¾/Å/ä/ķ/ž/[0^0l0t0‘0›0°0²0³0µ0¶0ø0¹0»0¼0½0¾0Ą0Į0Ä0˜€€ø˜€€˜€€˜€€˜€€˜€€˜€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜80€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€ 0€€˜0€Ø €˜0€Ø € 0€€ 0{{˜0€„˜0€„˜0€„˜0€„ 0{{˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€˜0€±€ 0{{˜0€Ż€˜0€Ż€˜0€Ż€˜0€Ż€˜0€Ż€˜0€Ż€˜0€Ż€˜0€Ż€˜0€Ż€˜0€Ż€˜0€Ż€˜0€Ż€˜0€Ż€˜0€Ż€˜0€Ż€ 0{{˜0€C˜0€C˜0€C˜0€C˜0€C˜0€C˜0€C˜0€C˜0€C˜0€C˜0€C 0{{˜0€Ń€˜0€Ń€˜0€Ń€˜0€€˜0€Ń€˜0€Ń€˜0€Ń€˜0€Ń€˜0€Ń€˜0€Ń€˜0€Ń€˜0€€˜0€€˜0€€˜0€Ń€˜0€Ń€˜0€Ń€˜0€Ń€ 0{{˜0€.˜0€.˜0€.˜0€.˜0€.˜0€.˜0€.˜0€.˜0€.˜0€.˜0€.˜0€.˜0€. 0{{˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€˜0€€ 0{{˜0€ &˜0€ &˜0€ &˜0€ &˜0€ &˜0€ &˜0€ &˜0€ &˜0€ &˜0€ &˜0€ &˜0€ &˜0€ &˜0€ &˜0€ &˜0€ &˜0€ &˜0€ &˜0€ &˜0€ &˜0€ & 0{{˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€˜0€*€ 0 {{˜0€€€˜0€€€˜0€€€˜0€€€˜0€€€˜0€€€˜0€€€˜0€€€˜0€€€˜0€€€˜0€€€˜0€€€˜0€€˜@0€€€č00˜@0€€€č00˜@0€€č00˜@0€€č00˜@0€€€˜@0€€˜@0€€˜@0€€č004 AYZ FP$©”ŖØ µ Ü {„“ĄĖ^e­ßł9¦ĪōRy–³Š?[u¬ģ,£Ļ]yƒÅķ÷_gŽ˜ÕBj“ąü/OYBJ_hq“›øĀßéT\–·$Kp“åA]g‚§8?‡ŗŌé#@J}‡ų’R • ¶ æ ß [!|!£!Į!ņ!"V"h"¤"æ" ###\$y$Ÿ$Ą$č$%3%=%Z%d%”%ē%ų%&G&&š&-'4'w'€'®'(B(g(Š(Ÿ(ń()B)¹)Į)Ž)č)*-*n*y*++_+h+–+,*,O,r,‡,š,-e-‘-™-¶-Ą-ę-.F.Q.¾/Å/ä/ķ/ž/[0l0t0‘0›0Ä0š@0€€š@0€€€š@0€€€š@0€€€š@0€€€š@0€€š@0€€š@0€€š@0€€š@0€€š@0€€š@0€€š@0€€š@0€€š@0€€š@0€€€ @ 0€€š@0€„š@0€„ @ 0€€€A 0kk€A 066€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€F€š@0€Fš@0€F€š@0€F€š@0€F€š@0€F€A 066€š@0€0š@0€0š@0€0š@0€0š@0€0š@0€0€š@0€0€š@0€0€š@0€0€š@0€0€š@0€0€š@0€0€š@0€0€š@0€0€A 066š@0€)!š@0€)!š@0€)!š@0€)!€š@0€)!š@0€)!€š@0€)!€š@0€)!€š@0€)!€š@0€)!€A 066€š@0€ŗ"š@0€ŗ"€š@0€ŗ"š@0€ŗ"€š@0€ŗ"š@0€ŗ"€š@0€ŗ"€š@0€ŗ"€š@0€ŗ"€š@0€ŗ"€š@0€ŗ"š@0€ŗ"š@0€ŗ"š@0€ŗ"€š@0€ŗ"€A 066€š@0€&š@0€&€š@0€&š@0€&š@0€&š@0€&š@0€&š@0€&š@0€&š@0€&€š@0€&€š@0€&€A 066š@0€6(š@0€6(š@0€6(š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(€š@0€6(€š@0€6(€š@0€6(€š@0€6(š@0€6(š@0€6(š@0€6(š@0€6(A 066€š@0€41€š@0€41€š@0€41š@0€41š@0€41š@0€41€š@0€41€š@0€41€š@0€41€š@0€41€š@0€41š@0€41š@0€41€š@0€41š@0€41š@0€41€š@0€41š@0€41€š@0€41š@0€41A 066€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5Hš@0€}5Hš@0€}5€š@0€}5š@0€}5A 066€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5€š@0€}5Hš@0€}5Hš@0€}5€š0€€€€ ½ Å[ÕZŠRŹK§ƒłĆ…Ó!Ž"B%Ō&Q(Ń)d-4/Ė0y2'4Ö5Ÿ8Ć8 !"#%&'()*+-.0135689;=>@ACDF¶^uÕø"A%R(č,B0h3¾7»8Ć8$,/247:<?BEGĀ8e‰žŖĀĆćó    4 @ \ ^ _ a  • ± ³ “ ¶ Ö ź   + ? [ ] ^ ` €  ¬ ® Æ ± Ń ć ’    % 7 S V W Y y ‰ „ Ø © « Ė Ż ł ü ż ’  0 L O P R r „   £ ¤ ¦ Ć0X’„ ’X”’%’•Ą•ĢX”’%’•Ą•ĢX”’%’•Ą•ĢX”’%’•Ą•ĢX”’%’•Ą•ĢX”’%’•Ą•ĢX”’%’•Ą•ĢX”’%’•Ą•ĢX”’%’•Ą•ĢX”’%’•Ą•ĢX”’%’•Ą•ĢX”’%’•Ą•Ģ•Œštš  š,2š$ƽb ŒŌŌ«/d×ÄŻaµ•’Te<@ń’’’€€€÷š’ šš0š( š ššB šS šæĖ’ ?ššČšš°š( š ššx² š S š:AĮ’æ intel_rgb_100"ńæ`ššlŅü’’Ü#5t@’’ _Toc156967727 _Toc176025230 _Toc166414669 _Toc176025231 _Toc166414670 _Toc176025232 _Toc176025233 _Toc166414671 _Toc176025234 _Toc166414672 _Toc176025235 _Toc166414673 _Toc176025236 _Toc166414674 _Toc176025237 _Toc166414675 _Toc176025238 _Toc166414676 _Toc176025239 _Toc166414677 _Toc176025240 _Toc176025241Ø {{„„±ŽŽ“DOҐrr‚&‚&b*b*:.Ä0 “ {‚ƒ’ææģģNNŽŽœœ||Ž&Ž&m*m*E.Ä0’’ 7IØBÜ,— 8IØBDvR9IØB¬S˜ :IØB$@R;IØBģ¬VIØBŌV?IØBl$V@IØB“ėVAIØBü^"BIØBL€"NNRļļóŽ&Ž&ā&Ä0   QTTņõõį&ä&ä&Ä0  9 *€urn:schemas-microsoft-com:office:smarttags€place€9 *€urn:schemas-microsoft-com:office:smarttags€State€8 *€urn:schemas-microsoft-com:office:smarttags€City€ œ»Ś õųū…Ä_fguvˆŠ‘”—”£°.qtw‚S ” h(k(n(x(y(†(P,S,V,`,a,n,°0°0²0²0³0³0µ0¶0ø0¹0»0¼0Į0Ä0\¹ō…Ä_fg³.p’8AR ” g(‰(O,q,°0°0²0²0³0³0µ0¶0ø0¹0»0¼0Į0Ä03”ŖØ µ {“±ĖĒÜŻ÷1BCYøéåų§q‡&š&a*y*ę-8.9.Q.‘0Æ0°0°0²0²0³0³0µ0¶0ø0¹0»0¼0Į0Ä0°0°0²0²0³0³0µ0¶0ø0¹0»0¼0Į0Ä0&ž’’’üžļ’3˜\?’’’’’’’’’čK‡t1’’’’]\“ (ŃC’’’’’’’’VC ģöä’’’’’’’’’ä B(Ń’’’’’’’’’g†ųbPŁ’’’’’’’’’)k“źE\ng’’’’’’’’fvl°†Ņ’’’’’’’’’©;¦ D:ø"-WŠ!˜8(m’’’’’’’’’‹N#ģåŖ’’’’’’’’’’CF$~”’G’’’’’’’’ŻL%ÄĢ„ž?’’’’’’’’¶"Ķ'|† ’œŻ*VĄØ’’’’’’’’’eāD(Ń’’’’’’’’’zH£LzT~P*'GRꕈń’’’’’’’’’dU’S˜˜8’,Ó2¾Te¬24ĻRūUnq~1 ({\ģåŖ’F9’’’’’’’%n]Ŗw’’’’’’’’’1cķ^tŠļ@ABDE’’’’Œb_øYš’’’’’’’’’¤!Ņ`,jP—’’’’’’’’’ŒY5fb½ųa/’’’’’’’’÷hZiž/~į’’’’’’’BqŠn(Ń’’’’’’’’’"*Fo„Iāņ<a>ipČt£’’’’’’’’’eG‰u¶ā"@>’’’’’’’’t#¢|(Ń’’’’’’’’’*h „Š„˜žĘŠ^„Š`„˜ž‡hˆH.h„ „˜žĘ ^„ `„˜ž.’h„p„L’Ęp^„p`„L’.h„@ „˜žĘ@ ^„@ `„˜ž.h„„˜žĘ^„`„˜ž.’h„ą„L’Ęą^„ą`„L’.h„°„˜žĘ°^„°`„˜ž.h„€„˜žĘ€^„€`„˜ž.’h„P„L’ĘP^„P`„L’.„„ģśĘ^„`„ģśo(„„ģśĘ^„`„ģśo(.„„ģśĘ^„`„ģśo(..„„ģśĘō^„`„ģśo(... „„ģśĘ\^„`„ģśo( ....’„œ„XüĘœ^„œ`„Xüo( „”„ČūĘ”^„”`„Čūo(....... „Œ „8ūĘŒ ^„Œ `„8ūo(........ „Ģ „`śĘĢ ^„Ģ `„`śo(.........„h„˜žĘŠ^„h`„˜žo(.„„PžĘ^„`„Pžo(.„Č„žĘČ^„Č`„žo(.„Ą„xżĘĄ^„Ą`„xżo(. „ø„čüĘŲ ^„ø`„čüo( ..... „° „XüĘ@ ^„° `„Xüo( ...... „Ø „ČūĘ^„Ø `„Čūo(....... „ „8ūĘx^„ `„8ūo(........ „ą„`śĘH^„ą`„`śo(.........„Š„˜žĘŠ^„Š`„˜žo(.€ „ „˜žĘ ^„ `„˜ž‡hˆH.‚ „p„L’Ęp^„p`„L’‡hˆH.€ „@ „˜žĘ@ ^„@ `„˜ž‡hˆH.€ „„˜žĘ^„`„˜ž‡hˆH.‚ „ą„L’Ęą^„ą`„L’‡hˆH.€ „°„˜žĘ°^„°`„˜ž‡hˆH.€ „€„˜žĘ€^„€`„˜ž‡hˆH.‚ „P„L’ĘP^„P`„L’‡hˆH.„h„˜žĘŠ^„h`„˜žo(.„„PžĘ^„`„Pžo(.„Č„žĘČ^„Č`„žo(.„Ą„xżĘĄ^„Ą`„xżo(. „ø„čüĘŲ ^„ø`„čüo( ..... „° „XüĘ@ ^„° `„Xüo( ...... „Ø „ČūĘ^„Ø `„Čūo(....... „ „8ūĘx^„ `„8ūo(........ „ą„`śĘH^„ą`„`śo(.........h„Š„˜žĘŠ^„Š`„˜ž.h „ „˜žĘ ^„ `„˜ž‡hˆH.’h „p„L’Ęp^„p`„L’‡hˆH.h „@ „˜žĘ@ ^„@ `„˜ž‡hˆH.h „„˜žĘ^„`„˜ž‡hˆH.’h „ą„L’Ęą^„ą`„L’‡hˆH.h „°„˜žĘ°^„°`„˜ž‡hˆH.h „€„˜žĘ€^„€`„˜ž‡hˆH.’h „P„L’ĘP^„P`„L’‡hˆH.h„Š„˜žĘŠ^„Š`„˜žOJQJo(‡hˆH·šh„ „˜žĘ ^„ `„˜žOJ QJ ^J o(‡hˆHoh„p„˜žĘp^„p`„˜žOJ QJ o(‡hˆH§šh„@ „˜žĘ@ ^„@ `„˜žOJQJo(‡hˆH·šh„„˜žĘ^„`„˜žOJ QJ ^J o(‡hˆHoh„ą„˜žĘą^„ą`„˜žOJ QJ o(‡hˆH§šh„°„˜žĘ°^„°`„˜žOJQJo(‡hˆH·šh„€„˜žĘ€^„€`„˜žOJ QJ ^J o(‡hˆHoh„P„˜žĘP^„P`„˜žOJ QJ o(‡hˆH§š„h„˜žĘh^„h`„˜ž.„ „˜žĘ ^„ `„˜žOJQJo(‡hˆH·š’ „p„L’Ęp^„p`„L’‡hˆH. „@ „˜žĘ@ ^„@ `„˜ž‡hˆH. „„˜žĘ^„`„˜ž‡hˆH.’ „ą„L’Ęą^„ą`„L’‡hˆH. „°„˜žĘ°^„°`„˜ž‡hˆH. „€„˜žĘ€^„€`„˜ž‡hˆH.’ „P„L’ĘP^„P`„L’‡hˆH. „„ŲĘØ^„`„ŲOJQJo(¾šh„Š„˜žĘŠ^„Š`„˜ž.h„ „˜žĘ ^„ `„˜ž.’h„p„L’Ęp^„p`„L’.h„@ „˜žĘ@ ^„@ `„˜ž.h„„˜žĘ^„`„˜ž.’h„ą„L’Ęą^„ą`„L’.h„°„˜žĘ°^„°`„˜ž.h„€„˜žĘ€^„€`„˜ž.’h„P„L’ĘP^„P`„L’.’"„h„˜žĘŠ^„h`„˜ž56;CJOJQJo(‡hˆHNOTES:„„PžĘ^„`„PžCJOJQJo(‡hˆH. „Č„žĘČ^„Č`„žo(‡hˆH... „Ą„xżĘĄ^„Ą`„xżo(‡hˆH.... „ø„čüĘø^„ø`„čüo(‡hˆH ..... „° „Xüʰ ^„° `„Xüo(‡hˆH ...... „Ø „ČūĘØ ^„Ø `„Čūo(‡hˆH.......  „ „8ūĘ ^„ `„8ūo(‡hˆH........  „ą„`śĘą^„ą`„`śo(‡hˆH.........’"„h„˜žĘŠ^„h`„˜ž56;CJOJQJo(‡hˆHNOTE:„„PžĘ^„`„PžCJOJ QJ o(‡hˆH. „Č„žĘČ^„Č`„žo(‡hˆH... „Ą„xżĘĄ^„Ą`„xżo(‡hˆH.... „ø„čüĘø^„ø`„čüo(‡hˆH ..... „° „Xüʰ ^„° `„Xüo(‡hˆH ...... „Ø „ČūĘØ ^„Ø `„Čūo(‡hˆH.......  „ „8ūĘ ^„ `„8ūo(‡hˆH........  „ą„`śĘą^„ą`„`śo(‡hˆH.........’„h„˜žĘh^„h`„˜ž1 = „Š„˜žĘŠ^„Š`„˜ž)„8„˜žĘ8^„8`„˜ž)„ „˜žĘ ^„ `„˜ž()„„˜žĘ^„`„˜ž()„p„˜žĘp^„p`„˜ž()„Ų „˜žĘŲ ^„Ų `„˜ž.„@ „˜žĘ@ ^„@ `„˜ž.„Ø „˜žĘØ ^„Ø `„˜ž.@h„h„˜ž^„h`„˜ž.h„Š„˜žĘŠ^„Š`„˜ž.h„ „˜žĘ ^„ `„˜ž.h„p„L’Ęp^„p`„L’.h„@ „˜žĘ@ ^„@ `„˜ž.h„„˜žĘ^„`„˜ž.h„ą„L’Ęą^„ą`„L’.h„°„˜žĘ°^„°`„˜ž.h„€„˜žĘ€^„€`„˜ž.h„P„L’ĘP^„P`„L’.’„„ģśĘ^„`„ģśo(„ž„PžĘ$’^„ž`„Pžo(.„“’„žĘō^„“’`„žo(..„¬„xżĘ,^„¬`„xżo(... „¤„čüĘü^„¤`„čüo( ....’„œ„XüĘœ^„œ`„Xüo( „”„ČūĘ”^„”`„Čūo(....... „Œ „8ūĘŒ ^„Œ `„8ūo(........ „Ģ „`śĘĢ ^„Ģ `„`śo(.........h„Š„˜žĘŠ^„Š`„˜žOJQJo(‡hˆH·šh„ „˜žĘ ^„ `„˜žOJ QJ ^J o(‡hˆHoh„p„˜žĘp^„p`„˜žOJ QJ o(‡hˆH§šh„@ „˜žĘ@ ^„@ `„˜žOJQJo(‡hˆH·šh„„˜žĘ^„`„˜žOJ QJ ^J o(‡hˆHoh„ą„˜žĘą^„ą`„˜žOJ QJ o(‡hˆH§šh„°„˜žĘ°^„°`„˜žOJQJo(‡hˆH·šh„€„˜žĘ€^„€`„˜žOJ QJ ^J o(‡hˆHoh„P„˜žĘP^„P`„˜žOJ QJ o(‡hˆH§šh„h„˜žĘh^„h`„˜ž.h„8„˜žĘ8^„8`„˜ž.’h„„L’Ę^„`„L’.h„Ų „˜žĘŲ ^„Ų `„˜ž.h„Ø „˜žĘØ ^„Ø `„˜ž.’h„x„L’Ęx^„x`„L’.h„H„˜žĘH^„H`„˜ž.h„„˜žĘ^„`„˜ž.’h„č„L’Ęč^„č`„L’.’„|ż„ĘL^„|ż`„56CJOJQJo(‡hˆHNote: „|ż„Ę“^„|ż`„o(‡hˆH Section . „L„PžĘL^„L`„Pžo(‡hˆH() „Ü„p’ĘÜ^„Ü`„p’o(‡hˆH() „l„PžĘl^„l`„Pžo(‡hˆH) „ü„PžĘü^„ü`„Pžo(‡hˆH) „Œ„ąžĘŒ^„Œ`„ąžo(‡hˆH) „„PžĘ^„`„Pžo(‡hˆH. „¬„p’ʬ^„¬`„p’o(‡hˆH. „h„˜žĘŠ^„h`„˜žo(‡hˆH. „„PžĘ^„`„Pžo(‡hˆH. „Č„žĘČ^„Č`„žo(‡hˆH. „Ą„xżĘĄ^„Ą`„xżo(‡hˆH. „ø„čüĘŲ ^„ø`„čüo(‡hˆH ..... „° „XüĘ@ ^„° `„Xüo(‡hˆH ...... „Ø „ČūĘ^„Ø `„Čūo(‡hˆH.......  „ „8ūĘx^„ `„8ūo(‡hˆH........  „ą„`śĘH^„ą`„`śo(‡hˆH.........„x„ˆ’Ęh^„x`„ˆ’B*OJQJo(·š„h„˜žĘh^„h`„˜žOJQJo(‡hˆH·š„ „˜žĘ ^„ `„˜žOJ QJ ^J o(‡hˆHo„p„˜žĘp^„p`„˜žOJ QJ o(‡hˆH§š„@ „˜žĘ@ ^„@ `„˜žOJQJo(‡hˆH·š„„˜žĘ^„`„˜žOJ QJ ^J o(‡hˆHo„ą„˜žĘą^„ą`„˜žOJ QJ o(‡hˆH§š„°„˜žĘ°^„°`„˜žOJQJo(‡hˆH·š„€„˜žĘ€^„€`„˜žOJ QJ ^J o(‡hˆHo„P„˜žĘP^„P`„˜žOJ QJ o(‡hˆH§š„Ų„(’Ęh^„Ų`„(’B*OJQJo(·š’>„ ž„˜žĘš^„ ž`„˜ž56789;<CJH*CJOJQJS*TXo(‡hˆHCaution: „h„˜žĘŠ^„h`„˜žOJQJo(¾š’"„h„˜žĘŠ^„h`„˜ž56;CJOJQJo(‡hˆHNOTES:„„PžĘ^„`„PžCJOJQJo(‡hˆH. „Č„žĘČ^„Č`„žo(‡hˆH... „Ą„xżĘĄ^„Ą`„xżo(‡hˆH.... „ø„čüĘø^„ø`„čüo(‡hˆH ..... „° „Xüʰ ^„° `„Xüo(‡hˆH ...... „Ø „ČūĘØ ^„Ø `„Čūo(‡hˆH.......  „ „8ūĘ ^„ `„8ūo(‡hˆH........  „ą„`śĘą^„ą`„`śo(‡hˆH.........h„8„˜žĘ8^„8`„˜žOJQJo(‡hˆH·šh„„˜žĘ^„`„˜žOJ QJ ^J o(‡hˆHoh„Ų „˜žĘŲ ^„Ų `„˜žOJ QJ o(‡hˆH§šh„Ø „˜žĘØ ^„Ø `„˜žOJQJo(‡hˆH·šh„x„˜žĘx^„x`„˜žOJ QJ ^J o(‡hˆHoh„H„˜žĘH^„H`„˜žOJ QJ o(‡hˆH§šh„„˜žĘ^„`„˜žOJQJo(‡hˆH·šh„č„˜žĘč^„č`„˜žOJ QJ ^J o(‡hˆHoh„ø„˜žĘø^„ø`„˜žOJ QJ o(‡hˆH§š „Tü„˜žĘ,^„Tü`„˜žo( Appendix „„ģśĘ^„`„ģśo(.„„ģśĘ^„`„ģśo(..„„ģśĘō^„`„ģśo(... „„ģśĘ\^„`„ģśo( ....’„œ„XüĘœ^„œ`„Xüo( „”„ČūĘ”^„”`„Čūo(....... „Œ „8ūĘŒ ^„Œ `„8ūo(........ „Ģ „`śĘĢ ^„Ģ `„`śo(.........h„Š„˜žĘŠ^„Š`„˜žOJQJo(‡hˆH·šh„ „˜žĘ ^„ `„˜žOJ QJ ^J o(‡hˆHoh„p„˜žĘp^„p`„˜žOJ QJ o(‡hˆH§šh„@ „˜žĘ@ ^„@ `„˜žOJQJo(‡hˆH·šh„„˜žĘ^„`„˜žOJ QJ ^J o(‡hˆHoh„ą„˜žĘą^„ą`„˜žOJ QJ o(‡hˆH§šh„°„˜žĘ°^„°`„˜žOJQJo(‡hˆH·šh„€„˜žĘ€^„€`„˜žOJ QJ ^J o(‡hˆHoh„P„˜žĘP^„P`„˜žOJ QJ o(‡hˆH§šh„h„˜žĘh^„h`„˜žOJQJo(‡hˆH·šh„8„˜žĘ8^„8`„˜žOJ QJ ^J o(‡hˆHoh„„˜žĘ^„`„˜žOJ QJ o(‡hˆH§šh„Ų „˜žĘŲ ^„Ų `„˜žOJQJo(‡hˆH·šh„Ø „˜žĘØ ^„Ø `„˜žOJ QJ ^J o(‡hˆHoh„x„˜žĘx^„x`„˜žOJ QJ o(‡hˆH§šh„H„˜žĘH^„H`„˜žOJQJo(‡hˆH·šh„„˜žĘ^„`„˜žOJ QJ ^J o(‡hˆHoh„č„˜žĘč^„č`„˜žOJ QJ o(‡hˆH§š’„h„˜ž^„h`„˜ž„„PžĘ8^„`„Pž..„Č„žĘČ^„Č`„ž...„Ą„xżĘĄ^„Ą`„xż.... „ø„čüĘø^„ø`„čü .....’„° „Xüʰ ^„° `„Xü „Ø „ČūĘØ ^„Ø `„Čū....... „ „8ūĘ ^„ `„8ū........ „ą„`śĘą^„ą`„`ś.........Š „ „˜žĘ ^„ `„˜žOJQJo(·šŠ „ „˜žĘ ^„ `„˜žOJ QJ o(oŠ „p„˜žĘp^„p`„˜žOJ QJ o(§šŠ „@ „˜žĘ@ ^„@ `„˜žOJQJo(·šŠ „„˜žĘ^„`„˜žOJ QJ o(oŠ „ą„˜žĘą^„ą`„˜žOJ QJ o(§šŠ „°„˜žĘ°^„°`„˜žOJQJo(·šŠ „€„˜žĘ€^„€`„˜žOJ QJ o(oŠ „P„˜žĘP^„P`„˜žOJ QJ o(§š„h„˜žĘŠ^„h`„˜žo(.„„PžĘ^„`„Pžo(.„Č„žĘČ^„Č`„žo(.„Ą„xżĘĄ^„Ą`„xżo(. „ø„čüĘŲ ^„ø`„čüo( ..... „° „XüĘ@ ^„° `„Xüo( ...... „Ø „ČūĘ^„Ø `„Čūo(....... „ „8ūĘx^„ `„8ūo(........ „ą„`śĘH^„ą`„`śo(.........’>„Øż„˜žĘx^„Øż`„˜ž56789;<CJH*CJOJQJS*TXo(‡hˆHWarning:h„h„˜žĘh^„h`„˜žOJ QJ o(‡hˆH§šh„8„˜žĘ8^„8`„˜žOJ QJ ^J o(‡hˆHoh„„˜žĘ^„`„˜žOJ QJ o(‡hˆH§šh„Ų „˜žĘŲ ^„Ų `„˜žOJQJo(‡hˆH·šh„Ø „˜žĘØ ^„Ø `„˜žOJ QJ ^J o(‡hˆHoh„x„˜žĘx^„x`„˜žOJ QJ o(‡hˆH§šh„H„˜žĘH^„H`„˜žOJQJo(‡hˆH·šh„„˜žĘ^„`„˜žOJ QJ ^J o(‡hˆHoh„č„˜žĘč^„č`„˜žOJ QJ o(‡hˆH§š’„„Ę8^„`„0 = „Š„Ę8^„Š`„.„ „Ę^„ `„.„p„ĘŲ ^„p`„)„@ „ĘØ ^„@ `„()„„Ęx^„`„()„ą„ĘH^„ą`„()„°„Ę^„°`„()„€„Ęč^„€`„() „h„˜žĘŠ^„h`„˜žo(‡hˆH. „„PžĘ^„`„Pžo(‡hˆH. „Č„žĘČ^„Č`„žo(‡hˆH. „Ą„xżĘĄ^„Ą`„xżo(‡hˆH. „ø„čüĘŲ ^„ø`„čüo(‡hˆH ..... „° „XüĘ@ ^„° `„Xüo(‡hˆH ...... „Ø „ČūĘ^„Ø `„Čūo(‡hˆH.......  „ „8ūĘx^„ `„8ūo(‡hˆH........  „ą„`śĘH^„ą`„`śo(‡hˆH..........÷hZidU’SĻRūUeG‰uŻL%zH£L©;¦ čK]\“ ²9: ({\Ó2¾TCF$ŒY5f"*Fo)k“1cķ^]\“ @’Ū ]\“ Œ’Ū ¶"Ķ'ž’’’Ų’Ū]\“ \“Ū ]\“ Ø“Ū P‘83WŠ!fvl%n]‹;•2Œb_eāD]\“ @”Ū t#¢|]\“ Œ”Ū œŻ*g†VC ä B]\“ Ų”Ū a>ip‹N#'GR¤!Ņ`’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ä’Ū`”?@%„„^„`„567>*CJOJQJ^Jo(ph" ’’’’Sųš˜ųš’’’’“T’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’‘’’’RØ„iUnV WdX’’’’’’’’’iRi(TbUdVsh’’’’’’’’“lr Tlr ˜lr ’’’’’’’’’’’’’’’’’’’’”U’’’’’’’’’’’’’’’’’’&’’&’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’         ’’’’        ’}f§        ’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’         ’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’rJāē        ’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’         ’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ĘQ¶Ż*Ż„Õ       ’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’         ’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’¢å”H+ø n;b J d õZ k ø;€5 ˜rüŅT™K+ųYß@Ó. µc Āe!zi!Ä"%"ųO(ų/+oT+]|+Q,‡.5[.F1“F1ł 363Ą4?`5ž>6¼7:f8C :ć8:;4;.%=² >{#?Z@\ B'D¾uG68Kb N‡oOņERŅHSVQNWåjW7&YŠ[®%\Üda¾{ŚĪÜ© ݘ[Żß-\ßŌnßO7ć}ć ä$åjhå‡:ęČVź-ģå ķś:šhbņ6óÆXóŽ+öą`ų­GśūĒ'ü@łÄ0KKKK’@€@@ˆ…x @@Ć0`@’’Unknown’’’’’’’’’’’’ G‡: ’Times New Roman5€Symbol3& ‡: ’ArialG5€  æ ūüĒhŸMS Mincho-’3’ fg;†SimSun‹[SO7& ‡ ŸVerdanacGaramond BookTimes New Roman5& ‡za€’Tahoma71 Courier?5 ‡z €’Courier New;€Wingdings;" Helvetica 1Hˆ¤ØhøDµF¬ä»fL~Dl)XDl)X!-!),.:;?]}Ø·ĒÉ    & 6"0000 0 0 00000’’’ ’ ’’’’’=’@’\’]’^’ą’([{·  0 0 00000’’;’[’į’å’ “œ‚€d˜0˜02ƒqHP š’?Ø’’’’’’’’’’’’’’’’’’’’’B”2’’SC:\Documents and Settings\jcihula\Application Data\Microsoft\Templates\TXT Spec.dotSIntel® Trusted Execution Technology  Launch Control Policy Linux Tools User Manual Joseph Cihula¤&                           ! " # $ % ž’ą…ŸņłOh«‘+'³Ł0Đ˜ō $< T` € Œ ˜¤¬“¼äTIntel® Trusted Execution Technology – Launch Control Policy Linux Tools User ManualTXT Spec.dotJoseph Cihula76Microsoft Office Word@tØ Y@ Š’å‘Ē@Ųķ±12ČDl)ž’ÕĶ՜.“—+,ł®DÕĶ՜.“—+,ł®L hpŒ”œ¤ ¬“¼Ä Ģ ,äIntel CorporationX˜0' TIntel® Trusted Execution Technology – Launch Control Policy Linux Tools User Manual Titlel 8@ _PID_HLINKSäA$N7G) _Toc1760252417A) _Toc1760252407;) _Toc17602523975) _Toc1760252387/) _Toc1760252377)) _Toc1760252367#) _Toc1760252357) _Toc1760252347) _Toc1760252337) _Toc1760252327 ) _Toc1760252317) _Toc176025230Thttp://www.intel.com/)   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ”¢£¤„¦§Ø©Ŗ«¬­®Æ°±²³“µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽßąįāćäåęēčéźėģķīļšńņóōõö÷ųłśž’’’üżž’ž’’’      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstž’’’vwxyz{|ž’’’~€‚ƒ„ž’’’ż’’’ż’’’ż’’’ż’’’Šž’’’ž’’’ž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’Root Entry’’’’’’’’ ĄF e»12ČŒ€Data ’’’’’’’’’’’’ū1Table’’’’ßāWordDocument’’’’õSummaryInformation(’’’’’’’’’’’’uDocumentSummaryInformation8’’’’’’’’}CompObj’’’’’’’’’’’’q’’’’’’’’’’’’ž’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’ž’ ’’’’ ĄFMicrosoft Office Word Document MSWordDocWord.Document.8ō9²qtboot-1.8.0/lcptools/Linux_LCP_Tools_User_Manual.pdf0000644000000000000000000026173512272416301020613 0ustar 00000000000000%PDF-1.4 %Ēģ¢ 5 0 obj <> stream xœXId5KƐ a™a™™Ė»‘y(cG„·+BB\h•4˜S² e!Ń~’|^ž_uµˆęE¤cūāsŲī?6ļm^’ׇÓ'N9n)–ø=œ$Žļ[ūŽÕė·­éß’Ż~?yē9ˆ§_œ“¤ˆŲ‘ēķÅ/' >9_¶ä ~g8抯(Фā²l\¤ŗLŗ"¹š sp\·Jt>l×"'¼%bvlā>©ˆ‹rf—Ć–8$'dC XŽŌGp>«Mv›\ÉED%*®2|ų¢ŃSˆÕÕŲ¢ŚWņ98Er¤y’å'!°K*s°P°R+C~)lBų&­4iĀØ¬ ļą½£¬S#ÅqRØ)Ǧ Q½Ā';Ņ,7j~ŒēõōėI„“ĖE«5<Š<ĮŖŠj%Wõ&Ä0–RÕŚjÉĄ˜sq¢ÅNR YQHŚ%ĄĆQQ@Į„ųč2ŠcŠ.(`"Bj„ŖEqIŪ„“@aĄāƒ5`CŠ.ÄBT®YצPYó‰ČKŪQ"ąxTźõō3lŠ)qŒś”Oˆ\hjn»†|Õö/š" !D |Īyx Y\±danĶ)Ŗó¤»KMZüŠÜŗ&ičäb\5ŻąŒnJ -ų;½†ŒŌ’µēĒbĻHäµ&W€j„ķÅO M ŌX­3”{§F¼2"ī0 ™‚×½†ŗ‡†9+ļĮū„fä'A’6ł 2¼Źjõ„&ćrŠxq( r“]HØÄēČÕ:åė§i–ȽęŪKøÜ +ģ0o!+±M°Ł!£ ØĘ`‹V""{Ķzžx¢%b{KH°µót§Ųm^]1lŅRļ-ÕŚXÉŲ}ĘŹ m³˜yŠ6sĄ™ø/C©U4•!’Ī(ėęP`JŅń‚imÄ27š/6ōŗ¬9źxĪˊ*mZŅ‘µĖš)µŖŗ¦y{ Z­³Ā°Įn[Qā<5¢@ē ”0Żł”z3‰kė¬tåʓÉlc’tsn{@$_{oś‚¦Ń0Jl\5‡Ö=Zx”¢J;yc‘¶Ēłaū„iăicOļ2¢Ä¶ŸŗF¹g¤÷I¬/)Ō&˜Į^¢‰%÷Ķ„2čL2e˜ŅeŻ~S3¢pé$?”Ų·ć£rm›pls’1’¢uŽRžš9ՙc;ö†Œ3&Åuī«e1‹ī”Ö=F“ÕȲ'+‡ÅĮ”gˆ”It#ĒcvŒīQyTĆŖAžĘy„ĮÉĘ«¼WÖ5J.=E†=čĆ·ÉVŪ%a®ĄµH/*ÓƐ÷SÓ³F–Ē:Zm‰ląé¹‰SOkKķÖ5·¦aš“u©¬De/ Ņ`;õTÖD¼Ź·¦°q"ż YO–`·•i—ĶE“›É¾"ź=ä?Ū ŸÖŅØ½Čł‘Ļ®i½æ5!5›ČK©Ćϵµ¾–<Ф“Ś»•ī>wYxų0 Xóšaščķ©rnbć=͟Kć=zHMQWt`ēCĆSdŹ×ŽÖ°¬ŠĘ÷ŹAN:…®§E£ŪŖĮd0›ŠŽP°UZ™€xLƒÄ¹s‰uhš&Qć讑Uä¹ ŗB=9ÆT<Š·o×~0µJVM¶ū7ėȓ¶QBg_žbēÆD=k2ŃŃBzécÅ ß.§ųŲ¢iģv|[}pĆff1öoO“ŗ³Ž±`Ō)޲ušś6:øæ;łķkü÷ zøč?öņ[æÆŪ—÷§/žēĶ® ÷?ćyWń^ƒSż9lģŘŃxL¹ū‡ÓłµĖżo§Æīͽ®xžu’xńWՍü)ąq2#m /BŁ£ (Ųw’­ŠŸ«„ēČ"-æŁ_<aw%Ęė®Ūżxś«īōgI™ĆłõĖŲLLåü†ź±øJ:æ©ź’š|µ:FoiöĒtU«·}Żé£Īl¾?æ­I„”jŽēæ]īōń•K<æ£ź’3Ēóæ_p¦åĪļŖ2å”Jɧ”ėL¾Ęó{ź"{­cõüƋ ¦WĘĶģüw]QKō²Ś½ĮEĻCŸ—xkŒo^ī°ķq;9ĄłöŠŪ]PÖcHÜį¼ó½½>MnĮŪBć"ēvgƏz,I±rF’^𮯒ϒø`rÖŅłŸŗŅG„¼žĪ·z‘בO.ø(f õü©ŚU\Ī«–¾d0?p>y­¾>³ŗ*‘¼šČw“Dž×µĻo«ē]’ö*„W-^Ū²¤9±øÓ~ąr[=Īžu_|r A”įŐ]Ņ^ᘓ”G”Õæ ńPĶ!W<†Ą¬Ü]üŪŠ÷|\±0sī9ŲżGĒ€?> stream xœÅ<ŪŽ$ÉUZ×†6Ā öd­wXØŽ1øŹŠéøGĘ+²„x±5’XžŪõXņ>šżœ×™'*«ŖwaF£©ˆŒĖ¹ß"2’t³TGĖēzŠĪŪ£³‹=~|0¶ü~Iæmų;ŽÉæ{ü惘…–F(kišę)”ßüįĮHįf±Xๆ…u€_Ö@[foŽz1aö Gø98hk9ėptr±³Ēē½(5}tJėYĒf6°¦ZĢl“½ž½<:-ŻlTœQz`Ģ|Į5ä,<Īń³‚9>ØŁĀ®J-sа†Xpw'm˜ƒM»Ę_Nx9˜ŒšĀ©"|FJ=;lėh3Œ\`$bš9y4Ź}bź £³ą–BĢŹćŒŚc–Y;$µņ6õH‹«ĀšzVĄ 8Æéłüš_Ęh7ū±ōę[ć®f¤2‘Ęf 8;āāĘŚ/³Adk€*=‚S@ģ2@Y-ŲBĮ’FŲŁrZŁY"ĮŒÉQŚpĘ2;d€Bc4EĄ H­"ĮJvĮ^°«Ē:4ĀaŒømPr¬P}~ų=̆€ 9m-žč+ŲyQµē„õ(ż¤G‚ FĮĪ ļ}ܹ¬*½™—læĶ l­ČȂ}B!GAŗ—ąłŅó’{nķfkinhÜR*™¶ł­«J ¹Čž~ŸøwŻI D@«yʁ@ÉŌń›ß!i¤rIŖ‘ĄQ2Pö“­=F DŲF†ŅVR ®Ž„GkrECFĘ2=>#C&3=(įĮŠYLT³^ŗaf@ Ś6j”<@0@ęŌBm?“}RŁ9ćü²”ĖK¤h˜ˆĮ£`$=2Ś#ADLPŃ KvVZ Ōõ9ĒF@¢ne@µ}]'€¶ dt3-­² ÷Ԑ¤RƒöE©”ȶø§ÆĶhs@fl -(ŠÖ‚ ”¦B¹Y:@GCóÖ: V\Ö7Ńčå6ĀˆęŁ“DQ"Óš¬ÖFHUĀ*÷$B¾lH‹x‚­ˆ“m3‘ŲH%ķkA €öEbØł2“3N9¬‹Ø£\€yŠfŅG3©P9mC>dŽä©ASĶUZ0rOV FS#䒃_J³œžźüįŅāƒ<żõł ōČäåéĒē'HŌĄéÓ§Ų ©Ø³žōżó&¬Ÿ~‚?„Zt k¤-¤‘”GU–Žä“5ßÖĒdĪŌ†~ļü„F8E÷<|^§e°!Ŗ>żąünt`?ļ ‘Ż‹…ģõ¦ķE “÷ ֜~z†&XŻ­@@@ķl€ĶHļÕt9ä­ ü ĻŪ/²üaÄL×f}ˆO_œ’ćĆæ>(Š «ž„…Ģfłņɼœƒä{#Vų”L!нkkž 0ĘzmN—(­S)čņ5^S¤§/Ā+ąE[÷oq1į,D˜š®Öp Äö†ŪDz’ŽŁ<>FĮ€œ—AĶK”čŲi:K,Æ8¤-2äI¹·`Ÿ ēp‰+%ż¤j1žØŁżŻāp-|7”PŠ®Æ;=¶Ē_Eä“Wä1Ňp%ɤޒ7TA<„+ yש`Y¶CRSHv|ŽÕŖĪģ°²J ¢rõ `¬p)FÜ- tXI*ϳ‘\)ŪWÕB“‘¬Öļ*Ī;–k‡¤Āe:p¼Y…æĘĖ¢*:²Rj_ß°v&8pxÓ”„ļŪŗo9rL,åHļ{tž!•6#Ū<ų†Œͺ䳬T§)š .'„¦×C¼Nōś¢?C?Żū³­Q"p|ÉHķĻą—-³IB­„֍0µóŒ+©Ž®ŗ$-Ō5" ?­Ūm]£ z—ü×Xßå{žžŒŃSX EåĪXē f(ՙ’Ņi¼tuØ<ˆDaÖĻń—FW¤Į°“:ē5āńÕ­}3l-'>’¬v¶Ē_ŸĪXŸpÄ L”F›ö·>%V:?żöü“ĢFyo Y¾ § 5zͼY4¬ŌUCdšé ĶäqįiŚ(&ĘĒŌłµŠ¢ķNŌb/ņ śöČŹE7ÆøōåM޹ģÕ^³Uƒ ~"Ąf¼iˆ:oµ$Ŗ>u™e[ŗÅ@G^K¶é¼ M‡wŹF1ßKY»K(·Õnćz§VvžAVS1CŒYōōX„¼ ’ŚbC„*xĄ»(“Ŗ‘±ŻŹEßńw®–õ/šĖ(Œēe¶jm,™¤g¦®ˆž”0E×@zY•ū“3•ĀŠ”Ś4 æIqx…%4¾VwŅ5ҽžČ[ÕĮH„=oBČŗ¶21MÜü”„+C)&¬Č2$™5o3H…č]ėĶką1N±vŖeį™ķÄT¼Y+*?՝7l8?L-+!×5+Ī»xæĶŠŃ!ÄX-ŠŪsąnyWjy+p÷tŅ%ŁtKZ‡·— ±°vap~Üėd RæĀ U;L›ŚŲģu7𠐑Y|®ŻLŌłó%ʕ˜};ą–zŹēļ.mIJXčj¶×T4¶ü¢öኊF1FH?kš)Č0će,br½Ē.mæ3¾>=æĘµs5ŗ›!²YO^WDņŻQc“‡V;d 7¤Ŗ£0ģŹZo˜ŗ('Ł km± ź|¹Ś#o°†,ŌÕö¤‚øżė‘‡Pš> ݁ļń6•&j ŲżxĻ`A\£¢z;ėÅz&„;šuéĮ±Ą§hü"Ce”PˆÆÉż6Åtą™  °PoXEø#ŗ­.`.²Qx¬žėøJ= 6čŠÆĻ\†ßŖ5»Č{֘3BXĢŠ'ŽXź¹r9čŻ+•]QŹ»¾J¾kX[”Š?(œ?’&Y‘EβU.Ē^…ń„²ļ‡<I,fš³,ģQ {œaYą7.hĻŠ“€~£§…Ōh9LÖÓV-~[õ“+ijU”OæØõÕrāŽĒyżaĪ*²)+ #ƒv¤[„—Éź…õ©­ąIQP²[6±Ø?¬ˆ6öżˆÖ˹šäĞ:_SyŲņ*§Ųe½/Šä±˜…æŒqx˰‚č;]µĖ£ź­:bz•+ £4¤\ģ(Ŗš‰Īēź×ĘĄØĢ[SĶž¦b~yž½R{"H°'`ƒŖūĪaĖ¢ø¬‹śü dRAŌĆLŚąŁ;pī’kėEæKžoKß9W?(0ņƒ[J1ˆŲuÉĒM˜žx³FH ėŪYzāŻ ’&>ł‰Ssņ|brń²MŽŠ’ķįĆ/xßßßH(§7ŽRŪ©e­Ąö8 “V¢{՛6rT”X=y%„åuAEY÷Ęąö‘Ž)ĄÅ“öqGE®°¼’÷ęT¶ėĪ¢d+ŅJ{?©öD™jO®°©ķ Ø:üA­cPx»|<²­£KŒCŻ„6„_ĄA÷Ü;ū‹g)mQk ”II ø˜m¼Š›ņ1CÕRģøå p‰kkŽč•÷VØpȼĪXć|)—ĀŅŪ[ž}CĮŒ¼é¢ĢĪE”ėøWÄב:–µ)O›– 7Z„vŲĒ2¶jėn•qߐ·_-[W\£nńźŚAįž[uåaKŸ–`BŲėo™“DŪ-tž<­ƶ±*qćm,U« {xĶwwž w¾į–<ÖŽ«Ū×½ā4»hgbŪuŒ')fµø…G›Č)Ķ>¶» ółIćVĪrėėÆĖ¢éęRß×ĖéŅכ­7۽︆“¶@\‰ė†ņāD.ʱ°¾² ģF 3ˆ·j6ˆNu[ųAõ£”3ՊšŠ]ö°õ~)Ó½=!]å¾ä'/£h»dĒżńTŽltį=?¾÷„.Oo©źĄolo¬GÜUöž’9x~ *Ę*IQ-˜ÜZ—žæÅŠ?П¦=F$ŽÕœöxtyGˆ"]޳ĢVŃU I œ‚LÓæ¤ōU}“¤Q¼#ŻśÖJęŃŻ‹W§āM¶G.ҽå¢éš‚ĻųīŁr‹īÄ Šb“{bÆŅńššń=¤=6e„øFÓļ^ābÓš@†ä\|u›sķŸnĄśl8%±qošŠ@ż ̼˜ņČĀEŸx²|oōÉŽŪŪ»RĘjÕ¢HĢ…5d|śréĢår!ķ)ˆĀ¶AO·RĒf!É d‰‡Äl~:Æ*ń÷Żotl ߯͋'Z“:lMÖ6Ā^•Š×Æ”ö"–²ö_rüNŖØŸ.⧇\ę.–"/½Öƒ|}żk=£»kŻ’~UMa"%±ǘoćĶĶ‹a3K–‘’³TflĒąč|$Z%½M“¢÷ŲöWžm\į^¾±ŁŲĄōŻ{sāś7T'>åĄ³‘I×DzķāŹcjsūKF…ŚōŖĄą8b2mćÜln_& ax¹Œ>5-š8%$šK©W¦ć£2`7ĘM?>Kš³pŽŽd&ʶæQļūō2ņ–J݆,Ū ¢ `^5WĄWŽŚ5Jn#-ŽOšKMÜ믯ƒ0\”gĖČĶŪļ׿ž$„œįA`pJŌ — r"ĀEaŚ,;ϼāĻZ³TÆøŃ×β!;i&’ŖĮH5Æ—ÖG n$`ąļvŹ -šUņ…Įf¦ČZ|bÅ:{ā·tzl@^Œä?VЌ éįR%w|O¹™5VłIƒW#·ęüĀ‘,k$Ś·EJāhg+mr²zUž ÆHē#·¶k·÷œ€ģ& _ęh6ŠäŃ}ÕļüźĖ:ŒÆJ2•erš8C£>Üż*Š^īø„k*‹$¢ųĮ„Ą÷\‚p—”xå›ż ūdzƒ,)ŁPįåž }Ć*'½œ²c^.eŸ÷ß9!»rƎooā—•Śœ®¢Q.·²oNIČõĒėøIāz‰kŁÄŠĻ|x«KS…CŸOs¾†ß­õóŻ›Xƒģķ×ĮXž>Į=՛Q&+ŲoæŪ“ēī¢XE6¾ėUģ_¦-¼m€_Żė M¼ }’” ūõ¦ø>0,ƒŽ·ŠÜ”oøģżøŖķ-ńöŻź[HĮ‹^{ōŹŃHäŚīĢ+ä&śąż?¾,té“°ŲŸEXĀDłeŅF…<©·@~XžĖÓ_П~^œP&,R ģm€l?HwhƒÉˆÆæÉĖŁÓ×lŻd¹¾±C<öm°‰Äė‰ųśOņl?GA&”&ö¤l+īŚ­Jź¹ęĢĀæ|ĄO3āWō…°!~E?~Bß üĢo~5~öĶ5Ÿr~˜Q¹?&æĢŲ ŸŚ’ų@ ųķŅ7&@‚„wŻ÷&Żø_­¤|ß[ŗm~<~×W’z 8‚9Mśśõ_ĄäɆÆĢ-åh¼nżė‡’PŸ­pendstream endobj 16 0 obj 4946 endobj 19 0 obj <> stream xœķ›Ė·‡‘ų%ŒŲyX›DŠ@™A0Y,¾®¹YX 9§Mģ ˜5`ņ÷ēWÅn6g5;Ū#mģ}ID֐UÅbń#Ł=óĆ`£ĮŹß©pq¹śaåc C 9 —+SyWĖ”X)k›±ü÷įū•5Ö;¶”˧Č1 €~dżšę»;ĶC“Ÿ{(ö„ĄÄl>s1‰¤E4%¢īńeˆ.cŻp±ņ™Č°"yo¼ö`ĆŠI™M(Ø'o’¢wŃ0iI‚č¹ĪŲ$}’!ōI…L€U¢lЇ›Åzt”˜ŖU-E›œaō(L†ÄOR’Ų9o¢Ō}F Ѓ]FKü‹n`Jˆo”‘Fń‚=F–į·³ÖP’MĀŁų(”¦ŖÄŃ Žxæ1ę«ń¼Xż{Åģ£IYF«ńĄä1ZŒ–Smģˆ5Ɯ‹ōÖ±$ÄŲ§lXŪpÕ%qDŗH€Įt1āa(K‚J¶Į$ ĪS0NĘ<„ąZ.Ņ#›(Ó·4ģ „P“l’8LlĮŖ/IŚFW¼ųĮą—L[ĄŽ+C½X}‹>˜$Rō!Č’>Įr¦&ŁĶ²E¦æ“8$|`‚e'OI-OZ]b“ÕŁ}3;˜ö9’EfIfŁK”ĮO’Ż(‰b:šz‰Ćlų„Ł@(ÉUSČߦÕ%øuzöķØķf‰¬ Ą“ɈŹ•BƛIhŚÕ`Ķ É=š„­dD˜Ć0ÕÉYYk÷$ń>IŽkj8Ų’É?ve’H$Ć ÷½HŸ÷$– †…zŠUH9G¦”VæčģTIgyóī­øģ4VXaV‰$±/;‰Sv°Cа¦ Rƒ%ZüT…eņV¼nŸ#ŌmoŖc‰”ē¾ōĢŚcŌPŃ:ŪØuép×;«w‚Vo&&ÉäÄØ`ņqŗĪVż4²ąz üԜ‡ģl¾ÆĻ#%’\²‹Ld£wŻZבy=$“8ÉA„i˜ź³&½˜4L^ī£Ž-’OöMģz2¶Xa£dW%žšDėĀ"©Ė‘ŗåR§+ŠĖ®,ŽXŁ”wU 8įń€ŗģ6žžf¤Ns]U=™Ģ-‚lŠSżæµ…} ®©ŻÕӝ£¤Īżn_ābķ|7TŌŻž‹:õ%ļ…’ū>NO„³Ī¹Ī~Ņ”diH“•«gH©§Z­yOķć\ósHUPśč Ÿu5žĢ­~1N«ėZČď>ä½z ]¬:Iķz Č }\ݐ‚u¤„&"ā”Äcf¤1—¼@S%‘jŽĪ3ŅW}[£@¶=©śŌ§ā^śŽĖuܘźH.{IŅó·äq](n̾Ԫcžņ^ƒ {Ķ^hæCŸZLÉ7×cøŚ£Jōt¼ėuų›ęÅ“~G7żŻ6Ž©Į4N6“W×¼x+6īÆWvų ’¾ĆEgł£7æ¾|q9üå|õņUōøpž-®w÷5(•ŻąHoŒ Ź_®Ö?ۜ’gõ×sQ/7Akqœ’› ^£uš÷ÕW×öf™;8"bĶ,ĢźÕH✌“ƒ;Æ×?ß  'ėhżĮf‹ųäĀqż”qÅ+nżŃDŲŁÖo¶ŪØ/Ÿ‹Gø@¦ś9—֟l¶øź$œl0Źœ’m&"č`4kqŠr=lKxoKŹ<š}o²žtėg֗ÆHBŽ{lŽ“ŠŽęZó”6?¬¼Ų®éėõ/6HÆˆŪŁśó Ģz"’PČż wŸõÆ6[hGŽ&·žåf‹#lN[ Ög\’V»9vė³®ßo¤č(ūŅwū|³•kSŽeż‡Ē¶E><•ޔķ¦O2Yž­$YĆł?‘?õąīk(ļwI!ŁRŽ1Ž7’[\­l¦øvźĢµ¼ćÓnD©ÓĒyŅś›ļ—°tn#K[Ó×ė?mdGĘߞyæó „äūāGĀՐŠ6ą‚vX}.ØÄ…/ä;‘÷·ōc­o]?÷ė@¤Oؼ-Ž^$4ķhž€5y)Įk@ęµ’ØgѳM”ūÓQ³Ī²>·kźŽ[–ē¹ņP”³žgœĄs ”ģE?Q—BĮQ󄈝-ŻuM¶‡Ž«ŻõyWžx#÷żcĘ„%ē§sėOAzFÕGi”¬O,~W²žÄæ…’Böņ¢é’ =€³¾EģĶw·źfŽgIœ8ŗóćļ6ņ*œJX{q¹€›{‡Źi_ )‘±ēąĮ“h×i€ŃMą'žx«·,£±å‘ŽŠ#Öųf¬-e‹`-&yb{kį$Ŗ5uĖØÖY_Ŗ]sŅ{1Ćģ4®É7kģ™üū[:kdršO\{,\;@øOn!g„pĮŹė³#„s'®©[FøĪśūīÅĮW(gßl ¬Ą =Āīņ «—Öb¢MoVļ1Ź®&Ā:}”Ą[ˆž÷ņ„Ž#Ą³'Æ©[¼ĪśūļĻfÖ³ž­ LØøĮŽ…Y¾æ„[~—ü˜oŖƒ[’!Ÿ×Ļ*gä4Ÿtq7Ÿā¢E ę’|łšŌų$Ø5uĖ ÖYļNagJ5/Xš°Å9ÆĻś«h{{Ššlļ0æ~ććÓ Ž»¼čÕ-õ”óėtŗ=[N·…ŒŗYż™Å±— oNĀ[Ó· oł[Ą[G·ņ~ĄļčNLčż-żØ_ZyŠoV7ŅÆ^Rå7[yŹ„ö‚sūģćĢņ›Ó#ģūōōĶź”Æ·~3ś~Ÿ8XœŠzŽš]‘=2b ¦Å–ž†÷Ö»0ń÷·tŪ_|~Čč{㻢Ļ-&ßRžłbjæŗ8L¾xłšŗeäė¬ßL¾kŽ®öĻß>Üd(å®^)ŲčnL÷ż-ż?–éćDßćŽRōŁåč[ A_żėŃo7įgĖ(č¬įNń2v~Ü ĮīĶŋ„̦ÜÓšĖö,Æēāó/7[łi,Ū§³Ž]^°źeÅcdß”Ēy¼œn‡Č²÷³ćDą*_öżõź™ŃDendstream endobj 20 0 obj 2575 endobj 24 0 obj <> stream xœ„YY9bą‚ų õXq=Ž—WŠh b&j ¤„‡ĪķĪ‚nw2džæ‘ļŲeūŌ-÷MZQ—OŁgżĪāź&)”ž$żŌ‡ćĶī‡ńĮMŽE7Żģ¬«Ļ§ņģ’¤ē¼gyžĒt»“Be„öąe‚·Žįē“4ÓŻ›UŅ '/#Ž06 OĪ‚ā£v2Ń&4ķš"y¬&M^E'¤šŽ;µÖL^#L>a…O­p ė`DP“7Ź «ó‰JĮ œ<%d 3Ahœ I ©ZG‘ xČHҽrI$W¤ę'/ƒ'’ÕB“ž:ėg•2ĀÓŚDų'¬ŠŲI–A?Æ&«üėÉROZXĖ"ōVR čD£Ų(Œ'Wėą E9ā žFhŅzĆęswowÖ/B$k³?<‹] ÖŚˆ›UŚfۘčt¶%ĄĒ&DaÉŲF€Ŗ*"t„dį„ĖĀBGZĆQ`i„Ęķ„"‡Y»8DCµ˜čDžĀµką ®ÖŁa•¢.ȂT“ķõ*ŅĆZ½(l&Āg¦wÆq¼qŽ~Ć| ÉQ7Ź©S“L~FQt°’9>„,¹rUĮŠ˜•]‹9A“IĄH$šŌQ ;&OĘWŹi”xķ…sœ¢  øR«" ųm\U€j>‡g-'Ėn’“$Œž TJzŗ»&×(ķ ŖÉĮ„=ćÅJB„ėnØk­$åģ®cį>CCåĄ(U?«¬§ („šdł©EiaāŠ"­€YX»œ…vĄœ)µõ‘É)&y±ł“ńĖ)ū &sEģFQ¹vXˆŲ @ˆAŠ&S—¬$­Ū{øĒeErnYm‘Ś”±£Č6IN(¹ŅjÜgUSA„AöeT* [–Ś2×`Ęõ Ź!1Z‘T©KM5*G³£ÖSyAµĪĄŹlĄß梷¬IG*Ļķš€¢¢ y*Y}MšźbÕB)ŽaÓėŽ ¾¾öīüD”äéųÄy˜ā›¦EĶßEMS½Ū쨪VčÕ:Gšøń īļwrś’ßą¢‡Ł€žå›>ŽLŗŲ}ż1ķŚ†WÊõnš†Ö 6™Hŗ\Žˆ:‘ēReŹ „Ņ ‘žåwyOcʧöt_H4f)uIĪÅ÷,9?°6ł…pĶmy€VŃü0a#ͲÖõGĖ;ćĆ©ōHµąÕ8ą¶ä"/ļ™aäų`Ģ-–®†nćaē!źiÕ!ņjČįŠĒą¬īPą‡]w˜`ģŠ6-iļÕØ’r­?· 7£Ē¬Ź*ĄŖo” Ål˜lĶŠi”7,YV¾mhõ‰ēå@dóS˜ēcR‰DŁ°ŗ=VØ6‚^#Źų÷ņµĶFIUÜ5LŖ Yóé]ž{&ŒĆ]”ÓHłŽę®Łóe飌#ŃGÄA‡Übb5§ötdŁś·½~ødXś‡“ĻÓ{Š=ExPä9˜&Æ<¼ŗål”!ńāŁīā/ʕķ]/?ćģŻb…ń5Ų¬Ą^"Ņż2f]Ł<†®Ū:cރ āē—Ķ/ 4Åįž»Ā qŸvU@D•ž\tōė‰WśšŽkw”ō·Ņ‡ī Šžņk 'n^)Aģ†0؛÷ÜÅ~ęa&|²½’†pB¦šķо¹žŒę¶.`x{]µ'Śé„āז>+uD£Ń€B[Óį¼¾KśŅbx}ęłåƒłņS›`Z=`{ģG^=8ńņ^‡°GŹūč Ģč;;ņŌ’’qü=āĆ0:q—$lŚ[Ӈa9ą­“¢„Įl5rםCéO’F²LKHżL–†7’m­S‘÷Įįrāh0šÜćņ«‡½ĒjÅūQDŗ#˜ü³|±1Ļuķ«ć÷»’źuIõendstream endobj 25 0 obj 2655 endobj 30 0 obj <> stream xœĶX[\G˜ėAgc’L"g@{ܗź[øIH(ā%ÖJ<Ų<-$ĶZŠųż|UŻ}ŗĪĢYļĘų[–O×t×õ«źŖžjofėö†’öė›ŻW;SŲĒĆžfG”ėw(†æeOūžŪžåĪĢĘ[2.‚—O‘bĄĪ9ć÷ƾܑ5q6yMĘļŒ}ĮW Pbžķ}¦2'Ē;ā\"ÖŽĪ¾ģ£Ķa6v½óٹ™ü>:ļg/'h&št™ęP°N~Nv½399Ń)8“Gęag“ųLšΤāę©Īå¹xš0™„GŹ\B•*_Ń$;Nr³c=čGÖś9ņŚgų'ČfģdĖ _“{r žlid-Čò ½­1³K|b”Pž}dW»*Åę ž~v¬ō†Ķ§ž¼ŽżkGäćœ2[+ž@š» ¬„T˜YGācŹ…O‹- >ö)ĻÄĘ.Øj+ĀGŲA‡ \Ģ.óŽK2aN0Ī»0[vQsˆƒj¹š‰1īV»A鶑„ČAŽ 0Ā éSėfŸWC3ĢĀ:H:Ų`sn.eY_+9•¢$7›g~9ŠÆaF*Bb`ß(Š•ŚA!  Ä E‹ļKHvްÖĖļpOE$·ČR;-ģų²Ķp  Ź€TZ€{QµTTzdŸ ŅrŲDfZ–Rs€™06Ų€Ä`heV„/×(‰f' G)ryAµ` š')zmĶ:ryNjG--rÉkÖŌU«„:ņxęZ¶µB|ƒl#q6{ɧ…B\ø¾8ʙo‹į:]ō:1qņ$e2I™tœœū!Ź—›¶”RX”)W•”DĻ)NT”Rcl®7OE,Ō6ø?$_*… š(’”6rz¬!%Ō|jʞ€ŽD’œųLZPƒ 3EsjÉÅkĄŁŃ²ę‚*uś-”.Å€ŽŅa¤ć‰¹’&>Ō:éQ’‚DγKżBYŖŗ÷”^{};&]÷łd–C-­CF]ó x€ŌܬŽ*ĖzŃ)]‰Ę ėø¶B®Ń!ÕwĖ‚Õč)˜‡Ül^ƇeĀąā[¤są‹Ž*¹u-–yi–h‹øQY8ōõ±PšC×rmGµ-:)x|oāÖcŪbmĆåX)Ž-Ys-ā5'Æ U—ZÉ@Ļ·2+bųR>V‚”j-Ö|Ūx²ŅĶšŚµ°Ņ™Œ/č¾žOŻa¢ŽAŚjNx6JżqM±±ž ^™Šµī¹®”/yåPbŌg¬t„ƒēX“ļ<„”†Ōy%é!yź²āŽ-?ēŠ{ÄŠUBŃŽĮ9c«?‰–õu «U;8šM‡¼ZG®B×;E 죣¦ 2Č[Æ@°ZZ*˜ąń;ˆ2Rƒē¢)”č*FGDōŅ/YŠ|ķńŅ' Å|[ŗ¶‹©Zr£)IśoĻ%j¢Ų†¾“,~iµ!š]³Z;·>AĶō¾£ƒo¬c8=Q)Ņ5_}³hŃó·©é»w;ś†n'Ķnµ–^Ÿł† ÷ē;³’ ’¾Ä ‡Ž€’Čä§æÆoöŗŚ=}–öŅ.\}ń®`^SžŁī­“‰1!šØrW7»é‡«ļž|Åģy4ķO‚2Fc”ļ³Ļn’ķÕżŌA-ś 1«>®z}2`ĒźüˆÕyś ^YŽXF †!³æśĒnŚ× Š%'']>}ó”ŒuӃļąŅōīį7Zł,˜sŽÓl—3©„é[¼CdČÓ;‡KĪ‹äģōŻĆ%Bf¬'8źļWižB,„‡` z•\ūõ’ĶMń”UÜpgÆü„6ŲMϧŸCuŒ«Öųéƒ×µ ?<$Ėu&³¦OŸį.øß×nšė^}ÅhńÅ/Čņ0}’Ą„09'>ōčk’„é#P1CCląÉ܄8~wx‰Š|‰Ó‹—lE_86(¤?޽s@?YŠÆØRiWĢŚÖ˜/¤ūfKŁ—apLŹ`#õQ,žįI1¢†wĪČ_G”¤KĢ 9;ż¤iKм‚ E12’P:†¾ÕŽŹSūōĆ%Č_5·ń»>õ¾Ø`É6eųkÅIFJS¦÷–Ÿ›üö›2 Uʱ ĀBŌ9¢TŌ!ŵ…ÓRi#ō?ƒ„ ŅG;U›ŗʧå * Š™fńčÅaqā§Źˆį9…‰é Å®n€ĻĒg¹TÕįF)ÄĄøģ!øä;£†įɈ؂eÓ2Rņė$Ms1Ę Z@yą«aę÷Œ«æī®~ż|ś-_U®l–…ß1BŃX!kģ|Ÿ“Š0 Dö”ONÅšńB;‡ Ōš&ÖbŠ+Z‚²tĄšb0nęĆmi·ČSšz92’8£w€HS»ß¾7ˆ/^ļó¬^©šę„Ė$ņ®W©lžüRH»čāŌĶahŹźwSóŖoWš‘‡ōwÅś^ŽbĶA…žQł=’Hį~³ž“tBuŻtÆN攕¦*µ•,½Ceģ$–ó&e-Mg2–ßÅ£žWīYAų֝{ąŽ„E å·RQā¹—%čfr™~ę)g”}}*YŠ×ƒ3LI¢ŖĶ£ż īŌČ»ŅW : ‹:Y‡Æ¶½š*~Ģ{t|i3Ÿ•G`6£yV×=Ķ… ±ŗ46mz¤Ax”¶\ÜQhō¹Ķ;H9^鳖 ‰Ļož.œ·źŌ¦ĘU¬vź nŌķd½£ķPn¾+ Ź[·ō—[ŃUn9¶©ŲYū[–ž²&ėŠW©Ś|žöīžÆ‘©į’1Uyēv<ĒĖąņHiš‡“ĖõčīJÜ×¶‚ż=Ą£ S,.† ?*H剘C–‹¤éܙūł½„ŻR3ŲčŃVųŅ}«ęv˜ŖZŌ»ą|^)ŲÅŪµč¬<šÖĶģ;ĮÉb³Ą`· Īż2ėd°l5:Ų¼»w7ģ²ył²Q›ŽØ¹z“]ķč†b‘śPw˜ōR¶·@±7šˆ,å^œß芦üżžĆĢiÅŽÜ ģSAY]lŪMŃf.=Ų¼·t n2»_7Īåłön8› ö}(K ŽĻ?Ŗ[Oq5@ŗéź3°Iē­7A•>ä;¹ųŠé—šhz*,MqŃŖIKķ?ņĆóšćóÜÅłŠ]^uĄ–‰.oæā,’īNÕ¶qxRė1Z.õ$”Œ;W?Y“Jė÷ŖU·XØnģ¶ÆQäe‰bQW¶nÖījß·{†ļdāvŸq^OsP ;ķ4䄳óŻHbŪendstream endobj 31 0 obj 2935 endobj 35 0 obj <> stream xœåZė%E,²ę²‘U`–‡Čå”ōEoSS/5TÄæ@&ńƒųiŒ™%žżžNUWש{»ēĪģ £»Łl×ézœĒļ¼Ŗļ7[5j³Uü·>\<Ž|³±>ø­wŃmoČÕēĖņģ’āēŻk—Ę䏩łÉ« GŠDf4̧Éü‘Övō<¶:Ą Ņ3Y2šēõ–L€~=Kź™ ²,‚o­ŌhƘ)GėYÕ&øBюwŞv4Ģų†Ģ‡ś¼ŲüsCdż"K›õćf%HK!ńn¤ eSL¼:Ė cāH,ģL«:0#¼„DPĢEŠĒh"”(lIŹĀYćFĶ #šbĄZL¼"ŽžĶ¶²P‹ĀŖ6Ya•¢a.œ…Sm <×ėd™"¾Ųl"B¢^l¾Ä@ņÖ9žāœĶL¹l£›_P4€Čąd͊!Ÿ\wՁƘ™ķ¹ÄŃ6#‘iʰEī˜< _)—ÅóŃ~tNR4¬a¬U]Ž~ē]uk>›§?'Ÿ=Ÿd `Ķ”9J§d¶ßžƒU£/Øfgd0ö¬›)¤®©”ŽVģk»R¬ Œū  »@©ü‘&ĻF^ 0ĀÉU mF;Š¢baģ²Č`sfLi_ˆs Eœ<É|y¤—ˬ+x˜Ź!0° ŠĪ±ƒ4 B2€M¶q²±Š¹žßC=.3’}‹ ĮµĆ¼/€·)6tBȑÖ8ą>³š *-¼/£R³Łņ™aę˜Ģø6A;8C+2+uh8FekV|”<‡Dė ¬¼ ö§ō¦1óČį9ˆPŌl4Ļ!«™SS¤š(E‘—GŖe9+²nąm”•ĶZ²a¦GŽ/‚±ēė¤8Īxć-›.‹Īø@xŹa2ä0iŲ9·ķ@0Ÿ&ŪL …Y@(ÉįŖl˜­g,ęP£t,™§ l+äģ/…B xĢ'ƒmųtćWüi¢0ö2蕧lƒ#Æ 1Xń¦0b “sńp649` JGé~3„žb@GaŠÜń@Üģ&֕8i’\¶œe•Ś™2Guk]I{uŒ杌ū¼2ęÓ%“¶3ʘW@$& ³Z-6˜Ēó•R™˜6Ø<öRä4ŚNµU2§%|fĢćd6+ĒM²‰Āąā,RwąDÆÅ¹eœ%³¹H˜g ,āBeŽ”ŽŪ3eā¢īP¹ģå(²y“ēMd=–Ķ—2l¢\Š53%9ń˜„ĒŠŠJuö@ĖY™Qœ”/ !‡šJŒ9ŪXҹšį±ić¼…Ė•I›į8A×ńæĖ åå *Šćp°ēD)¶æģ)Ś—5Ī Q1ÖM=Åō)vźÅ{¹FēŖ“ķŁĘdė™”ŗP÷ȧr ÉćP†÷f~ īaCSIjė”.ś$šĒ“Yµ˜Į†ŸxˆŻŲsŗŲŠc]J "C^£K ‹¤©€ w¾‚xBF˜°d9hfŠ7£Ķ"rhg/˜œöxhƒ„bßÉ]§ÄT$y,)!×ߖCGŃśĀ<œšKŻǹ¦ÓÆ Iō:£‚ƍ½;\Q(¹:¾”{Ų¢›™‹źæ›¶jw–£NØrŅhŗq¶ąÅ‘n8p¶QŪOńļ+4zØ ųOīüäóÅćķoĻ7~¶¹\8’ķ]Bæ†MłµŽj“;ĘĆ#Ź?Ž ĻģĪ’…i›Śt„­2=©­G-„²`žśÉ9sĀM£RؼøiĢ£W¢}žéś»oÆĆ¹Ōń޼U˜1Eė>»ųłėšć¤‰Z+;¼¹cēŽ–@ š-žķüOŲqmCNZFl8l‹.®ą"ø‡SqšöĆŪ»=ˆāšĪn“OĮ Ļ2SämŽŻķQÆcµŽćg«‚5ƃCu˜lžćE1m†ŸīPnŗäĆšg`Aėŗõ‹ĶˆztųŽBē^÷w,w±Ņµń‰—ĢÆ)"ī@³ø?ŪķXōqųākœm}ŠœÕ§aœw!kŽĶ@š‹:_?ÜķįU½»XōžŽƒPķ>tˆŚ Mļ$Å Ė=š>‡|ęH:’{f†‹D~x{% f‡—w{“æ&BćgĻ€ …{?<¹Øäq„^b;9ī–äć÷XŃē/Ī»=ĒāF„4?“Ķ–xu^tvŸåEÓĀņĻóĮ¢M_ķ½X$¶zøÄ@cUĢ\<镫g6]žOŃ;—†ˆ'M»“y?ŁķQT£„ į7;.L½£eŻ,jQœ½Ż”hOĪ:,‡u5°2¼9å#ŲP…»“k~TÜĮĘu5•"wŠŖąä„čæföˆDzĒᙢZhļU9\µŹłį&²žsŖTŠŚ!6½¼Cė‡’ž }ĮÄxZƳēwÜö’\L«ŠĢ°Œæ7!› &ė›K @uµÆŹŚ£/E§š“=Ė Éõsg)*OŠ?[ō£·qwG.ĖJ’.\¶½Uāš!Ėt!čµq‹ ­97¦€×üHÉś5ļj½VķŠg’ (r)T’Zōté ō_HL–p_óŠž;gKĄ÷,_gTÅ¢^ŲńŽ*yōŽGv)V@ E›kN‰‡y„‹…Óķ+¬{ÆI 0Ü$|mĒ×&¹Į²P ŗīĄ¼`}wóØh;Š£«d|ē…·ŽŗułGT1tn~&Žų'nŌYAīū±Xwzg”å×ŗ·Čŗ Œ“mXć2.I6;÷ĮFyŖFcÜ“ƒeōAåUįØõ(źUrõO,ń¢œ’‡³³–C|–_÷cq"2©f.£ŸjĻ—Ā ‘¬›Ä¬fh„f2ξ6AŅōqe@B$ŌtŖŚxqi¦ŒR ĖSīŌØ±"ÖkšČ’°ž“d³ĶK¾Ų^K{ „`÷ي)(ē¤ o,ŠūØØÖĖæ3«”Gé:&LüysžĮµP1Iä(čeįåax‰¦Œ\“½–z™«@ė"‹2«N¾†Č5ƙ³!µ‡ĮA:B62dl—6¾²ʤ4jš„Vś‡¶ÉŁ(ŚžXŅ„\˜®×9žØ%żųīó;¹»¶­žĶ©W#·¢Ó„Ī=A–©\@ŖEÉčņ® Vćq~n{‰bM¦M€bké!,,ē.JönKĆoĢj4ŃĒå"īDKpĖ„z£(tuŪö„ÕfönžB–Ņq•֝Y²DHÜQtčrK¦;{"{ų…^'ƒ•x!ĪkšÉR<®äĒ>Č•öŅXqYöŅpBćģĮg„…;[)f\Nµ!×.łOųĘÕyķŠ;×,9½@Œe+IČ~rāśåŖbŪ·~“æØ ?›œĻi#ķxŠ GŲÜūÜ ONšDō00m„q] gW€s=h®äŪGÆ,õŃ ~|-“ŻčŹĀ\U{X¼ ±OØæÅī!XcOF8)į‘‘»bČæ›wķSŪ>¤0Z äA‹t-š«Bdެ<¢~ōŹøÕ÷óć÷ė£ÄFŚ9J©„’}®• Aō÷øļ$£ćš ļ`žDż“ *ŠZĪ\Üó;$KO(J~)øzKśo=.›^6[ł»˜ofč"ZuvįKE)ŸÄ?ˆ“lż?j–_An(;šŸņ7„j3µcµ¹‘iš#-;Ź–ć9Ŗb<®ZAńĒźc#p0Sų`åńŚFØ%ā…>˜“[©w”w=łcŽJ½:½vŻ„Ą“ļ‚›¬Öī?ś“qåżGūānźÄż;esÅļŖø—x<Ŗ—ü©zéīļ{źqwW“‹ķ[ŗĆŽ¢Ž0=ß0-tTfųē„‘ŗŠ}ņ¾'¾eŅlüŗ[ń ©ļ±ŲŽø­mĪåéJ;pūĀųŹZ†˜LŖoŸ–I˜Ø-õqŠā;å)hńū“ųJą(hńĢ+3zœćz¹¤fgžE n9ödĢīĆ÷µCżOÜEq¤,wQOOy'ņ.'©æÄæ×įNUx*Y¶ yZ…ķ:ļé©°KšŽĶIÓ÷šćßĮ>”>ŗCõI}s½jā >mĢį=y üƒˆ2ŅŽ&ÉĒė~&u+OEXQöŹ›ļ>„®t•'/7–"ćõ3˜ ŅoĖ«7āā…Ęķcšā—Ż…Ļ2/Æ“¦ū„ Ĺ+Ėŗ ‰ģr™|ĶŲ7P·˜pJórƒ³ĆO¦{žzHėµęŁĀÕI_ ˆó%ł_’N–•2µČt»²ņ$NĻrä±8a8%ĄÓ«ó®ŗC®Õń£µ*}ēÅŻ“^P=ŃżŌ’{åå÷ 2©ø–™ÄµĘb”k_·–o¶ū‹Ū¾J˜ ųŁę?3étiendstream endobj 36 0 obj 3410 endobj 39 0 obj <> stream xœŻXY$G–«šĮzģe4kĖ®6źŚ<"/„„° †[#ń`óŌ`#ŌcÉūĄļē‹ČŖŹØéģ™ŁŃrˆ]­6#:3Ī/"#ėŪ­­Ūž;/כo7>¦°!‡ķõ†Ā¼>Öu(†×²gZ’yūĶƌĘ[2.B–O‘bĄēœńŪē_oȚ8š¼&ćwĮ¾`œ˜ĒD[Ÿ©ŒÉńŽ8–ŚŪїm“9ŒĘnŸÉo£ó~ōr‚F‚L—i tņc²ŪčmÉɉ™ƒ8ydv4‰Ļ¤ŃįL*n Šź\‹‡ “Y{“”Œ%T­²Š&Ł‘p¢ŪéÄ>²Ö‘iŸœ ›±“=ƒ}ŃnÉ%Ä7²§‘­ Ļ2ģ¶ĘŒ.ń‰…Cyō‘CķRØX*dśŃ±°>ߌēaó÷ ‘cŹģ­ÄÉ#ģ*š–RaidIŒ)>-¾$ÄŲ§<;»0`ŖMlį‚tā1ŗĢ4‘d˜ąœwa“0¢) ¦åĀ'ņ9M0  !°čpµ“€Ķ‹tA“ś’xo“ųDvqŚ\D8nøzŲ|…3H€}ü?ÜwМŻĀ96Ž3…ÓÆ8@€ ä ŁrąSͳT›hĢbģZĶŖ}F2óŒćŒݹDv~ę'NdÕq As,²į²P:[Uæ‹T›`Z”ō¬õˆīE“3ģ€wcFä([ŠŪ>’‡ĘŗXQĶd0ö|X8d”…a¦5\kš{ęxŸ÷ +‰ķpfūČRä$w8ŒšBśT‡cŻčóŠch„[ ƒT”ƒ0ēĘRś ōTŽŅ<ł|<‰ĖQb… 3ŅūZq¬ō²€ d %ZüLB³ó†­^~Gx‚"µEŽPŚiĒPm†]ФӺ܋©„¢Ņ£ś•–Ó&:ÓBJĻfBŪ` ƒ”•Ł”™tÜ£$›35J‘Ū ŗµKÄ@>Iӛh¶‘ŪsR;" h9i‘[V£ŁRW½š85Ē“вŸčTI°9J>-āĄżÅĮ1®|[ ÷™č¢ēŌ‰ėŒ “'i“IڤćāÜ6…0¾L¹™6T›€V"ķŖ ”ģ9eĄ „Õ›ėĶS ³ ī©—Ź!<Šf˜šn4“„ZO‡±' 7‘$' >“V ō`ĆB‘Äœ¦ābpv“ŠÜ0Š„³.æ…3kń £Ōa“r¼į®”‰µOz“¤ ™óRæp–®ī}Ø×ŽL掉A÷}>™åÄ$”¶Ö¦£Ņ| µ7«·JĄB/*fĪlÄ$`¶qķ…\£M«Ÿ= Vs`§`jp³yM7Ļ&ƒ‹o‘Y_ōVé­“xęeHXv`,āAe‘0ÓMĒĀ™¬˜%ĢV®żØ¾E' ļMÜzģ[¬cŲÄ9VŽw GhīELs0m؆ŌJz¾•ŁƗņ±2¤Š4€ęŪʓ•i†i×hd2i;_Š3żĻŗĆD½ƒ*“nȜ85÷Ē5ĒĘz&xå*hŪĀsØ©/ypbŌg¬L„Mf£ÉĻ2„”†4ĖN02C2*Yqļ–ŸsÅ=rč*£č豜±5žD }˜ŅjÕNüdC^ё»Ša£8ctŌt9cėVOK"ā ā iĀ’ē¦)œč*F[F4é—*˜|ķ1铆⠾S¹NSõäZs’Ģߞ[ÕB±śŅBNų„ՆĄw͊vn}‚&×ē3ųĆĶ•#ÓńQĖš56‹sżNfś9ŗ‹ó†ŁO݊– Nbƍū³Ł~‚_㔇ـ’ČĖOÆ×Ūß^mž}ž¶2.\}…ē]Į{ Błg»µN^Œ ‰G—»ŗŽ Æģ®že[Śv“­i;/¼ŻČ5‚ķ_ ?ŚĮ¹ˆ·Įš³Żż$Ęķš»ŻžŠ{š’Žß”Qćw;|Œ.e›æŪćŹ1Ųį×¼³žžįŽĆ7ĪšĖf‡@ą©æŚķyĪ*!Ÿģ`vq˜ńg­‚żą°8Mšb_8˜) %PÉŶ-_a[01Äįl@Pćš”|¾æŪóūo‡įr(,/E—)Ł(ū=S֚*no?ä"–¹śtƒ©™½śÓęź£/žķ‘łhĒCA 4|g·Ē³Ó6ĖİA¦ÄUTlĀ+¼ Ō Š{Ał)v›ä°{’Yrųöüŗ'\Šū)Ō>ŲńÓ”Pކ”!“Ć#¶ÉŗģĖp9›ŗÜ8¼¹Ūc€Ļ N_4’”Wź˜Śūś¢ģ{ģjH!†4q{ŒśUŌEī™÷£†^w9‹x=‡ĪAxyO÷€|gčž5‡Ī—ĒÄeč󷁒2Ī«©ēpŽt7}Ż&§ņtqūåyŃn™;ļįĪąüBśŪ!5Üéft©š^7f5RĻ>·¶~påń3'³žĀšåsŌLŹ(Ō”įRŽ0}Š” ęäŠČVč^zI’sĮHšŚŽÕe¼ŗ>ÜńċŖŸĄ¤>ōZgœ_÷$¾…®#ōŽn~ ‚įĒ<ąeWŌķėö“ŗ qśKžŲŗŹ£^ļüa»o·Kķ*ęj™0T†WÕjłłÕī!Å=1*Æ?=>īōŽ®y×+™Ŗ^o’ܽ:„ŃŁ3„9żå7ķTØ]ˆ?#Ū„ )Uf9E÷„Vŗü¾Ö:K]©Z–‹.·4ŸÉĀ’s@‡3×n6ćÆ6Ÿįļæ> stream xœŻZ[Å–1g° x—K’¢i×åŌ-ÉCB–B^°VŹĪÓ&E³Hų!æ?ß©źŖ:=Ó³»8 E!ŖĪTėw.Õö·ƒš“’[—W›o7Ö7xŻpµ!W×ū²vIń:Ÿ™×¾ŁØIYMŹxš²Į“wXąžQvxžõ†“ņ“ŠƒWæ[0¶ +G ų8l¤4Ć'ü”<öVO6 ^G7)=\nl4f";xcķdó š¶!NÄĘ6TՁį+ģ ‚C.‚?&yG%)7g›4;Œhvˆj1ń8yŌhČĀ- 2 \m²Ć*E#\©6>ėu²¬‘ƒ^6įŽS/7_į yė’ęHަQöbTāš Š HÖģų²äŹUšbVv)fŃ6#‘iŹpDī˜<_)ū™āY“Ÿœ“hŲ€hĄ•FQĄoćŖTó9¹Ų<~†<.\|…ē]Ā{ Lłg=h“_ŒG•»øŚŒw¶’Ś|zĮģł%ØĘ)~ ęg Wś>}rś·ē·QGC0-B3* ™āJ<‰ÕłrüłF­•ßßrĀFKć³ķ6hĪ ų·‹?ƒ!ŖÜ)†Ü‰Lg8lßµ*$%å߅PČŅ~üp»hQnwčäÜųėDަńŃv‡Ģ«ķųÆ­ քńĒ[. Į7¾¼t"ęÅń>U­Ē7Äŗ³»_¤ŁäŵŸągxŻėńÕ-[^ātkĄčŌ F3j ¼Ļ©ŸMžåvā™Ēgß@¶õAØVWÆĆ"œw!{IļĄ ‡ž£­ŗŻ!YžäāŅÆ¶, ĘYóĒOSѳsˆx‡īšĄ»ąāļY~#$ņćÜOV“ßŚīš’5®9»³ÅŒ§®Ļ! Cy Io²Ē?|Ś2¦āéYŪ×·—ŁÄˆźäĒĪLŠŲī4W,%»]?{•­ÅK:„uV?bVĮāķ9 ūļ?+1·‘8”;Œe‘•}Æk $Ģ&¼p’;;y¢SļvĶäUļl1*'g“}VĆ©“XØöp¾Ećcf‹ÜŒiįR!į p@Nų…w{nņć[[LłH¤øˆˆŃqːŒ†fŌūX©`°źnĶe$…[ƒ‹=1# X—Ké÷øPąP†Hšź'WœZu:ē3 ©’ųe ī÷£.¼_ńtgĖc°ĻŪU—ķšę¤9Õné@!¢( ÅÄĻ=iUōĪ„1B~ĮdOԃ"!ŽrŹĒuHĢØut‹%S) µšķÖJČ»¤˜ŲóÆm™_Ō4žæ )ØQžk**xÄ*ÖŹrĪ<ę<…Ć*e0õ{ 2,‚Ė$‹9.2MT”nÓ;[žĄi’-[—ąŻ­s‹lƘ õŒYO³aˆ~.É©’ń €ß¹>#Æć_ŠY®»Eņ߯Ęə\„O쬽ɒj’¾²a!¢gėĉ#0ČHU0Ą”š @ž<³Ģ˜” +N“1 ‹ŹŁ(ŗŲkŒ]ÜU°!žĀA“ ŹÅR–Ź0µ³üPĒ /Įóż‡³Ń®ÕK94ĄŽõ›~ĮGĘ)ķ©ė2WL+¹õ·õjņŹģģą`žBįÉ‘gW-{Ō-ūECM&z)Wšz°V*¾'T{Ń%jE”~{]ü.į} æqč*®ų²żvQ'šņ{„æ1X€–架Ȧµ9ū3ŌĀP>©čŪ’1¶31M>Ä9{v: ]įA"źÖ¢ö‚!=ė,ä<&Y¬Ęņ¬;[”±<įc”ęM]ķD¼Š¶¼qö…x"®gĒ-鈻I×ß1‘Č”śšÓ‘¢ģ¶·Ļńū¹ŌPLЧŗ aόŅļƒćÉéŲjŃ%ŽKŸ–£QĒ˜±N©öĮ@„gžÓ”" 7•ŻĆźĮ4‰ó›ŖĒŁ5p<]iKBvž€Ÿ_dĀbXÉÜ ¾›B¶±7¢]/J{Ūā§ķ¢1īÆd{ćėAZxdÖ¾ŁēĒ?6®½ę²R˜,Præ×¶ŽT!²ī÷O,Mįź÷¶¼W—IxēØ;ĆõśOģk¦Ä##ĒO™ƒUXĶĆ#²+„Ą¢` qµ<¹Źó3<į'L4æZ} Ó½¹3üesńń—ĀĮ/0Ė£P-¤łĆb¤,’’š+Šz|ō’i|~ »įõä?įo]ɐI],æn#MĻØõŒø®czĒņd’ĮÄqøŖ©N¼byė Ōó" ·&W¦eų]ƒ'åSi•”Ŗ…`GØ0AūE•“³žŻµŅzüTŹQ“O„Ż@”ĶõŁ’E'6 ³ļ:9ł‘E~ ĄÓŒ(ČAEĢ\·«#ōÉGfłr‚GĶxäĆĆaqń ­y$c֍ķ‚W ŚŃŻė]y·Ė¼1*‹ńåä÷KāŪ„œ>Τė­6āćo.üWTX<ž=ēoåx[2WńWÆāxž°4€¢bŪ÷ŗžö~„æøėG™$¾ŁČÆ3‹—öĪšßʰf‘j<¶ž¼]Ź#T˜LśįæŌˆ4|‘/5Ÿ÷ś¹ś-@ĶŽoŖ“÷Śļ÷Vßz;Ō"‡?ļÄU0už½ėślä„nÄhE²ę×dū!¢vóHł_śNMˆöĒ2_lž‘ŠČrendstream endobj 44 0 obj 3051 endobj 47 0 obj <> stream xœ½Y[GÖāK'vģBøhb#˜!œq_Ŗo E‚§X+ń€yŚ\:)~ą÷óUõōtĶŁY{‰¢L×v×嫯Ŗ«wæĢlŻ`ųßöqs{ųęąc C 9 · ķūTæC1ü-{–ļæ _Ģl¼%ć"tł)|ąœ3~xżÕ¬‰³ÉC4?÷Pģ ¾Aóœhš™Źœļˆs‰X{;ū2D›ĆlģpsšŁ¹™ü÷³—4tŗLs(X'?';DoćLNN4 Nąä‰uŲŁ$>“f‡3©ø9ĄŖsy.:Lfėц2—P­ŹW4ÉĪ„…ÜģŲO'ž‘µ~޼öąٌü‹v —€oäH#{A‘eųm™]ā«„ņģ#CķRØX+tśŁ±š1ŸćysųēČĒ9eŽVš@ņ» ¢„TXYG‚1å§%–Œ}Ź3q°«®ŚÄŽšˆŅEĄcv™× *Ʉ9!8ļĀl0¢×rįyŽœ&øҐ,6 vX“X¤ ¶`՗Ä{£-žż š‹Ó"ą8 õęš%Ī ! Rō!š’¾ƒåģVÉ©Kœ)œ~%± | Ė–OI,7­6ŃœÅŁ­™LūŽd–Ē»s‰|“œIdÓqAK,²į²(­¦ĄßU«Mp-Jz¶vÄöjÉĄ»99Ź–ā†×_04ÖÅŹjX˜ĮÜóa•aF„C[;køÖw“xŸ˜÷B +‰Ż‘4’ČRä$ļH˜į…ō©‰u³Ļ‰”aa¤ ā1Ą97—²®o”*Q–—˜Owp9 VØ0#!1±o•ÄJļ ŠPŌcP¢Å·%,;oŲėõē€'ˆ#R[䄝Vu|Õf8Ńm@:­ ą½øZ*+=ŖOXi9mb3­Ké9ąLčl@a0µ2»Ņ–Ž{”d³ P£¹½ [ ±D ō“4½eĶ>r{NjG-'-rĖźköŌÕØIņtZ޽B°Aµ‘€Ķ(ł“Jˆ;÷‡Ąøņm1Üg¢‹žS'”3/Šž¤M&i“Ž‹sčį|Yr³lØv­DŚUU(Łsʁ3„Õ›ėĶS · ī©—*!>ŠeøšīkX µž sOHo"IīųLŚЃ +EsZЋנ³£uĶ ]:ėņ[%͊/ „A/dzp„L|Ø}Ņ£%ɜgHż*Y»ŗ÷”^{m;&Ż÷łd–‹†ŚZ»ŗę@€ŌܬŽ*ėz5Ń$͉EAóq…\£ŻŖo‘«%šS83øŁ¼^÷Č “‹o‘¦/z«ģÖµDęeHXw`,āAeÕŠÖŻĘ*Y¼hš—Ū8jlŃIĆć{·Ēė¶HNUāŻ*‘5÷"^sšŚP…ŌJz¾•ŁƗņ© ¤Š2`Ķ·'+Ó Æ]_‹Š “Ißų‚nė×&źT©­ÖéLē"©¹?m%6Ö3Į«P±¶ž›šś’7š@£>ce*ķ:ūš|Ó!°4¤¦C$ĮČ ÉėT—•÷nżq®¼G]Ī[ń$Z×7KZ­ŚĮ‰_|țuä.tsP’Ą“AĪŲz€‚5ŅRÉÄCl$^˜‘.ynš"‰®r“gD/żZ‹€Æ=^ś¤©ø”ļR®ĖÅT#¹Õ’$ó·ē–GµP쾓.žŅfCą»f³vn{‚–ŠŪŽF¾¾ŽįüD•Čt|Ņ:|Åfõ¢Õļā¦oč®q“ -NšŻf-¼¹ƒ 7īĻfų’}…‡fžG^~śūęvųÓõįÅĖ4Čøpż%žwļ5(åŪĮ:y1&$]īśö0^L×’:üłšÕóKŠŒSü”g`4ž¾üōžŸ½~ˆ;†ić.£ź«PāéHģĪßǟOš0[küų‹‰ 6{;%Ė”’qżčC“»O_D®ėļ£Ķ?‚MŲ²qüh:‚³‰(Ļ¦#.rJaü»DїńłtÄ朷~ü{“¼Kć»ü?kĒ÷±oo[Ę'¬ŒŠ5nüx‚Ś€Gņųxāp*öN-")= \0kb‡„œ%Ž_OGp £_}=²l‚ūķė `)Đ$d B~:īėŁõ# ą™­żfb9/žæxYŖ/ü“Ć 21ŪcÖæž\๿PŒóÅ[²ć¦#^§.¾Ė H^ŒćlaŠĪ©ŲńĘ)šcF ¦‹·OVmļpˆ'Ž]هśV01kc?Ūżģ‡”Płrõj‚²R|rjļ÷yoņxeŖĄ3pxhCŲwv>ĘWŽ!”1ćĖ^õŲw,č0!ŒæäčL ˜_żų‡‰ē½ģ÷˜œjė·#gC’ØĻŌ„wōŪ@Õ&¦#ĘjL0 æˆü\>ź§WźÜS„Œ¹Ć)žŻ•°åJ{³Ÿ®g’Œ x4]?Yż¾TvwcųØ ÷4©”Mķ•J|ęż [~üĆZ÷‰K\”|1ńEęrŠĒõÆ@Z å­<ļAv»zē•ņ¬ļ]ü ”6ōŌā%—ÉhœTt®v žšRųĪč®^üö™ģŽŗ7ŒūŌĒ.•ŗŚ=ÄSŌż÷?ÜBéĢa~}&Ņ;w ģƒ ŻźŅ(_^^œW @Ż©˜·×ś>菧„ɾąKA® ė¶óŠNÖöu²#’ž$»ųĘNĖN·NėŒī* °Įŗlģ5ĀOęóāZāāŠ¤]2«`_°2kŠ‹VŻŗøžķ\JėY'E¦•)Äļ²fė¤Sž]ģ–żÓ½:¼Ē €4#=)ļįü†ĪŻ›ē-Ģš?¹ АČ©{°—8_ųyįļµ¾ŗ“* åŚī Pē‡×š1©UŌŽµŅµæ™¹|™ģß@›k3*"n?ė(Õę:ĢPņg=K}ČEKĀö÷&¶‘ųÕš Ćü}‡ēӌ”2·-q”w˜VÓłøęćŒé“šK„(Ä§ÕŻŌ‘ųéĽq%Œž#.ȧ’V#Ō'+·Ė¦;£’øĖžO”TŸėģ«ē¬É9ŻV‡Ż}5J°¹ ~4<ļ™ˆń–4Įg5æĒ”ā,īüūfć=°÷ƒīŽ¹K]ĻŪū˜ķńÆŒó3æē؈|¶ū9łos$·SĢq§–ļ™ÓwPÕÖėrŻÕt|§ƒėĮLīŚNā·µ¹{ŹV.u#Ņ>{¼» Ŗ¢y¤;ģ} ķ€k2솲Ū v ün£ŻƒÓWSŹfęŃy{®Ūu›YZZč-”’Š‹'ü»WÆłeJ§ńxū¢kEƒžż ÜDœĮ©ņ·}ė¬E5^Żbļ-õĘ q“żóģ°aü«€Z€ć¦æ¬ænųģšžmendstream endobj 48 0 obj 2560 endobj 51 0 obj <> stream xœŻZėÆ$E,(ˆ ÷ņPœ]ÉŚƒNoÕ©S/5QQ$A¾@nāšÓU0ę. ūĮæßß©źź:=Ó³wX0!„ŖÓUēż¬¹_oĶhikäß¶ø~“łzćBōŪą“ß>ڰo뛺öŁČŗœ™ÖŻ~µ1£q– ąr1pšXą·}ü冭 £IŪ`¾; v+Ļ€„4FŽŗÄyŒ$'˜öĪŽ.oƒM~4v{½q‰hd· äÜčŹ 8)ńč3öэŃnƒ³ad*77póFpŲŃD¹GĀ˜iō J”Ęģ€Ć$”¬Ļcö•jYķČø‘™F>©šĒÖŗ1ČŽ%č7Ų&œÉĄ_°[¦ż‘4ģ Yß֘‘¢Ü˜!œFDÕ}…X/XÓ$\€oČ|ØĻėĶ?7Ģ.Œ1‰“E0ćT†“³`cK\tĢ)Ėķ"K„Ž]L#‹°3¬Ś(ŒČQC!0C#%ŁCQ@ÉʏĀ9ņ£…1O !°–²ÜHc3-8 ;ØÅ€AÕTÖ ę-Pu9ŹŁ`³>˜=ų³yˆuˆz½łw`8RpŽĖ’!>r¢rÓ!d²˜_A,<0²ÅĒX(7¬6ņ˜ ³K27 ķ2|$ ̐XŽrįäf‚!Fļ5ÄĀ.ĀP%ŁJ ž;cµ¬…bž%B{¦DFp4&hes¦ķćˆj,…źÕ¢ąāā{ĪĻ6⾫”ķɉ5ČŻ ĪEńūā¶vŅųcĖAŒ¼Ϭo­@,.- †Gˆ…½/QHŽŸ£1ēy­čTˆ¢<É|s¤—›¢+D˜)!Šc?R[r[ø—ėĄc¢Łµ-(“3Āõüźń…‘[LŒŠŽ3:¹€h3bčŒ4P2-yų}a5WÆtˆ¾ā•VĢVhĘy[r|Ę÷Ö#0ĵ’°Ņ¶$9ŖX³£$½ [Ē*h€ŸKŅ›öĀ£¤ēØNø¢£IY}/œR•j‚TEŽ©VäD®(ŗA“qQ¶hÉÅĀ’$æ“Č·ŁHž œ˜®ˆ.~ōTŅd,i’$8· ˜Ļ“m¦", •”tUė‘bą€Å’jŒMµņTŪõ£ÄK…°?Ź`1Ż÷ āk‡ ¼`ÅØ2DU•YŲłlųÉ&k~ŗ“€Mއ_ķ¢•J»śųäNį“BDß°ńžČA6šüŠ-†{»=|62§įžnBĪŃĻ K\~¾Ū£#rÖ ļŹŚ™č(Æī<¾ģāšœÜJ1ZRXļ VĪÖŠp¹Kč]i¦„ŃiųįN$¬ę8ŪŚ.wĮPsf[oC(^D{°ŪĆŻ0 ¤įóÆv ˆ6B¢¶ŗ Ķū胏…_Äų}y·‡<čŅķšŹn˜š˜¼Õ„_ģ„@Jē?Ķ•™öŠ»l÷h÷Ńž_ż üIpŠÆķö˜S)A‘wœ9Āšv?/:Ų¹æC‡•zx+D@ć†ČŃč0ķ Æ˜Õ‚ p‹ĄvŅkąk;4‘0Tŗõś…|D¤GūTD•$ZV…ą™Åx‘(‰be…īźn¤:Ńēŗ~©~RΏƔŗß‘>GN™ĆšK¬Rš> +Ė ūösļˆLšŠš~·ŪĖč“HcZ%ÆhŖļ—Š«‹Žį•ā:$Å*Zønq–É.ńÓ 4’‰”ĘVKM”;Ę½Īł3uk]MmU żč„2w=Ź!ž pwƒ‰lČtģ9ģŸ'®d¼T: „“čzߔ½Ē8ŹSxź@T<\*®:Ż)Wkī}›ƒØūŪ)Š ¹ß”G&äžg¦ÄҲÜ~-µ¼%)4å˜ĀšāN°%$™ĖWA¹«Ęr1FØŌ2V,Œf¹Ąń0{”uĻÖr!!éSH( (E½*„½¼¾(įŽÜÉū&e?8‘-#¼œŒ‰ÖKņī»Ž~/¬AͰĆCµV>?.j~”“ĘÆhļĶb ļ<ÜČę›uV{c-üžP˜²Ø1öˆķ }ØÖkÉNÉ­cźāā-°ĆŽ„EŗŌ!¬D;‹ +`¬Ź#󵏽N»DóŗĻ‡B3e ¹7ūډā‰NŌx—Tķ|QĮ]ō§ŹØ•'̊Śæ[Ė·€ė×ߜaŚ!o3=)®:®gK\ZŽš£=04šNU>é*ä ¦ cKs2Æu‘Xµz?cČSIš|:ÉÆčeK?ٳ‡‹˜’“ŹżGĒdJ»šd2a„lk«ķ¢ė]E‰ZžPŃziY­M/Æ«į)ģiź°ęD×Īć^«éYē6^+@fĻŒč‘¹Š“SĶĢ·oPZ ĒŲgLƒp‘ÉÉrZśXé_ä©CÕŌæ|s/8§y˜€!Łć^š°āww™b×c™Ł“»ļ Ə—Ć\žĄū;\<Į #RözG®hb—ÆĖ°Ā3ĆJĞ‘‰®ņ„gÓ¢ų@«ņ{_ӶƧ˜Ü¢Š¼ģ³£»µÓ×YWøWÖżćŒµgf‰Š}ĢHpp—zNŪĪAg*PxéÄ2"Ą ł“ßēå mICV:Yԁ>[LĆ!Cąw„a²ių@DwĘ.“O(ŗŒøP'Wqžc.Fżżµāźg:Ų—6›źĄĒ›«÷>SjU®Ł{“Õlö\¤„…Y¤ †Ä…¤üyŻ*ö’Ź*恓Šu†—(=™˜r'kélˈAzō¬GĒVr7Ś?,OźŽČĖü±ź%ƒ™|éÄņlÕ·Ęę{Ōż{sT;3hŪ§¼n™¼ŌūBŪŠßĖcšŌ—¶<ÖÅXkģW;ż4rŌźId©īF!P×ŌŁ{«µ’¢Oßå¤ėŚ„•ß&Ļ«ŻŃ§ēwTŠłī꟣bżéérõAéÄ+‰ƶąg[øĪ3ņóµM­5ś“Š_h¹ē]…čķÕeætożŖvĪ~„,ŠŖÆ”dÄO?²Fvų¢±§ tz¶;o<.éne<>l™'ė£Śē§3›6?‘¼³æė{zł=õČ)?oRK‹ ÓõĻ=Ó~„Śœ‡Ļ©‡Ńž?Ū‹œū®ōšŁ†|Ąą0ŗ=“]*·öZ„ķŽ÷cy…‡G٬-rʰ`“”RķÉg‰/<)BŹo9ŖRF-<fUśé,$ź!OōĶä,Ī’"źo™a!q›¹ŽLO?É}Oh-.ŠQ¬3œs >)mX>"źą{}%EÆz›rÜ;:›Č•ØčV¹5Źæ¬ŌÉÕ§ź§).gĖØ³Ņō*‚ėīBūźāł³„Ē'¼ņŹkšƒg˜ĻĖļh .fĆČ»j0iø¼§pžŌ#Üóżé­½żfõ4¬O¾ü6æųxłżKé2mJė/~«SĆm£Ā ųĀp}hč÷÷¤–VgŹ¤ŸlžuŅj…endstream endobj 52 0 obj 3163 endobj 55 0 obj <> stream xœÅZŻ%EĻŗ źÅø ģ ‚Č]Pč¹½uź»ŽÄDIą‰Ķ$<ø>‚1wHŲ’~ēTW×é¹=»3ŗØĘŲēLÕłüŗšĆŽLd÷†’Ū>.Æv?ģ\LaCū«ķūXæC1ü-gęļoößļĢdyc#d¹} ųĄ=kÜžłw;O&N&ļ£Éų»ƒ`Wš<81OÉļ]öeJ–OÄ©DŠŽ&Wö‘r˜ ķ/w.[;y·Ö¹ÉÉ ?yČ“ŁO”€NnJ“Žāä­ÜhÜĄĶ#Ė É$¾“&‹;©Ų)@«µy*2Lfķ‘B™JØZå+šD“ĒāķdŁN+öy"7E¦]F pĆSĘIö öEŚ{›ßȞF¶Ā;x–a73ŁÄ7ŽĻ“‹j›BåP`©é&ĖVĄnų|=ž—»ģ¼wqJ™½•x y§ ¼õ©°4OÖKŒ}.|[|Iˆ±KyņģģĀ€©”Ų¾ĀņŅåÉf¦(ˆō&L Ī9&ā€y?ÄĀ“\ųFž"§ f4Ž!,:,Bm%`CHtA«+‰ĻF*Žķš>Ą.N[€‹Ē5W/wßā E’?ܷМķĀ9vŽ5…ÓÆ8 Ąo”™8š)‰ę&•’Ÿ²»Vs„jW€‘ĢP9lZ‰“«*P²g•×L”Vc(×ÉS ³ ę‡ŌKåx<Šf˜šī4“„ZO3‡±' 7ŃKN|'­čĮ†…"‰9ĶÅÅ4ąlżBsĆ@—ĪŗüNÓā @ēÓ£—ć5w„L\Ø}Ņ”%ɜ㐺…³tuēB{ĘŒ‰A÷}¾™åĘ,”¶Ö®£Ņ|šź&«#%`”ÓŒ˜4×^ČķZ]ó,ęĄNĮ<Ō`²9MwĻfƒ‹§H“Ąƒž”ŽJ‹gN–„åÖ"^T ī:ĪlE“Ь\ūQ}‹VĻML=ö-Ö5lę+ĒŁ…#4÷"¦¹@˜6¾†”¤Oe6ÄšP>V†“?Æ yŚ8O²Ķ0m;-"‚l&żDąŻčÕ&ź¾B[ŃéšĢ™Ss\s(Ö;Į)WASĻeM}É«š€£¾C²•v™ö®ÉPR“!œ`d‡d:U²āŽ.Ī÷Č”­Œ¢£ƒ{†j<½_čĖ9­¤NpāgņŠŽÜ….wŠ8FGĶAg;TG X=-Lˆxˆ Ä32Ҍ%ĒMS8ŃVŒöŒhŅ-U03xģ1钆⠾s¹Īƒ©zr„9IöoĒ-Ļ×B”}i!güśÕĄ³fE[»¾įg×Ū‰¾NĒpżFåČv|Ō2\ĶbE«ßŁL×¢»ųŃ4?żdW“dšņ$6ÜøæŽ™żųßwxča7ą’ČĖO_^ķ’x±{ņ4ķe]øųĻ»‚÷„ņŸiOV^Œ ‰G—»øŚ ÷ʋīžtĮāł%h Ö)~ Ź30‚½OæøłoĻocA±_„aT ²5”x:z6ē/ĆoFX˜‰Œ>¹`³óĆaLÄ”’zń%ä”ÉŻ$‘ķņ†=»÷B ŠŃź_(e h}8PĪ…ŒĖgĘ uųŸp&9›ś ~>rGHֆįžH¼‰øPƕäJŌĀŽ‚_x’S~ĀśčŹšū;f(1 ?ŁÉš‘['ž•īĘĪ’ī}ŒRäāŻ'ćˆĆƒ Ͼ=0(ĮŠöõN„bHģ: 8¼9& Į÷·ĘŹ"ąń­.}:²‚œg˟<-Õ~ša}ٰńćpń7šéČ€gķš«čąį"4ąšR’lĀėćeąA§O܃b‹Ż/ö³)(ī}ö1£Åį}@6#¾7Č}s¹×°ķēTheŚŪœ¶ĄÆ+„ā\~nqäIÉz§ėżø[óīrrVą2¾gĆž³Ś0%bV†åQ)ėĘĢ"Wq±gۚÕém]›2ģdŠ$ėtČ?aēāćšh¹²™1•m‰ņš`ˆ_$ŌtūĻ•Ų]Ų‰tÓä_ń›#±ZhUh»TXN“æĪĒ+K~¶„‰doJ>oĄ2ĒźŠ‚uĄÓŅĻu¦`{Cq‚āz)6¹¼=:ļ>˜˜uŽßüģ—÷8½øŠ„/-gļ/V¹”°­ČģÖ=Ų”¹‰åˆ ÷ęß_‚oås·äž 6ƒ· "±Ūė܌ķ;µ¶šN­²ś E яŠRĀŖŽU]¬Jw+ā­_xÜBłĒOŽ}ml,’"ĢV³ā=֒KĀł7F—ÉēoĆ #X}0ų¦„'X!ņ"–g ‹Uń<—Ō86tplrÉBĪŁ}ƒ{#ZĒė#’␼NéĖfA‹Zž°$2ÅĘ&zX?ƒ9†PԘüWGNK­ Ŗr\•ڳAb• |¼Ų + žT&ø¬6Ą7øp»ķ]*ńæ(¼tÅŽ9’.ŁVHĄ źįÕØ\jšīįÕ¹ĻCžgY.ž(ń[é{1X²iŻ­Æ5nž ĆX·Ję/ŃžMłøĒ!FżÆžžõŖ„ŽŻ¼gj+Ó÷öRøż’ń‹ž]V=c4„ž©Ēšla:&­¬4Ą’þƓA€ęÜĘ@§-D|ŽŽų¬² ė=SŪ‡žo›ØY–Ųš‚ģ’GĖ?ŽŪ»¬.wń¤ĻŃÓu-­d_Aū¶¦Œ:4žnI·]ńĀ’ś¹µ¹ē¬Ę¢xµożŪ±~ęŻÜ[XШߊõf€Tīæp­“zŸ~)€7£©ó’„üöŪ’­Ó=` gg:±ėlµ§Īķkžw ÅU‚ž=Gš¦½G×6ÜU¢ĮÖū’å(Xµ¼Ö[·‹ŚĘēiŸŹmƽ˜É愞’VšÆśČßHFč3€ŌŌŻŲ›Ćj,tnč3¤gų«~rkl8rśÓBB“Ššwz*.?(~½ū7AĖźendstream endobj 56 0 obj 2660 endobj 59 0 obj <> stream xœÕ[[ÆdEĢ€ŲgøL7ƒ¢=Jt7¦7u栉\T"ĮČI|ŸŽ‚1gHąĮßļ·ŖvķZÕ»öōéE1Ä®:U«Öõ[kUm¾Ś‹QŖ½ ’•׏7_m“óvļl°ūĒcĖļ›üŪFAæÓšé÷Ÿ÷_nÄ(“4B9ŠŅŽgńū”ŠūÆæŲ)Ü(ĀŽ‰€ækÖæ¬ĮŒ £7{L½¢nŒc-G÷N; ¹æŽč ŌhōŽ)­Gv˜Ń€¦ f“cÆG/÷NK7•v”ģĄĪ¢!GįiöųØF‹S• cŌ !ī¤c“łŌōĖ /GƒŃØQŸ*ńg¤Ō££±Šv°’$NīņŠÆ#Iqa4$ ą[ 1*O;ęFķHÕŹŪ<#-QM=*ā|CęS}^ož±1F»Ń’6éĘ3X!­ń‘Ø©Lұ ‘v'YĒŽä“µō’_įä ę™›:£D$ó³ GFįdIŠ÷>\ØJoʐ˜m¹ĮŃ:ĀGĶ E…w‡čHų2s3Ķ8:ŚÖņ khk@•Ję£ąæ3UéĮšKęiĻIgĻ')Ah5h%cTūÆ’NŖ‘ŹeÆ&'Ļ ßÓvž1‚<ĀV5”±’‚b r—­=ł}r ™ Ū™)üi¹3C ßՙ‘jŌ”™f„XŪ… rĄ1ąsjŒq_³sņ ;y’łf”—›¤+D˜HˆąÉ±³™°ĆHøˆI.×Ē D£.Cœ¬“ ®ēæC=61’bĖ(ƒŠö39Ś€hdčHH«,ü>±³WjD_ņJIfKgśy˜0>cėiäZX)CE•¬Y&£Ę¼­“c%2 očMcā‘ąŁ³®(ÉhŽ «Ž‰S•„šf²"oŖ%9I7ˆ6“”MZŅ~ž1„„/ ‚QäĖ(gœršL—D'æ<%˜ō &ē¾ęćd›iAž!% ®2Įd=Å8a1A!gžģ±`[ ¤xÉ3FĄÓÉ`1]Ē8ÅęxšfČ÷’Ó g’ “Ē7Ą`ADaÄą§ą¢1ÜY™yL€”<üę™rŠŽp:ć;5OÄMa¢mĘI H²ÉršTŖē™Õµ¶9ķ•1rŒ³÷igH;& ZėyL; Ć ³jÉĢ泈2S˜˜[)R­§ź"™•||&ŸĒ1Člš«dÓ 9e‘B½dēęq’L§"a^²ˆ •™B×3ꙉ‹B”pŁŹ‘es*åMd=’Ķå2lš¹É3ZĶ3iLXDc  “U*SjŹŹÄˆ ¤|“'œ˜©Ą˜²62U34VuœHŲT™Ō–t’+ÆŽÆ0ٵŁŲŸŠœf²ķoŚéņ«™ØĖŖžėlśõ`Ę9¾G¦Ŗ“Ҭc£ 4/µ¾ŠH3V¤’Ę>³ß«łĻ!ū=lØņDäŚĮ>!³>™ĒדY%[A†ŸxĶŲ ]o،%Żš CŚ#s € fIcv&hÜŗāēgųɗ4fšq*ūhµź9 ¦ J{4Ōž»bć¾SøN‰)Kņ˜ĻųTk‚<“ENŽēēį俦Y`)×4c„Śf½¬(ĪWĒĪžīČ3©:¾į4tÖĶĢE‰ß‰M]“;ĖQ9ĶØšq²ąõB7ܟlÄžCüū=ŌōOźüųļėĒū÷Æ6oź÷©\øśķ]Dæ¢ōg¹—*uŒ†Ź]=Ž Ļ®ž¹łż‘§NP”SŌ ¦6Š ~?żpżo_߆‰ƒMĆ’QfHeU¢u4ÄĪ_†ĄaRčįlŠf^R…æ^}z¹5z”ˆT„7ģI¼'r?ž¹Ć”ŒdƒSļŽē(…„Ÿźš&­ŠĀkåė 9|’@ˆą•²Ćƒ¤JDŪ¼-zŻš„A.c9ĀF)‡ļH¢¬ž[[ĀÄ*rĢlŪ½s)¢“(æ8į^ØžĆšŁ—ƒ{é‡gē_÷Ą±õÖYOę­tĆżĆŃ"­HśŅįˆ°č“٦_č€&Īßž4f^Ø»C­²?¢¼G¹õ·Ä•žŃøįöG- śhI½‡ēQƈvŲį(”ŚĮG9¼B*³ŌĪšŸIg³÷fbwIĀĢqŒŲ«‡#Z`t¶uöµyӖ±Š%š<š}äĄųbܾ|@wƒzŁsi&=ŚRN”+/_[„©’ ±…ÖŁč› Ć=ü Ś ĪŚČŽ©üO¬¢Ä~T5Ą”±ūHÅhįŲ•@$Nlö¹źŖˆvēŠ6ąÆĻØ÷†ŸÉÖUŠĻ%ĻQ658"» c™ż,Ū5‘—‰Ż3óżLž“ńéw˜~~ jĀ«†Śė˜3VøĄ\œsš cŻŻtUż ó€Ā$•³ß§„}Æz9£‰'”zę@U‚„|œ4|DĒi¦ˆ|T…o8nŹ1q&²ÖųF ĘCŸ.O”:{FNõÆ3˜(++žŌXų%3 Ł"›‡Ü;CSĮÉcœ^'p Ń7¼x ³‚4ĆīōĆašæ[8Įꔥ†›D–@÷đwÉU5I1h’'";ҬĄ>\ĄÕ<«iÕ¤±B™äCƒ€ü«‡·“{ŠØœäz¬ ÖH”—F 'ŃB·²*ŚĀ-i„Q­ŃtgÅŹ©ļ–Ø ~bq‰0uõ† GōģQ;;l›ŁySļĻ+ļ±3V¹e㑨ŽÉL¾öį,Ū2“t ¬qÕnÅübūrAŗµ5± `Ż÷نŃÄżįI~’\ĒYŲNc Łh`Å•g2IT 2D&(“b·‚„k2CAJ8ĆżdĒŌ\[Õ³^)“*¦¾ą§ų=*MŻJl¢ö]ęšÜł·%¶mLĶǦjįbįŪY‰z§ģ{µ›‚³ļ±óźq•£Ųp4/ØŖŲb6Łž5ya›Č朕pm6yĄSÄÆÖóZ¾–žĒģT?Ua/WŽm™|ċŽŹäTi܆Å]ōxe‰®»e’“ņ>XNÄ5C\$%2/½õøźŠ™ž/ÖšYdWØŹØ°“"Ś8vrü\X:Ó¹ŻxåHŅØåŠāŠś åčŋ_•±w—ƒ7YQ…{Ž/,įvĘ –ļ'=‡FфØ82DAīU²üJćcŃ7Ynķ{^$Į±UÖmʁ‚W« śéģH§½źWOõĻżü¬ŗųõlŖƒ$ e¢A_,Yry1ъ!r˜GpGax¼āJL²źvsR·“U•C,bcJ‘łš „uŽ9-^;Ē8ž9x“ÉIt‹ŃmĶrLŻ} åb÷įŻąŻļ+9„L«ūNp¦„>© Ź‚ķJÕÓ-‹ŗ¼žmYWžV™†7T9W ŅÜ]ŗQI[ ūėŻ % ½­8kÖŠīrßyRóÜōf~MӜŻķFķż®{VēcŖėŒ½°ųFS7=œW®ļÆõÜtĖ]Eŗ$8‹/+w0MėżĶ°ˆū9?b%˜ŌZ°öÓEŠśIÄRģ³ōŁÖæļƒļµ:éšfæ`mS7­7—+S¤†U$AUŪ¤gоćQqųA}®ÉČņo é_c?ā,Śjł*/‚cŌMoĪܱZāš m©Ū}«vB,bėߣ™MÄ`ǾÓ'Å"z0Nņö…v“({ĘȬÓkx É|ė^/īÖ<ųĮL“±ĪŃĆWPĪ /ü÷ĶĆń!×J¢‡kŌßļ`?¦;g„Œ“š¤Qą€Ž0FÉ0ü.]™ ģjŖ>Ž\½õ“Ŗŗģ_(O12p©v—n^ “D!˜‰¢’ ö»µ ĘOōśoC‡‹ś„°†N;ęŃlI½eģś>‡Õ>2iČk`łŻ*žõ;DD5Īü³čšQ˜°JØz8[ł!=uEeTl ÷&=¼Dh>pbēd©AV}2šŃS“Pzµaį1ĀŻ­`p’2nÅś—Č5]±Ēž^£b’×®ĢҨԻ殓•&£Ū…/žEx™fYLu ²[äGßj‹Ó­¶ynĻs®éņ»ķü-š 7·tq€5nĻ1äa§„ųķ,ÜõS,lłÉņŗõāĖ®5RÉį–X‘/N¹ āyŽĻqY9«sÆõĄÆ’DĒĻZö²”iæ>­—P“|`„W¹Ō“x? ŗ—ÜģÕ½»ōÜ{$æ—čX¾Õ·ŪŻ0aō®V·żīvWÆįłp~Ę ō]ÕÅż«’eäXBģÕĄŁöčĢ„mķš{—HgoÆ{>Źkę„gÆŸžr„Ź­nļž/×]ŹZõŸ’©›8{¾rŪ›7^¾1FW^"V.žŖīšĒ%I+/ūŗ”÷gVś}h7.|Ģ$˜‚.ųÜĀ©ę‹^āgAĮ‚“} Č/?D=Ō—ŸŽ”»sWš œz0Ųy駏ĘX§°[)ŠųŪ=~hćä“lę¢j@N¼āäu“óž(›ø~-1(ō ž{“ü^šć’5ĪætPƬŠT¾Õ¹ 4N>:ņē‹”{ś\ė +Ÿ-uµtž’S¢ÆĘ擛y[[ŲŹTæŠÜ¦2K£¾ų%l@ˆŠē6õQį¢Ėa½Ė ö0Šżk»ö‰` OēĄ`¢tæ œų¢wŌż,MS |#[w³Ź |.<$žqō-Ł«õ3vA9ƒŃÉc…ó£Ó¾y¬čÖ]TX4~tUxŚųe x×āŠĪ^twsĀJķ܅ļn`0«ž7ŻżĪµ}¹Ųó» ^ÆÖ»ż;ąEĖ {ś/攢ūŒc@#å½=©ģsW‹ŹźLēŠü.«ūSU%·ķ?‘ķ˜Ye“¢ćusQæĖ”Čč[ƒ×(,JŅ7ܟlž b mWendstream endobj 60 0 obj 3882 endobj 63 0 obj <> stream xœĶZ[cGVČUNÄ%°v ¼D䎾TßOH€”š’h$Xž„<‘²ü~¾ź>}ŗŽŻ^Ļl&h³ŠÖ]ī®®śź«K;łf«•±[ĶڇۻÕ7+¢ßŸüönE¾}>ÖĻ>kž\öLŸ’¶żz„•v†“ Šåb ąńē¬vŪ_­Čč tŚš½ƒb—ńÉ$!©H[—(«hyGP9`ķŒryLņJ›ķķŹ%k¹m°Ī)WN"蓉”ĻXG§¢Łg‚"[N4 Nąä‘u„#Ÿ‰ŹāLĢVyÜjmRŁA‡N|{0>«ģė­åSŠŃ(‰LVY¶ÓūȧÆ]8A&a'{ū‚Ł’Ą7°§­ Ļģ6Z+łÄ,”¤\`ØmōUbĀAøx(›x   ’“WĪ9ė•aĄˆ&@,LK™O$8L0 ¤!X4ī°€ŚĄšÄ \ø ·ŗyo0ٱDvqŲ<\'®Ž®¾ÄD Ī{žī[ܜģ,9v‰Õ™Ć/$D€ dq³aąc,77­&’JÅŲå5G\ķ28’X¦-GģN9°óMrœ$ÆŹ{)1ˆ†‹ˆ “¦^žĪZM„i”„gyO¹{¾ÉjvĄY•€er¶Ū’bhŒ •Õ pasĻłYBšį; mmę\ƒßMā\dŽj˜؁¤ŁG†y a†g’§c•K ‰&·°ö% -ü1Ą9«rž×·āž*7O>Ļp9¬aŗT„ČľSjP„ e@0)š][āfė4[=x|1¤äYBjĒY@¶itF(•Öz𾘚++²Æ°ŅpŲŹq^–šĪų¾Įx$S+±)mi¹F•h6r”—TėB¬¢ś©½iĶ6ryŽbG -pÉźk¶ŌVÆ&Iņx-ū‰ZQ°A¶Q›Qrq–W®/Žqꛬ¹Ī‡®øĪ¼@y*e2–2i99·żBŸ§ŲLŖ„M@))åŖ*,ѳ€K©Ń&ÕĪS ³5śGɗ*! >–›a6rŗÆq‹Æł4I˜{…ō:P‰Į™€Ļą5X³R1Å)¹x :[š×\0P„“LæYŅnq¤£8ōtāūaYŲt÷óĆs­|Ÿ•×BģÉu“­/…+ć+®“łžĘgĆĒ5ė!Øś†ŖŁ=’śį)žŗŗłķŚŃø5,ĀlѶ.ĢĻ—źd/ ŠaŻ}ŁS”æŅZļ_Ļīķ­dÜøń¬×²"}"S©E_–©Ąž}aLż)ćœ²dŻ"!žæx1!Öą‚Ę”‚NLgĖ~¢ó<…užL}{žčŹģp5Ļf¢"¢ló«(Ā®zńōŠ *›“’¹œłį‘c_夿)|Ä9m–qMDƒä!ėg ’¤qT?ؼ¼¢ō|օć’.Nżręė=]†Ā3ż,ģ?€ ©°lų UŌŽ7Øł /€ö€šsq½Ø÷Š iįŽKĒ8°@uõ!&®ķłłqMr Šblļæ”ž={ź<;i}myųŽŠīU‰bŲ<›.bÖ Ź(ė!=6Ć@rx"“ęWŽŁ’©ē?ež}“68”DėEķžņōVe”_šŗåäœ~ś’ó’Ļ“D“(éūA”æĄŠĮĮ›ū>ĮtJ:苾ęźÅqśµŹI%'/ü¤“”·>Üė‰2`äŪücjLFN.TåPüī/ećlį½r°½¬ūs:ÉnŌo]ŪÕ{rā(Å÷Q[÷8€'É/s§å¾`ęĖ«õņMrV­¹ |GÕśŪ„Ę£Šć;-я֗eø„{įa—ożŒŠ.Ī’3T„ԟnVŸćĻ’ĀĮ „endstream endobj 64 0 obj 2744 endobj 67 0 obj <> stream xœķZŪÆ$Eϲ‹ā°‘•ĖœD!Š™¦ī5QP$_ 'ńõé(3KĀ>ų÷ūūŖŗŗ¾ī©ž™³nÄ!„®oŖ¾ūµź|·ƒT;A’–›Ē›ļ6Śy»s6ŲŻć±åūæmōöŒßŽ}»ƒŠŅå€K{gœÅĪ)”wO¾Ł)Ü ĀΉ€ß5ėˆ/kqašf§ƒ‰ƒW“Ć Ńa­å ćĪÉ`!w7”ŒŽ9„õ Ó 3ąTĮ 6bķõąåĪié£Ņ‰Į œ<9Ogü pĘG5XPU* Q‡DŻI‡h3Õō儗ƒĮ‰hŌ ˆO•ų3RźĮŃZč'Œ ŲI’?'wFyčב¤Žø0’š-…”§ĄA;Rµņ6C¤%¬Ą©E\€oȼŌēĶęļc“| i“>`<ƒ]Ņ ›‘Ź$›ét’ÅCĒŚ‡Į°¬JOŒŠRB`.} *ŠŠJ#ģą!œVv¤0cF…(°"ƒ#3-8ŃP‹ U«¤°‘0hŖŽžö:5ńaŒ_d6 ”Ž…Ø7›Æq#9m-żā+Pj‚*D‰Hęg GF²$Å{Ÿ(¬Ņ›!$fēd ­#|$L(²(¼;DGĀČa„8"ķk9DĀŚĆP„’™üwĀ*=XsÉ“Ļƒ *›ęė*Ł!ē¢*R0P”—Œn^'Étj¦h‹ØQ™0”u„1AF. †Āå\Ž,›S)įQŻDÕ#Ł\nĆFČ!C“š iM¹ˆÖ “&«T¦ŌT•‰AEł)˜±ĄšŖ62u3“VuPŲŌ™Ō– tY’3ļŽļ0ŁµŁŚ/pސlūĆ"]>c5kYÕs“MĆL=€8ĒĻČŌ•VœumtĮ‘ šRė Ž±"õ“öy™ż^M?‡ģ÷°”ʀȵƒsBf}3­oF³J¶ƒ ?ņfkGYčfĆ –ttąd†tFęĢ’ĘģLŠøuʼnGĻš£/iJš āTöŃj¾ŌSŒ*{“Ōž»āĢ}Ēp S–ä1‡ųŌkJy&нĻOĖŃĶlƒ„Z3[+5?aFŃĖŽā|uķģņD†¤īųĄq講‰‹æ#›ŗhw’£l(ršAĶÖɂ7Gŗ”ÄżÅFģ>Åß`ŠCo@’¤Éß<Ž}|½łšKæKķĀõ×ļ"ę5 „ŸåNŖ41zYīśń¦»Ó_’cóÉ5”§IP“S4 ¦1Š ~æütż·'—°#AŲĢB1Ź ©¬JŒŽ†ŲłŖūiƒ”Bwoõ°A›īĆŽK  š—ėĻ€In "Uńu;ļ$QpņĻ÷{„2Š ؾŌļĪQ Õ½>&ŌīŻӏuč÷ĖĀčīG=eƔķäó6JŁŻ’ą[ŗī^ h3¢čutŻOš3&sŸg‡~Ų“ŒŁ ŪāÅ*ŖĪdķs)ʓpļõ{8ꁊ=ś,iē„ļž›¾^‚Ö[g}āŃŽœ}ŗĒ{D…ÅģĶ½ßźüŒÉ¶‰™D°öČ5bwżWP¾Óļį-]>ićĘi”ž=ęĢi×{dšė^śØ„!}€2ÅžŒN g1¤čī·=5õŽ9Ń ' ž<ó‹]S(2¤F'©’ ĒÓüóĒ= ‡\ø ļōŌ[ 2R•ā  IÆĆ1¼­€y†±›Ümśż#ьÓ™nĮb Ht4zŠĒv“ķ&w5c؅ n(Čcgåą Jē!z{¤é®^7(GYŃæ[ˆŽ.Btǘ«!šåNg/é Ś†Dˆź"b>~•4§‰óN“ i;“ÜŅ˦[2Įg1€ĪĪK4…–ajĶKDåf8Ļ'‡¦¶én]E[ŲwV"»’ “W3ab?dÉĻC§qFžw%õ?ˮՇźŽćĄ?Y‚ˆY˜£0Knzę›M'żØ‘“×ٽŪré»ķhŻn«Éļ®N“ÅÕoGł ˶”¬}ŠG õqō8C£3žG],DA‰®„ĢJ[‡FVXT‰ŚÕ½H¶ĆYō¾ļ÷T- “ö³čRØrƏ¤gėÉÅiĆZQ=—ŅƒDü³:7ÖYj¶Ym¶ +:ōŌųNß×JŖ Ī\³Ķ¼@4“A³½…²,OߕńóŚ@‰±:p·y°€b×§…õDzZ;śāA ^gö·-ånŸRcŪó%¼9\Ś‘,•ÕīĀ›…pEń„]ØĪ33ĶJç¾åõ©ŖžćõĀįį|lņĢĶ9œu”qä"c¼Ä0—ŅÄk=†·÷‚” OuSę‚_(Ÿj6;Õ¶įŗī½d«ž2˜ØĄū+Ÿ«¾“jߣī?˜ŗ¾ÜmBŪ85\ODæøbŚ>ŗķd½RÉc¼WnMRĢA0šWU63«‹Ü¾ģfō(õ.ūź§k×JWH¦e„Ÿu…9…(kÕł‘|ĄŠBŹ[Ir§·žž$fi¦(Š2¤5õ4Ū±õŽr<A?7ī<šž#÷«x¦‹›Ųńų­o‘Ęs‹Ūģŗī'VzßVi[÷‹3ļ®750.-øŌĮ›ćd-Li„!li£ytÕl‘¶LĶ&¹å ķ9ØZøžł¼ę§&N¦ß»},=ĶF+²ŗ3CTO_ސa²Ē~ļW‡ģ ļ4Rčš;•F‘yݹäąn5ĖńŖtŪŁˆnŁQšßH¹§ÆŁ™R/k2SņźmP*€'bw¤Će(Ż[¦ÄōLØōjņ?›‘/ø}œŒŅœ-Yż­ĄvžmZo-&Vo¼“æēŖępœ”æžœo=}Ł)¼ZW­GČöįmL“qsyŠ+{É-’JŽż÷gžV<³{—«–›Ģ"ŖŌ™„ĄŌ°mŚæUŅł”J©™[ŚJä[2Ž«¹`yZOwĮŪm­åͬŽ.žs÷įW ōGŽĢßärė1 vŸõōvnįȬf)2wætS8¶Ä`‚÷`³ž™śzL·õĢłšæ—ōWŠŹ?uŃ?z“å^ōŒKż‘“\PźGĻ`„¾ÕŸĻ*}+U¶_²O{0Šõ:ъ©fndŹŗ»,F­I¤ÖŌ³%}v-ÖøujŗÄÓ\‡^,7 ‹Tž¬¶Üßįń^Žŗø)³{fqzĄģ­gåāŃś+Ÿ€‚øōŽęDjéÉi{|y¾>¹”§ĖČ^6Ēw—-Ś Q.ŖŌ÷żdłyķ(ļ<ö™^ĶQ]{īgšņXśŚ”:ŽtQ囮’n‹4ī/éŗęÜÅĢ ü³üĪ€÷[Ąfm)Æ^ž_y'•÷}h/žßģ–SĶ Ģ$yōķ$Ÿ­Pv7Ė.ĻĶøµ”Āō÷_lžå?Žiendstream endobj 68 0 obj 3593 endobj 71 0 obj <> stream xœķ[ŪÆ$Eģ"8lÜ,søˆŒ@ ¦ī5A$Q_ 'ńõé(3KĀ>ų÷ūūŖŗŗ¾š©>3g#1²!ŪõuÕwæVĻ~·£TAŹĆõ£Õw+ķ¼Ż8ģęŃŹŲņ¼ĻĻ6 zN{¦ēæl¾]‰Qhi„rĄ„½3Īāē”Š›Ē߬ŒnaćDĄ{ Ä:āÉ@\½Łč`āčķpctXk9źøq2ŲQČĶõJ„F£7Ni=źtŒ8U0£X{=z¹qZŗŃØt¢@p'÷„CŽĀÓ?*œńQT• cŌĄ!QwŅĘ1ŚL5=9įåhp"5*āS%žŒ”zt“Ö:Ą #v’dąĻɍQśu$©#.Œ†d|K!FåéÄ 1aŌŽT­¼Ķi +pźQą2źózõ•1Ś>“I0žĮ®i„ĶHe’ŽMˆt:Éā”cķĆhHŲV„'Fč)Č@!0—>Fh E„vōN+;JR˜1“BX ‘N„Ń‘™ĄœĘhØE€†‚ŖURXH˜ “@UGO{Œšų0ʂ/2›…ˆPǁØ×«Æq#9m-ż ń(5Cö¢D$ó3ˆ„#€£@Y’ā½O” Véͳ-™=Hė Š, ļёš²Ÿ ŽH»ŃZ‘°†ö°T©d&’±JÖ\2OK'ў))Ah5h%cT›Ē'ÕHå²W“‚“gļi;CŒ °U e­¤ XƒÜ¢µ'æO®!“a;ĀŸ‘Ę‘‘;ņšhų©DŖQ‡"̱°¶) ä€cĄēŌć¼¾ft2„QždŽéeŸt…)#xrģG "Sī0.b’ĖĄuą1ŃØĖ”•Äõü걉‘[F„¶ŸŃŃD› CG¤”i•…ß'VcöJčK^)Él‰¦Ÿ—)ēĄglŻ -ƒ\++e©(G%kbŌ8J/ČÖɱą7)éMkā‘ҳg;\Q’Ń„¬ŗ&NU–j‚dEīTKr"W$Ż ŚLR6iIūb(P~QŒ"_FAyĘ)§ÉtItņ ¤§”&}J“Š‚sS ‚ł8Łfڐ!ÄRIJWa²žb °˜R!Wžģ±`[ ~¤xÉ#ą‰2ŲFL×5ØŲO„|/9½p&Łą@g|@„F ~ .ZƝ•™×”0„æRØč§3¾Øįx n msžŌHI6YN“Jõ ™³ŗÖ6—½²Fq–ē}:҉ CN­•F^Ó hĄ° جZ2óz&Q …‰ A᱕"•ŃJUɬäš™|dPŁ4_WÉ&9U‘‚ ½dtó:I¦S“0ļ@[DŹŒ”¬+2qQ0.[9²lN„„GuUds¹ › ū Ńj†¤5å"ZS€ŠZ˜¬R™"PSU&Få}¤tb¦kŖ6ŚČŌĶŠZÕuBaSgRwX*ŠeżÆ¼C8¾Ćd×fk€s‚dŪļ[ˆtłŒÕLT¬eUĻu6} zqŽŸ‘©+­8ėŚč‚#Aą„Ö bEź!iķó2ū½š_‡ģ÷°”ʀȵƒsBf}3ÆÆ'³J¶ƒ ?ńšµ£,t½bK:Śs2C:#s € fIcv&hÜŗāēgųɗ4%Ķq*ūhµ_ź9 &•=ZjĻ]±qß)\§Ā”%yÄ!>õߚRžÉ"'ļóórņ_Ól°TkšµRķ 3‰^vē«kgOdHźŽ÷‡Īŗ™¹(ń;±©‹vg9ʆ"§U³N¼>Ņ %ī/Vbó9ž’ƒzś/M~üłśŃę“«ÕG_śMj®¾Ęx1Æ)½–©ŅÄčaxd¹«G«į™ķÕ?WŸ]zš…@;E“`ą÷ĖĻ—ß=>‡ ¦aÅ(3¤²*1:bē«į§[p¤zxkK“äÖK  š×«?’Ü>*DŖā6$ŽDĮÉ?·Ż!”Ql@õžv‡pŽRØįēé1`BŽ£Zx­üšć-„¦nø»…›ō†Ćå=Ś=^äsō膗 q „žß’HY’g›ŅÄ* ŠĢl܍s)¤“,ļowš/“’axų-ŲĆč/żšģütÜ[oõƝ-uŸVŗįb»³Ø+’¾“Ż!,Fmv胭”FϘlŠ˜9AĄjŌ"6Wåg¶;8&U‡GŚøC=q•~‡öć@Śõ>Ł7Dć†W>jiH ‘Õ{œ÷hņÜp NЊåš iŌŅøĆ“J'YīĻČī’r’eČlw‘UŠqXWčkó”5c”‹ąG„ĄkĢ™㫾ĀS{¹Ŗ‰C±õ$Ś3Ձv’ ĖγSŻ÷Ln†źbÖל늪¼·ĆoH łĘĄ1(¹™ ‡_@tå¢9¦;Eę†ę›ÕĢ.—ļ$§”9$*UŖPe[;ĘnŌ¾W1Zm‘M4ŗ.„mėóć‡[ź“5 ē;Ū¦8®ģ;ŠłŌ™õ@ÅŽ_“Kķ’‘v]LY§ƒō™-õpõXEIƒZż¤©õīĮKĘłEOœžēs2~^ėłÕ“83 !Ž“F;oø×œ ųTm¬p ōf÷±+P—9FžGĀĖ9ė°”.–BhŻõ¢^ą±×]q{9€ļäT‡ME}Ÿń%°n#Įōaš©2Ōj¶Sč¹ThJÄ”āCōˆĻ·Äd€˜—Æ€ ”(0~5Ž[pÖ/Lt͘+$šåf'…0%BT+‰ćū2I¦I!ƒ&ÕÄ`ŖŃ-ą¼ž*ĻŻm­BEj•ƒ¦ĪKeg†iń#:.ET8ō ē¢·Ź6t­®¢-l;+‡×“ęµW™øÆŻŸvųmbP¢‹³ł¹ē“ĢŗŃŗĶŹ($މm²q7?½ŁMUæc\U^–ųf!øfØI ZMßÅüä­t®¤.‘³DäN/Œ’Éz]Sk n'UM²Ē<óĆ<¤1Øņ{8$¢! ‰|Xk”!Ä8%¬¬|‘l޳h’?ŲRY‚HĻo›TS'¦Bo߯ßW kEõlJ"Ybų ‹Gs†ŸŃVń[k#jVtō©ežŸ»åjNžƒ:KĮ<ŸļķJön•ģ-4‰Š†•ńÓŚ8źY, '£¼Œ5ķė =Õæ.˜é]Žß’+…KšĘlO½ė'ŌŁśØZ„„ĢQt üŗę!žżŅĘÓo¶»ÕsAõR”Ʊś‰z¦ńV„oy}.¾§x]hēåˆRbo¼ös›&<Ž’\dŠL©ńSŗ„ėG=•·÷‚ƒĮ„+ōt”QęÅ܅ó.½ŗĖT‹¬TmƒÖōęĮ–ܽ¹»A„Si­ņzTĶ“›ŸŖęė¼q9“-49—ÆŅµ€QŽŪ›7łŽ)“õ-¶ąąŖ©‰W Æ|ŠMmūŲ½×J/Øų¢›5ŽŒÜtįnųżŒµÖ Ž~Ōš’{5µÕ Pd ń~oįŃ#ĪÅ„÷óć åQ ‘é䨺Y„…>Mż¬2ų=j’aųŒD×O¬ėZˆ“ÕÖ <ŲĪ.Ī?lQ·œAWš+ĘÕŪżĮ;Ēw*^]}ųS+sĶŚŻļy6oʳHŗ¾NöNŅ'VĢ’]«Č’)«üŅB×^ž9Ż£FōÕ±’•źlːAjōō£cź4Š.ė^ŠGÆcÕSxoįńl՗fķæØūz”ūMh[§†ė‰Ųź½5Ż”**yS·\ņļ–{ƒ×ÓŒę…mFĆQܾģVõ(õvÖOÖ®•®KZŗĀœB0§ØÓƒ_åć6’Ō¦ųŌEnĶ= m¾¦ź2u~?·t•āÉ=]ą”'v‘rŌĄ– ·A7]dC˜ęžōxśø˜Ū¶žö÷·rĪ›-š|E©1bŽ:ĮÉ“ÄGs|bN.Üņߣ’¤Uᤩ{—»§Ż£i%-¬bsĶĖ?‹<ķw€’Čõi¹k¬ĮLĄr}ēļņ֖~'ŖeÉ#z Ƴ˜1osås«Ļ<½Ł²½œyn;Åsn&r„:ŗš8¬vĒ©“Øąć¹ ŻfVØN}†®:žßčŖ¼Æćīé…zźāP×)’²ò@=ÕØļć-^Ś6rõņŽāĢĮÓaĮĄÓa-ĘåķB:|µvĖč©O"Mü£B³¹~ߞ.2i†“õŪʧhŌ-o*«,šU^÷Ó=ļ ¦LŃ͊'›Y|]ĮŻSꄾ>üfj±M¦O9˜Ÿš/»č—Ņ[ū…d)eŌj1æyۜŸß6/Üt³ÖÓw}®7nŪ$Yś5ƒ¤ßƒ —®7ROŅĻ“*‹ŗó¦Ēƒ ŠÅ{śśįöH‡‡ äīQƋ¹ĢæxĪ½0ŅU‹¤;‡Dč·eBµW UW'MÅ®8N~Ÿ}Ŗo¾g Ęé·|ė5·Ń»< Kīćńt0l±O#ōC„t>†ņ|@łEŹ459‘zpErZž—ųxųmD;jkĶā[䟼诳$cæ×;“#ŖKßļ”ŹpĪGfśž …/}H,SŌŅš1]IQčä+©¦%:ŒTŒŽ/QŚū«*°y¬—,ÕśĢN¬”~S:lJłķŽ’UŁUeßåoõˊNĻFøā’ŻśŹ˜źę_& ę"›JŲU*»ė6ÓÖŅͤŸ:~±ś7 Ż…šendstream endobj 72 0 obj 3563 endobj 75 0 obj <> stream xœµZY$GÖ²k@½ƒÆšŚŠö» ˜r‘B␌o¶Fāó4`#4kÉūĄļē‹Č¬ŹØīźķY¼`!gFgFĘńÅUćo÷f²noųŸyqūl÷ķĪĒö1ä°¶£0Æļź:Ćk9ÓÖŻ³3“ń–Œ‹ąåS¤°Ą=güžł×;²&N&ļ£Éų݃±/X%ę)ŃŽg*Sr|"N%bļķäĖ>Ś&c÷·;Ÿ›Čļ£ó~ņrƒ&O—i ūä§d÷ŃŪ8‘“37póŽyŲÉ$¾“&‡;©ø)ąUēņTŌ²7ļQcbŠyŸof¹Ń8ŌŌŚßØ{¾ :€Źź­b°ģ—'fŹ,Dc0ĖøÖBŹhÕϚ«)S0gPټŽwĶ…ĮÅUdęĄ…ŽŖwė^4óŅ$,'Šq£²p˜÷ż…Ҥ˜9ĢR®õØŗE' ė&ŖėkÖ(w•āŻB‘=ē"Žs€šŽP5©•ō\•YĆEł®$Pk°ējćÉJ7Ć{×÷Ā"HgŅO.Šóž?õ„‰śUh«}:ąŁ(Õ÷wkŠõNšJUģm7Ļmu}É+ó€£¾c„+ķ<ūžüĢC(@iH3”#=$ļSŻVÜ»åē\qŗJ(Ś:øglµ'Ѳæmnµź;¾ÉWūČYčv§(mt§)Č rĒÖVMK,ā ā†ŒŌ°ä9i %ŗŠŃī½õK4—=Žś¤”ø‚o ×V˜Ŗ&Ļ4%I’ķ9åQ ŪŠ—–mĆ/­®5«½sėŌTŸOĢąėūoTŠtĒwš‡Æ¶Y¤˜ć·‰égė.zĢf=ir«½xšöČ6œø?ߙżgų’×ōŠš’dņÓėŪgū?Žģ>ł"ķ„]øł ć]Į¼¦ü³Ż['c‚ć‘ånžķ†ćĶæwŸŽ0{žA;œ ŒŃXČūÅg§{~q,¦•@(FU WM‰Ń‘Xœæ ļŽ0[küšŽČ›= ?ėD7&˱”’~ó°F¾;Å:Čč“°ö¬é …)FKņŚxØF݁ć5"»Xć†÷e™1¬ņ o’wių`²mČ~¾еãńŚ£Ņ'ė†7Xо WG“JßL$7ü`d…Ŗ#īķgčRŗØ6‹—÷1Jl‹&×ę€<|ł äō1Ł4|oY]Ą¼!…Ņšpä64Ų8üx¼(0z¾>^#fnué㑸ć#ŖŽ(UD®OČ1fó¼ü`¼J0²F,łą5 Kō(ł×˜0Č©Ų ¹PŽūā-YŲĻcvM 7'ŽĄœW=yNÅo²Ļ=z)Ęoŗ\,̱2’SPĢŽÆ1+» \BLNX&Ŗß²\æTĀl²ś>³J£ē $ģæ?X°'ŠÕŖ²oTōų rS&aŌÕOlšFŸķŌ/‡‘ūĒhųó ƒĖ4ü²Ńāš _BXeHūC‘1‡¬ļžŠü›¹ą2u _j&@·Ė *Č£§Œõ6‹Š ‡m„ fx&0ÖϘRģµ±Ū·FĢ ˆĖ¬Ļ^œ“!‚‘"ž°éEµPBļaŽR‚_irÕ1¤ÄÓlߟį‡'›Ęč6äd•'}y|‰hmģ_ņ؁]żģåƒć®O9n ¶Ra>ł#> „¼żŖŗ¤Lų.0гɓbÕͧp P4­Ÿ{“ÓÖTÜŚÅ«čžÕ ÜJš±PsėĢŗ†W›fŁäŗŹ) Lŗ RłB »-—rČ6¶1œpw Ō8EÓ'5HŠ’aWK„šń[–™(Ž޼r6æQ©ē=Hj’óa]/®m,|Ą“ØĆQųņP:!x¼•ÕI—›H®ŽĖfj&MÜ| 6w¦€UBļńkÜF§³qūseˆU4VĖ2(cµī†Ī§R袈 ß&s ōāĹõ£ÄÉ?o%ĪSįcsyQRc3ŸĖ„ēŹ­rŽęż3•ż  Ō'Ɨ×ļ<ā¶Ś‘N½|ø©Ė•:­M(ačÓ$-­åœ‚Gč¦xĀŌÆLÓĶ ÕéšŃ¦Ī:u)) õ‰īć+œOģˆŹ£¬-Q«™SõTäõR£×ĮZķÆ‚µfbŸÜ†:‚ļoéå&xU³«Ī>óÜ)Ąoc«¶b“Źļ÷˜UāĀ4‚ę|VŽčĀ6ū%›æŸ”~Kx• ى–ōEäŖś µ·žæ.µx]5ēćš$>ø€ÆĄ­äŃŻ{¾U2åüŖ²/ėżæˆŖ^ŗy¢ BÕŪžRœĶ(mW:\WŠh°} S5Ś©adŽ;Z1³ Ėļeˆ[įdSŚV÷ČKķä™Ń„¼ß”PóĢÉß‹oCf'Ÿ¶<ź6ÖmW³Ķß/;õąKQ£>ķŖü𛑂5ƒ‡«ę±]z¹ś±ųA°bĖdóҦnzd5yō‡p“2&ĄMßI 92ŸI-7żø)ņń|¾śtvĪ`æą ˜Nvć«BE§®TŪņõ‡“ݦ.gū¹X?®y×6M¶ųu„ŪĪčõ·ą×iāwĖwŹļŅ"ÆkÄ=ZäC]<ŁOėü»]Ó¶ ŗż%źįašä?ēWöś ’cå|Ś]`Æ#QéyŖG~é4xoÅāv}V·./uÖyŖįœŠšpۘ¼āqYę’†ĻŲørŠ—Ļa¼„²LH˜>rŒ&WRŠ38U«_ėzjÅZYNå>uł’Žc­ ó6ž··^V޳ś BłKÓē»’9ćß#endstream endobj 76 0 obj 3074 endobj 4 0 obj <> /Contents 5 0 R >> endobj 14 0 obj <> /Contents 15 0 R >> endobj 18 0 obj <> /Contents 19 0 R >> endobj 23 0 obj <> /Contents 24 0 R >> endobj 29 0 obj <> /Contents 30 0 R >> endobj 34 0 obj <> /Contents 35 0 R >> endobj 38 0 obj <> /Contents 39 0 R >> endobj 42 0 obj <> /Contents 43 0 R >> endobj 46 0 obj <> /Contents 47 0 R >> endobj 50 0 obj <> /Contents 51 0 R >> endobj 54 0 obj <> /Contents 55 0 R >> endobj 58 0 obj <> /Contents 59 0 R >> endobj 62 0 obj <> /Contents 63 0 R >> endobj 66 0 obj <> /Contents 67 0 R >> endobj 70 0 obj <> /Contents 71 0 R >> endobj 74 0 obj <> /Contents 75 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R 14 0 R 18 0 R 23 0 R 29 0 R 34 0 R 38 0 R 42 0 R 46 0 R 50 0 R 54 0 R 58 0 R 62 0 R 66 0 R 70 0 R 74 0 R ] /Count 16 /Rotate 0>> endobj 1 0 obj <> endobj 13 0 obj <> endobj 17 0 obj <> endobj 22 0 obj <> endobj 28 0 obj <> endobj 33 0 obj <> endobj 37 0 obj <> endobj 41 0 obj <> endobj 45 0 obj <> endobj 49 0 obj <> endobj 53 0 obj <> endobj 57 0 obj <> endobj 61 0 obj <> endobj 65 0 obj <> endobj 69 0 obj <> endobj 73 0 obj <> endobj 77 0 obj <> endobj 11 0 obj <> endobj 81 0 obj <> endobj 32 0 obj <> endobj 26 0 obj <> endobj 27 0 obj <> endobj 82 0 obj <> endobj 7 0 obj <> endobj 83 0 obj <> endobj 21 0 obj <> endobj 9 0 obj <> endobj 84 0 obj <> endobj 12 0 obj <> endobj 78 0 obj <>stream xœķ{ xTÕŁš9ē.3wÖ;3™É$“äĪd&ėL˜d&{€ Ł $$²’!¢D• !²\@ĮČR—jQśW'.ŠūuńÓŅjµhmmė'¶jAńµO!7’{ī$m’¶ß’}’óōžŽ“sęœsĻöīļ{f‚0BH6#ÕÕ6ųHyņī‚ba×µ}‘vĪ›įouݰιе<:~ ķ’\Ž·āŚžņO<‘×ā^\±jĆņČxķļJüSϲĪīŸż6f>B…šåö@‡Õ©]‡š®ļé¹vŻMū}k¼¼juWg¤=ķm„ųĖ×vŽŌĒ“U0žičt^×yķ²‰ń°Šé[½v]¤]¦ļūÖ,ėūĶĘw_‡ńp^F࣐Īõ:’&Ė«¶ ¹éēų{Jłīd]ī’ż=ź‰ü_yšė$ķæ»/¾oƛq#¾_‹×ć•8„»p3”[”µ=® z}„80ĘnlĀ*t 'įxlĮ,Ņ@ūŒ¹ØŒ<¬”q!śœ(ŲB» 戎DgŃy$c:i¤£čAŌ„špNĮxśVƒ±Š:c^†9æBæG°·ąš¾‡čÉlŅćģøļ$sÉ%փTųFbĘ+˜ēšEĢc+ö ēŠOŠ;LxüCüś“AžB7”ōĪĘ!ę&‘Čėä„B…ły¹9ŁĮ@V¦Z†Ļ›ž–š’œäq'ŗœRB|œ#6Ęm³FYĢ&ŃhŠė“A­ā9–!łpŲ^Ś4£ņ:\.WsĘD;öėķ0“$ž§+ŒĢ_äųʤøo“ćæŃN˜jĻ £Øp…»“Œ.<‚*~F–0Ž #ŗ ¶Ģ…&&•w÷ŗĖW†cJ»;:`F™[t†+.ų'Ž¢¬=¢Õ”ŗK—i2|hD£…Ŗj0¶oWĢÄJ…T”ޤÖgųĀfo˜$•ÓÜķź€Š» V‚7–+oŽī¾ś‚i“5K¤†Ć|iX„ģė\u†Ń.ēˆoth÷q-ķšźŗŻŻ‹spĘÄ$•÷4R<–ÓÜŃć ³°øR8 ĒYŽćrSt”÷t@é.ƒYµŗ…Ҧķ®QGŲ Ÿåa“7<FĢī?ė`†Źķ+“94“Ż~`~ÓÕo]“lnn¶Ć‡ŹŻ° ,VŽ[ Ųż¾Lčīč„{övŅs–÷:‡v-SĪŗ[9ƒ2“¼Ół÷F •w»Ė»;»K"«—†CŹjliRŌ•5OtM €7¬ņ¦£¬ŁAvu}S)=˜»³Ģ!ūTOĒDt”O¾tŅTĀag—3Œź›Ü04ŸĖņŃPW¾Ā<®f ³ź®Ģ sI¢Ū9ō ć÷łs_ļéœčį“Ä/­Vø+:††*ÜΊ”Ž”Īć曗ŗ¢{h¤ŗzØÆ¼v­k‚YĒǟŪåWģn‹=øpO9 ¢¾©Ųį25O6ė&›X K«€X€æŹ‰Ą2jlr9Q šš€§&Zo„zä“20n>ŠxmGĖņ§ŠS:Qu¹(wī:BK”Ž<æ)Ņv¢„Ž'QČļztŠ7£“o¬ č›Ķ“o¦¦wøa—§5ØÖ°:yźĻ(Ś,å=…alūƗEއ-„MŒƒ4GjÄĮŠšĘ ’>=ķ…zŖwˆšš;,zĆ\ÓØcz³S4 ŌkpWĻoir–MqA¤gRŹĄźīĪž” Q¢LŖ dčwĢ į -M'D°¤;›ž$˜”v”4xą]Ó 'ØV„—LõŅ–“¶P5eĄ'‰Zyå8Bh³ņ–U:”v×qŒ”>õdF]ĒI¤OTśą×š£ÖŹõņĒ{/­Ņ?Ŗ`ģźēIŚĆlBK õ H!“<ˆ§ĒĒĮĮ!”ńĆ?x¤?üŽ$ „ŗĻčÄÜŠ/ń[{MŅiČ?ü*äW ’;ä— ?vŠ#‚|ą Sŗļ`ŖtpÆCślŲ*Ž‘īN—ö'Iū ĘĆ0ÜųŸųž½1ŅŻ{½Ņž½. ķÅt£Å{µb®ń¤tŅ’ń?Ń ń1ÜĻ`ēŸžDÄÆœ_…¾b¾ĄāEēEāü¤īā?W|®ö“ł‹¾_§žL•ž|Ź$łŸ*~Ŗ#Üī{“ūą¬Gz²’,Żą©ļ t£ń§”ņóiŅė_pJ?0I£_„|ē©ńSÄųÜ]ŻŠī‹ohå®ųfä…gķŗµk×z’ψ@wļ®/łˆ„§3ü‘»läććžŲ]†'¦^½TaŃ©VäļŖy×+żėžb;e•BÅG…xųˆz–',¢ŁśŻÓJ‘•é2¹LIP`õēĶŗD?TØ4^Gxf%“ ³ćB"~‹ˆØä ?WĖ‘6Šß†üē³21ĢgVŽqäį±ę= c2šN˜ē™Č/1z įZ܎WćĢaŪyeZ6¹H†<®ąN˜€śĘßćBܧ(|óņPV9)×TŖlėČ:ĶFĆF›Śq°Š\e&f•ė`_Ī>ƾSŃI ;‘ė`]S.^Üvž²2ŪpQ°;19%™äd›ófā`Ąm3sb²;‘7‰¶` — •Ķ©śšč‘s•U%eUUēžī‡U•%ņ¦Ž{WmŲ°Š|tR~«½³«{éRģ>ł}œŠµté²ī„ņ{'±įƒä ņW §Ąm°ēø_ #Ź IÜc<ęyo`ać£aˆįČ£ˆ)fV3 ćo»Ļˆg‘,PLĻĮ†É•ȅSęA=w9Ź?š3čĖĪfq5b–±|n²ĘŌMæä§pŸ€Č¦ŠūÅ£]”LĆĶz1˜¢L.}’)[ŸmšmZhZj]gÕ b4jﳨHÜ܁:āśP_GU‰MóŠ#ź›mŲfŪ-‰"° ń·żā—p(sAŠļmSĪx>č/ml 9ŒDk—ˆĆī'^{‘½ŹŽŹµŚÆį®±Dėۚ)ƽi8'×0ädS«Ü¦\OŠÉZ£x „ŹÅU]Z½ ėēoX¾ućāW9gcė.pž“oßÓz<…ž²óŚõ/X¾ŗ¦WK3’ųÖķņöĘŪć(“»;ÜÜŠöūC} “~ZhµLĄ”5¼Śibā4w P[hĢž–ȞQ©­”Ļ˜›µócź§wć^mwLgž ø_».ß1sFĀ” K™™¾ū$![„כīb’‡ k„v‰HYŃ;³¤Ā¬ŽaJ"¬œeŽ.8ļ÷·łĮÅę(K Ü^ˆ{"Pŗ=)¦`šZn)Ó°›®nNaŲ12͚€ŁćY… ßč„üUCŹĀO» wų“|Ó³²†ŠźĢ»)Żē›ęNéM^ņėIõ8vĻķo–××ø%ø†<—Ž×¶ņŲ¬āŅBž]cqĘĢ.5Ū(2X£1[Šgdä‰fݬøŌ5#+-k÷’›’ĶaP„ƒÄ5Ž_ęŚ!:Ö =Zš›¦Ā¼Ž¦÷«ŖTśfU£~•j¹¾_µ^ÆÕÕé;ō}zFĻó*^Ąśƒµ0o€c8ŽQńL­¦]C4*AĒīŅ`l”x?§‚² `'@µ`KADfx»ųn;ŠŪڰ›²¼ ŌGJ®żUyϘŸœĄŪ_ū‘\‹ɏąVĖt\ŽObĒ~<š0š@:œ×‹śBó“ łÕu†:CdŠŌEŗ iS©žeŖŠnR7¤ÆToP‹ ±“$óÆŃīćcœ‰»¤Ö”'EķtJš(Š ńj”ćlj½ēżSŽ÷+äÅŅNĆAŚ-kD½$`.}QĆāOļ{ź«yé­?ļ)¾Ū›čö'åĻlyd¦uUHķž/U“.ĒZ÷ćŁ5•8/WęΉO–B„ŁÕŃ.«ddęČļNzŽ3T3nøēpēQšzCՙBP“™J5³ņėāźÜ <Ż K³ÖjÖ։kkāÖę™ćy’!§Ķ{ŠÉ›UE‡ų˜ų›M—šŠT‡ē|MgyĢ5Ą SD(ź“’šśŒš«ÉyZ|5"¢xkķ¤ŠuNcĶü_Ü¹ķŻŚÖŽ–åKqĮŪ•Ē&;n­=c›ūŻ®EūB Żr””žäYšķėH%Yiq5>W¾“ö•ņŖy•Õ ±ųĀpęś¾›£8łWz×ÉG§¤ś  ļNl««l‹‹³F5ÓÜļO—ā€;>ōwšhn(“Įļ"„”¾&s€ć fP5i%$“ZŅNV“„'` ‘±˜H80iššėX MaÕóŪGģ¢ŽóŽ-‘ÉÉ1†½“}ģŅ"öi®kü7Ü\īs‡¦n -`Ң҂öY³ģs³q»¦ŁŌīhö-Éj,h,īUui—™–Y»×n6¬³®‹éŲyāĻÉō…| ¾öœ„¾5¾uŽ.ÖĒ2ĪC ?d£źZŠqäŁl(G/śwĘų&čX’¼Só‡$ @F`aJNąbSAŌ¼TWŸĶÕFÕ·Ķ( T˜@Q §,ņ ¦±i>§É\ŠF³¢Ą£XW"„fNvn^żšø"ź4ŽčtŽ9z&¶(”OQz"BĮĶ•ŸßyäÜܚʭnéĒs° Gį‚Į‡öĖ]ė;=ÕR|riM\gł“TiNŸėÆ·|ßMĪ…’LJųŃå²éEßjķūŽ,~ś±›Fžćōw{æSȽLRkZĢ&Sž»ØÄ„sŪrŽŻ2§*ÓčSV—÷l“DEϤRŅ3ž>h‡O)é•$N÷LO«J¬ōT¦µˆ-ęvk{l‹cIį5…ėČn“±?õęBs”3’P“ļP4ļTz8ČĒD% B|2HIq`g¼‚ĶIٹP4¤lĻRŁø¢ņ"ĀB‘†\GcJ0&qFGfēréK{å½^õæ© «;ęķĻ-ŖŃ/Ś·ŗń¾ā†.<v½5Æu±|«?-¾&=e¶KJIOr·ēgōĘ3ĢōēåSׯx£Y…“ Ī”ōŒķ큜4oŃKwŠ3@hä/·÷ö:ć.gϜŠö8‡-Z§M£ųyŠEl—ā ʇŒų—„ćÉ©xōZ-ĘXQĻą—O8t4‘EŌ;£™¼ƒw^:Œkął:š;‚hŪ ä| ō°õxäÓt|üū”‚.Ļ? u¼=ŽĶ$³ijæąw»›I3»HӷгžéŒ~K±eµeĄĀZ,±{t¬3#3£#£/ƒĶČHރ,–Œć9(§6§=‡qnāŸĶ/žoæ (Ŗ¹M)€ `v½^ īÕ 8“*©æ‚y QŠ~ˆ3ķߑ’°lŁźŽeX:ŗäŽPéµi¾ø¹y›+ēļYTY;}ĘžŹŠ…YŽŌüåł•›ć—vvāÄS#Ų¹¢k•ÕdńGÉ÷ŚKœN_°Øąä¶Ż'sóüéžų»|(Ę'Zm€§Są~śH‹f‡b…=™|ˆļąū ® óš`na4{°šŠ¶Q“ę©Y5Bz^ĄĻčÄ/ĒŌ|‚+$Q¬ē¤Iģē—^esĘ*ÉmcɳÜėņļäqČw”‰?‚TŠāöd’é !*¼GĶØŃ=M‚¼?­_[«%„P=£”»R5č śANnŠÆlłŃXŁ8v›¼…õ²#ņåߍ Ā.m„ć}Ņ‚P¢ĄŽĶ3ęn¬Ö>Ø·÷AÄ`†Ńė$}¦>^K•ā] (ŽåX@-h¢vŌm 2ļ_¾x‘é¹x«™—°ZžÓåāIø.Ą>r‡¢ĆīēæõG# xćÅ/żGq6‰-öĀ„ŸāĶäIīõKµkšoĮ:ōĢ ÄJ€mِāJ:“^-ƒĘØ…8¤Mf|¬_ć×iŠ“µB„¦_;( iļīÕŌFåjš5d€c5qs·YN8-8¢a?[Ģv°},ĖŅvčfµˆeT£Ņ @Ē Č€9xł,xāÜÕ3zĄŪF”PŒčmpĄ”ĢŹ„ˆ® \&/ų׹0)]āߒ·ČēäÆ ļǧ ƚ‡O1Œm Ū/;ø×Ē¬ä ÷+Ęß旃ē¬UāŖ@ —¦JÓöį> ł€VeŻ«b…tX×^ޱ2I XŒ›Šń¤ā$ģÉó(’wńźøJD.'2)å×Ģ’U²Ę/—{äał>¹ćx9> 3ł¹3ĮŪęTޚ(žl«ŖŚF>”ÉmųŪø=(·9ĖNlŚv²pznöōün¹ķł¢¢üŖ½€nÜ. ›ˆ$§˜q¹q=ĖÄģU©ū^@¶iS!Ŗ‚qÖÖk»$WČEbTĀ3NńākÓŲSaķóSŽWĮfÄsūŗ³ĪķŖ˜Õü«o*o&7ŻńoÕ-ķņڲŒékŚK®[:ąMr1—ŗ_œÕŌ"Ŗ³²ŠŽ·šķœ\b÷8›)§ŅåŖįÄ*ä Åbv‚׊øÖš7XA- !a@`"Ņpvģ¬āu\‘7®ZöĖ›e?—ČŽ\ŖeG”Čś1šĻĄš&”J2©ŻŽ¦œYOI&l6Że"&“%dĮꤺSuæŠQ ·] ‹ƒ°¾B¶ŲF1Ł9°Ó9,Ÿ€4‚·lŁ{×mx qG½ƒ“±…yörūĮį½2"<~A~ˆ_ņf:†_ļƒ#~UŠšČqq£Īä^“zč°pü?ŲgŁ­g¢å”ŁF;狱Wr•qĶ\sÜ5ÜJć5q7$­IėĖŠćĻ$ÉkK éy))ī#^QÄfĖ”pę ’¹€?€©R*IMU Ę<Ÿ¢°“QM „¤VŁkš$gޢڧX0Zi‚I¦¾ „ßIM.¦¾ņØ/·@g•å®N_˜œ³¦ģ·Æ[֍Sļ¾§łŸ«ć[!ō6ÉqŅǼÕ`š•ćöEEY|C¶™f{ōl<ęJąŪf›°Ń˜öĀ+c,Š©  æžŻ‚RŠŽ;“)Šb²!¦œ­Q×51eŽj©UŗFŗŁiHv‚^ˆ:>~†šOĆńń߅¬Š!†@#dŠX£ļՉÅģQ<@čōxāļE6yDĻ€‡ńųÓ°'­# ĒnåŸO„‚j ¶AÆXIoÄLz#ڃ›rė"žū9å»)ʑ|~÷ē-ĶKW.iżdóŚļ7­EŽ“„³ī:x’޲k=‰Ł¶ą‚ ••æŁwųlõģ’@Ŗ|ڜm‹öšCJÖ(ŸU>źś·ŒæĒ~ĀG! r¢™”Ō*MUģõ"ćL('ŚŒģ÷Dœ°Ÿ³™¢Č z.ѱUż¼ @ˆ·ų<%/=z[%¬;‘˜®œ4ąUGg?‘‡Ūź=żeܲļw.»µ ƒźIntßqǚ[²®[_3OĒŗ;ß­­nšŗšo.%’Ń0rų‘}IpNJ©Ėģ6džŗPƒ‡x5A2]SJęrs5„†±…kÕ,p¬äÆ:¢:¢Įw ʊŠĀŸÅÅébŽ˜E¤Õ ź.õZ5§V³Ć:› ŲŃÉŽĆƒĘēć³ pż“¾Ė$æŗ"^ Åŗ{RŸš’"Ŗ”½|łeõ‰§×œ™™Ś’öVłqy/Ąi،£äLo_Ļ65žtpw½_žm–gālĆå`’//ø~ĶŖ½`“·š ȎB!ŲĶa+ÖŖ GLF½FƒP¬1VŠ%j£Ś¤4¶ėW뉸<@æ(@AA±žāHď]VŖ™Ü9Aą"Jf‹Ć>××[mņ—ņšæśMŻ–§S™k®.^ŽĆ¬¾(żō§ZrƒÜĢ~ņ ^ć‚Pž<Ū¼ŒyĮ6[[p„­7øIŻÆ[ļīj­»÷^—˜lĢŚowü^>Nž+pGĪ“­Žē³Aü©&‡ģ<Å&uȓ¦‚Õ+ł L{оÉū&ߓ̟’Į]ėßoš•œŖīŽä’āf}«óÜ8š7»ä„e­ūfčq›<,µxīøcƍ¹=·~ėķ3óā¢pL¬7)ŃŁ]aĶ™ 4NÜõJuÅéLŃ 勼 *śłūLÜPE˜čŖ—ģEyæŚl®,ÉéN„ēl;ŗbõŃĢU?YzģyæŹlŖ*ĶXČÄ]>K²ź×z<.ÆżņY¶ėꏜ®ŽÖžwN%‘¬†5Š/Mq=@÷×¹ŽųĆõÖŒėįH ÓSž.— :z¼®Ł:,ˆ®aĘf܊N&9ĄPz=¹™tˆž¶7Ė%Ė/Čæ†ō.ljąĶ’ĖŻnÓŁ’=?ɕ’čr6d5“,PĮ/įblÅŃx¦<:öŽwĆ5]ŪRÓćŅSv¬X¼=-Åć¢RyTīęf–Øu,yĖH™±ĢYo¬·,3v[6Øā„čż&QgLø—·iQpšDƒCŌp)Ö‘ā ŠU\|žk×tSČ2OÜԘ"‡Ÿ¹ |ណmm ß»žēÉ·÷m®Źņԧ޹›ĢŚu¶j^]Z’ģćĘחŌĖ?‘Ļ=|?öŖA}DŃŻŻŠī¦g- „PK>ףź¼ĘŁ'ö;UԊ›ŌŒcĒ× ł„Ŗ¾źœ.Ó7Ģų_Øcyøéѕ?żB1ćķ·ĪQŌļ”—»‰fvÅS ÷+–\į<ęmv2£üg±®Ož©xEk šŚg4jDŲQž(¬S ',“į.œ°x̹ēu’…°0o;£—'플āīĘp•%ÓĢčŌź(ū˜Čv=²¼”ŹõķąķōŽ2іšWŚgū×ć Ś Žõn•D:—"<'E&Šž±©l-ъzÕ­ĘčpD¬zI‹āńX­5źÕ* f0^ ]‚‘Ė7Å=”—>I§ž:" ”h$3qĮdn*ܲäē§ļ¹“ö|ł b4Ģ.‹k5'hŒ¦£?%ś‹ ø/^”×5¹Żiv ģū DTŪśjf(MĆĒņ5–VĖ*Ė€Ŗß¢"VN0šök+ŒQ[ŚA5ÕZē• D‰A&µVĪĹ®:W‚<ÜżµĻż;īÕFYę–OėĖĘ=7×Ōžyüjģ×'%%&ŗjO@sZį$^Ā-ýÜõóėÕkµ`čՂVĒŽHŌ ˜1 ¼Kł¾Ņ@Ńą4„ >ņ=“× BįL”k»~”%¦ši)ˆś§zL~XŽņĮ{ņ&łī½€‹Ļ¾@a%_ŒiŽ?3<ĶęX F`Ö¢ó!£Ÿ8Õ I³š%Upõńńc”dØÄqm!—£‡K™RÕ<”/dšø…Ŗfa‘Ö uŅK*ū>Ø0ąŠh‘VĆńœZ„f…ź)wGĆh0įx­Z…Ŗ!ĒĒ_ ™ą…jĻcµ–7*¤~ VŃDH> –@ FĖōŌłaE–°’ÓŪ#æņS1½B¢NŽ÷śķ££ā؂Ø«GÕ£"-øQŹH ¶“”(ŗ0’_ųRīĘĻĖ5ųįsēńa¹×Éa’Eņ1\5öÅTŲ²hĄ” Ż*VsU\ÓĢ-g8čhŁļāąm'Ą—«Ž©ˆBr-£āģLćåņ™^n#YĻōsėx-”𹁛yŹŅq‘/śė Dš µ”Ō§ß.F4·æøķj®nU Ž0¶»Č#į5cwÉżOĀńūńķä̟1~˜mE,źŸ¦š®ÜEƒ?–‡~{%Ŷ ś¼Ų˜8@oĢ9{*$Ø„“­Œ7XŁ4]²yƒī3*ĄiēŒIRIJJ„߇WŪŪķ«ķœ=ĖqĪćuOŲćłBTŖÜQĢO žÄš© Y?ŒM°Ēgž0'ÖĒ'9L ³š`X†1žøP؈ĄŅ+]Ŗģé×7¦Ū[¬‡{­ß3>d}Įų¤UŻÖ F HĆIsöO ö·QÕIµåł6pŠJļQä½Ś×a®Ŗ«\ŲMo_§¾N™ø ³F")Õt™“@āš%¼Ņ„Sņzł#Hėń.šu¢ń®äĻäK ßij[ÆĖ-Źė]ķˆ™•VĢ©‰Ž¶‘;ƞKׂ){äÕŹ«ńž­xŗü¦ĶļZR±¤?ńcG†Į śÜh6(‡ŻGD.t$ƒl! >C/ž"?TørłŠ6śŅö"bBHś;©-„ō ś/#F²‚¼ĻÜĄŒ°7榒E:éTŅ %ķ.&ŖeŖSéCuŹ_I3 TŸf{„1M™ę”k§Az\ūŠ®@·Q÷}¢žżÓ ĒöĪŻĘĆb@¼ė’]2uż¦›’•ž•ž•ž•ž•ž™żÕēÄÆ¦éĶż'x²\Z䛿hNķ“· iįģŌ֊šśźŖÅ#ž²ä`~¦Õ%66Ō5—T¦Åƒ 0Ļėh‰³üw’éŸėaŃ RŅļgŠ…Ąų8”˜–4"Ņ‡ę£EhŖEC€¹<“50üĀVTjP=ŖFUh1A~T¦ÜdēC¼oE&Ą“ˆQŖCĶØU¢4QF£yȎb –p ‡"ÅȬünA¤§Bhį²5Ż×uFŽ |āžaˆ¾ńļeŠ…ńÆuąÉax*““č朙·Šuä,z–f.Œśø0ÖĄē Č»!7B~ņ6ȇ wAīaņŃ{/sÆ J¾ā²Ædv Ś8™¹tJµ/’łÓ0ö]su^‡ŅųōŲ?’¹šųgJŗŅĢ>ƒšøaŌĀÕ”&¦y•śSč(ĄüĶÜ„~T}#:Jū¹[”ńGé8ęĻč(ū"jgyO”¹ JPA\ ŠårPĀ’Yu õ’³fą©ū"śģo<8’GĀO<×nœžrDä{«žD?eö3ć½ņ"ż£jˆ‘ Č <’½÷I endstream endobj 8 0 obj <> endobj 79 0 obj <>stream xœķZ|ŕŸŁ]­$ėĒ®~Z–,ķŹśaٲ-Ū²­Ųqšb[‰ÓĘIG Q"’J“`HŅ$6 NĄ “„Zzü>zeqJÜ+W „”„–ƒņ£ “ø%йoW¶IRīZ>½ūć>vōfß¼™™÷ę;oŽJB!¤CCˆD- —„Ź‘|ymµu®oOeŹyw!„Wt^3Ą·uu€ąU(æ³:µfż”ĒŚv"D<‰āwkÖmZiƍ!Ä,čénļz~Ó%ėņaUĢɬ×R‰Ņ =ė6Nćą®u}ķ™²ć„č³ėŪ7¦čgˆļ@ū“ äÆl_ߝ©÷œ…,'Õ×?)ūäśŌ†īŌćߏyŚĆxdmFY0Æ7ŸQ‰ŒdņĶ ót×äGčéRMѹš DĮE’5_t\¼įøS¦kqn‡4ēāƒx;¾ ÆĒ«št½‹Ų„UCcōvKet’ŠĖ8Žė”ÆŅ©N'ŠIō!ń&zųėŃč:…~žˆõŲ‡fƒģ”‡h š¢ø·ą|ōjĆeŠź<ū6zĘŅC&Ģć|߇Ē@ŪŪ‰ßĘ7_!>%‚ Ų‹ŽCŸ„’>ƒA’EX@ĒŠÓč)"z=J–“÷”½č›čEņZ Ō¶ÖTϊTUV„ĖĖJC%ÅEĮĀ‚@¾ßēõä¹yĪåĢuŲslŁV‹Łd4°Œ^§Õd©UJZA‘FEX“5ÄFs”A‡ŪķŽO•ķ–EŅĒžĮ-"ć=”{QŁyQŁ5SžŖˆĢb“§”Qźx5½-"“ˆĶ"’FĮ¦ÆĄHSE»z=ѵbNCW2 O4zX^lz?45¹ļQMVƒ§”;«øfi€ÕmS£øé,3DS“f”@*]q‘h Š„/*QÆ(ģNći„ž ĘōYĶŲäųžó«<6Ķ™2éQ)ĖÆ…vķęG‹ĘGöŒ±Ø#ŌvyŗŚW€åŚaŽ£ˆōE{Z%;F%Jöš"Ė™$|“‡ńHęˆö$!÷4ĀSŸ+±ŗ!¶Ė=īpŠ† 8ZĢŻ|ŚAŽDmky©82²‹ļZ;æÖ-åńx܉z Cč,Ś[ŖŲBÅE¦ Š•ģ•Ęģm—ęķåGvwĖsŻ#ĻAn큅i’[­FF¢]žhW{W}¦÷Qh•oØuyLVLןM5€J®I6ĘŻc7/Ž5Hó“7:2Ė>#INI@®ä„̃D¾“Ńā˜šĪ’²īYh¤s– wĆS-Ÿ=%*|¬‡ł‰8é™xļBIū”„ö±!‰mņ4%GFš<|ÓHr¤}lrØĆóž‘Ńęę‘T4 £¶ÄੱÉc»bӞøČ&{p Ų^B@ÓāXĆmˆO[¦‹ ĄŅČź€ą3oźVF­17†Z‹;ĄN1‰o>s—€Ąkī6 ēāƒšs7w7±oƑ»h/nŁ›'`Ł £±ü„0Ń2A oą–×RÆI3lÆĮŠĀćj}UėńäńŌq’9†…1µ”JŖ,8¢ÖT½uŚĮżˆż=žÕ«F.ōjŻ«Ä¼āąŠ)öŖōTņTź-µfNe±U-O&ŸL=Ižšū9ņĄ#߇īC‡ėāĆF.õ0žłFī ē·–r?‚ūų*īÄfīĄ?1čąnŽ“ĆŻ“;‡Ū³;Čķ r#ۚ¹·6sw¹€vķnę®r;†køįAžś0łü0žĪvwŠö”fīŗĮfnhŠĘm,į·UČÓ¹g›ž­*蚯ÕÜļJv]ÓE³Œ›³Z 9%ķęrl…Eŗ9“±+*f ƒś@ćĻ×{}LžGĻ»§wä:u¶»ĪbĶÖMfĆ“Z^«ĪŅhi„JKR -Ā„–e†B ‡hB ‡H‚Auh!DƒBĄö{=&‘Ź1[Å15*ެVqh–Šk cŃ،š[ėE†ū’z1lS”Åby°YT·\Åųę8HEāv«HŻXn…ójłå±1œ#UĖĒpcxhų¦›3\<tŠ]ĶKbbŹĖ%ęĪ8 ĀÕ?Šßßüo®Qµ4z×āśŃw)épkßõ4Žžö]ł ėiÄbø€Ę~q[“GÜęiœ~pąźĻķÆ’œÉ °R±æMU|ī™łĮ.$$—§D4lEø™Š…$ =÷«ē䬬Ōmp|ahõɐ}*Ż0Ņ.æ"ōū§ƒ†…•Z’¤tzż’2ĒVgQ9TœZKm¤Tżµ$&Y[Ć`³LóŒĄ¬Ā-LN2ƒ8Åh‚š0 ŒZ‘‰w±ćeŲä6¹#åU‘KpčŻŌg]µøśŃōS³¢7…*ń‚ōi\Ž)Ņō”ќ½°īÓh7nÅļ‘ķ擬¢°[Y‹Åd÷³!›×QKW±•–JG3]o©wÄlWč›uƒ¶ĮœĶöģ:ėBkŸuP5hU0Œęv“’ąA"÷vœ G­ą„ļÄN½ a#zž)µI&×ɐ„źF«äŹŌŗˆÕŹį! N³«C‰p0”Jźė&Ā”DYi¢GŖ¼ Re…ß“G+=¦*oøœ²˜ „+ŻŌӟöU߇½ŻwÜ2°ŗē—üüłøpųŒĘ_Xs–~÷ŽECE ł5“æ” ¹ķ:*™pŽ r{KN‹]©ŠŒÖfŠ˜\›OŅyL%¶*M)¶Ōå, š4-Lœ]jźe:m}9ƒtJ{•n@挒«ÓönVc5åq$)épdļE&‡ƒŌJ®ƒChµ޳ŠC˜·’GņŲ3 Iyc5ģhIįŗä 5N(xdØ0Fdm³IO öä!ƒŁ†õ “ ŗļ„žŪ;ø_~āVõƊV=>ųzśõ»üa]`YńĘČe[ø[^Į]Ū·Ż\7'}`u2}(ż»Ćwõµ„ļ0†Y‹įÉ?ŽĀŪ§]%,¬Ć„Ź…XP¶*.× (”ŒŽÓ„t¤:+ėŗ ²µ2²ēÉŲdg z-€U«Ó֐¤N[Ŗt„šŗ•&³Č[3Ą=W^ŠŲ:^ŚD,®)lņ˜Ü¤‡ “ķgĪłšµē=Ņ «ČbUśOgėąt4Mžš:Cķ@ZTŽī=ŠŠĄ–Wص™3Z s„5ę°­Ģ>_ÓdoC«4‹óū4ł×šWyÆŹO™r‘VWī*w¹v––™KKĖĀÕeõ„įŠp_Šč"~浓ųXSŖ čVōAnn”i”ūży Łrõż&+¬MŌ%$%¤]8‘`?.7€B Ńéą.}IP)õµµŠŚŚ²R”by‰,™SŹOžæ²¢źÆŃĢĆ{­$ŻdsņŁs„„‹*7Uņ’³:–ķݶe_zÓ×¢Ź]Y‡U;°źJZL"Œ*«ÅŚR_*óĻz‰1Ūvē¶į£‘Š ķ0Ģ­®5ć,60²×,ŲĪQ€÷ł`Ć·Øķ€÷Æ ‡WĒF8^£čĒ&ßL¤FV£Śhm0.%ŪŌ­–„¶v²Ū¦qIĄ-†Ö¬Ć"Dz.ŠeĶ“¬Ėe?€¬.Ė`†ńœ½ƒ>>źD8jŲĮ  Æ"ϟ_źgmB6mł ŁÄŗžgšē-īļYż­yvŁ‚šģŪ’üÓĮ=Ķ /Xw·«ŗvöį«`²}U_IQś¹¹ŃŁŗeiEś¹P¼:ŠN¾©x‰6#+ņ£[…žyśÆų–0­¹ ßŌ:ßb‹f³¾ß¼Ł„µdūIa¼“°š š_m­ēģ'*‰(‘ ®&D~ æęgpL@x×Gl#†@D˜ęwdiķZB{<ߊģŒ,įŁÆĪ`d¢®³'2ź_%Į}Ćé)ø+ŲqøŹPBŻ‘Ļš`0Hv0‘²>Ìā„ōĮō~GÅĀŅāesīžŃšå±÷w¬øį²¾ļ8WzŪFJƒå+“eėĖhóŸß»Ś]i5›Ožč.œ³nķ_>~ķÜ<}ö‚śŁG–vÆ(rI6ižüµ‚§vĀē£Aa®O«a"y<¬'e±X¢®Õ"¶ÅÕ®źŃ&Ł•²hŌ Ś±ŻžEßob‘—õ¶x“Ž”Wįõņ²¬^ÆU§v’ĆVŁ„“·Z Ų‚PįÖL»“ Cµį3·6lbB†žAæ‰÷ĪAŚī\|ČGI²cE߁üŸ§ßL?½:¹›ļżtŅa=ūÄ=^óāW kß!žÕčb¶n¼āŸ~ćvŒŚW^łģ· “†¾śś–²ōė%!I{€I"¤s~„ 0jNŻ¢NŖSjuē×iLυ݁wŅœKÕd½’Č&|2 ڈBIØŌŖBł­>z&hšd‚³8!¹ٟŁ]ćēĘp4O$Ź`q՘t›ˆżé³éż˜Āæ¬KoÆ£:?½“źÄ£é’Ā ę£2ĄN ¢gŽ"nņŒp½¶Ÿ²¾œ|Saļóół`•Æ*Ųčk öęoĪgü,³Óąt)ĶŁę|ó ™2›‘ÓĮs¹¹;.³ÓéRØT;3.šŹ‡pĆé"ѱb¶ø®xUqŖ˜*ŖvÕū•ĪسĶ9ąT8‹Š‹jœG‹“·°¶Ū<¬‹Qœ(ׂA1öķŒf’—ŪÅ&ʧÜ®› åńql“7!i.a±ģĀL3k{!ŻŹ Ģå\eP«LļŪ®³‹ó;›Ę€ÕXē, ®Ęd›õ:Æ]Ówеódē¾;ȵÜełē|DYMÆ»¦Źē;{š(+Ūąš ä=Mun™·ø3ŁŽq ŹŲUŃ vĶA7…#ć ¼7Dlc“/ ‹ Š(0·Ń©¬”-•£l…)3bL,»Ó`4 F?…)ƒs0ptöjc½ßPiˆŚ …Įī°×ŽŚµ·e³F°«ī"KķOLķōqÉ`6ŁbeŅQš9ʙ6ˆ¢Y„~ ½oHĻÖĒ‚©¦# ? ś÷¹ņĄd·«Éš_ó_Z+i.«{ zžäÆŲĻäA>Įb;Ȱղ=īc}ŲµC}ÜĖ~ §Ō™ $-iY)†€‰¦ńʹ…|żlæ—Ģ•¾ÓāžĪ“Mž­„wœ—N}±D\ éwäÕä™L¢j§Ņ;Š„ā!)Ń,żme®ņ¾/ӗéĖōeś2}™ž‘$}“,’z†9ó;¶ŃĄžÅ‹–]Öf.Z:7Ö“ĄŅŅųE’%ń’ü¢P½œKß>”÷ ““c)‡2…¤ļŻżh1Z„–”ĖPXÆ-EsQ 5”ȂZP£ÜŅ(’>/šöŽŚŗ7tµ_)’ śÄß@Šæ{6żĶå}ōžä<Ż Ļń8ś‡I!¢"’0ż]óyD­œüä’’1d’ˆzĶWDQE j>Ÿ@ĒĄł¤ŗßŚķ§ˆüØ“gČ{ŃŌõ\ō{č__8C£āĆĒV1µ!Gfńžå©MjéžXéf]ś»éeŗ»UśRĖų€ė/‰¶ endstream endobj 10 0 obj <> endobj 80 0 obj <>stream xœķ| XGŽwUuõ5÷ 3Ćp8Č0 ‚N‹  šÅ#ØĻx%˜Ć#n¢&Ł5÷}ķfßlˆ£ »1Ē7ŁęŲ#ŁÜ‰›d£1Yćf•i¾ŖšÄÄŻwæ÷ż¾ē{æēŁiŗ©®é®®ś×ļÖæ@€lhl˜(ģ3k€šē-ķģ‰·é€oĪ[³Ź3łŽqˆTü‰œß¼ gįҲ©Gó@«Čłé…KÖ-ˆ]/ž€ś‹ęwvżöó[ī ½‘T–."Ö ł5šrž¹héŖµ±ėgĻ m¼½dټĪŲłtĀĄŅε=üwÜGäś]¤ŅsIēŅłńž}@)=ĖV®Š·Ńļ{VĢļY7’ƒäś>ŅŽĒBŗ`ćOņGńFįŽ¤ĶĮ?~Ø®U»ŌVīĒĄMīŁ Įaš H|śĮ³ģ’°/įŸ+ĄĮƒą·ąmšÕPŻĶąNšsŠwŽu»Xķżągą`/x‹æeÕŠ½»OłQ)ųŖ½^/łĘzī›ƒ‡®öÕc€Ļ„ķŪ; nšėó˜|Ū«ÆßŽSÓįé-}Ō?ł£Ō¾ ×¶ö™:ĮŃdd“¦µ„S½fŅJżt_żŌ¶OĶöŽx»ńšQ±³ĒØzĢ·M}LŪ¦·µ$ öl›Ń²A4¾£Ŗõ±Lņ]ĖA «E“–VŅ=õōz’Ųõ©6±o1«`ēó@Ąź¤Dó X)Q‡HŽÕ)¬Ž~©Šų-Ć{MvŚw"k$­: ]Įą­gßŌŽHkĪūģ§5Üe`.ĮbĄ“g˜@€  ~pČ(xĢ<¤¤ļÉ+.5ķńģQö4īéŁ³iĻŻ{śö¼¶ēƒ=šC{NīAdŹ•žĒ“’KŻÕŠŲģnF MķMhŁ x׌Gg ©Ó“š“é<}šOŖ›†'Ō•į‰uÅø–ģu”r\.ĘcĀcšŲ°»pUxGv…ģįP1.vį`؇Jfą’P:~­äƒ’“%܁Į{÷eՖü`ļ>“ü?”č÷ÉĘŅ}ĪZ¼fļ–½¤['÷īeWœQ÷Ź™„{mµųšmVܳ¤g-2ŽžžH¹Ć‘RŖÜīH-UnJ"„ŻI©„[6[ŻĘ«›;Œ;»ÜW»wøwvlڼiŪĪėwm޵u×6£r„l*5®pÆ@ŹrYWj\ =G ē>üÕaäłµņkęB0×4)ww"ć,Xh3ć[öŪŹq¾ĶŠólvģ¶„cÆg<öŲ*ńoœ5Ų™:§:+±ÓVŒķä:+é®ÅęÄf²÷Ų b7¾ŌhČw꟫wėž­wkÕ»e²óżõnüĖz7w°Žž¬wĆżõnšD½ū¹g󯇞Īw’Riī÷ŗŸ<ču?±ßė~ö¹ēõOzFß’Ė_é>ł”n’t¦žMżH9øé 2īļoŲß»÷Hq)>½’Õżƒū%\†uzDD‡ؑ‡ąąęė®sõķ& ļŪäj= zĀģ°īhķ“ź§Ē‹ĄO?+W­\éæĄ§«éjuö ¾ź•ōÄ@O „ł 5}FZ6śŖż°ĻV³ØĻFJ?hdeāć_’2ö v«/ōLŚ—UäH¾ˆ²…Ā äŸķ a@÷ĄĖļ¾Ģ#‹¼fÆ9‹ ¹źĢ&œ„’)P.{\ķāŒD"ŪA³2^†²˜SÄ\.—o€µ\-ß ¶Ćvq\&öµh­Š+ZDuė1”Š(’u„ØMF,“£os˜N÷ūƒHe„Ć#‹`ś²‘Łd) ŚAŻfIr8’8槏=’ücŸN½1\Y_7¶ņÖ)j×KšXH¶^ŅŌ=Ż»AżĆż?W?Ł“į…ŚĻÕ.tœõ³[)8ĮjēģÖl˜Ķe[³ķ”Ā)։öF®ŃŚĮuXׁ5Ø‡ė±®±Ł-ėVh cˆ±öĄą©}“Ć“ i§µn 3Qø!ÉtŚ’ż¾›č •––•ZB%(';;'tXŠqŅń)·UŒ­›4&|ćT2T©¾”z^ŅŌ¼°aLūłż0wCļÓuš—TéłCh ^Nzn»¹Į ͊l*“ØÜi!…Yh?C;ư-껓]† hæR»Ņ ƒ‚Q£5Hf :”7b„5F 4ZŻVĢzÅM’Øk ³f2 óZAŸ+÷č . O*/D,ååģ@Œ‘-Iå` 8²(żž³¬>+ŸSĖx.Če%ńx¹¢ī®ąÕ›ĘĮĖŌ«ĘĮnį .VŌ«¹K/yK½.śŻ%ƾzÉ[p”zĖ›—¼›™(Ll„”l'̇~åØŌŖ¶¢.büšÓ!Ä5c¢ļ‘“(Ņ‘0*P"ĖŠgEaõŲ æ€®čr““¶y ÉÉčiÓ£Ų`•‘Ø,#ßųvŠĪą"2ˆDŽ“¼!/'Gw”4ņqzo”¾dżńģGĶP…šĄągІĪr†!‚ˆ’8“{½>s~łÕWäj8ų‘ś7›ĢJ•,:`ź@5l† į„p Ō@ ā¤7ū“ ˆ>l=Łzˆ r³£ĮGŠ‹‚ķ»~±š\®üļäæZą[•ŒRX®-ŃUX*’KŅk`¶ZWo©O®Nףėdä­ć4F‚Ģż:į&/ J`Ć&EkŖVKJÉō+pg–1Ė…Ruō,Õ+ +½R0QL :z­ps&A“Ÿ`:’OĘLGMaķõP¦ōz,°“4T’M ķĖ ģ)ŲmĀžĮāR¼ó¬śzźog  uS’īKIÉō­kŸ³!3#őé]×5g#ś\]¦^7Āķš:øAķx|ź;·ŽüĮES.ŗØa҉·æ>ż¢i‘É€2ļ•üļ€lSBüAŠq®JF³ŪŒxä6B£Qg`ƒ1ču:”ÉąAan×ĆqœĪdBMDa~ hé9 G ⢃äŅé]œ 'LĶ™ōzi \ !, +ųż”AĀŃāp0@gž Ęģ Ö.- š½ørąmXŖ¾Ž•5"„oƒE7sǶŁm)Sʝy–Ģõ=d×ó'|ØLmtwøĻ fg7gš+ųQś!ģ §—»ėłZ}”ĮՐ^ēnē"8ĀĻ’›Ķķ)sR#iķ®öōn®K˜ožk_–ŽƒV™{½i½éYd4Ÿķ£F§aZF“±P ¤£`TŃ؝dEČ= Jn$yLv9˜ųu`J%M ½Įį -9ž;3Œī Dy‹×tšP‚mŽ[ŹIŽÉ9Į1 B*ń(,(&Øü R„NįA’¼ųśÓÅoĢ:“ć–kf½9_3ńų²O!öēē\\æų“yœ÷hŪ¾Ö'ßé]u•Rõŗoō»ælŗ±jģŚŗ‹=ƒŹBĀ  ǀʭ–8µö@ž6;WY© ŁFf”&iklć3Ęša+ßŖm tkŗ+×j×V…6T:KFWF£ }a”¹ęMrĖ#‘QļÖ#½Ž ļS#š¾c\ķĄ tw“ƒź‡§7Śäƒ›”1É)ł„1RČ<ĘQ/U›Ū¤yŻŅzIēr9먐%Ŗ Ė;)KHGF›ŠDc˜$h<žtüRAGąrŠø tą.&\6/šødĄ¾w ÜH¾ĶC™¹œ‚Œ šxąŹ‘(U‰ųńE0eöڽ꬚ęÉUµ/\µž£‹ ÓžŌ=qsIAa(Pņ“Ł-÷Up›¢ćümŽuū'7¶Ą?.śÕø õĮĢ7Jźr‹żk¦t{²ŻÉ:4ųØŗ ć¼’²_ÄuÕCüqŹĄO”Q‚Ž”/Ļ Ž –ÕeU_Ö›õžFļ|ļź‘'—Wē²Z“&¹8# Åå,X|^`‘‰¶:qNm1l6ƀŅĖHin/7–»ĖQĄ+SuG/–oEķ/ʃ„ )}Č,Se)'T QÅ((Y²QØÄRVšIi`÷Q²1Ań‚Śģ!õ­?^²Æ¦9ŅiŽƒyš“åæö÷-næ~rKėKeį=cšn˜‚Šøņ‹Ć×??žXż°züthyę0,¾tyÆF’“1Użė§Į/4ęÉė"ė =¶Ü|GžūĪ'BylŻJųī'[hPŠeØA™°Ö£“ްŠCĢ bp“xIFÉ-m@ĀFjP`jÕˆ[ؽŽšĖ åĒ·" 'ĘŃYų'Ń9æC/ōqgń7g |Ę£Ä^Y?ų¾’+H¹  JA6aX=!jցx!3Qš% trÖŠR”æÄĢ(É) VŪĒeTēŌķ³RŚRŪÜ32Śż­ķ#gg”uHs s-sS:|9k k, ¶X\śYöƒ”ķŠ0ēšhB”Z°B«4ś:EąńXnˆ·5Y)ÓšĮÉ;…|Ž/„p¹Pƒk‰†kŗš*ükŃČ%ˆĶ’ „qqĆ0(Œ=Œ0įȰRM“Rw†<²Žz4ō©‡b^ ßĀnž&īģ¹!ÅĆĻą ś6Š ‹dEF˜‡@£e@aƜ7źéāĪQu^ž¦³sš½tē wGū玲;ąēŁ#­’ü^Ņ$Ńźß1»RHDĘō“4IØ‘,k$“•<ÉFn’5ÜVā#Ūx^Ų(¬W¢QؾÖ(TbiM†ÓȁƒėyČKÄ%ĘĒė@&(U  tOOąłJĆūłR~ ßÄĻē7š"qm‰ę#†'P•n‘Ź0uM &)݈&:t(öO"ŅŽ†>"^ēåˆŌ³BČĻyć†čĘ~ƒŅ”“Q=«žw©üсµčh+?å'š_¾Lię”^l˜*ŪģYöRūxŪ,©EÓb˜eš•ŪĮuŚzŠcĶźp8K,(??»DŠ8Ąr¢¢!Õҁ‚pĮ²Žc×ŁØźŅ„Qpéłc D†PÉ6Żi׳„˜®Ī¼€R:O•ł e­µcv6ß«žmnĒ’EsŪ”žžµ_Ż`ÜšĶöåO¬™Ņ4~ĀS‹vžYjX’œŸdMÕٳž=3ŗ:Œ®ūĖĀ9uSź?Ż}ĒG'Mœ;—Ģ÷2ß{Č|€ ō+¾rKåb“H%—T"Jk4ځ†Ī!˜>0ųѐbŽĒxꥹūāŖ™x Ō}«ÜFwĄ­'ŁD½Ąf`mŽŽInQ¢÷‹TÕÓūEŚÅ )|½¶C ūꖤ3÷3ępDåć‘›Ę$ą#Ą.Ęē¤ a%&_ų=ŻøąģĖź6øźm[o~ųÕõėZoņɝoµ.[†žü’ŗVx4\Ö®>’»GOÖ眽*æ|āgŌÖ#4ĀwiĮ®'äLØ­›ÉlPņ!ÄiBPĀ@‚X©7ź” Ū 5LŒ²QĆÄØabŌ¤š95-°QĆ%ŗs£ŽSŲDb‚‰š°Ė™Ź 9¶ć;üÜ[_sFŗóGūŌE}ŃßĒūßKś/ƒŪö¾Ņ®ŪiGaHāD p ZjB|Sq²łėҵńYó’„ ü 1_Ę'P3l(~2–Sžbf³±0©Ä†AŒpÜ5¢­Ńu‡¹'xÆ:»/$güł1/įĻLš¢R!BY .ĮjšB†:8Ī0Õ0_˜ÆgXeX•fĢ)>čóé8“)©D‡\%œf 3L²É{`PU¬“ćŽ%3d›āČ>@ö'?@ö6R8«ų˜s½:ۘ­d#§]¶Š»eĘā²Ž^%/ʊK†€ź?ī’qbx Ģä„ŝėć8ߛ….ez¦™V”–1I}ļzõż­æPß[°°Ž—ōBł‹{MyĶ£ĖĪØļĀ"(t<]«.GÓ/5½££śžƒóįcźž’|‘ӝ§>­žPßWŸĪN‡KĆ_ĮšüŃ.È6nÉ$!Iā5ÄŹä%وuˆĶ'?£eś8±ŽÅ0¤©”Lv­…QĢČČee¤ZKXBŃ7ź9‰³}ņ:kŠOĄ‰‚Ϛā(āøbŚ-08ń?ą ’¹3® W/÷Ē¢sTAr ņ‡£)‡£?FŒęšG£P-”Ē5Dń½Åč1_ńÉøXą4\1”ōK5’¶McćxŌ 1O“;0ųĆ —Ą )ج£tMf?‹"-źß©bS”ģĒXŒ$ZLī ›"äµS»ā­č¾ēžC“Ÿ{īf|ĻĶ7ŸmóėŅ¬Ž8L$  1-h‰‚żoI—/āŅE.S‰±Ģb{LØŠ`֚i‡ŃgüŃ3ļĒ1sšōIė”YĶ8 āK5ĖP·ŒļŠō¢®—ļŃh›äfM›–ėāVq«‰Z× N@˜X”]ĆĢ Œ‡«ń L>¢Vę ‘$-”4]ŖŅ3įdé Ä)Sbž_ĢBepcqądM%3ØébP3 nC£˜ KĢgä1ÌU4żļ˱/rģD\Žé‡śŽĆOĶIå šQėƒxūJp7F‘VRÜӅa¤•X.”ķW€Č MāQ‰”—?}X»Fąup“ņÜĄMÜÅg¢Ä@yŽ×Cü(*Ē”_Qt¢[,kÄ©b§ø\׊‘ą†v”Dئ ‹a‡Š {­bµĮ&Š{‰^X ©5ō©Ä ĻĆhe\ž}v’H©Ęī1&Ļfōg2Ī„?QŠ!vbŌG,x†¬˜Q'؏‡ØŁÅ8A}œ >)|ĆØŌĒƵČ÷Øe‚ž”Č+–£—€1öõmtģADWäKĪü–?zVĮ‡ˆ “ršCžmž$H>š+%Lئµ$$!E—b™ gņÓÅvm‹¾ÅÜnžd²ÓHy2ŒĢ†“F^gG©%vä-‘5Éd|¬ÆÉv.1TR8–%ÅI„„IŠ•YĘ,HƒDį,.5Żnd*ÅČĀŌFnŁ7ĘE±h< ĒG%¦Rܘä°Ųc†Šł¶¤Õb%X ųōYóZgŸ½ēu°­­³cv äo½{p¢:šįĒjJļ½E>»K}ļĄõŻĪł Ķ›=÷C﹋.ŽvĀ X”žZ}O}Gż ,1ļ&ø47ų“R4Ś6ĘUo«w5fēŔ šD$Šrr‰†“%£×ķEf»'„ąįūNŃ2t%"='Śē³„öżBai°Ģkō†½(E“ÉLŹ ZĖC°’¬ä¬ä¬äDs¤š)›*y‰ē|mr*?<ž0P"q“™é,R8GŌbbńü⬠‘µ2FW¶|ĄTė£É‡čŗō‘—Z¬ß3äoVUƒśłaxĻÖ}µSgŻ»£³°Äæ¦ńó#s®YčGŃ>žØÆ0xŪ„÷ü± ާĢĖp%E_ńę/„t ńš± ‹ A .ä ŅnU57ŠR2u;:ŲŃĪ s„ˆ¾r_ŖdsēI¹É™īĢ@¹Tje ¹Kó'I5¦:k{RNu~ jJmr7.NY:ß½ĄßŲąčq÷xVåÆ*ÜbńɊĮT&ŃQ‘fg.v ^oV ĪoŅ›kw2लBGiė4ہ×Ic£ĒöéIÅČxeU±±ø§ÉŻ#Kńčp<43:“ŹiĢŽbž™»Č¼0wyMī5ę-¹7™oÉÕŠ™›$ĀĒ™4’ƒ‡Ö#rA0jØfž‹9<šZ×ųÖī{ŌĮ͆å0÷Ź/wĪ«tīį§aå_ļ€Ā|C“ś—ėļz¦cņå“ 6óį „¶²ā»9 ¶Æœ7ĒisŚņ_ŗļ©Æ* ¾ØmæzQ¤;͐k/Ųb;ų‹I¬TR  'e·Ü s`DĢŽ±qZŃ0µ1«§a‹/-Ć®īūāˆżęˆd >±lpŠ(“OXō”™klaĄ‹ODæ<ż’ōÄ{ę}ŽŪG{¶‡hŽ<Ņ3ų­’ź³ų’ĒpcäÉÜdłRė„IRšž³“‰Lµ¹‡ŁŃß%dŻŠ™éSf§Ä£›¤oŠ‹]ئS×gŚMœiĪhÓüSlX:¶P§2Ću¬õahSŗ„šŌ±X-iL[&…Åō„cKUįŹó–Čl[pX Žœņy§Nyåšk_›8uāaoNĮMŻ‹węx£ę{ænœ»ąbC‡kYįĶz[kCI¹cŠĢЙͩ! ¦„%‡=xä8I%£ ŗĢ9!& P"üŠ-Ĭcä.--,Cњ˜ŗaKęqĒ™Zuq½Ć2cę× 1ŸŪ.ĖB"Œs}Čr‡Ā!nU`ō^f+éé-#$zˈT-Å^³X˜D+Ńė“,,¦eꋖy2ZmX˜B-SsŚĶ%Ćā71·īŲŠ9]jŠ2#2/d+ݱ[s¢Ę ńņBńz6]«+Ķ,»`žgāńtŗDēz*„)7°~ŚMÆ/æ¦ß_˜ŸŪ3fŅžNMŁkó×<Ŗ„«žjž¼zj×ŖKēŻ©yŒ%É}ä¶Ž; =’K™‘œdŹÉzژ™qĆÕE¦ĶšŌŁŌŃ9…`ą ĮĄ.‚Y+š@‹’W‚BĘ {‘§ÕėķŠg¦e”„Wڐ¦3ČBR•ė`ŗ"h“’-6•B“-‘æeKžæu2a;œR“l ‰ń}l²·šb‘ĒfnW†;#œ ©².Ÿd®D/—™ :ʠ̤ NžłĘĉ„ qZŃ2³B w2悙æŚĻŒ‹mŽó=q2[CnTŒÉČÄQ“æü<ūB¤‘9:;–ŲjŖhŽ­“ļj?ńįķ;jt}ż {–žōŁ«oœöӦʕu·?†Ź®ż`rCCav‰`‹¾9nŗśšzģČ«GE7e¦±\Ā‹’Ģż_ ¼ąqe²Ń׹C~˜aČwd&†!ĆhG(¹6hŖ ŽqÉ­°Ép1œoXW¬&“-¬Ć^Æ3ĢÉF‹YłXŚŌCś^‚Šļ)#}Æó%1T'„Ź ļ²ÄĢ8@fę»ĢHF|Ķļ„äĶC«žxiųbP„­Åm/¶-K5ćž:ēgķė^¬­k„…ė88EÓüÄĢ»>~łš@^­]3”°xbmķŸn„8Ŗ4ēčųŚßæöāӓķ3Įę‚Ķńql"%«ŅY”6ŹÓą¬J«õ“‹„“lČĢ'3`(„Wń³ķČ}LÖd(qxžV|Lä0ƒ˜†Y·łŒ|šøŠ9”2YcŒ%©1:ŽĆi<‘e椦JÉ“%‰Ęėż“5‰µ&± Ä®”Xz–Đ,I“%i³÷¼ŃšŠ0Cfq1H@1LČ͇/™©Ō`bĀäĢĆŽĒ÷Oķ[xä/SkŖļlŁVßß?yķÄ;ū¶ķn¼õ„‹` 4ļxļ¢ÉY9š“3ƒčŠ ēŸ^|įՉ4.Ņ=x wą ™ųōG”œlģ×į }eśx\ÆÆOoÓ7:ŗõIkõėÓ °Ņķ6¦±ÓģāĻbYTZ­6&õ2yļe@L”TÖ³’x†ŻŖ wz©ĆörnȈ™ūS-ŒŒF6 Ƨ…‘;· z³eó·Nˆć]*‰ƒ1÷Ńϼu–öé=·i'”óÄ¢J{\ŲāŽßŒ--ŁŁ¼āĻ#5퇗Ŗ_ØG ’ŌGß>oÜ}Ó^J]xĖČ¢¢Y/ē–ĀBh'­RæūkžļŻsuĢĀä,B:”Ł ŹB'C–“…7$[¹m5Ol ¶­a¬dęõ ėݲQ6ĢébІ©ĘrZ† -d*Ęi4ƒ¢7•£mŁĄī1 I7Ćś$E(ӆ mĒ@×|ā„“-Ć5)Ć1U\\ńžpEśŁŹ.ŃMqīµĒV·|” QPgœEćīŹ^·NW÷ö÷ö~*‹2ŅČ :nK¾^Ē&ļ<1Ķ$ŸĘĆ1Ļė3ŸĖ\L˜ ;nļ·$§Ģ©ŸņÓ)żż-żó’Ś8ekv~ŽäЁ_ćąåŗioæL%ń£Ä,øŠ‡åĢܧXa5"ä)Cœ@<ų^Ź70‚0Zu`60ĢØ€™$Į1—Ź YÖ)ģčeń„÷˘q‚ÄWœįįcÓĀV/c”ŃmŅŠp#ŸÄ(š‰Ÿyėa¶‰”ąčkW½ł¦®æŸO~īLސ‘ >«¶";I 8Ŗų4|††ć›ĀkµFEŌ7$Į¤^ ŌĄGYŽDąĖ‘č#,‡“?öZ@‡&©'¦°Øg ³cRØ¹Ć†˜Ā‚¾),]—•P\)}ƆœBs3­“é‘¶›ĀÓéN¹!uųäFŠ‹C°|\šAvœ;ĀĘmū~Ņ*]+EvB‰#?ͽŖ@“Ö^XŪāpč?‡PĀhž?bŅķÕ¦åęę.ŸŹ]}'µŸ!Üö(į6-8£Tē¢?ĄwdN†F½ŗ[_ś"­¢”½­‡ō„č$—Jņ>¤Õp ń^„—“ØCÓCÓu™’Ķeō½¢GĒf›c(į0s<Ü9}§‡Æg³Ā±Æš8ސæÅB‘¤Ąx…æF÷C^”KµÄŠ-v…ẏ­’6¢aŲZīõĮ³?śŖ¬ļļGīćŃæĆĻW©?lNˆŠ\fB²KŁ;+—)9B‰āū†øL‰Y¾Œ“ćK¬Ī^abŒpžP7“šwūćZ²”Aj³Ā6|ül@ĒāoJ±i.ķļgŃ@*1Å$¢õüšˆRĻeryÖLk^µ§:ū‰|qĢr»Ņ¤¤ŖÜ ģā”)MR ”»°ØP)l,ģ)ä’qē ©"L¢.dd yPŠÆ¢Į|-HēŪĢĘSÄ.J‹é&F! 0ųŁ`˜ń;MYŚ“ųūkģ™FöL#{¦Ńib“ Ļ1±ēó×cīø)›^mbšÓD%>mŽ”ż¤p–Į/}”Éķdq²Ē8Łcœģ1NgZbR҆¢Āiģā“šŅ³“6dć¤ihi±P@¬ č“Ņ:Ż&Å“ÉęC‘£MēŸÓµ†s—ÄÅ7¼UxVF‹Ķ–Ų[ĆÅ8qĘĶߓźö˜BŽÉv1©_oOjžŚpg‡cÅ)·Q1’č¼wå¬č_|ąQ“±vK®æ aLҘōhmœ“9×ļ§¢G6ÖMėhźhz’Hč^‚$Ģū¾īå’‹ŗ7i˜ī-ˆ'­šō@gų{Š–®Įå24žS¹LŁĘļ?V¹ •ēéŚo )į’®ŹżĻ4®ż_ŠøŒģDįRĻēC¼œP\ ’ˆvVJL%¶ G½”ŚTm«wHʰŒķaN£Kd!č¤×Ń%F2]jЧé@"īńAŒ‹ā/°|;a՜Hų姐3ʘX$ŘāN §,KĮ[µ0Š[•-©‚ƒ½<{‘„ØójB„ŠÖéŪpäČÖßéwäø9łŸä€œ (Fą°U÷”lqjc.W?ūĖqõs˜tü/0łŁ‡oŗågß¼ūēh„ś•ś<¬„f²QŸSæśćoüńõ?žžF”Ō.¼‹P”zķJV1*·{Ę£:{•§Ł²Šr¹“1M“ˆ&ńéŠ ku¶MIį4Cq<š'ękē‚„±D.Kb *įRõō? +éžÕ°ŅŠÕP|).ž„ųŅL’$Ā4ŽļG˜.šXµ·kęuużżõOuæųį³ŪwN½æ¾qeŻ}ØrŪ‡Mšš«š_nR_Uæ|ńȄņčÖLē›Ģėbž QńWpcœEi£=“¹zē„“IAį‘'+ uéU¼l¶Åb$’²¤łW#)g”ÖX”ö?¤°4dI`‘Ėā'ڊ$ż³(Ź÷TĄ÷Ć(ŠgžĻüŖž™’ŃõĀńéÕU{ęµżØ–8R­pßĆ×Ü8ķ~µ 9ėėˆ™bŲõn}]cnNŃĄÓh­/ķŻgŸcb\‚s+ˆlżŠ čMÄ#ö—‘Čõń#/KlE<$Uru€M±õؐNd„ŁpE/‘!TtŹ „ŹCFLĪ „Ņä‘ŲJ‚œIį)k±<ORų{,Ø·Ķza+¢’(@šļɈōeĒ­Šä7”μ·¾ææēē­# ø]yʘ?ćČmõ¼HGÉą§ÜļńZ„Ó•™’Sķ(%5[ĪĻ,–+3«äəsųˆcŗ·90£xæÄŃįé Ģ/¶­ē{Ķ«<ėrWł·ĆmśĶĪ­¹?†·¦j!9§s›2ˆ”˜ČČČ‹(ĢŲEķXNö(øü”yŒryŒfy©!&““Y,)™%į%3•CłÓ3ݐĄ¶Å©YÜ$x“E¦A‹ßCéeńŒ[\ö ‰œļ"ē;%‡įzG| ¢=ŌāE&¶E¶” :Łtn)a‹ē–X„ß?“Īć e‘{ˇE[įyžFØ$g(Ķ!ä”ųkR,Õ!ÉĮż>śĪĘW'hZßīŚxmvö’Ü+B7n(=ź‘Å]/Wkj_™·p‡?NÉž«&N„U·<_į{c|CcsUFF²œlČ¹é’šõE²‘¾ß„ź.ŖńłŗdMzŻ$2×cæ@QžN ö(U:ŽÉūyNkĒźµ>55)ĢÉ ®^2€k]’ŽÄŠjbdbV¶‰M“É©‘Dģ©ēffI,ąē…¼Å!x‹i,4ÄŚ I÷1,&±ÜĒmiēĒ»bų˜Nǽ·`0öŹa,pMżµ Ķ µ{ĻeQ4tŁČŸļéķķ‡W«„dĒ”†]Ę`9ššv'§>}§ŹµĢóēf„Źõb&įyLUlZ!E\/rˆ·Ė¼¹Š×@éĀAéÓ¦'WL˜žĄZCq1śEŒ8­‡G 1y³ŌžqlDJ,ÕJCfwp™\ ..øą.téq Xr™ž¢ŗ¢‡Óķ®t™ćŒ2bzžŒāxąx B“ń—Ć«"ē˃‘he€ ń8%2 Žš—-d‘#7¬,ś`"Ł7ŅlŌ2ā ,ȲQĒB±SåÕ[ÉĘópŁĪ®RėŌÉVŸ€„d{āŠūźć÷>GĶY_®X>Ļ“ęuOż¤wl›Ė‚væ•6EīčW«Y Õ°’J8O½ƒ»ŃäĪč¬ė¼";š9ŹbÖØ/Y“R*cæoS‰/CHVtpMK1ņnžž2Īšä|Ł@÷ Ŗ¤ļwē>å,Ö'‚i£db$жŁ+ėŹŲK&2eDZĖĒk1{õ„ŌŅß²įy$͌~L =Ā•ō§ŽČƒbś‰Ź%ŽīŽ-ź×'æ¢īSˆE‡ßMžžtüé&Mč³’ÉƒˆnŠõĮC;E«PņŠs91ž\@„G r”gӟ"óeåžVæŽņĄżō Ųč“cO‡tģp {śˆ Œ\ĻžE9˜>‰6Œb3m“e»śõ):Bł»É’rÖR€ø&äfē÷ŗLšįH3A2ƛbæST®~½=Ž7šÜź¾ą¶¼²uĆmš~ų*šŠöpĶXƒoę³ųƄļˆ+Å[Ä·Ä·GǶ+É6 ļOh¦iNk/צ›Ī¤{]¹!ŻpČpČøŅt‘é6óHóu«åĒÖ$²M!ŪN²=`}Ąö}ż[ĒĆIÕIÆ$÷„,KyӹЩ¦Ö„]āŹq½–¾ŪŻą~Åó¼·Ī{6cfĘ×¾M¾÷2=’×¶·’n§2Oe³VdŻ”õ«o’Žž½ż{ū÷ö’~Ō&ˆż"+Õ„ō§$d'ÖąFMŸX=³Öf±§ZSė¦55N®ožŠŅŚÖ°Ż<Ņ8«fö¤ÜżeŁ„e#3¦˜’“\U)Ž4}‘VWxÜS>VŁ»/§"otŗ?ōX~å~Uųśƒ'ŁSśœœ28HސYś8żĪQ`:˜ŖĮLPKØgv ¬ģ—›§‚:0 4F@9ā+O- “°˜ĮH`³@ ˜M<“\°ŸŲź4ž" ‚Ä“˜¦H&V¼ Tą Œ»^ŠA<< Œ Ų öPņĄhü DĢ|źe’ZȼŅ_ķčOy4Ļ_ŃÕy ū”m2ø š’2¤óOO‚“ƒēUĄÄephGƁŗs÷‚ĒÉ~#ļŃ}n$緐’QīŽĮIŻ5¼:Č’{ā×L!ūS±zp+Ł×“}9w/l#÷£»p-ųvųĪÆN¶ļ+…|p„7‚#ųpD(!ē8ĀĶ×$v¼ŠŌ’Š\3@žO+ńäZ²ó»Č¾lĮ'ˆY’ŲCŪ?³ł   ŗ“gßNwŽ1„;~,Āą öƒ‹É’%ųyŠMĘ^M˼ DÅąQōĢąsør×Ķīæ„ĖcÉw‘kǐ±5“’•“ŒK@ä’·Ąé®’©;ĮŌ-tēžcš÷`7Ź<īfœžĻ?”Š%¶Ēś}²ŻXł-H1ĶƗWēŃ’ō·Kƒ·Ŗ­Ś%z„Ģų’|žé‰Ņ endstream endobj 85 0 obj <>stream GPL Ghostscript 8.54 PDF Writer \376\377\000L\000i\000n\000u\000x\000 \000L\000C\000P\000 \000T\000o\000o\000l\000s\000 \000U\000s\000e\000r\000 \000M\000a\000n\000u\000a\000l\376\377\000J\000o\000s\000e\000p\000h\000 \000C\000i\000h\000u\000l\000a\000,\000 \000I\000n\000t\000e\000l\000 \000C\000o\000r\000p\000. endstream endobj 2 0 obj <>endobj xref 0 86 0000000000 65535 f 0000053472 00000 n 0000088649 00000 n 0000053298 00000 n 0000050996 00000 n 0000000015 00000 n 0000002042 00000 n 0000055341 00000 n 0000066215 00000 n 0000055743 00000 n 0000072007 00000 n 0000054449 00000 n 0000056612 00000 n 0000053537 00000 n 0000051138 00000 n 0000002062 00000 n 0000007080 00000 n 0000053587 00000 n 0000051282 00000 n 0000007101 00000 n 0000009748 00000 n 0000055676 00000 n 0000053626 00000 n 0000051426 00000 n 0000009769 00000 n 0000012496 00000 n 0000055119 00000 n 0000055196 00000 n 0000053676 00000 n 0000051570 00000 n 0000012517 00000 n 0000015524 00000 n 0000055049 00000 n 0000053728 00000 n 0000051714 00000 n 0000015545 00000 n 0000019027 00000 n 0000053800 00000 n 0000051858 00000 n 0000019048 00000 n 0000021848 00000 n 0000053861 00000 n 0000052002 00000 n 0000021869 00000 n 0000024992 00000 n 0000053911 00000 n 0000052146 00000 n 0000025013 00000 n 0000027645 00000 n 0000053972 00000 n 0000052290 00000 n 0000027666 00000 n 0000030901 00000 n 0000054033 00000 n 0000052434 00000 n 0000030922 00000 n 0000033654 00000 n 0000054094 00000 n 0000052578 00000 n 0000033675 00000 n 0000037629 00000 n 0000054155 00000 n 0000052722 00000 n 0000037650 00000 n 0000040466 00000 n 0000054216 00000 n 0000052866 00000 n 0000040487 00000 n 0000044152 00000 n 0000054266 00000 n 0000053010 00000 n 0000044173 00000 n 0000047808 00000 n 0000054327 00000 n 0000053154 00000 n 0000047829 00000 n 0000050975 00000 n 0000054388 00000 n 0000056815 00000 n 0000066416 00000 n 0000072211 00000 n 0000054795 00000 n 0000055277 00000 n 0000055553 00000 n 0000056196 00000 n 0000086995 00000 n trailer << /Size 86 /Root 1 0 R /Info 2 0 R /ID [<7D2931E5B8A694E02DA571C9AA15FE9A><7D2931E5B8A694E02DA571C9AA15FE9A>] >> startxref 89227 %%EOF tboot-1.8.0/lcptools/Makefile0000644000000000000000000000470612272416301014301 0ustar 00000000000000# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # lcptools makefile # ROOTDIR ?= $(CURDIR)/.. include $(ROOTDIR)/Config.mk TPMNV_TARGETS := \ tpmnv_defindex \ tpmnv_relindex \ tpmnv_lock \ tpmnv_getcap LCP1_TARGETS := \ lcp_writepol \ lcp_readpol \ lcp_crtpconf \ lcp_crtpol LCP2_TARGETS := \ lcp_mlehash \ lcp_crtpol2 \ lcp_crtpollist \ lcp_crtpolelt \ tpmnv : $(TPMNV_TARGETS) lcp1 : $(LCP1_TARGETS) lcp_mlehash lcp2 : $(LCP2_TARGETS) # # universal rules # build : $(TPMNV_TARGETS) $(LCP1_TARGETS) $(LCP2_TARGETS) dist : install install : @set -e; for i in $(TPMNV_TARGETS) $(LCP1_TARGETS) $(LCP2_TARGETS);\ do \ $(MAKE) DISTDIR=$(DISTDIR) INST_TARGET=$(DISTDIR)/usr/sbin/$$i do_install; \ done .PHONY: do_install do_install : $(INST_TARGET) $(INST_TARGET) : $(notdir $(INST_TARGET)) [ -d $(DISTDIR)/usr/sbin ] || $(INSTALL_DIR) $(DISTDIR)/usr/sbin $(INSTALL_PROG) -t $(DISTDIR)/usr/sbin $^ clean : rm -f *~ *.a *.so *.o *.rpm $(DEP_FILES) $(TPMNV_TARGETS) $(LCP1_TARGETS) $(LCP2_TARGETS) trousers_dep mrproper : clean distclean : clean # # trousers # trousers_dep: @printf "#include \n" | $(CC) -x c $(CFLAGS) $(LDFLAGS) $(LIBS) - -Wl,--defsym=main=0 -o $@ >/dev/null 2>&1 || (echo trousers-devel package is not installed && false) # # dependencies # LDFLAGS += -L. # LCP v2 POLELT_PLUGINS := mle_elt.o pconf_elt.o custom_elt.o sbios_elt.o LCP2_LIB := liblcp.a $(LCP2_LIB) : pol.o poldata.o pollist.o polelt.o lcputils2.o hash.o $(AR) rc $@ $^ lcp_crtpolelt : crtpolelt.o $(POLELT_PLUGINS) $(LCP2_LIB) $(CC) $(CFLAGS) $(LDFLAGS) $^ -lcrypto -llcp -o $@ lcp_crtpollist : crtpollist.o $(POLELT_PLUGINS) $(LCP2_LIB) $(CC) $(CFLAGS) $(LDFLAGS) $^ -lcrypto -llcp -o $@ lcp_crtpol2 : crtpol2.o $(POLELT_PLUGINS) $(LCP2_LIB) $(CC) $(CFLAGS) $(LDFLAGS) $^ -lcrypto -llcp -o $@ lcp_mlehash : mlehash.o $(CC) $(CFLAGS) $(LDFLAGS) $^ -lcrypto -lz -o $@ # LCP v1 and tpmnv_* UTIL_OBJS := lcptools.o lcputils.o LIBS += -lcrypto -ltspi -lz $(TPMNV_TARGETS) : tpmnv_% : %.o $(UTIL_OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ $(LCP1_TARGETS) : lcp_% : %.o $(UTIL_OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ # # implicit rules # HDRS := $(wildcard $(ROOTDIR)/include/*.h) $(wildcard $(CURDIR)/*.h) BUILD_DEPS := $(ROOTDIR)/Config.mk $(CURDIR)/Makefile %.o : %.c $(HDRS) $(BUILD_DEPS) trousers_dep $(CC) $(CFLAGS) -DNO_TBOOT_LOGLVL -c $< -o $@ tboot-1.8.0/lcptools/crtpconf.c0000644000000000000000000001344512272416301014623 0ustar 00000000000000/* * Copyright 2001 - 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 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. */ /* * crtpconf.c * * Command: lcp_crtpconf. * * This command can create PConf data for use when creating LCP policy data. * */ #include #include #include #include #include #include #define PRINT printf #include "../include/uuid.h" #include "../include/lcp.h" #include "lcptools.h" #include "lcputils.h" #define MAX_INDEX 24 static uint8_t locality = 0x1f; static char *file = NULL; static unsigned char *pcr_val = NULL; static int help_input = 0; static const char *short_option = "hp:f:"; static const char *usage_string = "lcp_crtpconf "\ "-p PCR_index1,PCR_index2,...,PCR_indexn "\ "[-f filename] [-h]\n"; static const char * option_strings[] ={ "-p PCR_Index1,PCR_Index2,...: uint8. \n", "-f file name of SRTMMeasurement: string. Content is appended.\n", "-h help. Will print out this help message.\n", 0 }; /* function: parse_cmdline * description: parse the input of commandline */ static int parse_cmdline(int argc, const char * argv[]) { int c; while (((c = getopt(argc, (char ** const)argv, short_option)) != -1)) switch (c){ case 'p': pcr_val = (unsigned char *)optarg; break; case 'f': file = optarg; break; case 'h': help_input = 1; break; default: return LCP_E_NO_SUCH_PARAMETER; } if ( optind < argc ) return LCP_E_INVALID_PARAMETER; return LCP_SUCCESS; } int main(int argc, char *argv[]) { uint16_t i = 0; uint32_t index[MAX_INDEX] = {0}; uint32_t idx_num = 0; FILE *p_file = NULL; unsigned char* srtm_data = NULL; uint32_t data_len = 0; TPM_LOCALITY_SELECTION local_sel; lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; /* * No parameter input will print out the help message. */ if ( argc == 1 ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } /* * Parse the parameters input to decide * what parameters will be passed to TSS API. */ ret_value = parse_cmdline(argc, (const char **)argv); if ( ret_value ) goto _error_end; /* * If user input -h(help), just print guide to * users and ignore other parameters. */ if ( help_input ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } /* * Parse command line string to get the PCR numbers. */ if ( pcr_val == NULL ) { log_error("Must input PCR numbers to creat PConf data.\n"); ret_value = LCP_E_INVALID_PARAMETER; goto _error_end; } idx_num = MAX_INDEX; str_split((char *)pcr_val, index, &idx_num); for ( i = 0; i < idx_num; i++ ) { if ( index[i] > 23 ) { ret_value = LCP_E_INVALID_PARAMETER; goto _error_end; } } local_sel = (TPM_LOCALITY_SELECTION)locality; ret_value = lcp_create_pconf(idx_num, index, 0, NULL, local_sel, &data_len, &srtm_data); if ( ret_value == LCP_SUCCESS ) { if ( file != NULL ) { /* * Write Platform configure data to file. */ p_file = fopen(file, "a"); if ( !p_file ) { log_error("Open file %s error!\n", file); ret_value = LCP_E_COMD_INTERNAL_ERR; goto _error_end; } log_debug("Data length is %d.\n", data_len); if ( data_len != fwrite(srtm_data, 1, data_len, p_file) ) { log_error("Write SRTM data into file error!"\ "Data length is %d.\n",data_len); fclose(p_file); ret_value = LCP_E_COMD_INTERNAL_ERR; goto _error_end; } fclose(p_file); } else print_hexmsg("the PConf data is:\n", data_len, srtm_data); free(srtm_data); } else goto _error_end; return LCP_SUCCESS; _error_end: /* * Error when execute. */ if ( srtm_data ) free(srtm_data); log_error("\nCommand CrtPConf failed:\n"); print_error(ret_value); return ret_value; } tboot-1.8.0/lcptools/crtpol.c0000644000000000000000000004120112272416301014277 0ustar 00000000000000/* * Copyright 2001 - 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 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. */ /* * crtpol.c * * Command: lcp_crtpol * * This command can create the LCP policy. * */ #include #include #include #include #include #include #include #include #define PRINT printf #include "../include/uuid.h" #include "../include/lcp.h" #include "lcptools.h" #include "lcputils.h" #define MAX_LISTNUM 2 #define BUFFER_SIZE 1024 static uint8_t pol_type = 0xff; static uint32_t alg = LCP_POLHALG_SHA1; static uint8_t ver = 0; static uint32_t pcf_val = 0; static uint8_t sinit_revoc = 0; static char *pol_file = NULL; static char *mle_file = NULL; static char *pol_data_file = NULL; static char *srtm_file = NULL; static int help_input = 0; static const char * short_option = "ht:a:v:s:m:o:b:"; static struct option longopts[]= { {"sr", 1, 0, 'n'}, {"pcf", 1, 0, 'p'}, {0, 0, 0, 0}, }; static const char *usage_string = "lcp_crtpol -t policy_type [-a hashalg] " "[-v version] [-sr SINIT revocation_counter] [-s srtm_file] " "[-m mle_file] [-o policyfile] [-b policydata_file] [-h]\n"; static const char *option_strings[] = { "-t Policy type: uint8/string.\n" "\tPolicy type is:\n" "\tLCP_POLTYPE_HASHONLY: 0 or \"hashonly\" \n" "\tLCP_POLTYPE_UNSIGNED: 1 or \"unsigned\" \n" "\tLCP_POLTYPE_SIGNED: 2 or \"signed\" \n" "\tLCP_POLTYPE_ANY: 3 or \"any\" \n" "\tLCP_POLTYPE_FORCEOWNERPOLICY: 4 or \"forceowner\" \n", "-a algorithm: uint8/string. algorithm used in the policy.\n" "\tAlgorithm choice:\n" "\t\tLCP_POLHALG_SHA1: 0 or \"sha1\" \n" "\tCurrently we only support SHA-1 algorithm.\n", "-v version: uint8. version number.\n" "\tCurrently 0 or 1 is allowed.\n", "-s PConf file name: String. File name of PConf data.\n", "-m MLE hash file name: String. File containing the MLE hashes.\n", "-o LCPPOLICY file name: String. File to save the output Policy.\n", "-b LCPPOLICYDATA file name: String. File to save Policy data.\n", "-sr SINIT Revocation count number: uint8.\n", "-pcf Policy Control Field: uint32.\n", "-h help. Will print out this help message.\n", NULL }; static param_option_t poltype_option_table[] = { {"hashonly", LCP_POLTYPE_HASHONLY}, {"unsigned", LCP_POLTYPE_UNSIGNED}, {"signed", LCP_POLTYPE_SIGNED}, {"any", LCP_POLTYPE_ANY}, {"forceowner", LCP_POLTYPE_FORCEOWNERPOLICY}, {NULL, -1} }; /* * function: parse_cmdline * description: parse the input of commandline */ static int parse_cmdline(int argc, const char * argv[]) { int c; unsigned int temp = 0; while ((c = getopt_long_only(argc, (char ** const)argv, short_option, longopts, NULL)) != -1) switch (c) { case 't': /* check whether user inputs the string for policy type*/ temp = parse_input_option(poltype_option_table, optarg); /* * if not, then the users should input the 0~4 number, */ if ( temp == (unsigned int)-1 ) if ( strtonum(optarg, &temp) ) return LCP_E_INVALID_PARAMETER; if ( temp > 4 ) { log_error("policy type out of range.\n"); return LCP_E_INVALID_PARAMETER; } pol_type = temp; break; case 'a': if ( strcasecmp(optarg, "sha1") == 0 ) alg = LCP_POLHALG_SHA1; else if ( strtonum(optarg, &alg) ) return LCP_E_INVALID_PARAMETER; if ( alg != LCP_POLHALG_SHA1 ) { log_error("Policy algorithm not supported!\n"); return LCP_E_INVALID_PARAMETER; } break; case 'v': if ( strtonum(optarg, &temp) ) return LCP_E_INVALID_PARAMETER; /* * Currently we only support version 0 or 1. */ if ( temp > 1 ) { log_error("version %d is not supported!\n", ver); return LCP_E_INVALID_PARAMETER; } ver = temp; break; case 's': srtm_file = optarg; break; case 'm': mle_file = optarg; break; case 'o': pol_file = optarg; break; case 'b': pol_data_file = optarg; break; case 'n': if ( strtonum(optarg, &temp) ) return LCP_E_INVALID_PARAMETER; if ( temp > 0xff ) return LCP_E_INVALID_PARAMETER; sinit_revoc = temp; break; case 'p': if ( strtonum(optarg, &pcf_val) ) return LCP_E_INVALID_PARAMETER; break; case 'h': help_input = 1; break; default: return LCP_E_NO_SUCH_PARAMETER; } if ( optind < argc ) return LCP_E_INVALID_PARAMETER; return LCP_SUCCESS; } /* read data from file */ static int read_data(const char *filename, unsigned int *size, unsigned char *data) { FILE *pfile = NULL; unsigned int len; if ( filename == NULL || data == NULL ) return -1; pfile = fopen(filename, "rb"); if ( pfile == NULL ) { //log_error("Can't open MLE/PConf file\n"); return -1; } fseek(pfile, 0, SEEK_END); len = ftell(pfile); fseek(pfile, 0, SEEK_SET); if ( len > BUFFER_SIZE ) { log_error("the file %s is too long. File size is %d.\n", filename, len); fclose(pfile); return -1; } if ( len != fread(data, 1, len, pfile) ) { fclose(pfile); log_error("Read data from file error!\n"); return -1; } *size = len; fclose(pfile); return 0; } /* save data to file */ static int save_data(unsigned char *data, unsigned int len, const char *file) { FILE *pfile = NULL; if ( data == NULL || file == NULL ) return -1; pfile = fopen(file, "wb"); if ( pfile == NULL ) { log_error("Open file %s error!\n", file); return -1; } if ( len != fwrite(data, 1, len, pfile) ) { fclose(pfile); log_error("Write data into file error!\n"); return -1; } fclose(pfile); return 0; } static int convert_hashes(unsigned int mle_len_ascii, unsigned char *mle_data_ascii, unsigned int *mle_len, unsigned char *mle_data) { unsigned long data; unsigned char *curr, *next; char tmp[3]; curr = mle_data_ascii; *mle_len = 0; while ( curr < (mle_data_ascii + mle_len_ascii) ) { errno = 0; data = 0; data = strtoul((char *)curr, (char **)&next, 16); /* overflow, which means there were no spaces in input */ if ( errno == ERANGE || (data & ~0xff) != 0 ) { /* copy 2 chars into separate buffer and convert them */ tmp[0] = *curr; tmp[1] = *(curr+1); tmp[2] = '\0'; data = strtoul(tmp, NULL, 16); next = curr + 2; } else if ( errno != 0 ) /* some other error */ break; if ( next == curr ) /* done */ break; mle_data[(*mle_len)++] = (unsigned char)data; curr = next; } if ( curr < (mle_data_ascii + mle_len_ascii - 1) ) return -1; else return 0; } /* create policy and policy data */ static lcp_result_t create_policy(lcp_policy_t *lcppolicy, unsigned char *mledata, unsigned int mlelen, unsigned char *pconfdata, unsigned int pconflen, unsigned char *policy, unsigned int *policylen, unsigned char *poldata, unsigned int *poldatalen) { pdlist_src_t listdata[MAX_LISTNUM]; unsigned int listnum = 0; uint32_t poldataver = 0; lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; switch (pol_type) { case LCP_POLTYPE_HASHONLY: if ( (mledata == NULL) || (mlelen == 0) ) { log_error("Please use MLE file to input the HASH value!\n"); return LCP_E_INVALID_PARAMETER; } if ( (ret_value = lcp_create_policy(lcppolicy, mlelen, mledata, policylen, policy)) != LCP_SUCCESS ) { log_error("create policy error\n"); return ret_value; } break; case LCP_POLTYPE_UNSIGNED: if ( ((mledata == NULL) || (mlelen == 0)) && ((pconfdata == NULL) || (pconflen == 0)) ) { log_error("Haven't input MLE file or PConf file.\n"); return LCP_E_INVALID_PARAMETER; } if ( mlelen != 0 ) { //print_hexmsg("the mle data is:\n", mlelen, mledata); listdata[listnum].algorithm = alg; listdata[listnum].type = LCP_POLDESC_MLE_UNSIGNED; listdata[listnum].list_version = 0;/*default value*/ listdata[listnum].listdata_length = mlelen; listdata[listnum].listdata= mledata; listnum++; } if ( pconflen != 0 ) { //print_hexmsg("the pconf data is:\n", pconflen, pconfdata); listdata[listnum].algorithm = alg; listdata[listnum].type= LCP_POLDESC_PCONF_UNSIGNED; listdata[listnum].list_version = 0;/*default value*/ listdata[listnum].listdata_length= pconflen; listdata[listnum].listdata = pconfdata; listnum++; } if ( (ret_value = lcp_create_unsigned_poldata(poldataver, listnum, listdata, poldatalen, poldata)) != LCP_SUCCESS ) { log_error("create policy data error\n"); return ret_value; } if ( (ret_value = lcp_create_policy(lcppolicy, *poldatalen, poldata, policylen, policy)) != LCP_SUCCESS ) { log_error("create policy error\n"); return ret_value; } break; case LCP_POLTYPE_ANY: if ( (ret_value = lcp_create_policy(lcppolicy, 0, NULL, policylen, policy)) != LCP_SUCCESS ) { log_error("create policy error\n"); return ret_value; } break; case LCP_POLTYPE_FORCEOWNERPOLICY: if ( (ret_value = lcp_create_policy(lcppolicy, 0, NULL, policylen, policy)) != LCP_SUCCESS ) { log_error("create policy error\n"); return ret_value; } break; case LCP_POLTYPE_SIGNED: default: log_error("Unsupported Policy type!\n"); return LCP_E_INVALID_PARAMETER; } return LCP_SUCCESS; } static unsigned char policy_data[BUFFER_SIZE]; static unsigned char policy[BUFFER_SIZE]; static unsigned char mle_data_ascii[BUFFER_SIZE]; static unsigned char mle_data[BUFFER_SIZE]; static unsigned char srtm_data[BUFFER_SIZE]; int main (int argc, char *argv[]) { unsigned int pol_len = BUFFER_SIZE; unsigned int pol_data_len = BUFFER_SIZE; unsigned int srtm_len = 0; unsigned int mle_len = 0, mle_len_ascii = 0; lcp_policy_t lcppolicy; lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; /* * No parameter input will print out the help message. */ if ( argc == 1 ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } /* * Parse the parameters input to decide * what parameters will be passed to TSS API. */ ret_value = parse_cmdline(argc, (const char **)argv); if ( ret_value ) goto _error_end; /* * If user input -h(help), just print guide to * users and ignore other parameters. */ if ( help_input ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } if ( pol_type == 0xff ) { log_error("No Policy type value has been input. "\ "Must input Policy type value to create Policy Object! \n"); ret_value = LCP_E_INVALID_PARAMETER; goto _error_end; } lcppolicy.version = ver; lcppolicy.hash_alg = alg; lcppolicy.policy_type = pol_type; lcppolicy.sinit_revocation_counter = sinit_revoc; lcppolicy.reserved[0] = 0; lcppolicy.reserved[1] = 0; lcppolicy.reserved[2] = 0; lcppolicy.policy_control = pcf_val; if ( mle_file ) { /* read ASCII hash data */ if ( read_data(mle_file, &mle_len_ascii, mle_data_ascii) < 0 ) { log_error("Can't open mle file.\n"); ret_value = LCP_E_COMD_INTERNAL_ERR; goto _error_end; } /* ensure that convert_hashes() won't overrun the buffer */ mle_data_ascii[BUFFER_SIZE - 1] = '\0'; /* convert ASCII hashes to binary */ if ( convert_hashes(mle_len_ascii, mle_data_ascii, &mle_len, mle_data) < 0 ) { log_error("Can't convert ASCII MLE hashes to binary.\n"); ret_value = LCP_E_COMD_INTERNAL_ERR; goto _error_end; } } if ( srtm_file ) { if ( read_data(srtm_file, &srtm_len, srtm_data) < 0 ) { log_error("Can't open PConf file.\n"); ret_value = LCP_E_COMD_INTERNAL_ERR; goto _error_end; } } /* * Create policy data and policy. */ if ( (ret_value = create_policy(&lcppolicy, mle_data, mle_len, srtm_data, srtm_len, policy, &pol_len, policy_data, &pol_data_len)) != LCP_SUCCESS ) { log_error("Create policy data and policy error!\n"); goto _error_end; } /* * Write policy into file. */ if ( pol_file != NULL ) { if ( save_data(policy, pol_len, pol_file) < 0 ) { log_error("Write policy into file error!\n"); ret_value = LCP_E_COMD_INTERNAL_ERR; goto _error_end; } } else print_hexmsg("the policy is:\n", pol_len, policy); if ( pol_type == LCP_POLTYPE_UNSIGNED ) { /* * Write policy data into file. */ if ( pol_data_file != NULL ) { if ( save_data(policy_data, pol_data_len, pol_data_file) < 0 ) { log_error("Write policy data into file error!\n"); ret_value = LCP_E_COMD_INTERNAL_ERR; goto _error_end; } } else print_hexmsg("the policy data is:\n", pol_data_len, policy_data); printf("Successfully create the policy and the policy data\n"); } else printf("Successfully create the policy\n"); return LCP_SUCCESS; _error_end: /* * Error when execution. */ log_error("\nCommand CrtPol failed:\n"); print_error(ret_value); return ret_value; } tboot-1.8.0/lcptools/crtpol2.c0000644000000000000000000003127112272416301014367 0ustar 00000000000000/* * crtpol2.c: Intel(R) TXT policy (LCP_POLICY) creation tool * * Copyright (c) 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. * */ #include #include #include #include #include #define _GNU_SOURCE #include #include #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "polelt_plugin.h" #include "pol.h" #include "poldata.h" #include "pollist.h" #include "lcputils2.h" static const char help[] = "Usage: lcp_crtpol2 [OPTION]\n" "Create an Intel(R) TXT policy (and policy data file)\n\n" "--create\n" " [--ver ] version\n" " --type type\n" " [--minver ] SINITMinVersion\n" " [--rev [,ctrN] revocation values (comma separated,\n" " no spaces\n" " [--ctrl policy file\n" " [--data policy data file\n" " [FILE]... policy list files\n" "--show\n" " [--brief] brief format output\n" " [policy file] policy file\n" " [policy data file] policy data file\n" "--help\n" "--verbose enable verbose output; can be\n" " specified with any command\n\n"; bool verbose = false; static struct option long_opts[] = { /* commands */ {"help", no_argument, NULL, 'H'}, {"create", no_argument, NULL, 'C'}, {"show", no_argument, NULL, 'S'}, /* options */ {"ver", required_argument, NULL, 'v'}, {"type", required_argument, NULL, 't'}, {"minver", required_argument, NULL, 'm'}, {"rev", required_argument, NULL, 'r'}, {"ctrl", required_argument, NULL, 'c'}, {"pol", required_argument, NULL, 'p'}, {"data", required_argument, NULL, 'd'}, {"brief", no_argument, NULL, 'b'}, {"verbose", no_argument, (int *)&verbose, true}, {0, 0, 0, 0} }; uint16_t version = LCP_DEFAULT_POLICY_VERSION; char policy_file[MAX_PATH] = ""; char poldata_file[MAX_PATH] = ""; char type[32] = ""; uint8_t sinit_min_ver = 0; unsigned int nr_rev_ctrs = 0; uint16_t rev_ctrs[LCP_MAX_LISTS] = { 0 }; uint32_t policy_ctrl = LCP_DEFAULT_POLICY_CONTROL; bool brief = false; unsigned int nr_files = 0; char files[LCP_MAX_LISTS][MAX_PATH]; static int create(void) { lcp_policy_data_t *poldata = NULL; lcp_policy_t *pol = malloc(sizeof(*pol)); if ( pol == NULL ) { ERROR("Error: failed to allocate policy\n"); return 1; } memset(pol, 0, sizeof(*pol)); pol->version = version; pol->hash_alg = LCP_POLHALG_SHA1; pol->sinit_min_version = sinit_min_ver; for ( unsigned int i = 0; i < nr_rev_ctrs; i++ ) pol->data_revocation_counters[i] = rev_ctrs[i]; pol->policy_control = policy_ctrl; if ( strcmp(type, "any") == 0 ) pol->policy_type = LCP_POLTYPE_ANY; else if ( strcmp(type, "list") == 0 ) { pol->policy_type = LCP_POLTYPE_LIST; poldata = malloc(sizeof(*poldata)); if ( poldata == NULL ) { ERROR("Error: failed to allocate memory\n"); free(pol); return 1; } memset(poldata, 0, sizeof(*poldata)); strlcpy(poldata->file_signature, LCP_POLICY_DATA_FILE_SIGNATURE, sizeof(poldata->file_signature)); poldata->num_lists = 0; for ( unsigned int i = 0; i < nr_files; i++ ) { bool no_sigblock_ok = false; lcp_policy_list_t *pollist = read_policy_list_file(files[i], false, &no_sigblock_ok); if ( pollist == NULL ) { free(pol); free(poldata); return 1; } poldata = add_policy_list(poldata, pollist); if ( poldata == NULL ) { free(pol); free(pollist); return 1; } free(pollist); } calc_policy_data_hash(poldata, &pol->policy_hash, pol->hash_alg); } bool ok; ok = write_file(policy_file, pol, get_policy_size(pol)); if ( ok && pol->policy_type == LCP_POLTYPE_LIST ) ok = write_file(poldata_file, poldata, get_policy_data_size(poldata)); free(pol); free(poldata); return ok ? 0 : 1; } static int show(void) { size_t len, pol_len = 0, poldata_len = 0; void *data; const char *pol_file = "", *poldata_file = ""; lcp_policy_t *pol = NULL; lcp_policy_data_t *poldata = NULL; int err = 1; data = read_file(files[0], &len, false); if ( data == NULL ) return 1; /* we allow files in any order or either one only, so assume that if first file doesn't verify as a policy then it must be policy data */ if ( !verify_policy(data, len, true) ) { poldata = (lcp_policy_data_t *)data; poldata_len = len; poldata_file = files[0]; } else { pol = data; pol_len = len; pol_file = files[0]; } if ( nr_files == 2 ) { data = read_file(files[1], &len, false); if ( data == NULL ) goto done; if ( pol == NULL ) { pol = data; pol_len = len; pol_file = files[1]; } else { poldata = data; poldata_len = len; poldata_file = files[1]; } } if ( pol != NULL ) { DISPLAY("policy file: %s\n", pol_file); if ( verify_policy(pol, pol_len, false) ) { display_policy(" ", pol, brief); err = 0; } } if ( poldata != NULL ) { DISPLAY("\npolicy data file: %s\n", poldata_file); if ( verify_policy_data(poldata, poldata_len) ) { display_policy_data(" ", poldata, brief); /* no use verifying hash if policy didn't validate or doesn't exist or isn't list type */ if ( err == 0 && pol->policy_type == LCP_POLTYPE_LIST ) { lcp_hash_t hash; calc_policy_data_hash(poldata, &hash, pol->hash_alg); if ( memcmp(&hash, &pol->policy_hash, get_lcp_hash_size(pol->hash_alg)) == 0 ) DISPLAY("\npolicy data hash matches policy hash\n"); else { ERROR("\nError: policy data hash does not match policy hash\n"); err = 1; } } else err = 1; } else err = 1; } done: free(pol); free(poldata); return err; } int main (int argc, char *argv[]) { int cmd = 0; bool prev_cmd = false; int c; do { c = getopt_long_only(argc, argv, "", long_opts, NULL); switch (c) { /* commands */ case 'H': /* help */ case 'C': /* create */ case 'S': /* show */ if ( prev_cmd ) { ERROR("Error: only one command can be specified\n"); return 1; } prev_cmd = true; cmd = c; LOG("cmdline opt: command: %c\n", cmd); break; case 'v': /* version */ version = strtoul(optarg, NULL, 0); LOG("cmdline opt: ver: 0x%x (%u)\n", version, version); break; case 'p': /* policy file */ strlcpy(policy_file, optarg, sizeof(policy_file)); LOG("cmdline opt: pol: %s\n", policy_file); break; case 'd': /* policy data file */ strlcpy(poldata_file, optarg, sizeof(poldata_file)); LOG("cmdline opt: data: %s\n", poldata_file); break; case 't': /* type */ strlcpy(type, optarg, sizeof(type)); LOG("cmdline opt: type: %s\n", type); break; case 'r': /* revocation counters */ nr_rev_ctrs = ARRAY_SIZE(rev_ctrs); parse_comma_sep_ints(optarg, rev_ctrs, &nr_rev_ctrs); LOG("cmdline opt: rev: "); for ( unsigned int i = 0; i < nr_rev_ctrs; i++ ) LOG("%u, ", rev_ctrs[i]); LOG("\n"); break; case 'm': /* SINITMinVersion */ sinit_min_ver = strtoul(optarg, NULL, 0); LOG("cmdline opt: minver: 0x%x (%u)\n", sinit_min_ver, sinit_min_ver); break; case 'c': /* PolicyControl */ policy_ctrl = strtoul(optarg, NULL, 0); LOG("cmdline opt: ctrl: 0x%x\n", policy_ctrl); break; case 'b': /* brief */ brief = true; LOG("cmdline opt: brief: %u\n", brief); break; case 0: case -1: break; default: ERROR("Error: unrecognized option\n"); return 1; } } while ( c != -1 ); /* process any remaining argv[] items */ while ( optind < argc && nr_files < ARRAY_SIZE(files) ) { LOG("cmdline opt: file: %s\n", argv[optind]); strlcpy(files[nr_files++], argv[optind], sizeof(files[0])); optind++; } if ( cmd == 0 ) { ERROR("Error: no command option was specified\n"); return 1; } else if ( cmd == 'H' ) { /* --help */ DISPLAY("%s", help); return 0; } else if ( cmd == 'C' ) { /* --create */ if ( *type == '\0' ) { ERROR("Error: no type specified\n"); return 1; } if ( strcmp(type, "list") != 0 && strcmp(type, "any") != 0 ) { ERROR("Error: unknown type\n"); return 1; } if ( *policy_file == '\0' ) { ERROR("Error: no policy file specified\n"); return 1; } if ( strcmp(type, "list") == 0 && *poldata_file == '\0' ) { ERROR("Error: list type but no policy data file specified\n"); return 1; } if ( strcmp(type, "list") == 0 && nr_files == 0 ) { ERROR("Error: list type but no policy lists specified\n"); return 1; } return create(); } else if ( cmd == 'S' ) { /* --show */ if ( nr_files == 0 ) { ERROR("Error: no policy or policy data file specified\n"); return 1; } if ( nr_files > 2 ) { ERROR("Error: too many files specified\n"); return 1; } return show(); } ERROR("Error: unknown command\n"); return 1; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/crtpolelt.c0000644000000000000000000002110712272416301015007 0ustar 00000000000000/* * crtpolelt.c: Intel(R) TXT policy element (LCP_POLICY_ELEMENT) creation tool * * Copyright (c) 2009 - 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 #define _GNU_SOURCE #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "polelt_plugin.h" #include "polelt.h" #include "lcputils2.h" #define MAX_HELP_TEXT 4096 static char help[MAX_HELP_TEXT] = "Usage: lcp_crtpolelt [OPTION]\n" "Create an Intel(R) TXT policy element of specified type.\n\n" "--create\n" " --type type of element; must be first option;\n" " see below for type strings and their\n" " options\n" " --out output file name\n" " [--ctrl ] PolEltControl field (hex or decimal)\n" "--show\n" " policy element file name\n" "--help help\n" "--verbose enable verbose output; can be\n" " specified with any command\n" "types :\n"; bool verbose = false; #define MAX_CMDLINE_OPTS 256 static struct option long_opts[MAX_CMDLINE_OPTS] = { /* commands */ {"help", no_argument, NULL, 'H'}, {"create", no_argument, NULL, 'C'}, {"show", no_argument, NULL, 'S'}, /* options */ {"type", required_argument, NULL, 't'}, {"out", required_argument, NULL, 'o'}, {"ctrl", required_argument, NULL, 'c'}, {"verbose", no_argument, (int *)&verbose, true}, {0, 0, 0, 0} }; static void add_plugins(void) { /* we will add each plugin's opts to end, so find initial last one */ unsigned int nr_opts = 0; struct option *opt = long_opts; while ( opt->name != NULL ) { opt++; nr_opts++; } for ( unsigned int i = 0; i < nr_polelt_plugins; i++ ) { polelt_plugin_t *plugin = polelt_plugins[i]; LOG("supporting LCP element plugin type \'%s\'\n", plugin->type_string); /* copy options */ struct option *plugin_opt = plugin->cmdline_opts; while ( plugin_opt != NULL && plugin_opt->name != NULL && nr_opts < ARRAY_SIZE(long_opts) ) { *opt++ = *plugin_opt++; nr_opts++; } if ( nr_opts == ARRAY_SIZE(long_opts) ) ERROR("Error: too many plugin options\n"); /* copy help text */ strncat(help, plugin->help_txt, MAX_HELP_TEXT - strlen(help) - 1); } } int main (int argc, char *argv[]) { int cmd = 0; polelt_plugin_t *curr_plugin = NULL; bool prev_cmd = false; uint32_t pol_elt_ctrl = DEFAULT_POL_ELT_CONTROL; char out_file[MAX_PATH] = ""; int c; /* add each plugin's command line option strings and help text */ add_plugins(); do { c = getopt_long_only(argc, argv, "", long_opts, NULL); switch (c) { case 'H': /* help */ case 'C': /* create */ case 'S': /* show */ if ( prev_cmd ) { ERROR("Error: only one command can be specified\n"); return 1; } prev_cmd = true; cmd = c; LOG("cmdline opt: command: %c\n", cmd); break; case 't': /* type */ curr_plugin = find_polelt_plugin_by_type_string(optarg); if ( curr_plugin == NULL ) { ERROR("Error: unknown type \'%s\'\n", optarg); return 1; } LOG("cmdline opt: type: \'%s\'\n", curr_plugin->type_string); break; case 'o': /* out */ strlcpy(out_file, optarg, sizeof(out_file)); LOG("cmdline opt: out: %s\n", out_file); break; case 'c': /* ctrl */ pol_elt_ctrl = strtoul(optarg, NULL, 0); LOG("cmdline opt: ctrl: 0x%x\n", pol_elt_ctrl); break; case 0: case -1: break; case '?': /* unknown option */ return 1; default: /* assume this is handled by the plugin */ if ( curr_plugin == NULL ) { ERROR("Error: type must be the first option\n"); return 1; } if ( !(curr_plugin->cmdline_handler)(c, optarg) ) return 1; break; } } while ( c != -1 ); if ( cmd == 0 ) { ERROR("Error: no command was specified\n"); return 1; } else if ( cmd == 'H' ) { /* --help */ DISPLAY("%s", help); return 0; } else if ( cmd == 'S' ) { /* --show */ if ( optind == argc ) { ERROR("Error: no files specified\n"); return 1; } /* process any remaining argv[] items as element files */ while ( optind < argc ) { LOG("cmdline opt: file: %s\n", argv[optind]); DISPLAY("policy element file: %s\n", argv[optind]); size_t len; lcp_policy_element_t *elt = (lcp_policy_element_t *) read_file(argv[optind++], &len, false); if ( elt == NULL ) return 1; if ( !verify_policy_element(elt, len) ) return 1; display_policy_element(" ", elt, false); } return 0; } else if ( cmd == 'C' ) { /* --create */ if ( curr_plugin == NULL ) { ERROR("Error: no type was specified\n"); return 1; } if ( *out_file == '\0' ) { ERROR("Error: no ouput file specified\n"); return 1; } /* process any remaining argv[] items in plugin */ while ( optind < argc ) { LOG("cmdline opt: file: %s\n", argv[optind]); if ( !(curr_plugin->cmdline_handler)(0, argv[optind]) ) return 1; optind++; } /* * write element to out_file */ lcp_policy_element_t *elt = (curr_plugin->create_elt)(); if ( elt == NULL ) { ERROR("Error: failed to allocate element\n"); return 1; } /* size is filled in by create() */ elt->type = curr_plugin->type; elt->policy_elt_control = pol_elt_ctrl; if ( !write_file(out_file, elt, elt->size) ) { ERROR("Error: error writing element\n"); free(elt); return 1; } free(elt); return 0; } ERROR("Error: unknown command option\n"); return 1; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/crtpollist.c0000644000000000000000000004317112272416301015203 0ustar 00000000000000/* * crtpollist.c: Intel(R) TXT policy list (LCP_POLICY_LIST) creation tool * * Copyright (c) 2009-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 #define _GNU_SOURCE #include #include #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "../include/lcp_hlp.h" #include "polelt_plugin.h" #include "pollist.h" #include "polelt.h" #include "lcputils2.h" static const char help[] = "Usage: lcp_crtpollist [OPTION]\n" "Create an Intel(R) TXT policy list.\n\n" "--create\n" " [--ver ] version\n" " --out policy list file\n" " [FILE]... policy element files\n" "--sign\n" " --pub PEM file of public key\n" " [--priv ] PEM file of private key\n" " [--rev ] revocation counter value\n" " [--nosig] don't add SigBlock\n" " --out policy list file\n" "--addsig\n" " --sig file containing signature (big-endian)\n" " --out policy list file\n" "--show\n" " policy list file\n" "--help\n" "--verbose enable verbose output; can be\n" " specified with any command\n\n" "The public and private keys can be created as follows:\n" " openssl genrsa -out privkey.pem 2048\n" " openssl rsa -pubout -in privkey.pem -out pubkey.pem\n"; bool verbose = false; static struct option long_opts[] = { /* commands */ {"help", no_argument, NULL, 'H'}, {"create", no_argument, NULL, 'C'}, {"sign", no_argument, NULL, 'S'}, {"addsig", no_argument, NULL, 'A'}, {"show", no_argument, NULL, 'W'}, /* options */ {"ver", required_argument, NULL, 'v'}, {"out", required_argument, NULL, 'o'}, {"pub", required_argument, NULL, 'u'}, {"priv", required_argument, NULL, 'i'}, {"rev", required_argument, NULL, 'r'}, {"nosig", no_argument, NULL, 'n'}, {"sig", required_argument, NULL, 's'}, {"verbose", no_argument, (int *)&verbose, true}, {0, 0, 0, 0} }; #define MAX_FILES 32 static uint16_t version = LCP_DEFAULT_POLICY_LIST_VERSION; static char pollist_file[MAX_PATH] = ""; static char pubkey_file[MAX_PATH] = ""; static char privkey_file[MAX_PATH] = ""; static char sig_file[MAX_PATH] = ""; static uint16_t rev_ctr = 0; static bool no_sigblock = false; static unsigned int nr_files = 0; static char files[MAX_FILES][MAX_PATH]; static lcp_signature_t *read_pubkey_file(const char *file) { FILE *fp = fopen(file, "r"); if ( fp == NULL ) { ERROR("Error: failed to open .pem file %s: %s\n", file, strerror(errno)); return NULL; } RSA *pubkey = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL); if ( pubkey == NULL ) { ERR_load_crypto_strings(); ERROR("Error: failed to read .pem file %s: %s\n", file, ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); return NULL; } unsigned int keysize = RSA_size(pubkey); if ( keysize == 0 ) { ERROR("Error: public key size is 0\n"); RSA_free(pubkey); return NULL; } lcp_signature_t *sig = malloc(sizeof(*sig) + 2*keysize); if ( sig == NULL ) { ERROR("Error: failed to allocate sig\n"); RSA_free(pubkey); return NULL; } memset(sig, 0, sizeof(*sig) + 2*keysize); sig->pubkey_size = keysize; if ( (unsigned int)BN_num_bytes(pubkey->n) != keysize ) { ERROR("Error: modulus size not match key size\n"); free(sig); RSA_free(pubkey); return NULL; } unsigned char key[keysize]; BN_bn2bin(pubkey->n, key); /* openssl key is big-endian and policy requires little-endian, so reverse bytes */ for ( unsigned int i = 0; i < keysize; i++ ) sig->pubkey_value[i] = *(key + (keysize - i - 1)); if ( verbose ) { LOG("signature:\n"); display_signature(" ", sig, false); } RSA_free(pubkey); return sig; } static bool sign_list_data(lcp_policy_list_t *pollist, const char *privkey_file) { if ( pollist == NULL || privkey_file == NULL ) return false; lcp_signature_t *sig = get_signature(pollist); if ( sig == NULL ) return false; /* read private key */ FILE *fp = fopen(privkey_file, "r"); if ( fp == NULL ) { ERROR("Error: failed to open .pem file %s: %s\n", privkey_file, strerror(errno)); return false; } RSA *privkey = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); if ( privkey == NULL ) { ERR_load_crypto_strings(); ERROR("Error: failed to read .pem file %s: %s\n", privkey_file, ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); return false; } if ( RSA_size(privkey) != sig->pubkey_size ) { ERROR("Error: private and public key sizes don't match\n"); RSA_free(privkey); return false; } /* first create digest of list (all except sig_block) */ tb_hash_t digest; if ( !hash_buffer((const unsigned char *)pollist, get_policy_list_size(pollist) - sig->pubkey_size, &digest, TB_HALG_SHA1) ) { ERROR("Error: failed to hash list\n"); RSA_free(privkey); return false; } if ( verbose ) { LOG("digest: "); print_hex("", &digest, get_hash_size(TB_HALG_SHA1)); } /* sign digest */ /* work on buffer because we need to byte swap before putting in policy */ uint8_t sigblock[sig->pubkey_size]; unsigned int sig_len = sig->pubkey_size; if ( !RSA_sign(NID_sha1, (const unsigned char *)&digest, get_hash_size(TB_HALG_SHA1), sigblock, &sig_len, privkey) ) { ERR_load_crypto_strings(); ERROR("Error: failed to sign list: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); RSA_free(privkey); return false; } if ( sig_len != sig->pubkey_size ) { ERROR("Error: signature length mismatch\n"); RSA_free(privkey); return false; } RSA_free(privkey); /* sigblock is big-endian and policy needs little-endian, so reverse */ for ( unsigned int i = 0; i < sig->pubkey_size; i++ ) *(get_sig_block(pollist) + i) = *(sigblock + (sig->pubkey_size - i - 1)); if ( verbose ) { LOG("signature:\n"); display_signature(" ", sig, false); } return true; } static int create(void) { lcp_policy_list_t *pollist = create_empty_policy_list(); if ( pollist == NULL ) return 1; pollist->version = version; for ( unsigned int i = 0; i < nr_files; i++ ) { size_t len; lcp_policy_element_t *elt = read_file(files[i], &len, false); if ( elt == NULL ) { free(pollist); return 1; } if ( !verify_policy_element(elt, len) ) { free(pollist); return 1; } pollist = add_policy_element(pollist, elt); if ( pollist == NULL ) return 1; } bool write_ok = write_policy_list_file(pollist_file, pollist); free(pollist); return write_ok ? 0 : 1; } static int sign(void) { /* read existing policy list file */ bool no_sigblock_ok = true; lcp_policy_list_t *pollist = read_policy_list_file(pollist_file, false, &no_sigblock_ok); if ( pollist == NULL ) return 1; /* read public key file */ lcp_signature_t *sig = read_pubkey_file(pubkey_file); if ( sig == NULL ) { free(pollist); return 1; } /* check public key size */ if ( (sig->pubkey_size != 128 /* 1024 bits */) && (sig->pubkey_size != 256 /* 2048 bits */) && (sig->pubkey_size != 384 /* 3072 bits */) ) { ERROR("Error: public key size is not 1024/2048/3072 bits\n"); free(sig); free(pollist); return 1; } sig->revocation_counter = rev_ctr; pollist = add_signature(pollist, sig); if ( pollist == NULL ) { free(sig); return 1; } pollist->sig_alg = LCP_POLSALG_RSA_PKCS_15; if ( no_sigblock ) memset(get_sig_block(pollist), 0, sig->pubkey_size); else { if ( !sign_list_data(pollist, privkey_file) ) { free(sig); free(pollist); return 1; } } bool write_ok = write_policy_list_file(pollist_file, pollist); free(sig); free(pollist); return write_ok ? 0 : 1; } static int addsig(void) { /* read existing policy list file */ bool no_sigblock_ok = true; lcp_policy_list_t *pollist = read_policy_list_file(pollist_file, false, &no_sigblock_ok); if ( pollist == NULL ) return 1; lcp_signature_t *sig = get_signature(pollist); if ( sig == NULL ) { free(pollist); return 1; } /* check public key size */ if ( (sig->pubkey_size != 128 /* 1024 bits */) && (sig->pubkey_size != 256 /* 2048 bits */) && (sig->pubkey_size != 384 /* 3072 bits */) ) { ERROR("Error: public key size is not 1024/2048/3072 bits\n"); free(pollist); return 1; } /* read signature file */ size_t len; uint8_t *data = read_file(sig_file, &len, false); if ( data == NULL ) { free(pollist); return 1; } if ( len != sig->pubkey_size ) { ERROR("Error: signature file size doesn't match public key size\n"); free(pollist); free(data); return 1; } /* verify that this sigblock actually matches the policy list */ LOG("verifying signature block...\n"); if ( !verify_signature((const unsigned char *)pollist, get_policy_list_size(pollist) - sig->pubkey_size, sig->pubkey_value, sig->pubkey_size, data, false) ) { ERROR("Error: signature file does not match policy list\n"); free(pollist); free(data); return 1; } LOG("signature file verified\n"); /* data is big-endian and policy needs little-endian, so reverse */ for ( unsigned int i = 0; i < sig->pubkey_size; i++ ) *(get_sig_block(pollist) + i) = *(data + (sig->pubkey_size - i - 1)); if ( verbose ) { LOG("signature:\n"); display_signature(" ", sig, false); } bool write_ok = write_policy_list_file(pollist_file, pollist); free(pollist); free(data); return write_ok ? 0 : 1; } static int show(void) { /* read existing file */ bool no_sigblock_ok = true; lcp_policy_list_t *pollist = read_policy_list_file(files[0], false, &no_sigblock_ok); if ( pollist == NULL ) return 1; DISPLAY("policy list file: %s\n", files[0]); display_policy_list("", pollist, false); if ( pollist->sig_alg == LCP_POLSALG_RSA_PKCS_15 && !no_sigblock_ok ) { if ( verify_pollist_sig(pollist) ) DISPLAY("signature verified\n"); else DISPLAY("failed to verify signature\n"); } return 0; } int main(int argc, char *argv[]) { int cmd = 0; bool prev_cmd = false; int c; do { c = getopt_long_only(argc, argv, "", long_opts, NULL); switch (c) { /* commands */ case 'H': /* help */ case 'C': /* create */ case 'S': /* sign */ case 'A': /* addsig */ case 'W': /* show */ if ( prev_cmd ) { ERROR("Error: only one command can be specified\n"); return 1; } prev_cmd = true; cmd = c; LOG("cmdline opt: command: %c\n", cmd); break; case 'v': /* version */ version = strtoul(optarg, NULL, 0); LOG("cmdline opt: ver: 0x%x (%u)\n", version, version); break; case 'o': /* out */ strlcpy(pollist_file, optarg, sizeof(pollist_file)); LOG("cmdline opt: out: %s\n", pollist_file); break; case 'u': /* pub */ strlcpy(pubkey_file, optarg, sizeof(pubkey_file)); LOG("cmdline opt: pub: %s\n", pubkey_file); break; case 'i': /* priv */ strlcpy(privkey_file, optarg, sizeof(privkey_file)); LOG("cmdline opt: pub: %s\n", privkey_file); break; case 'r': /* rev */ rev_ctr = strtoul(optarg, NULL, 0); LOG("cmdline opt: rev: 0x%x (%u)\n", rev_ctr, rev_ctr); break; case 'n': /* nosig */ no_sigblock = true; LOG("cmdline opt: nosig: %u\n", no_sigblock); break; case 's': /* sigblock */ strlcpy(sig_file, optarg, sizeof(sig_file)); LOG("cmdline opt: sigblock: %s\n", sig_file); break; case 0: case -1: break; default: ERROR("Error: unrecognized option\n"); return 1; } } while ( c != -1 ); /* process any remaining argv[] items */ while ( optind < argc && nr_files < ARRAY_SIZE(files) ) { LOG("cmdline opt: file: %s\n", argv[optind]); strlcpy(files[nr_files++], argv[optind], sizeof(files[0])); optind++; } if ( cmd == 0 ) { ERROR("Error: no command option was specified\n"); return 1; } else if ( cmd == 'H' ) { /* --help */ DISPLAY("%s", help); return 0; } else if ( cmd == 'C' ) { /* --create */ if ( *pollist_file == '\0' ) { ERROR("Error: no policy list output file specified\n"); return 1; } return create(); } else if ( cmd == 'S' ) { /* --sign */ if ( *pollist_file == '\0' ) { ERROR("Error: no policy list output file specified\n"); return 1; } if ( *pubkey_file == '\0' ) { ERROR("Error: no public key file specified\n"); return 1; } if ( no_sigblock ) { /* no signature wanted */ if ( *privkey_file != '\0' ) { ERROR("Error: private key file specified with --nosig option\n"); return 1; } } else { /* we generate sig, so need private key */ if ( *privkey_file == '\0' ) { ERROR("Error: no private key file specified\n"); return 1; } } return sign(); } else if ( cmd == 'A' ) { /* --addsig */ if ( *pollist_file == '\0' ) { ERROR("Error: no policy list output file specified\n"); return 1; } if ( *sig_file == '\0' ) { ERROR("Error: no signature file specified\n"); return 1; } return addsig(); } else if ( cmd == 'W' ) { /* --show */ if ( nr_files != 1 ) { ERROR("Error: no policy list file specified\n"); return 1; } return show(); } ERROR("Error: unknown command\n"); return 1; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/custom_elt.c0000644000000000000000000001575612272416301015172 0ustar 00000000000000/* * custom_elt.c: custom (user/ISV/etc. -defined) policy element * (LCP_MLE_ELEMENT) plugin * * Copyright (c) 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. * */ #include #include #include #include #include #include #define _GNU_SOURCE #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "polelt_plugin.h" #include "lcputils2.h" #define NULL_UUID { 0x00000000, 0x0000, 0x0000, 0x0000, \ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } static uuid_t uuid = NULL_UUID; static size_t data_len; static uint8_t *data; static char *skipspace(const char *s) { while (*s != '\0' && isspace(*s)) s++; return (char *)s; } static bool string_to_uuid(const char *s, uuid_t *uuid) { int i; char *next; *uuid = (uuid_t)NULL_UUID; s = skipspace(s); /* * users can input "tboot" to specify to use the default tb policy uuid * for wrapping tb policy into lcp custom element */ if ( strcmp(s, "tboot") == 0 ) { *uuid = (uuid_t)LCP_CUSTOM_ELEMENT_TBOOT_UUID; return true; } /* Fetch data1 */ if ( *s++ != '{' ) return false; s = skipspace(s); uuid->data1 = (uint32_t)strtoul(s, &next, 16); if ( next == s ) return false; else next = skipspace(next); s = next; /* Fetch data2 */ if ( *s++ != ',' ) return false; s = skipspace(s); uuid->data2 = (uint16_t)strtoul(s, &next, 16); if ( next == s ) return false; else next = skipspace(next); s = next; /* Fetch data3 */ if ( *s++ != ',' ) return false; s = skipspace(s); uuid->data3 = (uint16_t)strtoul(s, &next, 16); if ( next == s ) return false; else next = skipspace(next); s = next; /* Fetch data4 */ if ( *s++ != ',' ) return false; s = skipspace(s); uuid->data4 = (uint16_t)strtoul(s, &next, 16); if ( next == s ) return false; else next = skipspace(next); s = next; /* Fetch data5 */ if ( *s++ != ',' ) return false; s = skipspace(s); if ( *s++ != '{' ) return false; s = skipspace(s); for ( i = 0; i < 6; i++ ) { uuid->data5[i] = (uint8_t)strtoul(s, &next, 16); if ( next == s ) return false; else next = skipspace(next); s = next; if ( i < 5 ) { /* Check "," */ if ( *s++ != ',' ) return false; s = skipspace(s); } else { /* Check "}}" */ if ( *s++ != '}' ) return false; s = skipspace(s); if ( *s++ != '}' ) return false; s = skipspace(s); } } if ( *s != '\0' ) return false; return true; } static bool cmdline_handler(int c, const char *opt) { if ( c == 'u' ) { if ( !string_to_uuid(opt, &uuid) ) { ERROR("Error: uuid is not well formed: %s\n", opt); return false; } LOG("cmdline opt: uuid:"); if ( verbose ) { print_uuid(&uuid); LOG("\n"); } return true; } else if ( c != 0 ) { ERROR("Error: unknown option for custom type\n"); return false; } /* data file */ LOG("cmdline opt: data file: %s\n", opt); data = read_file(opt, &data_len, false); if ( data == NULL ) return false; return true; } static lcp_policy_element_t *create(void) { if ( are_uuids_equal(&uuid, &((uuid_t)NULL_UUID)) ) { ERROR("Error: no uuid specified\n"); free(data); return NULL; } size_t data_size = sizeof(lcp_custom_element_t) + data_len; lcp_policy_element_t *elt = malloc(sizeof(*elt) + data_size); if ( elt == NULL ) { ERROR("Error: failed to allocate element\n"); free(data); return NULL; } memset(elt, 0, sizeof(*elt) + data_size); elt->size = sizeof(*elt) + data_size; lcp_custom_element_t *custom = (lcp_custom_element_t *)&elt->data; custom->uuid = uuid; memcpy(custom->data, data, data_len); free(data); data = NULL; return elt; } static void display(const char *prefix, const lcp_policy_element_t *elt) { lcp_custom_element_t *custom = (lcp_custom_element_t *)elt->data; DISPLAY("%s uuid: ", prefix); print_uuid(&custom->uuid); DISPLAY("\n"); DISPLAY("%s data:\n", prefix); print_hex(prefix, custom->data, elt->size - sizeof(*elt) - sizeof(custom->uuid)); } static struct option opts[] = { {"uuid", required_argument, NULL, 'u'}, {0, 0, 0, 0} }; static polelt_plugin_t plugin = { "custom", opts, " custom\n" " --uuid UUID in format:\n" " {0xaabbccdd, 0xeeff, 0xgghh, 0xiijj,\n" " {0xkk 0xll, 0xmm, 0xnn, 0xoo, 0xpp}}\n" " or \"--uuid tboot\" to use default\n" " file containing element data\n", LCP_POLELT_TYPE_CUSTOM, &cmdline_handler, &create, &display }; REG_POLELT_PLUGIN(&plugin) /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/defindex.c0000644000000000000000000002751012272416301014571 0ustar 00000000000000/* * Copyright 2001 - 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 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. */ /* * defindex.c * * Command: tpmnv_defindex. * * This command can define the index in TPM NV Storage. * */ #include #include #include #include #include #include #define PRINT printf #include "../include/uuid.h" #include "../include/lcp2.h" #include "lcptools.h" #include "lcputils.h" static uint32_t index_value = 0; static uint32_t per_value = 0xffff; static uint32_t data_size = 0; static char *auth_value = NULL; static uint32_t auth_length = 0; static uint8_t r_loc_arg = 0; static uint8_t w_loc_arg = 0; static char *password = NULL; static uint32_t password_len = 0; static int help_input = 0; static const char *short_option = "hi:s:p:"; static struct option longopts[] = { {"pv", 1, 0, 'v'}, {"av", 1, 0, 'a'}, {"wl", 1, 0, 'w'}, {"rl", 1, 0, 'r'}, {0, 0, 0, 0}}; static const char *usage_string = "tpmnv_defindex -i index [-s size] " "[-pv permission_value] " "[-p passwd] [-av authentication_value] " "[-wl write_locality] [-rl read_locality] [-h]"; static const char * option_strings[] = { "-i index value: uint32/string.\n"\ "\tINDEX_LCP_DEF:0x50000001 or \"default\",\n"\ "\tINDEX_LCP_OWN:0x40000001 or \"owner\",\n"\ "\tINDEX_AUX:0x50000002 or \"aux\"\n", "-pv permission value: uint32.\n"\ "\tOptional for indices INDEX_LCP_DEF, INDEX_LCP_OWN, INDEX_AUX.\n"\ "\tDefault value for indices: INDEX_LCP_DEF:0x00002000;\n"\ "\tINDEX_LCP_OWN:0x00000002; INDEX_AUX:0x0; Othr:0x0\n", "-s data size: UNIT32. \n"\ "\tOptional for indices INDEX_LCP_DEF, INDEX_LCP_OWN and INDEX_AUX.\n"\ "\tDefault value for indices:\n"\ "\tINDEX_LCP_DEF and INDEX_LCP_OWN:54; INDEX_AUX:64. Unit is byte\n", "-av auth value: string. Auth value for defined index.\n", "-p password: string. \n", "-rl read locality value: uint8. There are 5 localities:0~4.\n"\ "\tFor example, locality value is 0x18 if locality 3 or 4. \n", "-wl write locality value: uint8. The same as read locality value.\n", "-h help. Will print out this help message.\n", NULL }; static param_option_t index_option_table[] = { {"default", INDEX_LCP_DEF}, {"owner", INDEX_LCP_OWN}, {"aux", INDEX_AUX}, {NULL, -1} }; /* * function: parse_cmdline * description: parse the input of commandline */ static int parse_cmdline(int argc, const char* argv[]) { int c; uint32_t temp = 0; while ((c = getopt_long_only(argc,(char ** const)argv, short_option, longopts, NULL)) != -1) switch (c) { case 'i': /* check whether user inputs the string for reserved indices */ index_value = parse_input_option(index_option_table, optarg); /* * if not, then the users should input the non-0 number, * 0 is not allowed for index */ if ( index_value == (uint32_t)-1 ) if ( strtonum(optarg, &index_value) || (index_value == 0) ) return LCP_E_INVALID_PARAMETER; break; case 's': if ( strtonum(optarg, &data_size) ) return LCP_E_INVALID_PARAMETER; break; case 'p': password = optarg; password_len = strlen(password); break; case 'h': help_input = 1; break; case 'v': if ( strtonum(optarg, &per_value) ) return LCP_E_INVALID_PARAMETER; break; case 'a': auth_value = optarg; auth_length = strlen(auth_value); break; case 'w': if ( strtonum(optarg, &temp) ) return LCP_E_INVALID_PARAMETER; if (temp > 0x1f || temp < 1) return LCP_E_INVALID_PARAMETER; w_loc_arg = temp; break; case 'r': if ( strtonum(optarg, &temp) ) return LCP_E_INVALID_PARAMETER; if ( temp > 0x1f || temp < 1 ) return LCP_E_INVALID_PARAMETER; r_loc_arg = temp; break; default: return LCP_E_NO_SUCH_PARAMETER; } if ( optind < argc ) return LCP_E_INVALID_PARAMETER; return LCP_SUCCESS; } int main (int argc, char* argv[]) { in_nv_definespace_t in_defspace; uint32_t per_authwrite = 0; uint32_t per_authread = 0; /* * Currently assume pcr selection size is 3. */ uint16_t pcr_size = 3; /* * PCR short info size is 2+3+1+20 = 26. */ unsigned char rd_pcrcom[26] = {0}; unsigned char *pdata; unsigned char wrt_pcrcom[26] = {0}; lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; /* * No parameter input will print out the help message. */ if ( argc == 1 ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } ret_value = parse_cmdline(argc, (const char **)argv); if ( ret_value ) goto _error_end; /* * If user input -h(help), just print guide to * users and ignore other parameters. */ if ( help_input ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } /* * Check whether parameter of index value has been input. */ if ( index_value == 0 ) { ret_value = LCP_E_NO_INDEXVALUE; goto _error_end; } in_defspace.index = index_value; /* * Check whether parameter of permission value has been input. */ if ( per_value == 0xffff ) { switch (in_defspace.index) { case INDEX_LCP_DEF: in_defspace.permission = PERMISSION_DEF; log_info("Haven't input permission value, "\ "use default value 0x%x\n", in_defspace.permission); break; case INDEX_LCP_OWN: in_defspace.permission = PERMISSION_OWN; log_info("Haven't input permission value, "\ "use default value 0x%x\n", in_defspace.permission); break; case INDEX_AUX: in_defspace.permission = PERMISSION_AUX; log_info("Haven't input permission value, "\ "use default value 0x%x\n", in_defspace.permission); break; default: ret_value = LCP_E_NO_PER_VALUE; goto _error_end; } } else in_defspace.permission = per_value; /* * Check whether parameter of datasize has been input. */ if ( data_size == 0 ) { switch (in_defspace.index) { case INDEX_LCP_DEF: in_defspace.size = DATASIZE_POL; log_info("Haven't input data size, "\ "use default value %d\n",\ in_defspace.size); break; case INDEX_LCP_OWN: in_defspace.size = DATASIZE_POL; log_info("Haven't input data size, "\ "use default value %d\n",\ in_defspace.size); break; case INDEX_AUX: in_defspace.size = DATASIZE_AUX; log_info("Haven't input data size, "\ "use default value %d\n",\ in_defspace.size); break; default : ret_value = LCP_E_NO_DATASIZE; goto _error_end; } } else in_defspace.size = data_size; /* * Check whether authentication value has been input. */ if ( auth_value == NULL ) { /* * Check the permission value, * if it needs authorization to read or write, * the authentication value should be inputted. */ per_authwrite = (in_defspace.permission & 0x4) >> 2; per_authread = (in_defspace.permission & 0x40000) >> 18; if ( per_authwrite || per_authread ) { ret_value = LCP_E_NO_AUTH; goto _error_end; } } /* * Check whether read locality value has been input. * If user hasn't input, set as default value: 0x1f. */ if ( r_loc_arg != 0 && r_loc_arg <= 0x1f ) { in_defspace.r_loc = r_loc_arg; } else if ( r_loc_arg == 0 ) { in_defspace.r_loc = LOCALITY_DEFAULT; } else { ret_value = LCP_E_INVALID_PARAMETER; goto _error_end; } /* * Check whether write locality value has been input. * If user hasn't input, set as default value: 0x1f. */ if ( w_loc_arg != 0 ) { in_defspace.w_loc = w_loc_arg; if ( (in_defspace.index == INDEX_AUX) && (in_defspace.w_loc != WR_LOCALITY_AUX) ) { ret_value = LCP_E_INVALID_PARAMETER; goto _error_end; } } else { if ( in_defspace.index == INDEX_AUX ) in_defspace.w_loc = WR_LOCALITY_AUX; else in_defspace.w_loc = LOCALITY_DEFAULT; } /* build the pcr_short_info for read_pcrcomposite*/ pdata = rd_pcrcom; lcp_loaddata_uint16(pcr_size, &pdata, 1); pdata += pcr_size; lcp_loaddata_byte((unsigned char)in_defspace.r_loc, &pdata); /* build the pcr_short_info for write_pcrcomposite*/ pdata = wrt_pcrcom; lcp_loaddata_uint16(pcr_size, &pdata, 1); pdata += pcr_size; lcp_loaddata_byte((unsigned char)in_defspace.w_loc, &pdata); ret_value = lcp_define_index(&in_defspace, auth_value, auth_length, password, password_len, rd_pcrcom, wrt_pcrcom); if ( ret_value == LCP_SUCCESS ) { log_info("\nSuccessfully defined index 0x%08x "\ "as permission 0x%x, data size is %d \n", in_defspace.index, in_defspace.permission, in_defspace.size); return ret_value; } _error_end: /* * Error when execute. */ log_error("\nCommand DefIndex failed:\n"); print_error(ret_value); return ret_value; } tboot-1.8.0/lcptools/getcap.c0000644000000000000000000003351612272416301014251 0ustar 00000000000000/* * Copyright 2001 - 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 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. */ /* * getcap.c * * Command: tpmnv_getcap. * * This command can get basic information from TPM like the the PCR number, * the indices have been defined and the public data associated with the * specified index. * */ #include #include #include #include #include #include #define PRINT printf #include "../include/uuid.h" #include "../include/lcp.h" #include "lcptools.h" #include "lcputils.h" #define BUFFER_SIZE 1024 static unsigned int index_value = 0; static int help_input = 0; static int perm_flags = 0; static char *password = NULL; static uint32_t passwd_length = 0; static const char *short_option = "hi:f:"; static const char *usage_string = "tpmnv_getcap [-i index] [-f password] [-h]"; static const char * option_strings[] ={ "-i index value: uint32/string. To get the public data of this index.\n"\ "\tINDEX_LCP_DEF:0x50000001 or \"default\",\n"\ "\tINDEX_LCP_OWN:0x40000001 or \"owner\",\n"\ "\tINDEX_AUX:0x50000002 or \"aux\"\n", "-f password: string displays TPM_PERMANENT_FLAGS.\n", "-h help. Will print out this help message.\n", NULL }; static param_option_t index_option_table[] = { {"default", INDEX_LCP_DEF}, {"owner", INDEX_LCP_OWN}, {"aux", INDEX_AUX}, {NULL, -1} }; /* * function: parse_cmdline * description: parse the input of commandline */ static int parse_cmdline(int argc, const char * argv[]) { int c; while (((c = getopt(argc, (char ** const)argv, short_option)) != -1)) switch (c){ case 'i': /* check whether user inputs the string for reserved indices */ index_value = parse_input_option(index_option_table, optarg); /* * if not, then the users should input the non-0 number, * 0 is not allowed for index */ if ( index_value == (uint32_t)-1 ) if ( strtonum(optarg, &index_value) || (index_value == 0) ) return LCP_E_INVALID_PARAMETER; break; case 'f': perm_flags = 1; password = optarg; passwd_length = strlen(password); break; case 'h': help_input = 1; break; default: return LCP_E_NO_SUCH_PARAMETER; } if ( optind < argc ) return LCP_E_INVALID_PARAMETER; return LCP_SUCCESS; } /* print the message return by getcap command */ static void print_nv_caps_msg(int datasize, const unsigned char *data, const char *msg) { uint16_t i = 0; uint32_t ibyte; for (i = 0; i < datasize; i++) { if ( (i % 32) == 0 ) { if ( datasize > 32 ) { log_info("\n\t"); } log_info("%s", msg); } else if ( (i % 4) == 0 ) { log_info(" %s", msg); } ibyte = *(data + i); ibyte &= 0x000000ff; log_info("%02x", ibyte); } log_info("\n"); } typedef struct { uint32_t disable : 1; uint32_t ownership : 1; uint32_t deactivated : 1; uint32_t readPubek : 1; uint32_t disableOwnerClear : 1; uint32_t allowMaintenance : 1; uint32_t physicalPresenceLifetimeLock : 1; uint32_t physicalPresenceHWEnable : 1; uint32_t physicalPresenceCMDEnable : 1; uint32_t CEKPUsed : 1; uint32_t TPMpost : 1; uint32_t TPMpostLock : 1; uint32_t FIPS : 1; uint32_t Operator : 1; uint32_t enableRevokeEK : 1; uint32_t nvLocked : 1; uint32_t readSRKPub : 1; uint32_t tpmEstablished : 1; uint32_t maintenanceDone : 1; } tpm_perm_flags_t; typedef struct { uint32_t deactivated : 1; uint32_t disableForceClear : 1; uint32_t physicalPresence : 1; uint32_t physicalPresenceLock : 1; uint32_t bGlobalLock : 1; } tpm_stclear_flags_t; static lcp_result_t display_flags(void) { uint32_t subcap = 0; unsigned char buffer[BUFFER_SIZE], *pbuf; uint32_t datasize = 0; lcp_result_t result = LCP_E_COMD_INTERNAL_ERR; tpm_perm_flags_t perm_flags; tpm_stclear_flags_t stclear_flags; subcap = TPM_CAP_FLAG_PERMANENT; result = lcp_get_tpmcap_auth(password, passwd_length, TSS_TPMCAP_FLAG, 4, (unsigned char *)&subcap, &datasize, buffer); if ( result != LCP_SUCCESS ) { log_error("Error getting TPM_PERMANENT_FLAGS.\n"); return result; } else if ( datasize != 2*sizeof(uint32_t) ) { log_error("Error getting TPM_PERMANENT_FLAGS.\n"); return LCP_E_GETCAP_REP_ERROR; } pbuf = buffer; lcp_unloaddata_uint32((uint32_t *)&perm_flags, &pbuf, 1); lcp_unloaddata_uint32((uint32_t *)&stclear_flags, &pbuf, 1); log_info("TPM_PERMANENT_FLAGS:\n"); log_info("\t disable: %s\n", bool_to_str(perm_flags.disable)); log_info("\t ownership: %s\n", bool_to_str(perm_flags.ownership)); log_info("\t deactivated: %s\n", bool_to_str(perm_flags.deactivated)); log_info("\t readPubek: %s\n", bool_to_str(perm_flags.readPubek)); log_info("\t disableOwnerClear: %s\n", bool_to_str(perm_flags.disableOwnerClear)); log_info("\t allowMaintenance: %s\n", bool_to_str(perm_flags.allowMaintenance)); log_info("\t physicalPresenceLifetimeLock: %s\n", bool_to_str(perm_flags.physicalPresenceLifetimeLock)); log_info("\t physicalPresenceHWEnable: %s\n", bool_to_str(perm_flags.physicalPresenceHWEnable)); log_info("\t physicalPresenceCMDEnable: %s\n", bool_to_str(perm_flags.physicalPresenceCMDEnable)); log_info("\t CEKPUsed: %s\n", bool_to_str(perm_flags.CEKPUsed)); log_info("\t TPMpost: %s\n", bool_to_str(perm_flags.TPMpost)); log_info("\t TPMpostLock: %s\n", bool_to_str(perm_flags.TPMpostLock)); log_info("\t FIPS: %s\n", bool_to_str(perm_flags.FIPS)); log_info("\t Operator: %s\n", bool_to_str(perm_flags.Operator)); log_info("\t enableRevokeEK: %s\n", bool_to_str(perm_flags.enableRevokeEK)); log_info("\t nvLocked: %s\n", bool_to_str(perm_flags.nvLocked)); log_info("\t readSRKPub: %s\n", bool_to_str(perm_flags.readSRKPub)); log_info("\t tpmEstablished: %s\n", bool_to_str(perm_flags.tpmEstablished)); log_info("\t maintenanceDone: %s\n", bool_to_str(perm_flags.maintenanceDone)); log_info("\nTPM_STCLEAR_FLAGS:\n"); log_info("\t deactivated: %s\n", bool_to_str(stclear_flags.deactivated)); log_info("\t disableForceClear: %s\n", bool_to_str(stclear_flags.disableForceClear)); log_info("\t physicalPresence: %s\n", bool_to_str(stclear_flags.physicalPresence)); log_info("\t physicalPresenceLock: %s\n", bool_to_str(stclear_flags.physicalPresenceLock)); log_info("\t bGlobalLock: %s\n", bool_to_str(stclear_flags.bGlobalLock)); return LCP_SUCCESS; } /* function: get_pubdata * * get public data of the index * public data format is: * { * TPM_STRUCTURE_TAG tag; * TPM_NV_INDEX nvIndex; * TPM_PCR_INFO_SHORT pcrInfoRead; * TPM_PCR_INFO_SHORT pcrInfoWrite; * TPM_NV_ATTRIBUTES permission; * TPM_BOOL bReadSTClear; * TPM_BOOL bWriteSTClear; * TPM_BOOL bWriteDefine; * UINT32 dataSize; * } */ static lcp_result_t get_pubdata(uint32_t index) { uint32_t index_retrieve = 0; uint16_t pcrread_sizeofselect = 0; uint16_t pcrwrite_sizeofselect = 0; uint32_t permission; uint32_t datasize = 0; unsigned char buffer[BUFFER_SIZE]; unsigned char *pbuffer; lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; ret_value = lcp_get_tpmcap(TSS_TPMCAP_NV_INDEX, 4, (unsigned char *)&index, &datasize, buffer); if ( ret_value != LCP_SUCCESS ) return ret_value; if ( datasize != 0 ) { /* start to parse public data of the index */ pbuffer = buffer + sizeof(TPM_STRUCTURE_TAG); /* get the index value */ lcp_unloaddata_uint32(&index_retrieve, &pbuffer, 1); /* * If the index retrieved correctly, * print the public data to the screen. */ if ( index_retrieve == index ) { log_info("\nThe public data value of index 0x%08x is: \n", index); /* print the public data to the screen */ print_nv_caps_msg(datasize, buffer, ""); /* parse pcrInfoRead */ lcp_unloaddata_uint16(&pcrread_sizeofselect, &pbuffer, 1); pbuffer += pcrread_sizeofselect; log_info("\n\tRead locality: "); print_locality(*pbuffer); log_info(".\n"); /* move the pbuffer to the start of pcrInfoWrite */ pbuffer += pcrread_sizeofselect + sizeof(TPM_LOCALITY_SELECTION) + sizeof(TPM_COMPOSITE_HASH); /* parse pcrInfoWrite */ lcp_unloaddata_uint16(&pcrwrite_sizeofselect, &pbuffer, 1); pbuffer += pcrwrite_sizeofselect; log_info("\n\tWrite locality: "); print_locality(*pbuffer); log_info(".\n"); /* move the pointer and get permission value */ pbuffer += pcrwrite_sizeofselect + sizeof(TPM_LOCALITY_SELECTION) + sizeof(TPM_COMPOSITE_HASH) + sizeof(TPM_STRUCTURE_TAG); lcp_unloaddata_uint32(&permission, &pbuffer, 1); log_info("\n\tPermission value is 0x%x:\n", permission); print_permissions(permission, "\t\t"); /* move the pointer and get data size */ pbuffer += sizeof(unsigned char) + sizeof(unsigned char) + sizeof(unsigned char); lcp_unloaddata_uint32(&datasize, &pbuffer, 1); log_info("\n\tData size is %d.\n", datasize); } else return LCP_E_NV_AREA_NOT_EXIST; } else return LCP_E_NV_AREA_NOT_EXIST; return LCP_SUCCESS; } /* get the pcr number and nv index list of the TPM device */ static lcp_result_t get_common(void) { uint16_t tmplen = 0; unsigned char buffer[BUFFER_SIZE]; uint32_t datasize = 0; lcp_result_t result = LCP_E_COMD_INTERNAL_ERR; /* * Get the NV list. */ result = lcp_get_tpmcap(TSS_TPMCAP_NV_LIST, 0, NULL, &datasize, buffer); if ( result != LCP_SUCCESS ) { log_error("Error get NV index list. \n"); return result; } if ( datasize != 0 ) { tmplen = datasize/4; log_info("\n%d indices have been defined\n", tmplen); log_info("list of indices for defined NV storage areas:\n"); print_nv_caps_msg(datasize, buffer, "0x"); } else log_info("No index has been defined. \n"); return LCP_SUCCESS; } int main (int argc, char *argv[]) { lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; ret_value = parse_cmdline(argc, (const char **)argv); if ( ret_value ) goto _error_end; /* * If user input -h(help), just print guide to * users and ignore other parameters. */ if ( help_input ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } if ( perm_flags ) { if ( password == NULL ) { ret_value = LCP_E_AUTH_FAIL; log_error("No password input! Password is needed to " "display flags.\n"); goto _error_end; } ret_value = display_flags(); if ( ret_value != LCP_SUCCESS ) goto _error_end; return LCP_SUCCESS; } if ( index_value != 0 ) { if ( (ret_value = get_pubdata(index_value)) != LCP_SUCCESS ) goto _error_end; } else if ( (ret_value = get_common()) != LCP_SUCCESS ) goto _error_end; return LCP_SUCCESS; _error_end: /* * Error when execute. */ log_error("\nCommand TpmCap failed:\n"); print_error(ret_value); return ret_value; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/hash.c0000644000000000000000000001050312272416301013720 0ustar 00000000000000/* * hash.c: support functions for tb_hash_t type * * 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. * */ #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" /* * are_hashes_equal * * compare whether two hash values are equal. * */ bool are_hashes_equal(const tb_hash_t *hash1, const tb_hash_t *hash2, uint16_t hash_alg) { if ( ( hash1 == NULL ) || ( hash2 == NULL ) ) return false; if ( hash_alg == TB_HALG_SHA1 ) return (memcmp(hash1, hash2, SHA1_LENGTH) == 0); else 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 ) return false; if ( hash_alg == TB_HALG_SHA1 ) { EVP_MD_CTX ctx; const EVP_MD *md; md = EVP_sha1(); EVP_DigestInit(&ctx, md); EVP_DigestUpdate(&ctx, buf, size); EVP_DigestFinal(&ctx, hash->sha1, NULL); return true; } else 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*sizeof(tb_hash_t)]; if ( hash1 == NULL || hash2 == NULL ) return false; if ( hash_alg == TB_HALG_SHA1 ) { EVP_MD_CTX ctx; const EVP_MD *md; memcpy(buf, &(hash1->sha1), sizeof(hash1->sha1)); memcpy(buf + sizeof(hash1->sha1), &(hash2->sha1), sizeof(hash1->sha1)); md = EVP_sha1(); EVP_DigestInit(&ctx, md); EVP_DigestUpdate(&ctx, buf, 2*sizeof(hash1->sha1)); EVP_DigestFinal(&ctx, hash1->sha1, NULL); return true; } else return false; } void print_hash(const tb_hash_t *hash, uint16_t hash_alg) { if ( hash == NULL ) return; if ( hash_alg == TB_HALG_SHA1 ) { for ( unsigned int i = 0; i < sizeof(hash->sha1); i++ ) fprintf(stderr, "%02x ", hash->sha1[i]); fprintf(stderr, "\n"); } else if ( hash_alg == TB_HALG_SHA256 ) { for ( unsigned int i = 0; i < sizeof(hash->sha256); i++ ) fprintf(stderr, "%02x ", hash->sha256[i]); fprintf(stderr, "\n"); } else return; } void copy_hash(tb_hash_t *dest_hash, const tb_hash_t *src_hash, uint16_t hash_alg) { if ( dest_hash == NULL || dest_hash == NULL ) return; if ( hash_alg == TB_HALG_SHA1 ) memcpy(dest_hash, src_hash, SHA1_LENGTH); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/lcptools.c0000644000000000000000000010267412272416301014647 0ustar 00000000000000/* * Copyright 2001 - 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 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. */ /* * lcptools.c * * This file implements all key functions used by LCP tools commands. * */ #include #include #include #include #include #include #define PRINT printf #include "../include/uuid.h" #include "../include/lcp.h" #include "lcptools.h" #include "lcputils.h" #define MAX_POLICY_LIST_SIZE 1024 /* Define the index * parameters: * p_in_defspace: contain the attributes of the index, * for example, datasize, permission * auth: password for the index with AUTHREAD/AUTHWRITE * auth_length: the length of auth password * passwd: the owner password * passwd_length: the length of the passwd * pcr_info_read: the pcr_short_info for pcrInfoRead * pcr_info_write: the pcr_short_info for pcrInfoWrite */ lcp_result_t lcp_define_index(in_nv_definespace_t *p_in_defspace, const char *auth, uint32_t auth_length, const char *passwd, uint32_t passwd_length, const unsigned char *pcr_info_read, const unsigned char *pcr_info_write) { TSS_HCONTEXT hcontext = NULL_HCONTEXT; TSS_HNVSTORE hnvstore = NULL_HNVSTORE; TSS_HPOLICY hpolobj = NULL_HOBJECT; TSS_HPCRS hwrtpcrcomp = NULL_HPCRS; TSS_HPCRS hrdpcrcomp = NULL_HPCRS; TSS_HPOLICY hpolicy = NULL_HPOLICY; TSS_HTPM htpm = NULL_HTPM; TSS_RESULT result; uint16_t pcr_size = 0; unsigned char *pdata; unsigned char rd_locality = 0; unsigned char wrt_locality = 0; lcp_result_t ret = LCP_E_COMD_INTERNAL_ERR; result = init_tss_context(&hcontext); CHECK_TSS_RETURN_VALUE("init_tss_context", result, ret); if ( passwd != NULL ) { result = set_tpm_secret(hcontext, &htpm, &hpolicy, passwd, passwd_length); CHECK_TSS_RETURN_VALUE("set_tpm_secret", result, ret); } /* * Create TPM NV object */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_NV, 0,&hnvstore); CHECK_TSS_RETURN_VALUE("Tspi_Context_CreateObject", result, ret); /* * if the nv object need authentication */ if ( auth != NULL ) { result = set_nv_secret(hcontext, hnvstore, &hpolobj, auth, auth_length); CHECK_TSS_RETURN_VALUE("set_nv_secret", result, ret); } /* * Set the index to be defined. */ result = Tspi_SetAttribUint32(hnvstore, TSS_TSPATTRIB_NV_INDEX, 0, p_in_defspace->index); CHECK_TSS_RETURN_VALUE("Tspi_SetAttribUint32 index", result, ret); /* * Set the permission for the index. */ result = Tspi_SetAttribUint32(hnvstore, TSS_TSPATTRIB_NV_PERMISSIONS, 0, p_in_defspace->permission); CHECK_TSS_RETURN_VALUE("Tspi_SetAttribUint32 permission", result, ret); /* * Set the data size to be defined. */ result = Tspi_SetAttribUint32(hnvstore, TSS_TSPATTRIB_NV_DATASIZE, 0, p_in_defspace->size); CHECK_TSS_RETURN_VALUE("Tspi_SetAttribUint32 data size", result, ret); /* * Define the space according to the parameters: index, * permission and datasize. * If the index is INDEX_AUX, the third parameter of * Tspi_NV_DefineSpace should be set. */ if ( p_in_defspace->index == INDEX_AUX ) { /* * Set PCR composite object. */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_PCRS, 3,&hwrtpcrcomp); CHECK_TSS_RETURN_VALUE("Tspi_Context_CreateObject", result, ret); /* * Set LocalityAtRelease inside the PCR composite object. * Locality Write for INDEX_AUX should be 3 or 4. */ result = Tspi_PcrComposite_SetPcrLocality(hwrtpcrcomp, WR_LOCALITY_AUX); CHECK_TSS_RETURN_VALUE("Tspi_PcrComposite_SetPcrLocality", result, ret); result = Tspi_NV_DefineSpace(hnvstore, 0, hwrtpcrcomp); CHECK_TSS_RETURN_VALUE("Tspi_NV_DefineSpace failed", result, ret); } else { /* * Set the locality number. */ if ( pcr_info_read ) { /* parse the pcr_info_read which is pcr_short_info format */ pdata = (unsigned char *)pcr_info_read; lcp_unloaddata_uint16(&pcr_size, &pdata, 1); pdata += pcr_size; lcp_unloaddata_byte(&rd_locality, &pdata); if ( rd_locality == 0 || rd_locality > 0x1f ) { log_error("Wrong read locality number!\n"); ret = LCP_E_TPM_BAD_LOCALITY; goto exit; } /* * Set PCR composite object. */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_PCRS, 3, &hrdpcrcomp); CHECK_TSS_RETURN_VALUE("Tspi_Context_CreateObject", result, ret); /* * Set LocalityAtRelease inside the PCR composite object. * Locality Write for INDEX_AUX should be 3 or 4. */ result = Tspi_PcrComposite_SetPcrLocality(hrdpcrcomp, rd_locality); CHECK_TSS_RETURN_VALUE("Tspi_PcrComposite_SetPcrLocality", result, ret); } if ( pcr_info_write != NULL ) { /* parse the pcr_info_write which is pcr_short_info format */ pdata = (unsigned char *)pcr_info_write; lcp_unloaddata_uint16(&pcr_size, &pdata, 1); pdata += pcr_size; lcp_unloaddata_byte(&wrt_locality, &pdata); if ( wrt_locality == 0 || wrt_locality > 0x1f ) { log_error("Wrong read locality number!\n"); ret = LCP_E_TPM_BAD_LOCALITY; goto exit; } /* * Set PCR composite object. */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_PCRS, 3, &hwrtpcrcomp); CHECK_TSS_RETURN_VALUE("Tspi_Context_CreateObject", result, ret); /* * Set LocalityAtRelease inside the PCR composite object. * Locality Write for INDEX_AUX should be 3 or 4. */ result = Tspi_PcrComposite_SetPcrLocality(hwrtpcrcomp, wrt_locality); CHECK_TSS_RETURN_VALUE("Tspi_PcrComposite_SetPcrLocality", result, ret); } result = Tspi_NV_DefineSpace(hnvstore, hrdpcrcomp, hwrtpcrcomp); CHECK_TSS_RETURN_VALUE("Tspi_NV_DefineSpace failed", result, ret); } ret = convert_error(result); exit: /* * Close context for the operation. */ close_tss_context(hcontext); return ret; } /* Release the index * Parameters: * index: the index to be release * passwd: the owner password * passwd_length: the length of the passwd */ lcp_result_t lcp_release_index(uint32_t index, const char *passwd, uint32_t passwd_length) { TSS_HCONTEXT hcontext = NULL_HCONTEXT; TSS_HNVSTORE hnvstore = NULL_HNVSTORE; TSS_HPOLICY hpolicy = NULL_HPOLICY; TSS_HTPM htpm = NULL_HTPM; TSS_RESULT result; lcp_result_t ret = LCP_E_COMD_INTERNAL_ERR; result = init_tss_context(&hcontext); CHECK_TSS_RETURN_VALUE("init_tss_context", result, ret); if ( passwd != NULL ) { result = set_tpm_secret(hcontext, &htpm, &hpolicy, passwd, passwd_length); CHECK_TSS_RETURN_VALUE("set_tpm_secret", result, ret); } /* * Create TPM NV object */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_NV, 0,&hnvstore); CHECK_TSS_RETURN_VALUE("Tspi_Context_CreateObject", result, ret); /* * Set the index to be released. */ result = Tspi_SetAttribUint32(hnvstore, TSS_TSPATTRIB_NV_INDEX, 0, index); CHECK_TSS_RETURN_VALUE("Tspi_SetAttribUint32 for setting NV index", result, ret); /* * Release the space according to the parameters: index and datasize. */ result = Tspi_NV_ReleaseSpace(hnvstore); CHECK_TSS_RETURN_VALUE("Tspi_NV_ReleaseSpace for deleting NV index", result, ret); ret = convert_error(result); exit: /* * Close context for the operation. */ close_tss_context(hcontext); return ret; } /* Read the content from the specified index * Parameters: * index: the index to be release * password: the owner password or the auth password of the index * passwd_length: the length of the passwd * read_offset: the offset to read * read_length: the length to read * data_length: the length of the data * data: the data read from the index */ lcp_result_t lcp_read_index(uint32_t index, const char *password, uint32_t pass_length, uint32_t read_offset, uint32_t read_length, uint32_t *data_length, unsigned char *data) { TSS_HCONTEXT hcontext = NULL_HCONTEXT; TSS_HNVSTORE hnvstore = NULL_HNVSTORE; TSS_HTPM htpm = NULL_HOBJECT; TSS_RESULT result; TSS_HPOLICY hnvpol; lcp_result_t ret = LCP_E_COMD_INTERNAL_ERR; uint32_t retlen; unsigned char *presult = NULL; unsigned char *policydata = NULL; uint32_t pwd_length = pass_length; uint32_t read_space = 0; result = init_tss_context(&hcontext); CHECK_TSS_RETURN_VALUE("init_tss_context", result, ret); /* * Create TPM NV object */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_NV, 0,&hnvstore); CHECK_TSS_RETURN_VALUE("Tspi_Context_CreateObject for nv object", result, ret); /* * Set the index to read */ result = Tspi_SetAttribUint32(hnvstore, TSS_TSPATTRIB_NV_INDEX, 0, index); CHECK_TSS_RETURN_VALUE("Tspi_SetAttribUint32 for setting NV index", result, ret); if ( password != NULL ) { result = set_nv_secret(hcontext, hnvstore, &hnvpol, password, pwd_length); CHECK_TSS_RETURN_VALUE("set_nv_secret", result, ret); } /* * Data length to read. */ read_space = read_length; if ( (read_length == 0)&&(read_offset == 0) ) { result = Tspi_Context_GetTpmObject(hcontext, &htpm); CHECK_TSS_RETURN_VALUE("Tspi_Context_GetTpmObject", result, ret); result = Tspi_TPM_GetCapability(htpm, TSS_TPMCAP_NV_INDEX, 4, (unsigned char *)&index, &retlen, &presult); CHECK_TSS_RETURN_VALUE("Tspi_TPM_GetCapability", result, ret); presult += retlen - 4; if ( retlen != 0 ) lcp_unloaddata_uint32(&read_space, &presult, 1); else { ret = LCP_E_TPM_BADINDEX; goto exit; } } if ( data == NULL || read_space > *data_length ) { log_info("Data size to read is %d.\n", read_space); log_info("Not enought memory allocated for output data! "\ "Max size allocated is %d.\n", *data_length); ret = LCP_E_INVALID_PARAMETER; goto exit; } /* * Read policy data from NV store. */ log_debug("begin to call the tss Tspi_NV_ReadValue\n"); result = Tspi_NV_ReadValue(hnvstore, read_offset, &read_space, &policydata); /* * Print error massage. */ if ( result != TSS_SUCCESS ) { ret = convert_error(result); goto exit; } ret = LCP_SUCCESS; memcpy(data, policydata, read_space); *data_length = read_space; exit: close_tss_context(hcontext); return ret; } /* Write the data into the specified index * Parameters: * index: the index to be release * password: the owner password or the auth password of the index * passwd_length: the length of the passwd * write_offset: the offset to write * length: the length of the data * data: the data to write */ lcp_result_t lcp_write_index(uint32_t index, const char *password, uint32_t passwd_length, uint32_t write_offset, uint32_t length, const unsigned char *data) { TSS_HCONTEXT hcontext = NULL_HCONTEXT; TSS_HNVSTORE hnvstore = NULL_HNVSTORE; TSS_RESULT result; TSS_HPOLICY hnvpol; lcp_result_t ret = LCP_E_COMD_INTERNAL_ERR; uint32_t pwd_length = passwd_length; result = init_tss_context(&hcontext); CHECK_TSS_RETURN_VALUE("init_tss_context", result, ret); /* * Create TPM NV object */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_NV, 0,&hnvstore); CHECK_TSS_RETURN_VALUE("Tspi_Context_CreateObject", result, ret); /* * Set the index to write */ result = Tspi_SetAttribUint32(hnvstore, TSS_TSPATTRIB_NV_INDEX, 0, index); CHECK_TSS_RETURN_VALUE("Tspi_SetAttribUint32 for setting NV index", result, ret); if ( password != NULL ) { result = set_nv_secret(hcontext, hnvstore, &hnvpol, password, pwd_length); CHECK_TSS_RETURN_VALUE("set_nv_secret", result, ret); } /* * Write data value to the NV store area. */ result = Tspi_NV_WriteValue(hnvstore, write_offset, length, (unsigned char *)data); /* * Print error massage. */ if ( result != TSS_SUCCESS ) { ret = convert_error(result); goto exit; } ret = LCP_SUCCESS; exit: close_tss_context(hcontext); return ret; } /* create the platform configuration * parameters: * num_indices: the count of the pcr_number * indices: the array of the pcr_numbers * pcr_len: the length of the pcr_hash_value * pcr_hash_val: the array of the pcr_values * locality: the locality value for the pcr_short_info * datalen: the length of produced pconf data * data: the produced pconf data */ lcp_result_t lcp_create_pconf(uint32_t num_indices, uint32_t *indices, uint32_t pcr_len, const unsigned char *pcr_hash_val, unsigned char locality, uint32_t *datalen, unsigned char **data) { TSS_HCONTEXT hcontext = NULL_HCONTEXT; TSS_HPCRS hpcrs = NULL_HPCRS; TSS_HTPM htpm = NULL_HOBJECT; TPM_PCR_SELECTION pselect; TSS_RESULT result = TSS_SUCCESS; lcp_result_t ret = LCP_E_COMD_INTERNAL_ERR; uint32_t idx; unsigned char *pcrval = NULL; uint32_t pcrlen; unsigned char hpcrhash[SHA1_HASH_LEN]; uint32_t hashlen = SHA1_HASH_LEN; uint64_t offset = 0; unsigned char *pdata; unsigned char *pcr_info = NULL; uint32_t pcr_info_size = 0; uint32_t size, index; unsigned char mask; unsigned char *pcr_read = NULL; uint32_t pcr_hash_size = 0; if ( (num_indices == 0) || (indices == NULL) ) return LCP_E_INVALID_PARAMETER; /* calculate the sizeofselect for the pconf*/ ret = calc_sizeofselect(num_indices, indices, &pselect); if ( ret != LCP_SUCCESS ) goto free_memory; /* decide whether need to read the pcr_value from the TPM */ if ( pcr_hash_val != NULL ) { /* use the pcr values from the input */ if ( pcr_len != num_indices * SHA1_HASH_LEN ) { log_error("Hash value length is not correct!\n"); ret = LCP_E_INVALID_PARAMETER; return ret; } if ( Trspi_Hash(TSS_HASH_SHA1, pcr_len, (unsigned char *)pcr_hash_val, hpcrhash) != TSS_SUCCESS ) { log_error("Calculate Hash value for Policy Data error!\n"); ret = LCP_E_HASH_ERROR; return ret; } } else { /* get the pcr value from the tpm*/ result = init_tss_context(&hcontext); CHECK_TSS_RETURN_VALUE("init_tss_context", result, ret); /* * Get the TPM object. */ result = Tspi_Context_GetTpmObject(hcontext, &htpm); CHECK_TSS_RETURN_VALUE("Tspi_Context_GetTpmObject", result, ret); /* * Create PCR Composite object */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_PCRS, TSS_PCRS_STRUCT_INFO_SHORT,&hpcrs); CHECK_TSS_RETURN_VALUE("Tspi_Context_CreateObject", result, ret); /* malloc the data buffer for the pcr value*/ pcr_hash_size = num_indices * SHA1_HASH_LEN; pcr_read = (unsigned char *)malloc(pcr_hash_size); if ( pcr_read == NULL ) { log_error("Out of memory!\n"); ret = LCP_E_OUTOFMEMORY; return ret; } /* read the pcr value for each pcr_number in the pselect */ pdata = pcr_read; for (size = 0; size < pselect.sizeOfSelect; size++) { for (index = 0, mask = 1; index < 8; index++, mask = mask << 1) { if ( pselect.pcrSelect[size] & mask ) { idx = index + (size << 3); /* * Read the PCR value. */ if ( (result = Tspi_TPM_PcrRead(htpm, idx, &pcrlen, &pcrval)) != TSS_SUCCESS ) { log_error("Read PCR value error! PCR Index = %d\n", idx); log_error("TSS API returns error.\n"); ret = LCP_E_TSS_ERROR; goto exit; } /* * Load the PCR value read from TPM. */ lcp_loaddata(SHA1_HASH_LEN, &pdata, pcrval); } } } if ( Trspi_Hash(TSS_HASH_SHA1, pcr_hash_size, pcr_read, hpcrhash) != TSS_SUCCESS ) { log_error("Calculate Hash value for Policy Data error!\n"); ret = LCP_E_HASH_ERROR; return ret; } } /* * Caculate return length and allocate memory. */ pcr_info_size = sizeof(pselect.sizeOfSelect) + pselect.sizeOfSelect + 1 + hashlen; if ( (pcr_info = calloc(1, pcr_info_size)) == NULL ) { log_error("Out of memory!\n"); ret = LCP_E_OUTOFMEMORY; goto exit; } /* *Create the PCR_INFO_SHORT structure. */ offset = 0; Trspi_LoadBlob_PCR_SELECTION(&offset, pcr_info, &pselect); Trspi_LoadBlob_BYTE(&offset, locality, pcr_info); Trspi_LoadBlob(&offset, hashlen, pcr_info, hpcrhash); *data = pcr_info; *datalen = pcr_info_size; /* * Execute successfully. */ log_info("Successfully Created PConf data!\n"); if ( pcr_read != NULL ) free(pcr_read); return LCP_SUCCESS; exit: close_tss_context(hcontext); free_memory: if ( ret != LCP_SUCCESS ) { if ( pcr_info != NULL ) free(pcr_info); } if ( pselect.pcrSelect != NULL ) free(pselect.pcrSelect); if ( pcr_read != NULL ) free(pcr_read); return ret; } /* Create the policy list for the policy data * the list format is : * { * uint16_t listtype; * uint8_t list_version; * uint8_t listsize; * union { * LCP_HASH HashList[listsize]; * TPM_PCR_INFO_SHORT PCRInfoList[listsize]; * } * Parameters: * src: the input of the data, type, version * data_length: the length of produced policy list * data: the produced policy list * big_endian: create the big or little endian policy list */ lcp_result_t lcp_create_policy_list(pdlist_src_t src, uint32_t *data_length, unsigned char *data, uint8_t big_endian) { uint8_t ver = src.list_version; uint8_t hashlen = SHA1_HASH_LEN; uint8_t listsize = 0; uint32_t read_offset = 0; unsigned char *pdata = data; unsigned char *pread_data; uint16_t select; uint16_t pcr_length; uint16_t list_type; uint32_t len = sizeof(src.type) + sizeof(src.list_version) + sizeof(listsize) + src.listdata_length; lcp_result_t result = LCP_E_COMD_INTERNAL_ERR; if ( data == NULL ) { log_error("Pass in NULL pointer when creating LCP Policy List!\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } if ( *data_length < len ) { log_error("the data have no enough space\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } switch (src.type) { case LCP_POLDESC_MLE_UNSIGNED: list_type = LCP_POLDESC_MLE_UNSIGNED; /* * allow the 1 more data length in the file */ if ( (src.listdata_length % hashlen > 1) ||(src.listdata_length / hashlen > 255) ) { log_error("the policy list data is not correct\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } listsize = src.listdata_length / hashlen; lcp_loaddata_uint16(list_type, &pdata, big_endian); lcp_loaddata_byte(ver, &pdata); lcp_loaddata_byte(listsize, &pdata); lcp_loaddata(listsize*hashlen, &pdata, src.listdata); *data_length = len - (src.listdata_length % hashlen); break; case LCP_POLDESC_PCONF_UNSIGNED: list_type = LCP_POLDESC_PCONF_UNSIGNED; lcp_loaddata_uint16(list_type, &pdata, big_endian); lcp_loaddata_byte(ver, &pdata); pdata += 1; /* * we will write the list size value * after parse data finished, just skip 1 byte now. * Parse the pconf list first */ pread_data = (unsigned char *)src.listdata; read_offset = 0; listsize =0; for ( ; read_offset < src.listdata_length - 1; listsize++) { /* * we need to read at least 2 byte to get the sizeof select */ lcp_unloaddata_uint16(&select, &pread_data, 1); log_debug("the select of list [%d] is %d\n", listsize, select); pcr_length = select + sizeof(select) + sizeof(TPM_LOCALITY_SELECTION) + SHA1_HASH_LEN; /* check whether the data input is long enough */ if ( (pcr_length + (size_t)(pread_data - src.listdata) -2) > src.listdata_length ) { log_error("the policy list data is not correct\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } /* load the data into the policy list */ lcp_loaddata_uint16(select, &pdata, big_endian); lcp_loaddata(pcr_length - 2, &pdata, pread_data); pread_data += pcr_length - 2; read_offset = (uint32_t)(pread_data - src.listdata); /* check whether the data input is too long*/ if ( (listsize == 255) && ((src.listdata_length - read_offset) > 1) ){ log_error("the policy list data is too big\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } } /* * check whether the input is correct, allow 1 more char */ if ( src.listdata_length - read_offset > 1 ) { log_error("the policy list data is not correct\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } /* * reset the offset value after parsing data finished. */ pdata = data + 3; lcp_loaddata_byte(listsize, &pdata); *data_length = len - (src.listdata_length - read_offset); break; default: log_error("the policy list type is not supported\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } return LCP_SUCCESS; } /* Create the unsigned lcp policy data in little endian format * Parameters: * version: the policy data version * list_number: the count of the policy list * listdata: the plicylist array * data_length: the length of produced policy data * data: the produced policy data */ lcp_result_t lcp_create_unsigned_poldata(uint8_t version, uint8_t list_number, pdlist_src_t *listdata, uint32_t *data_length, unsigned char *data) { unsigned char policylist[MAX_POLICY_LIST_SIZE]; uint32_t policy_list_len = MAX_POLICY_LIST_SIZE; uint32_t i = 0; unsigned char *pdata = data; lcp_result_t ret = LCP_E_COMD_INTERNAL_ERR; uuid_t uuid = LCP_POLICY_DATA_UUID; if ( *data_length < (sizeof(uuid_t) + sizeof(version) + sizeof(list_number)) ) { log_error("the policy data buf is not enough\n"); ret = LCP_E_INVALID_PARAMETER; return ret; } /* begin to produce the header of the policy data */ lcp_loaddata_uint32(uuid.data1, &pdata, 0); lcp_loaddata_uint16(uuid.data2, &pdata, 0); lcp_loaddata_uint16(uuid.data3, &pdata, 0); lcp_loaddata_uint16(uuid.data4, &pdata, 0); lcp_loaddata(6, &pdata, uuid.data5); lcp_loaddata_byte(version, &pdata); lcp_loaddata_byte(list_number, &pdata); for (i = 0; i < list_number; i++ ) { log_debug("create the policy list %d\n", i); policy_list_len = MAX_POLICY_LIST_SIZE; if ( lcp_create_policy_list(*(listdata+i), &policy_list_len, policylist, 0) ) { ret = LCP_E_CREATE_POLLIST; return ret; } /* check whether the return buffer is enough */ if ( ((pdata -data) + policy_list_len) > *data_length ) { log_error("the policy data buf is not enough\n"); ret = LCP_E_INVALID_PARAMETER; return ret; } lcp_loaddata(policy_list_len, &pdata, policylist); } *data_length = (uint32_t)(pdata -data); return LCP_SUCCESS; } /* Create the lcp policy in big endian format * Parameters: * policy: the input infoes for policy, for example, the version, type... * length: the length of the policy data or the mle hash value * policy_dataorhash: the policy data or the mle hash value * data_length: the length of the produced policy * data: the length of the produced policy */ lcp_result_t lcp_create_policy(lcp_policy_t *policy, uint32_t length, const unsigned char *policy_dataorhash, uint32_t *data_length, unsigned char *data) { unsigned char polhash[SHA1_HASH_LEN] = { 0 }; uint32_t policy_length = DATASIZE_POL; unsigned char hashval[SHA1_HASH_LEN]; uint32_t hash_len = SHA1_HASH_LEN; unsigned char *pdata = data; lcp_result_t result = LCP_E_COMD_INTERNAL_ERR; if ( policy->policy_type == LCP_POLTYPE_SIGNED ) { log_error("signed policy is not support\n"); result = LCP_E_INVALID_PARAMETER; return result; } if ( *data_length < policy_length ) { log_error("the data buf is not enough\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } lcp_loaddata_byte(policy->version, &pdata); lcp_loaddata_byte(policy->hash_alg, &pdata); lcp_loaddata_byte(policy->policy_type, &pdata); lcp_loaddata_byte(policy->sinit_revocation_counter, &pdata); lcp_loaddata_uint32(policy->policy_control, &pdata, 1); lcp_loaddata_uint16(policy->reserved[0], &pdata, 1); lcp_loaddata_uint16(policy->reserved[1], &pdata, 1); lcp_loaddata_uint16(policy->reserved[2], &pdata, 1); if ( policy->policy_type == LCP_POLTYPE_UNSIGNED ) { if ( Trspi_Hash(TSS_HASH_SHA1, length, (unsigned char *)policy_dataorhash, hashval) != TSS_SUCCESS ) { log_error("Calculate Hash value for Policy Data error!\n"); result = LCP_E_HASH_ERROR; return result; } lcp_loaddata(hash_len, &pdata, hashval); } else if ( policy->policy_type == LCP_POLTYPE_HASHONLY ) { if ( length != (policy_length - (DATASIZE_POL - SHA1_HASH_LEN)) ) { log_error("the hash length is not correct\n"); result = LCP_E_COMD_INTERNAL_ERR; return result; } lcp_loaddata(length, &pdata, (unsigned char *)policy_dataorhash); } else { lcp_loaddata(SHA1_HASH_LEN, &pdata, polhash); } *data_length = policy_length; return LCP_SUCCESS; } /* get the tpm capibilities * Parameters: * caparea: the capability to get * subcaplen: the length of the sub capablity value * subcap: the sub capolibity to get * outlen: the length of return value * resp_data: the response data */ lcp_result_t lcp_get_tpmcap(uint32_t caparea, uint32_t subcaplen, const unsigned char *subcap, uint32_t *outlen, unsigned char *resp_data) { return lcp_get_tpmcap_auth(NULL, 0, caparea, subcaplen, subcap, outlen, resp_data); } /* get the tpm capibilities * Parameters: * password: ownerauth * psswd_length: length of ownerauth * caparea: the capability to get * subcaplen: the length of the sub capablity value * subcap: the sub capolibity to get * outlen: the length of return value * resp_data: the response data */ lcp_result_t lcp_get_tpmcap_auth(const char *password, uint32_t passwd_length, uint32_t caparea, uint32_t subcaplen, const unsigned char *subcap, uint32_t *outlen, unsigned char *resp_data) { TSS_HCONTEXT hcontext = NULL_HCONTEXT; TSS_HTPM htpm = NULL_HTPM; TSS_HPOLICY hpolicy = NULL_HPOLICY; TSS_RESULT result; uint32_t i = 0; lcp_result_t ret = LCP_E_COMD_INTERNAL_ERR; unsigned char *resp; result = init_tss_context(&hcontext); CHECK_TSS_RETURN_VALUE("init_tss_context", result, ret); if ( password != NULL ) { result = set_tpm_secret(hcontext, &htpm, &hpolicy, password, passwd_length); CHECK_TSS_RETURN_VALUE("set_tpm_secret", result, ret); } else { /* * Get the TPM object. */ result = Tspi_Context_GetTpmObject(hcontext, &htpm); CHECK_TSS_RETURN_VALUE("Tspi_Context_GetTpmObject", result, ret); } result = Tspi_TPM_GetCapability(htpm, caparea, subcaplen, (unsigned char *)subcap, outlen, &resp); CHECK_TSS_RETURN_VALUE("Tspi_TPM_GetCapability", result, ret); log_debug("The response data is:\n" ); for (i = 0; i < *outlen; i++) { log_debug("%02x ", resp[i]); if ( i%16 == 15 ) log_debug("\n"); } log_debug("\n"); memcpy(resp_data, resp, *outlen); ret = LCP_SUCCESS; exit: close_tss_context(hcontext); return ret; } tboot-1.8.0/lcptools/lcptools.h0000644000000000000000000001711212272416301014644 0ustar 00000000000000/* * Copyright 2001 - 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 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 __LCPTOOLS_H__ #define __LCPTOOLS_H__ #define NULL_HCONTEXT 0 #define NULL_HOBJECT 0 #define NULL_HNVSTORE 0 #define NULL_HPCRS NULL_HOBJECT #define NULL_HPOLICY NULL_HOBJECT #define NULL_HTPM NULL_HOBJECT /* * Define the return value of the commands. */ typedef uint16_t lcp_result_t; #define LCP_SUCCESS 0 /* The command execute successful */ #define LCP_E_INVALID_PARAMETER 1 /* The input parameter not match the requirement */ #define LCP_E_NO_INDEXVALUE 2 /* Haven't input index value */ #define LCP_E_NO_DATASIZE 3 /* Haven't input data size value */ #define LCP_E_TSS_ERROR 4 /* TSS API revoke failed */ #define LCP_E_NV_AREA_EXIST 5 /* NV area reference have been defined, can't be defined again */ #define LCP_E_TPM_BADINDEX 6 /* Index value is invalid */ #define LCP_E_TPM_BAD_DATASIZE 7 /* The data size is invalid */ #define LCP_E_TPM_MAXNVWRITES 8 /* Exceed the max write time of NV */ #define LCP_E_NO_AUTH 9 /* Haven't input authentication value */ #define LCP_E_NV_AREA_NOT_EXIST 10 /* NV area reference haven't been defined before, can't be released */ #define LCP_E_TPM_AREA_LOCKED 11 /* The NV area is locked and not writeable */ #define LCP_E_GETCAP_REP_ERROR 12 /* Get capability returns incorrect response */ #define LCP_E_NO_PER_VALUE 13 /* Haven't input permission value */ #define LCP_E_INVALID_HANDLER 14 /* Invalid handler is returned */ #define LCP_E_AUTH_CONFLICT 15 /* Authentication method conflict */ #define LCP_E_AUTH_FAIL 16 /* Authentication failed */ #define LCP_E_OWNER_SET 17 /* TSS return error */ #define LCP_E_TPM_WRONGPCRVALUE 18 /* TSS return error */ #define LCP_E_INVALID_STRUCTURE 19 /* TSS return error */ #define LCP_E_NOWRITE 20 /* TSS return error */ #define LCP_E_TPM_BAD_LOCALITY 21 /* TSS return error */ #define LCP_E_TPM_BAD_PRESENCE 22 /* TSS return error */ #define LCP_E_TPM_DISABLED_CMD 23 /* TSS return error */ #define LCP_E_TPM_NOSPACE 24 /* TSS return error */ #define LCP_E_TPM_NOT_FULLWRITE 25 /* TSS return error */ #define LCP_E_NO_SUCH_PARAMETER 26 /* Can't find such kind of parameter */ #define LCP_E_CREATE_POLLIST 27 /* Create Polict List error */ #define LCP_E_OUTOFMEMORY 28 /* Failed memory assign */ #define LCP_E_HASH_ERROR 29 /* Failed when hash */ #define LCP_E_NO_INPUTPARA 30 /* No parameter has been input */ #define LCP_E_COMD_INTERNAL_ERR 31 /* Other err when run the command */ #define SHA1_HASH_LEN 20 #define SHA256_HASH_LEN 32 typedef struct { uint32_t index; uint32_t permission; uint32_t size; uint8_t r_loc; uint8_t w_loc; } in_nv_definespace_t; typedef struct { uint8_t algorithm; uint8_t list_version; uint16_t type; uint32_t listdata_length; unsigned char *listdata; } pdlist_src_t; lcp_result_t lcp_define_index(in_nv_definespace_t *p_in_defspace, const char *auth, uint32_t auth_length, const char *passwd, uint32_t passwd_length, const unsigned char *read_srtm, const unsigned char *write_srtm); lcp_result_t lcp_release_index(uint32_t index_value, const char *passwd, uint32_t passwd_length); lcp_result_t lcp_read_index(uint32_t index_value, const char* password, uint32_t pass_length, uint32_t read_offset, uint32_t read_length, uint32_t* datalength, unsigned char* data); lcp_result_t lcp_write_index(uint32_t index_value, const char* password, uint32_t passwd_length, uint32_t write_offset, uint32_t fleng, const unsigned char* policydata); lcp_result_t lcp_create_pconf(uint32_t num_indices, uint32_t* indices, uint32_t pcr_len, const unsigned char* pcr_hash_val, unsigned char locality, uint32_t* dataLen, unsigned char** srtmdata); lcp_result_t lcp_create_policy_list(pdlist_src_t policylist_src, uint32_t* policy_list_length, unsigned char* policy_list, uint8_t big_endian); lcp_result_t lcp_create_unsigned_poldata(uint8_t policydata_version, uint8_t list_number, pdlist_src_t * listdata, uint32_t* data_length, unsigned char* data); lcp_result_t lcp_create_policy(lcp_policy_t *policy, uint32_t length, const unsigned char* policy_dataorhash, uint32_t* data_length, unsigned char* data); lcp_result_t lcp_get_tpmcap(uint32_t caparea, uint32_t subcaplen, const unsigned char *subcap, uint32_t *outlen, unsigned char *respdata); lcp_result_t lcp_get_tpmcap_auth(const char *password, uint32_t passwd_length, uint32_t caparea, uint32_t subcaplen, const unsigned char *subcap, uint32_t *outlen, unsigned char *respdata); #endif tboot-1.8.0/lcptools/lcptools2.txt0000644000000000000000000000505212272416301015316 0ustar 00000000000000These are some example instructions for creating an Intel(R) TXT Launch Control Policy (LCP) using the new LCP tools (i.e. for platforms produced after 2008). These steps assume that all referenced binaries have already been built and paths are relative to the tboot/lcptools/ directory: Create policy element(s): ======================== Create an MLE element: --------------------- 1. lcp_mlehash -c "the command line for tboot from grub.conf" /boot/tboot.gz > mle_hash 2. lcp_crtpolelt --create --type mle --ctrl 0x00 --minver 17 --out mle.elt mle_hash Create a PCONF element: ---------------------- 1. cat /sys/devices/platform/tpm_tis/pcrs |grep -e PCR-00 -e PCR-01 > pcrs 2. lcp_crtpolelt --create --type pconf --out pconf.elt pcrs Create an SBIOS element: ----------------------- 1. Create hash file containing BIOS hash(es), e.g. named sbios_hash 2. lcp_crtpolelt --create --type sbios --out sbios.elt sbios_hash Create a CUSTOM element: ----------------------- 1. Create or determine the UUID that will identify this data format (e.g. using 'uuidgen') 2. Create the data the will be placed in this element. E.g. the policy file from tb_polgen. 2. lcp_crtpolelt --create --type custom --out custom.elt --uuid Create policy list(s): ===================== Combine the elements into an unsigned list: ------------------------------------------ 1. lcp_crtpollist --create --out list_unsig.lst mle.elt pconf.elt The two blocks below are intended to be mutually exclusive. The openssl signing is supported for cases where the signing environment is separate from the policy creation environment and the software allowed to run there is strictly controlled and already supports openssl. Use lcp_crtpollist to sign the list: ----------------------------------- 1. openssl genrsa -out privkey.pem 2048 2. openssl rsa -pubout -in privkey.pem -out pubkey.pem 3. cp list_unsig.lst list_sig.lst 4. lcp_crtpollist --sign --pub pubkey.pem --priv privkey.pem --out list_sig.lst Use openssl to sign the list: ---------------------------- 1. openssl rsa -pubout -in privkey.pem -out pubkey.pem 2. cp list_unsig.lst list_sig.lst 3. lcp_crtpollist --sign --pub pubkey.pem --nosig --out list_sig.lst 4. openssl genrsa -out privkey.pem 2048 5. openssl dgst -sha1 -sign privkey.pem -out list.sig list_sig.lst 6. lcp_crtpollist --addsig --sig list.sig --out list_sig.lst Create policy and policy data files: =================================== 1. lcp_crtpol2 --create --type list --pol list.pol --data list.data list_{unsig,sig}.lst tboot-1.8.0/lcptools/lcputils.c0000644000000000000000000004321512272416301014642 0ustar 00000000000000/* * Copyright 2001 - 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 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. */ /* * lcputils.c * * This file implements all common functions used by the commands * and key functions. * */ #include #include #include #include #include #include #include #define PRINT printf #include "../include/uuid.h" #include "../include/lcp.h" #include "lcptools.h" #include "lcputils.h" static const char *ret_info[] = { NULL, /* 0-LCP_SUCCESS, Each command will has its own success message.*/ "Incorrect parameter input.", /* 1-LCP_E_INVALID_PARAMETER */ "Please input the index value", /* 2-LCP_E_NO_INDEXVALUE */ "Please input the data size to be defined", /* 3-LCP_E_NO_DATASIZE */ "TSS API failed", /* 4-LCP_E_TSS_ERROR */ "Index has already been defined.", /* 5-LCP_E_NV_AREA_EXIST */ "The index is incorrect or wrong "\ "permission value.", /* 6-LCP_E_TPM_BADINDEX */ "The size of the data parameter is bad or "\ "inconsistent with the referenced key.",/* 7-LCP_E_TPM_BAD_DATASIZE */ "The maximum number of NV writes without an owner has been reached.", /* 8-LCP_E_TPM_MAXNVWRITES */ "Please input authentication value.", /* 9-LCP_E_NO_AUTH */ "Index does not exist.", /* 10-LCP_E_NV_AREA_NOT_EXIST*/ "TPM_AREA_LOCKED. The index has been locked.", /* 11-LCP_E_TPM_AREA_LOCKED */ "Incorrect response when getting capability.", /* 12-LCP_E_GETCAP_REP_ERROR */ "Please input the permission value for the index to be defined!", /* 13-LCP_E_NO_PER_VALUE */ "Invalid handler is returned.", /* 14-LCP_E_INVALID_HANDLER */ "Authentication method conflict.", /* 15-LCP_E_AUTH_CONFLICT */ "Authentication failed. Password or authencation value not match", /* 16-LCP_E_AUTH_FAIL */ "TPM owner set error!", /* 17-LCP_E_OWNER_SET */ "Wrong PCR value!", /* 18-LCP_E_TPM_WRONGPCRVALUE*/ "Invalid structure!", /* 19-LCP_E_INVALID_STRUCTURE*/ "TPM No Write error!", /* 20-LCP_E_NOWRITE */ "Bad locality error!", /* 21-LCP_E_TPM_BAD_LOCALITY */ "Bad presence error!", /* 22-LCP_E_TPM_BAD_PRESENCE */ "TPM disabled command error!", /* 23-LCP_E_TPM_DISABLED_CMD */ "TPM no space error!", /* 24-LCP_E_TPM_NOSPACE */ "TPM not full write error!", /* 25-LCP_E_TPM_NOT_FULLWRITE*/ "Incorrect parameter input.", /* 26-LCP_E_NO_SUCH_PARAMETER*/ "Creat policy_list error", /* 27-LCP_E_CREATE_POLLIST */ "Failed assign memory!", /* 28-LCP_E_OUTOFMEMORY */ "Hash failed!", /* 29-LCP_E_HASH_ERROR */ "Haven't input any parameter, please use -h for help", /* 30-LCP_E_NO_INPUTPARA */ "Internal error when executing the command",/* 31-LCP_E_COMD_INTERNAL_ERR*/ NULL }; /* * Parse the input param and return the corresponding option value * If the parameter is not correct, it will return -1 */ uint32_t parse_input_option(param_option_t *table, const char *arg) { param_option_t *p = table; uint32_t ret_value = -1; while (p && p->param){ if ( strcasecmp(arg, p->param) == 0 ) { ret_value = p->option; break; } p++; } return ret_value; } /* * Convert the string input into number. * This function can support both decimalist and hex */ int strtonum(const char *in_para, unsigned int *num_out) { int ret_value = -1; char* endptr; uint64_t test_value; if( in_para == NULL || num_out == NULL ) return -1; errno = 0; *num_out = (unsigned int)strtoul(in_para, &endptr, 0); if ( (*endptr == '\0') && (*in_para != '\0') && (errno == 0) ){ test_value = (uint64_t)strtoull(in_para, &endptr, 0); if ( test_value == (uint64_t)(*num_out) ) ret_value = 0; } return ret_value; } const char * bool_to_str(int b) { return b ? "TRUE" : "FALSE"; } void print_help(const char *usage_str, const char * option_string[]) { uint16_t i = 0; if ( usage_str == NULL || option_string == NULL ) return; printf("\nUsage: %s\n", usage_str); for (; option_string[i] != 0; i++) printf("%s", option_string[i]); } void print_error(lcp_result_t ret_value) { log_error("\t%s\n", ret_info[ret_value]); } /* * Convert TSS error codes to our defined error codes. */ lcp_result_t convert_error(TSS_RESULT result) { lcp_result_t ret; switch (result & 0xfff) { case TSS_SUCCESS: ret = LCP_SUCCESS; break; case TSS_E_INVALID_HANDLE: ret = LCP_E_INVALID_HANDLER; break; case TSS_E_NV_AREA_EXIST: ret = LCP_E_NV_AREA_EXIST; break; case TSS_E_NV_AREA_NOT_EXIST: ret = LCP_E_NV_AREA_NOT_EXIST; break; case TSS_E_BAD_PARAMETER: ret = LCP_E_INVALID_PARAMETER; break; case TSS_E_INTERNAL_ERROR: ret = LCP_E_COMD_INTERNAL_ERR; break; case TPM_E_BADINDEX: ret = LCP_E_TPM_BADINDEX; break; case TPM_E_AUTH_CONFLICT: ret = LCP_E_AUTH_CONFLICT; break; case TPM_E_AUTHFAIL: ret = LCP_E_AUTH_FAIL; break; case TPM_E_OWNER_SET: ret = LCP_E_OWNER_SET; break; case TPM_E_BAD_DATASIZE: ret = LCP_E_TPM_BAD_DATASIZE; break; case TPM_E_MAXNVWRITES: ret = LCP_E_TPM_MAXNVWRITES; break; case TPM_E_INVALID_STRUCTURE: ret = LCP_E_INVALID_STRUCTURE; break; case TPM_E_PER_NOWRITE: ret = LCP_E_NOWRITE; break; case TPM_E_AREA_LOCKED: ret = LCP_E_TPM_AREA_LOCKED; break; case TPM_E_BAD_LOCALITY: ret = LCP_E_TPM_BAD_LOCALITY; break; case TPM_E_BAD_PRESENCE: ret = LCP_E_TPM_BAD_PRESENCE; break; case TPM_E_DISABLED_CMD: ret = LCP_E_TPM_DISABLED_CMD; break; case TPM_E_NOSPACE: ret = LCP_E_TPM_NOSPACE; break; case TPM_E_NOT_FULLWRITE: ret = LCP_E_TPM_NOT_FULLWRITE; break; case TPM_E_WRONGPCRVAL: ret = LCP_E_TPM_WRONGPCRVALUE; break; default: ret = LCP_E_TSS_ERROR; } return ret; } void print_hexmsg(const char *header_msg, int datalength, const unsigned char *data) { int i; log_info("%s", header_msg); for (i = 0; i < datalength; i++) { log_info("%02x ", *(data + i)); if ( i % 16 == 15 ) log_info("\n"); } log_info("\n"); } /* split the input string in the format: num1,num2,...,numN * into the numeric array = {num1, num2, ... , numN} */ void str_split(char *str_in, uint32_t ints[], unsigned int *nr_ints) { unsigned int nr = 0; char *str = NULL; while ( true ) { str = strsep(&str_in, ","); if ( str == NULL || nr == *nr_ints ) break; ints[nr++] = strtoul(str, NULL, 0); } if ( nr == *nr_ints && str != NULL ) log_error("Error: too many items in list\n"); *nr_ints = nr; } uint16_t lcp_decode_uint16(const unsigned char *in, uint8_t big_endian) { uint16_t temp = 0; if ( in == NULL ) return 0; if ( big_endian ) { temp = (in[1] & 0xFF); temp |= (in[0] << 8); } else { temp = (in[0] & 0xFF); temp |= (in[1] << 8); } return temp; } void lcp_uint32toarray(uint32_t i, unsigned char *out, uint8_t big_endian) { if ( out == NULL ) return; if ( big_endian ) { out[0] = (unsigned char) ((i >> 24) & 0xFF); out[1] = (unsigned char) ((i >> 16) & 0xFF); out[2] = (unsigned char) ((i >> 8) & 0xFF); out[3] = (unsigned char) (i & 0xFF); } else { out[3] = (unsigned char) ((i >> 24) & 0xFF); out[2] = (unsigned char) ((i >> 16) & 0xFF); out[1] = (unsigned char) ((i >> 8) & 0xFF); out[0] = (unsigned char) (i & 0xFF); } } void lcp_uint16toarray(uint16_t i, unsigned char *out, uint8_t big_endian) { if ( out == NULL ) return; if ( big_endian ) { out[0] = (unsigned char) ((i >> 8) & 0xFF); out[1] = (unsigned char) (i & 0xFF); } else { out[1] = (unsigned char) ((i >> 8) & 0xFF); out[0] = (unsigned char) (i & 0xFF); } } uint32_t lcp_decode_uint32(const unsigned char *y, uint8_t big_endian) { uint32_t x = 0; if ( y == NULL ) return 0; if ( big_endian ) { x = y[0]; x = ((x << 8) | (y[1] & 0xFF)); x = ((x << 8) | (y[2] & 0xFF)); x = ((x << 8) | (y[3] & 0xFF)); } else { x = y[3]; x = ((x << 8) | (y[2] & 0xFF)); x = ((x << 8) | (y[1] & 0xFF)); x = ((x << 8) | (y[0] & 0xFF)); } return x; } void lcp_loaddata_uint32(uint32_t in, unsigned char **blob, uint8_t big_endian) { if ( blob == NULL ) return; if ( *blob != NULL ) lcp_uint32toarray(in, *blob, big_endian); *blob += sizeof(in); } void lcp_loaddata_uint16(uint16_t in, unsigned char **blob, uint8_t big_endian) { if ( blob == NULL ) return; if ( *blob != NULL ) lcp_uint16toarray(in, *blob, big_endian); *blob += sizeof(in); } void lcp_unloaddata_uint32(uint32_t *out, unsigned char **blob, uint8_t big_endian) { if ( blob == NULL || out == NULL ) return; *out = lcp_decode_uint32(*blob, big_endian); *blob += sizeof(*out); } void lcp_unloaddata_uint16(uint16_t *out, unsigned char **blob, uint8_t big_endian) { if ( blob == NULL || out == NULL ) return; *out = lcp_decode_uint16(*blob, big_endian); *blob += sizeof(*out); } void lcp_loaddata_byte(unsigned char data, unsigned char **blob) { if ( blob == NULL ) return; if ( *blob != NULL ) **blob = data; (*blob)++; } void lcp_unloaddata_byte(unsigned char *dataout, unsigned char **blob) { if ( blob == NULL || dataout == NULL ) return; *dataout = **blob; (*blob)++; } void lcp_loaddata(uint32_t size, unsigned char **container, unsigned char *object) { if ( container == NULL || object == NULL ) return; if ( *container ) memcpy(*container, object, size); (*container) += size; } void lcp_unloaddata(uint32_t size, unsigned char **container, unsigned char *object) { if ( *container == NULL || object == NULL ) return; memcpy(object, *container, size); (*container) += size; } /* init the context in the TSS */ TSS_RESULT init_tss_context(TSS_HCONTEXT *hcontext) { TSS_RESULT result; result = Tspi_Context_Create(hcontext); if ( (result) != TSS_SUCCESS ) return result; result = Tspi_Context_Connect(*hcontext, NULL); return result; } /* close the TSS context */ void close_tss_context(TSS_HCONTEXT hcontext) { if ( hcontext != NULL_HCONTEXT ) { Tspi_Context_FreeMemory(hcontext, NULL); Tspi_Context_Close(hcontext); } } /* Set the password to the tpm object of the tss context */ TSS_RESULT set_tpm_secret(TSS_HCONTEXT hcontext, TSS_HTPM *htpm, TSS_HPOLICY *hpolicy, const char *passwd, uint32_t passwd_length) { TSS_RESULT result; /* * Get TPM object */ result = Tspi_Context_GetTpmObject(hcontext, htpm); if ( result != TSS_SUCCESS ) return result; result = Tspi_GetPolicyObject(*htpm, TSS_POLICY_USAGE, hpolicy); if ( result != TSS_SUCCESS ) return result; /* * Set password */ result = Tspi_Policy_SetSecret(*hpolicy, TSS_SECRET_MODE_PLAIN, passwd_length, (unsigned char *)passwd); return result; } /* Create the NV policy object and assign it to the NV object */ TSS_RESULT set_nv_secret(TSS_HCONTEXT hcontext, TSS_HNVSTORE hnvstore, TSS_HPOLICY *hpolobj, const char *auth, uint32_t auth_len) { TSS_RESULT result; /* * Create policy object for the NV object */ result = Tspi_Context_CreateObject(hcontext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, hpolobj); if ( result != TSS_SUCCESS ) return result; /* * Set password */ result = Tspi_Policy_SetSecret(*hpolobj, TSS_SECRET_MODE_PLAIN, auth_len, (unsigned char *)auth); if ( result != TSS_SUCCESS ) return result; /* * Set password */ result = Tspi_Policy_AssignToObject(*hpolobj, hnvstore); return result; } /* calculate the size of select for the pcr selection */ lcp_result_t calc_sizeofselect(uint32_t num_indices, uint32_t *indices, TPM_PCR_SELECTION *pselect) { uint32_t i; uint32_t idx; uint16_t bytes_to_hold; lcp_result_t ret; idx = indices[0]; bytes_to_hold = (idx / 8) + 1; log_debug("bytes to hold is %d.\n", bytes_to_hold); /* * Create selection index first. */ if ( (pselect->pcrSelect = malloc(bytes_to_hold)) == NULL ) { ret = LCP_E_OUTOFMEMORY; return ret; } pselect->sizeOfSelect = bytes_to_hold; memset(pselect->pcrSelect, 0, bytes_to_hold); /* * set the bit in the selection structure */ pselect->pcrSelect[idx / 8] |= (1 << (idx % 8)); for (i = 1; i < num_indices; i++) { idx = indices[i]; bytes_to_hold = (idx / 8) + 1; log_debug("bytes to hold is %d.\n", bytes_to_hold); log_debug("size of select is %d.\n", pselect->sizeOfSelect); if ( pselect->sizeOfSelect < bytes_to_hold ) { if ( (pselect->pcrSelect = realloc(pselect->pcrSelect, bytes_to_hold)) == NULL ) { ret = LCP_E_OUTOFMEMORY; return ret; } /* * set the newly allocated bytes to 0 */ memset(&pselect->pcrSelect[pselect->sizeOfSelect], 0, bytes_to_hold - pselect->sizeOfSelect); pselect->sizeOfSelect = bytes_to_hold; } pselect->pcrSelect[idx / 8] |= (1 << (idx % 8)); } return LCP_SUCCESS; } void print_locality(unsigned char loc) { char s[32] = ""; if ( loc & ~0x1f ) sprintf(s, "unknown (%x)", (unsigned int)loc); else { if ( !(loc & 0x1f) ) strcat(s, "--, "); if ( loc & TPM_LOC_ZERO ) strcat(s, "0, "); if ( loc & TPM_LOC_ONE ) strcat(s, "1, "); if ( loc & TPM_LOC_TWO ) strcat(s, "2, "); if ( loc & TPM_LOC_THREE ) strcat(s, "3, "); if ( loc & TPM_LOC_FOUR ) strcat(s, "4, "); /* remove trailing ", " */ s[strlen(s) - 2] = '\0'; } log_info("%s", s); } void print_permissions(UINT32 perms, const char *prefix) { if ( perms == 0 ) log_info("%s --\n", prefix); if ( perms & TPM_NV_PER_READ_STCLEAR ) log_info("%s TPM_NV_PER_READ_STCLEAR\n", prefix); if ( perms & TPM_NV_PER_AUTHREAD ) log_info("%s TPM_NV_PER_AUTHREAD\n", prefix); if ( perms & TPM_NV_PER_OWNERREAD ) log_info("%s TPM_NV_PER_OWNERREAD\n", prefix); if ( perms & TPM_NV_PER_PPREAD ) log_info("%s TPM_NV_PER_PPREAD\n", prefix); if ( perms & TPM_NV_PER_GLOBALLOCK ) log_info("%s TPM_NV_PER_GLOBALLOCK\n", prefix); if ( perms & TPM_NV_PER_WRITE_STCLEAR ) log_info("%s TPM_NV_PER_WRITE_STCLEAR\n", prefix); if ( perms & TPM_NV_PER_WRITEDEFINE ) log_info("%s TPM_NV_PER_WRITEDEFINE\n", prefix); if ( perms & TPM_NV_PER_WRITEALL ) log_info("%s TPM_NV_PER_WRITEALL\n", prefix); if ( perms & TPM_NV_PER_AUTHWRITE ) log_info("%s TPM_NV_PER_AUTHWRITE\n", prefix); if ( perms & TPM_NV_PER_OWNERWRITE ) log_info("%s TPM_NV_PER_OWNERWRITE\n", prefix); if ( perms & TPM_NV_PER_PPWRITE ) log_info("%s TPM_NV_PER_PPWRITE\n", prefix); } tboot-1.8.0/lcptools/lcputils.h0000644000000000000000000001210612272416301014642 0ustar 00000000000000/* * Copyright 2001 - 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 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 __LCPUTILS_H__ #define __LCPUTILS_H__ /* * Log message functions */ #define log_message(dest, fmt, ...) fprintf(dest, fmt, ## __VA_ARGS__) /* * Error logging */ #define log_error(fmt, ...) log_message(stderr, fmt, ##__VA_ARGS__) /* * Info Logging */ #define log_info(fmt, ...) log_message(stdout, fmt, ##__VA_ARGS__) #define LCP_DEBUG 1 #ifdef LCP_DEBUG #define log_debug(fmt, ...) log_message(stdout, fmt, ##__VA_ARGS__) #else #define log_debug(fmt, ...) #endif #define CHECK_TSS_RETURN_VALUE(api_name, result, ret) \ do { if ((result) != TSS_SUCCESS) { \ log_error("%s failed: %s (0x08%x)\n", (api_name), \ Trspi_Error_String((result)), \ (result)); \ (ret) = LCP_E_TSS_ERROR; \ goto exit; \ } \ }while (0) typedef struct { const char *param; uint32_t option; } param_option_t; uint32_t parse_input_option(param_option_t *table, const char *arg); int strtonum(const char *in_para, unsigned int *num_out); const char *bool_to_str(int b); void print_help(const char *usage_str, const char *option_string[]); void print_error(lcp_result_t ret_value); lcp_result_t convert_error(TSS_RESULT result); void print_hexmsg(const char *header_msg, int datalength, const unsigned char *data); uint16_t lcp_decode_uint16(const unsigned char *in, uint8_t big_endian); void lcp_uint32toarray(uint32_t i, unsigned char *out, uint8_t big_endian); void lcp_uint16toarray(uint16_t i, unsigned char *out, uint8_t big_endian); uint32_t lcp_decode_uint32(const unsigned char *y, uint8_t big_endian); void lcp_loaddata_uint32(uint32_t in, unsigned char **blob, uint8_t big_endian); void lcp_loaddata_uint16(uint16_t in, unsigned char **blob, uint8_t big_endian); void lcp_unloaddata_uint32(uint32_t * out, unsigned char **blob, uint8_t big_endian); void lcp_unloaddata_uint16(uint16_t *out, unsigned char **blob, uint8_t big_endian); void lcp_loaddata_byte(unsigned char data, unsigned char **blob); void lcp_unloaddata_byte(unsigned char *dataout, unsigned char **blob); void lcp_loaddata(uint32_t size, unsigned char **container, unsigned char *object); void lcp_unloaddata(uint32_t size, unsigned char **container, unsigned char *object); TSS_RESULT init_tss_context(TSS_HCONTEXT *hcontext); void close_tss_context(TSS_HCONTEXT hcontext); TSS_RESULT set_tpm_secret(TSS_HCONTEXT hcontext, TSS_HTPM *htpm, TSS_HPOLICY *hpolicy, const char *passwd, uint32_t passwd_length); TSS_RESULT set_nv_secret(TSS_HCONTEXT hcontext, TSS_HNVSTORE hnvstore, TSS_HPOLICY *hpolobj, const char *auth, uint32_t auth_len); lcp_result_t calc_sizeofselect(uint32_t num_indices, uint32_t *indices, TPM_PCR_SELECTION *pselect); void print_locality(unsigned char loc); void print_permissions(UINT32 perms, const char *prefix); void str_split(char *str_in, uint32_t ints[], unsigned int *number); #endif tboot-1.8.0/lcptools/lcputils2.c0000644000000000000000000002216112272416301014721 0ustar 00000000000000/* * lcputils2.c: misc. LCP helper fns * * Copyright (c) 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "polelt_plugin.h" #include "lcputils2.h" void ERROR(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } void LOG(const char *fmt, ...) { va_list ap; if ( verbose ) { va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } } void DISPLAY(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); } size_t strlcpy(char *dst, const char *src, size_t siz) { strncpy(dst, src, siz-1); if ( siz != 0 ) *(dst + siz-1) = '\0'; return strlen(src); } void print_hex(const char *prefix, const void *data, size_t n) { #define NUM_CHARS_PER_LINE 20 unsigned int i = 0; while ( i < n ) { if ( i % NUM_CHARS_PER_LINE == 0 && prefix != NULL ) DISPLAY("%s", prefix); DISPLAY("%02x ", *(uint8_t *)data++); i++; if ( i % NUM_CHARS_PER_LINE == 0 ) DISPLAY("\n"); } if ( i % NUM_CHARS_PER_LINE != 0 ) DISPLAY("\n"); } void parse_comma_sep_ints(char *s, uint16_t ints[], unsigned int *nr_ints) { unsigned int nr = 0; while ( true ) { char *str = strsep(&s, ","); if ( str == NULL || nr == *nr_ints ) break; ints[nr++] = strtoul(str, NULL, 0); } if ( nr == *nr_ints ) ERROR("Error: too many items in list\n"); *nr_ints = nr; return; } void *read_file(const char *file, size_t *length, bool fail_ok) { FILE *fp = fopen(file, "rb"); if ( fp == NULL ) { if ( !fail_ok ) ERROR("Error: failed to open file %s: %s\n", file, strerror(errno)); return NULL; } /* find size */ fseek(fp, 0, SEEK_END); long len = ftell(fp); rewind(fp); void *data = malloc(len); if ( data == NULL ) { ERROR("Error: failed to allocate %d bytes memory\n", len); fclose(fp); return NULL; } if ( fread(data, len, 1, fp) != 1 ) { ERROR("Error: reading file %s\n", file); free(data); fclose(fp); return NULL; } fclose(fp); if ( length != NULL ) *length = len; return data; } bool write_file(const char *file, const void *data, size_t size) { FILE *fp = fopen(file, "wb"); if ( fp == NULL ) { ERROR("Error: failed to open file %s for writing: %s\n", file, strerror(errno)); return false; } if ( fwrite(data, size, 1, fp) != 1 ) { ERROR("Error: writing file %s\n", file); fclose(fp); return false; } fclose(fp); return true; } bool parse_line_hashes(const char *line, tb_hash_t *hash) { /* skip any leading whitespace */ while ( *line != '\0' && isspace(*line) ) line++; /* rest of line is hex of hash */ unsigned int i = 0; while ( *line != '\0' && *line != '\n' ) { char *next; hash->sha1[i++] = (uint8_t)strtoul(line, &next, 16); if ( next == line ) /* done */ break; line = next; /* spaces at end cause strtoul() to interpret as 0, so skip them */ while ( *line != '\0' && !isxdigit(*line) ) line++; } if ( i != get_hash_size(TB_HALG_SHA1) ) { ERROR("Error: incorrect number of chars for hash\n"); return false; } return true; } bool parse_file(const char *filename, bool (*parse_line)(const char *line)) { if ( filename == NULL || parse_line == NULL ) return false; LOG("reading hashes file %s...\n", filename); FILE *fp = fopen(filename, "r"); if ( fp == NULL ) { ERROR("Error: failed to open file %s (%s)\n", filename, strerror(errno)); return false; } static char line[128]; while ( true ) { char *s = fgets(line, sizeof(line), fp); if ( s == NULL ) { fclose(fp); return true; } LOG("read line: %s", line); if ( !(*parse_line)(line) ) { fclose(fp); return false; } } fclose(fp); return false; } const char *hash_alg_to_str(uint8_t alg) { static const char *alg_str[] = { "LCP_POLHALG_SHA1" }; static char buf[32]; if ( alg > ARRAY_SIZE(alg_str) ) { snprintf(buf, sizeof(buf), "unknown (%u)", alg); return buf; } else return alg_str[alg]; } size_t get_lcp_hash_size(uint8_t hash_alg) { if ( hash_alg != LCP_POLHALG_SHA1 ) return 0; return SHA1_LENGTH; } bool verify_signature(const uint8_t *data, size_t data_size, const uint8_t *pubkey, size_t pubkey_size, const uint8_t *sig, bool is_sig_little_endian) { unsigned int i; /* policy key is little-endian and openssl wants big-endian, so reverse */ uint8_t key[pubkey_size]; for ( i = 0; i < pubkey_size; i++ ) key[i] = *(pubkey + (pubkey_size - i - 1)); /* create RSA public key struct */ RSA *rsa_pubkey = RSA_new(); if ( rsa_pubkey == NULL ) { ERROR("Error: failed to allocate key\n"); return false; } rsa_pubkey->n = BN_bin2bn(key, pubkey_size, NULL); /* uses fixed exponent (LCP_SIG_EXPONENT) */ char exp[32]; snprintf(exp, sizeof(exp), "%u", LCP_SIG_EXPONENT); rsa_pubkey->e = NULL; BN_dec2bn(&rsa_pubkey->e, exp); rsa_pubkey->d = rsa_pubkey->p = rsa_pubkey->q = NULL; /* first create digest of data */ tb_hash_t digest; if ( !hash_buffer(data, data_size, &digest, TB_HALG_SHA1) ) { ERROR("Error: failed to hash list\n"); RSA_free(rsa_pubkey); return false; } if ( verbose ) { LOG("digest: "); print_hex("", &digest, get_hash_size(TB_HALG_SHA1)); } /* sigblock is little-endian and openssl wants big-endian, so reverse */ uint8_t sigblock[pubkey_size]; if ( is_sig_little_endian ) { for ( i = 0; i < pubkey_size; i++ ) sigblock[i] = *(sig + (pubkey_size - i - 1)); sig = sigblock; } if ( verbose ) { /* raw decryption of sigblock */ uint8_t unsig[pubkey_size]; if ( RSA_public_decrypt(pubkey_size, sig, unsig, rsa_pubkey, RSA_NO_PADDING) == -1 ) { ERR_load_crypto_strings(); ERROR("Error: failed to decrypt sig: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); } else { LOG("decrypted sig:\n"); print_hex("", unsig, pubkey_size); } } /* verify digest */ if ( !RSA_verify(NID_sha1, (const unsigned char *)&digest, get_hash_size(TB_HALG_SHA1), (uint8_t *)sig, pubkey_size, rsa_pubkey) ) { ERR_load_crypto_strings(); ERROR("Error: failed to verify list: %s\n", ERR_error_string(ERR_get_error(), NULL)); ERR_free_strings(); RSA_free(rsa_pubkey); return false; } RSA_free(rsa_pubkey); return true; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/lcputils2.h0000644000000000000000000000574412272416301014736 0ustar 00000000000000/* * lcputils2.h: LCP utility fns * * Copyright (c) 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 __LCPUTILS2_H__ #define __LCPUTILS2_H__ #define MAJOR_VER(v) ((v) >> 8) #define MINOR_VER(v) ((v) & 0xff) #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #define MAX_PATH 256 extern bool verbose; extern void ERROR(const char *fmt, ...); extern void LOG(const char *fmt, ...); extern void DISPLAY(const char *fmt, ...); extern size_t strlcpy(char *dst, const char *src, size_t siz); extern void print_hex(const char *prefix, const void *data, size_t n); extern void parse_comma_sep_ints(char *s, uint16_t ints[], unsigned int *nr_ints); extern void *read_file(const char *file, size_t *length, bool fail_ok); extern bool write_file(const char *file, const void *data, size_t size); extern bool parse_line_hashes(const char *line, tb_hash_t *hash); extern bool parse_file(const char *filename, bool (*parse_line)(const char *line)); extern const char *hash_alg_to_str(uint8_t alg); extern size_t get_lcp_hash_size(uint8_t hash_alg); extern bool verify_signature(const uint8_t *data, size_t data_size, const uint8_t *pubkey, size_t pubkey_size, const uint8_t *sig, bool is_sig_little_endian); #endif /* __LCPUTILS2_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/lock.c0000644000000000000000000001062012272416301013725 0ustar 00000000000000/* * Copyright 2001 - 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 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. */ /* * nvlock.c * * Command: tpmnv_lock. * * This command can lock the TPM NV Storage. * */ #include #include #include #include #include #include #define PRINT printf #include "../include/uuid.h" #include "../include/lcp.h" #include "lcptools.h" #include "lcputils.h" static int force = 0; static int help_input = 0; static const char *short_option = "hf"; static const char *usage_string = "tpmnv_lock [-f] [-h]"; static const char * option_strings[] ={ "-f force to lock.\n", "-h help. Will print out this help message.\n" ,0 }; /* function: parse_cmdline * description: parse the input of commandline */ static int parse_cmdline(int argc, const char * argv[]) { int c; while (((c = getopt(argc, (char ** const)argv, short_option)) != -1)) switch (c){ case 'f': force = 1; break; case 'h': help_input = 1; break; default: return LCP_E_NO_SUCH_PARAMETER; } if ( optind < argc ) return LCP_E_INVALID_PARAMETER; return LCP_SUCCESS; } int main (int argc, char *argv[]) { char confirm_lock[4] = {0}; char c; in_nv_definespace_t in_defspace; lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; ret_value = parse_cmdline(argc, (const char **)argv); if ( ret_value ) goto _error_end; /* * If user input -h(help), just print guide to * users and ignore other parameters. */ if (help_input) { print_help(usage_string, option_strings); return LCP_SUCCESS; } /* * Check whether force to lock. */ if ( force == 0 ) { int dummy; /* * If haven't input force to lock, reminder to confirm * whether lock or not. */ do { log_info("Really want to lock TPM NV? (Y/N) "); dummy = scanf("%3s", confirm_lock); if ( dummy <= 0 ) return LCP_E_COMD_INTERNAL_ERR; c = confirm_lock[0] | ' '; } while ( (c != 'n') && (c != 'y') ); if ( c == 'n') { ret_value = LCP_SUCCESS; return ret_value; } } /* * Set index as TPM_NV_INDEX_LOCK, datasize as 0 to lock TPM NV */ in_defspace.index = TPM_NV_INDEX_LOCK; in_defspace.permission = 0; in_defspace.size = 0; ret_value = lcp_define_index(&in_defspace, NULL, 0, NULL, 0, NULL, NULL); if ( ret_value == LCP_SUCCESS ) { /* * Execute successfully. */ log_info("Successfully locked TPM NV!\n"); return ret_value; } _error_end: /* * Error when execute. */ log_error("\nCommand NvLock failed:\n"); print_error(ret_value); return ret_value; } tboot-1.8.0/lcptools/mle_elt.c0000644000000000000000000001157412272416301014427 0ustar 00000000000000/* * mle_elt.c: MLE policy element (LCP_MLE_ELEMENT) plugin * * Copyright (c) 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. * */ #include #include #include #include #include #define _GNU_SOURCE #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "polelt_plugin.h" #include "lcputils2.h" #define MAX_HASHES 32 static uint8_t sinit_min_version; static unsigned int nr_hashes; static tb_hash_t hashes[MAX_HASHES]; static bool parse_mle_line(const char *line) { if ( nr_hashes == MAX_HASHES ) return false; return parse_line_hashes(line, &hashes[nr_hashes++]); } static bool cmdline_handler(int c, const char *opt) { if ( c == 'm' ) { sinit_min_version = (uint8_t)strtoul(opt, NULL, 0); LOG("cmdline opt: sinit_min_version: 0x%x\n", sinit_min_version); return true; } else if ( c != 0 ) { ERROR("Error: unknown option for mle type\n"); return false; } /* MLE hash files */ LOG("cmdline opt: mle hash file: %s\n", opt); if ( !parse_file(opt, parse_mle_line) ) return false; return true; } static lcp_policy_element_t *create(void) { size_t data_size = sizeof(lcp_mle_element_t) + nr_hashes * get_hash_size(TB_HALG_SHA1); lcp_policy_element_t *elt = malloc(sizeof(*elt) + data_size); if ( elt == NULL ) { ERROR("Error: failed to allocate element\n"); return NULL; } memset(elt, 0, sizeof(*elt) + data_size); elt->size = sizeof(*elt) + data_size; lcp_mle_element_t *mle = (lcp_mle_element_t *)&elt->data; mle->sinit_min_version = sinit_min_version; mle->hash_alg = TB_HALG_SHA1; mle->num_hashes = nr_hashes; lcp_hash_t *hash = mle->hashes; for ( unsigned int i = 0; i < nr_hashes; i++ ) { memcpy(hash, &hashes[i], get_hash_size(TB_HALG_SHA1)); hash = (void *)hash + get_hash_size(TB_HALG_SHA1); } return elt; } static void display(const char *prefix, const lcp_policy_element_t *elt) { lcp_mle_element_t *mle = (lcp_mle_element_t *)elt->data; DISPLAY("%s sinit_min_version: 0x%x\n", prefix, mle->sinit_min_version); DISPLAY("%s hash_alg: %s\n", prefix, hash_alg_to_str(mle->hash_alg)); DISPLAY("%s num_hashes: %u\n", prefix, mle->num_hashes); uint8_t *hash = (uint8_t *)&mle->hashes; unsigned int hash_size = get_hash_size(mle->hash_alg); for ( unsigned int i = 0; i < mle->num_hashes; i++ ) { DISPLAY("%s hashes[%u]: ", prefix, i); print_hex("", hash, hash_size); hash += hash_size; } } static struct option opts[] = { {"minver", required_argument, NULL, 'm'}, {0, 0, 0, 0} }; static polelt_plugin_t plugin = { "mle", opts, " mle\n" " [--minver ] minimum version of SINIT\n" " [FILE2] ... one or more files containing MLE\n" " hash(es); each file can contain\n" " multiple hashes\n", LCP_POLELT_TYPE_MLE, &cmdline_handler, &create, &display }; REG_POLELT_PLUGIN(&plugin) /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/mlehash.c0000644000000000000000000003065712272416301014432 0ustar 00000000000000/* * mhash.c: tool to determine the SHA-1 hash of a Intel(R) TXT MLE * * Copyright (c) 2006-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. * */ #include #include #include #include #include #include #include #include #include #include #define PRINT printf #include "../include/elf_defns.h" #include "../include/uuid.h" #include "../include/mle.h" #define SHA1_LENGTH 20 static bool verbose = false; #define log_info(fmt, ...) verbose ? printf(fmt, ##__VA_ARGS__) : 0 /* * is_elf_image * * check an image is elf or not? * */ static bool is_elf_image(const void *image, const size_t size) { elf_header_t *elf; log_info("checking whether image is an elf image ... "); if ( image == NULL ) { log_info(": failed! - Pointer is zero.\n"); return false; } /* check size */ if ( sizeof(elf_header_t) > size ) { log_info(": failed! - Image size is smaller than ELF header size.\n"); return false; } elf = (elf_header_t *)image; /* check magic number for ELF */ if (( elf->e_ident[EI_MAG0] != ELFMAG0 ) || ( elf->e_ident[EI_MAG1] != ELFMAG1 ) || ( elf->e_ident[EI_MAG2] != ELFMAG2 ) || ( elf->e_ident[EI_MAG3] != ELFMAG3 )) { log_info(": failed! - ELF magic number is not matched.\n"); return false; } /* check data encoding in ELF */ if ( elf->e_ident[EI_DATA] != ELFDATA2LSB ) { log_info(": failed! - ELF data encoding is not the least significant " "byte occupying the lowest address.\n"); return false; } /* check ELF image is executable? */ if ( elf->e_type != ET_EXEC ) { log_info(": failed! - ELF image is not executable.\n"); return false; } /* check ELF image is for IA? */ if ( elf->e_machine != EM_386 ) { log_info(": failed! - ELF image is not for IA.\n"); return false; } /* check ELF version is valid? */ if ( elf->e_version != EV_CURRENT ) { log_info(": failed! - ELF version is invalid.\n"); return false; } if ( sizeof(elf_program_header_t) > elf->e_phentsize ) { log_info(": failed! - Program size is smaller than program " "header size.\n"); return false; } log_info(": succeeded!\n"); return true; } static bool get_elf_image_range(const elf_header_t *elf, void **start, void **end) { int i; unsigned long u_start, u_end; if (elf == NULL) { log_info("Error: ELF header pointer is zero.\n"); return false; } /* assumed that already passed is_elf_image() check */ if ((start == NULL) || (end == NULL)) { log_info("Error: Output pointers are zero.\n"); return false; } u_start = 0; u_end = 0; for (i = 0; i < elf->e_phnum; i++) { elf_program_header_t *ph = (elf_program_header_t *) ((void *)elf + elf->e_phoff + i*elf->e_phentsize); if (ph->p_type == PT_LOAD) { if (u_start > ph->p_paddr) u_start = ph->p_paddr; if (u_end < ph->p_paddr+ph->p_memsz) u_end = ph->p_paddr+ph->p_memsz; } } if (u_start >= u_end) { *start = NULL; *end = NULL; return false; } else { *start = (void *)u_start; *end = (void *)u_end; return true; } } /* * * expand entire file into memory * */ static bool expand_elf_image(const elf_header_t *elf, void *base, size_t size) { int i; log_info("expanding elf image ... "); if ( elf == NULL ) { log_info(": failed! - ELF header pointer is zero.\n"); return false; } /* assumed that already passed is_elf_image() check */ /* load elf image into memory */ for (i = 0; i < elf->e_phnum; i++) { elf_program_header_t *ph = (elf_program_header_t *) ((void *)elf + elf->e_phoff + i*elf->e_phentsize); if (ph->p_type == PT_LOAD) { if ( ph->p_memsz > size ) { log_info("expanded image exceeded allocated size\n"); return false; } memcpy(base, (void *)elf + ph->p_offset, ph->p_filesz); memset(base + ph->p_filesz, 0, ph->p_memsz - ph->p_filesz); base += ph->p_memsz; size -= ph->p_memsz; } } log_info(": succeeded!.\n"); return true; } /* * print_dump * * dump the memory * */ #if 0 static void print_dump(uint32_t s, uint32_t e) { uint32_t i,j; unsigned char* p; for ( i = s, j = 0; i < e; i++, j++ ) { p = (unsigned char*)i; log_info("%02x ", *p); if ( j % 20 == 0 ) log_info("\n"); } log_info("\n"); } #endif /* * read_file * * read file from disk, if compressed, uncompress it * */ static bool read_file(const char *filename, void **buffer, size_t *length) { gzFile fcompressed = NULL; FILE *fdecompressed = NULL; struct stat filestat; char tmpbuffer[1024]; unsigned long i; *length = 0; *buffer = NULL; /* check the file exists or not */ log_info("checking whether the file exists or not ... "); if ( stat(filename, &filestat) ) goto error; log_info(": existed!\n"); /* try uncompress the file (gzopen will handle uncompressed files too) */ log_info("trying to uncompress the file ... "); fcompressed = gzopen(filename, "rb"); if ( !fcompressed ) { log_info(": failed!\n"); return false; } log_info(": succeeded!\n"); log_info("creating a temporary file to uncompress ... "); fdecompressed = tmpfile(); if ( !fdecompressed ) goto error; log_info(": succeeded!\n"); log_info("opening the decompressed file ... "); while ( !gzeof(fcompressed) ) { i = gzread(fcompressed, tmpbuffer, 1024); *length += i; if ( fwrite(tmpbuffer, 1, i, fdecompressed) != i ) goto error; } log_info(": succeeded!\n"); gzclose(fcompressed); fcompressed = NULL; log_info("testing decompression is ... "); if ( *length > 0 ) { log_info(": succeeded!\n"); /* uncompression succeeded */ fseek(fdecompressed, 0, SEEK_SET); } else { log_info(": failed!\n"); goto error; } /* read file into buffer */ log_info("reading the decompressed file ... "); *buffer = malloc(*length); if ( *buffer == NULL ) goto error; memset(*buffer, 0, *length); if ( fread(*buffer, 1, *length, fdecompressed) != *length ) goto error; fclose(fdecompressed); log_info(": succeeded!\n"); return true; error: log_info(": failed!\n"); if ( fcompressed ) gzclose(fcompressed); if ( fdecompressed ) fclose(fdecompressed); free(*buffer); return false; } static mle_hdr_t *find_mle_hdr(void *start, size_t size) { void *end; end = start + size - sizeof(uuid_t); while ( start <= end ) { if ( are_uuids_equal((const uuid_t *)start, &((uuid_t)MLE_HDR_UUID)) ) return (mle_hdr_t *)start; start += sizeof(uuid_t); } return NULL; } /* * main */ int main(int argc, char* argv[]) { void *elf_start=NULL, *elf_end=NULL; void *exp_start=NULL; void *base=NULL; size_t size, exp_size; elf_header_t *base_as_elf; uint8_t hash[SHA1_LENGTH]; mle_hdr_t *mle_hdr; int i, c; bool help = false; char *mle_file; extern int optind; /* current index of get_opt() */ EVP_MD_CTX ctx; const EVP_MD *md; char *cmdline = NULL; while ((c = getopt(argc, (char ** const)argv, "hvc:")) != -1) { switch (c) { case 'h': help = true; break; case 'v': verbose = true; break; case 'c': if ( optarg == NULL ) { printf("Misssing command line string for -c option\n"); return 1; } cmdline = malloc(strlen(optarg) + 1); if ( cmdline == NULL ) { printf("Out of memory\n"); return 1; } strcpy(cmdline, optarg); break; default: printf("Unknonw command line option\n"); break; } } if ( help || (optind == argc) ) { printf("mhash [-h] [-v] [-c cmdline] mle_file\n" "\t-h Help: will print out this help message.\n" "\t-v Verbose: display progress indications.\n" "\t-c cmdline Command line: specify quote-delimited command line.\n" "\tmle_file: file name of MLE binary (gzip or not) to hash.\n"); free(cmdline); return 1; } mle_file = argv[optind]; /* read file */ if ( !read_file(mle_file, &base, &size) ) goto error; /* expand image */ if ( !is_elf_image(base, size) ) goto error; base_as_elf = (elf_header_t *)base; /* get expanded size and allocate memory for it */ if ( !get_elf_image_range(base_as_elf, &elf_start, &elf_end) ) goto error; exp_size = elf_end - elf_start; exp_start = malloc(exp_size); if ( exp_start == NULL ) { log_info("not enough memory for expanded image\n"); goto error; } /* expand the image */ if ( !expand_elf_image(base_as_elf, exp_start, exp_size) ) goto error; /* find the MLE header in the expanded image */ mle_hdr = find_mle_hdr(exp_start, exp_size); if ( mle_hdr == NULL ) { log_info("no MLE header found in image\n"); goto error; } /* before hashing, find command line area in MLE then zero-fill and copy command line param to it */ if ( mle_hdr->cmdline_end_off > mle_hdr->cmdline_start_off && cmdline != NULL ) { memset(exp_start + mle_hdr->cmdline_start_off, '\0', mle_hdr->cmdline_end_off - mle_hdr->cmdline_start_off); strncpy(exp_start + mle_hdr->cmdline_start_off, cmdline, mle_hdr->cmdline_end_off - mle_hdr->cmdline_start_off - 1); } /* SHA-1 the MLE portion of the image */ md = EVP_sha1(); EVP_DigestInit(&ctx, md); EVP_DigestUpdate(&ctx, exp_start + mle_hdr->mle_start_off, mle_hdr->mle_end_off - mle_hdr->mle_start_off); EVP_DigestFinal(&ctx, (unsigned char *)hash, NULL); log_info("SHA-1 = "); /* we always print the hash regardless of verbose mode */ for ( i = 0; i < SHA1_LENGTH; i++ ) { printf("%02x", hash[i]); if ( i < SHA1_LENGTH - 1 ) printf(" "); } printf("\n"); free(base); free(exp_start); return 0; error: free(base); free(exp_start); return 1; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/pconf_elt.c0000644000000000000000000002013512272416301014750 0ustar 00000000000000/* * pconf_elt.c: platform config policy element (LCP_PCONF_ELEMENT) plugin * * Copyright (c) 2009 - 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 #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #define NR_PCRS 24 #define MAX_PCR_INFOS 32 /* * TPM_PCR_INFO_SHORT * (from tboot/tpm.{h,c} */ typedef struct __packed { uint16_t size_of_select; uint8_t pcr_select[3]; } tpm_pcr_selection_t; typedef uint8_t tpm_locality_selection_t; #define TPM_DIGEST_SIZE 20 typedef struct __packed { uint8_t digest[TPM_DIGEST_SIZE]; } tpm_digest_t; typedef tpm_digest_t tpm_composite_hash_t; typedef tpm_digest_t tpm_pcr_value_t; typedef struct __packed { tpm_pcr_selection_t select; uint32_t value_size; tpm_pcr_value_t pcr_value[]; } tpm_pcr_composite_t; 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; /* need to define TPM_PCR_INFO_SHORT before including lcp2.h */ #define TPM_PCR_INFO_SHORT tpm_pcr_info_short_t #include "../include/lcp2.h" #include "polelt_plugin.h" #include "lcputils2.h" static unsigned int nr_pcr_infos; static tpm_pcr_info_short_t pcr_infos[MAX_PCR_INFOS]; static unsigned int nr_pcrs; static unsigned int pcrs[NR_PCRS]; static tb_hash_t digests[NR_PCRS]; static bool parse_pconf_line(const char *line) { if ( nr_pcrs == NR_PCRS ) return false; /* skip any leading whitespace and non-digits */ while ( *line != '\0' && (isspace(*line) || !isdigit(*line)) ) line++; /* get PCR # */ pcrs[nr_pcrs] = (unsigned int)strtoul(line, (char **)&line, 10); if ( pcrs[nr_pcrs] >= NR_PCRS ) { ERROR("Error: invalid PCR value\n"); return false; } LOG("parsed PCR: %u\n", pcrs[nr_pcrs]); /* skip until next digit */ while ( *line != '\0' && !isxdigit(*line) ) line++; if ( !parse_line_hashes(line, &digests[nr_pcrs]) ) return false; nr_pcrs++; return true; } static bool make_pcr_info(unsigned int nr_pcrs, unsigned int pcrs[], tb_hash_t digests[], tpm_pcr_info_short_t *pcr_info) { unsigned int i; /* don't use TSS Trspi_xxx fns to create this so that there is no runtime dependency on a TSS */ /* fill in pcrSelection */ /* TPM structures are big-endian, so byte-swap */ pcr_info->pcr_selection.size_of_select = bswap_16(3); memset(&pcr_info->pcr_selection.pcr_select, 0, sizeof(pcr_info->pcr_selection.pcr_select)); for ( i = 0; i < nr_pcrs; i++ ) pcr_info->pcr_selection.pcr_select[pcrs[i]/8] |= 1 << (pcrs[i] % 8); /* set locality to default (0x1f) */ pcr_info->locality_at_release = 0x1f; /* * digest is hash of TPM_PCR_COMPOSITE */ size_t pcr_comp_size = offsetof(tpm_pcr_composite_t, pcr_value) + nr_pcrs * sizeof(tpm_pcr_value_t); tpm_pcr_composite_t *pcr_comp = (tpm_pcr_composite_t *)malloc(pcr_comp_size); if ( pcr_comp == NULL ) return false; memcpy(&pcr_comp->select, &pcr_info->pcr_selection, sizeof(pcr_comp->select)); pcr_comp->value_size = bswap_32(nr_pcrs * sizeof(tpm_pcr_value_t)); /* concat specified digests */ for ( i = 0; i < nr_pcrs; i++ ) { memcpy(&pcr_comp->pcr_value[i], &digests[i], sizeof(pcr_comp->pcr_value[0])); } /* then hash it */ tb_hash_t hash; if ( !hash_buffer((uint8_t *)pcr_comp, pcr_comp_size, &hash, TB_HALG_SHA1) ) { free(pcr_comp); return false; } /* then copy it */ memcpy(&pcr_info->digest_at_release, &hash, sizeof(pcr_info->digest_at_release)); free(pcr_comp); return true; } static bool cmdline_handler(int c, const char *opt) { if ( c != 0 ) { ERROR("Error: unknown option for pconf type\n"); return false; } nr_pcrs = 0; memset(&pcrs, 0, sizeof(pcrs)); memset(&digests, 0, sizeof(digests)); /* pconf files */ LOG("cmdline opt: pconf file: %s\n", opt); if ( !parse_file(opt, parse_pconf_line) ) return false; if ( !make_pcr_info(nr_pcrs, pcrs, digests, &pcr_infos[nr_pcr_infos++]) ) return false; return true; } static lcp_policy_element_t *create(void) { size_t data_size = sizeof(uint16_t) + nr_pcr_infos * sizeof(pcr_infos[0]); lcp_policy_element_t *elt = malloc(sizeof(*elt) + data_size); if ( elt == NULL ) { ERROR("Error: failed to allocate element\n"); return NULL; } memset(elt, 0, sizeof(*elt) + data_size); elt->size = sizeof(*elt) + data_size; lcp_pconf_element_t *pconf = (lcp_pconf_element_t *)&elt->data; pconf->num_pcr_infos = nr_pcr_infos; memcpy(&pconf->pcr_infos, &pcr_infos, nr_pcr_infos * sizeof(pcr_infos[0])); return elt; } static void display(const char *prefix, const lcp_policy_element_t *elt) { lcp_pconf_element_t *pconf = (lcp_pconf_element_t *)elt->data; DISPLAY("%s num_pcr_infos: %u\n", prefix, pconf->num_pcr_infos); for ( unsigned int i = 0; i < pconf->num_pcr_infos; i++ ) { tpm_pcr_info_short_t *pcr_info = (tpm_pcr_info_short_t *)&pconf->pcr_infos[i]; DISPLAY("%s pcr_infos[%u]:\n", prefix, i); DISPLAY("%s pcrSelect: 0x%02x%02x%02x\n", prefix, pcr_info->pcr_selection.pcr_select[0], pcr_info->pcr_selection.pcr_select[1], pcr_info->pcr_selection.pcr_select[2]); DISPLAY("%s localityAtRelease: 0x%x\n", prefix, pcr_info->locality_at_release); DISPLAY("%s digestAtRelease: ", prefix); print_hex("", &pcr_info->digest_at_release, get_hash_size(TB_HALG_SHA1)); } } static polelt_plugin_t plugin = { "pconf", NULL, " pconf\n" " [FILE2] ... one or more files containing PCR\n" " numbers and the desired digest\n" " of each; each file will be a PCONF\n", LCP_POLELT_TYPE_PCONF, &cmdline_handler, &create, &display }; REG_POLELT_PLUGIN(&plugin) /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/pol.c0000644000000000000000000001105312272416301013570 0ustar 00000000000000/* * pol.c: * * Copyright (c) 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. * */ #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "polelt_plugin.h" #include "pol.h" #include "lcputils2.h" size_t get_policy_size(const lcp_policy_t *pol) { return offsetof(lcp_policy_t, policy_hash) + get_lcp_hash_size(pol->hash_alg); } bool verify_policy(const lcp_policy_t *pol, size_t size, bool silent) { if ( get_policy_size(pol) > size ) { if ( !silent ) ERROR("Error: policy too big\n"); return false; } if ( pol->version < LCP_DEFAULT_POLICY_VERSION || MAJOR_VER(pol->version) != MAJOR_VER(LCP_DEFAULT_POLICY_VERSION) ) { if ( !silent ) ERROR("Error: invalid policy version: 0x%x\n", pol->version); return false; } if ( pol->hash_alg != LCP_POLHALG_SHA1 ) { if ( !silent ) ERROR("Error: invalid policy hash alg: %u\n", pol->hash_alg); return false; } if ( pol->policy_type != LCP_POLTYPE_ANY && pol->policy_type != LCP_POLTYPE_LIST ) { if ( !silent ) ERROR("Error: invlaid policy type: %u\n", pol->policy_type); return false; } if ( pol->reserved1 != 0 || pol->reserved2[0] != 0 || pol->reserved2[1] != 0 ) { if ( !silent ) ERROR("Error: reserved fields not 0: %u, %u, %u\n", pol->reserved1, pol->reserved2[0], pol->reserved2[1]); return false; } return true; } void display_policy(const char *prefix, const lcp_policy_t *pol, bool brief) { (void)brief; /* quiet compiler warning portbly */ if ( pol == NULL ) return; if ( prefix == NULL ) prefix = ""; DISPLAY("%s version: 0x%x\n", prefix, pol->version); DISPLAY("%s hash_alg: %s\n", prefix, hash_alg_to_str(pol->hash_alg)); DISPLAY("%s policy_type: %s\n", prefix, policy_type_to_str(pol->policy_type)); DISPLAY("%s sinit_min_version: 0x%x\n", prefix, pol->sinit_min_version); DISPLAY("%s data_revocation_counters: ", prefix); for ( unsigned int i = 0; i < ARRAY_SIZE(pol->data_revocation_counters); i++ ) DISPLAY("%u, ", pol->data_revocation_counters[i]); DISPLAY("\n"); DISPLAY("%s policy_control: 0x%x\n", prefix, pol->policy_control); DISPLAY("%s policy_hash: ", prefix); print_hex("", &pol->policy_hash, get_lcp_hash_size(pol->hash_alg)); } const char *policy_type_to_str(uint8_t type) { static const char *types[] = { "list", "any" }; static char buf[32] = ""; if ( type >= ARRAY_SIZE(types) ) { snprintf(buf, sizeof(buf), "unknown (%u)", type); return buf; } return types[type]; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/pol.h0000644000000000000000000000410512272416301013575 0ustar 00000000000000/* * pol.h: * * Copyright (c) 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 __POL_H__ #define __POL_H__ extern size_t get_policy_size(const lcp_policy_t *pol); extern bool verify_policy(const lcp_policy_t *pol, size_t size, bool silent); extern void display_policy(const char *prefix, const lcp_policy_t *pol, bool brief); extern const char *policy_type_to_str(uint8_t type); #endif /* __POL_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/poldata.c0000644000000000000000000001420312272416301014422 0ustar 00000000000000/* * poldata.c: * * Copyright (c) 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. * */ #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "../include/lcp_hlp.h" #include "polelt_plugin.h" #include "poldata.h" #include "pollist.h" #include "lcputils2.h" size_t get_policy_data_size(const lcp_policy_data_t *poldata) { size_t size = offsetof(lcp_policy_data_t, policy_lists); const lcp_policy_list_t *pollist = &poldata->policy_lists[0]; for ( unsigned int i = 0; i < poldata->num_lists; i++ ) { size += get_policy_list_size(pollist); pollist = (void *)pollist + get_policy_list_size(pollist); } return size; } bool verify_policy_data(const lcp_policy_data_t *poldata, size_t size) { if ( offsetof(lcp_policy_data_t, policy_lists) >= size ) { ERROR("Error: policy data too small\n"); return false; } if ( strcmp(poldata->file_signature, LCP_POLICY_DATA_FILE_SIGNATURE) != 0 ) { ERROR("Error: policy data file signature invalid (%s): \n", poldata->file_signature); return false; } if ( poldata->reserved[0] != 0 || poldata->reserved[1] != 0 || poldata->reserved[2] != 0 ) { ERROR("Error: policy data reserved fields not 0: %u, %u, %u\n", poldata->reserved[0], poldata->reserved[1], poldata->reserved[2]); return false; } if ( poldata->num_lists == 0 || poldata->num_lists >= LCP_MAX_LISTS ) { ERROR("Error: too many lists: %u\n", poldata->num_lists); return false; } /* try to bound size as closely as possible */ size -= offsetof(lcp_policy_data_t, policy_lists); const lcp_policy_list_t *pollist = &poldata->policy_lists[0]; for ( unsigned int i = 0; i < poldata->num_lists; i++ ) { LOG("verifying list %u:\n", i); if ( !verify_policy_list(pollist, size, NULL, false) ) return false; size -= get_policy_list_size(pollist); pollist = (void *)pollist + get_policy_list_size(pollist); } return true; } void display_policy_data(const char *prefix, const lcp_policy_data_t *poldata, bool brief) { if ( poldata == NULL ) return; if ( prefix == NULL ) prefix = ""; DISPLAY("%s file_signature: %s\n", prefix, poldata->file_signature); DISPLAY("%s num_lists: %u\n", prefix, poldata->num_lists); char new_prefix[strlen(prefix)+8]; sprintf(new_prefix, "%s ", prefix); const lcp_policy_list_t *pollist = &poldata->policy_lists[0]; for ( unsigned int i = 0; i < poldata->num_lists; i++ ) { DISPLAY("%s list %u:\n", prefix, i); display_policy_list(new_prefix, pollist, brief); pollist = (void *)pollist + get_policy_list_size(pollist); } } lcp_policy_data_t *add_policy_list(lcp_policy_data_t *poldata, const lcp_policy_list_t *pollist) { if ( poldata == NULL || pollist == NULL ) return NULL; /* adding a policy list requires growing the policy data */ size_t old_size = get_policy_data_size(poldata); size_t list_size = get_policy_list_size(pollist); lcp_policy_data_t *new_poldata = realloc(poldata, old_size + list_size); if ( new_poldata == NULL ) { ERROR("Error: failed to allocate memory\n"); free(poldata); return NULL; } /* realloc() copies over previous contents */ /* add to end */ memcpy((void *)new_poldata + old_size, pollist, list_size); new_poldata->num_lists++; return new_poldata; } void calc_policy_data_hash(const lcp_policy_data_t *poldata, lcp_hash_t *hash, uint8_t hash_alg) { size_t hash_size = get_lcp_hash_size(hash_alg); uint8_t hash_list[hash_size * LCP_MAX_LISTS]; memset(hash_list, 0, sizeof(hash_list)); /* accumulate each list's msmt to list */ lcp_hash_t *curr_hash = (lcp_hash_t *)hash_list; const lcp_policy_list_t *pollist = &poldata->policy_lists[0]; for ( unsigned int i = 0; i < poldata->num_lists; i++ ) { calc_policy_list_hash(pollist, curr_hash, hash_alg); pollist = (void *)pollist + get_policy_list_size(pollist); curr_hash = (void *)curr_hash + hash_size; } /* hash list */ hash_buffer(hash_list, hash_size * poldata->num_lists, (tb_hash_t *)hash, hash_alg); return; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/poldata.h0000644000000000000000000000454212272416301014434 0ustar 00000000000000/* * poldata.h: * * Copyright (c) 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 __POLDATA_H__ #define __POLDATA_H__ extern size_t get_policy_data_size(const lcp_policy_data_t *poldata); extern bool verify_policy_data(const lcp_policy_data_t *poldata, size_t size); extern void display_policy_data(const char *prefix, const lcp_policy_data_t *poldata, bool brief); extern lcp_policy_data_t *add_policy_list(lcp_policy_data_t *poldata, const lcp_policy_list_t *pollist); extern void calc_policy_data_hash(const lcp_policy_data_t *poldata, lcp_hash_t *hash, uint8_t hash_alg); #endif /* __POLDATA_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/polelt.c0000644000000000000000000000751112272416301014301 0ustar 00000000000000/* * polelt.c: * * Copyright (c) 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. * */ #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "polelt_plugin.h" #include "lcputils2.h" #define POLELT_MAX_PLUGINS 32 unsigned int nr_polelt_plugins; polelt_plugin_t *polelt_plugins[POLELT_MAX_PLUGINS]; polelt_plugin_t *find_polelt_plugin_by_type(uint32_t type) { for ( unsigned int i = 0; i < nr_polelt_plugins; i++ ) { if ( type == polelt_plugins[i]->type ) return polelt_plugins[i]; } return NULL; } polelt_plugin_t *find_polelt_plugin_by_type_string(const char *type_str) { for ( unsigned int i = 0; i < nr_polelt_plugins; i++ ) { if ( strcmp(type_str, polelt_plugins[i]->type_string) == 0 ) return polelt_plugins[i]; } return NULL; } bool verify_policy_element(const lcp_policy_element_t *elt, size_t size) { if ( size < sizeof(*elt) ) { ERROR("Error: data is too small\n"); return false; } if ( size != elt->size ) { ERROR("Error: data is too small\n"); return false; } /* no members to verify */ return true; } void display_policy_element(const char *prefix, const lcp_policy_element_t *elt, bool brief) { DISPLAY("%s size: 0x%x (%u)\n", prefix, elt->size, elt->size); polelt_plugin_t *plugin = find_polelt_plugin_by_type(elt->type); const char *type_str = (plugin == NULL) ? "unknown" : plugin->type_string; DISPLAY("%s type: \'%s\' (%u)\n", prefix, type_str, elt->type); DISPLAY("%s policy_elt_control: 0x%08x\n", prefix, elt->policy_elt_control); /* don't display element data for brief output */ if ( brief ) return; char new_prefix[strlen(prefix)+8]; snprintf(new_prefix, sizeof(new_prefix), "%s ", prefix); DISPLAY("%s data:\n", prefix); if ( plugin == NULL ) print_hex(new_prefix, elt->data, elt->size - sizeof(*elt)); else (*plugin->display)(new_prefix, elt); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/polelt.h0000644000000000000000000000422212272416301014302 0ustar 00000000000000/* * polelt.h: * * Copyright (c) 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 __POLELT_H__ #define __POLELT_H__ extern polelt_plugin_t *find_polelt_plugin_by_type(uint32_t type); extern polelt_plugin_t *find_polelt_plugin_by_type_string(const char *type_str); extern bool verify_policy_element(const lcp_policy_element_t *elt, size_t size); extern void display_policy_element(const char *prefix, const lcp_policy_element_t *elt, bool brief); #endif /* __POLELT_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/polelt_plugin.h0000644000000000000000000000554312272416301015667 0ustar 00000000000000/* * polelt_plugin.h: policy element plugin support * * Copyright (c) 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 __POLELT_PLUGIN_H__ #define __POLELT_PLUGIN_H__ #define MAX_ELT_TYPE_STR_LEN 32 typedef struct { const char *type_string; struct option *cmdline_opts; const char *help_txt; uint32_t type; /* c = option char (or 0 for non-option args) */ bool (*cmdline_handler)(int c, const char *opt); /* uses state from cmdline_handler */ lcp_policy_element_t *(*create_elt)(void); void (*display)(const char *prefix, const lcp_policy_element_t *elt); } polelt_plugin_t; extern unsigned int nr_polelt_plugins; extern polelt_plugin_t *polelt_plugins[]; #define REG_POLELT_PLUGIN(plugin) \ static void reg_plugin(void) __attribute__ ((constructor)); \ static void reg_plugin(void) \ { \ polelt_plugins[nr_polelt_plugins++] = plugin; \ } /* users must define these: */ extern void ERROR(const char *fmt, ...); extern void LOG(const char *fmt, ...); extern void DISPLAY(const char *fmt, ...); #endif /* __POLELT_PLUGIN_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/pollist.c0000644000000000000000000003551612272416301014476 0ustar 00000000000000/* * pollist.c: * * Copyright (c) 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. * */ #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "../include/lcp_hlp.h" #include "polelt_plugin.h" #include "pollist.h" #include "polelt.h" #include "lcputils2.h" bool verify_policy_list(const lcp_policy_list_t *pollist, size_t size, bool *no_sigblock, bool size_is_exact) { if ( pollist == NULL ) return false; if ( size < sizeof(*pollist) ) { ERROR("Error: data is too small (%u)\n", size); return false; } if ( pollist->version < LCP_DEFAULT_POLICY_LIST_VERSION || MAJOR_VER(pollist->version) != MAJOR_VER(LCP_DEFAULT_POLICY_LIST_VERSION) ) { ERROR("Error: unsupported version 0x%04x\n", pollist->version); return false; } if ( pollist->reserved != 0 ) { ERROR("Error: reserved field must be 0: %u\n", pollist->reserved); return false; } if ( pollist->sig_alg != LCP_POLSALG_NONE && pollist->sig_alg != LCP_POLSALG_RSA_PKCS_15 ) { ERROR("Error: unsupported sig_alg %u\n", pollist->sig_alg); return false; } /* verify policy_elements_size */ size_t base_size = offsetof(lcp_policy_list_t, policy_elements); /* no sig, so size should be exact */ if ( pollist->sig_alg == LCP_POLSALG_NONE ) { if ( size_is_exact && base_size + pollist->policy_elements_size != size ) { ERROR("Error: size incorrect (no sig): 0x%x != 0x%x\n", base_size + pollist->policy_elements_size, size); return false; } else if ( !size_is_exact && base_size + pollist->policy_elements_size > size ) { ERROR("Error: size incorrect (no sig): 0x%x > 0x%x\n", base_size + pollist->policy_elements_size, size); return false; } } /* verify size exactly later, after check sig field */ else if ( base_size + sizeof(lcp_signature_t) + pollist->policy_elements_size > size ) { ERROR("Error: size incorrect (sig min): 0x%x > 0x%x\n", base_size + sizeof(lcp_signature_t) + pollist->policy_elements_size, size); return false; } /* verify sum of policy elements' sizes */ uint32_t elts_size = 0; const lcp_policy_element_t *elt = pollist->policy_elements; while ( elts_size < pollist->policy_elements_size ) { if ( elts_size + elt->size > pollist->policy_elements_size ) { ERROR("Error: size incorrect (elt size): 0x%x > 0x%x\n", elts_size + elt->size, pollist->policy_elements_size); return false; } elts_size += elt->size; elt = (void *)elt + elt->size; } if ( elts_size != pollist->policy_elements_size ) { ERROR("Error: size incorrect (elt size): 0x%x != 0x%x\n", elts_size, pollist->policy_elements_size); return false; } /* verify sig */ if ( pollist->sig_alg == LCP_POLSALG_RSA_PKCS_15 ) { lcp_signature_t *sig = (lcp_signature_t *) ((void *)&pollist->policy_elements + pollist->policy_elements_size); /* check size w/ sig_block */ if ( !size_is_exact && base_size + pollist->policy_elements_size + get_signature_size(sig) > size + sig->pubkey_size ) { ERROR("Error: size incorrect (sig): 0x%x > 0x%x\n", base_size + pollist->policy_elements_size + get_signature_size(sig), size + sig->pubkey_size); return false; } else if ( size_is_exact && base_size + pollist->policy_elements_size + get_signature_size(sig) != size ) { /* check size w/o sig_block */ if ( base_size + pollist->policy_elements_size + get_signature_size(sig) != size + sig->pubkey_size ) { ERROR("Error: size incorrect (sig exact): 0x%x != 0x%x\n", base_size + pollist->policy_elements_size + get_signature_size(sig), size + sig->pubkey_size); return false; } else { if ( no_sigblock != NULL ) *no_sigblock = true; } } else { if ( no_sigblock != NULL ) *no_sigblock = false; if ( !verify_pollist_sig(pollist) ) { ERROR("Error: signature does not verify\n"); return false; } } } else { if ( no_sigblock != NULL ) *no_sigblock = false; } return true; } void display_policy_list(const char *prefix, const lcp_policy_list_t *pollist, bool brief) { static const char *sig_alg_str[] = { "LCP_POLSALG_NONE", "LCP_POLSALG_RSA_PKCS_15" }; if ( pollist == NULL ) return; if ( prefix == NULL ) prefix = ""; DISPLAY("%s version: 0x%x\n", prefix, pollist->version); DISPLAY("%s sig_alg: %s\n", prefix, sig_alg_str[pollist->sig_alg]); DISPLAY("%s policy_elements_size: 0x%x (%u)\n", prefix, pollist->policy_elements_size, pollist->policy_elements_size); char new_prefix[strlen(prefix)+8]; snprintf(new_prefix, sizeof(new_prefix), "%s ", prefix); unsigned int i = 0; size_t elts_size = pollist->policy_elements_size; const lcp_policy_element_t *elt = pollist->policy_elements; while ( elts_size > 0 ) { DISPLAY("%s policy_element[%u]:\n", prefix, i++); display_policy_element(new_prefix, elt, brief); elts_size -= elt->size; elt = (void *)elt + elt->size; } lcp_signature_t *sig = get_signature(pollist); if ( sig != NULL ) { DISPLAY("%s signature:\n", prefix); display_signature(new_prefix, sig, brief); if ( verify_pollist_sig(pollist) ) DISPLAY("%s signature verifies\n", prefix); else DISPLAY("%s signature fails to verify\n", prefix); } } lcp_policy_list_t *create_empty_policy_list(void) { lcp_policy_list_t *pollist = malloc(offsetof(lcp_policy_list_t, policy_elements)); if ( pollist == NULL ) { ERROR("Error: failed to allocate memory\n"); return NULL; } pollist->version = LCP_DEFAULT_POLICY_LIST_VERSION; pollist->reserved = 0; pollist->sig_alg = LCP_POLSALG_NONE; pollist->policy_elements_size = 0; return pollist; } lcp_policy_list_t *add_policy_element(lcp_policy_list_t *pollist, const lcp_policy_element_t *elt) { if ( pollist == NULL || elt == NULL ) return NULL; /* adding a policy element requires growing the policy list */ size_t old_size = get_policy_list_size(pollist); lcp_policy_list_t *new_pollist = realloc(pollist, old_size + elt->size); if ( new_pollist == NULL ) { ERROR("Error: failed to allocate memory\n"); free(pollist); return NULL; } /* realloc() copies over previous contents */ /* we add at the beginning of the elements list (don't want to overwrite a signature) */ memmove((void *)&new_pollist->policy_elements + elt->size, &new_pollist->policy_elements, old_size - offsetof(lcp_policy_list_t, policy_elements)); memcpy(&new_pollist->policy_elements, elt, elt->size); new_pollist->policy_elements_size += elt->size; return new_pollist; } bool del_policy_element(lcp_policy_list_t *pollist, uint32_t type) { if ( pollist == NULL ) return false; /* find first element of specified type (there should only be one) */ size_t elts_size = pollist->policy_elements_size; lcp_policy_element_t *elt = pollist->policy_elements; while ( elts_size > 0 ) { if ( elt->type == type ) { /* move everything up */ size_t tot_size = get_policy_list_size(pollist); size_t elt_size = elt->size; memmove(elt, (void *)elt + elt_size, tot_size - ((void *)elt + elt_size - (void *)pollist)); pollist->policy_elements_size -= elt_size; return true; } elts_size -= elt->size; elt = (void *)elt + elt->size; } return false; } bool verify_pollist_sig(const lcp_policy_list_t *pollist) { lcp_signature_t *sig = get_signature(pollist); if ( sig == NULL ) return true; return verify_signature((const unsigned char *)pollist, get_policy_list_size(pollist) - sig->pubkey_size, sig->pubkey_value, sig->pubkey_size, get_sig_block(pollist), true); } void display_signature(const char *prefix, const lcp_signature_t *sig, bool brief) { char new_prefix[strlen(prefix)+8]; snprintf(new_prefix, sizeof(new_prefix), "%s\t", prefix); DISPLAY("%s revocation_counter: 0x%x (%u)\n", prefix, sig->revocation_counter, sig->revocation_counter); DISPLAY("%s pubkey_size: 0x%x (%u)\n", prefix, sig->pubkey_size, sig->pubkey_size); if ( brief ) return; DISPLAY("%s pubkey_value:\n", prefix); print_hex(new_prefix, sig->pubkey_value, sig->pubkey_size); DISPLAY("%s sig_block:\n", prefix); print_hex(new_prefix, (void *)&sig->pubkey_value + sig->pubkey_size, sig->pubkey_size); } lcp_policy_list_t *add_signature(lcp_policy_list_t *pollist, const lcp_signature_t *sig) { if ( pollist == NULL || sig == NULL ) return NULL; /* adding a signature requires growing the policy list */ size_t old_size = get_policy_list_size(pollist); size_t sig_size = sizeof(*sig) + 2*sig->pubkey_size; lcp_policy_list_t *new_pollist = realloc(pollist, old_size + sig_size); if ( new_pollist == NULL ) { ERROR("Error: failed to allocate memory\n"); free(pollist); return NULL; } /* realloc() copies over previous contents */ size_t sig_begin = old_size; /* if a signature already exists, replace it */ lcp_signature_t *curr_sig = get_signature(new_pollist); if ( curr_sig != NULL ) sig_begin = (void *)curr_sig - (void *)new_pollist; memcpy((void *)new_pollist + sig_begin, sig, sig_size); return new_pollist; } unsigned char *get_sig_block(const lcp_policy_list_t *pollist) { lcp_signature_t *sig = get_signature(pollist); if ( sig == NULL ) return NULL; return (unsigned char *)&sig->pubkey_value + sig->pubkey_size; } void calc_policy_list_hash(const lcp_policy_list_t *pollist, lcp_hash_t *hash, uint8_t hash_alg) { uint8_t *buf_start = (uint8_t *)pollist; size_t len = get_policy_list_size(pollist); if ( pollist->sig_alg == LCP_POLSALG_RSA_PKCS_15 ) { lcp_signature_t *sig = get_signature(pollist); if ( sig == NULL ) return; buf_start = sig->pubkey_value; len = sig->pubkey_size; } hash_buffer(buf_start, len, (tb_hash_t *)hash, hash_alg); } lcp_policy_list_t *read_policy_list_file(const char *file, bool fail_ok, bool *no_sigblock_ok) { if ( file == NULL || *file == '\0' || no_sigblock_ok == NULL ) return NULL; /* read existing file, if it exists */ size_t len; lcp_policy_list_t *pollist = read_file(file, &len, fail_ok); if ( pollist == NULL ) return NULL; bool no_sigblock; if ( !verify_policy_list(pollist, len, &no_sigblock, true) ) { free(pollist); return NULL; } if ( !*no_sigblock_ok && no_sigblock ) { ERROR("Error: policy list does not have sig_block\n"); free(pollist); return NULL; } /* if there is no sig_block then create one w/ all 0s so that get_policy_list_size() will work correctly; it will be stripped when writing it back */ lcp_signature_t *sig = get_signature(pollist); if ( sig != NULL && no_sigblock ) { LOG("input file has no sig_block\n"); size_t keysize = sig->pubkey_size; pollist = realloc(pollist, len + keysize); if ( pollist == NULL ) return NULL; memset((void *)pollist + len, 0, keysize); } *no_sigblock_ok = no_sigblock; return pollist; } bool write_policy_list_file(const char *file, const lcp_policy_list_t *pollist) { size_t len = get_policy_list_size(pollist); /* check if sig_block all 0's--if so then means there was no sig_block when file was read but empty one was added, so don't write it */ lcp_signature_t *sig = get_signature(pollist); if ( sig != NULL ) { uint8_t *sig_block = (uint8_t *)&sig->pubkey_value + sig->pubkey_size; while ( sig_block < ((uint8_t *)pollist + len) ) { if ( *sig_block++ != 0 ) break; } /* all 0's */ if ( sig_block == ((uint8_t *)pollist + len) ) { LOG("output file has no sig_block\n"); len -= sig->pubkey_size; } } return write_file(file, pollist, len); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/pollist.h0000644000000000000000000000621312272416301014473 0ustar 00000000000000/* * pollist.h: * * Copyright (c) 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 __POLLIST_H__ #define __POLLIST_H__ extern bool verify_policy_list(const lcp_policy_list_t *pollist, size_t size, bool *no_sigblock, bool size_is_exact); extern void display_policy_list(const char *prefix, const lcp_policy_list_t *pollist, bool brief); extern lcp_policy_list_t *create_empty_policy_list(void); extern lcp_policy_list_t *add_policy_element(lcp_policy_list_t *pollist, const lcp_policy_element_t *elt); extern bool del_policy_element(lcp_policy_list_t *pollist, uint32_t type); extern bool verify_pollist_sig(const lcp_policy_list_t *pollist); extern void display_signature(const char *prefix, const lcp_signature_t *sig, bool brief); extern lcp_policy_list_t *add_signature(lcp_policy_list_t *pollist, const lcp_signature_t *sig); extern unsigned char *get_sig_block(const lcp_policy_list_t *pollist); extern void calc_policy_list_hash(const lcp_policy_list_t *pollist, lcp_hash_t *hash, uint8_t hash_alg); extern lcp_policy_list_t *read_policy_list_file(const char *file, bool fail_ok, bool *no_sigblock_ok); extern bool write_policy_list_file(const char *file, const lcp_policy_list_t *pollist); #endif /* __POLLIST_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/readpol.c0000644000000000000000000002047212272416301014431 0ustar 00000000000000/* * Copyright 2001 - 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 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. */ /* * readpol.c * Command: lcp_readpol. * This command can read LCP policy from TPM NV Storage. */ #include #include #include #include #include #include #include #define PRINT printf #include "../include/uuid.h" #include "../include/lcp.h" #include "lcptools.h" #include "lcputils.h" #define BUFFER_SIZE 1024 static uint32_t index_value = 0; static char* file = NULL; static uint32_t size = 0; static char *password = NULL; static uint32_t passwd_length = 0; static int help_input = 0; static const char *short_option = "hi:f:s:p:"; static const char *usage_string = "lcp_readpol -i index_value " "[-s read_size] [-f output_file] [-p passwd] [-h]"; static const char *option_strings[] = { "-i index value: uint32/string.\n" "\tINDEX_LCP_DEF:0x50000001 or \"default\",\n" "\tINDEX_LCP_OWN:0x40000001 or \"owner\",\n" "\tINDEX_AUX:0x50000002 or \"aux\"\n", "-f file_name: string. Name of file to store the policy data in. \n", "-s size to read: uint32. Value size to read from NV store.\n", "-p password: string. \n", "-h help. Will print out this help message.\n", NULL }; static param_option_t index_option_table[] = { {"default", INDEX_LCP_DEF}, {"owner", INDEX_LCP_OWN}, {"aux", INDEX_AUX}, {NULL, -1} }; /* * function: parse_cmdline * description: parse the input of commandline */ static int parse_cmdline(int argc, const char * argv[]) { int c; while (((c = getopt(argc, (char ** const)argv, short_option)) != -1)) switch (c){ case 'i': /* check whether user inputs the string for reserved indices */ index_value = parse_input_option(index_option_table, optarg); /* * if not, then the users should input the non-0 number, * 0 is not allowed for index */ if ( index_value == (uint32_t)-1 ) if ( strtonum(optarg, &index_value) || (index_value == 0) ) return LCP_E_INVALID_PARAMETER; break; case 'f': file = optarg; break; case 'p': password = optarg; passwd_length = strlen(password); break; case 's': if ( strtonum(optarg, &size) ) return LCP_E_INVALID_PARAMETER; break; case 'h': help_input = 1; break; default: return LCP_E_NO_SUCH_PARAMETER; } if ( optind < argc ) return LCP_E_INVALID_PARAMETER; return LCP_SUCCESS; } static void print_hash(lcp_hash_t *hash) { unsigned int i; for ( i = 0; i < sizeof(hash->sha1)/sizeof(hash->sha1[0]); i++ ) log_info("%02x ", hash->sha1[i]); log_info("\n"); } static void print_policy(unsigned char* pol_buf, uint32_t buf_len) { lcp_policy_t pol; unsigned char *pdata = pol_buf; static const char *pol_types[] = {"LCP_POLTYPE_HASHONLY", "LCP_POLTYPE_UNSIGNED", "LCP_POLTYPE_SIGNED", "LCP_POLTYPE_ANY", "LCP_POLTYPE_FORCEOWNERPOLICY"}; if ( buf_len < (offsetof(lcp_policy_t, policy_hash) + sizeof(pol.policy_hash.sha1) + 1) ) { log_error("policy buffer is too small\n"); return; } lcp_unloaddata_byte(&pol.version, &pdata); lcp_unloaddata_byte(&pol.hash_alg, &pdata); lcp_unloaddata_byte(&pol.policy_type, &pdata); lcp_unloaddata_byte(&pol.sinit_revocation_counter, &pdata); lcp_unloaddata_uint32(&pol.policy_control, &pdata, 1); lcp_unloaddata_uint16(&pol.reserved[0], &pdata, 1); lcp_unloaddata_uint16(&pol.reserved[1], &pdata, 1); lcp_unloaddata_uint16(&pol.reserved[2], &pdata, 1); lcp_unloaddata(sizeof(pol.policy_hash.sha1), &pdata, (unsigned char *)&pol.policy_hash); log_info("version: %d\n", (int)pol.version); log_info("hash_alg: %d\n", (int)pol.hash_alg); log_info("policy_type: %d", (int)pol.policy_type); if ( pol.policy_type < sizeof(pol_types)/sizeof(pol_types[0]) ) log_info(" - %s\n", pol_types[pol.policy_type]); else log_info(" - unknown\n"); log_info("sinit_revocation_counter: %d\n", (int)pol.sinit_revocation_counter); log_info("policy_control: %x\n", pol.policy_control); log_info("policy_hash: "); print_hash(&pol.policy_hash); } int main (int argc, char *argv[]) { FILE *p_file = NULL; unsigned char policy_data[BUFFER_SIZE]; uint32_t data_length = BUFFER_SIZE; lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; /* * No parameter input will print out the help message. */ if ( argc == 1 ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } ret_value = parse_cmdline(argc, (const char **)argv); if ( ret_value ) goto exit; /* * If user input -h(help), just print guide to * users and ignore other parameters. */ if ( help_input ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } /* * Check whether parameter of index value has been input. */ if ( index_value == 0 ) { ret_value = LCP_E_NO_INDEXVALUE; goto exit; } if ( size == 0 ) log_info("No size has been specified. Will read all index data.\n"); /* * Read NV data from TPM NV store. */ ret_value = lcp_read_index(index_value, password, passwd_length, 0, size, &data_length, policy_data); if ( ret_value ) goto exit; if ( file != NULL ) { /* * Write policy data into file. */ p_file = fopen(file, "wb"); if ( !p_file ) { log_error("Open file %s error!\n", file); ret_value = LCP_E_COMD_INTERNAL_ERR; goto exit; } if ( data_length != fwrite(policy_data, 1, data_length, p_file) ) { log_error("Write policy data into file error!\n"); ret_value = LCP_E_COMD_INTERNAL_ERR; goto exit; } } else { print_hexmsg("the policy is:\n", data_length, policy_data); print_policy(policy_data, data_length); } exit: if ( p_file != NULL ) fclose(p_file); if ( ret_value != LCP_SUCCESS ) { log_error("\nCommand ReadPol failed:\n"); print_error(ret_value); } else log_info("Successfully read value from index: 0x%08x.\n", index_value); return ret_value; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/relindex.c0000644000000000000000000001225312272416301014613 0ustar 00000000000000/* * Copyright 2001 - 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 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. */ /* * relindex.c * * Command: tpmnv_relindex. * * This command can release the index defined in TPM NV Storage. * */ #include #include #include #include #include #include #define PRINT printf #include "../include/uuid.h" #include "../include/lcp.h" #include "lcptools.h" #include "lcputils.h" static uint32_t index_value = 0; static char *password = NULL; static uint32_t passwd_length = 0; static int help_input = 0; static const char *short_option = " hi:p:"; static const char *usage_string = "tpmnv_relindex -i index -p passwd [-h]"; static const char * option_strings[] ={ "-i index value: uint32/string.\n"\ "\tINDEX_LCP_DEF:0x50000001 or \"default\",\n"\ "\tINDEX_LCP_OWN:0x40000001 or \"owner\",\n"\ "\tINDEX_AUX:0x50000002 or \"aux\"\n", "-p password: string. \n", "-h help. Will print out this help message.\n", 0 }; static param_option_t index_option_table[] = { {"default", INDEX_LCP_DEF}, {"owner", INDEX_LCP_OWN}, {"aux", INDEX_AUX}, {NULL, -1} }; /* function: parse_cmdline * description: parse the input of commandline */ static int parse_cmdline(int argc, const char * argv[]) { int c; while (((c = getopt(argc,(char ** const)argv, short_option)) != -1)) switch (c){ case 'i': /* check whether user inputs the string for reserved indices */ index_value = parse_input_option(index_option_table, optarg); /* * if not, then the users should input the non-0 number, * 0 is not allowed for index */ if ( index_value == (uint32_t)-1 ) if ( strtonum(optarg, &index_value) || (index_value == 0) ) return LCP_E_INVALID_PARAMETER; break; case 'p': password = optarg; passwd_length = strlen(password); break; case 'h': help_input = 1; break; default: return LCP_E_NO_SUCH_PARAMETER; } if ( optind < argc ) return LCP_E_INVALID_PARAMETER; return LCP_SUCCESS; } int main (int argc, char *argv[]) { lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; /* * No parameter input will print out the help message. */ if ( argc == 1 ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } /* * Parse the parameters input to decide * what parameters will be passed to TSS API. */ ret_value = parse_cmdline(argc, (const char **)argv); if ( ret_value ) goto _error_end; /* * If user input -h(help), just print guide to * users and ignore other parameters. */ if ( help_input ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } if ( index_value == 0 ) { ret_value = LCP_E_NO_INDEXVALUE; goto _error_end; } if ( password == NULL ) { ret_value = LCP_E_AUTH_FAIL; log_error("No password input! Password is needed to release index.\n"); goto _error_end; } ret_value = lcp_release_index(index_value, password, passwd_length); if ( ret_value == LCP_SUCCESS ) { /* * Execute successfully. */ log_info("Successfully released index 0x%08x \n", index_value); return ret_value; } _error_end: /* * Error when execute. */ log_error("\nCommand RelIndex failed:\n"); print_error(ret_value); return ret_value; } tboot-1.8.0/lcptools/sbios_elt.c0000644000000000000000000001276712272416301014776 0ustar 00000000000000/* * sbios_elt.c: SBIOS policy element (LCP_SBIOS_ELEMENT) plugin * * Copyright (c) 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 #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "polelt_plugin.h" #include "lcputils2.h" #define MAX_HASHES 33 /* +1 for fallback_hash */ static unsigned int nr_hashes; static tb_hash_t hashes[MAX_HASHES]; static uint16_t *get_num_hashes(lcp_sbios_element_t *sbios) { /* because fallback_hash is variable size, need to calculate this */ return (void *)&sbios->fallback_hash + get_hash_size(TB_HALG_SHA1) + sizeof(sbios->reserved2); } static lcp_hash_t *get_hashes(lcp_sbios_element_t *sbios) { /* because fallback_hash is variable size, need to calculate this */ return (void *)get_num_hashes(sbios) + sizeof(sbios->num_hashes); } static bool parse_sbios_line(const char *line) { if ( nr_hashes == MAX_HASHES ) return false; return parse_line_hashes(line, &hashes[nr_hashes++]); } static bool cmdline_handler(int c, const char *opt) { if ( c != 0 ) { ERROR("Error: unknown option for sbios type\n"); return false; } /* BIOS hash files */ LOG("cmdline opt: sbios hash file: %s\n", opt); if ( !parse_file(opt, parse_sbios_line) ) return false; if ( nr_hashes == 0 ) { ERROR("Error: no hashes provided\n"); return false; } return true; } static lcp_policy_element_t *create(void) { /* take entire struct size and subtract size of fallback_hash because sizeof(lcp_hash_t) is not accurate (hence get_hash_size()), then add it back in w/ 'nr_hashes' */ size_t data_size = sizeof(lcp_sbios_element_t) - sizeof(lcp_hash_t) + nr_hashes * get_hash_size(TB_HALG_SHA1); lcp_policy_element_t *elt = malloc(sizeof(*elt) + data_size); if ( elt == NULL ) { ERROR("Error: failed to allocate element\n"); return NULL; } memset(elt, 0, sizeof(*elt) + data_size); elt->size = sizeof(*elt) + data_size; lcp_sbios_element_t *sbios = (lcp_sbios_element_t *)&elt->data; sbios->hash_alg = TB_HALG_SHA1; memcpy(&sbios->fallback_hash, &hashes[0], get_hash_size(TB_HALG_SHA1)); *get_num_hashes(sbios) = nr_hashes - 1; lcp_hash_t *hash = get_hashes(sbios); for ( unsigned int i = 1; i < nr_hashes; i++ ) { memcpy(hash, &hashes[i], get_hash_size(TB_HALG_SHA1)); hash = (void *)hash + get_hash_size(TB_HALG_SHA1); } return elt; } static void display(const char *prefix, const lcp_policy_element_t *elt) { lcp_sbios_element_t *sbios = (lcp_sbios_element_t *)elt->data; unsigned int hash_size = get_hash_size(sbios->hash_alg); DISPLAY("%s hash_alg: %s\n", prefix, hash_alg_to_str(sbios->hash_alg)); DISPLAY("%s fallback_hash: ", prefix); print_hex("", (tb_hash_t *)&sbios->fallback_hash, hash_size); DISPLAY("%s num_hashes: %u\n", prefix, *get_num_hashes(sbios)); uint8_t *hash = (uint8_t *)get_hashes(sbios); for ( unsigned int i = 0; i < *get_num_hashes(sbios); i++ ) { DISPLAY("%s hashes[%u]: ", prefix, i); print_hex("", hash, hash_size); hash += hash_size; } } static polelt_plugin_t plugin = { "sbios", NULL, " sbios\n" " [FILE2] ... one or more files containing BIOS\n" " hash(es); each file can contain\n" " multiple hashes; the first hash in\n" " the first file will be the fallback\n" " hash\n", LCP_POLELT_TYPE_SBIOS, &cmdline_handler, &create, &display }; REG_POLELT_PLUGIN(&plugin) /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/lcptools/writepol.c0000644000000000000000000001622212272416301014646 0ustar 00000000000000/* * Copyright 2001 - 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 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. */ /* * writepol.c * Command: lcp_writepol. * This command can write LCP policy into TPM NV Storage. */ #include #include #include #include #include #include #define PRINT printf #include "../include/uuid.h" #include "../include/lcp.h" #include "lcptools.h" #include "lcputils.h" static uint32_t index_value = 0; static char *file_arg=NULL; static uint32_t fLeng; static unsigned char *policy_data = NULL; static char *password = NULL; static uint32_t passwd_length = 0; static int help_input = 0; static unsigned char empty_pol_data[] = {0}; static const char *short_option = "ehi:f:p:"; static const char *usage_string = "lcp_writepol -i index_value " "[-f policy_file] [-e] [-p passwd] [-h]"; static const char *option_strings[] = { "-i index value: uint32/string.\n" "\tINDEX_LCP_DEF:0x50000001 or \"default\",\n" "\tINDEX_LCP_OWN:0x40000001 or \"owner\",\n" "\tINDEX_AUX:0x50000002 or \"aux\"\n", "-f file_name: string. File name of the policy data is stored. \n", "-p password: string. \n", "-e write 0 length data to the index.\n" "\tIt will be used for some special index.\n" "\tFor example, the index with permission WRITEDEFINE.\n", "-h help. Will print out this help message.\n", NULL }; static param_option_t index_option_table[] = { {"default", INDEX_LCP_DEF}, {"owner", INDEX_LCP_OWN}, {"aux", INDEX_AUX}, {NULL, -1} }; /* * function: parse_cmdline * description: parse the input of commandline */ static int parse_cmdline(int argc, const char * argv[]) { int c; while (((c = getopt(argc, (char ** const)argv, short_option)) != -1)) switch (c){ case 'i': /* check whether user inputs the string for reserved indices */ index_value = parse_input_option(index_option_table, optarg); /* * if not, then the users should input the non-0 number, * 0 is not allowed for index */ if ( index_value == (uint32_t)-1 ) if ( strtonum(optarg, &index_value) || (index_value == 0) ) return LCP_E_INVALID_PARAMETER; break; case 'f': file_arg = optarg; break; case 'p': password = optarg; passwd_length = strlen(password); break; case 'e': policy_data = empty_pol_data; fLeng = 0; break; case 'h': help_input = 1; break; default: return LCP_E_NO_SUCH_PARAMETER; } if ( optind < argc ) return LCP_E_INVALID_PARAMETER; return LCP_SUCCESS; } int main (int argc, char *argv[]) { char *file = NULL; FILE *p_file = NULL; lcp_result_t ret_value = LCP_E_COMD_INTERNAL_ERR; /* * No parameter input will print out the help message. */ if ( argc == 1 ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } /* * Parse the parameters input to decide * what parameters will be passed to TSS API. */ ret_value = parse_cmdline(argc, (const char **)argv); if ( ret_value ) goto exit; /* * If user input -h(help), just print guide to * users and ignore other parameters. */ if ( help_input ) { print_help(usage_string, option_strings); return LCP_SUCCESS; } if ( index_value == 0 ) { ret_value = LCP_E_NO_INDEXVALUE; goto exit; } if ( file_arg && (policy_data == NULL) ) file = file_arg; else if ( file_arg && (policy_data == empty_pol_data) ) { log_error("Cannot use '-f' and '-e' option at the same time!\n"); ret_value = LCP_E_INVALID_PARAMETER; goto exit; } if ( (file_arg == NULL) && (policy_data == NULL) ) { log_error("Must specify policy file name or use -e option! \n"); ret_value = LCP_E_INVALID_PARAMETER; goto exit; } if ( policy_data == NULL ) { p_file = fopen(file, "rb"); if ( !p_file ) { log_error("Open file %s error!\n", file); ret_value = LCP_E_COMD_INTERNAL_ERR; goto exit; } /* * Get length of file. */ fseek(p_file, 0, SEEK_END); fLeng = ftell(p_file); fseek(p_file, 0, SEEK_SET); policy_data = (unsigned char *)malloc(fLeng); if ( !policy_data ) { log_error("Memory alloc error!\n"); ret_value = LCP_E_OUTOFMEMORY; goto exit; } /* * Read policy data from file. */ if ( fLeng != fread(policy_data, 1, fLeng, p_file) ) { log_error("Read policy data from file error!\n"); ret_value = LCP_E_COMD_INTERNAL_ERR; goto exit; } } ret_value = lcp_write_index(index_value, password, passwd_length, 0, fLeng, policy_data); exit: if ( ret_value != LCP_SUCCESS ) { log_error("\nCommand WritePol failed:\n"); print_error(ret_value); } else { log_info("\nSuccessfully write policy into index 0x%08x \n", index_value); } if ( (policy_data != NULL) && (policy_data != empty_pol_data) ) free(policy_data); if ( p_file != NULL ) fclose(p_file); return ret_value; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tb_polgen/Makefile0000644000000000000000000000166312272416301014412 0ustar 00000000000000# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # tb_polgen makefile # ROOTDIR ?= $(CURDIR)/.. include $(ROOTDIR)/Config.mk TARGET = tb_polgen # libraries LIBS += -lcrypto -lz # # universal rules # build : $(TARGET) dist : install install : $(DISTDIR)/usr/sbin/$(TARGET) $(DISTDIR)/usr/sbin/$(TARGET) : $(TARGET) [ -d $(DISTDIR)/usr/sbin ] || $(INSTALL_DIR) $(DISTDIR)/usr/sbin $(INSTALL_PROG) -t $(DISTDIR)/usr/sbin $(TARGET) clean : rm -f *~ *.a *.so *.o *.rpm $(DEP_FILES) $(TARGET) mrproper : clean distclean : clean # # dependencies # $(TARGET) : tb_polgen.o commands.o policy.o param.o hash.o $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ # # implicit rules # HDRS := $(wildcard $(ROOTDIR)/include/*.h) $(wildcard $(CURDIR)/*.h) BUILD_DEPS := $(ROOTDIR)/Config.mk $(CURDIR)/Makefile %.o : %.c $(HDRS) $(BUILD_DEPS) $(CC) $(CFLAGS) -DNO_TBOOT_LOGLVL -c $< -o $@ tboot-1.8.0/tb_polgen/commands.c0000644000000000000000000002300612272416301014712 0ustar 00000000000000/* * commands.c: handlers for commands * * Copyright (c) 2006-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. * */ #include #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/uuid.h" #include "../include/lcp2.h" #include "../include/tb_error.h" #include "../include/tb_policy.h" #include "tb_polgen.h" extern tb_policy_t *g_policy; static bool hash_file(const char *filename, bool unzip, tb_hash_t *hash) { FILE *f; static char buf[1024]; EVP_MD_CTX ctx; const EVP_MD *md; int read_cnt; if ( unzip ) f = (FILE *)gzopen(filename, "rb"); else f = fopen(filename, "rb"); if ( f == NULL ) { error_msg("File %s does not exist\n", filename); return false; } md = EVP_sha1(); EVP_DigestInit(&ctx, md); do { if ( unzip ) read_cnt = gzread((gzFile)f, buf, sizeof(buf)); else read_cnt = fread(buf, 1, sizeof(buf), f); if ( read_cnt == 0 ) break; EVP_DigestUpdate(&ctx, buf, read_cnt); } while ( true ); EVP_DigestFinal(&ctx, hash->sha1, NULL); if ( unzip ) gzclose((gzFile)f); else fclose(f); return true; } bool do_show(const param_data_t *params) { /* read the policy file */ if ( !read_policy_file(params->policy_file, NULL) ) { error_msg("Error reading policy file %s\n", params->policy_file); return false; } /* this also displays it */ verify_policy(g_policy, calc_policy_size(g_policy), true); return true; } bool do_create(const param_data_t *params) { bool existing_policy = false; /* read the policy file, if it exists */ info_msg("reading existing policy file %s...\n", params->policy_file); if ( !read_policy_file(params->policy_file, &existing_policy) ) { /* this means there was an error reading an existing file */ if ( existing_policy ) { error_msg("Error reading policy file %s\n", params->policy_file); return false; } } /* policy_type must be specified for new policy */ if ( !existing_policy && params->policy_type == -1 ) { error_msg("Must specify --policy_type for new policy\n"); return false; } /* if file does not exist then create empty policy */ if ( !existing_policy ) new_policy(params->policy_type, params->policy_control); else modify_policy(params->policy_type, params->policy_control); info_msg("writing new policy file...\n"); if ( !write_policy_file(params->policy_file) ) return false; return true; } bool do_add(const param_data_t *params) { /* read the policy file, if it exists */ info_msg("reading existing policy file %s...\n", params->policy_file); if ( !read_policy_file(params->policy_file, NULL) ) { error_msg("Error reading policy file %s\n", params->policy_file); return false; } /* see if there is already an entry for this module */ tb_policy_entry_t *pol_entry = find_policy_entry(g_policy, params->mod_num); if ( pol_entry == NULL || pol_entry->mod_num != params->mod_num ) { /* since existing entry whose mod_num is TB_POL_MOD_NUM_ANY will */ /* match, exclude it unless that is what is being added */ pol_entry = add_pol_entry(params->mod_num, params->pcr, params->hash_type); if ( pol_entry == NULL ) { error_msg("cannot add another entry\n"); return false; } } else modify_pol_entry(pol_entry, params->pcr, params->hash_type); /* hash command line and files */ if ( params->hash_type == TB_HTYPE_IMAGE ) { EVP_MD_CTX ctx; const EVP_MD *md; tb_hash_t final_hash, hash; /* hash command line */ info_msg("hashing command line \"%s\"...\n", params->cmdline); md = EVP_sha1(); EVP_DigestInit(&ctx, md); EVP_DigestUpdate(&ctx, (unsigned char *)params->cmdline, strlen(params->cmdline)); EVP_DigestFinal(&ctx, (unsigned char *)&final_hash, NULL); if ( verbose ) { info_msg("hash is..."); print_hash(&final_hash, TB_HALG_SHA1); } /* hash file */ info_msg("hashing image file %s...\n", params->image_file); if ( !hash_file(params->image_file, true, &hash) ) return false; if ( verbose ) { info_msg("hash is..."); print_hash(&hash, TB_HALG_SHA1); } if ( !extend_hash(&final_hash, &hash, TB_HALG_SHA1) ) return false; if ( verbose ) { info_msg("cummulative hash is..."); print_hash(&final_hash, TB_HALG_SHA1); } if ( !add_hash(pol_entry, &final_hash) ) { error_msg("cannot add another hash\n"); return false; } } info_msg("writing new policy file...\n"); if ( !write_policy_file(params->policy_file) ) return false; return true; } bool do_del(const param_data_t *params) { /* read the policy file, if it exists */ info_msg("reading existing policy file %s...\n", params->policy_file); if ( !read_policy_file(params->policy_file, NULL) ) { error_msg("Error reading policy file %s\n", params->policy_file); return false; } /* see if there is an entry for this module */ tb_policy_entry_t *pol_entry = find_policy_entry(g_policy, params->mod_num); if ( pol_entry == NULL ) { error_msg("specified mod_num does not exist\n"); return false; } /* if pos was specified, find it */ if ( params->pos != -1 ) { if ( params->pos >= pol_entry->num_hashes ) { error_msg("specified pos does not exist\n"); return false; } /* if entry only has 1 hash, then delete the entire entry */ if ( pol_entry->num_hashes == 1 ) { if ( !del_entry(pol_entry) ) { error_msg("failed to delete entry\n"); return false; } } else { if ( !del_hash(pol_entry, params->pos) ) { error_msg("failed to delete hash\n"); return false; } } } else { if ( !del_entry(pol_entry) ) { error_msg("failed to delete entry\n"); return false; } } info_msg("writing new policy file...\n"); if ( !write_policy_file(params->policy_file) ) return false; return true; } bool do_unwrap(const param_data_t *params) { bool ret = false; /* read the elt file */ info_msg("reading existing elt file %s...\n", params->elt_file); size_t file_len; void *file = read_elt_file(params->elt_file, &file_len); if ( file == NULL ) { error_msg("Error reading elt file %s\n", params->elt_file); return false; } if ( sizeof(lcp_policy_element_t) > file_len ) { error_msg("data is too small\n"); goto exit; } lcp_policy_element_t *elt = (lcp_policy_element_t *)file; if ( file_len != elt->size ) { error_msg("data is too small\n"); goto exit; } if ( elt->type != LCP_POLELT_TYPE_CUSTOM ) { error_msg("Bad element type %u (i.e. non-custom)\n", elt->type); goto exit; } lcp_custom_element_t *custom = (lcp_custom_element_t *)&elt->data; tb_policy_t *pol = (tb_policy_t *)&custom->data; memcpy(g_policy, pol, calc_policy_size(pol)); info_msg("writing/overwriting policy file...\n"); if ( !write_policy_file(params->policy_file) ) goto exit; ret = true; exit: free(file); file = NULL; return ret; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tb_polgen/hash.c0000644000000000000000000001147112272416301014037 0ustar 00000000000000/* * hash.c: support functions for tb_hash_t type * * Copyright (c) 2006-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. * */ #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/tb_error.h" #include "../include/tb_policy.h" #include "tb_polgen.h" /* * are_hashes_equal * * compare whether two hash values are equal. * */ bool are_hashes_equal(const tb_hash_t *hash1, const tb_hash_t *hash2, uint16_t hash_alg) { if ( ( hash1 == NULL ) || ( hash2 == NULL ) ) { error_msg("Error: hash pointer is zero.\n"); return false; } if ( hash_alg == TB_HALG_SHA1 ) return (memcmp(hash1, hash2, SHA1_LENGTH) == 0); else { error_msg("unsupported hash alg (%d)\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 ) { error_msg("Error: There is no space for output hash.\n"); return false; } if ( hash_alg == TB_HALG_SHA1 ) { EVP_MD_CTX ctx; const EVP_MD *md; md = EVP_sha1(); EVP_DigestInit(&ctx, md); EVP_DigestUpdate(&ctx, buf, size); EVP_DigestFinal(&ctx, hash->sha1, NULL); return true; } else { error_msg("unsupported hash alg (%d)\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*sizeof(tb_hash_t)]; if ( hash1 == NULL || hash2 == NULL ) { error_msg("Error: There is no space for output hash.\n"); return false; } if ( hash_alg == TB_HALG_SHA1 ) { EVP_MD_CTX ctx; const EVP_MD *md; memcpy(buf, &(hash1->sha1), sizeof(hash1->sha1)); memcpy(buf + sizeof(hash1->sha1), &(hash2->sha1), sizeof(hash1->sha1)); md = EVP_sha1(); EVP_DigestInit(&ctx, md); EVP_DigestUpdate(&ctx, buf, 2*sizeof(hash1->sha1)); EVP_DigestFinal(&ctx, hash1->sha1, NULL); return true; } else { error_msg("unsupported hash alg (%d)\n", hash_alg); return false; } } void print_hash(const tb_hash_t *hash, uint16_t hash_alg) { if ( hash == NULL ) { error_msg("NULL"); return; } if ( hash_alg == TB_HALG_SHA1 ) { for ( unsigned int i = 0; i < sizeof(hash->sha1); i++ ) printf("%02x ", hash->sha1[i]); printf("\n"); } else { error_msg("unsupported hash alg (%d)\n", hash_alg); return; } } void copy_hash(tb_hash_t *dest_hash, const tb_hash_t *src_hash, uint16_t hash_alg) { if ( dest_hash == NULL || dest_hash == NULL ) { error_msg("hashes are NULL\n"); return; } if ( hash_alg == TB_HALG_SHA1 ) memcpy(dest_hash, src_hash, SHA1_LENGTH); else error_msg("unsupported hash alg (%d)\n", hash_alg); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tb_polgen/param.c0000644000000000000000000003744412272416301014224 0ustar 00000000000000/* * param.c: support functions for parsing command line parameters * * Copyright (c) 2006-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. * */ #include #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/tb_error.h" #include "../include/tb_policy.h" #include "tb_polgen.h" static const char *help[] = { "tb_polgen --create --type nonfatal|continue|halt\n", " [--ctrl ]\n", " [--verbose]\n", " \n", "tb_polgen --add --num |any\n", " --pcr |none\n", " --hash any|image\n", " [--cmdline \"command line\"]\n", " [--image ]\n", " [--verbose]\n", " \n", "tb_polgen --del --num |any\n", " [--pos ]\n", " [--verbose]\n", " \n", "tb_polgen --unwrap --elt \n", " [--verbose]\n", " \n", "tb_polgen --show [--verbose]\n", " \n", "tb_polgen --help\n", NULL }; /* * Define storage for user input parameter pointers */ bool verbose = false; static struct option long_options[] = { /* major sub-commands */ {"help", no_argument, NULL, 'H'}, {"create", no_argument, NULL, 'C'}, {"add", no_argument, NULL, 'A'}, {"del", no_argument, NULL, 'D'}, {"unwrap", no_argument, NULL, 'U'}, {"show", no_argument, NULL, 'S'}, {"type", required_argument, NULL, 't'}, {"ctrl", required_argument, NULL, 'c'}, {"num", required_argument, NULL, 'n'}, {"pcr", required_argument, NULL, 'p'}, {"hash", required_argument, NULL, 'h'}, {"cmdline", required_argument, NULL, 'l'}, {"image", required_argument, NULL, 'i'}, {"pos", required_argument, NULL, 'o'}, {"elt", required_argument, NULL, 'e'}, {"verbose", no_argument, (int*)&verbose, true}, {0, 0, 0, 0} }; typedef struct { const char *name; int int_opt; } option_table_t; static option_table_t policy_type_opts[] = { {"nonfatal", int_opt : TB_POLTYPE_CONT_NON_FATAL}, {"continue", int_opt : TB_POLTYPE_CONT_VERIFY_FAIL}, {"halt", int_opt : TB_POLTYPE_HALT}, {NULL} }; static option_table_t hash_type_opts[] = { {"image", int_opt : TB_HTYPE_IMAGE}, {"any", int_opt : TB_HTYPE_ANY}, {NULL} }; static option_table_t mod_num_opts[] = { {"any", int_opt : TB_POL_MOD_NUM_ANY}, {""}, {NULL} }; static option_table_t pcr_opts[] = { {"none", int_opt : TB_POL_PCR_NONE}, {""}, {NULL} }; static bool strtonum(char *optarg, int *i) { if ( optarg == NULL || i == NULL ) return false; errno = 0; char* p; unsigned int value = (unsigned int)strtoul(optarg, &p, 0); /* error if either no value or extra chars after value or out of range */ if ( *optarg == '\0' || *p != '\0' || errno != 0) return false; *i = value; return true; } static bool parse_int_option(option_table_t *table, char *optarg, int *option) { if ( option == NULL ) { info_msg("NULL option\n"); return false; } info_msg("optarg = %s\n", optarg); while ( table->name != NULL ) { /* matches keyword so return its value */ if ( strcasecmp(table->name, optarg) == 0 ) { *option = table->int_opt; return true; } /* no keyword match but numeric arg is allowed, so try to convert */ else if ( *table->name == '\0' ) return strtonum(optarg, option); table++; } return false; } void print_params(param_data_t *params) { info_msg("params:\n"); info_msg("\t cmd = %d\n", params->cmd); info_msg("\t policy_type = %d\n", params->policy_type); info_msg("\t policy_control = %d\n", params->policy_control); info_msg("\t mod_num = %d\n", params->mod_num); info_msg("\t pcr = %d\n", params->pcr); info_msg("\t hash_type = %d\n", params->hash_type); info_msg("\t pos = %d\n", params->pos); info_msg("\t cmdline length = %lu\n", strlen(params->cmdline)); info_msg("\t cmdline = %s\n", params->cmdline); info_msg("\t image_file = %s\n", params->image_file); info_msg("\t elt_file = %s\n", params->elt_file); info_msg("\t policy_file = %s\n", params->policy_file); } static bool validate_params(param_data_t *params) { const char *msg = NULL; switch( params->cmd ) { case POLGEN_CMD_NONE: msg = "Missing command argument\n"; goto error; case POLGEN_CMD_CREATE: /* these are required in all cases */ if ( strlen(params->policy_file) == 0 ) { msg = "Missing policy file\n"; goto error; } if ( params->policy_type == -1 ) { msg = "Missing policy type\n"; goto error; } if ( (params->policy_control & ~TB_POLCTL_EXTEND_PCR17) != 0 ) { msg = "Invalid --ctrl value\n"; goto error; } return true; case POLGEN_CMD_ADD: /* these are required in all cases */ if ( strlen(params->policy_file) == 0 ) { msg = "Missing policy file\n"; goto error; } /* if hash_type is not ANY then need an image file */ if ( params->hash_type != TB_HTYPE_ANY && strlen(params->image_file) == 0 ) { msg = "Missing --image option\n"; goto error; } /* if hash_type is ANY then no need for an image file */ if ( params->hash_type == TB_HTYPE_ANY && strlen(params->image_file) != 0 ) { msg = "Extra --image option\n"; goto error; } if ( params->hash_type == -1 ) { msg = "Missing --hash option\n"; goto error; } if ( (params->pcr < 0 || params->pcr > TB_POL_MAX_PCR) && params->pcr != TB_POL_PCR_NONE ) { msg = "Invalid --pcr value\n"; goto error; } if ( (params->mod_num < 0 || params->mod_num > TB_POL_MAX_MOD_NUM) && params->mod_num != TB_POL_MOD_NUM_ANY ) { msg = "Invalid --num value\n"; goto error; } return true; case POLGEN_CMD_DEL: /* these are required in all cases */ if ( strlen(params->policy_file) == 0 ) { msg = "Missing policy file\n"; goto error; } if ( (params->mod_num < 0 || params->mod_num > TB_POL_MAX_MOD_NUM) && params->mod_num != TB_POL_MOD_NUM_ANY ) { msg = "Invalid --num value\n"; goto error; } return true; case POLGEN_CMD_UNWRAP: if ( strlen(params->policy_file) == 0 ) { msg = "Missing policy file\n"; goto error; } if ( strlen(params->elt_file) == 0 ) { msg = "Missing elt file\n"; goto error; } return true; case POLGEN_CMD_SHOW: if ( strlen(params->policy_file) == 0 ) { msg = "Missing policy file\n"; goto error; } return true; case POLGEN_CMD_HELP: return true; default: msg = "Unknown command\n"; goto error; } error: error_msg("%s", msg); if ( verbose ) print_params(params); return false; } #define HANDLE_MULTIPLE_CMDS(cmd) \ if ( (cmd) != POLGEN_CMD_NONE ) { \ error_msg("Only one command can be specified\n"); \ return false; \ } bool parse_input_params(int argc, char **argv, param_data_t *params) { int c; int option_index = 0; /* defaults */ params->cmd = POLGEN_CMD_NONE; params->mod_num = -1; params->pcr = -1; params->policy_type = -1; params->policy_control = TB_POLCTL_EXTEND_PCR17; params->hash_type = -1; params->policy_file[0] = '\0'; params->cmdline[0] = '\0'; params->image_file[0] = '\0'; params->elt_file[0] = '\0'; while ( true ) { c = getopt_long_only(argc, argv, "HCADUSt:c:n:p:h:l:i:o:e:", long_options, &option_index); if ( c == -1 ) /* no more args */ break; switch (c) { /* commands */ case 'H': /* --help */ HANDLE_MULTIPLE_CMDS(params->cmd); params->cmd = POLGEN_CMD_HELP; return true; case 'C': /* --create */ HANDLE_MULTIPLE_CMDS(params->cmd); params->cmd = POLGEN_CMD_CREATE; break; case 'A': /* --add */ HANDLE_MULTIPLE_CMDS(params->cmd); params->cmd = POLGEN_CMD_ADD; break; case 'D': /* --del */ HANDLE_MULTIPLE_CMDS(params->cmd); params->cmd = POLGEN_CMD_DEL; break; case 'U': /* --unwrap */ HANDLE_MULTIPLE_CMDS(params->cmd); params->cmd = POLGEN_CMD_UNWRAP; break; case 'S': /* --show */ HANDLE_MULTIPLE_CMDS(params->cmd); params->cmd = POLGEN_CMD_SHOW; break; /* options */ case 'n': /* --num */ if ( !parse_int_option(mod_num_opts, optarg, (int *)¶ms->mod_num) ) { error_msg("Unknown --num option\n"); return false; } break; case 'p': /* --pcr */ if ( !parse_int_option(pcr_opts, optarg, (int *)¶ms->pcr) ) { error_msg("Unknown --pcr option\n"); return false; } break; case 't': /* --type */ if ( !parse_int_option(policy_type_opts, optarg, (int *)¶ms->policy_type) ) { error_msg("Unknown --type option\n"); return false; } break; case 'c': /* --ctrl */ if ( !strtonum(optarg, ¶ms->policy_control) ) { error_msg("Unknown --ctrl option\n"); return false; } break; case 'h': /* --hash */ if ( !parse_int_option(hash_type_opts, optarg, (int *)¶ms->hash_type) ) { error_msg("Unknown --hash option\n"); return false; } break; case 'o': /* --pos */ if ( !strtonum(optarg, ¶ms->pos) ) { error_msg("Unknown --pos option\n"); return false; } break; case 'i': /* --image */ if ( optarg == NULL ) { error_msg("Misssing filename for --image option\n"); return false; } strncpy(params->image_file, optarg, sizeof(params->image_file)); params->image_file[sizeof(params->image_file)-1] = '\0'; break; case 'l': /* --cmdline */ if ( optarg == NULL ) { error_msg("Misssing string for --cmdline option\n"); return false; } if (strlen(optarg) > sizeof(params->cmdline) - 1) { error_msg("Command line length of %lu exceeds %d " "character maximum\n", strlen(optarg), TBOOT_KERNEL_CMDLINE_SIZE-1); return false; } strncpy(params->cmdline, optarg, sizeof(params->cmdline)); params->cmdline[sizeof(params->cmdline)-1] = '\0'; break; case 'e': /* --elt */ if ( optarg == NULL ) { error_msg("Missing filename for --elt option\n"); return false; } strncpy(params->elt_file, optarg, sizeof(params->elt_file)); params->elt_file[sizeof(params->elt_file)-1] = '\0'; break; default: break; } } /* last argument is policy file */ if ( optind >= argc ){ error_msg("Missing filename for policy file\n"); return false; } strncpy(params->policy_file, argv[optind], sizeof(params->policy_file)); params->policy_file[sizeof(params->policy_file)-1] = '\0'; return validate_params(params); } void display_help_msg(void) { for ( int i = 0; help[i] != NULL; i++ ) printf("%s", help[i]); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tb_polgen/policy.c0000644000000000000000000001707612272416301014422 0ustar 00000000000000/* * policy.c: policy support functions * * Copyright (c) 2006-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. * */ #include #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/tb_error.h" #include "../include/tb_policy.h" #include "tb_polgen.h" /* buffer for policy read/written from/to policy file */ static uint8_t _policy_buf[MAX_TB_POLICY_SIZE]; tb_policy_t *g_policy = (tb_policy_t *)_policy_buf; void *read_elt_file(const char *elt_filename, size_t *length) { FILE *fp = fopen(elt_filename, "rb"); if ( fp == NULL ) { error_msg("fopen %s failed, errno %s\n", elt_filename, strerror(errno)); return NULL; } /* find size */ fseek(fp, 0, SEEK_END); long len = ftell(fp); rewind(fp); void *data = malloc(len); if ( data == NULL ) { error_msg("failed to allocate %ld bytes memory\n", len); fclose(fp); return NULL; } if ( fread(data, len, 1, fp) != 1 ) { error_msg("reading file %s failed, errono %s\n", elt_filename, strerror(errno)); free(data); fclose(fp); return NULL; } fclose(fp); if ( length != NULL ) *length = len; return data; } bool read_policy_file(const char *policy_filename, bool *file_exists) { FILE *f = fopen(policy_filename, "r"); if ( f == NULL ) { if ( file_exists != NULL ) *file_exists = (errno != ENOENT); info_msg("fopen failed, errno %s\n", strerror(errno)); return false; } if ( file_exists != NULL ) *file_exists = true; /* clear for good measure */ memset(_policy_buf, 0, sizeof(_policy_buf)); size_t read_cnt = fread(_policy_buf, 1, sizeof(_policy_buf), f); if ( ferror(f) ) { error_msg("fread failed, errno %s\n", strerror(errno)); fclose(f); return false; } if ( read_cnt == 0 ) { error_msg("Policy file %s is empty\n", policy_filename); fclose(f); return false; } fclose(f); if ( !verify_policy(g_policy, read_cnt, verbose) ) { error_msg("Policy file %s is corrupt\n", policy_filename); return false; } return true; } bool write_policy_file(const char *policy_filename) { verify_policy(g_policy, sizeof(_policy_buf), verbose); FILE *f = fopen(policy_filename, "w"); if ( f == NULL ) { info_msg("fopen failed, errno %s\n", strerror(errno)); return false; } size_t pol_size = calc_policy_size(g_policy); size_t write_cnt = fwrite(_policy_buf, 1, pol_size, f); if ( write_cnt != pol_size ) { info_msg("error writing policy, errno %s\n", strerror(errno)); fclose(f); return false; } fclose(f); return true; } void new_policy(int policy_type, int policy_control) { /* current version is 2 */ g_policy->version = 2; g_policy->hash_alg = TB_HALG_SHA1; g_policy->num_entries = 0; modify_policy(policy_type, policy_control); } void modify_policy(int policy_type, int policy_control) { if ( policy_type != -1 ) g_policy->policy_type = policy_type; g_policy->policy_control = (uint32_t)policy_control; } tb_policy_entry_t *add_pol_entry(uint8_t mod_num, uint8_t pcr, uint8_t hash_type) { /* assumes check for existing mod_num already done */ info_msg("adding new policy entry for mod_num %u (pcr: %u, " "hash_type: %u)\n", mod_num, pcr, hash_type); /* TODO: if there is already a MOD_NUM_ANY entry then insert this */ /* new one before it */ /* always goes at end of policy, so no need to make space, */ /* just find end of policy data */ size_t size = calc_policy_size(g_policy); if ( size + sizeof(tb_policy_entry_t) > sizeof(_policy_buf) ) return NULL; tb_policy_entry_t *pol_entry = (tb_policy_entry_t *)(_policy_buf + size); pol_entry->mod_num = mod_num; pol_entry->pcr = pcr; pol_entry->hash_type = hash_type; pol_entry->num_hashes = 0; g_policy->num_entries++; return pol_entry; } void modify_pol_entry(tb_policy_entry_t *pol_entry, uint8_t pcr, uint8_t hash_type) { if ( pol_entry == NULL ) return; info_msg("modifying policy entry for mod_num %u\n", pol_entry->mod_num); pol_entry->pcr = pcr; pol_entry->hash_type = hash_type; } bool add_hash(tb_policy_entry_t *pol_entry, const tb_hash_t *hash) { if ( pol_entry == NULL ) return false; /* since pol_entry may not be last in policy, need to make space */ size_t pol_size = calc_policy_size(g_policy); size_t hash_size = get_hash_size(g_policy->hash_alg); if ( pol_size + hash_size > sizeof(_policy_buf) ) return false; unsigned char *entry_end = (unsigned char *)pol_entry + sizeof(*pol_entry) + (pol_entry->num_hashes * hash_size); unsigned char *pol_end = _policy_buf + pol_size; memmove(entry_end + hash_size, entry_end, pol_end - entry_end); copy_hash((tb_hash_t *)entry_end, hash, g_policy->hash_alg); pol_entry->num_hashes++; return true; } bool del_hash(tb_policy_entry_t *pol_entry, int i) { if ( pol_entry == NULL ) return false; if ( i < 0 || i >= pol_entry->num_hashes ) return false; void *start = get_policy_entry_hash(pol_entry, g_policy->hash_alg, i); size_t size = get_hash_size(g_policy->hash_alg); memmove(start, start + size, calc_policy_size(g_policy) - size); pol_entry->num_hashes--; return true; } bool del_entry(tb_policy_entry_t *pol_entry) { if ( pol_entry == NULL ) return false; void *start = pol_entry; size_t size = calc_policy_entry_size(pol_entry, g_policy->hash_alg); memmove(start, start + size, calc_policy_size(g_policy) - size); g_policy->num_entries--; return true; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tb_polgen/tb_polgen.c0000644000000000000000000000553112272416301015065 0ustar 00000000000000/* * tb_polgen.c: policy generation tool for tboot * * Copyright (c) 2006-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. * */ #include #include #include #include #include #define PRINT printf #include "../include/config.h" #include "../include/hash.h" #include "../include/tb_error.h" #include "../include/tb_policy.h" #include "tb_polgen.h" int main (int argc, char *argv[]) { param_data_t params; bool ret; if ( !parse_input_params(argc, argv, ¶ms) ) return 1; print_params(¶ms); switch ( params.cmd ) { case POLGEN_CMD_CREATE: ret = do_create(¶ms); break; case POLGEN_CMD_ADD: ret = do_add(¶ms); break; case POLGEN_CMD_DEL: ret = do_del(¶ms); break; case POLGEN_CMD_UNWRAP: ret = do_unwrap(¶ms); break; case POLGEN_CMD_SHOW: ret = do_show(¶ms); break; case POLGEN_CMD_HELP: display_help_msg(); ret = true; break; default: ret = false; break; } return (ret ? 0 : 1); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tb_polgen/tb_polgen.h0000644000000000000000000000752412272416301015076 0ustar 00000000000000/* * tb_polgen.h: types and definitions for tb_polgen * * 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_POLGEN_H__ #define __TB_POLGEN_H__ extern bool verbose; #define error_msg(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) #define info_msg(fmt, ...) if (verbose) printf(fmt , ##__VA_ARGS__) #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) typedef enum { POLGEN_CMD_NONE, POLGEN_CMD_HELP, POLGEN_CMD_CREATE, POLGEN_CMD_ADD, POLGEN_CMD_DEL, POLGEN_CMD_UNWRAP, POLGEN_CMD_SHOW, } polgen_cmd_t; typedef struct { polgen_cmd_t cmd; int policy_type; int policy_control; int mod_num; int pcr; int hash_type; int pos; char cmdline[TBOOT_KERNEL_CMDLINE_SIZE]; char image_file[FILENAME_MAX]; char elt_file[FILENAME_MAX]; char policy_file[FILENAME_MAX]; } param_data_t; /* in param.c */ extern bool parse_input_params(int argc, char **argv, param_data_t *params); extern void display_help_msg(void); extern void print_params(param_data_t *params); /* in commands.c */ extern bool do_create(const param_data_t *params); extern bool do_add(const param_data_t *params); extern bool do_del(const param_data_t *params); extern bool do_unwrap(const param_data_t *params); extern bool do_show(const param_data_t *params); /* in policy.c */ extern void *read_elt_file(const char *elt_filename, size_t *length); extern bool read_policy_file(const char *policy_filename, bool *file_exists); extern bool write_policy_file(const char *policy_filename); extern void new_policy(int policy_type, int policy_control); extern void modify_policy(int policy_type, int policy_control); extern tb_policy_entry_t *add_pol_entry(uint8_t mod_num, uint8_t pcr, uint8_t hash_type); extern void modify_pol_entry(tb_policy_entry_t *pol_entry, uint8_t pcr, uint8_t hash_type); extern bool add_hash(tb_policy_entry_t *pol_entry, const tb_hash_t *hash); extern bool del_hash(tb_policy_entry_t *pol_entry, int i); extern bool del_entry(tb_policy_entry_t *pol_entry); #endif /* __TB_POLGEN_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/20_linux_tboot0000644000000000000000000001503312272416301014716 0ustar 00000000000000#! /bin/sh set -e # grub-mkconfig helper script. # Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. # # GRUB is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # GRUB is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GRUB. If not, see . prefix=/usr exec_prefix=${prefix} bindir=${exec_prefix}/bin libdir=${exec_prefix}/lib if test -e /usr/share/grub/grub-mkconfig_lib; then . /usr/share/grub/grub-mkconfig_lib elif test -e ${libdir}/grub/grub-mkconfig_lib; then . ${libdir}/grub/grub-mkconfig_lib fi export TEXTDOMAIN=grub export TEXTDOMAINDIR=${prefix}/share/locale CLASS="--class gnu-linux --class gnu --class os --class tboot" if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then OS=GNU/Linux else OS="${GRUB_DISTRIBUTOR} GNU/Linux" CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr '[A-Z]' '[a-z]' | cut -d' ' -f1) ${CLASS}" fi # loop-AES arranges things so that /dev/loop/X can be our root device, but # the initrds that Linux uses don't like that. case ${GRUB_DEVICE} in /dev/loop/*|/dev/loop[0-9]) GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"` # We can't cope with devices loop-mounted from files here. case ${GRUB_DEVICE} in /dev/*) ;; *) exit 0 ;; esac ;; esac if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \ || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \ || uses_abstraction "${GRUB_DEVICE}" lvm; then LINUX_ROOT_DEVICE=${GRUB_DEVICE} else LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} fi linux_entry () { os="$1" version="$2" tboot_version="$3" recovery="$4" args="$5" tboot_args="$6" iommu_args="$7" if ${recovery} ; then title="$(gettext_quoted "%s, with tboot %s and Linux %s (recovery mode)")" else title="$(gettext_quoted "%s, with tboot %s and Linux %s")" fi if [ -d /sys/firmware/efi ] ; then mb_directive="multiboot2" mb_mod_directive="module2" mb_extra_kernel="noefi" else mb_directive="multiboot" mb_mod_directive="module" mb_extra_kernel="" fi printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${tboot_version}" "${version}" if ! ${recovery} ; then save_default_entry | sed -e "s/^/\t/" fi if [ -d /sys/firmware/efi ] ; then printf "\tinsmod multiboot2\n" fi if [ -z "${prepare_boot_cache}" ]; then prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" fi printf '%s\n' "${prepare_boot_cache}" xmessage="$(gettext_printf "Loading tboot %s ..." ${tboot_version})" lmessage="$(gettext_printf "Loading Linux %s ..." ${version})" cat << EOF echo '$xmessage' ${mb_directive} ${rel_tboot_dirname}/${tboot_basename} ${rel_tboot_dirname}/${tboot_basename} ${tboot_args} echo '$lmessage' ${mb_mod_directive} ${rel_dirname}/${basename} ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args} ${iommu_args} ${mb_extra_kernel} EOF if test -n "${initrd}" ; then message="$(gettext_printf "Loading initial ramdisk ...")" cat << EOF echo '$message' ${mb_mod_directive} ${rel_dirname}/${initrd} ${rel_dirname}/${initrd} EOF fi if test -n "${sinit_list}" ; then for i in ${sinit_list}; do message="$(gettext_printf "Loading sinit $i ...")" cat << EOF echo '$message' ${mb_mod_directive} ${rel_dirname}/${i} ${rel_dirname}/${i} EOF done fi cat << EOF } EOF } linux_list=`for i in /boot/vmlinu[xz]-* /vmlinu[xz]-* ; do basename=$(basename $i) version=$(echo $basename | sed -e "s,^[^0-9]*-,,g") if grub_file_is_not_garbage "$i" && grep -qx "CONFIG_INTEL_TXT=y" /boot/config-${version} 2> /dev/null ; then echo -n "$i " ; fi done` tboot_list=`for i in /boot/tboot*.gz; do if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi done` sinit_list=`for i in /boot/*sinit* /boot/*SINIT*; do basename=$(basename $i) if grub_file_is_not_garbage "$i" ; then echo -n "$basename " ; fi done` prepare_boot_cache= while [ "x${tboot_list}" != "x" ] && [ "x$linux_list" != "x" ] ; do list="${linux_list}" current_tboot=`version_find_latest $tboot_list` tboot_basename=`basename ${current_tboot}` tboot_dirname=`dirname ${current_tboot}` rel_tboot_dirname=`make_system_path_relative_to_its_root $tboot_dirname` # tboot_version=`echo $tboot_basename | sed -e "s,.gz$,,g;s,^tboot-,,g"` tboot_version="1.7.0" echo "submenu \"tboot ${tboot_version}\" {" while [ "x$list" != "x" ] ; do linux=`version_find_latest $list` echo "Found linux image: $linux" >&2 basename=`basename $linux` dirname=`dirname $linux` rel_dirname=`make_system_path_relative_to_its_root $dirname` version=`echo $basename | sed -e "s,^[^0-9]*-,,g"` alt_version=`echo $version | sed -e "s,\.old$,,g"` linux_root_device_thisversion="${LINUX_ROOT_DEVICE}" initrd= for i in "initrd.img-${version}" "initrd-${version}.img" \ "initrd-${version}" "initramfs-${version}.img" \ "initrd.img-${alt_version}" "initrd-${alt_version}.img" \ "initrd-${alt_version}" "initramfs-${alt_version}.img" \ "initramfs-genkernel-${version}" \ "initramfs-genkernel-${alt_version}"; do if test -e "${dirname}/${i}" ; then initrd="$i" break fi done if test -n "${initrd}" ; then echo "Found initrd image: ${dirname}/${initrd}" >&2 else # "UUID=" magic is parsed by initrds. Since there's no initrd, it can't work here. linux_root_device_thisversion=${GRUB_DEVICE} fi if [ -d /sys/firmware/efi ] ; then # there's no vga console available under EFI tboot_log="logging=serial,memory" else tboot_log="logging=serial,vga,memory" fi linux_entry "${OS}" "${version}" "${tboot_version}" false \ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" ${tboot_log} "intel_iommu=on" if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then linux_entry "${OS}" "${version}" "${tboot_version}" true \ "single ${GRUB_CMDLINE_LINUX}" ${tboot_log} "intel_iommu=on" fi list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '` done echo "}" tboot_list=`echo $tboot_list | tr ' ' '\n' | grep -vx $current_tboot | tr '\n' ' '` done tboot-1.8.0/tboot/20_linux_xen_tboot0000644000000000000000000002026012272416301015566 0ustar 00000000000000#! /bin/sh set -e # grub-mkconfig helper script. # Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. # # GRUB is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # GRUB is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GRUB. If not, see . prefix=/usr exec_prefix=${prefix} bindir=${exec_prefix}/bin libdir=${exec_prefix}/lib if test -e /usr/share/grub/grub-mkconfig_lib; then . /usr/share/grub/grub-mkconfig_lib elif test -e ${libdir}/grub/grub-mkconfig_lib; then . ${libdir}/grub/grub-mkconfig_lib fi export TEXTDOMAIN=grub export TEXTDOMAINDIR=${prefix}/share/locale CLASS="--class gnu-linux --class gnu --class os --class xen" if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then OS=GNU/Linux else OS="${GRUB_DISTRIBUTOR} GNU/Linux" CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1) ${CLASS}" fi # loop-AES arranges things so that /dev/loop/X can be our root device, but # the initrds that Linux uses don't like that. case ${GRUB_DEVICE} in /dev/loop/*|/dev/loop[0-9]) GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"` # We can't cope with devices loop-mounted from files here. case ${GRUB_DEVICE} in /dev/*) ;; *) exit 0 ;; esac ;; esac if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \ || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \ || uses_abstraction "${GRUB_DEVICE}" lvm; then LINUX_ROOT_DEVICE=${GRUB_DEVICE} else LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} fi # Allow overriding GRUB_CMDLINE_LINUX and GRUB_CMDLINE_LINUX_DEFAULT. if [ "${GRUB_CMDLINE_LINUX_XEN_REPLACE}" ]; then GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX_XEN_REPLACE}" fi if [ "${GRUB_CMDLINE_LINUX_XEN_REPLACE_DEFAULT}" ]; then GRUB_CMDLINE_LINUX_DEFAULT="${GRUB_CMDLINE_LINUX_XEN_REPLACE_DEFAULT}" fi if [ "x`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2>/dev/null || true`" = xbtrfs ] \ || [ "x`stat -f --printf=%T /`" = xbtrfs ]; then rootsubvol="`make_system_path_relative_to_its_root /`" rootsubvol="${rootsubvol#/}" if [ "x${rootsubvol}" != x ]; then GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}" fi fi linux_entry () { os="$1" version="$2" xen_version="$3" recovery="$4" args="$5" xen_args="$6" tboot_version="$7" tboot_args="$8" iommu_args="$9" if ${recovery} ; then title="$(gettext_quoted "%s, with Xen %s, Tboot %s and Linux %s (recovery mode)")" else title="$(gettext_quoted "%s, with Xen %s, Tboot %s and Linux %s")" fi printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${xen_version}" "${tboot_version}" "${version}" if ! ${recovery} ; then save_default_entry | sed -e "s/^/\t/" fi if [ -z "${prepare_boot_cache}" ]; then prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" fi printf '%s\n' "${prepare_boot_cache}" xmessage="$(gettext_printf "Loading Xen %s ..." ${xen_version})" tmessage="$(gettext_printf "Loading Tboot %s ..." ${tboot_version})" lmessage="$(gettext_printf "Loading Linux %s ..." ${version})" cat << EOF echo '$tmessage' multiboot ${rel_tboot_dirname}/${tboot_basename} ${rel_tboot_dirname}/${tboot_basename} ${tboot_args} echo '$xmessage' module ${rel_xen_dirname}/${xen_basename} ${rel_xen_dirname}/${xen_basename} placeholder ${xen_args} ${iommu_args} echo '$lmessage' module ${rel_dirname}/${basename} ${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args} EOF if test -n "${initrd}" ; then message="$(gettext_printf "Loading initial ramdisk ...")" cat << EOF echo '$message' module ${rel_dirname}/${initrd} ${rel_dirname}/${initrd} EOF fi if test -n "${sinit_list}" ; then for i in ${sinit_list}; do message="$(gettext_printf "Loading sinit $i ...")" cat << EOF echo '$message' module ${rel_dirname}/${i} ${rel_dirname}/${i} EOF done fi cat << EOF } EOF } linux_list=`for i in /boot/vmlinu[xz]-* /vmlinu[xz]-* /boot/kernel-*; do if grub_file_is_not_garbage "$i"; then basename=$(basename $i) version=$(echo $basename | sed -e "s,^[^0-9]*-,,g") dirname=$(dirname $i) config= for j in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do if test -e "${j}" ; then config="${j}" break fi done if (grep -qx "CONFIG_XEN_DOM0=y" "${config}" 2> /dev/null || grep -qx "CONFIG_XEN_PRIVILEGED_GUEST=y" "${config}" 2> /dev/null); then echo -n "$i " ; fi fi done` if [ "x${linux_list}" = "x" ] ; then exit 0 fi xen_list=`for i in /boot/xen*; do if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi done` tboot_list=`for i in /boot/tboot*.gz; do if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi done` sinit_list=`for i in /boot/*sinit* /boot/*SINIT*; do basename=$(basename $i) if grub_file_is_not_garbage "$i" ; then echo -n "$basename " ; fi done` prepare_boot_cache= while [ "x${xen_list}" != "x" ] ; do current_xen=`version_find_latest $xen_list` xen_basename=`basename ${current_xen}` xen_dirname=`dirname ${current_xen}` rel_xen_dirname=`make_system_path_relative_to_its_root $xen_dirname` xen_version=`echo $xen_basename | sed -e "s,.gz$,,g;s,^xen-,,g"` tlist="${tboot_list}" while [ "x${tlist}" != "x" ] && [ "x$linux_list" != "x" ] ; do current_tboot=`version_find_latest $tlist` tboot_basename=`basename ${current_tboot}` tboot_dirname=`dirname ${current_tboot}` rel_tboot_dirname=`make_system_path_relative_to_its_root $tboot_dirname` tboot_version="1.7.0" list="${linux_list}" echo "submenu \"Xen ${xen_version}\" \"Tboot ${tboot_version}\"{" while [ "x$list" != "x" ] ; do linux=`version_find_latest $list` echo "Found linux image: $linux" >&2 basename=`basename $linux` dirname=`dirname $linux` rel_dirname=`make_system_path_relative_to_its_root $dirname` version=`echo $basename | sed -e "s,^[^0-9]*-,,g"` alt_version=`echo $version | sed -e "s,\.old$,,g"` linux_root_device_thisversion="${LINUX_ROOT_DEVICE}" initrd= for i in "initrd.img-${version}" "initrd-${version}.img" \ "initrd-${version}" "initrd.img-${alt_version}" \ "initrd-${alt_version}.img" "initrd-${alt_version}" \ "initramfs-genkernel-${version}" \ "initramfs-genkernel-${alt_version}" ; do if test -e "${dirname}/${i}" ; then initrd="$i" break fi done if test -n "${initrd}" ; then echo "Found initrd image: ${dirname}/${initrd}" >&2 else # "UUID=" magic is parsed by initrds. Since there's no initrd, it can't work here. linux_root_device_thisversion=${GRUB_DEVICE} fi linux_entry "${OS}" "${version}" "${xen_version}" false \ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" "${GRUB_CMDLINE_XEN} ${GRUB_CMDLINE_XEN_DEFAULT}" "${tboot_version}" "logging=serial,vga,memory" "iommu=force" if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then linux_entry "${OS}" "${version}" "${xen_version}" true \ "single ${GRUB_CMDLINE_LINUX}" "${GRUB_CMDLINE_XEN}" "${tboot_version}" "logging=serial,vga,memory" "iommu=force" fi list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '` done echo "}" tlist=`echo $tlist | tr ' ' '\n' | grep -vx $current_tboot | tr '\n' ' '` done xen_list=`echo $xen_list | tr ' ' '\n' | grep -vx $current_xen | tr '\n' ' '` done tboot-1.8.0/tboot/Config.mk0000644000000000000000000000277512272416301013673 0ustar 00000000000000# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # tboot-specific build settings # ROOTDIR ?= $(CURDIR)/.. # tboot needs too many customized compiler settings to use system CFLAGS, # so if environment wants to set any compiler flags, it must use TBOOT_CFLAGS CFLAGS := $(TBOOT_CFLAGS) include $(ROOTDIR)/Config.mk # if target arch is 64b, then convert -m64 to -m32 (tboot is always 32b) CFLAGS := $(shell echo $(CFLAGS) | sed -e s/-m64/-m32/) CFLAGS += -march=i686 CFLAGS += -nostdinc CFLAGS += -fno-builtin -fno-common -fno-strict-aliasing CFLAGS += -fomit-frame-pointer CFLAGS += -pipe CFLAGS += -iwithprefix include CFLAGS += -I$(CURDIR)/include -I$(ROOTDIR)/include # ensure no floating-point variables CFLAGS += -msoft-float # Disable PIE/SSP if GCC supports them. They can break us. CFLAGS += $(call cc-option,$(CC),-nopie,) CFLAGS += $(call cc-option,$(CC),-fno-stack-protector,) CFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,) # changeset variable for banner CFLAGS += -DTBOOT_CHANGESET=\""$(shell ((hg parents --template "{isodate|isodate} {rev}:{node|short}" >/dev/null && hg parents --template "{isodate|isodate} {rev}:{node|short}") || echo "2014-01-30 12:00 +0800 1.8.0") 2>/dev/null)"\" AFLAGS += -D__ASSEMBLY__ # Most CFLAGS are safe for assembly files: # -std=gnu{89,99} gets confused by #-prefixed end-of-line comments AFLAGS += $(patsubst -std=gnu%,,$(CFLAGS)) # LDFLAGS are only passed directly to $(LD) LDFLAGS = -melf_i386 tboot-1.8.0/tboot/Makefile0000644000000000000000000000662512272416301013573 0ustar 00000000000000# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # tboot makefile # include $(CURDIR)/Config.mk TARGET := $(CURDIR)/tboot # boot.o must be first obj-y := common/boot.o obj-y += common/acpi.o common/cmdline.o common/com.o common/e820.o obj-y += common/elf.o common/hash.o common/index.o common/integrity.o obj-y += common/linux.o common/loader.o common/memcmp.o common/memcpy.o obj-y += common/misc.o common/mutex.o common/paging.o common/pci_cfgreg.o obj-y += common/policy.o common/printk.o common/rijndael.o common/sha1.o obj-y += common/strcmp.o common/strlen.o common/strncmp.o common/strncpy.o obj-y += common/strtoul.o common/tb_error.o common/tboot.o common/tpm.o obj-y += common/vga.o common/vmac.o common/vsprintf.o obj-y += txt/acmod.o txt/errors.o txt/heap.o txt/mtrrs.o txt/txt.o obj-y += txt/verify.o txt/vmcs.o obj-y += common/tpm_12.o common/tpm_20.o obj-y += common/sha256.o OBJS := $(obj-y) TARGET_LDS := $(CURDIR)/common/tboot.lds $(TARGET).gz : $(TARGET) gzip -f -9 < $< > $@ $(TARGET) : $(OBJS) $(TARGET_LDS) $(LD) $(LDFLAGS) -T $(TARGET_LDS) -N $(OBJS) -o $(@D)/.$(@F).0 $(NM) -n $(@D)/.$(@F).0 >$(TARGET)-syms $(LD) $(LDFLAGS) -T $(TARGET_LDS) $(LDFLAGS_STRIP) $(@D)/.$(@F).0 -o $(TARGET) rm -f $(@D)/.$(@F).0 $(TARGET_LDS) : $(TARGET_LDS).x $(HDRS) $(CPP) -P -E -Ui386 $(AFLAGS) -o $@ $< $(TARGET_LDS).x : FORCE # # universal rules # dist : install build : $(TARGET).gz install : $(DISTDIR)/boot/$(TARGET).gz $(DISTDIR)/boot/$(TARGET).gz : $(TARGET).gz [ -d $(DISTDIR)/boot ] || $(INSTALL_DIR) $(DISTDIR)/boot $(INSTALL_DATA) $(TARGET).gz $(DISTDIR)/boot/$(notdir $(TARGET)).gz $(INSTALL_DATA) $(TARGET)-syms $(DISTDIR)/boot/$(notdir $(TARGET))-syms [ -d $(DISTDIR)/etc/grub.d ] || $(INSTALL_DIR) $(DISTDIR)/etc/grub.d $(INSTALL) -m755 -t $(DISTDIR)/etc/grub.d 20* clean : rm -f $(TARGET)* $(TARGET_LDS) *~ include/*~ include/txt/*~ *.o common/*~ txt/*~ common/*.o txt/*.o rm -f tags TAGS cscope.files cscope.in.out cscope.out cscope.po.out distclean : clean # # TAGS / tags # define all_sources ( find . -name '*.[chS]' -print ) endef define set_exuberant_flags exuberant_flags=`$1 --version 2>/dev/null | grep -iq exuberant && \ echo "-I __initdata,__exitdata,__acquires,__releases \ -I EXPORT_SYMBOL \ --extra=+f --c-kinds=+px"` endef .PHONY: TAGS TAGS : rm -f TAGS; \ $(call set_exuberant_flags,etags); \ $(all_sources) | xargs etags $$exuberant_flags -a .PHONY: tags tags : rm -f tags; \ $(call set_exuberant_flags,ctags); \ $(all_sources) | xargs ctags $$exuberant_flags -a # # cscope # .PHONY: cscope cscope : $(all_sources) > cscope.files cscope -k -b -q # # MAP # .PHONY: MAP MAP : $(NM) -n $(TARGET)-syms | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' > System.map # # implicit rules # HDRS := $(wildcard $(CURDIR)/include/*.h) HDRS += $(wildcard $(CURDIR)/include/txt/*.h) BUILD_DEPS := $(ROOTDIR)/Config.mk $(CURDIR)/Config.mk $(CURDIR)/Makefile # fix case where gcc doesn't use builtin memcmp() when built w/o optimizations ifeq ($(debug),y) CFLAGS += -O2 endif %.o : %.c $(HDRS) $(BUILD_DEPS) $(CC) $(CFLAGS) -c $< -o $@ %.o : %.S $(HDRS) $(BUILD_DEPS) $(CC) $(AFLAGS) -c $< -o $@ %.i : %.c $(HDRS) $(BUILD_DEPS) $(CPP) $(CFLAGS) $< -o $@ # -std=gnu{89,99} gets confused by # as an end-of-line comment marker %.s : %.S $(HDRS) $(BUILD_DEPS) $(CPP) $(AFLAGS) $< -o $@ tboot-1.8.0/tboot/common/acpi.c0000644000000000000000000003416112272416301014477 0ustar 00000000000000/* * 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 #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 *)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; } extern loader_ctx *g_ldr_ctx; static bool find_rsdp(void) { uint32_t length; uint8_t *ldr_rsdp = NULL; if ( rsdp != NULL ) return true; /* for grins, let's try asking the loader_ctx if it has a copy */ ldr_rsdp = get_loader_rsdp(g_ldr_ctx, &length); 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(loader_ctx *lctx) { if (rsdp != NULL) return rsdp; if (true == find_rsdp()) return rsdp; /* so far we're striking out. Must have been an EFI lauch */ if (false == is_loader_launch_efi(lctx)){ /* uncle */ return NULL; } /* EFI launch, and the loader didn't grace us with an ACPI tag. * We can try to find this the hard way, right? */ 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 = 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); } 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; } uint32_t address = (uint32_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; } uint32_t address = (uint32_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)(acpi_sinfo->wakeup_vector) = (uint32_t)resume_vector; else if ( acpi_sinfo->vector_width <= 64 ) *(uint64_t *)(unsigned 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: */ tboot-1.8.0/tboot/common/boot.S0000644000000000000000000002757512272416301014521 0ustar 00000000000000/* * boot.S: assembly bootstrapping code for tboot module * * 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 #define BSP_STACK_SIZE 4096 #define AP_STACK_SIZE 1024 #define cs_sel 1<<3 #define ds_sel 2<<3 #define cs16_sel 4<<3 #define ds16_sel 5<<3 /* opcode prefixes for 16bit data and addressing */ #define DATA16 .byte 0x66 #define ADDR16 .byte 0x67 /* 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_OFF 8 /* errorcode for post-launch memory layout verfication failure */ #define LAYOUT_ERR 0xc0008001 .section ".tboot_multiboot_header","w" .align 4 /* multiboot header */ #define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_HEADER_MODS_ALIGNED | \ MULTIBOOT_HEADER_WANT_MEMORY) /* magic number for multiboot header */ .long MULTIBOOT_HEADER_MAGIC /* flags for bootloader */ .long MULTIBOOT_HEADER_FLAGS /* checksum: negated sum of above */ .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) /* multiboot2 header */ .align 8 multiboot2_header: .long MB2_HEADER_MAGIC .long MB2_ARCH_X86 .long multiboot2_header_end - multiboot2_header /* checksum */ .long -(MB2_HEADER_MAGIC + MB2_ARCH_X86 + (multiboot2_header_end - multiboot2_header)) multiboot2_header_end: /* tag requests here--RLM, fix me!! Well, maybe! */ .short MB2_HDR_TAG_END .short 0 .long 8 .text ENTRY(start) ENTRY(_start) ENTRY(_stext) jmp __start /* 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.) */ ENTRY(_post_launch_entry) /* verify phys addr we were entered at is the one we expected * ebx contains the phys addr of the entry point * ecx contains the phy addr of the MLE page table */ cmp $_post_launch_entry, %ebx jne layout_err /* 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 */ /* get addr of MLE page table from OsSinitData */ /* start of TXT heap (== BiosDataSize) */ mov (TXT_PRIV_CONFIG_REGS_BASE + TXTCR_HEAP_BASE), %eax add (%eax), %eax /* skip BiosData */ add (%eax), %eax /* skip OsMleData */ mov (MLE_PGTBL_OFF+8)(%eax), %eax /* addr of MLE page table */ /* get to page table itself (there is only one for tboot) */ mov (%eax), %eax /* pgdir ptr -> pgdir */ /* TODO when SINIT ready */ /* mov (%ecx), %eax */ and $PAGE_MASK, %eax mov (%eax), %eax /* pgdir -> pgtbl */ and $PAGE_MASK, %eax /* find last page (pte) */ mov $_mle_end, %ecx sub $_mle_start, %ecx /* size of MLE */ shr $PAGE_SHIFT-3, %ecx sub $8, %ecx /* size/4k*8 is offset+1 of last pte */ add %ecx, %eax mov (%eax), %eax /* pte of last page */ and $PAGE_MASK, %eax /* calc expected addr of last page */ mov $(_mle_end - 1), %ebx /* addr of last byte of MLE... */ and $PAGE_MASK, %ebx /* ...rounded to page start */ /* are they equal? */ cmp %ebx, %eax je __start /* yes, so continue with normal launch */ layout_err: /* layout check failed so TXT RESET */ /* set a special error code */ movl $LAYOUT_ERR, (TXT_PRIV_CONFIG_REGS_BASE + TXTCR_ERRORCODE) /* unlock memory config (and serialize) */ movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXTCR_CMD_UNLOCK_MEM_CONFIG) movl (TXT_PRIV_CONFIG_REGS_BASE + TXTCR_STS), %eax /* TXT RESET */ movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXTCR_CMD_RESET) mov $6, %eax mov $0xcf9, %edx out %al, (%dx) /* for debug chipsets where TXT RESET may not work */ ud2 ENTRY(__start) /* Set up a few descriptors: on entry only CS is guaranteed good. */ lgdt %cs:gdt_descr mov $(ds_sel),%ecx mov %ecx,%ds mov %ecx,%es mov %ecx,%fs mov %ecx,%gs mov %ecx,%ss ljmp $(cs_sel),$(1f) 1: leal bsp_stack,%esp /* Reset EFLAGS (subsumes CLI and CLD). */ pushl $0 popf /* preserve EAX to be a param to begin_launch--it should * contain either MULTIBOOT_MAGIC or MULTIBOOT2_MAGIC--we'll need * to figure out which */ mov %eax,%edx /* Initialize BSS (no nasty surprises!) */ mov $__bss_start,%edi mov $_end,%ecx sub %edi,%ecx xor %eax,%eax rep stosb /* Load IDT */ lidt idt_descr /* enable MCE */ mov %cr4,%eax or $CR4_MCE,%eax mov %eax,%cr4 /* pass multiboot info struct, magic and call measured launch code */ push %edx push %ebx call begin_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) 1: pause cmp $0, (aps_exit_guest) je 1b /* VMCALL out of guest */ .byte 0x0f,0x01,0xc1 jmp 1b #include "shutdown.S" /* * entry point for GETSEC[WAKEUP] */ ENTRY(_txt_wakeup) # prepare this thread for C code /* Set up a few descriptors: on entry only CS is guaranteed good. */ lgdt %cs:gdt_descr mov $0x10, %ecx mov %ecx, %ds mov %ecx, %es mov %ecx, %fs mov %ecx, %gs mov %ecx, %ss ljmp $(cs_sel), $(1f) /* Load IDT */ 1: lidt idt_descr /* enable MCE */ mov %cr4,%eax or $CR4_MCE,%eax mov %eax,%cr4 # get initial APIC ID for this processor mov $0x01, %eax xor %ebx, %ebx cpuid shr $24, %ebx # set stack as id-based offset from AP stack base # spin hlt if we exceed, since C code can't handle shared stack cmp $NR_CPUS, %ebx jl 3f # TBD: increment global counter so BSP can tell we exceeded NR_CPUS 2: cli hlt jmp 2b 3: mov $AP_STACK_SIZE, %eax mul %ebx mov $ap_stacks, %ecx sub %eax, %ecx mov %ecx, %esp call txt_cpu_wakeup /* * entry point for switch to real mode and jump * entry point in %ebx */ ENTRY(_prot_to_real) /* disable interrupts */ cli mov 0x4(%esp), %ebx /* deal with parameter, real mode program entry point */ mov %ebx, %eax and $0xffff0, %eax shr $4, %eax mov %ax, _real_mode_entry_point + 4 and $0xfff0000f, %ebx mov %ebx, _real_mode_entry_point /* load proper segments for real mode */ mov $(ds16_sel), %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs mov %ax, %ss lidt real_idt_desc xor %eax, %eax ljmp $(cs16_sel), $(1f) .code16 1: mov %eax, %cr0 mov $0x0, %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs mov %ax, %ss .code32 DATA16 ADDR16 ljmp *_real_mode_entry_point /* * interrupt handler */ int_handler: call handle_exception ud2 /* * descriptors and descriptor tables */ .align 8 /* GDT */ gdt_descr: .word gdt_table_end - gdt_table - 1 .long gdt_table .align PAGE_SIZE, 0 ENTRY(gdt_table) /* unused */ .quad 0x0000000000000000 cs_descr: /* cs */ .word 0xffff /* limit = 4GB */ .word 0x00 /* base = 0 */ .word 0x9b00 /* read + exec + accessed */ .word 0x00cf /* granularity = 4096 */ ds_descr: /* ds */ .word 0xffff /* limit = 4GB */ .word 0x00 /* base = 0 */ .word 0x9300 /* read + write + accessed */ .word 0x00cf /* granularity = 4096 */ tss_descr: /* tss */ .word 0xffff /* limit = 4GB */ .word 0x00 /* base = 0 */ .word 0x8900 /* system segment, 32b available TSS */ .word 0x008f /* granularity = 4096 */ cs16_desc: /* cs16 */ .word 0xffff /* limit = 4GB */ .word 0x0000 /* base = 0 */ .word 0x9b00 /* read + exec + accessed */ .word 0x008f /* granularity = 4096, D = 0 */ ds16_desc: /* ds16 */ .word 0xffff /* limit = 4GB */ .word 0x0000 /* base = 0 */ .word 0x9300 /* read + exec + accessed */ .word 0x008f /* granularity = 4096, D = 0 */ /* end (unused) */ .quad 0x0000000000000000 ENTRY(gdt_table_end) /* IDT */ idt_descr: .word idt_table_end - idt_table - 1 .long idt_table .align 8 idt_table: .rept 18 .word int_handler - _start .word cs_sel .word 0x8e00 /* present, DPL=0, 32b, interrupt */ .word (int_handler - _start + TBOOT_START) >> 16 .endr /* for machine-check exception */ .word int_handler - _start .word cs_sel .word 0x8f00 /* present, DPL=0, 32b, trap */ .word (int_handler - _start + TBOOT_START) >> 16 .rept 237 .word int_handler - _start .word cs_sel .word 0x8e00 /* present, DPL=0, 32b, interrupt */ .word (int_handler - _start + TBOOT_START) >> 16 .endr idt_table_end: /* Real Mode IDT */ real_idt_desc: .word 0x03ff .long 0 #include "wakeup.S" /* * stacks */ .section ".bss.stack_aligned","w" 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 .section ".bss.page_aligned","w" ENTRY(idle_pg_table) .fill 1*PAGE_SIZE,1,0 .align PAGE_SIZE, 0 ENTRY(host_vmcs) .fill 1*PAGE_SIZE,1,0 .align PAGE_SIZE, 0 /* the input info when os/vmm kerneltrap into tboot */ ENTRY(ap_vmcs) .fill NR_CPUS * PAGE_SIZE, 1, 0 /* * misc. bss data */ .section ".bss" _real_mode_entry_point: .long 0 .word 0 .section ".data" ENTRY(s3_flag) .long 0 /* * shared data page with kernel (i.e. Xen) * (put at end so that not split e820 region for tboot) */ .section ".tboot_shared","w" .align PAGE_SIZE, 0 ENTRY(_tboot_shared) .fill PAGE_SIZE,1,0 .align PAGE_SIZE, 0 ENTRY(_end) tboot-1.8.0/tboot/common/cmdline.c0000644000000000000000000004233412272416301015177 0ustar 00000000000000/* * 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 /* * 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" }, /* vga,serial,memory|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(void) { cmdline_parse(g_cmdline, 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_log_targets |= TBOOT_LOG_TARGET_VGA; 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; } extern 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; } const char *skip_filename(const char *cmdline) { if ( cmdline == NULL || *cmdline == '\0' ) return cmdline; /* strip leading spaces, file name, then any spaces until the next non-space char (e.g. " /foo/bar baz" -> "baz"; "/foo/bar" -> "")*/ while ( *cmdline != '\0' && isspace(*cmdline) ) cmdline++; while ( *cmdline != '\0' && !isspace(*cmdline) ) cmdline++; while ( *cmdline != '\0' && isspace(*cmdline) ) cmdline++; return cmdline; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/common/com.c0000644000000000000000000001005012272416301014330 0ustar 00000000000000/*- * 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 #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 */ extern bool g_psbdf_enabled; extern bool g_pbbdf_enabled; extern 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: */ tboot-1.8.0/tboot/common/e820.c0000644000000000000000000006435512272416301014251 0ustar 00000000000000/* * e820.c: support functions for manipulating the e820 table * * 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 /* 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) */ uint32_t g_min_ram = 0; /* * copy of bootloader/BIOS e820 table with adjusted entries * this version will replace original in mbi */ #define MAX_E820_ENTRIES (TBOOT_E820_COPY_SIZE / sizeof(memory_map_t)) static unsigned int g_nr_map; static memory_map_t *g_copy_e820_map = (memory_map_t *)TBOOT_E820_COPY_ADDR; static efi_memory_desc_t *efi_memmap_addr = NULL; static uint32_t efi_memmap_size = 0; static inline void split64b(uint64_t val, uint32_t *val_lo, uint32_t *val_hi) { *val_lo = (uint32_t)(val & 0xffffffff); *val_hi = (uint32_t)(val >> 32); } static inline uint64_t combine64b(uint32_t val_lo, uint32_t val_hi) { return ((uint64_t)val_hi << 32) | (uint64_t)val_lo; } static inline uint64_t e820_base_64(memory_map_t *entry) { return combine64b(entry->base_addr_low, entry->base_addr_high); } static inline uint64_t e820_length_64(memory_map_t *entry) { return combine64b(entry->length_low, entry->length_high); } /* * print_e820_map * * Prints copied e820 map w/o any header (i.e. just entries, indented by a tab) * */ static void print_map(memory_map_t *e820, int nr_map) { for ( int i = 0; i < nr_map; i++ ) { memory_map_t *entry = &e820[i]; uint64_t base_addr, length; base_addr = e820_base_64(entry); length = e820_length_64(entry); printk(TBOOT_DETA"\t%016Lx - %016Lx (%d)\n", (unsigned long long)base_addr, (unsigned long long)(base_addr + length), entry->type); } } static bool insert_after_region(memory_map_t *e820map, unsigned int *nr_map, unsigned int pos, uint64_t addr, uint64_t size, uint32_t type) { /* no more room */ if ( *nr_map + 1 > MAX_E820_ENTRIES ) return false; /* shift (copy) everything up one entry */ for ( unsigned int i = *nr_map - 1; i > pos; i--) e820map[i+1] = e820map[i]; /* now add our entry */ split64b(addr, &(e820map[pos+1].base_addr_low), &(e820map[pos+1].base_addr_high)); split64b(size, &(e820map[pos+1].length_low), &(e820map[pos+1].length_high)); e820map[pos+1].type = type; e820map[pos+1].size = sizeof(memory_map_t) - sizeof(uint32_t); (*nr_map)++; return true; } static void remove_region(memory_map_t *e820map, unsigned int *nr_map, unsigned int pos) { /* shift (copy) everything down one entry */ for ( unsigned int i = pos; i < *nr_map - 1; i++) e820map[i] = e820map[i+1]; (*nr_map)--; } static bool protect_region(memory_map_t *e820map, unsigned int *nr_map, uint64_t new_addr, uint64_t new_size, uint32_t new_type) { uint64_t addr, tmp_addr, size, tmp_size; uint32_t type; unsigned int i; if ( new_size == 0 ) return true; /* check for wrap */ if ( new_addr + new_size < new_addr ) return false; /* find where our region belongs in the table and insert it */ for ( i = 0; i < *nr_map; i++ ) { addr = e820_base_64(&e820map[i]); size = e820_length_64(&e820map[i]); type = e820map[i].type; /* is our region at the beginning of the current map region? */ if ( new_addr == addr ) { if ( !insert_after_region(e820map, nr_map, i-1, new_addr, new_size, new_type) ) return false; break; } /* are we w/in the current map region? */ else if ( new_addr > addr && new_addr < (addr + size) ) { if ( !insert_after_region(e820map, nr_map, i, new_addr, new_size, new_type) ) return false; /* fixup current region */ tmp_addr = e820_base_64(&e820map[i]); split64b(new_addr - tmp_addr, &(e820map[i].length_low), &(e820map[i].length_high)); i++; /* adjust to always be that of our region */ /* insert a copy of current region (before adj) after us so */ /* that rest of code can be common with previous case */ if ( !insert_after_region(e820map, nr_map, i, addr, size, type) ) return false; break; } /* is our region in a gap in the map? */ else if ( addr > new_addr ) { if ( !insert_after_region(e820map, nr_map, i-1, new_addr, new_size, new_type) ) return false; break; } } /* if we reached the end of the map without finding an overlapping */ /* region, insert us at the end (note that this test won't trigger */ /* for the second case above because the insert() will have incremented */ /* nr_map and so i++ will still be less) */ if ( i == *nr_map ) { if ( !insert_after_region(e820map, nr_map, i-1, new_addr, new_size, new_type) ) return false; return true; } i++; /* move to entry after our inserted one (we're not at end yet) */ tmp_addr = e820_base_64(&e820map[i]); tmp_size = e820_length_64(&e820map[i]); /* did we split the (formerly) previous region? */ if ( (new_addr >= tmp_addr) && ((new_addr + new_size) < (tmp_addr + tmp_size)) ) { /* then adjust the current region (adj size first) */ split64b((tmp_addr + tmp_size) - (new_addr + new_size), &(e820map[i].length_low), &(e820map[i].length_high)); split64b(new_addr + new_size, &(e820map[i].base_addr_low), &(e820map[i].base_addr_high)); return true; } /* if our region completely covers any existing regions, delete them */ while ( (i < *nr_map) && ((new_addr + new_size) >= (tmp_addr + tmp_size)) ) { remove_region(e820map, nr_map, i); tmp_addr = e820_base_64(&e820map[i]); tmp_size = e820_length_64(&e820map[i]); } /* finally, if our region partially overlaps an existing region, */ /* then truncate the existing region */ if ( i < *nr_map ) { tmp_addr = e820_base_64(&e820map[i]); tmp_size = e820_length_64(&e820map[i]); if ( (new_addr + new_size) > tmp_addr ) { split64b((tmp_addr + tmp_size) - (new_addr + new_size), &(e820map[i].length_low), &(e820map[i].length_high)); split64b(new_addr + new_size, &(e820map[i].base_addr_low), &(e820map[i].base_addr_high)); } } return true; } /* * is_overlapped * * Detect whether two ranges are overlapped. * * return: true = overlapped */ static bool is_overlapped(uint64_t base, uint64_t end, uint64_t e820_base, uint64_t e820_end) { uint64_t length = end - base, e820_length = e820_end - e820_base; uint64_t min, max; min = (base < e820_base)?base:e820_base; max = (end > e820_end)?end:e820_end; /* overlapping */ if ( (max - min) < (length + e820_length) ) return true; if ( (max - min) == (length + e820_length) && ( ((length == 0) && (base > e820_base) && (base < e820_end)) || ((e820_length == 0) && (e820_base > base) && (e820_base < end)) ) ) return true; return false; } /* helper funcs for loader.c */ memory_map_t *get_e820_copy() { return g_copy_e820_map; } unsigned int get_nr_map() { return g_nr_map; } /* * copy_e820_map * * Copies the raw e820 map from bootloader to new table with room for expansion * * return: false = error (no table or table too big for new space) */ bool copy_e820_map(loader_ctx *lctx) { get_tboot_min_ram(); g_nr_map = 0; if (have_loader_memmap(lctx)){ uint32_t memmap_length = get_loader_memmap_length(lctx); memory_map_t *memmap = get_loader_memmap(lctx); printk(TBOOT_DETA"original e820 map:\n"); print_map(memmap, memmap_length/sizeof(memory_map_t)); uint32_t entry_offset = 0; while ( entry_offset < memmap_length && g_nr_map < MAX_E820_ENTRIES ) { memory_map_t *entry = (memory_map_t *) (((uint32_t) memmap) + entry_offset); /* we want to support unordered and/or overlapping entries */ /* so use protect_region() to insert into existing map, since */ /* it handles these cases */ if ( !protect_region(g_copy_e820_map, &g_nr_map, e820_base_64(entry), e820_length_64(entry), entry->type) ) return false; if (lctx->type == 1) entry_offset += entry->size + sizeof(entry->size); if (lctx->type == 2) /* the MB2 memory map entries don't have a size-- * they have a "zero" with a value of zero. Additionally, * because they *end* with a size and the MB1 guys *start* * with a size, we get into trouble if we try to use them, */ entry_offset += sizeof(memory_map_t); } if ( g_nr_map == MAX_E820_ENTRIES ) { printk(TBOOT_ERR"Too many e820 entries\n"); return false; } } else if ( have_loader_memlimits(lctx) ) { printk(TBOOT_DETA"no e820 map, mem_lower=%x, mem_upper=%x\n", get_loader_mem_lower(lctx), get_loader_mem_upper(lctx)); /* lower limit is 0x00000000 - *0x400 (i.e. in kb) */ g_copy_e820_map[0].base_addr_low = 0; g_copy_e820_map[0].base_addr_high = 0; g_copy_e820_map[0].length_low = (get_loader_mem_lower(lctx)) << 10; g_copy_e820_map[0].length_high = 0; g_copy_e820_map[0].type = E820_RAM; g_copy_e820_map[0].size = sizeof(memory_map_t) - sizeof(uint32_t); /* upper limit is 0x00100000 - *0x400 */ g_copy_e820_map[1].base_addr_low = 0x100000; g_copy_e820_map[1].base_addr_high = 0; split64b((uint64_t)(get_loader_mem_upper(lctx)) << 10, &(g_copy_e820_map[1].length_low), &(g_copy_e820_map[1].length_high)); g_copy_e820_map[1].type = E820_RAM; g_copy_e820_map[1].size = sizeof(memory_map_t) - sizeof(uint32_t); g_nr_map = 2; } else { printk(TBOOT_ERR"no e820 map nor memory limits provided\n"); return false; } return true; } bool e820_protect_region(uint64_t addr, uint64_t size, uint32_t type) { return protect_region(g_copy_e820_map, &g_nr_map, addr, size, type); } /* * e820_check_region * * Given a range, check which kind of range it covers * * return: E820_GAP, it covers gap in e820 map; * E820_MIXED, it covers at least two different kinds of ranges; * E820_XXX, it covers E820_XXX range only; * it will not return 0. */ uint32_t e820_check_region(uint64_t base, uint64_t length) { memory_map_t* e820_entry; uint64_t end = base + length, e820_base, e820_end, e820_length; uint32_t type; uint32_t ret = 0; bool gap = true; /* suppose there is always a virtual gap at first */ e820_base = 0; e820_length = 0; for ( unsigned int i = 0; i < g_nr_map; i = gap ? i : i+1, gap = !gap ) { e820_entry = &g_copy_e820_map[i]; if ( gap ) { /* deal with the gap in e820 map */ e820_base = e820_base + e820_length; e820_length = e820_base_64(e820_entry) - e820_base; type = E820_GAP; } else { /* deal with the normal item in e820 map */ e820_base = e820_base_64(e820_entry); e820_length = e820_length_64(e820_entry); type = e820_entry->type; } if ( e820_length == 0 ) continue; /* if the range is zero, then skip */ e820_end = e820_base + e820_length; if ( !is_overlapped(base, end, e820_base, e820_end) ) continue; /* if no overlapping, then skip */ /* if the value of ret is not assigned before, then set ret to type directly */ if ( ret == 0 ) { ret = type; continue; } /* if the value of ret is assigned before but ret is equal to type, then no need to do anything */ if ( ret == type ) continue; /* if the value of ret is assigned before but it is GAP, then no need to do anything since any type merged with GAP is GAP */ if ( ret == E820_GAP ) continue; /* if the value of ret is assigned before but it is not GAP and type is GAP now this time, then set ret to GAP since any type merged with GAP is GAP. */ if ( type == E820_GAP ) { ret = E820_GAP; continue; } /* if the value of ret is assigned before but both ret and type are not GAP and their values are not equal, then set ret to MIXED since any two non-GAP values are merged into MIXED if they are not equal. */ ret = E820_MIXED; } /* deal with the last gap */ if ( is_overlapped(base, end, e820_base + e820_length, (uint64_t)-1) ) ret = E820_GAP; /* print the result */ printk(TBOOT_DETA" (range from %016Lx to %016Lx is in ", base, base + length); switch (ret) { case E820_RAM: printk(TBOOT_INFO"E820_RAM)\n"); break; case E820_RESERVED: printk(TBOOT_INFO"E820_RESERVED)\n"); break; case E820_ACPI: printk(TBOOT_INFO"E820_ACPI)\n"); break; case E820_NVS: printk(TBOOT_INFO"E820_NVS)\n"); break; case E820_UNUSABLE: printk(TBOOT_INFO"E820_UNUSABLE)\n"); break; case E820_GAP: printk(TBOOT_INFO"E820_GAP)\n"); break; case E820_MIXED: printk(TBOOT_INFO"E820_MIXED)\n"); break; default: printk(TBOOT_INFO"UNKNOWN)\n"); } return ret; } /* * e820_reserve_ram * * Given the range, any ram range in e820 is in it, change type to reserved. * * return: false = error */ bool e820_reserve_ram(uint64_t base, uint64_t length) { memory_map_t* e820_entry; uint64_t e820_base, e820_length, e820_end; uint64_t end; if ( length == 0 ) return true; end = base + length; /* find where our region should cover the ram in e820 */ for ( unsigned int i = 0; i < g_nr_map; i++ ) { e820_entry = &g_copy_e820_map[i]; e820_base = e820_base_64(e820_entry); e820_length = e820_length_64(e820_entry); e820_end = e820_base + e820_length; /* if not ram, no need to deal with */ if ( e820_entry->type != E820_RAM ) continue; /* if the range is before the current ram range, skip the ram range */ if ( end <= e820_base ) continue; /* if the range is after the current ram range, skip the ram range */ if ( base >= e820_end ) continue; /* case 1: the current ram range is within the range: base, e820_base, e820_end, end */ if ( (base <= e820_base) && (e820_end <= end) ) e820_entry->type = E820_RESERVED; /* case 2: overlapping: base, e820_base, end, e820_end */ else if ( (e820_base >= base) && (end > e820_base) && (e820_end > end) ) { /* split the current ram map */ if ( !insert_after_region(g_copy_e820_map, &g_nr_map, i-1, e820_base, (end - e820_base), E820_RESERVED) ) return false; /* fixup the current ram map */ i++; split64b(end, &(g_copy_e820_map[i].base_addr_low), &(g_copy_e820_map[i].base_addr_high)); split64b(e820_end - end, &(g_copy_e820_map[i].length_low), &(g_copy_e820_map[i].length_high)); /* no need to check more */ break; } /* case 3: overlapping: e820_base, base, e820_end, end */ else if ( (base > e820_base) && (e820_end > base) && (end >= e820_end) ) { /* fixup the current ram map */ split64b((base - e820_base), &(g_copy_e820_map[i].length_low), &(g_copy_e820_map[i].length_high)); /* split the current ram map */ if ( !insert_after_region(g_copy_e820_map, &g_nr_map, i, base, (e820_end - base), E820_RESERVED) ) return false; i++; } /* case 4: the range is within the current ram range: e820_base, base, end, e820_end */ else if ( (base > e820_base) && (e820_end > end) ) { /* fixup the current ram map */ split64b((base - e820_base), &(g_copy_e820_map[i].length_low), &(g_copy_e820_map[i].length_high)); /* split the current ram map */ if ( !insert_after_region(g_copy_e820_map, &g_nr_map, i, base, length, E820_RESERVED) ) return false; i++; /* fixup the rest of the current ram map */ if ( !insert_after_region(g_copy_e820_map, &g_nr_map, i, end, (e820_end - end), e820_entry->type) ) return false; i++; /* no need to check more */ break; } else { printk(TBOOT_ERR"we should never get here\n"); return false; } } return true; } void print_e820_map(void) { print_map(g_copy_e820_map, g_nr_map); } bool get_ram_ranges(uint64_t *min_lo_ram, uint64_t *max_lo_ram, uint64_t *min_hi_ram, uint64_t *max_hi_ram) { 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; bool found_reserved_region = false; uint64_t last_min_ram_base = 0, last_min_ram_size = 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 ( unsigned int i = 0; i < g_nr_map; i++ ) { memory_map_t *entry = &g_copy_e820_map[i]; uint64_t base = e820_base_64(entry); uint64_t limit = base + e820_length_64(entry); if ( entry->type == E820_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 ) { printk(TBOOT_DETA"discarding RAM above reserved regions: 0x%Lx - 0x%Lx\n", base, limit); if ( !e820_reserve_ram(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; } /* find highest (< ) RAM region of at least bytes */ 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; if ( ram_base == NULL || ram_size == NULL ) return; for ( unsigned int i = 0; i < g_nr_map; i++ ) { memory_map_t *entry = &g_copy_e820_map[i]; if ( entry->type == E820_RAM ) { uint64_t base = e820_base_64(entry); uint64_t length = e820_length_64(entry); /* over 4GB so use the last region that fit */ if ( base + length > limit ) break; if ( size <= length ) { last_fit_base = base; last_fit_size = length; } } } *ram_base = last_fit_base; *ram_size = last_fit_size; } #define PAGE_4K (1 << 12) efi_memory_desc_t *get_efi_memmap(uint32_t *memmap_size) { unsigned int i; memory_map_t *mp; efi_memory_desc_t *ep; uint32_t space_required; if (efi_memmap_addr == NULL){ /* we haven't done the conversion yet--is there room? */ space_required = sizeof(memory_map_t) * g_nr_map + sizeof(efi_memory_desc_t) * g_nr_map + 0xf; if (space_required >= TBOOT_E820_COPY_SIZE){ printk(TBOOT_ERR "Insufficient space to make EFI copy of E820 [%d => %d]\n", space_required, TBOOT_E820_COPY_SIZE); return NULL; } /* for fun, we'll align the entries to 0x10 */ ep = efi_memmap_addr = (efi_memory_desc_t *) ((TBOOT_E820_COPY_ADDR + sizeof(memory_map_t) * g_nr_map + 0xf) & ~0xf); /* printk(TBOOT_INFO"efi memmap base now at %p\n", ep); */ mp = g_copy_e820_map; for (i = 0; i < g_nr_map; i++){ uint64_t length; ep[i].phys_addr = ep[i].virt_addr = e820_base_64(mp + i); ep[i].pad = 0; length = e820_length_64(mp + i); length += PAGE_4K - 1; length &= ~(PAGE_4K - 1); ep[i].num_pages = length / PAGE_4K; switch (mp[i].type){ case E820_RAM: ep[i].type = EFI_CONVENTIONAL_MEMORY; ep[i].attribute |= EFI_MEMORY_WB; break; case E820_ACPI: ep[i].type = EFI_ACPI_RECLAIM_MEMORY; break; case E820_NVS: ep[i].type = EFI_ACPI_MEMORY_NVS; break; case E820_UNUSABLE: ep[i].type = EFI_UNUSABLE_MEMORY; break; case E820_GAP: case E820_MIXED: case E820_RESERVED: default: ep[i].type = EFI_RESERVED_TYPE; break; } /* printk(TBOOT_INFO "EFI entry %d at %016Lx type %d with %Lx pages\n", i, ep[i].phys_addr, ep[i].type, ep[i].num_pages); */ efi_memmap_size += sizeof(efi_memory_desc_t); } } *memmap_size = efi_memmap_size; return efi_memmap_addr; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/common/elf.c0000644000000000000000000001363312272416301014332 0ustar 00000000000000/* * elf.c: support functions for manipulating ELF binaries * * 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 extern loader_ctx *g_ldr_ctx; bool is_elf_image(const void *image, size_t size) { elf_header_t *elf; if ( image == NULL ) { printk(TBOOT_ERR"Error: Pointer is zero.\n"); return false; } /* check size */ if ( sizeof(elf_header_t) > size ) { printk(TBOOT_ERR"Error: Image size is smaller than ELF header size.\n"); return false; } elf = (elf_header_t *)image; /* check magic number for ELF */ if ( (elf->e_ident[EI_MAG0] != ELFMAG0) || (elf->e_ident[EI_MAG1] != ELFMAG1) || (elf->e_ident[EI_MAG2] != ELFMAG2) || (elf->e_ident[EI_MAG3] != ELFMAG3) ) { printk(TBOOT_WARN"Error: ELF magic number is not matched.\n"); return false; } /* check data encoding in ELF */ if ( elf->e_ident[EI_DATA] != ELFDATA2LSB ) { printk(TBOOT_ERR"Error: ELF data encoding is not the least significant " "byte occupying the lowest address.\n"); return false; } /* check ELF image is executable? */ if ( elf->e_type != ET_EXEC ) { printk(TBOOT_ERR"Error: ELF image is not executable.\n"); return false; } /* check ELF image is for IA? */ if ( elf->e_machine != EM_386 ) { printk(TBOOT_ERR"Error: ELF image is not for IA.\n"); return false; } /* check ELF version is valid? */ if ( elf->e_version != EV_CURRENT ) { printk(TBOOT_ERR"Error: ELF version is invalid.\n"); return false; } if ( sizeof(elf_program_header_t) > elf->e_phentsize ) { printk(TBOOT_ERR"Error: Program size is smaller than program " "header size.\n"); return false; } return true; } #if 0 static bool get_elf_image_range(const elf_header_t *elf, void **start, void **end) { uint32_t u_start, u_end; if (elf == NULL) { printk(TBOOT_ERR"Error: ELF header pointer is zero.\n"); return false; } /* assumed that already passed is_elf_image() check */ if ((start == NULL) || (end == NULL)) { printk(TBOOT_ERR"Error: Output pointers are zero.\n"); return false; } u_start = 0; u_end = 0; for ( int i = 0; i < elf->e_phnum; i++ ) { elf_program_header_t *ph = (elf_program_header_t *) ((void *)elf + elf->e_phoff + i*elf->e_phentsize); if (ph->p_type == PT_LOAD) { if (u_start > ph->p_paddr) u_start = ph->p_paddr; if (u_end < ph->p_paddr+ph->p_memsz) u_end = ph->p_paddr+ph->p_memsz; } } if (u_start >= u_end) { printk(TBOOT_ERR"Error: PT_LOAD header not found\n"); *start = NULL; *end = NULL; return false; } else { *start = (void *)u_start; *end = (void *)u_end; return true; } } #endif bool expand_elf_image(const elf_header_t *elf, void **entry_point) { if ( elf == NULL ) { printk(TBOOT_ERR"Error: ELF header pointer is zero.\n"); return false; } if ( entry_point == NULL ) { printk(TBOOT_ERR"Error: Output pointer is zero.\n"); return false; } /* assumed that already passed is_elf_image() check */ /* load elf image into memory */ for ( int i = 0; i < elf->e_phnum; i++ ) { elf_program_header_t *ph = (elf_program_header_t *) ((void *)elf + elf->e_phoff + i*elf->e_phentsize); if ( ph->p_type == PT_LOAD ) { memcpy((void *)ph->p_paddr, (void *)elf + ph->p_offset, ph->p_filesz); memset((void *)(ph->p_paddr + ph->p_filesz), 0, ph->p_memsz - ph->p_filesz); } } *entry_point = (void *)elf->e_entry; return true; } bool jump_elf_image(void *entry_point, uint32_t magic) { __asm__ __volatile__ ( " jmp *%%ecx; " " ud2; " :: "a" (magic), "b" (g_ldr_ctx->addr), "c" (entry_point)); return true; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/common/hash.c0000644000000000000000000001313712272416301014506 0ustar 00000000000000/* * 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 /* * 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*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 if ( hash_alg == TB_HALG_SHA512 ) print_hex(NULL, (uint8_t *)hash->sha512, sizeof(hash->sha512)); 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: */ tboot-1.8.0/tboot/common/index.c0000644000000000000000000000372612272416301014675 0ustar 00000000000000/*- * 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/index.c */ #include /* * 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 */ } tboot-1.8.0/tboot/common/integrity.c0000644000000000000000000004306212272416301015601 0ustar 00000000000000/* * integrity.c: routines for memory integrity measurement & * verification. Memory integrity is protected with tpm seal * * Copyright (c) 2007-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 extern char _end[]; /* put in .data section to that they aren't cleared on S3 resume */ /* state whose integrity needs to be maintained across S3 */ __data pre_k_s3_state_t g_pre_k_s3_state; __data post_k_s3_state_t g_post_k_s3_state; /* state sealed before extending PCRs and launching kernel */ static __data uint8_t sealed_pre_k_state[2048]; static __data uint32_t sealed_pre_k_state_size; /* state sealed just before entering S3 (after kernel shuts down) */ static __data uint8_t sealed_post_k_state[2048]; static __data uint32_t sealed_post_k_state_size; /* PCR 17+18 values post-launch and before extending (used to seal verified launch hashes and memory integrity UMAC) */ __data tpm_pcr_value_t post_launch_pcr17, post_launch_pcr18; extern tboot_shared_t _tboot_shared; extern bool hash_policy(tb_hash_t *hash, uint16_t hash_alg); extern void apply_policy(tb_error_t error); #define EVTTYPE_TB_MEASUREMENT (0x400 + 0x101) extern bool evtlog_append(uint8_t pcr, hash_list_t *hl, uint32_t type); typedef struct { uint8_t mac_key[VMAC_KEY_LEN/8]; uint8_t shared_key[sizeof(_tboot_shared.s3_key)]; } sealed_secrets_t; static bool extend_pcrs(void) { for ( int i = 0; i < g_pre_k_s3_state.num_vl_entries; i++ ) { if ( !g_tpm->pcr_extend(g_tpm, 2, g_pre_k_s3_state.vl_entries[i].pcr, &g_pre_k_s3_state.vl_entries[i].hl) ) return false; if ( !evtlog_append(g_pre_k_s3_state.vl_entries[i].pcr, &g_pre_k_s3_state.vl_entries[i].hl, EVTTYPE_TB_MEASUREMENT) ) return false; } return true; } static void print_pre_k_s3_state(void) { printk(TBOOT_DETA"pre_k_s3_state:\n"); printk(TBOOT_DETA"\t vtd_pmr_lo_base: 0x%Lx\n", g_pre_k_s3_state.vtd_pmr_lo_base); printk(TBOOT_DETA"\t vtd_pmr_lo_size: 0x%Lx\n", g_pre_k_s3_state.vtd_pmr_lo_size); printk(TBOOT_DETA"\t vtd_pmr_hi_base: 0x%Lx\n", g_pre_k_s3_state.vtd_pmr_hi_base); printk(TBOOT_DETA"\t vtd_pmr_hi_size: 0x%Lx\n", g_pre_k_s3_state.vtd_pmr_hi_size); printk(TBOOT_DETA"\t pol_hash: "); print_hash(&g_pre_k_s3_state.pol_hash, g_tpm->cur_alg); printk(TBOOT_DETA"\t VL measurements:\n"); for ( unsigned int i = 0; i < g_pre_k_s3_state.num_vl_entries; i++ ) { printk(TBOOT_DETA"\t PCR %d (alg count %d):\n", g_pre_k_s3_state.vl_entries[i].pcr, g_pre_k_s3_state.vl_entries[i].hl.count); for ( unsigned int j = 0; j < g_pre_k_s3_state.vl_entries[i].hl.count; j++ ) { printk(TBOOT_DETA"\t\t alg %04X: ", g_pre_k_s3_state.vl_entries[i].hl.entries[j].alg); print_hash(&g_pre_k_s3_state.vl_entries[i].hl.entries[j].hash, g_pre_k_s3_state.vl_entries[i].hl.entries[j].alg); } } } static void print_post_k_s3_state(void) { printk(TBOOT_DETA"post_k_s3_state:\n"); printk(TBOOT_DETA"\t kernel_s3_resume_vector: 0x%Lx\n", g_post_k_s3_state.kernel_s3_resume_vector); printk(TBOOT_DETA"\t kernel_integ: "); print_hex(NULL, &g_post_k_s3_state.kernel_integ, sizeof(g_post_k_s3_state.kernel_integ)); } static bool seal_data(const void *data, size_t data_size, const void *secrets, size_t secrets_size, uint8_t *sealed_data, uint32_t *sealed_data_size) { /* TPM_Seal can only seal small data (like key or hash), so hash data */ struct __packed { tb_hash_t data_hash; uint8_t secrets[secrets_size]; } blob; uint32_t err; memset(&blob, 0, sizeof(blob)); if ( !hash_buffer(data, data_size, &blob.data_hash, g_tpm->cur_alg) ) { printk(TBOOT_ERR"failed to hash data\n"); return false; } if ( secrets != NULL && secrets_size > 0 ) memcpy(blob.secrets, secrets, secrets_size); err = g_tpm->seal(g_tpm, 2, sizeof(blob), (const uint8_t *)&blob, sealed_data_size, sealed_data); if ( !err ) printk(TBOOT_WARN"failed to seal data\n"); /* since blob might contain secret, clear it */ memset(&blob, 0, sizeof(blob)); return err; } static bool verify_sealed_data(const uint8_t *sealed_data, uint32_t sealed_data_size, const void *curr_data, size_t curr_data_size, void *secrets, size_t secrets_size) { /* sealed data is hash of state data and optional secret */ struct __packed { tb_hash_t data_hash; uint8_t secrets[secrets_size]; } blob; bool err = true; uint32_t data_size = sizeof(blob); if ( !g_tpm->unseal(g_tpm, 2, sealed_data_size, sealed_data, &data_size, (uint8_t *)&blob) ) { printk(TBOOT_ERR"failed to unseal blob\n"); return false; } if ( data_size != sizeof(blob) ) { printk(TBOOT_WARN"unsealed state data size mismatch\n"); goto done; } /* verify that (hash of) current data maches sealed hash */ tb_hash_t curr_data_hash; memset(&curr_data_hash, 0, sizeof(curr_data_hash)); if ( !hash_buffer(curr_data, curr_data_size, &curr_data_hash, g_tpm->cur_alg) ) { printk(TBOOT_WARN"failed to hash state data\n"); goto done; } if ( !are_hashes_equal(&blob.data_hash, &curr_data_hash, g_tpm->cur_alg) ) { printk(TBOOT_WARN"sealed hash does not match current hash\n"); goto done; } if ( secrets != NULL && secrets_size > 0 ) memcpy(secrets, &blob.secrets, secrets_size); err = false; done: /* clear secret from local memory */ memset(&blob, 0, sizeof(blob)); return !err; } /* * pre- PCR extend/kernel launch S3 data are sealed to PCRs 17+18 with * post-launch values (i.e. before extending) */ bool seal_pre_k_state(void) { /* save hash of current policy into g_pre_k_s3_state */ memset(&g_pre_k_s3_state.pol_hash, 0, sizeof(g_pre_k_s3_state.pol_hash)); if ( !hash_policy(&g_pre_k_s3_state.pol_hash, g_tpm->cur_alg) ) { printk(TBOOT_ERR"failed to hash policy\n"); goto error; } print_pre_k_s3_state(); /* read PCR 17/18, only for tpm1.2 */ if ( g_tpm->major == TPM12_VER_MAJOR ) { if ( !g_tpm->pcr_read(g_tpm, 2, 17, &post_launch_pcr17) || !g_tpm->pcr_read(g_tpm, 2, 18, &post_launch_pcr18) ) goto error; } sealed_pre_k_state_size = sizeof(sealed_pre_k_state); if ( !seal_data(&g_pre_k_s3_state, sizeof(g_pre_k_s3_state), NULL, 0, sealed_pre_k_state, &sealed_pre_k_state_size) ) goto error; /* we can't leave the system in a state without valid measurements of about-to-execute code in the PCRs, so this is a fatal error */ if ( !extend_pcrs() ) { apply_policy(TB_ERR_FATAL); return false; } return true; /* even if sealing fails, we must extend PCRs to represent valid measurements of about-to-execute code */ error: if ( !extend_pcrs() ) apply_policy(TB_ERR_FATAL); return false; } static bool measure_memory_integrity(vmac_t *mac, uint8_t key[VMAC_KEY_LEN/8]) { vmac_ctx_t ctx; uint8_t nonce[16] = {}; unsigned long virt = MAC_VIRT_START; /* we require memory is 4K page aligned in tboot */ #define MAC_ALIGN PAGE_SIZE COMPILE_TIME_ASSERT(MAC_VIRT_SIZE >= MAC_PAGE_SIZE); COMPILE_TIME_ASSERT((unsigned long)(-1) - MAC_VIRT_START > MAC_VIRT_SIZE ); COMPILE_TIME_ASSERT(PAGE_SIZE % VMAC_NHBYTES == 0); /* enable paging */ if ( !enable_paging() ) return false; vmac_set_key(key, &ctx); for ( unsigned int i = 0; i < _tboot_shared.num_mac_regions; i++ ) { uint64_t start = _tboot_shared.mac_regions[i].start; /* overflow? */ if ( plus_overflow_u64(start, _tboot_shared.mac_regions[i].size) ) { printk(TBOOT_ERR"start plus size overflows during MACing\n"); return false; } /* if not overflow, we get end */ uint64_t end = start + _tboot_shared.mac_regions[i].size; start = start & ~(MAC_ALIGN - 1); end = (end - 1) | (MAC_ALIGN - 1); /* overflow? */ if ( plus_overflow_u64(end, 1) ) { printk(TBOOT_ERR"end up to the alignment overflows during MACing\n"); return false; } /* if not overflow, we get end aligned */ end++; printk(TBOOT_DETA"MACing region %u: 0x%Lx - 0x%Lx\n", i, start, end); /* * spfn: start pfn in 2-Mbyte page * epfn: end pfn in 2-Mbyte page * align_base: start physical address, which is 2-Mbyte page aligned */ /* check overflow? */ if ( plus_overflow_u64(end, MAC_PAGE_SIZE) ) { printk(TBOOT_ERR"end plus MAC_PAGE_SIZE overflows during MACing\n"); return false; } unsigned long spfn; unsigned long epfn = (unsigned long)((end + MAC_PAGE_SIZE - 1) >> TB_L1_PAGETABLE_SHIFT); unsigned long nr_pfns, nr_virt_pfns; uint64_t align_base; unsigned long valign_base, vstart, vend; do { spfn = (unsigned long)(start >> TB_L1_PAGETABLE_SHIFT); align_base = (uint64_t)spfn << TB_L1_PAGETABLE_SHIFT; valign_base = virt; vstart = valign_base + (unsigned long)(start - align_base); nr_pfns = epfn - spfn; nr_virt_pfns = (MAC_VIRT_END - virt) >> TB_L1_PAGETABLE_SHIFT; if ( nr_virt_pfns >= nr_pfns ) { /* region can fit into the rest virtual space */ map_pages_to_tboot(valign_base, spfn, nr_pfns); vend = valign_base + (unsigned long)(end - align_base); virt += nr_pfns << TB_L1_PAGETABLE_SHIFT; start = end; } else { /* region cannot fit into the rest virtual space, will trunc */ map_pages_to_tboot(valign_base, spfn, nr_virt_pfns); vend = MAC_VIRT_END; virt = MAC_VIRT_START; start = align_base + (nr_virt_pfns << TB_L1_PAGETABLE_SHIFT); } /* MAC the 2-Mbyte pages */ while ( (vend > vstart) && ((vend - vstart) >= MAC_PAGE_SIZE) ) { vmac_update((uint8_t *)(uintptr_t)vstart, MAC_PAGE_SIZE, &ctx); vstart += MAC_PAGE_SIZE; } /* MAC the rest */ if ( vend > vstart ) vmac_update((uint8_t *)(uintptr_t)vstart, vend - vstart, &ctx); /* destroy the mapping */ if ( virt == MAC_VIRT_START ) destroy_tboot_mapping(MAC_VIRT_START, MAC_VIRT_END); } while ( start < end ); } *mac = vmac(NULL, 0, nonce, NULL, &ctx); /* wipe ctx to ensure key not left in memory */ memset(&ctx, 0, sizeof(ctx)); /* return to protected mode without paging */ if (!disable_paging()) return false; return true; } /* * verify memory integrity and sealed VL hashes, then re-extend hashes * * this must be called post-launch but before extending any modules or other * measurements into PCRs */ bool verify_integrity(void) { tpm_pcr_value_t pcr17, pcr18; /* read PCR 17/18, only for tpm1.2 */ if ( g_tpm->major == TPM12_VER_MAJOR ) { if ( !g_tpm->pcr_read(g_tpm, 2, 17, &pcr17) || !g_tpm->pcr_read(g_tpm, 2, 18, &pcr18) ) goto error; printk(TBOOT_DETA"PCRs before unseal:\n"); printk(TBOOT_DETA" PCR 17: "); print_hash((tb_hash_t *)&pcr17, TB_HALG_SHA1); printk(TBOOT_DETA" PCR 18: "); print_hash((tb_hash_t *)&pcr18, TB_HALG_SHA1); } /* verify integrity of pre-kernel state data */ printk(TBOOT_INFO"verifying pre_k_s3_state\n"); if ( !verify_sealed_data(sealed_pre_k_state, sealed_pre_k_state_size, &g_pre_k_s3_state, sizeof(g_pre_k_s3_state), NULL, 0) ) goto error; if ( !g_tpm->verify_creation(g_tpm, sealed_post_k_state_size, sealed_post_k_state) ) { printk(TBOOT_ERR"extended PCR values don't match creation values in sealed blob.\n"); goto error; } /* verify integrity of post-kernel state data */ printk(TBOOT_INFO"verifying post_k_s3_state\n"); sealed_secrets_t secrets; if ( !verify_sealed_data(sealed_post_k_state, sealed_post_k_state_size, &g_post_k_s3_state, sizeof(g_post_k_s3_state), &secrets, sizeof(secrets)) ) goto error; /* Verify memory integrity against sealed value */ vmac_t mac; if ( !measure_memory_integrity(&mac, secrets.mac_key) ) goto error; if ( memcmp(&mac, &g_post_k_s3_state.kernel_integ, sizeof(mac)) ) { printk(TBOOT_INFO"memory integrity lost on S3 resume\n"); printk(TBOOT_DETA"MAC of current image is: "); print_hex(NULL, &mac, sizeof(mac)); printk(TBOOT_DETA"MAC of pre-S3 image is: "); print_hex(NULL, &g_post_k_s3_state.kernel_integ, sizeof(g_post_k_s3_state.kernel_integ)); goto error; } printk(TBOOT_INFO"memory integrity OK\n"); /* re-extend PCRs with VL measurements we can't leave the system in a state without valid measurements of about-to-execute code in the PCRs, so this is a fatal error */ if ( !extend_pcrs() ) { apply_policy(TB_ERR_FATAL); return false; } /* copy sealed shared key back to _tboot_shared.s3_key */ memcpy(_tboot_shared.s3_key, secrets.shared_key, sizeof(_tboot_shared.s3_key)); /* wipe secrets from memory */ memset(&secrets, 0, sizeof(secrets)); return true; error: /* since we can't leave the system without any measurments representing the code-about-to-execute, and yet there is no integrity of that code, just cap PCR 18 */ if ( !g_tpm->cap_pcrs(g_tpm, 2, 18) ) apply_policy(TB_ERR_FATAL); return false; } /* * post- kernel launch S3 state is sealed to PCRs 17+18 with post-launch * values (i.e. before extending with VL hashes) */ bool seal_post_k_state(void) { sealed_secrets_t secrets; /* since tboot relies on the module it launches for resource protection, that module should have at least one region for itself, otherwise it will not be protected against S3 resume attacks */ if ( _tboot_shared.num_mac_regions == 0 ) { printk(TBOOT_ERR"no memory regions to MAC\n"); return false; } /* calculate the memory integrity hash */ uint32_t key_size = sizeof(secrets.mac_key); /* key must be random and secret even though auth not necessary */ if ( !g_tpm->get_random(g_tpm, 2, secrets.mac_key, &key_size) || key_size != sizeof(secrets.mac_key) ) return false; if ( !measure_memory_integrity(&g_post_k_s3_state.kernel_integ, secrets.mac_key) ) return false; /* copy s3_key into secrets to be sealed */ memcpy(secrets.shared_key, _tboot_shared.s3_key, sizeof(secrets.shared_key)); print_post_k_s3_state(); sealed_post_k_state_size = sizeof(sealed_post_k_state); if ( !seal_data(&g_post_k_s3_state, sizeof(g_post_k_s3_state), &secrets, sizeof(secrets), sealed_post_k_state, &sealed_post_k_state_size) ) return false; /* wipe secrets from memory */ memset(&secrets, 0, sizeof(secrets)); return true; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/common/linux.c0000644000000000000000000003765712272416301014737 0ustar 00000000000000/* * linux.c: support functions for manipulating Linux kernel binaries * * 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 extern loader_ctx *g_ldr_ctx; /* MLE/kernel shared data page (in boot.S) */ extern tboot_shared_t _tboot_shared; static boot_params_t *boot_params; extern void *get_tboot_mem_end(void); static void printk_long(const char *what) { /* chunk the command line into 70 byte chunks */ #define CHUNK_SIZE 70 int cmdlen = strlen(what); const char *cptr = what; char cmdchunk[CHUNK_SIZE+1]; while (cmdlen > 0) { strncpy(cmdchunk, cptr, CHUNK_SIZE); cmdchunk[CHUNK_SIZE] = 0; printk(TBOOT_INFO"\t%s\n", cmdchunk); cmdlen -= CHUNK_SIZE; cptr += CHUNK_SIZE; } } /* expand linux kernel with kernel image and initrd image */ bool expand_linux_image(const void *linux_image, size_t linux_size, const void *initrd_image, size_t initrd_size, void **entry_point, bool is_measured_launch) { linux_kernel_header_t *hdr; uint32_t real_mode_base, protected_mode_base; unsigned long real_mode_size, protected_mode_size; /* Note: real_mode_size + protected_mode_size = linux_size */ uint32_t initrd_base; int vid_mode = 0; /* Check param */ if ( linux_image == NULL ) { printk(TBOOT_ERR"Error: Linux kernel image is zero.\n"); return false; } if ( linux_size == 0 ) { printk(TBOOT_ERR"Error: Linux kernel size is zero.\n"); return false; } if ( linux_size < sizeof(linux_kernel_header_t) ) { printk(TBOOT_ERR"Error: Linux kernel size is too small.\n"); return false; } hdr = (linux_kernel_header_t *)(linux_image + KERNEL_HEADER_OFFSET); if ( hdr == NULL ) { printk(TBOOT_ERR"Error: Linux kernel header is zero.\n"); return false; } if ( entry_point == NULL ) { printk(TBOOT_ERR"Error: Output pointer is zero.\n"); return false; } /* recommended layout 0x0000 - 0x7FFF Real mode kernel 0x8000 - 0x8FFF Stack and heap 0x9000 - 0x90FF Kernel command line for details, see linux_defns.h */ /* if setup_sects is zero, set to default value 4 */ if ( hdr->setup_sects == 0 ) hdr->setup_sects = DEFAULT_SECTOR_NUM; if ( hdr->setup_sects > MAX_SECTOR_NUM ) { printk(TBOOT_ERR "Error: Linux setup sectors %d exceed maximum limitation 64.\n", hdr->setup_sects); return false; } /* set vid_mode */ linux_parse_cmdline(get_cmdline(g_ldr_ctx)); if ( get_linux_vga(&vid_mode) ) hdr->vid_mode = vid_mode; /* compare to the magic number */ if ( hdr->header != HDRS_MAGIC ) { /* old kernel */ printk(TBOOT_ERR "Error: Old kernel (< 2.6.20) is not supported by tboot.\n"); return false; } if ( hdr->version < 0x0205 ) { printk(TBOOT_ERR "Error: Old kernel (<2.6.20) is not supported by tboot.\n"); return false; } /* boot loader is grub, set type_of_loader to 0x7 */ hdr->type_of_loader = LOADER_TYPE_GRUB; /* set loadflags and heap_end_ptr */ hdr->loadflags |= FLAG_CAN_USE_HEAP; /* can use heap */ hdr->heap_end_ptr = KERNEL_CMDLINE_OFFSET - BOOT_SECTOR_OFFSET; /* load initrd and set ramdisk_image and ramdisk_size */ /* The initrd should typically be located as high in memory as possible, as it may otherwise get overwritten by the early kernel initialization sequence. */ /* check if Linux command line explicitly specified a memory limit */ uint64_t mem_limit; get_linux_mem(&mem_limit); if ( mem_limit > 0x100000000ULL || mem_limit == 0 ) mem_limit = 0x100000000ULL; uint64_t max_ram_base, max_ram_size; get_highest_sized_ram(initrd_size, mem_limit, &max_ram_base, &max_ram_size); if ( max_ram_size == 0 ) { printk(TBOOT_ERR"not enough RAM for initrd\n"); return false; } if ( initrd_size > max_ram_size ) { printk(TBOOT_ERR"initrd_size is too large\n"); return false; } if ( max_ram_base > ((uint64_t)(uint32_t)(~0)) ) { printk(TBOOT_ERR"max_ram_base is too high\n"); return false; } if ( plus_overflow_u32((uint32_t)max_ram_base, (uint32_t)(max_ram_size - initrd_size)) ) { printk(TBOOT_ERR"max_ram overflows\n"); return false; } initrd_base = (max_ram_base + max_ram_size - initrd_size) & PAGE_MASK; /* should not exceed initrd_addr_max */ if ( initrd_base + initrd_size > hdr->initrd_addr_max ) { if ( hdr->initrd_addr_max < initrd_size ) { printk(TBOOT_ERR"initrd_addr_max is too small\n"); return false; } initrd_base = hdr->initrd_addr_max - initrd_size; initrd_base = initrd_base & PAGE_MASK; } memmove((void *)initrd_base, initrd_image, initrd_size); printk(TBOOT_DETA"Initrd from 0x%lx to 0x%lx\n", (unsigned long)initrd_base, (unsigned long)(initrd_base + initrd_size)); hdr->ramdisk_image = initrd_base; hdr->ramdisk_size = initrd_size; /* calc location of real mode part */ real_mode_base = LEGACY_REAL_START; if ( have_loader_memlimits(g_ldr_ctx)) real_mode_base = ((get_loader_mem_lower(g_ldr_ctx)) << 10) - REAL_MODE_SIZE; if ( real_mode_base < TBOOT_KERNEL_CMDLINE_ADDR + TBOOT_KERNEL_CMDLINE_SIZE ) real_mode_base = TBOOT_KERNEL_CMDLINE_ADDR + TBOOT_KERNEL_CMDLINE_SIZE; if ( real_mode_base > LEGACY_REAL_START ) real_mode_base = LEGACY_REAL_START; real_mode_size = (hdr->setup_sects + 1) * SECTOR_SIZE; if ( real_mode_size + sizeof(boot_params_t) > KERNEL_CMDLINE_OFFSET ) { printk(TBOOT_ERR"realmode data is too large\n"); return false; } /* calc location of protected mode part */ protected_mode_size = linux_size - real_mode_size; /* if kernel is relocatable then move it above tboot */ /* else it may expand over top of tboot */ if ( hdr->relocatable_kernel ) { protected_mode_base = (uint32_t)get_tboot_mem_end(); /* fix possible mbi overwrite in grub2 case */ /* assuming grub2 only used for relocatable kernel */ /* assuming mbi & components are contiguous */ unsigned long ldr_ctx_end = get_loader_ctx_end(g_ldr_ctx); if ( ldr_ctx_end > protected_mode_base ) protected_mode_base = ldr_ctx_end; /* overflow? */ if ( plus_overflow_u32(protected_mode_base, hdr->kernel_alignment - 1) ) { printk(TBOOT_ERR"protected_mode_base overflows\n"); return false; } /* round it up to kernel alignment */ protected_mode_base = (protected_mode_base + hdr->kernel_alignment - 1) & ~(hdr->kernel_alignment-1); hdr->code32_start = protected_mode_base; } else if ( hdr->loadflags & FLAG_LOAD_HIGH ) { protected_mode_base = BZIMAGE_PROTECTED_START; /* bzImage:0x100000 */ /* overflow? */ if ( plus_overflow_u32(protected_mode_base, protected_mode_size) ) { printk(TBOOT_ERR "protected_mode_base plus protected_mode_size overflows\n"); return false; } /* Check: protected mode part cannot exceed mem_upper */ if ( have_loader_memlimits(g_ldr_ctx)){ uint32_t mem_upper = get_loader_mem_upper(g_ldr_ctx); if ( (protected_mode_base + protected_mode_size) > ((mem_upper << 10) + 0x100000) ) { printk(TBOOT_ERR "Error: Linux protected mode part (0x%lx ~ 0x%lx) " "exceeds mem_upper (0x%lx ~ 0x%lx).\n", (unsigned long)protected_mode_base, (unsigned long) (protected_mode_base + protected_mode_size), (unsigned long)0x100000, (unsigned long)((mem_upper << 10) + 0x100000)); return false; } } } else { printk(TBOOT_ERR"Error: Linux protected mode not loaded high\n"); return false; } /* set cmd_line_ptr */ hdr->cmd_line_ptr = real_mode_base + KERNEL_CMDLINE_OFFSET; /* load protected-mode part */ memmove((void *)protected_mode_base, linux_image + real_mode_size, protected_mode_size); printk(TBOOT_DETA"Kernel (protected mode) from 0x%lx to 0x%lx\n", (unsigned long)protected_mode_base, (unsigned long)(protected_mode_base + protected_mode_size)); /* load real-mode part */ memmove((void *)real_mode_base, linux_image, real_mode_size); printk(TBOOT_DETA"Kernel (real mode) from 0x%lx to 0x%lx\n", (unsigned long)real_mode_base, (unsigned long)(real_mode_base + real_mode_size)); /* copy cmdline */ const char *kernel_cmdline = skip_filename(get_cmdline(g_ldr_ctx)); printk(TBOOT_INFO"Linux cmdline placed in header: "); printk_long(kernel_cmdline); printk(TBOOT_INFO"\n"); memcpy((void *)hdr->cmd_line_ptr, kernel_cmdline, strlen(kernel_cmdline)); /* need to put boot_params in real mode area so it gets mapped */ boot_params = (boot_params_t *)(real_mode_base + real_mode_size); memset(boot_params, 0, sizeof(*boot_params)); memcpy(&boot_params->hdr, hdr, sizeof(*hdr)); /* need to handle a few EFI things here if such is our parentage */ if (is_loader_launch_efi(g_ldr_ctx)){ struct efi_info *efi = (struct efi_info *)(boot_params->efi_info); struct screen_info_t *scr = (struct screen_info_t *)(boot_params->screen_info); uint32_t address = 0; uint64_t long_address = 0UL; /* loader signature */ memcpy(&efi->efi_ldr_sig, "EL64", sizeof(uint32_t)); /* EFI system table addr */ { if (get_loader_efi_ptr(g_ldr_ctx, &address, &long_address)){ if (long_address){ efi->efi_systable = (uint32_t) (long_address & 0xffffffff); efi->efi_systable_hi = long_address >> 32; } else { efi->efi_systable = address; efi->efi_systable_hi = 0; } } else { printk(TBOOT_INFO"failed to get efi system table ptr\n"); } } /* EFI memmap descriptor size */ efi->efi_memdescr_size = 0x30; /* EFI memmap descriptor version */ efi->efi_memdescr_ver = 1; #if 1 /* EFI memmap addr */ { uint32_t length; efi->efi_memmap = (uint32_t) get_efi_memmap(&length); /* EFI memmap size */ efi->efi_memmap_size = length; } #else efi->efi_memmap = 0; efi->efi_memmap_size = 0x70; #endif /* EFI memmap high--since we're consing our own, we know this == 0 */ efi->efi_memmap_hi = 0; /* if we're here, GRUB2 probably threw a framebuffer tag at us */ load_framebuffer_info(g_ldr_ctx, (void *)scr); } /* detect e820 table */ if (have_loader_memmap(g_ldr_ctx)) { int i; memory_map_t *p = get_loader_memmap(g_ldr_ctx); uint32_t memmap_start = (uint32_t) p; uint32_t memmap_length = get_loader_memmap_length(g_ldr_ctx); for ( i = 0; (uint32_t)p < memmap_start + memmap_length; i++ ) { boot_params->e820_map[i].addr = ((uint64_t)p->base_addr_high << 32) | (uint64_t)p->base_addr_low; boot_params->e820_map[i].size = ((uint64_t)p->length_high << 32) | (uint64_t)p->length_low; boot_params->e820_map[i].type = p->type; p = (void *)p + p->size + sizeof(p->size); } boot_params->e820_entries = i; } if (0 == is_loader_launch_efi(g_ldr_ctx)){ screen_info_t *screen = (screen_info_t *)&boot_params->screen_info; screen->orig_video_mode = 3; /* BIOS 80*25 text mode */ screen->orig_video_lines = 25; screen->orig_video_cols = 80; screen->orig_video_points = 16; /* set font height to 16 pixels */ screen->orig_video_isVGA = 1; /* use VGA text screen setups */ screen->orig_y = 24; /* start display text @ screen end*/ } /* set address of tboot shared page */ if ( is_measured_launch ) *(uint64_t *)&boot_params->tboot_shared_addr = (uintptr_t)&_tboot_shared; *entry_point = (void *)hdr->code32_start; return true; } /* jump to protected-mode code of kernel */ bool jump_linux_image(void *entry_point) { #define __BOOT_CS 0x10 #define __BOOT_DS 0x18 static const uint64_t gdt_table[] __attribute__ ((aligned(16))) = { 0, 0, 0x00c09b000000ffff, /* cs */ 0x00c093000000ffff /* ds */ }; /* both 4G flat, CS: execute/read, DS: read/write */ static struct __packed { uint16_t length; uint32_t table; } gdt_desc; gdt_desc.length = sizeof(gdt_table) - 1; gdt_desc.table = (uint32_t)&gdt_table; /* load gdt with CS = 0x10 and DS = 0x18 */ __asm__ __volatile__ ( " lgdtl %0; " " mov %1, %%ecx; " " mov %%ecx, %%ds; " " mov %%ecx, %%es; " " mov %%ecx, %%fs; " " mov %%ecx, %%gs; " " mov %%ecx, %%ss; " " ljmp %2, $(1f); " " 1: " " xor %%ebp, %%ebp; " " xor %%edi, %%edi; " " xor %%ebx, %%ebx; " :: "m"(gdt_desc), "i"(__BOOT_DS), "i"(__BOOT_CS)); /* jump to protected-mode code */ __asm__ __volatile__ ( " cli; " " mov %0, %%esi; " /* esi holds address of boot_params */ " jmp *%%edx; " " ud2; " :: "a"(boot_params), "d"(entry_point)); return true; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/common/loader.c0000644000000000000000000016601412272416301015034 0ustar 00000000000000/* * loader.c: support functions for manipulating ELF/Linux kernel * binaries * * 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 #include #include /* copy of kernel/VMM command line so that can append 'tboot=0x1234' */ static char *new_cmdline = (char *)TBOOT_KERNEL_CMDLINE_ADDR; /* MLE/kernel shared data page (in boot.S) */ extern tboot_shared_t _tboot_shared; /* multiboot struct saved so that post_launch() can use it (in tboot.c) */ extern loader_ctx *g_ldr_ctx; extern bool is_elf_image(const void *image, size_t size); extern bool expand_elf_image(const elf_header_t *elf, void **entry_point); extern bool expand_linux_image(const void *linux_image, size_t linux_size, const void *initrd_image, size_t initrd_size, void **entry_point, bool is_measured_launch); extern bool jump_elf_image(const void *entry_point, uint32_t magic); extern bool jump_linux_image(const void *entry_point); extern bool is_sinit_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet); extern uint32_t g_mb_orig_size; #define LOADER_CTX_BAD(xctx) \ xctx == NULL ? true : \ xctx->addr == NULL ? true : \ xctx->type != 1 && xctx->type != 2 ? true : false #define MB_NONE 0 #define MB1_ONLY 1 #define MB2_ONLY 2 #define MB_BOTH 3 static void printk_long(char *what) { /* chunk the command line into 70 byte chunks */ #define CHUNK_SIZE 70 int cmdlen = strlen(what); char *cptr = what; char cmdchunk[CHUNK_SIZE+1]; while (cmdlen > 0) { strncpy(cmdchunk, cptr, CHUNK_SIZE); cmdchunk[CHUNK_SIZE] = 0; printk(TBOOT_INFO"\t%s\n", cmdchunk); cmdlen -= CHUNK_SIZE; cptr += CHUNK_SIZE; } } static module_t *get_module_mb1(const multiboot_info_t *mbi, unsigned int i) { if ( mbi == NULL ) { printk(TBOOT_ERR"Error: mbi pointer is zero.\n"); return NULL; } if ( i >= mbi->mods_count ) { printk(TBOOT_ERR"invalid module #\n"); return NULL; } return (module_t *)(mbi->mods_addr + i * sizeof(module_t)); } static struct mb2_tag *next_mb2_tag(struct mb2_tag *start) { /* given "start", what's the beginning of the next tag */ void *addr = (void *) start; if (start == NULL) return NULL; if (start->type == MB2_TAG_TYPE_END) return NULL; addr += ((start->size + 7) & ~7); return (struct mb2_tag *) addr; } static struct mb2_tag *find_mb2_tag_type(struct mb2_tag *start, uint32_t tag_type) { while (start != NULL){ if (start->type == tag_type) return start; start = next_mb2_tag(start); } return start; } static module_t *get_module_mb2(loader_ctx *lctx, unsigned int i) { struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); unsigned int ii; struct mb2_tag_module *tag_mod = NULL; module_t *mt = NULL; start = find_mb2_tag_type(start, MB2_TAG_TYPE_MODULE); if (start != NULL){ for (ii = 1; ii <= i; ii++){ if (start == NULL) return NULL; else { /* nudge off this hit */ start = next_mb2_tag(start); start = find_mb2_tag_type(start, MB2_TAG_TYPE_MODULE); } } /* if we're here, we have the tag struct for the desired module */ tag_mod = (struct mb2_tag_module *) start; mt = (module_t *) &(tag_mod->mod_start); } return mt; } #if 0 void print_mbi(const multiboot_info_t *mbi) { /* print mbi for debug */ unsigned int i; printk(TBOOT_DETA"print mbi@%p ...\n", mbi); printk(TBOOT_DETA"\t flags: 0x%x\n", mbi->flags); if ( mbi->flags & MBI_MEMLIMITS ) printk(TBOOT_DETA"\t mem_lower: %uKB, mem_upper: %uKB\n", mbi->mem_lower, mbi->mem_upper); if ( mbi->flags & MBI_BOOTDEV ) { printk(TBOOT_DETA"\t boot_device.bios_driver: 0x%x\n", mbi->boot_device.bios_driver); printk(TBOOT_DETA"\t boot_device.top_level_partition: 0x%x\n", mbi->boot_device.top_level_partition); printk(TBOOT_DETA"\t boot_device.sub_partition: 0x%x\n", mbi->boot_device.sub_partition); printk(TBOOT_DETA"\t boot_device.third_partition: 0x%x\n", mbi->boot_device.third_partition); } if ( mbi->flags & MBI_CMDLINE ) { # define CHUNK_SIZE 72 /* Break the command line up into 72 byte chunks */ int cmdlen = strlen(mbi->cmdline); char *cmdptr = (char *)mbi->cmdline; char chunk[CHUNK_SIZE+1]; printk(TBOOT_DETA"\t cmdline@0x%x: ", mbi->cmdline); chunk[CHUNK_SIZE] = '\0'; while (cmdlen > 0) { strncpy(chunk, cmdptr, CHUNK_SIZE); printk(TBOOT_DETA"\n\t\"%s\"", chunk); cmdptr += CHUNK_SIZE; cmdlen -= CHUNK_SIZE; } printk(TBOOT_DETA"\n"); } if ( mbi->flags & MBI_MODULES ) { printk(TBOOT_DETA"\t mods_count: %u, mods_addr: 0x%x\n", mbi->mods_count, mbi->mods_addr); for ( i = 0; i < mbi->mods_count; i++ ) { module_t *p = (module_t *)(mbi->mods_addr + i*sizeof(module_t)); printk(TBOOT_DETA"\t %d : mod_start: 0x%x, mod_end: 0x%x\n", i, p->mod_start, p->mod_end); printk(TBOOT_DETA"\t string (@0x%x): \"%s\"\n", p->string, (char *)p->string); } } if ( mbi->flags & MBI_AOUT ) { const aout_t *p = &(mbi->syms.aout_image); printk(TBOOT_DETA "\t aout :: tabsize: 0x%x, strsize: 0x%x, addr: 0x%x\n", p->tabsize, p->strsize, p->addr); } if ( mbi->flags & MBI_ELF ) { const elf_t *p = &(mbi->syms.elf_image); printk(TBOOT_DETA "\t elf :: num: %u, size: 0x%x, addr: 0x%x, shndx: 0x%x\n", p->num, p->size, p->addr, p->shndx); } if ( mbi->flags & MBI_MEMMAP ) { memory_map_t *p; printk(TBOOT_DETA "\t mmap_length: 0x%x, mmap_addr: 0x%x\n", mbi->mmap_length, mbi->mmap_addr); for ( p = (memory_map_t *)mbi->mmap_addr; (uint32_t)p < mbi->mmap_addr + mbi->mmap_length; p=(memory_map_t *)((uint32_t)p + p->size + sizeof(p->size)) ) { printk(TBOOT_DETA"\t size: 0x%x, base_addr: 0x%04x%04x, " "length: 0x%04x%04x, type: %u\n", p->size, p->base_addr_high, p->base_addr_low, p->length_high, p->length_low, p->type); } } if ( mbi->flags & MBI_DRIVES ) { printk(TBOOT_DETA"\t drives_length: %u, drives_addr: 0x%x\n", mbi->drives_length, mbi->drives_addr); } if ( mbi->flags & MBI_CONFIG ) { printk(TBOOT_DETA"\t config_table: 0x%x\n", mbi->config_table); } if ( mbi->flags & MBI_BTLDNAME ) { printk(TBOOT_DETA"\t boot_loader_name@0x%x: %s\n", mbi->boot_loader_name, (char *)mbi->boot_loader_name); } if ( mbi->flags & MBI_APM ) { printk(TBOOT_DETA"\t apm_table: 0x%x\n", mbi->apm_table); } if ( mbi->flags & MBI_VBE ) { printk(TBOOT_DETA"\t vbe_control_info: 0x%x\n" "\t vbe_mode_info: 0x%x\n" "\t vbe_mode: 0x%x\n" "\t vbe_interface_seg: 0x%x\n" "\t vbe_interface_off: 0x%x\n" "\t vbe_interface_len: 0x%x\n", mbi->vbe_control_info, mbi->vbe_mode_info, mbi->vbe_mode, mbi->vbe_interface_seg, mbi->vbe_interface_off, mbi->vbe_interface_len ); } } #endif bool verify_loader_context(loader_ctx *lctx) { unsigned int count; if (LOADER_CTX_BAD(lctx)) return false; count = get_module_count(lctx); if (count < 1){ printk(TBOOT_ERR"Error: no MB%d modules\n", lctx->type); return false; } else return true; } static bool remove_mb2_tag(loader_ctx *lctx, struct mb2_tag *cur) { uint8_t *s, *d, *e; struct mb2_tag *next, *end; next = next_mb2_tag(cur); if (next == NULL){ printk(TBOOT_ERR"missing next tag in remove_mb2_tag\n"); return false; } /* where do we stop? */ end = (struct mb2_tag *)(lctx->addr + 8); end = find_mb2_tag_type(end, MB2_TAG_TYPE_END); if (end == NULL){ printk(TBOOT_ERR"remove_mb2_tag, no end tag!!!!\n"); return false; } e = (uint8_t *) end + end->size; /* we'll do this byte-wise */ s = (uint8_t *) next; d = (uint8_t *) cur; while (s <= e){ *d = *s; d++; s++; } /* adjust MB2 length */ *((unsigned long *) lctx->addr) -= (uint8_t *)next - (uint8_t *)cur; /* sanity check */ /* print_loader_ctx(lctx); */ return true; } static bool grow_mb2_tag(loader_ctx *lctx, struct mb2_tag *which, uint32_t how_much) { struct mb2_tag *next, *new_next, *end; int growth, slack; uint8_t *s, *d; // uint32_t old_size = which->size; /* we're holding the tag struct to grow, get its successor */ next = next_mb2_tag(which); /* find the end--we will need it */ end = (struct mb2_tag *)(lctx->addr + 8); end = find_mb2_tag_type(end, MB2_TAG_TYPE_END); /* How much bigger does it need to be? */ /* NOTE: this breaks the MBI 2 structure for walking * until we're done copying. */ which->size += how_much; /* what's the new growth for its successor? */ new_next = next_mb2_tag(which); growth = ((void *) new_next) - ((void *) next); /* check to make sure there's actually room for the growth */ slack = g_mb_orig_size - *(uint32_t *) (lctx->addr); if (growth > slack){ printk(TBOOT_ERR"YIKES!!! grow_mb2_tag slack %d < growth %d\n", slack, growth); } /* now we copy down from the bottom, going up */ s = ((uint8_t *) end) + end->size; d = s + growth; while (s >= (uint8_t *)next){ *d = *s; d--; s--; } /* adjust MB2 length */ *((uint32_t *) lctx->addr) += growth; return true; } static void *remove_module(loader_ctx *lctx, void *mod_start) { module_t *m = NULL; unsigned int i; if ( !verify_loader_context(lctx)) return NULL; for ( i = 0; i < get_module_count(lctx); i++ ) { m = get_module(lctx, i); if ( mod_start == NULL || (void *)m->mod_start == mod_start ) break; } /* not found */ if ( m == NULL ) { printk(TBOOT_ERR"could not find module to remove\n"); return NULL; } if (lctx->type == MB1_ONLY){ /* multiboot 1 */ /* if we're removing the first module (i.e. the "kernel") then */ /* need to adjust some mbi fields as well */ multiboot_info_t *mbi = (multiboot_info_t *) lctx->addr; if ( mod_start == NULL ) { mbi->cmdline = m->string; mbi->flags |= MBI_CMDLINE; mod_start = (void *)m->mod_start; } /* copy remaing mods down by one */ memmove(m, m + 1, (mbi->mods_count - i - 1)*sizeof(module_t)); mbi->mods_count--; return mod_start; } if (lctx->type == MB2_ONLY){ /* multiboot 2 */ /* if we're removing the first module (i.e. the "kernel") then */ /* need to adjust some mbi fields as well */ char cmdbuf[TBOOT_KERNEL_CMDLINE_SIZE]; cmdbuf[0] = '\0'; if ( mod_start == NULL ) { char *cmdline = get_cmdline(lctx); char *mod_string = get_module_cmd(lctx, m); if ((strlen(mod_string)) > (strlen(cmdline))){ if (strlen(mod_string) >= TBOOT_KERNEL_CMDLINE_SIZE){ printk(TBOOT_ERR"No room to copy MB2 cmdline [%d < %d]\n", (int)(strlen(cmdline)), (int)(strlen(mod_string))); } else { char *s = mod_string; char *d = cmdbuf; while (*s){ *d = *s; d++; s++; } *d = *s; // strcpy(cmdbuf, mod_string); } } else { // strcpy(cmdline,mod_string); char *s = mod_string; char *d = cmdline; while (*s){ *d = *s; d++; s++; } *d = *s; /* note: we didn't adjust the "size" field, since it didn't * grow and this saves us the pain of shuffling everything * after cmdline (which is usually first) */ } mod_start = (void *)m->mod_start; } /* so MB2 is a different beast. The modules aren't necessarily * adjacent, first, last, anything. What we can do is bulk copy * everything after the thing we're killing over the top of it, * and shorten the total length of the MB2 structure. */ { struct mb2_tag *cur; struct mb2_tag_module *mod = NULL; module_t *cur_mod = NULL; cur = (struct mb2_tag *)(lctx->addr + 8); cur = find_mb2_tag_type(cur, MB2_TAG_TYPE_MODULE); mod = (struct mb2_tag_module *) cur; if (mod != NULL) cur_mod = (module_t *)&(mod->mod_start); while (cur_mod != NULL && cur_mod != m){ /* nudge off current record */ cur = next_mb2_tag(cur); cur = find_mb2_tag_type(cur, MB2_TAG_TYPE_MODULE); mod = (struct mb2_tag_module *) cur; if (mod != NULL) cur_mod = (module_t *)&(mod->mod_start); else cur_mod = NULL; } if (cur_mod == NULL){ printk(TBOOT_ERR"remove_module() for MB2 failed\n"); return NULL; } /* we're here. cur is the MB2 tag we need to overwrite. */ if (false == remove_mb2_tag(lctx, cur)) return NULL; } if (cmdbuf[0] != '\0'){ /* we need to grow the mb2_tag_string that holds the cmdline. * we know there's room, since we've shortened the MB2 by the * length of the module_tag we've removed, which contained * the longer string. */ struct mb2_tag *cur = (struct mb2_tag *)(lctx->addr + 8); struct mb2_tag_string *cmd; cur = find_mb2_tag_type(cur, MB2_TAG_TYPE_CMDLINE); cmd = (struct mb2_tag_string *) cur; if (cmd == NULL){ printk(TBOOT_ERR"remove_modules MB2 shuffle NULL cmd\n"); return NULL; } grow_mb2_tag(lctx, cur, strlen(cmdbuf) - strlen(cmd->string)); /* now we're all good, except for fixing up cmd */ { char * s = cmdbuf; char *d = cmd->string; while (*s){ *d = *s; d++; s++; } *d = *s; } } return mod_start; } return NULL; } static bool adjust_kernel_cmdline(loader_ctx *lctx, const void *tboot_shared_addr) { const char *old_cmdline; if (lctx == NULL) return false; if (lctx->addr == NULL) return false; if (lctx->type == MB1_ONLY || lctx->type == MB2_ONLY){ old_cmdline = get_cmdline(lctx); if (old_cmdline == NULL) old_cmdline = ""; snprintf(new_cmdline, TBOOT_KERNEL_CMDLINE_SIZE, "%s tboot=%p", old_cmdline, tboot_shared_addr); new_cmdline[TBOOT_KERNEL_CMDLINE_SIZE - 1] = '\0'; if (lctx->type == MB1_ONLY){ /* multiboot 1 */ multiboot_info_t *mbi = (multiboot_info_t *) lctx->addr; /* assumes mbi is valid */ mbi->cmdline = (u32)new_cmdline; mbi->flags |= MBI_CMDLINE; return true; } if (lctx->type == MB2_ONLY){ /* multiboot 2 */ /* this is harder, since the strings sit inline */ /* we need to grow the mb2_tag_string that holds the cmdline. * TODO: should be checking that we're not running off the * end of the original MB2 space. */ struct mb2_tag *cur = (struct mb2_tag *)(lctx->addr + 8); struct mb2_tag_string *cmd; cur = find_mb2_tag_type(cur, MB2_TAG_TYPE_CMDLINE); cmd = (struct mb2_tag_string *) cur; if (cmd == NULL){ printk(TBOOT_ERR"adjust_kernel_cmdline() NULL MB2 cmd\n"); return NULL; } if (false == grow_mb2_tag(lctx, cur, strlen(new_cmdline) - strlen(cmd->string))) return false; /* now we're all good, except for fixing up cmd */ { char *s = new_cmdline; char *d = cmd->string; while (*s){ *d = *s; d++; s++; } *d = *s; } // strcpy(cmd->string, cmdbuf); cmd->size = 2 * sizeof(uint32_t) + strlen(cmd->string) + 1; } return true; } return false; } bool is_kernel_linux(void) { if ( !verify_loader_context(g_ldr_ctx) ) return false; // module_t *m = (module_t *)g_mbi->mods_addr; module_t *m = get_module(g_ldr_ctx, 0); void *kernel_image = (void *)m->mod_start; size_t kernel_size = m->mod_end - m->mod_start; return !is_elf_image(kernel_image, kernel_size); } static bool find_module(loader_ctx *lctx, void **base, size_t *size, const void *data, size_t len) { if ( lctx == NULL || lctx->addr == NULL) { printk(TBOOT_ERR"Error: context pointer is zero.\n"); return false; } if ( base == NULL ) { printk(TBOOT_ERR"Error: base is NULL.\n"); return false; } *base = NULL; if ( size != NULL ) *size = 0; if ( 0 == get_module_count(lctx)) { printk(TBOOT_ERR"Error: no module.\n"); return false; } for ( unsigned int i = get_module_count(lctx) - 1; i > 0; i-- ) { module_t *m = get_module(lctx, i); /* check size */ size_t mod_size = m->mod_end - m->mod_start; if ( len > mod_size ) { printk(TBOOT_ERR"Error: image size is smaller than data size.\n"); return false; } if ( memcmp((void *)m->mod_start, data, len) == 0 ) { *base = (void *)m->mod_start; if ( size != NULL ) *size = mod_size; return true; } } return false; } bool find_lcp_module(loader_ctx *lctx, void **base, uint32_t *size) { size_t size2 = 0; void *base2 = NULL; if ( base != NULL ) *base = NULL; if ( size != NULL ) *size = 0; /* try policy data file for old version (0x00 or 0x01) */ find_module_by_uuid(lctx, &base2, &size2, &((uuid_t)LCP_POLICY_DATA_UUID)); /* not found */ if ( base2 == NULL ) { /* try policy data file for new version (0x0202) */ find_module_by_file_signature(lctx, &base2, &size2, LCP_POLICY_DATA_FILE_SIGNATURE); if ( base2 == NULL ) { printk(TBOOT_WARN"no LCP module found\n"); return false; } else printk(TBOOT_INFO"v2 LCP policy data found\n"); } else printk(TBOOT_INFO"v1 LCP policy data found\n"); if ( base != NULL ) *base = base2; if ( size != NULL ) *size = size2; return true; } /* * remove (all) SINIT and LCP policy data modules (if present) */ bool remove_txt_modules(loader_ctx *lctx) { if ( 0 == get_module_count(lctx)) { printk(TBOOT_ERR"Error: no module.\n"); return false; } /* start at end of list so that we can remove w/in the loop */ for ( unsigned int i = get_module_count(lctx) - 1; i > 0; i-- ) { module_t *m = get_module(lctx, i); void *base = (void *)m->mod_start; if ( is_sinit_acmod(base, m->mod_end - (unsigned long)base, true) ) { printk(TBOOT_INFO"got sinit match on module #%d\n", i); if ( remove_module(lctx, base) == NULL ) { printk(TBOOT_ERR "failed to remove SINIT module from module list\n"); return false; } } } void *base = NULL; if ( find_lcp_module(lctx, &base, NULL) ) { if ( remove_module(lctx, base) == NULL ) { printk(TBOOT_ERR"failed to remove LCP module from module list\n"); return false; } } return true; } extern unsigned long get_tboot_mem_end(void); static bool below_tboot(unsigned long addr) { return addr >= 0x100000 && addr < TBOOT_BASE_ADDR; } static unsigned long max(unsigned long a, unsigned long b) { return (a > b) ? a : b; } static unsigned long get_mbi_mem_end_mb1(const multiboot_info_t *mbi) { unsigned long end = (unsigned long)(mbi + 1); if ( mbi->flags & MBI_CMDLINE ) end = max(end, mbi->cmdline + strlen((char *)mbi->cmdline) + 1); if ( mbi->flags & MBI_MODULES ) { end = max(end, mbi->mods_addr + mbi->mods_count * sizeof(module_t)); unsigned int i; for ( i = 0; i < mbi->mods_count; i++ ) { module_t *p = get_module_mb1(mbi, i); end = max(end, p->string + strlen((char *)p->string) + 1); } } if ( mbi->flags & MBI_AOUT ) { const aout_t *p = &(mbi->syms.aout_image); end = max(end, p->addr + p->tabsize + sizeof(unsigned long) + p->strsize); } if ( mbi->flags & MBI_ELF ) { const elf_t *p = &(mbi->syms.elf_image); end = max(end, p->addr + p->num * p->size); } if ( mbi->flags & MBI_MEMMAP ) end = max(end, mbi->mmap_addr + mbi->mmap_length); if ( mbi->flags & MBI_DRIVES ) end = max(end, mbi->drives_addr + mbi->drives_length); /* mbi->config_table field should contain */ /* "the address of the rom configuration table returned by the */ /* GET CONFIGURATION bios call", so skip it */ if ( mbi->flags & MBI_BTLDNAME ) end = max(end, mbi->boot_loader_name + strlen((char *)mbi->boot_loader_name) + 1); if ( mbi->flags & MBI_APM ) /* per Grub-multiboot-Main Part2 Rev94-Structures, apm size is 20 */ end = max(end, mbi->apm_table + 20); if ( mbi->flags & MBI_VBE ) { /* VBE2.0, VBE Function 00 return 512 bytes*/ end = max(end, mbi->vbe_control_info + 512); /* VBE2.0, VBE Function 01 return 256 bytes*/ end = max(end, mbi->vbe_mode_info + 256); } return PAGE_UP(end); } static void fixup_modules(loader_ctx *lctx, size_t offset) { unsigned int module_count = get_module_count(lctx); for ( unsigned int i = 0; i < module_count; i++ ) { module_t *m = get_module(lctx, i); if ( below_tboot(m->mod_start) ) { m->mod_start += offset; m->mod_end += offset; } /* MB2 module strings are inline, not addresses */ if (lctx->type == 1) if ( below_tboot(m->string) ) m->string += offset; } } /* * fixup_loader_ctx() is to be called after modules and/or mbi are moved from * below tboot memory to above tboot. It will fixup all pointers in mbi if * mbi was moved; fixup modules table if any modules are moved. If mbi was * moved, adjust the addr field in context, otherwise, leave alone. */ static void fixup_loader_ctx(loader_ctx *lctx, size_t offset) { if (LOADER_CTX_BAD(lctx)) return; bool moving_ctx = below_tboot((unsigned long)lctx->addr); multiboot_info_t *mbi = lctx->addr; if ( moving_ctx ) { printk(TBOOT_INFO"loader context was moved from %p to ", lctx->addr); lctx->addr += offset; printk(TBOOT_INFO"%p\n", lctx->addr); } if (0 < get_module_count(lctx)) { if (lctx->type == MB1_ONLY) if ( below_tboot(mbi->mods_addr) ) mbi->mods_addr += offset; /* not required for MB2--if we moved the pile, we moved this too */ fixup_modules(lctx, offset); } if (lctx->type == MB1_ONLY){ /* RLM change. There's no use passing these on to Xen or whatever, * since they will be tboot's addrs, not the target's! We don't * want the thing we launch using tboot image addresses to deduce * anything about itself! */ if (mbi->flags & MBI_AOUT){ mbi->syms.aout_image.addr = 0; mbi->flags &= ~MBI_AOUT; } if (mbi->flags & MBI_ELF){ mbi->syms.elf_image.addr = 0; mbi->flags &= ~MBI_ELF; } } if (lctx->type == MB2_ONLY){ struct mb2_tag *start, *victim; /* as above, we need to remove ELF tag if we have it */ start = (struct mb2_tag *) (lctx->addr + 8); victim = find_mb2_tag_type(start, MB2_TAG_TYPE_ELF_SECTIONS); if (victim != NULL) (void) remove_mb2_tag(lctx,victim); /* and that's all, folks! */ return; } if ( !moving_ctx) return; /* tboot replace mmap_addr w/ a copy, and make a copy of cmdline * because we modify it. Those pointers don't need offset adjustment. * To make it general and depend less on such kind of changes, just * check whether we need to adjust offset before trying to do it for * each field */ if ( (mbi->flags & MBI_CMDLINE) && below_tboot(mbi->cmdline) ) mbi->cmdline += offset; if ( (mbi->flags & MBI_MEMMAP) && below_tboot(mbi->mmap_addr) ) mbi->mmap_addr += offset; if ( (mbi->flags & MBI_DRIVES) && below_tboot(mbi->drives_addr) ) mbi->drives_addr += offset; if ( (mbi->flags & MBI_CONFIG) && below_tboot(mbi->config_table) ) mbi->config_table += offset; if ( (mbi->flags & MBI_BTLDNAME) && below_tboot(mbi->boot_loader_name) ) mbi->boot_loader_name += offset; if ( (mbi->flags & MBI_APM) && below_tboot(mbi->apm_table) ) mbi->apm_table += offset; if ( mbi->flags & MBI_VBE ) { if ( below_tboot(mbi->vbe_control_info) ) mbi->vbe_control_info += offset; if ( below_tboot(mbi->vbe_mode_info) ) mbi->vbe_mode_info += offset; } return; } static uint32_t get_lowest_mod_start(loader_ctx *lctx) { uint32_t lowest = 0xffffffff; unsigned int mod_count = get_module_count(lctx); for ( unsigned int i = 0; i < mod_count; i++ ) { module_t *m = get_module(lctx, i); if ( m->mod_start < lowest ) lowest = m->mod_start; } return lowest; } static uint32_t get_highest_mod_end(loader_ctx *lctx) { uint32_t highest = 0; unsigned int mod_count = get_module_count(lctx); for ( unsigned int i = 0; i < mod_count; i++ ) { module_t *m = get_module(lctx, i); if ( m->mod_end > highest ) highest = m->mod_end; } return highest; } /* * Move any mbi components/modules/mbi that are below tboot to just above tboot */ static void move_modules(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return; unsigned long lowest = get_lowest_mod_start(lctx); unsigned long from = 0; if ( below_tboot(lowest) ) from = lowest; else if ( below_tboot((unsigned long)lctx->addr) ) from = (unsigned long)lctx->addr; else return; unsigned long highest = get_highest_mod_end(lctx); unsigned long to = PAGE_UP(highest); if ( to < get_tboot_mem_end() ) to = get_tboot_mem_end(); /* * assuming that all of the members of mbi (e.g. cmdline, * syms.aout_image.addr, etc.) are contiguous with the mbi structure */ if ( to < get_loader_ctx_end(lctx) ) to = get_loader_ctx_end(lctx); memcpy((void *)to, (void *)from, TBOOT_BASE_ADDR - from); printk(TBOOT_DETA"0x%lx bytes copied from 0x%lx to 0x%lx\n", TBOOT_BASE_ADDR - from, from, to); fixup_loader_ctx(lctx, to - from); return; } module_t *get_module(loader_ctx *lctx, unsigned int i) { if (LOADER_CTX_BAD(lctx)) return NULL; if (lctx->type == MB1_ONLY){ return(get_module_mb1((multiboot_info_t *) lctx->addr, i)); } else { /* so currently, must be type 2 */ return(get_module_mb2(lctx, i)); } } static void *remove_first_module(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return NULL; return(remove_module(lctx, NULL)); } /* a shame this has to be so big, but if we get an MB2 VBE struct, * those are pretty close to 1K on their own. */ #define MB2_TEMP_SIZE 512 static uint32_t mb2_temp[MB2_TEMP_SIZE]; static bool convert_mb2_to_mb1(void) { /* it's too hard to do this in place. MB2 "data" is all inline, so * it can be copied to a new location, as is, and still be intact. MB1 * has pointers in the info struct to other stuff further along in its * stuff, so it doesn't copy/move well. We'll make a copy of the MB2 * info, and then build the MB1 in place where the MB2 we started with was. */ uint32_t mb2_size; multiboot_info_t *mbi; uint32_t i, obd; if (LOADER_CTX_BAD(g_ldr_ctx)) return false; if (g_ldr_ctx->type != MB2_ONLY) return false; mb2_size = *((uint32_t *)g_ldr_ctx->addr); if (mb2_size >= MB2_TEMP_SIZE * 4) return false; /* copy it all to temp */ { uint8_t *s, *d; s = (uint8_t *) g_ldr_ctx->addr; d = (uint8_t *) mb2_temp; for (i = 0; i < mb2_size; i++) d[i] = s[i]; mbi = (multiboot_info_t *) g_ldr_ctx->addr; g_ldr_ctx->addr = mb2_temp; for (i = 0; i < mb2_size; i++) ((uint8_t *)mbi)[i] = 0; } /* out of band data pointer */ obd = (uint32_t) mbi + sizeof(multiboot_info_t); /* uint32 align it, just in case */ obd = (obd + 3) & ~3; /* do we have mem_limits? */ if (have_loader_memlimits(g_ldr_ctx)){ mbi->flags |= MBI_MEMLIMITS; mbi->mem_lower = get_loader_mem_lower(g_ldr_ctx); mbi->mem_upper = get_loader_mem_upper(g_ldr_ctx); } /* do we have a boot device? */ { struct mb2_tag *start = (struct mb2_tag *)(g_ldr_ctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_BOOTDEV); if (start != NULL){ struct mb2_tag_bootdev *bd = (struct mb2_tag_bootdev *) start; mbi->flags |= MBI_BOOTDEV; mbi->boot_device.bios_driver = bd->biosdev; mbi->boot_device.top_level_partition = bd->part; mbi->boot_device.sub_partition = bd->slice; mbi->boot_device.third_partition = 0xff; } } /* command line */ { const char *mb2_cmd = get_cmdline(g_ldr_ctx); if (mb2_cmd){ char *mb1_cmd = (char *) obd; while (*mb2_cmd){ *mb1_cmd = *mb2_cmd; mb1_cmd++; mb2_cmd++; obd++; } /* uint32_t align it again */ obd = (obd + 3) & ~3; mbi->flags |= MBI_CMDLINE; } } /* modules--in MB1, this is a count and a pointer to an array of module_t */ mbi->mods_count = get_module_count(g_ldr_ctx); if (mbi->mods_count > 0){ /* for mb1, the modulke strings are out-of-band */ uint32_t obd_str = obd + (mbi->mods_count * sizeof(module_t)); mbi->mods_addr = obd; for (i = 0; i < mbi->mods_count; i++){ module_t *mb1_mt = (module_t *) obd; module_t *mb2_mt = get_module(g_ldr_ctx, i); char *s = (char *)&mb2_mt->string; mb1_mt->mod_start = mb2_mt->mod_start; mb1_mt->mod_end = mb2_mt->mod_end; mb1_mt->reserved = 0; if (*s){ char *d = (char *) obd_str; mb1_mt->string = obd_str; while (*s){ *d = *s; d++; s++; obd_str++; } *d = *s; obd_str++; } else { mb1_mt->string = 0; } } /* uint32_t align past the strings */ obd = (obd_str + 3) & ~3; mbi->flags |= MBI_MODULES; } /* a.out/elf sections--we know these are not there */ /* memory map--we can just use the modified copy for this one */ if (have_loader_memmap(g_ldr_ctx)){ mbi->mmap_addr = (uint32_t)get_e820_copy(); mbi->mmap_length = (get_nr_map()) * sizeof(memory_map_t); mbi->flags |= MBI_MEMMAP; } /* drives info --there's no equivalent in MB2 */ /* config table -- again, nothing equivalent? */ /* boot loader name */ { struct mb2_tag *start = (struct mb2_tag *)(g_ldr_ctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_LOADER_NAME); if (start){ struct mb2_tag_string *bload = (struct mb2_tag_string *) start; char *s, *d; mbi->boot_loader_name = obd; s = (char *) &bload->string[0]; d = (char *) obd; while (*s){ *d = *s; s++; d++; obd++; } *d = *s; obd++; obd = (obd + 3) & ~3; mbi->flags |= MBI_BTLDNAME; } } /* apm table */ { struct mb2_tag *start = (struct mb2_tag *)(g_ldr_ctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_APM); if (start){ struct mb2_tag_apm *apm = (struct mb2_tag_apm *) start; uint8_t *s, *d; s = (uint8_t *)&apm->version; d = (uint8_t *) obd; mbi->apm_table = obd; for (i = 0; i < sizeof(struct mb2_tag_apm) - sizeof(uint32_t); i++){ *d = *s; d++; s++; obd++; } obd = (obd + 3) & ~3; mbi->flags |= MBI_APM; } } /* vbe poop, if we can get these to map across */ { struct mb2_tag *start = (struct mb2_tag *)(g_ldr_ctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_VBE); if (start){ struct mb2_tag_vbe *vbe = (struct mb2_tag_vbe *) start; uint8_t *s, *d; mbi->vbe_mode = vbe->vbe_mode; mbi->vbe_interface_seg = vbe->vbe_interface_seg; mbi->vbe_interface_off = vbe->vbe_interface_off; mbi->vbe_interface_len = vbe->vbe_interface_len; mbi->vbe_control_info = obd; d = (uint8_t *) obd; s = &vbe->vbe_control_info.external_specification[0]; for (i = 0; i < 512; i++){ *d = *s; d++; s++; obd++; } /* if obd was aligned before, it still is */ mbi->vbe_mode_info = obd; d = (uint8_t *) obd; s = &vbe->vbe_mode_info.external_specification[0]; for (i = 0; i < 256; i++){ *d = *s; d++; s++; obd++; } mbi->flags |= MBI_VBE; } } /* all good--point g_ldr_ctx addr to new, fix type */ g_ldr_ctx->addr = (void *)&mbi; g_ldr_ctx->type = MB1_ONLY; return true; } static uint32_t determine_multiboot_type(void *image) { /* walk through the allowed region looking for multiboot header magic */ /* note that we're going low-tech--we're not verifying a valid header, * and probably should. */ int result = MB_NONE; void *walker; for (walker = image; walker < walker + MULTIBOOT_HEADER_SEARCH_LIMIT; walker += sizeof(uint32_t)){ if (*((uint32_t *)walker) == MULTIBOOT_HEADER_MAGIC){ result += MB1_ONLY; break; } } for (walker = image; walker < walker + MB2_HEADER_SEARCH_LIMIT; walker += sizeof(uint64_t)){ if (*((uint32_t *)walker) == MB2_HEADER_MAGIC){ result += MB2_ONLY; break; } } return result; } bool launch_kernel(bool is_measured_launch) { enum { ELF, LINUX } kernel_type; void *kernel_entry_point; uint32_t mb_type = MB_NONE; if ( !verify_loader_context(g_ldr_ctx) ) return false; /* remove all SINIT and LCP modules since kernel may not handle */ remove_txt_modules(g_ldr_ctx); module_t *m = get_module(g_ldr_ctx,0); void *kernel_image = (void *)m->mod_start; size_t kernel_size = m->mod_end - m->mod_start; if ( is_elf_image(kernel_image, kernel_size) ) { printk(TBOOT_INFO"kernel is ELF format\n"); kernel_type = ELF; mb_type = determine_multiboot_type(kernel_image); switch (mb_type){ case MB1_ONLY: /* if this is an EFI boot, this is not sufficient */ if (is_loader_launch_efi(g_ldr_ctx)){ printk(TBOOT_ERR"Target kernel only supports multiboot1 "); printk(TBOOT_ERR"which will not suffice for EFI launch\n"); return false; } /* if we got MB2 and they want MB1 and this is trad BIOS, * we can downrev the MB data to MB1 and pass that along. */ if (g_ldr_ctx->type == MB2_ONLY){ if (false == convert_mb2_to_mb1()) return false; } break; case MB2_ONLY: /* if we got MB1, we need to die here */ if (g_ldr_ctx->type == MB1_ONLY){ printk(TBOOT_ERR"Target requires multiboot 2, loader only "); printk(TBOOT_ERR"supplied multiboot 1m giving up\n"); return false; } break; case MB_BOTH: /* we'll pass through whichever we got, and hope */ mb_type = g_ldr_ctx->type; break; default: printk(TBOOT_INFO"but kernel does not have multiboot header\n"); return false; } /* fix for GRUB2, which may load modules into memory before tboot */ move_modules(g_ldr_ctx); } else { printk(TBOOT_INFO"assuming kernel is Linux format\n"); kernel_type = LINUX; } /* print_mbi(g_mbi); */ kernel_image = remove_first_module(g_ldr_ctx); if ( kernel_image == NULL ) return false; if ( kernel_type == ELF ) { if ( is_measured_launch ) adjust_kernel_cmdline(g_ldr_ctx, &_tboot_shared); if ( !expand_elf_image((elf_header_t *)kernel_image, &kernel_entry_point) ) return false; printk(TBOOT_INFO"transfering control to kernel @%p...\n", kernel_entry_point); /* (optionally) pause when transferring to kernel */ if ( g_vga_delay > 0 ) delay(g_vga_delay * 1000); return jump_elf_image(kernel_entry_point, mb_type == MB1_ONLY ? MB_MAGIC : MB2_LOADER_MAGIC); } else if ( kernel_type == LINUX ) { m = get_module(g_ldr_ctx,0); void *initrd_image = (void *)m->mod_start; size_t initrd_size = m->mod_end - m->mod_start; expand_linux_image(kernel_image, kernel_size, initrd_image, initrd_size, &kernel_entry_point, is_measured_launch); printk(TBOOT_INFO"transfering control to kernel @%p...\n", kernel_entry_point); /* (optionally) pause when transferring to kernel */ if ( g_vga_delay > 0 ) delay(g_vga_delay * 1000); return jump_linux_image(kernel_entry_point); } printk(TBOOT_ERR"unknown kernel type\n"); return false; } /* * find_module_by_uuid * * find a module by its uuid * */ bool find_module_by_uuid(loader_ctx *lctx, void **base, size_t *size, const uuid_t *uuid) { return find_module(lctx, base, size, uuid, sizeof(*uuid)); } /* * find_module_by_file_signature * * find a module by its file signature * */ bool find_module_by_file_signature(loader_ctx *lctx, void **base, size_t *size, const char* file_signature) { return find_module(lctx, base, size, file_signature, strlen(file_signature)); } bool verify_modules(loader_ctx *lctx) { uint64_t base, size; module_t *m; uint32_t module_count; if (LOADER_CTX_BAD(lctx)) return false; module_count = get_module_count(lctx); /* verify e820 map to make sure each module is OK in e820 map */ /* check modules in mbi should be in RAM */ for ( unsigned int i = 0; i < module_count; i++ ) { m = get_module(lctx,i); base = m->mod_start; size = m->mod_end - m->mod_start; printk(TBOOT_INFO "verifying module %d of mbi (%Lx - %Lx) in e820 table\n\t", i, base, (base + size - 1)); if ( e820_check_region(base, size) != E820_RAM ) { printk(TBOOT_ERR": failed.\n"); return false; } else printk(TBOOT_INFO": succeeded.\n"); } return true; } char *get_module_cmd(loader_ctx *lctx, module_t *mod) { if (LOADER_CTX_BAD(lctx) || mod == NULL) return NULL; if (lctx->type == MB1_ONLY) return (char *) mod->string; else /* currently must be type 2 */ return (char *)&(mod->string); } char *get_first_module_cmd(loader_ctx *lctx) { module_t *mod = get_module(lctx, 0); return get_module_cmd(lctx, mod); } char *get_cmdline(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return NULL; if (lctx->type == MB1_ONLY){ /* multiboot 1 */ if (((multiboot_info_t *)lctx->addr)->flags & MBI_CMDLINE){ return (char *) ((multiboot_info_t *)lctx->addr)->cmdline; } else { return NULL; } } else { /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_CMDLINE); if (start != NULL){ struct mb2_tag_string *cmd = (struct mb2_tag_string *) start; return (char *) &(cmd->string); } return NULL; } } bool have_loader_memlimits(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return false; if (lctx->type == MB1_ONLY){ return (((multiboot_info_t *)lctx->addr)->flags & MBI_MEMLIMITS) != 0; } else { /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_MEMLIMITS); return (start != NULL); } } uint32_t get_loader_mem_lower(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return 0; if (lctx->type == MB1_ONLY){ return ((multiboot_info_t *)lctx->addr)->mem_lower; } /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_MEMLIMITS); if (start != NULL){ struct mb2_tag_memlimits *lim = (struct mb2_tag_memlimits *) start; return lim->mem_lower; } return 0; } uint32_t get_loader_mem_upper(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return 0; if (lctx->type == MB1_ONLY){ return ((multiboot_info_t *)lctx->addr)->mem_upper; } /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_MEMLIMITS); if (start != NULL){ struct mb2_tag_memlimits *lim = (struct mb2_tag_memlimits *) start; return lim->mem_upper; } return 0; } unsigned int get_module_count(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return 0; if (lctx->type == MB1_ONLY){ return(((multiboot_info_t *) lctx->addr)->mods_count); } else { /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); unsigned int count = 0; start = find_mb2_tag_type(start, MB2_TAG_TYPE_MODULE); while (start != NULL){ count++; /* nudge off this guy */ start = next_mb2_tag(start); start = find_mb2_tag_type(start, MB2_TAG_TYPE_MODULE); } return count; } } bool have_loader_memmap(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return false; if (lctx->type == MB1_ONLY){ return (((multiboot_info_t *) lctx->addr)->flags & MBI_MEMMAP) != 0; } else { /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_MMAP); return (start != NULL); } } memory_map_t *get_loader_memmap(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return NULL; if (lctx->type == MB1_ONLY){ /* multiboot 1 */ return (memory_map_t *)((multiboot_info_t *) lctx->addr)->mmap_addr; } else { /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_MMAP); if (start != NULL){ struct mb2_tag_mmap *mmap = (struct mb2_tag_mmap *) start; /* note here: the MB2 mem entries start with the 64-bit address. * the memory_map_t starts with four bytes of dummy "size". * Pointing to the MB2 mmap "entry_version" instead of the entries * lines the two tables up. */ return (memory_map_t *) &(mmap->entry_version); } return NULL; } } uint32_t get_loader_memmap_length(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return 0; if (lctx->type == MB1_ONLY){ /* multiboot 1 */ return (uint32_t)((multiboot_info_t *) lctx->addr)->mmap_length; } else { /* currently must be type 2 */ struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_MMAP); if (start != NULL){ struct mb2_tag_mmap *mmap = (struct mb2_tag_mmap *) start; /* mmap->size is the size of the whole tag. We have 16 bytes * ahead of the entries */ return mmap->size - 16; } return 0; } } unsigned long get_loader_ctx_end(loader_ctx *lctx) { if (LOADER_CTX_BAD(lctx)) return 0; if (lctx->type == 1){ /* multiboot 1 */ return (get_mbi_mem_end_mb1((multiboot_info_t *) lctx->addr)); } else { /* currently must be type 2 */ unsigned long mb2_size = *((unsigned long *) lctx->addr); return PAGE_UP(mb2_size + (unsigned long) lctx->addr); } } /* * will go through all modules to find an RACM that matches the platform * (size can be NULL) */ bool find_platform_racm(loader_ctx *lctx, void **base, uint32_t *size) { if ( base != NULL ) *base = NULL; if ( size != NULL ) *size = 0; if ( 0 == get_module_count(lctx)) { printk(TBOOT_ERR"no module info\n"); return false; } for ( int i = get_module_count(lctx) - 1; i >= 0; i-- ) { module_t *m = get_module(lctx, i); printk(TBOOT_DETA "checking if module %s is an RACM for this platform...\n", get_module_cmd(lctx, m)); void *base2 = (void *)m->mod_start; uint32_t size2 = m->mod_end - (unsigned long)(base2); if ( is_racm_acmod(base2, size2, false) && does_acmod_match_platform((acm_hdr_t *)base2) ) { if ( base != NULL ) *base = base2; if ( size != NULL ) *size = size2; printk(TBOOT_DETA"RACM matches platform\n"); return true; } } /* no RACM found for this platform */ printk(TBOOT_ERR"no RACM found\n"); return false; } /* * will go through all modules to find an SINIT that matches the platform * (size can be NULL) */ bool find_platform_sinit_module(loader_ctx *lctx, void **base, uint32_t *size) { if ( base != NULL ) *base = NULL; if ( size != NULL ) *size = 0; if ( 0 == get_module_count(lctx)) { printk(TBOOT_ERR"no module info\n"); return false; } for ( unsigned int i = get_module_count(lctx) - 1; i > 0; i-- ) { module_t *m = get_module(lctx, i); if (lctx->type == 1) printk(TBOOT_DETA "checking if module %s is an SINIT for this platform...\n", (const char *)m->string); if (lctx->type == 2) printk(TBOOT_DETA "checking if module %s is an SINIT for this platform...\n", (const char *)&(m->string)); void *base2 = (void *)m->mod_start; uint32_t size2 = m->mod_end - (unsigned long)(base2); if ( is_sinit_acmod(base2, size2, false) && does_acmod_match_platform((acm_hdr_t *)base2) ) { if ( base != NULL ) *base = base2; if ( size != NULL ) *size = size2; printk(TBOOT_DETA"SINIT matches platform\n"); return true; } } /* no SINIT found for this platform */ printk(TBOOT_ERR"no SINIT AC module found\n"); return false; } void replace_e820_map(loader_ctx *lctx) { /* replace original with the copy */ if (LOADER_CTX_BAD(lctx)) return; if (lctx->type == MB1_ONLY){ /* multiboot 1 */ multiboot_info_t *mbi = (multiboot_info_t *) lctx->addr; mbi->mmap_addr = (uint32_t)get_e820_copy(); mbi->mmap_length = (get_nr_map()) * sizeof(memory_map_t); mbi->flags |= MBI_MEMMAP; /* in case only MBI_MEMLIMITS was set */ return; } else { /* currently must be type 2 */ memory_map_t *old, *new; uint32_t i; uint32_t old_memmap_size = get_loader_memmap_length(lctx); uint32_t old_memmap_entry_count = old_memmap_size / sizeof(memory_map_t); if (old_memmap_entry_count < (get_nr_map())){ /* we have to grow */ struct mb2_tag *map = (struct mb2_tag *)(lctx->addr + 8); map = find_mb2_tag_type(map, MB2_TAG_TYPE_MMAP); if (map == NULL){ printk(TBOOT_ERR"MB2 map not found\n"); return; } if (false == grow_mb2_tag(lctx, map, sizeof(memory_map_t) * ((get_nr_map()) - old_memmap_entry_count))){ printk(TBOOT_ERR"MB2 failed to grow e820 map tag\n"); return; } } /* copy in new data */ { /* RLM: for now, we'll leave the entries in MB1 format (with real * size). That may need revisited. */ new = get_e820_copy(); old = get_loader_memmap(lctx); for (i = 0; i < (get_nr_map()); i++){ *old = *new; old++, new++; } } /* printk(TBOOT_INFO"AFTER replace_e820_map, loader context:\n"); print_loader_ctx(lctx); */ printk(TBOOT_INFO"replaced memory map:\n"); print_e820_map(); return; } return; } void print_loader_ctx(loader_ctx *lctx) { if (lctx->type != MB2_ONLY){ printk(TBOOT_ERR"this routine only prints out multiboot 2\n"); return; } else { struct mb2_tag *start = (struct mb2_tag *)(lctx->addr + 8); printk(TBOOT_INFO"MB2 dump, size %d\n", *(uint32_t *)lctx->addr); while (start != NULL){ printk(TBOOT_INFO"MB2 tag found of type %d size %d ", start->type, start->size); switch (start->type){ case MB2_TAG_TYPE_CMDLINE: case MB2_TAG_TYPE_LOADER_NAME: { struct mb2_tag_string *ts = (struct mb2_tag_string *) start; printk(TBOOT_INFO"%s", ts->string); } break; case MB2_TAG_TYPE_MODULE: { struct mb2_tag_module *ts = (struct mb2_tag_module *) start; printk_long(ts->cmdline); } break; default: break; } printk(TBOOT_INFO"\n"); start = next_mb2_tag(start); } return; } } uint8_t *get_loader_rsdp(loader_ctx *lctx, uint32_t *length) { struct mb2_tag *start; struct mb2_tag_new_acpi *new_acpi; if (LOADER_CTX_BAD(lctx)) return NULL; if (lctx->type != MB2_ONLY) return NULL; if (length == NULL) return NULL; start = (struct mb2_tag *) (lctx->addr + 8); new_acpi = (struct mb2_tag_new_acpi *) find_mb2_tag_type(start, MB2_TAG_TYPE_ACPI_NEW); if (new_acpi == NULL){ /* we'll try the old type--the tag structs are the same */ new_acpi = (struct mb2_tag_new_acpi *) find_mb2_tag_type(start, MB2_TAG_TYPE_ACPI_OLD); if (new_acpi == NULL) return NULL; } *length = new_acpi->size - 8; return new_acpi->rsdp; } bool get_loader_efi_ptr(loader_ctx *lctx, uint32_t *address, uint64_t *long_address) { struct mb2_tag *start, *hit; struct mb2_tag_efi32 *efi32; struct mb2_tag_efi64 *efi64; if (LOADER_CTX_BAD(lctx)) return false; if (lctx->type != MB2_ONLY) return false; start = (struct mb2_tag *)(lctx->addr + 8); hit = find_mb2_tag_type(start, MB2_TAG_TYPE_EFI32); if (hit != NULL){ efi32 = (struct mb2_tag_efi32 *) hit; *address = (uint32_t) efi32->pointer; *long_address = 0; return true; } hit = find_mb2_tag_type(start, MB2_TAG_TYPE_EFI64); if (hit != NULL){ efi64 = (struct mb2_tag_efi64 *) hit; *long_address = (uint64_t) efi64->pointer; *address = 0; return true; } return false; } bool is_loader_launch_efi(loader_ctx *lctx) { uint32_t addr = 0; uint64_t long_addr = 0; if (LOADER_CTX_BAD(lctx)) return false; return (get_loader_efi_ptr(lctx, &addr, &long_addr)); } void load_framebuffer_info(loader_ctx *lctx, void *vscr) { screen_info_t *scr = (screen_info_t *) vscr; struct mb2_tag *start; if (scr == NULL) return; if (LOADER_CTX_BAD(lctx)) return; start = (struct mb2_tag *)(lctx->addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_FRAMEBUFFER); if (start != NULL){ struct mb2_fb *mbf = (struct mb2_fb *) start; scr->lfb_base = (uint32_t) mbf->common.fb_addr; scr->lfb_width = mbf->common.fb_width; scr->lfb_height = mbf->common.fb_height; scr->lfb_depth = mbf->common.fb_bpp; scr->lfb_line_len = mbf->common.fb_pitch; scr->red_mask_size = mbf->fb_red_mask_size; scr->red_field_pos = mbf->fb_red_field_position; scr->blue_mask_size = mbf->fb_blue_mask_size; scr->blue_field_pos = mbf->fb_blue_field_position; scr->green_mask_size = mbf->fb_green_mask_size; scr->green_field_pos = mbf->fb_green_field_position; scr->lfb_size = scr->lfb_line_len * scr->lfb_height; /* round up to next 64k */ scr->lfb_size = (scr->lfb_size + 65535) & 65535; scr->orig_video_isVGA = 0x70; /* EFI FB */ scr->orig_y = 24; } } void determine_loader_type(void *addr, uint32_t magic) { if (g_ldr_ctx->addr == NULL){ /* brave new world */ g_ldr_ctx->addr = addr; /* save for post launch */ switch (magic){ case MB_MAGIC: g_ldr_ctx->type = MB1_ONLY; { /* we may as well do this here--if we received an ELF * sections tag, we won't use it, and it's useless to * Xen downstream, since it's OUR ELF sections, not Xen's */ multiboot_info_t *mbi = (multiboot_info_t *) addr; if (mbi->flags & MBI_AOUT){ mbi->flags &= ~MBI_AOUT; } if (mbi->flags & MBI_ELF){ mbi->flags &= ~MBI_ELF; } } break; case MB2_LOADER_MAGIC: g_ldr_ctx->type = MB2_ONLY; /* save the original MB2 info size, since we have * to put updates inline */ g_mb_orig_size = *(uint32_t *) addr; { /* we may as well do this here--if we received an ELF * sections tag, we won't use it, and it's useless to * Xen downstream, since it's OUR ELF sections, not Xen's */ struct mb2_tag *start = (struct mb2_tag *)(addr + 8); start = find_mb2_tag_type(start, MB2_TAG_TYPE_ELF_SECTIONS); if (start != NULL) (void) remove_mb2_tag(g_ldr_ctx, start); } break; default: g_ldr_ctx->type = 0; break; } } /* so at this point, g_ldr_ctx->type has one of three values: * 0: not a multiboot launch--we're doomed * 1: MB1 launch * 2: MB2 launch */ } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/common/memcmp.c0000644000000000000000000000375312272416301015044 0ustar 00000000000000/*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * 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. */ /* $FreeBSD: src/sys/libkern/memcmp.c,v 1.1 2008/09/23 14:45:10 obrien Exp $ */ #include /* * 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); } tboot-1.8.0/tboot/common/memcpy.c0000644000000000000000000000715112272416301015054 0ustar 00000000000000/*- * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * 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. */ /* $FreeBSD: src/sys/powerpc/powerpc/bcopy.c,v 1.5.24.1 2010/02/10 00:26:20 kensmith Exp $ */ #include /* * sizeof(word) MUST BE A POWER OF TWO * SO THAT wmask BELOW IS ALL ONES */ typedef int word; /* "word" used for optimal copy speed */ #define wsize sizeof(word) #define wmask (wsize - 1) /* * Copy a block of memory, handling overlap. * This is the routine that actually implements * (the portable versions of) bcopy, memcpy, and memmove. */ void *memcpy(void *dst0, const void *src0, size_t length) { char *dst; const char *src; size_t t; dst = dst0; src = src0; if (length == 0 || dst == src) { /* nothing to do */ goto done; } /* * Macros: loop-t-times; and loop-t-times, t>0 */ #define TLOOP(s) if (t) TLOOP1(s) #define TLOOP1(s) do { s; } while (--t) if ((unsigned long)dst < (unsigned long)src) { /* * Copy forward. */ t = (int)src; /* only need low bits */ if ((t | (int)dst) & wmask) { /* * Try to align operands. This cannot be done * unless the low bits match. */ if ((t ^ (int)dst) & wmask || length < wsize) { t = length; } else { t = wsize - (t & wmask); } length -= t; TLOOP1(*dst++ = *src++); } /* * Copy whole words, then mop up any trailing bytes. */ t = length / wsize; TLOOP(*(word *)dst = *(const word *)src; src += wsize; dst += wsize); t = length & wmask; TLOOP(*dst++ = *src++); } else { /* * Copy backwards. Otherwise essentially the same. * Alignment works as before, except that it takes * (t&wmask) bytes to align, not wsize-(t&wmask). */ src += length; dst += length; t = (int)src; if ((t | (int)dst) & wmask) { if ((t ^ (int)dst) & wmask || length <= wsize) { t = length; } else { t &= wmask; } length -= t; TLOOP1(*--dst = *--src); } t = length / wsize; TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(const word *)src); t = length & wmask; TLOOP(*--dst = *--src); } done: return (dst0); } tboot-1.8.0/tboot/common/misc.c0000644000000000000000000002340312272416301014513 0ustar 00000000000000/* * 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 /* * 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"); } 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(); } } /* 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[257] = { _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: */ tboot-1.8.0/tboot/common/mutex.S0000644000000000000000000000372112272416301014703 0ustar 00000000000000/* $OpenBSD: mutex.S,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 */ #include .code32 /* stack offset of mutex pointer parameter */ #define SOFF 8 ENTRY(mtx_init) pushl %ebp movl %esp, %ebp movl SOFF(%ebp), %eax xorl %edx, %edx movl %edx, (%eax) leave ret ENTRY(mtx_enter) pushl %ebp movl %esp, %ebp 1: movl SOFF(%ebp), %ecx /* * %ecx contains the mtx. */ movl $1, %eax xchgl %eax, (%ecx) # test_and_set(mtx->mtx_lock) testl %eax, %eax # if (already held) jnz 2f leave ret 2: pause movl (%ecx), %eax testl %eax, %eax jz 1b jmp 2b ENTRY(mtx_leave) pushl %ebp movl %esp, %ebp movl SOFF(%ebp), %ecx xorl %eax, %eax movl %eax, (%ecx) leave ret tboot-1.8.0/tboot/common/paging.c0000644000000000000000000001604112272416301015025 0ustar 00000000000000/* * paging.c: enable PAE paging and map pages in tboot * * 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 /* Page-Directory-Pointer Table */ uint64_t __attribute__ ((__section__ (".bss.page_aligned"))) pdptr_table[TB_L2_PAGETABLE_ENTRIES]; /* Page Directory */ uint64_t __attribute__ ((__section__ (".bss.page_aligned"))) pd_table[4*TB_L1_PAGETABLE_ENTRIES]; extern char _start[]; extern char _end[]; extern void apply_policy(tb_error_t error); static uint64_t *get_pdptre(unsigned long virt) { return pdptr_table + pdptr_table_offset(virt); } /* get the Page-Directory Entry according to the virtual address */ static uint64_t *get_pde(unsigned long virt) { unsigned long pdptr_tab_offset; uint64_t *ppde, *ppdptre; uint64_t *p; ppdptre = get_pdptre(virt); if ( !(get_pdptre_flags(*ppdptre) & _PAGE_PRESENT) ) { /* If not present, create Page Directory */ pdptr_tab_offset = pdptr_table_offset(virt); p = pd_table + pdptr_tab_offset * TB_L1_PAGETABLE_ENTRIES; memset(p, 0, sizeof(uint64_t) * TB_L1_PAGETABLE_ENTRIES); *ppdptre = MAKE_TB_PDPTE((unsigned long)p); } ppde = (uint64_t *)(unsigned long)get_pdptre_paddr(*ppdptre); ppde += pd_table_offset(virt); return ppde; } static inline void flush_tlb(void) { write_cr3(read_cr3()); } /* * map 2-Mbyte pages to tboot: * tboot pages are mapped into DIRECTMAP_VIRT_START ~ DIRECTMAP_VIRT_END; * other pages for MACing are mapped into MAC_VIRT_START ~ MAC_VIRT_END. */ void map_pages_to_tboot(unsigned long vstart, unsigned long pfn, unsigned long nr_pfns) { uint64_t start, end; uint64_t *ppde; start = (uint64_t)pfn << TB_L1_PAGETABLE_SHIFT; end = (uint64_t)(pfn + nr_pfns) << TB_L1_PAGETABLE_SHIFT; do { ppde = get_pde(vstart); *ppde = MAKE_TB_PDE(start); start += MAC_PAGE_SIZE; vstart += MAC_PAGE_SIZE; } while ( start < end ); flush_tlb(); } /* map tboot pages into tboot */ static void map_tboot_pages(unsigned long pfn, unsigned long nr_pfns) { uint64_t start, end; start = (uint64_t)pfn << TB_L1_PAGETABLE_SHIFT; end = (uint64_t)(pfn + nr_pfns) << TB_L1_PAGETABLE_SHIFT; /* older gcc versions don't understand '#pragma GCC diagnostic ignored' and thus won't disable the 'unsinged comparison against 0' warning, so assert that DIRECTMAP_VIRT_START == 0 and then we don't need to compare 'start >= DIRECTMAP_VIRT_START' */ COMPILE_TIME_ASSERT(DIRECTMAP_VIRT_START == 0); if ( end > DIRECTMAP_VIRT_END ) { printk(TBOOT_ERR"0x%llx ~ 0x%llx cannot be mapped as direct map\n", start, end); disable_paging(); apply_policy(TB_ERR_FATAL); } map_pages_to_tboot(start, pfn, nr_pfns); } /* destroy the map */ void destroy_tboot_mapping(unsigned long vstart, unsigned long vend) { unsigned long virt; uint64_t *ppdptre, *ppde; if (((vstart & ~MAC_PAGE_MASK) == 0 ) || ((vend & ~MAC_PAGE_MASK) == 0 )) return; virt = vstart; while ( virt < vend ) { ppdptre = get_pdptre(virt); if ( !(get_pdptre_flags(*ppdptre) & _PAGE_PRESENT) ) { virt += 1UL << TB_L2_PAGETABLE_SHIFT; virt &= ~((1UL << TB_L2_PAGETABLE_SHIFT) - 1); continue; } ppde = get_pde(virt); if ( get_pde_flags(*ppde) & _PAGE_PRESENT ) *ppde = 0; virt += MAC_PAGE_SIZE; virt &= MAC_PAGE_MASK; } flush_tlb(); } static unsigned long build_directmap_pagetable(void) { unsigned int i; uint64_t *ppdptre; unsigned long tboot_spfn, tboot_epfn; memset(pdptr_table, 0, sizeof(pdptr_table)); memset(pd_table, 0, sizeof(pd_table)); for ( i = 0; i < sizeof(pd_table)/TB_L1_PAGETABLE_ENTRIES; i++ ) { ppdptre = &pdptr_table[i]; *ppdptre = MAKE_TB_PDPTE((unsigned long)( pd_table + i * TB_L1_PAGETABLE_ENTRIES)); } /* map serial log address ~ kernel command address */ tboot_spfn = (unsigned long)TBOOT_SERIAL_LOG_ADDR >> TB_L1_PAGETABLE_SHIFT; tboot_epfn = ((unsigned long)(TBOOT_KERNEL_CMDLINE_ADDR + TBOOT_KERNEL_CMDLINE_SIZE + MAC_PAGE_SIZE - 1)) >> TB_L1_PAGETABLE_SHIFT; map_tboot_pages(tboot_spfn, tboot_epfn - tboot_spfn); /* map tboot */ tboot_spfn = (unsigned long)&_start >> TB_L1_PAGETABLE_SHIFT; tboot_epfn = ((unsigned long)&_end + MAC_PAGE_SIZE - 1) >> TB_L1_PAGETABLE_SHIFT; map_tboot_pages(tboot_spfn, tboot_epfn - tboot_spfn); return (unsigned long)pdptr_table; } static unsigned long cr0, cr4; bool enable_paging(void) { unsigned long eflags; /* disable interrupts */ eflags = read_eflags(); disable_intr(); /* flush caches */ wbinvd(); /* save old cr0 & cr4 */ cr0 = read_cr0(); cr4 = read_cr4(); write_cr4((cr4 | CR4_PAE | CR4_PSE) & ~CR4_PGE); write_cr3(build_directmap_pagetable()); write_cr0(cr0 | CR0_PG); /* enable interrupts */ write_eflags(eflags); return (read_cr0() & CR0_PG); } bool disable_paging(void) { /* restore cr0 & cr4 */ write_cr0(cr0); write_cr4(cr4); return !(read_cr0() & CR0_PG); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/common/pci_cfgreg.c0000755000000000000000000001012012272416301015643 0ustar 00000000000000/* * 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 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: */ tboot-1.8.0/tboot/common/policy.c0000644000000000000000000007001512272416301015060 0ustar 00000000000000/* * policy.c: support functions for tboot verification launch * * 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 #define PRINT printk #include #include #include #include #include #include #include #include #include #include #include #include #include extern void shutdown(void); extern void s3_launch(void); /* MLE/kernel shared data page (in boot.S) */ extern tboot_shared_t _tboot_shared; extern long s3_flag; /* * 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, 0, 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, 0, 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; // 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)os_sinit_data->lcp_po_base; lcp_size = (uint32_t)os_sinit_data->lcp_po_size; } else { extern loader_ctx *g_ldr_ctx; if ( !find_lcp_module(g_ldr_ctx, &lcp_base, &lcp_size) ) return false; } /* if lcp policy data version is 2+ */ if ( memcmp((void *)lcp_base, 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 ) { 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; } pollist = (void *)pollist + get_policy_list_size(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->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; 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; } 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) { if ( !extend_hash(&hl->entries[i].hash, &img_hl.entries[j].hash, hl->entries[i].alg) ) return false; 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 launch_kernel(false); 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(module_t *module, tb_policy_entry_t *pol_entry, uint16_t hash_alg) { /* assumes module is valid */ void *base = (void *)module->mod_start; size_t size = module->mod_end - module->mod_start; char *cmdline = 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(loader_ctx *lctx) { /* assumes mbi is valid */ verify_g_policy(); /* module 0 is always extended to PCR 18, so add entry for it */ apply_policy(verify_module(get_module(lctx, 0), NULL, g_policy->hash_alg)); /* now verify each module and add its hash */ for ( unsigned int i = 0; i < get_module_count(lctx); i++ ) { module_t *module = get_module(lctx, i); tb_policy_entry_t *pol_entry = find_policy_entry(g_policy, i); if ( module == NULL ) { printk(TBOOT_ERR"missing module entry %u\n", i); apply_policy(TB_ERR_MODULE_VERIFICATION_FAILED); } else if ( pol_entry == NULL ) { printk(TBOOT_ERR"policy entry for module %u not found\n", i); apply_policy(TB_ERR_MODULES_NOT_IN_POLICY); } else apply_policy(verify_module(module, pol_entry, g_policy->hash_alg)); } 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) ) { printk(TBOOT_ERR"\t :nv index should be OWNERWRITE, 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: */ tboot-1.8.0/tboot/common/printk.c0000644000000000000000000001177612272416301015101 0ustar 00000000000000/* * 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 uint8_t g_log_level = TBOOT_LOG_LEVEL_ALL; uint8_t g_log_targets = TBOOT_LOG_TARGET_SERIAL | TBOOT_LOG_TARGET_VGA; 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 = NULL; static void memlog_init(void) { if ( g_log == NULL ) { g_log = (tboot_log_t *)TBOOT_SERIAL_LOG_ADDR; g_log->uuid = (uuid_t)TBOOT_LOG_UUID; g_log->curr_pos = 0; } /* initialize these post-launch as well, since bad/malicious values */ /* could compromise environment */ g_log = (tboot_log_t *)TBOOT_SERIAL_LOG_ADDR; g_log->max_size = TBOOT_SERIAL_LOG_SIZE - sizeof(*g_log); /* 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 ( g_log == NULL || 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(void) { mtx_init(&print_lock); /* parse loglvl from string to int */ get_tboot_loglvl(); /* parse logging targets */ get_tboot_log_targets(); /* parse serial settings */ if ( !get_tboot_serial() ) g_log_targets &= ~TBOOT_LOG_TARGET_SERIAL; if ( g_log_targets & TBOOT_LOG_TARGET_MEMORY ) memlog_init(); if ( g_log_targets & TBOOT_LOG_TARGET_SERIAL ) serial_init(); if ( g_log_targets & TBOOT_LOG_TARGET_VGA ) { vga_init(); get_tboot_vga_delay(); /* parse vga delay time */ } } #define WRITE_LOGS(s, n) \ do { \ 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[256]; 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: */ tboot-1.8.0/tboot/common/rijndael.c0000644000000000000000000016340412272416301015356 0ustar 00000000000000/* $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 #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); } tboot-1.8.0/tboot/common/sha1.c0000644000000000000000000002236612272416301014423 0ustar 00000000000000/*$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 #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; } tboot-1.8.0/tboot/common/sha256.c0000644000000000000000000002145712272416301014577 0ustar 00000000000000#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); } tboot-1.8.0/tboot/common/shutdown.S0000644000000000000000000000741312272416301015416 0ustar 00000000000000/* * shutdown.S: assembly extry points for shutdown * * 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. * */ compat_mode_entry: /* Disable paging and therefore leave 64 bit mode. */ movl %cr0, %eax andl $~CR0_PG, %eax movl %eax, %cr0 /* Clear MSR_EFER[LME], disabling long mode */ movl $MSR_EFER,%ecx rdmsr btcl $_EFER_LME,%eax wrmsr jmp 1f 1: /* fall through to shutdown_entry32 */ shutdown_entry32: /* restore tboot context */ lgdt %cs:gdt_descr mov $(ds_sel),%ecx mov %ecx,%ds mov %ecx,%es mov %ecx,%fs mov %ecx,%gs mov %ecx,%ss ljmp $(cs_sel),$(1f) 1: leal bsp_stack,%esp # default to BSP stack # BSP has separate stack (above) movl $MSR_APICBASE,%ecx rdmsr andl $APICBASE_BSP,%eax jnz 3f # get initial APIC ID for this processor mov $0x01, %eax xor %ebx, %ebx cpuid shr $24, %ebx # set stack as id-based offset from AP stack base # "truncate" if too big so that we at least have a stack # (even if shared with another AP) cmp $NR_CPUS, %ebx jl 2f mov $NR_CPUS-1, %ebx 2: mov $AP_STACK_SIZE, %eax mul %ebx mov $ap_stacks, %ecx sub %eax, %ecx mov %ecx, %esp 3: /* Reset EFLAGS (subsumes CLI and CLD). */ pushl $0x0 popf /* Load IDT */ lidt idt_descr /* disable paging */ mov %cr0, %eax and $~CR0_PG, %eax mov %eax, %cr0 jmp 1f 1: /* clear cr4 except for SMXE */ mov $0x4000, %eax mov %eax, %cr4 /* true shutdown work for tboot */ call shutdown ud2 /* * unified (32b/64b) shutdown entry point */ ENTRY(shutdown_entry) .code64 cli wbinvd movl $MSR_EFER,%ecx rdmsr bt $_EFER_LME,%eax jnc shutdown_entry32 lgdt gdt_descr(%rip) mov $(ds_sel),%ecx mov %ecx,%ds mov %ecx,%es mov %ecx,%fs mov %ecx,%gs mov %ecx,%ss 1: /* Jump to low identity mapping in compatibility mode. */ ljmp *compatibility_mode_far(%rip) ud2 compatibility_mode_far: .long compat_mode_entry .word cs_sel .code32 tboot-1.8.0/tboot/common/strcmp.c0000644000000000000000000000364312272416301015074 0ustar 00000000000000/*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * 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/strcmp.c */ #include /* * 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)); } tboot-1.8.0/tboot/common/strlen.c0000644000000000000000000000335512272416301015073 0ustar 00000000000000/*- * 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 */ #include size_t strlen(str) const char *str; { register const char *s; for (s = str; *s; ++s); return(s - str); } tboot-1.8.0/tboot/common/strncmp.c0000644000000000000000000000362012272416301015245 0ustar 00000000000000/*- * Copyright (c) 1989, 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/strncmp.c */ #include 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); } tboot-1.8.0/tboot/common/strncpy.c0000644000000000000000000000416412272416301015265 0ustar 00000000000000/*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * 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/strncpy.c */ #include /* * 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); } tboot-1.8.0/tboot/common/strtoul.c0000644000000000000000000000612212272416301015273 0ustar 00000000000000/*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * 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: @(#)strtoul.c 8.1 (Berkeley) 6/4/93 */ /* $FreeBSD: src/sys/libkern/strtoul.c,v 1.6.32.1 2010/02/10 00:26:20 kensmith Exp $ */ #include #include #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); } tboot-1.8.0/tboot/common/tb_error.c0000644000000000000000000001333112272416301015375 0ustar 00000000000000/* * 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 #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 ( no_err_idx ) return false; if ( !g_tpm->nv_write(g_tpm, 0, 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; } tboot-1.8.0/tboot/common/tboot.c0000644000000000000000000004710312272416301014712 0ustar 00000000000000/* * tboot.c: main entry point and "generic" routines for measured launch * 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. * */ #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 #include #include #include extern void _prot_to_real(uint32_t dist_addr); extern bool set_policy(void); extern void verify_all_modules(loader_ctx *lctx); extern void verify_all_nvindices(void); extern void apply_policy(tb_error_t error); void s3_launch(void); /* counter timeout for waiting for all APs to exit guests */ #define AP_GUEST_EXIT_TIMEOUT 0x01000000 extern long s3_flag; extern char s3_wakeup_16[]; extern char s3_wakeup_end[]; extern atomic_t ap_wfs_count; extern struct mutex ap_lock; /* loader context struct saved so that post_launch() can use it */ __data loader_ctx g_loader_ctx = { NULL, 0 }; __data loader_ctx *g_ldr_ctx = &g_loader_ctx; __data uint32_t g_mb_orig_size = 0; /* MLE/kernel shared data page (in boot.S) */ extern tboot_shared_t _tboot_shared; /* * caution: must make sure the total wakeup entry code length * (s3_wakeup_end - s3_wakeup_16) can fit into one page. */ static __data uint8_t g_saved_s3_wakeup_page[PAGE_SIZE]; unsigned long get_tboot_mem_end(void) { return PAGE_UP((unsigned long)&_end); } static tb_error_t verify_platform(void) { return txt_verify_platform(); } static bool is_launched(void) { return txt_is_launched(); } static bool prepare_cpu(void) { return txt_prepare_cpu(); } static void copy_s3_wakeup_entry(void) { if ( s3_wakeup_end - s3_wakeup_16 > PAGE_SIZE ) { printk(TBOOT_ERR"S3 entry is too large to be copied into one page!\n"); return; } /* backup target address space first */ memcpy(g_saved_s3_wakeup_page, (void *)TBOOT_S3_WAKEUP_ADDR, s3_wakeup_end - s3_wakeup_16); /* copy s3 entry into target mem */ memcpy((void *)TBOOT_S3_WAKEUP_ADDR, s3_wakeup_16, s3_wakeup_end - s3_wakeup_16); } static void restore_saved_s3_wakeup_page(void) { /* restore saved page */ memcpy((void *)TBOOT_S3_WAKEUP_ADDR, g_saved_s3_wakeup_page, s3_wakeup_end - s3_wakeup_16); } static void post_launch(void) { uint64_t base, size; tb_error_t err; extern tboot_log_t *g_log; extern void shutdown_entry(void); printk(TBOOT_INFO"measured launch succeeded\n"); /* init MLE/kernel shared data page early, .num_in_wfs used in ap wakeup*/ _tboot_shared.num_in_wfs = 0; txt_post_launch(); /* backup DMAR table */ save_vtd_dmar_table(); if ( s3_flag ) s3_launch(); /* remove all TXT modules before verifying modules */ remove_txt_modules(g_ldr_ctx); /* * verify e820 table and adjust it to protect our memory regions */ /* ensure all modules are in RAM */ if ( !verify_modules(g_ldr_ctx) ) apply_policy(TB_ERR_POST_LAUNCH_VERIFICATION); /* marked mem regions used by TXT (heap, SINIT, etc.) as E820_RESERVED */ err = txt_protect_mem_regions(); apply_policy(err); /* verify that tboot is in valid RAM (i.e. E820_RAM) */ base = (uint64_t)TBOOT_BASE_ADDR; size = (uint64_t)((unsigned long)&_end - base); printk(TBOOT_INFO"verifying tboot and its page table (%Lx - %Lx) in e820 table\n\t", base, (base + size - 1)); if ( e820_check_region(base, size) != E820_RAM ) { printk(TBOOT_ERR": failed.\n"); apply_policy(TB_ERR_FATAL); } else printk(TBOOT_INFO": succeeded.\n"); /* protect ourselves, MLE page table, and MLE/kernel shared page */ base = (uint64_t)TBOOT_BASE_ADDR; size = (uint64_t)get_tboot_mem_end() - base; uint32_t mem_type = is_kernel_linux() ? E820_RESERVED : E820_UNUSABLE; printk(TBOOT_INFO"protecting tboot (%Lx - %Lx) in e820 table\n", base, (base + size - 1)); if ( !e820_protect_region(base, size, mem_type) ) apply_policy(TB_ERR_FATAL); /* if using memory logging, reserve log area */ if ( g_log_targets & TBOOT_LOG_TARGET_MEMORY ) { base = TBOOT_SERIAL_LOG_ADDR; size = TBOOT_SERIAL_LOG_SIZE; printk(TBOOT_INFO"reserving tboot memory log (%Lx - %Lx) in e820 table\n", base, (base + size - 1)); if ( !e820_protect_region(base, size, E820_RESERVED) ) apply_policy(TB_ERR_FATAL); } /* replace map in loader context with copy */ replace_e820_map(g_ldr_ctx); printk(TBOOT_DETA"adjusted e820 map:\n"); print_e820_map(); /* * verify modules against policy */ verify_all_modules(g_ldr_ctx); /* * verify nv indices against policy */ if ( (g_tpm->major == TPM12_VER_MAJOR) && get_tboot_measure_nv() ) verify_all_nvindices(); /* * seal hashes of modules and VL policy to current value of PCR17 & 18 */ if ( !seal_pre_k_state() ) apply_policy(TB_ERR_S3_INTEGRITY); /* * init MLE/kernel shared data page */ memset(&_tboot_shared, 0, PAGE_SIZE); _tboot_shared.uuid = (uuid_t)TBOOT_SHARED_UUID; _tboot_shared.version = 6; _tboot_shared.log_addr = (uint32_t)g_log; _tboot_shared.shutdown_entry = (uint32_t)shutdown_entry; _tboot_shared.tboot_base = (uint32_t)&_start; _tboot_shared.tboot_size = (uint32_t)&_end - (uint32_t)&_start; uint32_t key_size = sizeof(_tboot_shared.s3_key); if ( !g_tpm->get_random(g_tpm, 2, _tboot_shared.s3_key, &key_size) || key_size != sizeof(_tboot_shared.s3_key) ) apply_policy(TB_ERR_S3_INTEGRITY); _tboot_shared.num_in_wfs = atomic_read(&ap_wfs_count); if ( use_mwait() ) { _tboot_shared.flags |= TB_FLAG_AP_WAKE_SUPPORT; _tboot_shared.ap_wake_trigger = AP_WAKE_TRIGGER_DEF; } else if ( get_tboot_mwait() ) { printk(TBOOT_ERR"ap_wake_mwait specified but the CPU doesn't support it.\n"); } print_tboot_shared(&_tboot_shared); launch_kernel(true); apply_policy(TB_ERR_FATAL); } void cpu_wakeup(uint32_t cpuid, uint32_t sipi_vec) { printk(TBOOT_INFO"cpu %u waking up, SIPI vector=%x\n", cpuid, sipi_vec); /* change to real mode and then jump to SIPI vector */ _prot_to_real(sipi_vec); } #define ICR_LOW 0x300 void startup_rlps(void) { uint32_t rlp_count = ((cpuid_ecx(1) >> 16) & 0xff) - 1; uint32_t apicbase = (uint32_t)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) { tb_error_t err; /* bsp check & tpm check done by caller */ /* SMX must be supported */ if ( !(cpuid_ecx(1) & CPUID_X86_FEATURE_SMX) ) apply_policy(TB_ERR_SMX_NOT_SUPPORTED); /* Enable SMX */ write_cr4(read_cr4() | CR4_SMXE); /* prepare cpu */ if ( !prepare_cpu() ) apply_policy(TB_ERR_FATAL); /* prepare tpm */ if ( !prepare_tpm() ) apply_policy(TB_ERR_TPM_NOT_READY); /* Place RLPs in Wait for SIPI state */ startup_rlps(); /* Verify loader context */ if ( !verify_loader_context(g_ldr_ctx) ) apply_policy(TB_ERR_FATAL); /* load racm */ err = txt_launch_racm(g_ldr_ctx); apply_policy(err); } static void shutdown_system(uint32_t); void check_racm_result(void) { txt_get_racm_error(); shutdown_system(TB_SHUTDOWN_HALT); } void begin_launch(void *addr, uint32_t magic) { tb_error_t err; if (g_ldr_ctx->type == 0) determine_loader_type(addr, magic); /* 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 ) { const char *cmdline_orig = get_cmdline(g_ldr_ctx); const char *cmdline = NULL; if (cmdline_orig){ cmdline = skip_filename(cmdline_orig); } memset(g_cmdline, '\0', sizeof(g_cmdline)); if (cmdline) strncpy(g_cmdline, cmdline, sizeof(g_cmdline)-1); } /* always parse cmdline */ tboot_parse_cmdline(); /* initialize all logging targets */ printk_init(); 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); /* if telled to check revocation acm result, go with simplified path */ if ( get_tboot_call_racm_check() ) check_racm_result(); /* never return */ if ( s3_flag ) printk(TBOOT_INFO"resume from S3\n"); /* RLM scaffolding if (g_ldr_ctx->type == 2) print_loader_ctx(g_ldr_ctx); */ /* clear resume vector on S3 resume so any resets will not use it */ 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()); /* make copy of e820 map that we will use and adjust */ if ( !s3_flag ) { if ( !copy_e820_map(g_ldr_ctx) ) apply_policy(TB_ERR_FATAL); } /* 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 */ /* make TPM ready for measured launch */ if ( !tpm_detect() ) apply_policy(TB_ERR_TPM_NOT_READY); /* read tboot 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); /* ensure there are modules */ if ( !s3_flag && !verify_loader_context(g_ldr_ctx) ) apply_policy(TB_ERR_FATAL); /* this is being called post-measured launch */ if ( is_launched() ) post_launch(); /* make the CPU ready for measured launch */ if ( !prepare_cpu() ) apply_policy(TB_ERR_FATAL); /* do s3 launch directly, if is a s3 resume */ if ( s3_flag ) { txt_s3_launch_environment(); printk(TBOOT_ERR"we should never get here\n"); apply_policy(TB_ERR_FATAL); } /* 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); /* launch the measured environment */ err = txt_launch_environment(g_ldr_ctx); apply_policy(err); } void s3_launch(void) { /* restore backed-up s3 wakeup page */ restore_saved_s3_wakeup_page(); /* remove DMAR table if necessary */ remove_vtd_dmar_table(); if ( !is_launched() ) apply_policy(TB_ERR_S3_INTEGRITY); else { /* this is being called post-measured launch */ /* verify saved hash integrity and re-extend PCRs */ if ( !verify_integrity() ) apply_policy(TB_ERR_S3_INTEGRITY); } print_tboot_shared(&_tboot_shared); /* (optionally) pause when transferring kernel resume */ if ( g_vga_delay > 0 ) delay(g_vga_delay * 1000); _prot_to_real(g_post_k_s3_state.kernel_s3_resume_vector); } 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 */ 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) { /* wait-for-sipi only invoked for APs, so skip all BSP shutdown code */ if ( _tboot_shared.shutdown_type == TB_SHUTDOWN_WFS ) { atomic_inc(&ap_wfs_count); _tboot_shared.ap_wake_trigger = 0; mtx_enter(&ap_lock); printk(TBOOT_INFO"shutdown(): TB_SHUTDOWN_WFS\n"); if ( use_mwait() ) ap_wait(get_apicid()); else handle_init_sipi_sipi(get_apicid()); apply_policy(TB_ERR_FATAL); } printk(TBOOT_INFO"wait until all APs ready for txt shutdown\n"); while( atomic_read(&_tboot_shared.num_in_wfs) < atomic_read(&ap_wfs_count) ) cpu_relax(); /* ensure localities 0, 1 are inactive (in case kernel used them) */ release_locality(0); release_locality(1); if ( _tboot_shared.shutdown_type == TB_SHUTDOWN_S3 ) { /* restore DMAR table if needed */ restore_vtd_dmar_table(); /* save kernel/VMM resume vector for sealing */ g_post_k_s3_state.kernel_s3_resume_vector = _tboot_shared.acpi_sinfo.kernel_s3_resume_vector; /* create and seal memory integrity measurement */ if ( !seal_post_k_state() ) apply_policy(TB_ERR_S3_INTEGRITY); /* OK to leave key in memory on failure since if user cared they would have policy that doesn't continue for TB_ERR_S3_INTEGRITY error */ else /* wipe S3 key from memory now that it is sealed */ memset(_tboot_shared.s3_key, 0, sizeof(_tboot_shared.s3_key)); } /* cap dynamic PCRs extended as part of launch (17, 18, ...) */ if ( is_launched() ) { /* cap PCRs to ensure no follow-on code can access sealed data */ g_tpm->cap_pcrs(g_tpm, 2, -1); /* have TPM save static PCRs (in case VMM/kernel didn't) */ /* per TCG spec, TPM can invalidate saved state if any other TPM operation is performed afterwards--so do this last */ if ( _tboot_shared.shutdown_type == TB_SHUTDOWN_S3 ) g_tpm->save_state(g_tpm, 2); /* scrub any secrets by clearing their memory, then flush cache */ /* we don't have any secrets to scrub, however */ ; /* in mwait "mode", APs will be in MONITOR/MWAIT and can be left there */ if ( !use_mwait() ) { /* force APs to exit mini-guests if any are in and wait until */ /* all are out before shutting down TXT */ printk(TBOOT_INFO"waiting for APs (%u) to exit guests...\n", atomic_read(&ap_wfs_count)); force_aps_exit(); uint32_t timeout = AP_GUEST_EXIT_TIMEOUT; do { if ( timeout % 0x8000 == 0 ) printk(TBOOT_INFO"."); else cpu_relax(); if ( timeout % 0x200000 == 0 ) printk(TBOOT_INFO"\n"); timeout--; } while ( ( atomic_read(&ap_wfs_count) > 0 ) && timeout > 0 ); printk(TBOOT_INFO"\n"); if ( timeout == 0 ) printk(TBOOT_INFO"AP guest exit loop timed-out\n"); else printk(TBOOT_INFO"all APs exited guests\n"); } else { /* reset ap_wfs_count to avoid tboot hash changing in S3 case */ atomic_set(&ap_wfs_count, 0); } /* turn off TXT (GETSEC[SEXIT]) */ txt_shutdown(); } /* machine shutdown */ shutdown_system(_tboot_shared.shutdown_type); } 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: */ tboot-1.8.0/tboot/common/tboot.lds.x0000644000000000000000000000173412272416301015520 0ustar 00000000000000/* ld script to make i386 Linux kernel * Written by Martin Mares * Modified for i386 Xen by Keir Fraser * Modified for tboot by Joseph Cihula */ #include #undef ENTRY #undef ALIGN OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) ENTRY(start) PHDRS { text PT_LOAD ; } SECTIONS { . = TBOOT_BASE_ADDR; /* 0x800000 */ .text : { *(.tboot_multiboot_header) . = ALIGN(4096); *(.mlept) _stext = .; /* text */ _mle_start = .; /* beginning of MLE pages */ *(.text) *(.fixup) *(.gnu.warning) } :text = 0x9090 _etext = .; /* end of text section */ .rodata : { *(.rodata) *(.rodata.*) } . = ALIGN(4096); _mle_end = .; /* end of MLE pages */ .data : { /* Data */ *(.data) *(.tboot_shared) CONSTRUCTORS } . = ALIGN(4096); __bss_start = .; /* BSS */ .bss : { *(.bss.stack_aligned) *(.bss.page_aligned) *(.bss) } _end = . ; } tboot-1.8.0/tboot/common/tpm.c0000644000000000000000000003610212272416301014360 0ustar 00000000000000/* * 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 struct tpm_if *g_tpm = NULL; u16 tboot_alg_list[] = {TB_HALG_SHA1, TB_HALG_SHA256}; /* * 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 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 */ #define TPM_REG_STS 0x18 typedef union { u8 _raw[4]; /* 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 */ /* version >= 2 */ u8 command_cancel : 1; u8 reset_establishment : 1; u8 tpm_family : 2; u8 reserved2 : 4; }; } tpm_reg_sts_t; /* TPM_DATA_FIFO_x */ #define TPM_REG_DATA_FIFO 0x24 typedef union { uint8_t _raw[1]; /* 1-byte reg */ } tpm_reg_data_fifo_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 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; } static bool tpm_wait_cmd_ready(uint32_t locality) { uint32_t i; tpm_reg_access_t reg_acc; tpm_reg_sts_t reg_sts; /* 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; } /* 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: 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 "); #endif i = 0; do { /* write 1 to TPM_STS_x.commandReady to let TPM enter ready state */ memset((void *)®_sts, 0, sizeof(reg_sts)); reg_sts.command_ready = 1; write_tpm_reg(locality, TPM_REG_STS, ®_sts); cpu_relax(); /* then see if it has */ read_tpm_reg(locality, TPM_REG_STS, ®_sts); #ifdef TPM_TRACE printk(TBOOT_INFO"."); #endif if ( reg_sts.command_ready == 1 ) 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 ) { printk(TBOOT_DETA"TPM: status reg content: %02x %02x %02x\n", (uint32_t)reg_sts._raw[0], (uint32_t)reg_sts._raw[1], (uint32_t)reg_sts._raw[2]); 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; } 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; tpm_reg_sts_t reg_sts; 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 = %d\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 { read_tpm_reg(locality, TPM_REG_STS, ®_sts); /* find out how many bytes the TPM can accept in a row */ row_size = reg_sts.burst_count; 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 { read_tpm_reg(locality,TPM_REG_STS, ®_sts); #ifdef TPM_TRACE printk(TBOOT_INFO"Wait on Expect = 0, Status register %02x\n", reg_sts._raw[0]); #endif if ( reg_sts.sts_valid == 1 && reg_sts.expect == 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 expect becoming 0 timeout\n"); ret = false; goto RelinquishControl; } /* command has been written to the TPM, it is time to execute it. */ memset(®_sts, 0, sizeof(reg_sts)); reg_sts.tpm_go = 1; write_tpm_reg(locality, TPM_REG_STS, ®_sts); /* check for data available */ i = 0; do { read_tpm_reg(locality,TPM_REG_STS, ®_sts); #ifdef TPM_TRACE printk(TBOOT_INFO"Waiting for DA Flag, Status register %02x\n", reg_sts._raw[0]); #endif if ( reg_sts.sts_valid == 1 && reg_sts.data_avail == 1 ) 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 { read_tpm_reg(locality, TPM_REG_STS, ®_sts); row_size = reg_sts.burst_count; 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 memset(®_sts, 0, sizeof(reg_sts)); reg_sts.command_ready = 1; write_tpm_reg(locality, TPM_REG_STS, ®_sts); 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 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 prepare_tpm(void) { /* * must ensure TPM_ACCESS_0.activeLocality bit is clear * (: locality is not active) */ return release_locality(0); } bool tpm_detect(void) { tpm_reg_sts_t reg_sts; if ( !tpm_validate_locality(0) ) { printk(TBOOT_ERR"TPM: Locality 0 is not open\n"); return false; } /* get TPM family from TPM status register */ memset((void *)®_sts, 0, sizeof(reg_sts)); write_tpm_reg(0, TPM_REG_STS, ®_sts); read_tpm_reg(0, TPM_REG_STS, ®_sts); printk(TBOOT_INFO"TPM: TPM Family 0x%d\n", reg_sts.tpm_family); if (reg_sts.tpm_family == 1) g_tpm = &tpm_20_if; else g_tpm = &tpm_12_if; g_tpm->cur_loc = 0; 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: */ tboot-1.8.0/tboot/common/tpm_12.c0000644000000000000000000017612112272416301014670 0ustar 00000000000000/* * 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 /* * 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 ( 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 || in == NULL || in->count != 1) { ti->error = TPM_BAD_PARAMETER; return false; } if ( 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 ( 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 ( 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 ( 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[] = {(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 ( 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 ( 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 */ 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 ( 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 ( 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 = ti->cur_loc; uint32_t ret; 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; 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 ) 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 ( 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 (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 */ 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; } 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, }; /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/common/tpm_20.c0000644000000000000000000021676012272416301014673 0ustar 00000000000000/* * 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 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 ( !tpm_submit_cmd(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 ( !tpm_submit_cmd(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 ( !tpm_submit_cmd(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 ( !tpm_submit_cmd(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 ( !tpm_submit_cmd(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 ( !tpm_submit_cmd(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 ( !tpm_submit_cmd(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 ( !tpm_submit_cmd(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 ( !tpm_submit_cmd(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 ( !tpm_submit_cmd(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 ( !tpm_submit_cmd(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 ( !tpm_submit_cmd(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 u32 handle2048; 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 ( !tpm_submit_cmd(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 ( !tpm_submit_cmd(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 ( !tpm_submit_cmd(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 ( !tpm_submit_cmd(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 ){ ti->error = TPM_RC_FAILURE; 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 ){ ti->error = TPM_RC_FAILURE; 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 ) { ti->error = TPM_RC_FAILURE; 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 ) { ti->error = TPM_RC_FAILURE; 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 == 0 || data_size > MAX_NV_INDEX_SIZE ) { ti->error = TPM_RC_FAILURE; 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 ) { ti->error = TPM_RC_FAILURE; 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 ) { ti->error = TPM_RC_FAILURE; 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.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 ) { ti->error = TPM_RC_FAILURE; 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 ) { ti->error = TPM_RC_FAILURE; 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 ) { ti->error = TPM_RC_FAILURE; 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 %u 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 %x random bytes but only got %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 %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 %u 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; 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; } static bool tpm20_cap_pcrs(struct tpm_if *ti, u32 locality, int pcr) { if ( ti == NULL || locality >= TPM_NR_LOCALITIES || pcr == 0 ) { ti->error = TPM_RC_FAILURE; return false; } 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, count=0; unsigned int i; /* 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 */ get_tboot_extpol(); /* init NV index */ ti->tb_policy_index = 0x1200001; ti->lcp_own_index = 0x1400001; ti->tb_err_index = 0x1200002; /* 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(0, &event_in, &event_out); if (ret != TPM_RC_SUCCESS) { printk(TBOOT_WARN"TPM: PcrEvent 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 cout = %08X\n", count); for (unsigned int i=0; ialg_count; i++) printk(TBOOT_INFO"\t\t %08X\n", ti->algs[i]); /* 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_PLATFORM; 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.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_ECB; 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; ret = _tpm20_create_primary(0, &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; 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: */ tboot-1.8.0/tboot/common/vga.c0000644000000000000000000000736412272416301014345 0ustar 00000000000000/* * 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 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 ( int y = 1; y < MAX_LINES; y++ ) { for ( int x = 0; x < MAX_COLS; x++ ) writew(VGA_ADDR(x, y-1), readw(VGA_ADDR(x, y))); } /* clear last line */ for ( int 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: */ tboot-1.8.0/tboot/common/vmac.c0000644000000000000000000012321612272416301014511 0ustar 00000000000000/* -------------------------------------------------------------------------- * 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 #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 tboot-1.8.0/tboot/common/vsprintf.c0000644000000000000000000003476512272416301015450 0ustar 00000000000000/* * 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 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; 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, &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: */ tboot-1.8.0/tboot/common/wakeup.S0000644000000000000000000000524612272416301015041 0ustar 00000000000000/* * wakeup.S: assembly S3 wakeup support * * 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. * */ /* * s3 resume entry called from BIOS */ .code16 .align PAGE_SIZE, 0 ENTRY(s3_wakeup_16) cli cld mov %cs, %ax mov %ax, %ds lgdtl real_gdt_desc - s3_wakeup_16 mov $1, %eax mov %eax, %cr0 ljmpl $(cs_sel), $(s3_wakeup_32) .align 8 /* * descriptors and descriptor tables */ real_gdt_desc: .word real_gdt_table_end - real_gdt_table - 1 .long TBOOT_S3_WAKEUP_ADDR + real_gdt_table - s3_wakeup_16 .align 8 real_gdt_table: /* unused */ .quad 0x0000000000000000 real_cs_desc: /* cs */ .word 0xffff /* limit = 4GB */ .word 0x00 /* base = 0 */ .word 0x9a00 /* read + exec */ .word 0x00cf /* granularity = 4096 */ real_ds_desc: /* ds */ .word 0xffff /* limit = 4GB */ .word 0x00 /* base = 0 */ .word 0x9200 /* read + write */ .word 0x00cf /* granularity = 4096 */ /* end (unused) */ .quad 0x0000000000000000 real_gdt_table_end: ENTRY(s3_wakeup_end) .code32 s3_wakeup_32: mov $(ds_sel), %ecx mov %ecx, %ds mov $1, %eax mov %eax, s3_flag jmp __start tboot-1.8.0/tboot/include/acpi.h0000644000000000000000000003511512272416301014637 0ustar 00000000000000/* $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 deviec_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 extern bool save_vtd_dmar_table(void); extern bool restore_vtd_dmar_table(void); extern bool remove_vtd_dmar_table(void); extern struct acpi_table_ioapic *get_acpi_ioapic_table(void); extern struct acpi_mcfg *get_acpi_mcfg_table(void); extern void disable_smis(void); extern bool machine_sleep(const tboot_acpi_sleep_info_t *); extern void set_s3_resume_vector(const tboot_acpi_sleep_info_t *, uint64_t); extern struct acpi_rsdp *get_rsdp(loader_ctx *lctx); #endif /* __ACPI_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/include/atomic.h0000644000000000000000000001306612272416301015200 0ustar 00000000000000/*- * 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__ */ tboot-1.8.0/tboot/include/cmdline.h0000644000000000000000000000535412272416301015340 0ustar 00000000000000/* * 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 extern char g_cmdline[CMDLINE_SIZE]; extern void tboot_parse_cmdline(void); extern void get_tboot_loglvl(void); extern void get_tboot_log_targets(void); extern bool get_tboot_serial(void); extern void get_tboot_baud(void); extern void get_tboot_fmt(void); extern void get_tboot_vga_delay(void); extern bool get_tboot_mwait(void); extern bool get_tboot_prefer_da(void); extern void get_tboot_min_ram(void); extern bool get_tboot_call_racm(void); extern bool get_tboot_call_racm_check(void); extern bool get_tboot_measure_nv(void); extern void get_tboot_extpol(void); /* for parse cmdline of linux kernel, say vga and mem */ extern void linux_parse_cmdline(const char *cmdline); extern bool get_linux_vga(int *vid_mode); extern bool get_linux_mem(uint64_t *initrd_max_mem); extern const char *skip_filename(const char *cmdline); extern 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: */ tboot-1.8.0/tboot/include/com.h0000644000000000000000000002343112272416301014477 0ustar 00000000000000/*- * 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; extern void comc_init(void); extern 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: */ tboot-1.8.0/tboot/include/compiler.h0000644000000000000000000000367112272416301015537 0ustar 00000000000000/* * 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: */ tboot-1.8.0/tboot/include/ctype.h0000644000000000000000000000614712272416301015052 0ustar 00000000000000/* * 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 */ extern const uint8_t _ctype[]; #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)); } #endif /* __CTYPE_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/include/e820.h0000644000000000000000000001110012272416301014365 0ustar 00000000000000/* * e820.h: support functions for manipulating the e820 table * * 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 __E820_H__ #define __E820_H__ #ifndef E820_RAM #define E820_RAM 1 #endif #ifndef E820_RESERVED #define E820_RESERVED 2 #endif #ifndef E820_ACPI #define E820_ACPI 3 #endif #ifndef E820_NVS #define E820_NVS 4 #endif #ifndef E820_UNUSABLE #define E820_UNUSABLE 5 #endif /* these are only used by e820_check_region() */ #define E820_MIXED ((uint32_t)-1 - 1) #define E820_GAP ((uint32_t)-1) #define E820MAX 128 typedef struct __packed { uint64_t addr; /* start of memory segment */ uint64_t size; /* size of memory segment */ uint32_t type; /* type of memory segment */ } e820entry_t; typedef struct { uint32_t type; uint32_t pad; uint64_t phys_addr; uint64_t virt_addr; uint64_t num_pages; uint64_t attribute; } efi_memory_desc_t; extern memory_map_t *get_e820_copy(void); extern unsigned int get_nr_map(void); extern bool copy_e820_map(loader_ctx *lctx); extern bool e820_protect_region(uint64_t addr, uint64_t size, uint32_t type); extern bool e820_reserve_ram(uint64_t base, uint64_t length); extern void print_e820_map(void); extern uint32_t e820_check_region(uint64_t base, uint64_t length); extern bool get_ram_ranges(uint64_t *min_lo_ram, uint64_t *max_lo_ram, uint64_t *min_hi_ram, uint64_t *max_hi_ram); extern void get_highest_sized_ram(uint64_t size, uint64_t limit, uint64_t *ram_base, uint64_t *ram_size); /* EFI memory map support */ extern efi_memory_desc_t *get_efi_memmap(uint32_t *memmap_size); /* * Memory map descriptor: */ /* Memory types: */ #define EFI_RESERVED_TYPE 0 #define EFI_LOADER_CODE 1 #define EFI_LOADER_DATA 2 #define EFI_BOOT_SERVICES_CODE 3 #define EFI_BOOT_SERVICES_DATA 4 #define EFI_RUNTIME_SERVICES_CODE 5 #define EFI_RUNTIME_SERVICES_DATA 6 #define EFI_CONVENTIONAL_MEMORY 7 #define EFI_UNUSABLE_MEMORY 8 #define EFI_ACPI_RECLAIM_MEMORY 9 #define EFI_ACPI_MEMORY_NVS 10 #define EFI_MEMORY_MAPPED_IO 11 #define EFI_MEMORY_MAPPED_IO_PORT_SPACE 12 #define EFI_PAL_CODE 13 #define EFI_MAX_MEMORY_TYPE 14 /* Attribute values: */ #define EFI_MEMORY_UC ((u64)0x0000000000000001ULL) /* uncached */ #define EFI_MEMORY_WC ((u64)0x0000000000000002ULL) /* write-coalescing */ #define EFI_MEMORY_WT ((u64)0x0000000000000004ULL) /* write-through */ #define EFI_MEMORY_WB ((u64)0x0000000000000008ULL) /* write-back */ #define EFI_MEMORY_WP ((u64)0x0000000000001000ULL) /* write-protect */ #define EFI_MEMORY_RP ((u64)0x0000000000002000ULL) /* read-protect */ #define EFI_MEMORY_XP ((u64)0x0000000000004000ULL) /* execute-protect */ #define EFI_MEMORY_RUNTIME ((u64)0x8000000000000000ULL) /* range requires runtime mapping */ #define EFI_MEMORY_DESCRIPTOR_VERSION 1 #define EFI_PAGE_SHIFT 12 #endif /* __E820_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/include/integrity.h0000644000000000000000000000644112272416301015741 0ustar 00000000000000/* * 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; extern pre_k_s3_state_t g_pre_k_s3_state; extern post_k_s3_state_t g_post_k_s3_state; extern bool seal_pre_k_state(void); extern bool seal_post_k_state(void); extern 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: */ tboot-1.8.0/tboot/include/io.h0000644000000000000000000000557412272416301014340 0ustar 00000000000000/*- * 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__ */ tboot-1.8.0/tboot/include/linux_defns.h0000644000000000000000000002527212272416301016244 0ustar 00000000000000/* * linux_defns.h: Linux kernel type definitions * * 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 __LINUX_DEFNS_H__ #define __LINUX_DEFNS_H__ #define SECTOR_SIZE (1 << 9) /* 0x200 = 512B */ #define KERNEL_HEADER_OFFSET 0x1F1 /* linux kernel header */ typedef struct __attribute__ ((packed)) { uint8_t setup_sects; /* The size of the setup in sectors */ #define DEFAULT_SECTOR_NUM 4 /* default sector number 4 */ #define MAX_SECTOR_NUM 64 /* max sector number 64 */ uint16_t root_flags; /* If set, the root is mounted readonly */ uint32_t syssize; /* The size of the 32-bit code in 16-byte paras */ uint16_t ram_size; /* DO NOT USE - for bootsect.S use only */ uint16_t vid_mode; /* Video mode control */ uint16_t root_dev; /* Default root device number */ uint16_t boot_flag; /* 0xAA55 magic number */ uint16_t jump; /* Jump instruction */ uint32_t header; /* Magic signature "HdrS" */ #define HDRS_MAGIC 0x53726448 uint16_t version; /* Boot protocol version supported */ uint32_t realmode_swtch; /* Boot loader hook */ uint16_t start_sys; /* The load-low segment (0x1000) (obsolete) */ uint16_t kernel_version; /* Points to kernel version string */ uint8_t type_of_loader; /* Boot loader identifier */ #define LOADER_TYPE_LILO 0x01 #define LOADER_TYPE_LOADLIN 0x10 #define LOADER_TYPE_BOOTSECT_LOADER 0x20 #define LOADER_TYPE_SYSLINUX 0x30 #define LOADER_TYPE_ETHERBOOT 0x40 #define LOADER_TYPE_ELILO 0x50 #define LOADER_TYPE_GRUB 0x71 #define LOADER_TYPE_U_BOOT 0x80 #define LOADER_TYPE_XEN 0x90 #define LOADER_TYPE_UNKNOWN 0xFF uint8_t loadflags; /* Boot protocol option flags */ #define FLAG_LOAD_HIGH 0x01 #define FLAG_CAN_USE_HEAP 0x80 uint16_t setup_move_size;/* Move to high memory size (used with hooks) */ uint32_t code32_start; /* Boot loader hook */ uint32_t ramdisk_image; /* initrd load address (set by boot loader) */ uint32_t ramdisk_size; /* initrd size (set by boot loader) */ uint32_t bootsect_kludge;/* DO NOT USE - for bootsect.S use only */ uint16_t heap_end_ptr; /* Free memory after setup end */ uint16_t pad1; /* Unused */ uint32_t cmd_line_ptr; /* 32-bit pointer to the kernel command line */ uint32_t initrd_addr_max;/* Highest legal initrd address */ uint32_t kernel_alignment; /* Physical addr alignment required for kernel */ uint8_t relocatable_kernel; /* Whether kernel is relocatable or not */ uint8_t pad2[3]; /* Unused */ uint32_t cmdline_size; /* Maximum size of the kernel command line */ uint32_t hardware_subarch; /* Hardware subarchitecture */ uint64_t hardware_subarch_data; /* Subarchitecture-specific data */ uint32_t payload_offset; uint32_t payload_length; uint64_t setup_data; } linux_kernel_header_t; typedef struct __attribute__ ((packed)) { uint8_t screen_info[0x040-0x000]; /* 0x000 */ uint8_t apm_bios_info[0x054-0x040]; /* 0x040 */ uint8_t _pad2[4]; /* 0x054 */ uint8_t tboot_shared_addr[8]; /* 0x058 */ uint8_t ist_info[0x070-0x060]; /* 0x060 */ uint8_t _pad3[16]; /* 0x070 */ uint8_t hd0_info[16]; /* obsolete! */ /* 0x080 */ uint8_t hd1_info[16]; /* obsolete! */ /* 0x090 */ uint8_t sys_desc_table[0x0b0-0x0a0]; /* 0x0a0 */ uint8_t _pad4[144]; /* 0x0b0 */ uint8_t edid_info[0x1c0-0x140]; /* 0x140 */ uint8_t efi_info[0x1e0-0x1c0]; /* 0x1c0 */ uint8_t alt_mem_k[0x1e4-0x1e0]; /* 0x1e0 */ uint8_t scratch[0x1e8-0x1e4]; /* 0x1e4 */ uint8_t e820_entries; /* 0x1e8 */ uint8_t eddbuf_entries; /* 0x1e9 */ uint8_t edd_mbr_sig_buf_entries; /* 0x1ea */ uint8_t _pad6[6]; /* 0x1eb */ linux_kernel_header_t hdr; /* setup header */ /* 0x1f1 */ uint8_t _pad7[0x290-0x1f1-sizeof(linux_kernel_header_t)]; uint8_t edd_mbr_sig_buffer[0x2d0-0x290]; /* 0x290 */ e820entry_t e820_map[E820MAX]; /* 0x2d0 */ uint8_t _pad8[48]; /* 0xcd0 */ uint8_t eddbuf[0xeec-0xd00]; /* 0xd00 */ uint8_t _pad9[276]; /* 0xeec */ } boot_params_t; typedef struct __attribute__ ((packed)) { u8 orig_x; /* 0x00 */ u8 orig_y; /* 0x01 */ u16 ext_mem_k; /* extended memory size in kb */ /* 0x02 */ u16 orig_video_page; /* 0x04 */ u8 orig_video_mode; /* representing the specific mode that was in effect when booting */ /* 0x06 */ u8 orig_video_cols; /* 0x07 */ u16 unused2; /* 0x08 */ u16 orig_video_ega_bx; /* video state and installed memory */ /* 0x0a */ u16 unused3; /* 0x0c */ u8 orig_video_lines; /* 0x0e */ u8 orig_video_isVGA; /* distinguish between VGA text and vesa lfb based screen setups */ /* 0x0f */ u16 orig_video_points; /* font height */ /* 0x10 */ u16 lfb_width; /* 0x12 */ u16 lfb_height; /* 0x14 */ u16 lfb_depth; /* 0x16 */ u32 lfb_base; /* 0x18 */ u32 lfb_size; /* 0x1c */ u16 cl_magic; /* 0x20 */ u16 cl_offset; /* 0x22 */ u16 lfb_line_len; /* 0x24 */ u8 red_mask_size; /* 0x26 */ u8 red_field_pos; /* 0x27 */ u8 green_mask_size; /* 0x28 */ u8 green_field_pos; /* 0x29 */ u8 blue_mask_size; /* 0x2a */ u8 blue_field_pos; /* 0x2b */ u8 reserved_mask_size; /* 0x2c */ u8 reserved_field_pos; /* 0x2d */ u16 vesapm_segment; /* 0x2e */ u16 vesapm_offset; /* 0x30 */ u16 lfb_pages; /* 0x32 */ u16 vesa_attrib; /* 0x34 */ u32 capabilities; /* 0x36 */ /* padding out to 0x40 */ } screen_info_t; /* recommended layout | Protected-mode kernel | The kernel protected-mode code. 100000 +---------------------------+ | I/O memory hole | 0A0000 +---------------------------+ | Reserved for BIOS | Do not use. Reserved for BIOS EBDA. 099100 +---------------------------+ | cmdline | 099000 +---------------------------+ | Stack/heap | For use by the kernel real-mode code. 098000 +---------------------------+ | Kernel setup | The kernel real-mode code. 090200 +---------------------------+ | Kernel boot sector | The kernel legacy boot sector. 090000 +---------------------------+ | Boot loader | <- Boot sector entry point 0000:7C00 001000 +---------------------------+ | Reserved for MBR/BIOS | 000800 +---------------------------+ | Typically used by MBR | 000600 +---------------------------+ | BIOS use only | 000000 +---------------------------+ */ #define BZIMAGE_PROTECTED_START 0x100000 #define LEGACY_REAL_START 0x90000 #define REAL_KERNEL_OFFSET 0x0000 #define BOOT_SECTOR_OFFSET 0x0200 #define KERNEL_CMDLINE_OFFSET 0x9000 #define REAL_END_OFFSET 0x9100 #define REAL_MODE_SIZE REAL_END_OFFSET - REAL_KERNEL_OFFSET struct efi_info { uint32_t efi_ldr_sig; uint32_t efi_systable; uint32_t efi_memdescr_size; uint32_t efi_memdescr_ver; uint32_t efi_memmap; uint32_t efi_memmap_size; uint32_t efi_systable_hi; uint32_t efi_memmap_hi; }; #endif /* __LINUX_DEFNS_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/include/loader.h0000644000000000000000000001033112272416301015162 0ustar 00000000000000/* * loader.h: support functions for manipulating ELF and AOUT binaries * * 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 __LOADER_H__ #define __LOADER_H__ typedef struct { void *addr; uint32_t type; } loader_ctx; extern loader_ctx *g_ldr_ctx; #ifndef __MULTIBOOT_H__ /* a few useful utility types */ typedef struct { uint32_t mod_start; uint32_t mod_end; uint32_t string; uint32_t reserved; } module_t; typedef struct { uint32_t size; uint32_t base_addr_low; uint32_t base_addr_high; uint32_t length_low; uint32_t length_high; uint32_t type; } memory_map_t; #endif extern void print_loader_ctx(loader_ctx *lctx); extern bool find_module_by_uuid(loader_ctx *lctx, void **base, size_t *size, const uuid_t *uuid); extern bool find_module_by_file_signature(loader_ctx *lctx, void **base, size_t *size, const char* file_signature); extern bool find_platform_racm(loader_ctx *lctx, void **base, uint32_t *size); extern bool find_platform_sinit_module(loader_ctx *lctx, void **base, uint32_t *size); extern bool find_lcp_module(loader_ctx *lctx, void **base, uint32_t *size); extern bool is_kernel_linux(void); extern bool launch_kernel(bool is_measured_launch); extern bool verify_loader_context(loader_ctx *lctx); extern bool verify_modules(loader_ctx *lctx); extern module_t *get_module(loader_ctx *lctx, unsigned int i); extern unsigned int get_module_count(loader_ctx *lctx); extern bool remove_txt_modules(loader_ctx *lctx); extern bool have_loader_memlimits(loader_ctx *lctx); extern bool have_loader_memmap(loader_ctx *lctx); extern memory_map_t *get_loader_memmap(loader_ctx *lctx); extern uint32_t get_loader_memmap_length(loader_ctx *lctx); extern uint32_t get_loader_mem_lower(loader_ctx *lctx); extern uint32_t get_loader_mem_upper(loader_ctx *lctx); extern char *get_module_cmd(loader_ctx *lctx, module_t *mod); extern char *get_cmdline(loader_ctx *lctx); extern void determine_loader_type(void *addr, uint32_t magic); extern unsigned long get_loader_ctx_end(loader_ctx *lctx); extern void replace_e820_map(loader_ctx *lctx); extern uint8_t *get_loader_rsdp(loader_ctx *lctx, uint32_t *length); extern bool is_loader_launch_efi(loader_ctx *lctx); extern bool get_loader_efi_ptr(loader_ctx *lctx, uint32_t *address, uint64_t *long_address); extern void load_framebuffer_info(loader_ctx *lctx, void *vscr); extern char *get_first_module_cmd(loader_ctx *lctx); #endif /* __LOADER_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/include/misc.h0000644000000000000000000000607112272416301014655 0ustar 00000000000000/* * 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__ extern void print_hex(const char * buf, const void * prtptr, size_t size); extern 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: */ tboot-1.8.0/tboot/include/msr.h0000644000000000000000000000751012272416301014522 0ustar 00000000000000/*- * 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__ #ifndef __ASSEMBLY__ /* from: * $FreeBSD: src/sys/i386/include/cpufunc.h,v 1.155.2.3 2009/11/25 01:52:36 kmacy Exp $ */ static inline uint64_t rdmsr(uint32_t msr) { uint64_t rv; __asm__ __volatile__ ("rdmsr" : "=A" (rv) : "c" (msr)); return (rv); } static inline void wrmsr(uint32_t msr, uint64_t newval) { __asm__ __volatile__ ("wrmsr" : : "A" (newval), "c" (msr)); } #endif /* !__ASSEMBLY__ */ /* * 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 /* * 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 MTRR_TYPE_UNCACHABLE 0 #define MTRR_TYPE_WRTHROUGH 4 #define MTRR_TYPE_WRBACK 6 #endif /* __MSR_H__ */ tboot-1.8.0/tboot/include/multiboot.h0000644000000000000000000002260612272416301015742 0ustar 00000000000000/* * multiboot.h: definitions for the multiboot bootloader specification * * Copyright (c) 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 __MULTIBOOT_H__ #define __MULTIBOOT_H__ #include /* Multiboot Header Definitions of OS image*/ #define MULTIBOOT_HEADER_MAGIC 0x1BADB002 #define MULTIBOOT_HEADER_SEARCH_LIMIT 8192 /* Bit definitions of flags field of multiboot header*/ #define MULTIBOOT_HEADER_MODS_ALIGNED 0x1 #define MULTIBOOT_HEADER_WANT_MEMORY 0x2 /* bit definitions of flags field of multiboot information */ #define MBI_MEMLIMITS (1<<0) #define MBI_BOOTDEV (1<<1) #define MBI_CMDLINE (1<<2) #define MBI_MODULES (1<<3) #define MBI_AOUT (1<<4) #define MBI_ELF (1<<5) #define MBI_MEMMAP (1<<6) #define MBI_DRIVES (1<<7) #define MBI_CONFIG (1<<8) #define MBI_BTLDNAME (1<<9) #define MBI_APM (1<<10) #define MBI_VBE (1<<11) /* multiboot 2 constants */ #define MB2_HEADER_MAGIC 0xe85250d6 #define MB2_LOADER_MAGIC 0x36d76289 #define MB2_HEADER_SEARCH_LIMIT 32768 #define MB2_ARCH_X86 0 #define MB2_HDR_TAG_END 0 #define MB2_HDR_TAG_INFO_REQ 1 #define MB2_HDR_TAG_ADDR 2 #define MB2_HDR_TAG_ENTRY_ADDR 3 #define MB2_HDR_TAG_CONSOLE_FLAGS 4 #define MB2_HDR_TAG_FRAMEBUFFER 5 #define MB2_HDR_TAG_MOD_ALIGN 6 #define MB2_HDR_TAG_OPTIONAL 1 #define MB2_CONS_FLAGS_CONS_REQ 1 #define MB2_CONS_FLAGS_EGA_TEXT_SUP 2 #define MB2_TAG_TYPE_END 0 #define MB2_TAG_TYPE_CMDLINE 1 #define MB2_TAG_TYPE_LOADER_NAME 2 #define MB2_TAG_TYPE_MODULE 3 #define MB2_TAG_TYPE_MEMLIMITS 4 #define MB2_TAG_TYPE_BOOTDEV 5 #define MB2_TAG_TYPE_MMAP 6 #define MB2_TAG_TYPE_VBE 7 #define MB2_TAG_TYPE_FRAMEBUFFER 8 #define MB2_TAG_TYPE_ELF_SECTIONS 9 #define MB2_TAG_TYPE_APM 10 #define MB2_TAG_TYPE_EFI32 11 #define MB2_TAG_TYPE_EFI64 12 #define MB2_TAG_TYPE_SMBIOS 13 #define MB2_TAG_TYPE_ACPI_OLD 14 #define MB2_TAG_TYPE_ACPI_NEW 15 #define MB2_TAG_TYPE_NETWORK 16 #ifndef __ASSEMBLY__ /* mb2 header flags */ struct mb2_hdr_tag_info_req { uint16_t type; uint16_t flags; uint32_t size; uint32_t requests[0]; }; struct mb2_hdr_tag_addr { uint16_t type; uint16_t flags; uint32_t size; uint32_t header_addr; uint32_t load_addr; uint32_t load_end_addr; uint32_t bss_end_addr; }; struct mb2_hdr_tag_entry_addr { uint16_t type; uint16_t flags; uint32_t size; uint32_t entry_addr; }; struct mb2_hdr_tag_console_flags { uint16_t type; uint16_t flags; uint32_t size; uint32_t console_flags; }; struct mb2_hdr_tag_framebuffer { uint16_t type; uint16_t flags; uint32_t size; uint32_t width; uint32_t height; uint32_t depth; }; struct mb2_hdr_tag_mod_align { uint16_t type; uint16_t flags; uint32_t size; uint32_t width; uint32_t height; uint32_t depth; }; /* MB2 info tags */ struct mb2_tag { uint32_t type; uint32_t size; }; struct mb2_tag_string { uint32_t type; uint32_t size; char string[0]; }; struct mb2_tag_memlimits { uint32_t type; uint32_t size; uint32_t mem_lower; uint32_t mem_upper; }; struct mb2_tag_bootdev { uint32_t type; uint32_t size; uint32_t biosdev; uint32_t slice; uint32_t part; }; struct mb2_mmap_entry { uint64_t addr; uint64_t len; #define MULTIBOOT_MEMORY_AVAILABLE 1 #define MULTIBOOT_MEMORY_RESERVED 2 #define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 #define MULTIBOOT_MEMORY_NVS 4 #define MULTIBOOT_MEMORY_BADRAM 5 uint32_t type; uint32_t zero; } __attribute__((packed)); struct mb2_tag_mmap { uint32_t type; uint32_t size; uint32_t entry_size; uint32_t entry_version; struct mb2_mmap_entry entries[0]; }; struct mb2_tag_module { uint32_t type; uint32_t size; uint32_t mod_start; uint32_t mod_end; char cmdline[0]; }; struct mb2_tag_old_acpi { uint32_t type; uint32_t size; uint8_t rsdp[0]; }; struct mb2_tag_new_acpi { uint32_t type; uint32_t size; uint8_t rsdp[0]; }; struct mb2_tag_efi32 { uint32_t type; uint32_t size; uint32_t pointer; }; struct mb2_tag_efi64 { uint32_t type; uint32_t size; uint64_t pointer; }; struct mb2_tag_network { uint32_t type; uint32_t size; uint8_t dhcpack[0]; }; struct mb2_tag_smbios { uint32_t type; uint32_t size; uint8_t major; uint8_t minor; uint8_t reserved[6]; uint8_t tables[0]; }; struct mb2_tag_elf_sections { uint32_t type; uint32_t size; uint32_t num; uint32_t entsize; uint32_t shndx; char sections[0]; }; struct mb2_tag_apm { uint32_t type; uint32_t size; uint16_t version; uint16_t cseg; uint32_t offset; uint16_t cseg_16; uint16_t dseg; uint16_t flags; uint16_t cseg_len; uint16_t cseg_16_len; uint16_t dseg_len; }; struct mb2_vbe_info_block { uint8_t external_specification[512]; }; struct mb2_vbe_mode_info_block { uint8_t external_specification[256]; }; struct mb2_tag_vbe { uint32_t type; uint32_t size; uint16_t vbe_mode; uint16_t vbe_interface_seg; uint16_t vbe_interface_off; uint16_t vbe_interface_len; struct mb2_vbe_info_block vbe_control_info; struct mb2_vbe_mode_info_block vbe_mode_info; }; struct mb2_fb_common { uint32_t type; uint32_t size; uint64_t fb_addr; uint32_t fb_pitch; uint32_t fb_width; uint32_t fb_height; uint8_t fb_bpp; #define MB2_FB_TYPE_INDEXED 0 #define MB2_FB_TYPE_RGB 1 #define MB2_FB_TYPE_EGA_TEXT 2 uint8_t fb_type; uint16_t reserved; }; struct mb2_color { uint8_t red; uint8_t green; uint8_t blue; }; struct mb2_fb { struct mb2_fb_common common; union { struct { uint16_t fb_palette_num_colors; struct mb2_color fb_palette[0]; }; struct { uint8_t fb_red_field_position; uint8_t fb_red_mask_size; uint8_t fb_green_field_position; uint8_t fb_green_mask_size; uint8_t fb_blue_field_position; uint8_t fb_blue_mask_size; }; }; }; /* MB1 */ typedef struct { uint32_t tabsize; uint32_t strsize; uint32_t addr; uint32_t reserved; } aout_t; /* a.out kernel image */ typedef struct { uint32_t num; uint32_t size; uint32_t addr; uint32_t shndx; } elf_t; /* elf kernel */ typedef struct { uint8_t bios_driver; uint8_t top_level_partition; uint8_t sub_partition; uint8_t third_partition; } boot_device_t; typedef struct { uint32_t flags; /* valid if flags[0] (MBI_MEMLIMITS) set */ uint32_t mem_lower; uint32_t mem_upper; /* valid if flags[1] set */ boot_device_t boot_device; /* valid if flags[2] (MBI_CMDLINE) set */ uint32_t cmdline; /* valid if flags[3] (MBI_MODS) set */ uint32_t mods_count; uint32_t mods_addr; /* valid if flags[4] or flags[5] set */ union { aout_t aout_image; elf_t elf_image; } syms; /* valid if flags[6] (MBI_MEMMAP) set */ uint32_t mmap_length; uint32_t mmap_addr; /* valid if flags[7] set */ uint32_t drives_length; uint32_t drives_addr; /* valid if flags[8] set */ uint32_t config_table; /* valid if flags[9] set */ uint32_t boot_loader_name; /* valid if flags[10] set */ uint32_t apm_table; /* valid if flags[11] set */ uint32_t vbe_control_info; uint32_t vbe_mode_info; uint16_t vbe_mode; uint16_t vbe_interface_seg; uint16_t vbe_interface_off; uint16_t vbe_interface_len; } multiboot_info_t; typedef struct { uint32_t mod_start; uint32_t mod_end; uint32_t string; uint32_t reserved; } module_t; typedef struct { uint32_t size; uint32_t base_addr_low; uint32_t base_addr_high; uint32_t length_low; uint32_t length_high; uint32_t type; } memory_map_t; #endif /* __ASSEMBLY__ */ #endif /* __MULTIBOOT_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/include/mutex.h0000644000000000000000000000410412272416301015057 0ustar 00000000000000/* $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__ uint32_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__ */ tboot-1.8.0/tboot/include/page.h0000644000000000000000000000462412272416301014640 0ustar 00000000000000/* * 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 */ #define PAGE_UP(p) (((unsigned long)(p) + PAGE_SIZE- 1) & PAGE_MASK) #define PAGE_DOWN(p) ((unsigned long)(p) & PAGE_MASK) #endif /* __PAGE_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/include/paging.h0000644000000000000000000001030112272416301015156 0ustar 00000000000000/* * 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: */ tboot-1.8.0/tboot/include/pci_cfgreg.h0000755000000000000000000000527612272416301016023 0ustar 00000000000000/* * 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: */ tboot-1.8.0/tboot/include/printk.h0000644000000000000000000000470412272416301015232 0ustar 00000000000000/* * 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_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 extern uint8_t g_log_level; extern uint8_t g_log_targets; extern uint8_t g_vga_delay; extern 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) extern void printk_init(void); extern void printk(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); #endif tboot-1.8.0/tboot/include/processor.h0000644000000000000000000001722012272416301015737 0ustar 00000000000000/* 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_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 */ #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 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_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) static inline unsigned long read_cr0(void) { unsigned long data; __asm__ __volatile__ ("movl %%cr0,%0" : "=r" (data)); return (data); } static inline void write_cr0(unsigned long data) { __asm__ __volatile__("movl %0,%%cr0" : : "r" (data)); } static inline unsigned long read_cr4(void) { unsigned long data; __asm__ __volatile__ ("movl %%cr4,%0" : "=r" (data)); return (data); } static inline void write_cr4(unsigned long data) { __asm__ __volatile__ ("movl %0,%%cr4" : : "r" (data)); } static inline unsigned long read_cr3(void) { unsigned long data; __asm__ __volatile__ ("movl %%cr3,%0" : "=r" (data)); return (data); } static inline void write_cr3(unsigned long data) { __asm__ __volatile__("movl %0,%%cr3" : : "r" (data) : "memory"); } static inline uint32_t read_eflags(void) { uint32_t ef; __asm__ __volatile__ ("pushfl; popl %0" : "=r" (ef)); return (ef); } static inline void write_eflags(uint32_t ef) { __asm__ __volatile__ ("pushl %0; popfl" : : "r" (ef)); } 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 uint64_t rdtsc(void) { uint64_t rv; __asm__ __volatile__ ("rdtsc" : "=A" (rv)); return (rv); } static inline void wbinvd(void) { __asm__ __volatile__ ("wbinvd"); } static inline uint32_t bsrl(uint32_t mask) { uint32_t result; __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) { __asm__ __volatile__ ("lock;addl $0,0(%%esp)" : : : "memory"); } static inline void cpu_monitor(const void *addr, int extensions, int hints) { __asm __volatile__ ("monitor;" : :"a" (addr), "c" (extensions), "d"(hints)); } static inline void cpu_mwait(int extensions, int hints) { __asm __volatile__ ("mwait;" : :"a" (hints), "c" (extensions)); } #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: */ tboot-1.8.0/tboot/include/rijndael.h0000644000000000000000000000437312272416301015515 0ustar 00000000000000/* $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 */ tboot-1.8.0/tboot/include/sha1.h0000644000000000000000000000550712272416301014561 0ustar 00000000000000/*$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; }; extern void sha1_init(struct sha1_ctxt *); extern void sha1_pad(struct sha1_ctxt *); extern void sha1_loop(struct sha1_ctxt *, const uint8_t *, size_t); extern 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__ */ tboot-1.8.0/tboot/include/sha256.h0000644000000000000000000000233112272416301014725 0ustar 00000000000000#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__ */ tboot-1.8.0/tboot/include/string.h0000644000000000000000000000523512272416301015231 0ustar 00000000000000/*- * 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__ */ tboot-1.8.0/tboot/include/tpm.h0000644000000000000000000002356312272416301014527 0ustar 00000000000000/* * 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_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) /* * 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) /* * 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 */ extern u16 tboot_alg_list[]; typedef tb_hash_t tpm_digest_t; typedef tpm_digest_t tpm_pcr_value_t; /* only for tpm1.2 to (un)seal */ extern tpm_pcr_value_t post_launch_pcr17; extern 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; 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); }; extern struct tpm_if tpm_12_if; extern struct tpm_if tpm_20_if; extern struct tpm_if *g_tpm; extern bool tpm_validate_locality(uint32_t locality); extern bool release_locality(uint32_t locality); extern bool prepare_tpm(void); extern bool tpm_detect(void); extern void tpm_print(struct tpm_if *ti); extern bool tpm_submit_cmd(u32 locality, u8 *in, u32 in_size, u8 *out, u32 *out_size); //#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: */ tboot-1.8.0/tboot/include/tpm_20.h0000644000000000000000000014475512272416301015037 0ustar 00000000000000/* * 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 TRUE 1 #define FALSE 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: */ tboot-1.8.0/tboot/include/txt/acmod.h0000644000000000000000000001366112272416301015627 0ustar 00000000000000/* * 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; uint32_t reserved1; 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; extern acm_hdr_t *g_sinit; /* 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 reserved : 26; }; } 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; extern void print_txt_caps(const char *prefix, txt_caps_t caps); extern bool is_racm_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet); extern acm_hdr_t *copy_racm(const acm_hdr_t *racm); extern bool verify_racm(const acm_hdr_t *acm_hdr); extern bool is_sinit_acmod(const void *acmod_base, uint32_t acmod_size, bool quiet); extern bool does_acmod_match_platform(const acm_hdr_t* hdr); extern acm_hdr_t *copy_sinit(const acm_hdr_t *sinit); extern bool verify_acmod(const acm_hdr_t *acm_hdr); extern uint32_t get_supported_os_sinit_data_ver(const acm_hdr_t* hdr); extern txt_caps_t get_sinit_capabilities(const acm_hdr_t* hdr); extern tpm_info_list_t *get_tpm_info_list(const acm_hdr_t* hdr); #endif /* __TXT_ACMOD_H__ */ /* * Local variables: * mode: C * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/include/txt/config_regs.h0000644000000000000000000001543412272416301017031 0ustar 00000000000000/* * 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; /* * fns to read/write TXT config regs */ #ifndef IS_INCLUDED static inline uint64_t read_config_reg(uint32_t config_regs_base, uint32_t reg) { /* these are MMIO so make sure compiler doesn't optimize */ return *(volatile uint64_t *)(unsigned long)(config_regs_base + reg); } #endif static inline void write_config_reg(uint32_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)(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: */ tboot-1.8.0/tboot/include/txt/errorcode.h0000644000000000000000000000744112272416301016527 0ustar 00000000000000/* * 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: */ tboot-1.8.0/tboot/include/txt/heap.h0000644000000000000000000002572712272416301015467 0ustar 00000000000000/* * 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 */ void *lctx_addr; /* needs to be restored to ebx */ uint32_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; /* 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)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)); } extern uint64_t calc_os_sinit_data_size(uint32_t version); extern bool verify_txt_heap(const txt_heap_t *txt_heap, bool bios_data_only); extern bool verify_bios_data(const txt_heap_t *txt_heap); extern 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: */ tboot-1.8.0/tboot/include/txt/mtrrs.h0000644000000000000000000001130012272416301015677 0ustar 00000000000000/* * 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; extern bool set_mtrrs_for_acmod(const acm_hdr_t *hdr); extern void save_mtrrs(mtrr_state_t *saved_state); extern void set_all_mtrrs(bool enable); extern bool set_mem_type(const void *base, uint32_t size, uint32_t mem_type); extern void restore_mtrrs(const mtrr_state_t *saved_state); extern 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: */ tboot-1.8.0/tboot/include/txt/smx.h0000644000000000000000000001203112272416301015341 0ustar 00000000000000/* * 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; extern 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: */ tboot-1.8.0/tboot/include/txt/txt.h0000644000000000000000000000500512272416301015354 0ustar 00000000000000/* * 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 extern bool txt_is_launched(void); extern bool txt_get_error(void); extern void txt_get_racm_error(void); extern tb_error_t supports_txt(void); extern tb_error_t txt_verify_platform(void); extern bool txt_prepare_cpu(void); extern tb_error_t txt_launch_environment(loader_ctx *lctx); extern tb_error_t txt_launch_racm(loader_ctx *lctx); extern void txt_post_launch(void); extern tb_error_t txt_protect_mem_regions(void); extern tb_error_t txt_post_launch_verify_platform(void); extern bool txt_s3_launch_environment(void); extern void txt_shutdown(void); extern bool txt_is_powercycle_required(void); extern void ap_wait(unsigned int cpuid); extern uint32_t g_using_da; #endif /* __TXT_TXT_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/include/txt/verify.h0000644000000000000000000000427712272416301016053 0ustar 00000000000000/* * 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__ extern 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); extern bool verify_e820_map(sinit_mdr_t* mdrs_base, uint32_t num_mdrs); extern bool verify_stm(unsigned int cpuid); extern 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: */ tboot-1.8.0/tboot/include/txt/vmcs.h0000644000000000000000000003144312272416301015512 0ustar 00000000000000/* * 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; } extern void handle_init_sipi_sipi(unsigned int cpuid); extern void force_aps_exit(void); #endif /* __TXT_VMCS_H__ */ /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/include/types.h0000644000000000000000000000552412272416301015070 0ustar 00000000000000/* * 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 #define NULL ((void*)0) typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; 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. */ typedef unsigned long size_t; /* * This is specifically for IA32. */ typedef unsigned int uintptr_t; typedef unsigned long long u64; typedef unsigned long long uint64_t; 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: */ tboot-1.8.0/tboot/include/vga.h0000755000000000000000000000610512272416301014500 0ustar 00000000000000/* * 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: */ tboot-1.8.0/tboot/include/vmac.h0000644000000000000000000001641512272416301014653 0ustar 00000000000000#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 */ #ifdef __cplusplus #define __STDC_CONSTANT_MACROS #endif //#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; /* --------------------------------------------------------------------- */ #ifdef __cplusplus extern "C" { #endif /* -------------------------------------------------------------------------- * <<<<< 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); /* --------------------------------------------------------------------- */ #ifdef __cplusplus } #endif #endif /* HEADER_AES_H */ tboot-1.8.0/tboot/txt/acmod.c0000644000000000000000000010023712272416301014173 0ustar 00000000000000/* * 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 txt-test/dump-acm.c */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif /* IS_INCLUDED */ 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_u32((uint32_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)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_u32((uint32_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)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_u32((unsigned 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)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_u32((unsigned long)hdr, tpm_info_off) ) { printk("hdr plus tpm_info_off overflows\n"); return NULL; } tpm_info = (tpm_info_list_t *) ((unsigned 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 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 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 > 4 ) { 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->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 *)(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)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)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 */ 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)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"); /* 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; } /* * Local variables: * mode: C * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/tboot/txt/errors.c0000644000000000000000000002251712272416301014430 0ustar 00000000000000/* * 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 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: */ tboot-1.8.0/tboot/txt/heap.c0000644000000000000000000006717712272416301014044 0ustar 00000000000000/* * 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 #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) 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) 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 ) { 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/sizeof(uint32_t); 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; *((uint64_t *)(&curr)) = log_descr->phys_addr + log_descr->pcr_events_offset; *((uint64_t *)(&next)) = log_descr->phys_addr + log_descr->next_event_offset; 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) { 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 ) 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 2 cores */ if ( bios_data->num_logical_procs < 2 ) { 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) + sizeof(size) ) { if ( !verify_ext_data_elts(bios_data->ext_data_elts, size - sizeof(*bios_data) - sizeof(size)) ) return false; } print_bios_data(bios_data); 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 */ printk(TBOOT_DETA"\t loader context addr: %p\n", os_mle_data->lctx_addr); } 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; } /* field checks */ if ( os_mle_data->lctx_addr == NULL ) { printk(TBOOT_ERR"OS to MLE data loader context addr field is NULL\n"); return false; } 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) - sizeof(size)) ) 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 */ sinit_mle_data = get_sinit_mle_data_start(txt_heap); 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: */ tboot-1.8.0/tboot/txt/mtrrs.c0000644000000000000000000004617012272416301014264 0ustar 00000000000000/* * 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 #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 eflags; unsigned 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 */ eflags = read_eflags(); 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(); write_cr4(cr4 & ~CR4_PGE); /* 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) */ write_cr4(cr4); /* enable interrupts */ write_eflags(eflags); 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); 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)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: */ tboot-1.8.0/tboot/txt/txt.c0000644000000000000000000012104312272416301013725 0ustar 00000000000000/* * 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 extern char _start[]; /* start of module */ extern char _end[]; /* end of module */ extern char _mle_start[]; /* start of text section */ extern char _mle_end[]; /* end of text section */ extern char _post_launch_entry[]; /* entry point post SENTER, in boot.S */ extern char _txt_wakeup[]; /* RLP join address for GETSEC[WAKEUP] */ extern long s3_flag; extern struct mutex ap_lock; /* MLE/kernel shared data page (in boot.S) */ extern tboot_shared_t _tboot_shared; extern void apply_policy(tb_error_t error); extern void cpu_wakeup(uint32_t cpuid, uint32_t sipi_vec); extern void print_event(const tpm12_pcr_event_t *evt); extern void print_event_2(void *evt, uint16_t alg); /* * this is the structure whose addr we'll put in TXT heap * it needs to be within the MLE pages, so force it to the .text section */ static __text const mle_hdr_t g_mle_hdr = { uuid : MLE_HDR_UUID, length : sizeof(mle_hdr_t), version : MLE_HDR_VER, entry_point : (uint32_t)&_post_launch_entry - TBOOT_START, first_valid_page : 0, mle_start_off : (uint32_t)&_mle_start - TBOOT_BASE_ADDR, mle_end_off : (uint32_t)&_mle_end - TBOOT_BASE_ADDR, capabilities : { MLE_HDR_CAPS }, cmdline_start_off : (uint32_t)g_cmdline - TBOOT_BASE_ADDR, cmdline_end_off : (uint32_t)g_cmdline + CMDLINE_SIZE - 1 - TBOOT_BASE_ADDR, }; /* * counts of APs going into wait-for-sipi */ /* count of APs in WAIT-FOR-SIPI */ atomic_t ap_wfs_count; static void print_file_info(void) { printk(TBOOT_DETA"file addresses:\n"); printk(TBOOT_DETA"\t &_start=%p\n", &_start); printk(TBOOT_DETA"\t &_end=%p\n", &_end); printk(TBOOT_DETA"\t &_mle_start=%p\n", &_mle_start); printk(TBOOT_DETA"\t &_mle_end=%p\n", &_mle_end); 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); print_txt_caps("\t ", mle_hdr->capabilities); } /* * build_mle_pagetable() */ /* page dir/table entry is phys addr + P + R/W + PWT */ #define MAKE_PDTE(addr) (((uint64_t)(unsigned 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 */ static __mlept uint8_t g_mle_pt[3 * PAGE_SIZE]; /* pgdir ptr + pgdir + ptab = 3 */ static void *build_mle_pagetable(uint32_t mle_start, uint32_t mle_size) { void *ptab_base; uint32_t ptab_size, mle_off; void *pg_dir_ptr_tab, *pg_dir, *pg_tab; uint64_t *pte; printk(TBOOT_DETA"MLE start=%x, end=%x, size=%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 NULL; } /* should start on page boundary */ if ( mle_start & ~PAGE_MASK ) { printk(TBOOT_ERR"MLE start is not page-aligned\n"); return NULL; } /* place ptab_base below MLE */ ptab_size = sizeof(g_mle_pt); ptab_base = &g_mle_pt; memset(ptab_base, 0, ptab_size); 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 ); return ptab_base; } static __data event_log_container_t *g_elog = NULL; static __data heap_event_log_ptr_elt2_t *g_elog_2 = NULL; /* 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)(unsigned long)(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; if (g_tpm->algs_banks[i] != TB_HALG_SHA1) { evt_log->event_log_descr[i].pcr_events_offset = 32 + sizeof(tpm20_log_descr_t); evt_log->event_log_descr[i].next_event_offset = 32 + sizeof(tpm20_log_descr_t); } } 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)(unsigned long)(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; if (g_tpm->algs[i] != TB_HALG_SHA1) { evt_log->event_log_descr[i].pcr_events_offset = 32 + sizeof(tpm20_log_descr_t); evt_log->event_log_descr[i].next_event_offset = 32 + sizeof(tpm20_log_descr_t); } } 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)(unsigned long)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; if (g_tpm->cur_alg != TB_HALG_SHA1) { evt_log->event_log_descr[0].pcr_events_offset = 32 + sizeof(tpm20_log_descr_t); evt_log->event_log_descr[0].next_event_offset = 32 + sizeof(tpm20_log_descr_t); } 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; evt_log = (heap_event_log_ptr_elt_t *)elt->data; evt_log->event_log_phys_addr = (uint64_t)(unsigned long)init_event_log(); elt->type = HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR; elt->size = sizeof(*elt) + sizeof(*evt_log); 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); } bool evtlog_append_tpm12(uint8_t pcr, tb_hash_t *hash, uint32_t type) { if ( g_elog == NULL ) return true; tpm12_pcr_event_t *next = (tpm12_pcr_event_t *) ((void*)g_elog + g_elog->next_event_offset); if ( g_elog->next_event_offset + sizeof(*next) > g_elog->size ) return false; next->pcr_index = pcr; next->type = type; memcpy(next->digest, hash, sizeof(*hash)); next->data_size = 0; g_elog->next_event_offset += sizeof(*next) + next->data_size; print_event(next); return true; } void dump_event_2(void) { heap_event_log_descr_t *log_descr; for ( unsigned int i=0; icount; i++ ) { log_descr = &g_elog_2->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); uint32_t hash_size, data_size; hash_size = get_hash_size(log_descr->alg); if ( hash_size == 0 ) return; void *curr, *next; *((u64 *)(&curr)) = log_descr->phys_addr + log_descr->pcr_events_offset; *((u64 *)(&next)) = log_descr->phys_addr + log_descr->next_event_offset; 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; } } } bool evtlog_append_tpm20(uint8_t pcr, uint16_t alg, tb_hash_t *hash, uint32_t type) { heap_event_log_descr_t *cur_desc = NULL; uint32_t hash_size; void *cur, *next; for ( unsigned int i=0; icount; i++ ) { if ( g_elog_2->event_log_descr[i].alg == alg ) { cur_desc = &g_elog_2->event_log_descr[i]; break; } } if ( !cur_desc ) return false; hash_size = get_hash_size(alg); if ( hash_size == 0 ) return false; *((u64 *)(&cur)) = *((u64 *)(&next)) = cur_desc->phys_addr + cur_desc->next_event_offset; if ( cur_desc->next_event_offset + 32 > cur_desc->size ) return false; *((u32 *)next) = pcr; next += sizeof(u32); *((u32 *)next) = type; next += sizeof(u32); memcpy((uint8_t *)next, hash, hash_size); next += hash_size/sizeof(uint32_t); *((u32 *)next) = 0; cur_desc->next_event_offset += 3*sizeof(uint32_t) + hash_size; print_event_2(cur, alg); return true; } bool evtlog_append(uint8_t pcr, hash_list_t *hl, uint32_t type) { switch (g_tpm->major) { case TPM12_VER_MAJOR: evtlog_append_tpm12(pcr, &hl->entries[0].hash, type); break; case TPM20_VER_MAJOR: for (unsigned int i=0; icount; i++) evtlog_append_tpm20(pcr, hl->entries[i].alg, &hl->entries[i].hash, type); break; default: return false; } return true; } __data uint32_t g_using_da = 0; __data acm_hdr_t *g_sinit = 0; /* * sets up TXT heap */ static txt_heap_t *init_txt_heap(void *ptab_base, acm_hdr_t *sinit, loader_ctx *lctx) { txt_heap_t *txt_heap; uint64_t *size; 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 *)((uint32_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->lctx_addr = lctx->addr; 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 *)((uint32_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)(unsigned long)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)(unsigned long)&g_mle_hdr - (uint64_t)(unsigned long)&_mle_start; /* VT-d PMRs */ uint64_t min_lo_ram, max_lo_ram, min_hi_ram, max_hi_ram; if ( !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 */ void *lcp_base = NULL; uint32_t lcp_size = 0; if ( find_lcp_module(lctx, &lcp_base, &lcp_size) && lcp_size > 0 ) { /* copy to heap */ if ( lcp_size > sizeof(os_mle_data->lcp_po_data) ) { printk(TBOOT_ERR"LCP owner policy data file is too large (%u)\n", lcp_size); return NULL; } memcpy(os_mle_data->lcp_po_data, lcp_base, lcp_size); os_sinit_data->lcp_po_base = (unsigned long)&os_mle_data->lcp_po_data; os_sinit_data->lcp_po_size = lcp_size; } /* capabilities : choose monitor wake mechanism first */ txt_caps_t sinit_caps = get_sinit_capabilities(sinit); txt_caps_t caps_mask = { 0 }; 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; if (is_loader_launch_efi(lctx)){ /* we were launched EFI, set efi_rsdt_ptr */ struct acpi_rsdp *rsdp = get_rsdp(lctx); 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 */ os_sinit_data->efi_rsdt_ptr = (uint64_t)((uint32_t) 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; } static void txt_wakeup_cpus(void) { uint16_t cs; mle_join_t mle_join; unsigned int ap_wakeup_count; if ( !verify_stm(get_apicid()) ) apply_policy(TB_ERR_POST_LAUNCH_VERIFICATION); /* enable SMIs on BSP before waking APs (which will enable them on APs) because some SMM may take immediate SMI and hang if AP gets in first */ printk(TBOOT_DETA"enabling SMIs on BSP\n"); __getsec_smctrl(); atomic_set(&ap_wfs_count, 0); /* RLPs will use our GDT and CS */ extern char gdt_table[], gdt_table_end[]; __asm__ __volatile__ ("mov %%cs, %0\n" : "=r"(cs)); mle_join.entry_point = (uint32_t)(unsigned long)&_txt_wakeup; mle_join.seg_sel = cs; mle_join.gdt_base = (uint32_t)gdt_table; mle_join.gdt_limit = gdt_table_end - gdt_table - 1; printk(TBOOT_DETA"mle_join.entry_point = %x\n", mle_join.entry_point); printk(TBOOT_DETA"mle_join.seg_sel = %x\n", mle_join.seg_sel); printk(TBOOT_DETA"mle_join.gdt_base = %x\n", mle_join.gdt_base); printk(TBOOT_DETA"mle_join.gdt_limit = %x\n", mle_join.gdt_limit); write_priv_config_reg(TXTCR_MLE_JOIN, (uint64_t)(unsigned long)&mle_join); mtx_init(&ap_lock); txt_heap_t *txt_heap = get_txt_heap(); sinit_mle_data_t *sinit_mle_data = get_sinit_mle_data_start(txt_heap); os_sinit_data_t *os_sinit_data = get_os_sinit_data_start(txt_heap); /* choose wakeup mechanism based on capabilities used */ if ( os_sinit_data->capabilities.rlp_wake_monitor ) { printk(TBOOT_INFO"joining RLPs to MLE with MONITOR wakeup\n"); printk(TBOOT_DETA"rlp_wakeup_addr = 0x%x\n", sinit_mle_data->rlp_wakeup_addr); *((uint32_t *)(unsigned long)(sinit_mle_data->rlp_wakeup_addr)) = 0x01; } else { printk(TBOOT_INFO"joining RLPs to MLE with GETSEC[WAKEUP]\n"); __getsec_wakeup(); printk(TBOOT_INFO"GETSEC[WAKEUP] completed\n"); } /* assume BIOS isn't lying to us about # CPUs, else some CPUS may not */ /* have entered wait-for-sipi before we launch *or* we have to wait */ /* for timeout before launching */ /* (all TXT-capable CPUs have at least 2 cores) */ bios_data_t *bios_data = get_bios_data_start(txt_heap); ap_wakeup_count = bios_data->num_logical_procs - 1; if ( ap_wakeup_count >= NR_CPUS ) { printk(TBOOT_INFO"there are too many CPUs (%u)\n", ap_wakeup_count); ap_wakeup_count = NR_CPUS - 1; } printk(TBOOT_INFO"waiting for all APs (%d) to enter wait-for-sipi...\n", ap_wakeup_count); /* wait for all APs that woke up to have entered wait-for-sipi */ uint32_t timeout = AP_WFS_TIMEOUT; do { if ( timeout % 0x8000 == 0 ) printk(TBOOT_INFO"."); else cpu_relax(); if ( timeout % 0x200000 == 0 ) printk(TBOOT_INFO"\n"); timeout--; } while ( ( atomic_read(&ap_wfs_count) < ap_wakeup_count ) && timeout > 0 ); printk(TBOOT_INFO"\n"); if ( timeout == 0 ) printk(TBOOT_INFO"wait-for-sipi loop timed-out\n"); else printk(TBOOT_INFO"all APs in wait-for-sipi\n"); } 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(loader_ctx *lctx) { void *mle_ptab_base; os_mle_data_t *os_mle_data; txt_heap_t *txt_heap; /* * find correct SINIT AC module in modules list */ find_platform_sinit_module(lctx, (void **)&g_sinit, NULL); /* if it is newer than BIOS-provided version, then copy it to */ /* BIOS reserved region */ g_sinit = copy_sinit(g_sinit); if ( g_sinit == NULL ) return TB_ERR_SINIT_NOT_PRESENT; /* do some checks on it */ if ( !verify_acmod(g_sinit) ) return TB_ERR_ACMOD_VERIFY_FAILED; /* print some debug info */ print_file_info(); print_mle_hdr(&g_mle_hdr); /* create MLE page table */ mle_ptab_base = build_mle_pagetable( g_mle_hdr.mle_start_off + TBOOT_BASE_ADDR, g_mle_hdr.mle_end_off - g_mle_hdr.mle_start_off); if ( mle_ptab_base == NULL ) return TB_ERR_FATAL; /* initialize TXT heap */ txt_heap = init_txt_heap(mle_ptab_base, g_sinit, lctx); 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; printk(TBOOT_INFO"executing GETSEC[SENTER]...\n"); /* (optionally) pause before executing GETSEC[SENTER] */ if ( g_vga_delay > 0 ) delay(g_vga_delay * 1000); __getsec_senter((uint32_t)g_sinit, (g_sinit->size)*4); printk(TBOOT_INFO"ERROR--we should not get here!\n"); return TB_ERR_FATAL; } bool txt_s3_launch_environment(void) { /* initial launch's TXT heap data is still in place and assumed valid */ /* so don't re-create; this is OK because it was untrusted initially */ /* and would be untrusted now */ /* initialize event log in os_sinit_data, so that events will not */ /* repeat when s3 */ if ( g_elog ) g_elog = (event_log_container_t *)init_event_log(); /* get sinit binary loaded */ g_sinit = (acm_hdr_t *)(uint32_t)read_pub_config_reg(TXTCR_SINIT_BASE); if ( g_sinit == NULL ) return false; /* set MTRRs properly for AC module (SINIT) */ set_mtrrs_for_acmod(g_sinit); printk(TBOOT_INFO"executing GETSEC[SENTER]...\n"); /* (optionally) pause before executing GETSEC[SENTER] */ if ( g_vga_delay > 0 ) delay(g_vga_delay * 1000); __getsec_senter((uint32_t)g_sinit, (g_sinit->size)*4); printk(TBOOT_ERR"ERROR--we should not get here!\n"); return false; } tb_error_t txt_launch_racm(loader_ctx *lctx) { acm_hdr_t *racm = NULL; /* * find correct revocation AC module in modules list */ find_platform_racm(lctx, (void **)&racm, NULL); /* copy it to a 32KB aligned memory address */ racm = copy_racm(racm); if ( racm == NULL ) return TB_ERR_SINIT_NOT_PRESENT; /* do some checks on it */ if ( !verify_racm(racm) ) return TB_ERR_ACMOD_VERIFY_FAILED; /* save MTRRs before we alter them for RACM launch */ /* - not needed by far since always reboot after RACM launch */ //save_mtrrs(...); /* set MTRRs properly for AC module (RACM) */ if ( !set_mtrrs_for_acmod(racm) ) return TB_ERR_FATAL; /* clear MSEG_BASE/SIZE registers */ write_pub_config_reg(TXTCR_MSEG_BASE, 0); write_pub_config_reg(TXTCR_MSEG_SIZE, 0); printk(TBOOT_INFO"executing GETSEC[ENTERACCS]...\n"); /* (optionally) pause before executing GETSEC[ENTERACCS] */ if ( g_vga_delay > 0 ) delay(g_vga_delay * 1000); __getsec_enteraccs((uint32_t)racm, (racm->size)*4, 0xF0); /* powercycle by writing 0x0a+0x0e to port 0xcf9, */ /* warm reset by write 0x06 to port 0xcf9 */ //outb(0xcf9, 0x0a); //outb(0xcf9, 0x0e); outb(0xcf9, 0x06); printk(TBOOT_ERR"ERROR--we should not get here!\n"); return TB_ERR_FATAL; } bool txt_prepare_cpu(void) { unsigned long eflags, cr0; uint64_t mcg_cap, mcg_stat; /* must be running at CPL 0 => this is implicit in even getting this far */ /* since our bootstrap code loads a GDT, etc. */ cr0 = read_cr0(); /* must be in protected mode */ if ( !(cr0 & CR0_PE) ) { printk(TBOOT_ERR"ERR: not in protected mode\n"); return false; } /* 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) */ eflags = read_eflags(); if ( eflags & X86_EFLAGS_VM ) { printk(TBOOT_INFO"EFLAGS.VM set\n"); write_eflags(eflags | ~X86_EFLAGS_VM); } printk(TBOOT_INFO"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; } void txt_post_launch(void) { txt_heap_t *txt_heap; os_mle_data_t *os_mle_data; tb_error_t err; /* verify MTRRs, VT-d settings, TXT heap, etc. */ err = txt_post_launch_verify_platform(); /* don't return the error yet, because we need to restore settings */ if ( err != TB_ERR_NONE ) printk(TBOOT_ERR"failed to verify platform\n"); /* get saved OS state (os_mvmm_data_t) from LT heap */ txt_heap = get_txt_heap(); os_mle_data = get_os_mle_data_start(txt_heap); /* clear error registers so that we start fresh */ write_priv_config_reg(TXTCR_ERRORCODE, 0x00000000); write_priv_config_reg(TXTCR_ESTS, 0xffffffff); /* write 1's to clear */ /* bring RLPs into environment (do this before restoring MTRRs to ensure */ /* SINIT area is mapped WB for MONITOR-based RLP wakeup) */ txt_wakeup_cpus(); /* restore pre-SENTER IA32_MISC_ENABLE_MSR (no verification needed) (do after AP wakeup so that if restored MSR has MWAIT clear it won't prevent wakeup) */ printk(TBOOT_DETA"saved IA32_MISC_ENABLE = 0x%08x\n", os_mle_data->saved_misc_enable_msr); wrmsr(MSR_IA32_MISC_ENABLE, os_mle_data->saved_misc_enable_msr); if ( use_mwait() ) { /* set MONITOR/MWAIT support */ uint64_t misc; misc = rdmsr(MSR_IA32_MISC_ENABLE); misc |= MSR_IA32_MISC_ENABLE_MONITOR_FSM; wrmsr(MSR_IA32_MISC_ENABLE, misc); } /* restore pre-SENTER MTRRs that were overwritten for SINIT launch */ restore_mtrrs(&(os_mle_data->saved_mtrr_state)); /* now, if there was an error, apply policy */ apply_policy(err); /* always set the TXT.CMD.SECRETS flag */ write_priv_config_reg(TXTCR_CMD_SECRETS, 0x01); read_priv_config_reg(TXTCR_E2STS); /* just a fence, so ignore return */ printk(TBOOT_INFO"set TXT.CMD.SECRETS flag\n"); /* open TPM locality 1 */ write_priv_config_reg(TXTCR_CMD_OPEN_LOCALITY1, 0x01); read_priv_config_reg(TXTCR_E2STS); /* just a fence, so ignore return */ printk(TBOOT_INFO"opened TPM locality 1\n"); } void ap_wait(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; } /* ensure MONITOR/MWAIT support is set */ uint64_t misc; misc = rdmsr(MSR_IA32_MISC_ENABLE); misc |= MSR_IA32_MISC_ENABLE_MONITOR_FSM; wrmsr(MSR_IA32_MISC_ENABLE, misc); /* this is close enough to entering monitor/mwait loop, so inc counter */ atomic_inc((atomic_t *)&_tboot_shared.num_in_wfs); mtx_leave(&ap_lock); printk(TBOOT_INFO"cpu %u mwait'ing\n", cpuid); while ( _tboot_shared.ap_wake_trigger != cpuid ) { cpu_monitor(&_tboot_shared.ap_wake_trigger, 0, 0); mb(); if ( _tboot_shared.ap_wake_trigger == cpuid ) break; cpu_mwait(0, 0); } uint32_t sipi_vec = (uint32_t)_tboot_shared.ap_wake_addr; atomic_dec(&ap_wfs_count); atomic_dec((atomic_t *)&_tboot_shared.num_in_wfs); cpu_wakeup(cpuid, sipi_vec); } void txt_cpu_wakeup(void) { txt_heap_t *txt_heap; os_mle_data_t *os_mle_data; unsigned int cpuid = get_apicid(); if ( cpuid >= NR_CPUS ) { printk(TBOOT_ERR"cpuid (%u) exceeds # supported CPUs\n", cpuid); apply_policy(TB_ERR_FATAL); return; } mtx_enter(&ap_lock); printk(TBOOT_INFO"cpu %u waking up from TXT sleep\n", cpuid); txt_heap = get_txt_heap(); os_mle_data = get_os_mle_data_start(txt_heap); /* apply (validated) (pre-SENTER) MTRRs from BSP to each AP */ restore_mtrrs(&(os_mle_data->saved_mtrr_state)); /* restore pre-SENTER IA32_MISC_ENABLE_MSR */ wrmsr(MSR_IA32_MISC_ENABLE, os_mle_data->saved_misc_enable_msr); if ( !verify_stm(cpuid) ) apply_policy(TB_ERR_POST_LAUNCH_VERIFICATION); /* enable SMIs */ printk(TBOOT_DETA"enabling SMIs on cpu %u\n", cpuid); __getsec_smctrl(); atomic_inc(&ap_wfs_count); if ( use_mwait() ) ap_wait(cpuid); else handle_init_sipi_sipi(cpuid); } tb_error_t txt_protect_mem_regions(void) { uint64_t base, size; /* * TXT has 2 regions of RAM that need to be reserved for use by only the * hypervisor; not even dom0 should have access: * TXT heap, SINIT AC module */ /* TXT heap */ base = read_pub_config_reg(TXTCR_HEAP_BASE); size = read_pub_config_reg(TXTCR_HEAP_SIZE); printk(TBOOT_INFO"protecting TXT heap (%Lx - %Lx) in e820 table\n", base, (base + size - 1)); if ( !e820_protect_region(base, size, E820_RESERVED) ) return TB_ERR_FATAL; /* SINIT */ base = read_pub_config_reg(TXTCR_SINIT_BASE); size = read_pub_config_reg(TXTCR_SINIT_SIZE); printk(TBOOT_INFO"protecting SINIT (%Lx - %Lx) in e820 table\n", base, (base + size - 1)); if ( !e820_protect_region(base, size, E820_RESERVED) ) return TB_ERR_FATAL; /* TXT private space */ base = TXT_PRIV_CONFIG_REGS_BASE; size = TXT_CONFIG_REGS_SIZE; printk(TBOOT_INFO "protecting TXT Private Space (%Lx - %Lx) in e820 table\n", base, (base + size - 1)); if ( !e820_protect_region(base, size, E820_RESERVED) ) return TB_ERR_FATAL; /* ensure that memory not marked as good RAM by the MDRs is RESERVED in the e820 table */ txt_heap_t* txt_heap = get_txt_heap(); sinit_mle_data_t *sinit_mle_data = get_sinit_mle_data_start(txt_heap); uint32_t num_mdrs = sinit_mle_data->num_mdrs; sinit_mdr_t *mdrs_base = (sinit_mdr_t *)(((void *)sinit_mle_data - sizeof(uint64_t)) + sinit_mle_data->mdrs_off); printk(TBOOT_INFO"verifying e820 table against SINIT MDRs: "); if ( !verify_e820_map(mdrs_base, num_mdrs) ) { printk(TBOOT_ERR"verification failed.\n"); return TB_ERR_POST_LAUNCH_VERIFICATION; } printk(TBOOT_INFO"verification succeeded.\n"); return TB_ERR_NONE; } void txt_shutdown(void) { unsigned long apicbase; /* shutdown shouldn't be called on APs, but if it is then just hlt */ apicbase = rdmsr(MSR_APICBASE); if ( !(apicbase & APICBASE_BSP) ) { printk(TBOOT_INFO"calling txt_shutdown on AP\n"); while ( true ) halt(); } /* set TXT.CMD.NO-SECRETS flag (i.e. clear SECRETS flag) */ write_priv_config_reg(TXTCR_CMD_NO_SECRETS, 0x01); read_priv_config_reg(TXTCR_E2STS); /* fence */ printk(TBOOT_INFO"secrets flag cleared\n"); /* unlock memory configuration */ write_priv_config_reg(TXTCR_CMD_UNLOCK_MEM_CONFIG, 0x01); read_pub_config_reg(TXTCR_E2STS); /* fence */ printk(TBOOT_INFO"memory configuration unlocked\n"); /* if some APs are still in wait-for-sipi then SEXIT will hang */ /* so TXT reset the platform instead, expect mwait case */ if ( (!use_mwait()) && atomic_read(&ap_wfs_count) > 0 ) { printk(TBOOT_INFO "exiting with some APs still in wait-for-sipi state (%u)\n", atomic_read(&ap_wfs_count)); write_priv_config_reg(TXTCR_CMD_RESET, 0x01); } /* close TXT private config space */ /* implicitly closes TPM localities 1 + 2 */ read_priv_config_reg(TXTCR_E2STS); /* fence */ write_priv_config_reg(TXTCR_CMD_CLOSE_PRIVATE, 0x01); read_pub_config_reg(TXTCR_E2STS); /* fence */ printk(TBOOT_INFO"private config space closed\n"); /* SMXE may not be enabled any more, so set it to make sure */ write_cr4(read_cr4() | CR4_SMXE); /* call GETSEC[SEXIT] */ printk(TBOOT_INFO"executing GETSEC[SEXIT]...\n"); __getsec_sexit(); printk(TBOOT_INFO"measured environment torn down\n"); } 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 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\n"); 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: */ tboot-1.8.0/tboot/txt/verify.c0000644000000000000000000004542512272416301014423 0ustar 00000000000000/* * 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 extern long s3_flag; /* * CPUID extended feature info */ static unsigned int g_cpuid_ext_feat_info; /* * IA32_FEATURE_CONTROL_MSR */ static unsigned long g_feat_ctrl_msr; static void read_processor_info(void) { unsigned long f1, f2; /* is CPUID supported? */ /* (it's supported if ID flag in EFLAGS can be set and cleared) */ asm("pushf\n\t" "pushf\n\t" "pop %0\n\t" "mov %0,%1\n\t" "xor %2,%0\n\t" "push %0\n\t" "popf\n\t" "pushf\n\t" "pop %0\n\t" "popf\n\t" : "=&r" (f1), "=&r" (f2) : "ir" (X86_EFLAGS_ID)); if ( ((f1^f2) & X86_EFLAGS_ID) == 0 ) { g_cpuid_ext_feat_info = 0; return; } g_cpuid_ext_feat_info = cpuid_ecx(1); g_feat_ctrl_msr = rdmsr(MSR_IA32_FEATURE_CONTROL); printk(TBOOT_DETA"IA32_FEATURE_CONTROL_MSR: %08lx\n", g_feat_ctrl_msr); } 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; read_processor_info(); /* 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 ( !e820_reserve_ram(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 ( !e820_reserve_ram(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 e820 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 ( !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_e820_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) && (!e820_reserve_ram(base, length)) ) return false; base = mdr_entry->base + mdr_entry->length; } /* deal with the last gap */ length = (uint64_t)-1 - base; return e820_reserve_ram(base, length); } static void print_mseg_hdr(mseg_hdr_t *mseg_hdr) { printk(TBOOT_DETA"MSEG header dump for 0x%x:\n", (uint32_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) MSR_IA32_SMM_MONITOR_CTL_MSEG_BASE(smm_mon_ctl); txt_mseg_base = (void *)(uint32_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: */ tboot-1.8.0/tboot/txt/vmcs.c0000644000000000000000000004401712272416301014063 0ustar 00000000000000/* * 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 /* 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) ) extern char gdt_table[]; #define RESET_TSS_DESC(n) gdt_table[((n)<<3)+5] = 0x89 /* lock that protects APs against race conditions on wakeup and shutdown */ struct mutex ap_lock; /* counter for APs entering/exiting wait-for-sipi */ extern 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) */ extern tboot_shared_t _tboot_shared; extern char _end[]; extern void print_cr0(const char *s); extern void cpu_wakeup(uint32_t cpuid, uint32_t sipi_vec); extern void apply_policy(tb_error_t error); 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); } extern uint32_t idle_pg_table[PAGE_SIZE / 4]; /* 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 */ uint32_t pt_entry = PTE_FLAGS; uint32_t *pte = &idle_pg_table[0]; while ( pt_entry <= (uint32_t)&_end + PTE_FLAGS ) { *pte = pt_entry; /* Incriments 4MB page at a time */ pt_entry += 1 << FOURMB_PAGE_SHIFT; pte++; } } extern char host_vmcs[PAGE_SIZE]; extern char ap_vmcs[NR_CPUS][PAGE_SIZE]; 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; /* 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((unsigned long)idle_pg_table); write_cr4(read_cr4() | CR4_PSE); write_cr0(read_cr0() | CR0_PG); if ( __vmxon((unsigned 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)vmcs); __vmpclear((unsigned 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); } /* in tboot/common/boot.S */ extern void vmx_asm_vmexit_handler(void); extern void _mini_guest(void); /* 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 cr0, cr3, cr4, eflags, 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, (uint32_t)&_mini_guest); __vmwrite(HOST_CS_SELECTOR, seg); __vmwrite(HOST_RIP, (unsigned long)vmx_asm_vmexit_handler); /* 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 */ eflags = read_eflags(); __vmwrite(GUEST_RFLAGS, eflags); __asm__ __volatile__ ("mov %%esp,%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) { 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)vmcs); __vmptrld((unsigned 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; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/test-patches/e820-test.patch0000644000000000000000000001653512272416301016065 0ustar 00000000000000diff -r 4ea7c584151a tboot/common/e820.c --- a/tboot/common/e820.c Tue Jan 13 11:29:14 2009 -0800 +++ b/tboot/common/e820.c Tue Jan 20 22:25:23 2009 -0800 @@ -623,6 +623,202 @@ bool get_ram_ranges(multiboot_info_t *mb return true; } +#define RUN_CASE(caseid) \ +{ \ + if ( caseid() ) \ + printk("VALIDATE_E820_UNIT_TEST: " #caseid " passed\n"); \ + else \ + printk("VALIDATE_E820_UNIT_TEST: " #caseid " failed\n"); \ +} + +#define E820_ENTRY(s, e, t) \ + { \ + sizeof(memory_map_t)-sizeof(uint32_t), \ + ((uint64_t)(s) & 0xffffffULL), \ + ((uint64_t)(s) >> 32), \ + (((uint64_t)(e) - (uint64_t)(s)) & 0xffffffffULL), \ + (((uint64_t)(e) - (uint64_t)(s)) >> 32), \ + (t) \ + } + +static memory_map_t test_map[32] = { + E820_ENTRY(0x00000, 0x04000, E820_RAM), + E820_ENTRY(0x08000, 0x0c000, E820_RAM), + E820_ENTRY(0x10000, 0x14000, E820_RAM), + E820_ENTRY(0x18000, 0x1c000, E820_RAM), + E820_ENTRY(0x20000, 0x24000, E820_RAM), + E820_ENTRY(0x28000, 0x2c000, E820_RAM), + E820_ENTRY(0x30000, 0x34000, E820_RAM), + E820_ENTRY(0x38000, 0x3c000, E820_RAM), + E820_ENTRY(0x40000, 0x44000, E820_RAM), + E820_ENTRY(0x48000, 0x4c000, E820_RAM), + E820_ENTRY(0x50000, 0x54000, E820_RAM), + E820_ENTRY(0x58000, 0x5c000, E820_RAM), + E820_ENTRY(0x60000, 0x64000, E820_RAM), + E820_ENTRY(0x68000, 0x6c000, E820_RAM), + E820_ENTRY(0x70080, 0x74080, E820_RAM), + E820_ENTRY(0x78000, 0x7c000, E820_RAM), + E820_ENTRY(0x100000000ULL, 0x120000000ULL, E820_RAM), +}; +static int nr_test_map = 17; + +#define UNIT_PROTECT_REG(s, e) \ + printk("protecting 0x%Lx - 0x%Lx\n", (uint64_t)(s), (uint64_t)(e)); \ + if ( !protect_region(test_map, &nr_test_map, (s), ((e) - (s)), \ + E820_RESERVED) ) { \ + printk("\tFAILED\n"); \ + return false; \ + } + +static bool verify_entry(int idx, uint64_t start, uint64_t end, uint32_t type) +{ + memory_map_t *entry = &test_map[idx]; + uint64_t base = e820_base_64(entry); + uint64_t length = e820_length_64(entry); + + if ( start == base && (end - start) == length && type == entry->type ) + return true; + else + return false; +} + +#define UNIT_VERIFY(idx, s, e, t) \ + if ( !verify_entry(idx, s, e, t) ) { \ + printk("verification of index %u failed\n", idx); \ + return false; \ + } + + +static bool UNIT_PROT_01(void) +{ + /* reserve within gap space (e1---e1 r1---r1 e2---e2) */ + UNIT_PROTECT_REG(0x05000, 0x06000); + UNIT_VERIFY(0, 0x0, 0x04000, E820_RAM); + UNIT_VERIFY(1, 0x05000, 0x06000, E820_RESERVED); + return true; +} + +static bool UNIT_PROT_02(void) +{ + /* reserve partially overlapping beginning 1 (r1---e1+++r1---e1) */ + UNIT_PROTECT_REG(0x07000, 0x0a000); + UNIT_VERIFY(2, 0x07000, 0x0a000, E820_RESERVED); + UNIT_VERIFY(3, 0x0a000, 0x0c000, E820_RAM); + return true; +} + +static bool UNIT_PROT_03(void) +{ + /* reserve partially overlapping beginning 2 (r1---e1+++e1--e2+++r1--e2) */ + UNIT_PROTECT_REG(0x0e000, 0x1a000); + UNIT_VERIFY(4, 0x0e000, 0x1a000, E820_RESERVED); + UNIT_VERIFY(5, 0x1a000, 0x1c000, E820_RAM); + return true; +} + +static bool UNIT_PROT_04(void) +{ + /* reserve partially overlapping end 1 (e1---r1+++e1---r1) */ + UNIT_PROTECT_REG(0x22000, 0x26000); + UNIT_VERIFY(6, 0x20000, 0x22000, E820_RAM); + UNIT_VERIFY(7, 0x22000, 0x26000, E820_RESERVED); + return true; +} + +static bool UNIT_PROT_05(void) +{ + /* reserve partially overlapping end 2 (e1---r1+++e1---e2+++e2---r1) */ + UNIT_PROTECT_REG(0x2a000, 0x36000); + UNIT_VERIFY(8, 0x28000, 0x2a000, E820_RAM); + UNIT_VERIFY(9, 0x2a000, 0x36000, E820_RESERVED); + return true; +} + +static bool UNIT_PROT_06(void) +{ + /* reserve partially overlapping 2 (e1---r1+++e1---e2+++r1---e1) */ + UNIT_PROTECT_REG(0x3a000, 0x42000); + UNIT_VERIFY(10, 0x38000, 0x3a000, E820_RAM); + UNIT_VERIFY(11, 0x3a000, 0x42000, E820_RESERVED); + UNIT_VERIFY(12, 0x42000, 0x44000, E820_RAM); + return true; +} + +static bool UNIT_PROT_07(void) +{ + /* reserve fully containing 1 (r1---e1+++e1---r1) */ + UNIT_PROTECT_REG(0x46000, 0x4e000); + UNIT_VERIFY(13, 0x46000, 0x4e000, E820_RESERVED); + return true; +} + +static bool UNIT_PROT_08(void) +{ + /* reserve fully containing 2 (r1---e1+++e1-e2+++e2---r1) */ + UNIT_PROTECT_REG(0x4e000, 0x5d000); + UNIT_VERIFY(14, 0x4e000, 0x5d000, E820_RESERVED); + return true; +} + +static bool UNIT_PROT_09(void) +{ + /* reserve fully contained (e1---r1+++r1---e1) */ + UNIT_PROTECT_REG(0x62000, 0x63000); + UNIT_VERIFY(15, 0x60000, 0x62000, E820_RAM); + UNIT_VERIFY(16, 0x62000, 0x63000, E820_RESERVED); + UNIT_VERIFY(17, 0x63000, 0x64000, E820_RAM); + return true; +} + +static bool UNIT_PROT_10(void) +{ + /* reserve identical (e1r1+++e1r1) */ + UNIT_PROTECT_REG(0x68000, 0x6c000); + UNIT_VERIFY(18, 0x68000, 0x6c000, E820_RESERVED); + return true; +} + +static bool UNIT_PROT_11(void) +{ + /* reserve sub-page in sub-page range */ + UNIT_PROTECT_REG(0x70040, 0x74040); + UNIT_VERIFY(19, 0x70040, 0x74040, E820_RESERVED); + UNIT_VERIFY(20, 0x74040, 0x74080, E820_RAM); + UNIT_VERIFY(21, 0x78000, 0x7c000, E820_RAM); + return true; +} + +static bool UNIT_PROT_12(void) +{ + /* reserve in high memory (e1---r1+++r1---e1) */ + UNIT_PROTECT_REG(0x100004000ULL, 0x100006000ULL); + UNIT_VERIFY(22, 0x100000000ULL, 0x100004000ULL, E820_RAM); + UNIT_VERIFY(23, 0x100004000ULL, 0x100006000ULL, E820_RESERVED); + UNIT_VERIFY(24, 0x100006000ULL, 0x120000000ULL, E820_RAM); + return true; +} + +void unit_test_validate_e820(void) +{ + printk("test map before:\n"); + print_map(test_map, nr_test_map); + + RUN_CASE(UNIT_PROT_01); + RUN_CASE(UNIT_PROT_02); + RUN_CASE(UNIT_PROT_03); + RUN_CASE(UNIT_PROT_04); + RUN_CASE(UNIT_PROT_05); + RUN_CASE(UNIT_PROT_06); + RUN_CASE(UNIT_PROT_07); + RUN_CASE(UNIT_PROT_08); + RUN_CASE(UNIT_PROT_09); + RUN_CASE(UNIT_PROT_10); + RUN_CASE(UNIT_PROT_11); + RUN_CASE(UNIT_PROT_12); + + printk("all e820 unit tests passed:\n"); + print_map(test_map, nr_test_map); +} /* * Local variables: diff -r 4ea7c584151a tboot/common/tboot.c --- a/tboot/common/tboot.c Tue Jan 13 11:29:14 2009 -0800 +++ b/tboot/common/tboot.c Tue Jan 20 22:25:23 2009 -0800 @@ -267,6 +267,9 @@ void begin_launch(multiboot_info_t *mbi) printk("command line: %s\n", g_cmdline); if ( s3_flag ) printk("resume from S3\n"); + + extern void unit_test_validate_e820(void); + unit_test_validate_e820(); /* we should only be executing on the BSP */ rdmsrl(MSR_IA32_APICBASE, apicbase); tboot-1.8.0/test-patches/mtrrs-test.patch0000644000000000000000000004305112272416301016547 0ustar 00000000000000--- tboot/txt/mtrrs.c 2008-05-28 12:01:12.000000000 -0700 +++ tboot/txt/mtrrs-test.c 2008-05-28 12:00:34.000000000 -0700 @@ -415,10 +415,423 @@ return true; } +#ifdef MTRR_VALIDATION_UNITTEST + +#define RUN_CASE(caseid) {\ + if ( caseid() )\ + printk("VALIDATE_MTTR_UNIT_TEST: " #caseid " passed\n");\ + else\ + printk("VALIDATE_MTTR_UNIT_TEST: " #caseid " failed\n");\ +} + +static mtrr_state_t g_test_state; + +static bool UNIT_VM_V_01(void) +{ + g_test_state.num_var_mtrrs = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_02(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 0; + g_test_state.mtrr_physmasks[0].mask = 0x000000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_03(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0x000000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_04(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFFFFF; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_05(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_06(void) +{ + g_test_state.num_var_mtrrs = 2; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x001000; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 1; + g_test_state.mtrr_physmasks[1].mask = 0xFFF000; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_07(void) +{ + g_test_state.num_var_mtrrs = 2; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x001000; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 0; + g_test_state.mtrr_physmasks[1].mask = 0xFFF000; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_08(void) +{ + g_test_state.num_var_mtrrs = 2; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_WRPROT; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000800; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_WRPROT; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x000800; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 1; + g_test_state.mtrr_physmasks[1].mask = 0xFFF800; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_09(void) +{ + g_test_state.num_var_mtrrs = 2; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_WRCOMB; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000800; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x000800; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 1; + g_test_state.mtrr_physmasks[1].mask = 0xFFF800; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_10(void) +{ + g_test_state.num_var_mtrrs = 2; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_WRTHROUGH; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000800; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_WRBACK; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x000800; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 1; + g_test_state.mtrr_physmasks[1].mask = 0xFFF800; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_V_11(void) +{ + g_test_state.num_var_mtrrs = 3; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000800; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_WRTHROUGH; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x000800; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 1; + g_test_state.mtrr_physmasks[1].mask = 0xFFF800; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + g_test_state.mtrr_physbases[2].type = MTRR_TYPE_WRPROT; + g_test_state.mtrr_physbases[2].reserved1 = 0; + g_test_state.mtrr_physbases[2].base = 0x000800; + g_test_state.mtrr_physbases[2].reserved2 = 0; + g_test_state.mtrr_physmasks[2].reserved1 = 0; + g_test_state.mtrr_physmasks[2].v = 1; + g_test_state.mtrr_physmasks[2].mask = 0xFFF000; + g_test_state.mtrr_physmasks[2].reserved2 = 0; + + return validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_01(void) +{ + g_test_state.num_var_mtrrs = 17; + + return !validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_02(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0x000001; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return !validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_03(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0x800001; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return !validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_04(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0x000002; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return !validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_05(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0x00FF00; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return !validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_06(void) +{ + g_test_state.num_var_mtrrs = 1; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0x400000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + + return !validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_07(void) +{ + g_test_state.num_var_mtrrs = 2; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000000; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x001000; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 1; + g_test_state.mtrr_physmasks[1].mask = 0xFFF0F0; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + + return !validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_08(void) +{ + g_test_state.num_var_mtrrs = 2; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_WRCOMB; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000800; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF000; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_WRTHROUGH; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x000800; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 1; + g_test_state.mtrr_physmasks[1].mask = 0xFFF800; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + + return !validate_mtrrs(&g_test_state); +} + +static bool UNIT_VM_IV_09(void) +{ + g_test_state.num_var_mtrrs = 3; + g_test_state.mtrr_physbases[0].type = MTRR_TYPE_UNCACHABLE; + g_test_state.mtrr_physbases[0].reserved1 = 0; + g_test_state.mtrr_physbases[0].base = 0x000800; + g_test_state.mtrr_physbases[0].reserved2 = 0; + g_test_state.mtrr_physmasks[0].reserved1 = 0; + g_test_state.mtrr_physmasks[0].v = 1; + g_test_state.mtrr_physmasks[0].mask = 0xFFF800; + g_test_state.mtrr_physmasks[0].reserved2 = 0; + g_test_state.mtrr_physbases[1].type = MTRR_TYPE_WRTHROUGH; + g_test_state.mtrr_physbases[1].reserved1 = 0; + g_test_state.mtrr_physbases[1].base = 0x000800; + g_test_state.mtrr_physbases[1].reserved2 = 0; + g_test_state.mtrr_physmasks[1].reserved1 = 0; + g_test_state.mtrr_physmasks[1].v = 1; + g_test_state.mtrr_physmasks[1].mask = 0xFFF000; + g_test_state.mtrr_physmasks[1].reserved2 = 0; + g_test_state.mtrr_physbases[2].type = MTRR_TYPE_WRPROT; + g_test_state.mtrr_physbases[2].reserved1 = 0; + g_test_state.mtrr_physbases[2].base = 0x000800; + g_test_state.mtrr_physbases[2].reserved2 = 0; + g_test_state.mtrr_physmasks[2].reserved1 = 0; + g_test_state.mtrr_physmasks[2].v = 1; + g_test_state.mtrr_physmasks[2].mask = 0xFFF000; + g_test_state.mtrr_physmasks[2].reserved2 = 0; + + return !validate_mtrrs(&g_test_state); +} + +void unit_test_validate_mtrrs(void) +{ + RUN_CASE(UNIT_VM_V_01 ); /* Zero items */ + RUN_CASE(UNIT_VM_V_02 ); /* 1 invalid item */ + RUN_CASE(UNIT_VM_V_03 ); /* 1 valid item. Whole region protected. */ + RUN_CASE(UNIT_VM_V_04 ); /* 1 valid item. 1 page protected. */ + RUN_CASE(UNIT_VM_V_05 ); /* 1 valid item. 2^n pages protected. */ + RUN_CASE(UNIT_VM_V_06 ); /* 2 valid item. 2^n pages protected. */ + RUN_CASE(UNIT_VM_V_07 ); /* 2 items, 1 valid, 1 invalid. 2^n pages protected. */ + RUN_CASE(UNIT_VM_V_08 ); /* 2 overlapped items, with same type. */ + RUN_CASE(UNIT_VM_V_09 ); /* 2 overlapped items, 1 MTRR_TYPE_UNCACHABLE (0) */ + RUN_CASE(UNIT_VM_V_10 ); /* 2 overlapped items, 1 MTRR_TYPE_WRTHROUGH (4), 1 MTRR_TYPE_WRBACK(6) */ + RUN_CASE(UNIT_VM_V_11 ); /* 3 overlapped items, 1 MTRR_TYPE_UNCACHABLE(0), 1 MTRR_TYPE_WRTHROUGH (4), 1 MTRR_TYPE_WRPROT(5) */ + RUN_CASE(UNIT_VM_IV_01); /* 17 items, should be larger than mtrr_cap.vcnt */ + RUN_CASE(UNIT_VM_IV_02); /* 1 valid item, non-contiguous case 1. */ + RUN_CASE(UNIT_VM_IV_03); /* 1 valid item, non-contiguous case 2. */ + RUN_CASE(UNIT_VM_IV_04); /* 1 valid item, non-contiguous case 3. */ + RUN_CASE(UNIT_VM_IV_05); /* 1 valid item, non-contiguous case 4. */ + RUN_CASE(UNIT_VM_IV_06); /* 1 valid item, non-contiguous case 5. */ + RUN_CASE(UNIT_VM_IV_07); /* 2 valid items. One with non-contiguous region. */ + RUN_CASE(UNIT_VM_IV_08); /* 2 overlapped items, 1 MTRR_TYPE_WRCOMB(1), 1 MTRR_TYPE_WRTHROUGH(4) */ + RUN_CASE(UNIT_VM_IV_09); /* 3 overlapped items, 1 MTRR_TYPE_UNCACHABLE(0), 1 MTRR_TYPE_WRTHROUGH (4), 1 MTRR_TYPE_WRPROT(5) */ +} + +#endif /* MTRR_VALIDATION_UNITTEST */ + void restore_mtrrs(mtrr_state_t *saved_state) { int ndx; +#ifdef MTRR_VALIDATION_UNITTEST + unit_test_validate_mtrrs(); +#endif /* MTRR_VALIDATION_UNITTEST */ + /* disable all MTRRs first */ set_all_mtrrs(false); tboot-1.8.0/test-patches/tpm-test.patch0000644000000000000000000032142012272416301016177 0ustar 00000000000000diff -r 950fec11ef90 tboot/common/tboot.c --- a/tboot/common/tboot.c Sun Jan 15 23:21:20 2012 +0800 +++ b/tboot/common/tboot.c Tue Apr 17 10:15:33 2012 +0800 @@ -313,6 +313,7 @@ void begin_launch(multiboot_info_t *mbi) /* has already been launched */ /* make TPM ready for measured launch */ + tpm_unit_test_before_senter(); if ( !is_tpm_ready(0) ) apply_policy(TB_ERR_TPM_NOT_READY); diff -r 950fec11ef90 tboot/common/tpm.c --- a/tboot/common/tpm.c Sun Jan 15 23:21:20 2012 +0800 +++ b/tboot/common/tpm.c Tue Apr 17 10:13:40 2012 +0800 @@ -2121,6 +2121,2815 @@ uint32_t tpm_get_random(uint32_t localit return ret; } +#ifdef TPM_UNIT_TEST + +static void clean_buf(void) +{ + memset(cmd_buf, 0, TPM_CMD_SIZE_MAX); + memset(rsp_buf, 0, TPM_RSP_SIZE_MAX); +} + +static bool check_buf(uint8_t *exp_cmd, uint32_t cmd_size, + uint8_t *exp_rsp, uint32_t rsp_size) +{ + if ( memcmp(exp_cmd, cmd_buf, cmd_size) != 0 ) + return false; + if ( memcmp(exp_rsp, rsp_buf, rsp_size) != 0 ) + return false; + return true; +} + +static bool UNIT_PE_V_01(void) +{ + uint32_t locality = 0; + uint32_t pcr = 16; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, 0x04, 0x0a, + 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, 0x8f, 0x1d, + 0x68, 0xd1, 0x39, 0x61}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, + 0x04, 0x04}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, + 0x04, 0x0a, 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, + 0x8f, 0x1d, 0x68, 0xd1, 0x39, 0x61}; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PE_V_02(void) +{ + uint32_t locality = 0; + uint32_t pcr = 16; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t *out = NULL; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, + 0x04, 0x04}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00}; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, out); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PE_V_03(void) +{ + uint32_t locality = 2; + uint32_t pcr = 16; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, 0x04, 0x0a, + 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, 0x8f, 0x1d, + 0x68, 0xd1, 0x39, 0x61}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, + 0x04, 0x04}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, + 0x04, 0x0a, 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, + 0x8f, 0x1d, 0x68, 0xd1, 0x39, 0x61}; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PE_V_04(void) +{ + uint32_t locality = 2; + uint32_t pcr = 17; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + /* for SDP3 */ + /* + 0xe2, 0x76, 0x21, 0x70, 0x8d, 0x8b, 0x74, 0x20, + 0x5e, 0x61, 0x3c, 0xe6, 0xd3, 0x39, 0xf8, 0x0b, + 0x3d, 0x83, 0x18, 0x42}};*/ + /* for WB */ + 0x46, 0xF5, 0xBE, 0x07, 0x41, 0xA0, 0xCC, 0x80, + 0x0C, 0x9D, 0x14, 0x68, 0x25, 0x75, 0x48, 0x7B, + 0x78, 0xB6, 0xD2, 0xA1}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x11, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, + 0x04, 0x04}; + uint8_t exp_rsp[] = { + /* for SDP3 */ + /* 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xe2, 0x76, 0x21, 0x70, 0x8d, 0x8b, + 0x74, 0x20, 0x5e, 0x61, 0x3c, 0xe6, 0xd3, 0x39, + 0xf8, 0x0b, 0x3d, 0x83, 0x18, 0x42}; */ + /* for WB */ + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x46, 0xF5, 0xBE, 0x07, 0x41, 0xA0, + 0xCC, 0x80, 0x0C, 0x9D, 0x14, 0x68, 0x25, 0x75, + 0x48, 0x7B, 0x78, 0xB6, 0xD2, 0xA1}; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PE_V_05(void) +{ + uint32_t locality = 2; + uint32_t pcr = 18; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + /* + tpm_pcr_value_t exp_out = {{ + 0xe5, 0x9b, 0x4b, 0xf8, 0xd3, 0x42, 0x3f, 0xe7, + 0xeb, 0xc4, 0x2c, 0xe3, 0xb0, 0xf8, 0x98, 0x35, + 0x09, 0x9e, 0x2b, 0x96}}; + */ + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x12, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, + 0x04, 0x04}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00/*, 0xe5, 0x9b, 0x4b, 0xf8, 0xd3, 0x42, + 0x3f, 0xe7, 0xeb, 0xc4, 0x2c, 0xe3, 0xb0, 0xf8, + 0x98, 0x35, 0x09, 0x9e, 0x2b, 0x96*/}; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + /* + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + */ + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PE_V_06(void) +{ + uint32_t locality = 2; + uint32_t pcr = 19; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, 0x04, 0x0a, + 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, 0x8f, 0x1d, + 0x68, 0xd1, 0x39, 0x61}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x13, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, + 0x04, 0x04}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, + 0x04, 0x0a, 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, + 0x8f, 0x1d, 0x68, 0xd1, 0x39, 0x61}; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PE_V_07(void) +{ + uint32_t locality = 2; + uint32_t pcr = 20; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, 0x04, 0x0a, + 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, 0x8f, 0x1d, + 0x68, 0xd1, 0x39, 0x61}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, + 0x04, 0x04}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, + 0x04, 0x0a, 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, + 0x8f, 0x1d, 0x68, 0xd1, 0x39, 0x61}; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PE_IV_01(void) +{ + uint32_t locality = 0; + uint32_t pcr = 16; + tpm_digest_t *in = NULL; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, in, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PE_IV_02(void) +{ + uint32_t locality = 5; + uint32_t pcr = 16; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PE_IV_03(void) +{ + uint32_t locality = 0; + uint32_t pcr = 24; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PE_IV_04(void) +{ + uint32_t locality = 2; + uint32_t pcr = 16; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_FAIL; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PE_IV_05(void) +{ + uint32_t locality = 1; + uint32_t pcr = 16; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_FAIL; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PE_IV_06(void) +{ + uint32_t locality = 0; + uint32_t pcr = 17; + tpm_digest_t in = {{ + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}}; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_LOCALITY;/* in SPD 3 whould be TPM_NOTLOCAL */ + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x11, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, + 0x04, 0x04}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x3d}; + + clean_buf(); + ret = tpm_pcr_extend(locality, pcr, &in, &out); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_01(void) +{ + uint32_t locality = 0; + uint32_t pcr = 16; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x10}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_02(void) +{ + uint32_t locality = 0; + uint32_t pcr = 16; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, 0x04, 0x0a, + 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, 0x8f, 0x1d, + 0x68, 0xd1, 0x39, 0x61}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x10}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, + 0x04, 0x0a, 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, + 0x8f, 0x1d, 0x68, 0xd1, 0x39, 0x61}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_03(void) +{ + uint32_t locality = 2; + uint32_t pcr = 16; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x10}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_04(void) +{ + uint32_t locality = 2; + uint32_t pcr = 16; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, 0x04, 0x0a, + 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, 0x8f, 0x1d, + 0x68, 0xd1, 0x39, 0x61}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x10}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xfd, 0x60, 0xed, 0x16, 0xe5, 0x04, + 0x04, 0x0a, 0xaf, 0xa1, 0xc1, 0xcc, 0xed, 0x33, + 0x8f, 0x1d, 0x68, 0xd1, 0x39, 0x61}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_05(void) +{ + uint32_t locality = 2; + uint32_t pcr = 17; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + /* for SDP3 */ + /* 0xf8, 0xf2, 0xfb, 0x54, 0xdb, 0x1b, 0xcb, 0xdf, + 0xcf, 0x48, 0xbe, 0xde, 0xb4, 0xf6, 0x94, 0x97, + 0x19, 0x25, 0xbd, 0x9b}}; */ + /* for WB */ + 0x68, 0x2C, 0xC6, 0x4B, 0x89, 0x60, 0x4A, 0xF6, + 0x53, 0x0B, 0x80, 0xC2, 0xD7, 0x35, 0x00, 0x4F, + 0xC8, 0x95, 0x74, 0xE0}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x11}; + uint8_t exp_rsp[] = { + /* for SDP3 */ + /* 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0xf2, 0xfb, 0x54, 0xdb, 0x1b, + 0xcb, 0xdf, 0xcf, 0x48, 0xbe, 0xde, 0xb4, 0xf6, + 0x94, 0x97, 0x19, 0x25, 0xbd, 0x9b}; */ + /* for WB */ + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x68, 0x2C, 0xC6, 0x4B, 0x89, 0x60, + 0x4A, 0xF6, 0x53, 0x0B, 0x80, 0xC2, 0xD7, 0x35, + 0x00, 0x4F, 0xC8, 0x95, 0x74, 0xE0}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_06(void) +{ + uint32_t locality = 2; + uint32_t pcr = 18; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + /* + tpm_pcr_value_t exp_out = {{ + 0x8d, 0x84, 0xdb, 0x02, 0xc0, 0x13, 0x9d, 0x2c, + 0x51, 0xdb, 0x15, 0xd8, 0xc6, 0xc4, 0x1b, 0xc0, + 0x6b, 0x34, 0xbe, 0xeb}}; + */ + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x12}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00/*, 0x8d, 0x84, 0xdb, 0x02, 0xc0, 0x13, + 0x9d, 0x2c, 0x51, 0xdb, 0x15, 0xd8, 0xc6, 0xc4, + 0x1b, 0xc0, 0x6b, 0x34, 0xbe, 0xeb*/}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + /* + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + */ + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_07(void) +{ + uint32_t locality = 2; + uint32_t pcr = 19; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x13}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_08(void) +{ + uint32_t locality = 2; + uint32_t pcr = 20; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x14}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_V_09(void) +{ + uint32_t locality = 0; + uint32_t pcr = 17; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + tpm_pcr_value_t exp_out = {{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff}}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x11}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + if ( memcmp(&out, &exp_out, sizeof(out)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PR_IV_01(void) +{ + uint32_t locality = 5; + uint32_t pcr = 16; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PR_IV_02(void) +{ + uint32_t locality = 0; + uint32_t pcr = 24; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PR_IV_03(void) +{ + uint32_t locality = 2; + uint32_t pcr = 16; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_FAIL; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PR_IV_04(void) +{ + uint32_t locality = 1; + uint32_t pcr = 16; + tpm_pcr_value_t out = {{0,}}; + uint32_t ret; + + uint32_t exp_ret = TPM_FAIL; + + clean_buf(); + ret = tpm_pcr_read(locality, pcr, &out); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PS_V_01(void) +{ + uint32_t locality = 0; + uint32_t pcr = 16; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0xc8, 0x00, 0x03, 0x00, 0x00, 0x01}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00}; + + clean_buf(); + ret = tpm_pcr_reset(locality, pcr); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PS_V_02(void) +{ + uint32_t locality = 2; + uint32_t pcr = 16; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0xc8, 0x00, 0x03, 0x00, 0x00, 0x01}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00}; + + clean_buf(); + ret = tpm_pcr_reset(locality, pcr); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PS_V_03(void) +{ + uint32_t locality = 2; + uint32_t pcr = 20; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0xc8, 0x00, 0x03, 0x00, 0x00, 0x10}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00}; + + clean_buf(); + ret = tpm_pcr_reset(locality, pcr); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PS_IV_01(void) +{ + uint32_t locality = 0; + uint32_t pcr = 15; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_pcr_reset(locality, pcr); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PS_IV_02(void) +{ + uint32_t locality = 0; + uint32_t pcr = 24; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_pcr_reset(locality, pcr); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PS_IV_03(void) +{ + uint32_t locality = 5; + uint32_t pcr = 16; + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_pcr_reset(locality, pcr); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_PS_IV_04(void) +{ + uint32_t locality = 0; + uint32_t pcr = 20; + uint32_t ret; + + uint32_t exp_ret = TPM_NOTLOCAL; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0xc8, 0x00, 0x03, 0x00, 0x00, 0x10}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x33}; + + clean_buf(); + ret = tpm_pcr_reset(locality, pcr); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_PS_IV_05(void) +{ + uint32_t locality = 2; + uint32_t pcr = 17; + uint32_t ret; + + uint32_t exp_ret = TPM_NOTLOCAL; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0xc8, 0x00, 0x03, 0x00, 0x00, 0x02}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x33}; + + clean_buf(); + ret = tpm_pcr_reset(locality, pcr); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +#define TPM_NV_INDEX_LCP_OWN 0x40000002 +#define TPM_NV_INDEX_SELFDEF 0x400000ff +#define TPM_NV_INDEX_UNDEF 0x400000ee + +static bool UNIT_NW_V_01(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 0; + uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, + 0x00, 0xcd, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1a, 0x1b, 0x1c}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00}; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, data, data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NW_V_02(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_SELFDEF; + uint32_t offset = 0; + static uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 256 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 512 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09}; /* 746 */ + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + static uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0xcd, 0x40, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xea, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}; /* 768 */ + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00}; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, + (uint8_t *)data, data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf((uint8_t *)exp_cmd, sizeof(exp_cmd), + exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NW_V_03(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_SELFDEF; + uint32_t offset = 746; + uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, + 0x00, 0xcd, 0x40, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x02, 0xea, 0x00, 0x00, 0x00, 0x16, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00}; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, data, data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NW_V_04(void) +{ + uint32_t locality = 2; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 0; + uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, + 0x00, 0xcd, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00}; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, data, data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NW_IV_01(void) +{ + uint32_t locality = 5; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 0; + uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, data, data_size); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_NW_IV_02(void) +{ + uint32_t locality = 2; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 0; + uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_FAIL; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, data, data_size); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_NW_IV_03(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_UNDEF; + uint32_t offset = 0; + uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_BADINDEX; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, + 0x00, 0xcd, 0x40, 0x00, 0x00, 0xee, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x02}; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, data, data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NW_IV_04(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 29; + uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_NOSPACE; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, + 0x00, 0xcd, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x1d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x11}; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, data, data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NW_IV_05(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 20; + uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_NOSPACE; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, + 0x00, 0xcd, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x11}; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, data, data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NW_IV_06(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_SELFDEF; + uint32_t offset = 0; + static uint8_t data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 256 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 512 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a}; /* 747 */ + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_nv_write_value(locality, index, offset, + (uint8_t *)data, data_size); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_NR_V_01(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 0; + uint8_t data[29] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_size = sizeof(data); + uint8_t exp_data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0xcf, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1a, 0x1b, 0x1c}; + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, data, &data_size); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_size ) + return false; + if ( memcmp(data, &exp_data, sizeof(data)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NR_V_02(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_SELFDEF; + uint32_t offset = 0; + static uint8_t data[TPM_NV_READ_VALUE_DATA_SIZE_MAX] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_size = sizeof(data); + static uint8_t exp_data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 256 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 512 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, }; /* 754 */ + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0xcf, 0x40, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xf2}; + static uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xf2, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; /* 768 */ + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, + (uint8_t *)data, &data_size); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_size ) + return false; + if ( memcmp((uint8_t *)data, (uint8_t *)exp_data, sizeof(data)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), + (uint8_t *)exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NR_V_03(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_SELFDEF; + uint32_t offset = 754; + uint8_t data[14] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_size = sizeof(data); + uint8_t exp_data[] = { + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0xcf, 0x40, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x02, 0xf2, 0x00, 0x00, 0x00, 0x0e}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15}; + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, data, &data_size); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_size ) + return false; + if ( memcmp(data, &exp_data, sizeof(data)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NR_V_04(void) +{ + uint32_t locality = 2; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 0; + uint8_t data[20] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_size = sizeof(data); + uint8_t exp_data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13}; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0xcf, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x14}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13}; + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, data, &data_size); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_size ) + return false; + if ( memcmp(data, &exp_data, sizeof(data)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NR_IV_01(void) +{ + uint32_t locality = 5; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 0; + uint8_t data[20] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_BAD_PARAMETER; + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, data, &data_size); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_NR_IV_02(void) +{ + uint32_t locality = 2; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 0; + uint8_t data[20] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_FAIL; + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, data, &data_size); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_NR_IV_03(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_UNDEF; + uint32_t offset = 0; + uint8_t data[20] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_BADINDEX; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0xcf, 0x40, 0x00, 0x00, 0xee, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x14}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x02}; + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, data, &data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NR_IV_04(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 29; + uint8_t data[20] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_NOSPACE; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0xcf, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x1d, 0x00, 0x00, 0x00, 0x14}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x11}; + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, data, &data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NR_IV_05(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_LCP_OWN; + uint32_t offset = 20; + uint8_t data[20] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_NOSPACE; + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0xcf, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x14}; + uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x11}; + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, data, &data_size); + if ( ret != exp_ret ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_NR_IV_06(void) +{ + uint32_t locality = 0; + uint32_t index = TPM_NV_INDEX_SELFDEF; + uint32_t offset = 0; + static uint8_t data[TPM_NV_READ_VALUE_DATA_SIZE_MAX + 1] = {0,}; + uint32_t data_size = sizeof(data); + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_size = TPM_NV_READ_VALUE_DATA_SIZE_MAX; + static uint8_t exp_data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 256 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 512 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, }; /* 754 */ + uint8_t exp_cmd[] = { + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, + 0x00, 0xcf, 0x40, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xf2}; + static uint8_t exp_rsp[] = { + 0x00, 0xc4, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xf2, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; /* 768 */ + + clean_buf(); + ret = tpm_nv_read_value(locality, index, offset, + (uint8_t *)data, &data_size); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_size ) + return false; + if ( memcmp((uint8_t *)data, (uint8_t *)exp_data, sizeof(data)) != 0 ) + return false; + if ( !check_buf(exp_cmd, sizeof(exp_cmd), + (uint8_t *)exp_rsp, sizeof(exp_rsp)) ) + return false; + + return true; +} + +static bool UNIT_HMAC_V_01(void) +{ + uint8_t key[20] = { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x00, 0x00, 0x00, 0x00}; + uint32_t in_data_size = 8; + uint8_t in_data[9] = "Hi There"; + uint8_t digest[20]; + bool ret; + + bool exp_ret = true; + uint8_t exp_md[20] = { + 0x67, 0x5b, 0x0b, 0x3a, 0x1b, 0x4d, 0xdf, 0x4e, 0x12, 0x48, + 0x72, 0xda, 0x6c, 0x2f, 0x63, 0x2b, 0xfe, 0xd9, 0x57, 0xe9}; + + clean_buf(); + ret = hmac(key, in_data, in_data_size, digest); + + if ( ret != exp_ret ) + return false; + { + printk("hmac result:\n"); + for ( int i = 0; i < 20; i++ ) + printk("%02x ", digest[i]); + printk("\n"); + } + + if ( memcmp( digest, exp_md, sizeof(digest)) != 0 ) + return false; + + return true; +} + +/* +static bool UNIT_OS_V_01(void) +{ + uint32_t locality = 0; + tpm_entity_type_t ent_type = TPM_ET_SRK; + uint32_t ent_value = TPM_KH_SRK; + tpm_nonce_t odd_osap, even_osap, nonce_even; + tpm_authhandle_t hauth; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + + clean_buf(); + ret = tpm_osap(locality, ent_type, ent_value, &odd_osap, &hauth, + &nonce_even, &even_osap); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_OI_V_01(void) +{ + uint32_t locality = 0; + tpm_nonce_t nonce_even; + tpm_authhandle_t hauth; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + + clean_buf(); + ret = tpm_oiap(locality, &hauth, &nonce_even); + if ( ret != exp_ret ) + return false; + + return true; +} +*/ + +static bool test_tpm_wrap_seal(void) +{ + //uint32_t locality = 0; + //tpm_pcr_info_long_t pcr_info = + // {0x16, 0x01, 0x01, {3, {0, 0, 0}}, {3, {0, 0, 0}}, {{0,}}, {{0,}}}; + uint32_t in_data_size = 0x20; + uint8_t in_data[] = { + 0xaa,0xbd,0x5e,0x82,0xee,0x67,0x78,0x5e,0x43,0xbc,0x5e,0x26, + 0x64,0x5e,0x12,0x12,0x5b,0x90,0xdf,0x0a,0x53,0x61,0x96,0x4b, + 0xb9,0x4e,0x1d,0x2e,0x3c,0xb5,0xe6,0x1d}; + //tpm_stored_data12_t *sealed_data = (tpm_stored_data12_t *)&blob; + uint32_t ret = true; + uint8_t key_authdata[20] = { + 0x5b, 0xaa, 0x61, 0xe4, 0xc9, 0xb9, 0x3f, 0x3f, 0x06, 0x82, + 0x25, 0x0b, 0x6c, 0xf8, 0x33, 0x1b, 0x7e, 0xe6, 0x8f, 0xd8}; + uint8_t bb_authdata[20] = { + 0x5b, 0xaa, 0x61, 0xe4, 0xc9, 0xb9, 0x3f, 0x3f, 0x06, 0x82, + 0x25, 0x0b, 0x6c, 0xf8, 0x33, 0x1b, 0x7e, 0xe6, 0x8f, 0xd8}; + tpm_nonce_t odd_osap = {{ + 0x1f, 0xd5, 0xc9, 0xa9, 0x4c, 0x67, 0xed, 0xe2, 0x66, 0x8d, + 0x7f, 0xde, 0x7e, 0x81, 0xd4, 0x29, 0xc3, 0xbe, 0xbb, 0xb3}}; + tpm_nonce_t even_osap = {{ + 0x4f, 0xe5, 0xf4, 0xe3, 0x92, 0x35, 0x2e, 0x22, 0x9b, 0xe7, + 0xdd, 0x1b, 0xe0, 0xb7, 0x70, 0xf9, 0xd1, 0xf5, 0x6f, 0x74}}; + tpm_nonce_t nonce_even = {{ + 0xff, 0xbe, 0x07, 0x7c, 0x87, 0x07, 0x98, 0x0c, 0x00, 0xbc, + 0xbb, 0x96, 0x01, 0x88, 0xda, 0xc3, 0x0d, 0x02, 0xc0, 0x2e}}; + tpm_nonce_t nonce_odd = {{ + 0x1f, 0xd5, 0xc9, 0xa9, 0x4c, 0x67, 0xed, 0xe2, 0x66, 0x8d, + 0x7f, 0xde, 0x7e, 0x81, 0xd4, 0x29, 0xc3, 0xbe, 0xbb, 0xb3}}; + //tpm_authhandle_t hauth = 0; + 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 = 0;//sizeof(pcr_info); + uint32_t offset; + uint32_t ordinal = TPM_ORD_SEAL; + tpm_digest_t digest; + + /* generate nonce */ + //odd_osap = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; + + /* establish a osap session */ + //ret = tpm_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 *)&key_authdata, WRAPPER_IN_BUF, offset, + (uint8_t *)&shared_secret); + { + printk("shared_secret:\n"); + for ( int i = 0; i < 20; i++ ) + printk("%02x ", shared_secret[i]); + printk("\n"); + } + + /* 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, &bb_authdata, sizeof(blob_authdata)); + XOR_BLOB_TYPE(&enc_auth, &digest); + { + printk("enc_auth:\n"); + for ( int i = 0; i < 20; i++ ) + printk("%02x ", enc_auth[i]); + printk("\n"); + } + + /* generate nonce */ + //nonce_odd = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; + + /* 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); + { + printk("in param digest:\n"); + for ( int i = 0; i < 20; i++ ) + printk("%02x ", digest.digest[i]); + printk("\n"); + } + + + /* 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); + { + printk("pub auth data:\n"); + for ( int i = 0; i < 20; i++ ) + printk("%02x ", pub_auth[i]); + printk("\n"); + } + + + /* call the simple seal function */ + /*ret = tpm_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, + (tpm_stored_data12_header_t *)sealed_data, + &nonce_even, &res_auth); + */ + + return ret; +} + +static uint8_t blob[512]; +static uint32_t sealed_data_size; + +static bool UNIT_SL_V_01(void) +{ + uint32_t locality = 0; + tpm_pcr_info_long_t pcr_info = + {0x6, 0x01, 0x01, {3, {0, 0, 0}}, {3, {0, 0, 0}}, {{0,}}, {{0,}}}; + uint32_t in_data_size = 20; + uint8_t in_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + + sealed_data_size = 512; + clean_buf(); + ret = _tpm_wrap_seal(locality, &pcr_info, in_data_size, in_data, + &sealed_data_size, blob); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_SL_V_02(void) +{ + uint32_t locality = 2; + tpm_pcr_info_long_t pcr_info = + {0x6, 0x04, 0x04, {3, {0, 0, 2}}, {3, {0, 0, 2}}, {{0,}}, {{0,}}}; + uint32_t in_data_size = 20; + uint8_t in_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + uint32_t ret; + uint32_t offset = 0; + uint32_t blob_size = 20; + + uint32_t exp_ret = TPM_SUCCESS; + + + tpm_pcr_value_t pcr_value; + ret = tpm_pcr_read(locality, 17, &pcr_value); + if ( ret != TPM_SUCCESS ) + return false; + offset = 0; + UNLOAD_PCR_SELECTION(WRAPPER_IN_BUF, offset, &pcr_info.creation_pcr_selection); + UNLOAD_INTEGER(WRAPPER_IN_BUF, offset, blob_size); + UNLOAD_BLOB_TYPE(WRAPPER_IN_BUF, offset, &pcr_value); + sha1_buffer(WRAPPER_IN_BUF, offset, + (uint8_t *)&pcr_info.digest_at_creation); + memcpy((uint8_t *)&pcr_info.digest_at_release, + (uint8_t *)&pcr_info.digest_at_creation, + sizeof(pcr_info.digest_at_release)); + + sealed_data_size = 512; + clean_buf(); + ret = _tpm_wrap_seal(locality, &pcr_info, in_data_size, in_data, + &sealed_data_size, blob); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_SL_V_03(void) +{ + uint32_t locality = 0; + tpm_locality_selection_t release_locs = TPM_LOC_ZERO; + uint32_t pcr_nr_create = 0, pcr_nr_release = 0; + uint8_t *pcr_indcs_create = NULL, *pcr_indcs_release = NULL; + const tpm_pcr_value_t ** pcr_values_release = NULL; + uint32_t in_data_size = 20; + uint8_t in_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + + sealed_data_size = 512; + clean_buf(); + ret = tpm_seal(locality, release_locs, pcr_nr_create, pcr_indcs_create, + pcr_nr_release, pcr_indcs_release, pcr_values_release, + in_data_size, in_data, &sealed_data_size, blob); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_SL_V_04(void) +{ + uint32_t locality = 2; + tpm_locality_selection_t release_locs = TPM_LOC_TWO; + uint32_t pcr_nr_create = 1, pcr_nr_release = 1; + uint8_t pcr_indcs_create[1] = {17}, pcr_indcs_release[1] = {17}; + const tpm_pcr_value_t *pcr_values_release[1]; + uint32_t in_data_size = 20; + uint8_t in_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + + + tpm_pcr_value_t pcr_value; + ret = tpm_pcr_read(locality, 17, &pcr_value); + if ( ret != TPM_SUCCESS ) + return false; + pcr_values_release[0] = &pcr_value; + + sealed_data_size = 512; + clean_buf(); + ret = tpm_seal(locality, release_locs, pcr_nr_create, pcr_indcs_create, + pcr_nr_release, pcr_indcs_release, pcr_values_release, + in_data_size, in_data, &sealed_data_size, blob); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_SL_V_05(void) +{ + uint32_t locality = 2; + tpm_locality_selection_t release_locs = TPM_LOC_TWO; + uint32_t pcr_nr_create = 4, pcr_nr_release = 4; + uint8_t pcr_indcs_create[4] = {17,18,19,20}, + pcr_indcs_release[4] = {17,18,19,20}; + const tpm_pcr_value_t *pcr_values_release[4]; + uint32_t in_data_size = 20; + uint8_t in_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + + + tpm_pcr_value_t pcr_value[4]; + + for ( uint32_t i = 0; i < 4; i++ ) { + ret = tpm_pcr_read(locality, 17 + i, &pcr_value[i]); + if ( ret != TPM_SUCCESS ) + return false; + pcr_values_release[i] = &pcr_value[i]; + } + + sealed_data_size = 512; + clean_buf(); + ret = tpm_seal(locality, release_locs, pcr_nr_create, pcr_indcs_create, + pcr_nr_release, pcr_indcs_release, pcr_values_release, + in_data_size, in_data, &sealed_data_size, blob); + if ( ret != exp_ret ) + return false; + + return true; +} + +static bool UNIT_USL_V_01(void) +{ + uint32_t locality = 0; + uint32_t data_size = 20; + uint8_t data[20] = + {0, }; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_data_size = 20; + uint8_t exp_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + + clean_buf(); + ret = _tpm_wrap_unseal(locality, blob, &data_size, data); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_data_size ) + return false; + if ( memcmp(data, exp_data, data_size) != 0 ) + return false; + + return true; +} + +static bool UNIT_USL_V_02(void) +{ + uint32_t locality = 2; + uint32_t data_size = 20; + uint8_t data[20] = + {0, }; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_data_size = 20; + uint8_t exp_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + + clean_buf(); + ret = _tpm_wrap_unseal(locality, blob, &data_size, data); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_data_size ) + return false; + if ( memcmp(data, exp_data, data_size) != 0 ) + return false; + + return true; +} + +static bool UNIT_USL_V_03(void) +{ + uint32_t locality = 0; + uint32_t data_size = 20; + uint8_t data[20] = + {0, }; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_data_size = 20; + uint8_t exp_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + + clean_buf(); + ret = tpm_unseal(locality, sealed_data_size, blob, &data_size, data); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_data_size ) + return false; + if ( memcmp(data, exp_data, data_size) != 0 ) + return false; + + return true; +} + +static bool UNIT_USL_V_04(void) +{ + uint32_t locality = 2; + uint32_t data_size = 20; + uint8_t data[20] = + {0, }; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_data_size = 20; + uint8_t exp_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + + clean_buf(); + ret = tpm_unseal(locality, sealed_data_size, blob, &data_size, data); + if ( ret != exp_ret ) + return false; + if ( data_size != exp_data_size ) + return false; + if ( memcmp(data, exp_data, data_size) != 0 ) + return false; + + return true; +} + +static bool UNIT_USL_IV_01(void) +{ + uint32_t locality = 2; + uint32_t data_size = 20; + uint8_t data[20] = + {0, }; + uint32_t ret; + + uint32_t exp_ret = TPM_SUCCESS; + uint32_t exp_data_size = 20; + uint8_t exp_data[20] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + + blob[sealed_data_size/2] ^= 0x10; + clean_buf(); + ret = tpm_unseal(locality, sealed_data_size, blob, &data_size, data); + if ( ret != exp_ret ) + return true; + if ( data_size != exp_data_size ) + return true; + if ( memcmp(data, exp_data, data_size) != 0 ) + return true; + + return false; +} + +#define RUN_CASE(caseid) {\ + if ( caseid() )\ + printk("TPM_UNIT_TEST: " #caseid " passed\n");\ + else\ + printk("TPM_UNIT_TEST: " #caseid " failed\n");\ +} + +void tpm_unit_test_before_senter(void) +{ + RUN_CASE(UNIT_PR_V_01 ); /* Pcr16 */ + RUN_CASE(UNIT_PE_V_01 ); /* Pcr16, out != NULL */ + RUN_CASE(UNIT_PR_V_02 ); /* Pcr16 */ + RUN_CASE(UNIT_PS_V_01 ); /* Pcr16 */ + RUN_CASE(UNIT_PE_V_02 ); /* Pcr16, out = NULL */ + RUN_CASE(UNIT_PR_V_09 ); /* Pcr17 */ + RUN_CASE(UNIT_PE_IV_01); /* in = NULL */ + RUN_CASE(UNIT_PE_IV_02); /* locality = 5 */ + RUN_CASE(UNIT_PE_IV_03); /* pcr24 */ + RUN_CASE(UNIT_PE_IV_04); /* locality = 2 */ + RUN_CASE(UNIT_PE_IV_06); /* pcr17 */ + RUN_CASE(UNIT_PR_IV_01); /* locality = 5 */ + RUN_CASE(UNIT_PR_IV_02); /* Pcr24 */ + RUN_CASE(UNIT_PR_IV_03); /* Locality = 2 */ + RUN_CASE(UNIT_PS_IV_01); /* Pcr15 */ + RUN_CASE(UNIT_PS_IV_02); /* Pcr24 */ + RUN_CASE(UNIT_PS_IV_03); /* Locality = 5 */ + RUN_CASE(UNIT_PS_IV_04); /* Pcr20, locality = 0 */ + RUN_CASE(UNIT_NW_V_01 ); /* LCP_OWN, off 0, 29 bytes */ + RUN_CASE(UNIT_NR_V_01 ); /* LCP_OWN, off 0, 29 bytes */ + RUN_CASE(UNIT_NW_V_02 ); /* SELFDEF, off 0, 746 bytes */ + RUN_CASE(UNIT_NW_V_03 ); /* SELFDEF, off 746, 22bytes */ + RUN_CASE(UNIT_NR_V_02 ); /* SELFDEF, off 0, 754 bytes */ + RUN_CASE(UNIT_NR_V_03 ); /* SELFDEF, off 754, 14bytes */ + RUN_CASE(UNIT_NW_IV_01); /* Locality = 5 */ + RUN_CASE(UNIT_NW_IV_02); /* Locality = 2 */ + RUN_CASE(UNIT_NW_IV_03); /* UNDEF */ + RUN_CASE(UNIT_NW_IV_04); /* LCP_OWN, off 29 */ + RUN_CASE(UNIT_NW_IV_05); /* LCP_OWN, off 20, 20bytes */ + RUN_CASE(UNIT_NW_IV_06); /* SELFDEF, off 0, 747bytes */ + RUN_CASE(UNIT_NR_IV_01); /* Locality = 5 */ + RUN_CASE(UNIT_NR_IV_02); /* Locality = 2 */ + RUN_CASE(UNIT_NR_IV_03); /* UNDEF */ + RUN_CASE(UNIT_NR_IV_04); /* LCP_OWN, off 29 */ + RUN_CASE(UNIT_NR_IV_05); /* LCP_OWN, off 20, 20bytes */ + RUN_CASE(UNIT_NR_IV_06); /* SELFDEF, off 0, 755bytes */ +} + +void tpm_unit_test_after_senter(void) +{ + RUN_CASE(UNIT_PS_V_02 ); /* Pcr16 */ + RUN_CASE(UNIT_PR_V_03 ); /* Pcr16 */ + RUN_CASE(UNIT_PE_V_03 ); /* pcr16, out != NULL */ + RUN_CASE(UNIT_PR_V_04 ); /* Pcr16 */ + RUN_CASE(UNIT_PR_V_05 ); /* Pcr17 */ + RUN_CASE(UNIT_PE_V_04 ); /* Pcr17, out != NULL */ + RUN_CASE(UNIT_PR_V_06 ); /* Pcr18 */ + RUN_CASE(UNIT_PE_V_05 ); /* Pcr18, out != NULL */ + RUN_CASE(UNIT_PR_V_07 ); /* Pcr19 */ + RUN_CASE(UNIT_PE_V_06 ); /* Pcr19, out != NULL */ + RUN_CASE(UNIT_PR_V_08 ); /* Pcr20 */ + RUN_CASE(UNIT_PE_V_07 ); /* Pcr20, out != NULL */ + RUN_CASE(UNIT_PS_V_03 ); /* Pcr20 */ + RUN_CASE(UNIT_PE_IV_05); /* locality = 1 */ + RUN_CASE(UNIT_PR_IV_04); /* locality = 1 */ + RUN_CASE(UNIT_PS_IV_05); /* Pcr17, Locality = 2 */ + RUN_CASE(UNIT_NW_V_04); /* LCP_OWN, off 0, 20 bytes */ + RUN_CASE(UNIT_NR_V_04); /* LCP_OWN, off 0, 20 bytes */ + //RUN_CASE(UNIT_OS_V_01 ); /* TPM_ET_SRK */ + //RUN_CASE(UNIT_OI_V_01 ); /* loc = 0 */ + RUN_CASE(UNIT_HMAC_V_01);/* */ + RUN_CASE(test_tpm_wrap_seal);/* */ + RUN_CASE(UNIT_SL_V_05 ); /* loc = 2 */ + RUN_CASE(UNIT_USL_V_04 ); /* loc = 2 */ + RUN_CASE(UNIT_USL_IV_01); /* loc = 2 */ + RUN_CASE(UNIT_SL_V_04 ); /* loc = 2 */ + RUN_CASE(UNIT_USL_V_04 ); /* loc = 2 */ + RUN_CASE(UNIT_SL_V_03 ); /* loc = 2 */ + RUN_CASE(UNIT_USL_V_03 ); /* loc = 2 */ + RUN_CASE(UNIT_SL_V_02 ); /* loc = 2 */ + RUN_CASE(UNIT_USL_V_02 ); /* loc = 2 */ + RUN_CASE(UNIT_SL_V_01 ); /* loc = 0 */ + RUN_CASE(UNIT_USL_V_01 ); /* loc = 0 */ +} + +#endif /* TPM_UNIT_TEST */ + /* * Local variables: * mode: C diff -r 950fec11ef90 tboot/include/tpm.h --- a/tboot/include/tpm.h Sun Jan 15 23:21:20 2012 +0800 +++ b/tboot/include/tpm.h Tue Apr 17 10:13:40 2012 +0800 @@ -272,7 +272,18 @@ extern uint32_t tpm_get_random(uint32_t extern uint32_t tpm_get_random(uint32_t locality, uint8_t *random_data, uint32_t *data_size); +#define TPM_UNIT_TEST 1 + +#ifdef TPM_UNIT_TEST +void tpm_unit_test_before_senter(void); +void tpm_unit_test_after_senter(void); +#else +#define tpm_unit_test_before_senter() +#define tpm_unit_test_after_senter() +#endif /* TPM_UNIT_TEST */ + #endif /* __TPM_H__ */ + /* * Local variables: diff -r 950fec11ef90 tboot/txt/txt.c --- a/tboot/txt/txt.c Sun Jan 15 23:21:20 2012 +0800 +++ b/tboot/txt/txt.c Tue Apr 17 10:13:40 2012 +0800 @@ -741,6 +741,8 @@ void txt_post_launch(void) write_priv_config_reg(TXTCR_ERRORCODE, 0x00000000); write_priv_config_reg(TXTCR_ESTS, 0xffffffff); /* write 1's to clear */ + tpm_unit_test_after_senter(); + /* bring RLPs into environment (do this before restoring MTRRs to ensure */ /* SINIT area is mapped WB for MONITOR-based RLP wakeup) */ txt_wakeup_cpus(); tboot-1.8.0/test-patches/vsprintf-test.patch0000644000000000000000000000411412272416301017250 0ustar 00000000000000--- tboot/common/vsprintf.c 2010-06-22 15:41:16.000000000 -0700 +++ tboot/common/test_vsprintf.c 2010-06-22 15:42:26.000000000 -0700 @@ -33,12 +33,13 @@ * */ -#include +/* unit test code, should test it on i386 arch */ +#include #include #include -#include -#include -#include +#include +#include +#include "../include/div64.h" /* * write the character into the buffer @@ -421,6 +422,58 @@ int snprintf(char *buf, size_t size, con return count; } +void myprintf(const char *fmt, ...) +{ + char buf[256]; + int n; + va_list ap; + int i; + + memset(buf, '\0', sizeof(buf)); + va_start(ap, fmt); + n = vscnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + /* print */ + for ( i = 0; i < n; i++ ) + printf("%c", buf[i]); +} + +int main(void) +{ + int nums[] = {-20000, -1, 0, 200, 0xFFFE, 0xFFFFFFFE}; + int i, j; + + for ( j = 0; j < sizeof(nums); j++ ) { + i = nums[j]; + + printf("%c,%s,%d,%o,%x,%X,%u,%p\n", 'a', "abc", i, i, i, i, i, &i); + myprintf("%c,%s,%d,%o,%x,%X,%u,%p\n", 'a', "abc", i, i, i, i, i, &i); + printf("%-+ 10.4d,%-+ 10.3u\n", i, i); + myprintf("%-+ 10.4d,%-+ 10.3u\n", i, i); + printf("%-+ 10d,%-+ 10u\n", i, i); + myprintf("%-+ 10d,%-+ 10u\n", i, i); + printf("%-+.3d,%-+.3u\n", i, i); + myprintf("%-+.3d,%-+.3u\n", i, i); + printf("%.3-+d,%.3-+u\n", i, i); + myprintf("%.3-+d,%.3-+u\n", i, i); + printf("%d.3-+,%d.3-+u\n", i, i); + myprintf("%d.3-+,%d.3-+u\n", i, i); + printf("%+0d,%+0d\n", -i, i); + myprintf("%+0d,%+0d\n", -i, i); + printf("%#o,%#x,%#X\n", i, i, i); + myprintf("%#o,%#x,%#X\n", i, i, i); + printf("%lld,%Ld,%Lld,%llld\n", i, i, i, i); + myprintf("%lld,%Ld,%Lld,%llld\n", i, i, i, i); + printf("%d,%d\n", i); + myprintf("%d,%d\n", i); + printf("%%%%%%%%%%\n"); + myprintf("%%%%%%%%%%\n"); + } + + return 0; +} + /* * Local variables: * mode: C tboot-1.8.0/txt-test/Kbuild0000644000000000000000000000002312272416301013717 0ustar 00000000000000obj-m = txt-test.o tboot-1.8.0/txt-test/Makefile0000644000000000000000000000144612272416301014234 0ustar 00000000000000# Copyright (c) 2006-2007, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # txt-test makefile # ROOTDIR ?= $(CURDIR)/.. include $(ROOTDIR)/Config.mk LINUX_BASE_DIR = $(ROOTDIR)/../ LINUX_BUILD_DIR = $(LINUX_BASE_DIR)/build-linux-2.6.18-xen_$(TARGET_ARCH) LINUX_SRC_DIR = $(LINUX_BASE_DIR)/linux-2.6.18-xen.hg # uncomment to build test kernel module #MOD_TARGET := txt-test.ko # # universal targets # dist : install build : $(MOD_TARGET) install : build clean : rm -f $(MOD_TARGET) *~ *.o *.mod.* *.symvers distclean : clean # # dependencies # BUILD_DEPS := $(ROOTDIR)/Config.mk $(CURDIR)/Makefile $(MOD_TARGET) : $(BUILD_DEPS) txt-test.c $(MAKE) -C $(LINUX_BUILD_DIR) M=$(CURDIR) modules %.o : %.c $(BUILD_DEPS) $(CC) $(CFLAGS) -DNO_TBOOT_LOGLVL -c $< -o $@ tboot-1.8.0/txt-test/txt-test.c0000644000000000000000000002061512272416301014533 0ustar 00000000000000/* * txt-test: Linux kernel module that will display various information about * the status of TXT. It also indicates whether the various TXT * memory regions are protected from access by the kernel. * * 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include "../include/config.h" #include "../include/uuid.h" #include "../include/tboot.h" #include "../tboot/include/tpm.h" #include "../tboot/include/txt/config_regs.h" /* device name for Intel(r) TXT device we create */ #define DEVICE_NAME "txt" static struct file_operations fops; static int dev_major; #define TBOOT_MEM_BASE (TBOOT_START - 4*PAGE_SIZE) /* 0x8c000 is Xen's start of trampoline code */ #define TBOOT_MEM_SIZE (0x4f000 + 3*PAGE_SIZE) #define TXT_CONFIG_REGS_SIZE (NR_TXT_CONFIG_PAGES*PAGE_SIZE) #define TPM_LOCALITY_SIZE (NR_TPM_LOCALITY_PAGES*PAGE_SIZE) #define TPM_REG_ACCESS 0x00000000 static inline uint64_t read_txt_config_reg(void *config_regs_base, uint32_t reg) { /* these are MMIO so make sure compiler doesn't optimize */ return *(volatile uint64_t *)(config_regs_base + reg); } static inline const char * bit_to_str(uint64_t b) { return b ? "TRUE" : "FALSE"; } static bool test_access_txt_priv_config(void) { void *ptr = NULL; printk("testing for access to TXT private config space...\n"); /* try to get pointer to TXT private config space */ ptr = (void *)ioremap_nocache(TXT_PRIV_CONFIG_REGS_BASE, TXT_CONFIG_REGS_SIZE); if ( ptr == NULL ) printk(KERN_ALERT "ERROR: ioremap_nocache for private space failed\n"); else { printk(KERN_ALERT "ioremap_nocache for private space succeeded\n"); iounmap(ptr); } return (ptr == NULL); #if 0 /* try using hypercall */ { struct xen_domctl domctl = { 0 }; privcmd_hypercall_t hypercall = { 0 }; int ret = -1; domctl.cmd = XEN_DOMCTL_iomem_permission; domctl.domain = DOMID_DOM0; domctl.u.iomem_permission.first_mfn = 0xfed20; domctl.u.iomem_permission.nr_mfns = 0x10; domctl.u.iomem_permission.allow_access = 1; domctl->interface_version = XEN_DOMCTL_INTERFACE_VERSION; hypercall.op = __HYPERVISOR_domctl; hypercall.arg[0] = (unsigned long)domctl; ret = ioctl(xc_handle, IOCTL_PRIVCMD_HYPERCALL, (unsigned long)hypercall); if ( ret < 0 ) printk(KERN_ALERT "\nERROR: failed to set iomem permissions\n"); else { if ((PrivatePtr = (void *)ioremap_nocache(0xFED20000, 0x1000)) == NULL) printk(KERN_ALERT "\nERROR: ioremap_nocache for private space failed\n\n"); else { printk(KERN_ALERT "ioremap_nocache for private space succeeded\n"); iounmap(PrivatePtr); } } } #endif } static bool test_access_tpm_localities(void) { int locality; void *base, *ptr=NULL; int access; printk("testing for access to TPM localities " "(ff = locality unavailable):\n"); for ( locality = 0; locality < TPM_NR_LOCALITIES; locality++ ) { base = (void *)(unsigned long)TPM_LOCALITY_BASE_N(locality); ptr = (void *)ioremap_nocache((unsigned long)base, TPM_LOCALITY_SIZE); if ( ptr == NULL ) { printk(KERN_ALERT "ERROR: ioremap_nocache for TPM locality %d failed\n", locality); return false; } access = readb(ptr + TPM_REG_ACCESS); printk(KERN_ALERT "TPM: Locality %d access = %x\n", locality, access); iounmap(ptr); } return true; } static bool test_access_txt_heap(void) { void *txt_pub, *ptr; uint64_t base, size; printk("testing for access to SINIT and TXT heap memory...\n"); /* get pointer to TXT public config space */ txt_pub = (void *)ioremap_nocache(TXT_PUB_CONFIG_REGS_BASE, TXT_CONFIG_REGS_SIZE); if ( txt_pub == NULL ) { printk(KERN_ALERT "ERROR: ioremap_nocache for public space failed\n"); return false; } /* SINIT */ base = read_txt_config_reg(txt_pub, TXTCR_SINIT_BASE); size = read_txt_config_reg(txt_pub, TXTCR_SINIT_SIZE); ptr = (void *)ioremap_nocache(base, size); if ( ptr == NULL ) { printk(KERN_ALERT "ERROR: ioremap_nocache for SINIT failed\n"); } else { printk(KERN_ALERT "ioremap_nocache for SINIT succeeded\n"); iounmap(txt_pub); iounmap(ptr); return false; } /* TXT heap */ base = read_txt_config_reg(txt_pub, TXTCR_HEAP_BASE); size = read_txt_config_reg(txt_pub, TXTCR_HEAP_SIZE); ptr = (void *)ioremap_nocache(base, size); if ( ptr == NULL ) { printk(KERN_ALERT "ERROR: ioremap_nocache for TXT heap failed\n"); iounmap(txt_pub); return true; } else { printk(KERN_ALERT "ioremap_nocache for TXT heap succeeded\n"); iounmap(txt_pub); iounmap(ptr); return false; } } static bool test_access_tboot(void) { void *ptr; printk("testing for access to tboot memory...\n"); ptr = (void *)ioremap_nocache(TBOOT_MEM_BASE, TBOOT_MEM_SIZE); if ( ptr == NULL ) { printk(KERN_ALERT "ERROR: ioremap_nocache for tboot failed\n"); return true; } else { printk(KERN_ALERT "ioremap_nocache for tboot succeeded\n"); iounmap(ptr); return false; } } static bool is_txt_supported(void) { return true; } static __init int mod_init(void) { if ( !is_txt_supported() ) { printk(KERN_ALERT "Intel(r) TXT is not supported\n"); return 0; } /* make sure no one else has grabbed the public config space */ if ( check_mem_region(TXT_PUB_CONFIG_REGS_BASE, TXT_CONFIG_REGS_SIZE) ) { printk(KERN_ALERT "ERROR: TXT public config space is already reserved\n"); return -EBUSY; } /* register a TXT device (let kernel pick major #) */ dev_major = register_chrdev(0, DEVICE_NAME, &fops); if ( dev_major < 0 ) { printk (KERN_ALERT "ERROR: failed to create TXT device (%d)\n", dev_major); return 0; } /* * begin tests */ test_access_txt_priv_config(); test_access_tpm_localities(); test_access_txt_heap(); test_access_tboot(); unregister_chrdev(dev_major, DEVICE_NAME); return 0; } static __exit void mod_exit(void) { printk("txt-test module unloading\n"); } module_init(mod_init); module_exit(mod_exit); MODULE_LICENSE("BSD"); /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/utils/Makefile0000644000000000000000000000205112272416301013571 0ustar 00000000000000# Copyright (c) 2006-2010, Intel Corporation # All rights reserved. # -*- mode: Makefile; -*- # # utils makefile # ROOTDIR ?= $(CURDIR)/.. include $(ROOTDIR)/Config.mk TARGETS := txt-stat acminfo parse_err CFLAGS += -D_LARGEFILE64_SOURCE # # universal targets # build : $(TARGETS) dist : install install : @set -e; for i in $(TARGETS);\ do \ $(MAKE) DISTDIR=$(DISTDIR) INST_TARGET=$(DISTDIR)/usr/sbin/$$i do_install; \ done .PHONY: do_install do_install : $(INST_TARGET) $(INST_TARGET) : $(notdir $(INST_TARGET)) [ -d $(DISTDIR)/usr/sbin ] || $(INSTALL_DIR) $(DISTDIR)/usr/sbin $(INSTALL_PROG) -t $(DISTDIR)/usr/sbin $^ clean : rm -f $(TARGETS) *~ *.o *.mod.* *.symvers distclean : clean # # dependencies # BUILD_DEPS := $(ROOTDIR)/Config.mk $(CURDIR)/Makefile txt-stat : txt-stat.o $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ acminfo : acminfo.o $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ parse_err : parse_err.o $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ %.o : %.c $(BUILD_DEPS) $(CC) $(CFLAGS) -DNO_TBOOT_LOGLVL -c $< -o $@ tboot-1.8.0/utils/acminfo.c0000644000000000000000000001546212272416301013723 0ustar 00000000000000/* * acminfo.c: Linux app that will display header information for a TXT * Authenticated Code Module (ACM) and match it with the current * system * * Copyright (c) 2006-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 #define printk printf #include "../include/config.h" #include "../include/uuid.h" #include "../include/mle.h" #include "../tboot/include/compiler.h" #include "../tboot/include/processor.h" #include "../tboot/include/misc.h" #include "../tboot/include/txt/acmod.h" #include "../tboot/include/txt/config_regs.h" /* override of fn. that will be called by verify_acmod() */ typedef struct { uint32_t acm_max_size; } getsec_parameters_t; static bool get_parameters(getsec_parameters_t *params) { params->acm_max_size = 0x8000; return true; } static unsigned long long rdmsr(unsigned int msr) { unsigned long long val = 0; /* read MSRs in userspace by reading /dev/cpu/0/msr file */ int fd = open("/dev/cpu/0/msr", O_RDONLY); if ( fd == -1 ) { printf("Error: failed to open /dev/cpu/0/msr\n"); return 0; } /* lseek() to MSR # */ if ( lseek(fd, msr, SEEK_SET) == (off_t)-1 ) printf("Error: failed to find MSR 0x%x\n", msr); else { if ( read(fd, &val, sizeof(val)) != sizeof(val) ) printf("Error: failed to read MSR 0x%x value\n", msr); } close(fd); return val; } #define MSR_IA32_PLATFORM_ID 0x17 static void *pub_config_base; #define read_pub_config_reg(reg) *(volatile uint64_t *)(pub_config_base + \ reg); #define MIN_OS_SINIT_DATA_VER 4 #define MAX_OS_SINIT_DATA_VER 6 #define IS_INCLUDED /* prevent acmod.c #include */ #include "../tboot/txt/acmod.c" static void *load_acm(const char *file_name, size_t *size) { int fd; struct stat sb; void *addr; fd = open(file_name, O_RDONLY); if ( fd == -1 ) { printf("Error: failed to open file %s\n", file_name); return NULL; } if ( fstat(fd, &sb) == -1 ) { printf("Error: failed to get file length\n"); close(fd); return NULL; } addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if ( addr == NULL ) { printf("Error: failed to map file %s of size %lu\n", file_name, sb.st_size); close(fd); return NULL; } if ( size != NULL ) *size = sb.st_size; return addr; } void print_hex(const char* prefix, const void *start, size_t len) { const void *end = start + len; while ( start < end ) { printf("%s", prefix); for ( int i = 0; i < 16; i++ ) { if ( start < end ) printf("%02x ", *(uint8_t *)start); start++; } printf("\n"); } } static bool display_acm(void *acm_addr, size_t size, const char *file_name) { if ( !is_acmod(acm_addr, size, NULL, false) ) return false; acm_hdr_t *hdr = (acm_hdr_t *)acm_addr; print_acm_hdr(hdr, file_name); /* display signature info */ printf("signature information:\n"); printf("\t key size*4: 0x%x (%u)\n", hdr->key_size, hdr->key_size); printf("\t RSA public key:\n"); print_hex("\t ", hdr->rsa2048_pubkey, hdr->key_size*4); printf("\t RSA public key exponent: 0x%08x\n", hdr->pub_exp); printf("\t PKCS #1.5 RSA signature:\n"); print_hex("\t ", hdr->rsa2048_sig, 256); return true; } static bool is_txt_supported(void) { return true; } static bool match_platform(acm_hdr_t *hdr) { if ( !is_txt_supported() ) { printf("Intel(r) TXT is not supported\n"); return false; } int fd_mem = open("/dev/mem", O_RDONLY); if ( fd_mem == -1 ) { printf("ERROR: cannot open /dev/mem\n"); return false; } pub_config_base = mmap(NULL, TXT_CONFIG_REGS_SIZE, PROT_READ, MAP_PRIVATE, fd_mem, TXT_PUB_CONFIG_REGS_BASE); if ( pub_config_base == MAP_FAILED ) { printf("ERROR: cannot map config regs by mmap()\n"); close(fd_mem); return false; } else { if ( does_acmod_match_platform(hdr) ) printf("ACM matches platform\n"); else printf("ACM does not match platform\n"); munmap(pub_config_base, TXT_CONFIG_REGS_SIZE); } close(fd_mem); return true; } int main(int argc, char *argv[]) { void *acm_mem = NULL; char *acm_file; size_t size; bool valid; if ( argc != 2 ) { printf("usage: %s acm_file_name\n", argv[0]); return 1; } acm_file = argv[1]; /* load ACM file into memory */ acm_mem = load_acm(acm_file, &size); if ( acm_mem == NULL ) { printf("Error: failed to read ACM %s\n", acm_file); return 1; } /* display the ACM info */ valid = display_acm(acm_mem, size, acm_file); if ( valid ) match_platform((acm_hdr_t *)acm_mem); /* this allows us to use dump-acm return code to indicate valid ACM */ return valid ? 0 : 1; } /* * Local variables: * mode: C * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/utils/parse_err.c0000644000000000000000000001133512272416301014264 0ustar 00000000000000/* * parse_err.c: Linux app that will parse a TXT.ERRORCODE value * * 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 #include #include #include #define printk printf #include "../tboot/include/txt/config_regs.h" #include "../tboot/include/txt/errorcode.h" static inline uint64_t read_txt_config_reg(void *config_regs_base, uint32_t reg) { /* these are MMIO so make sure compiler doesn't optimize */ return *(volatile uint64_t *)(config_regs_base + reg); } int main(int argc, char *argv[]) { txt_errorcode_t err; if ( argc > 2 ) { printf("usage: %s []\n", argv[0]); return 1; } if ( argc == 2 ) { err._raw = strtoul(argv[1], NULL, 0); if ( errno != 0 ) { printf("Error: TXT.ERRORCODE value is not a valid number\n"); return 1; } } else { int fd_mem = open("/dev/mem", O_RDONLY); if ( fd_mem == -1 ) { printf("ERROR: cannot open /dev/mem\n"); return 1; } void *txt_pub = mmap(NULL, TXT_CONFIG_REGS_SIZE, PROT_READ, MAP_PRIVATE, fd_mem, TXT_PUB_CONFIG_REGS_BASE); if ( txt_pub == MAP_FAILED ) { printf("ERROR: cannot map config regs\n"); close(fd_mem); return 1; } err._raw = read_txt_config_reg(txt_pub, TXTCR_ERRORCODE); munmap(txt_pub, TXT_CONFIG_REGS_SIZE); close(fd_mem); } printf("ERRORCODE: 0x%08jx\n", err._raw); /* AC module error (don't know how to parse other errors) */ if ( err.valid ) { if ( err.external == 0 ) /* processor error */ printk("\t processor error 0x%x\n", (uint32_t)err.type); else { /* external SW error */ txt_errorcode_sw_t sw_err; sw_err._raw = err.type; if ( sw_err.src == 1 ) /* unknown SW error */ printk("unknown SW error 0x%x:0x%x\n", sw_err.err1, sw_err.err2); else { /* ACM error */ acmod_error_t acmod_err; acmod_err._raw = sw_err._raw; printk("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("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("LCP2 error: minor error = 0x%x, index = %u\n", acmod_err.lcp_minor, acmod_err.lcp_index); } } } else printk("no error\n"); return 0; } /* * Local variables: * mode: C * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ tboot-1.8.0/utils/txt-stat.c0000644000000000000000000003303112272416301014067 0ustar 00000000000000/* * txt-stat: Linux app that will display various information about * the status of TXT. * * Copyright (c) 2006-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 #define printk printf #include "../include/config.h" #include "../include/uuid.h" #include "../include/tboot.h" #define IS_INCLUDED /* disable some codes in included files */ static inline uint64_t read_config_reg(uint32_t config_regs_base, uint32_t reg); #include "../tboot/include/txt/config_regs.h" typedef uint8_t mtrr_state_t; typedef uint8_t txt_caps_t; typedef uint8_t multiboot_info_t; void print_hex(const char* prefix, const void *start, size_t len); #include "../include/hash.h" #include "../tboot/include/txt/heap.h" #include "../tboot/txt/heap.c" static inline uint64_t read_txt_config_reg(void *config_regs_base, uint32_t reg) { /* these are MMIO so make sure compiler doesn't optimize */ return *(volatile uint64_t *)(config_regs_base + reg); } static inline const char * bit_to_str(uint64_t b) { return b ? "TRUE" : "FALSE"; } void print_hex(const char* prefix, const void *start, size_t len) { const void *end = start + len; while ( start < end ) { printf("%s", prefix); for ( int i = 0; i < 16; i++ ) { if ( start < end ) printf("%02x ", *(uint8_t *)start); start++; } printf("\n"); } } void print_hash(const tb_hash_t *hash, uint16_t hash_alg) { if ( hash == NULL ) { printk("NULL"); return; } if ( hash_alg == TB_HALG_SHA1 ) print_hex(NULL, (uint8_t *)hash->sha1, sizeof(hash->sha1)); else { printk("unsupported hash alg (%u)\n", hash_alg); return; } } void print_help(const char *usage_str, const char *option_string[]) { uint16_t i = 0; if ( usage_str == NULL || option_string == NULL ) return; printf("\nUsage: %s\n", usage_str); for ( ; option_string[i] != NULL; i++ ) printf("%s", option_string[i]); } static void display_config_regs(void *txt_config_base) { printf("Intel(r) TXT Configuration Registers:\n"); /* STS */ txt_sts_t sts; sts._raw = read_txt_config_reg(txt_config_base, TXTCR_STS); printf("\tSTS: 0x%08jx\n", sts._raw); printf("\t senter_done: %s\n", bit_to_str(sts.senter_done_sts)); printf("\t sexit_done: %s\n", bit_to_str(sts.sexit_done_sts)); printf("\t mem_config_lock: %s\n", bit_to_str(sts.mem_config_lock_sts)); printf("\t private_open: %s\n", bit_to_str(sts.private_open_sts)); printf("\t locality_1_open: %s\n", bit_to_str(sts.locality_1_open_sts)); printf("\t locality_2_open: %s\n", bit_to_str(sts.locality_2_open_sts)); /* ESTS */ txt_ests_t ests; ests._raw = read_txt_config_reg(txt_config_base, TXTCR_ESTS); printf("\tESTS: 0x%02jx\n", ests._raw); printf("\t txt_reset: %s\n", bit_to_str(ests.txt_reset_sts)); /* E2STS */ txt_e2sts_t e2sts; e2sts._raw = read_txt_config_reg(txt_config_base, TXTCR_E2STS); printf("\tE2STS: 0x%016jx\n", e2sts._raw); printf("\t secrets: %s\n", bit_to_str(e2sts.secrets_sts)); /* ERRORCODE */ printf("\tERRORCODE: 0x%08jx\n", read_txt_config_reg(txt_config_base, TXTCR_ERRORCODE)); /* DIDVID */ txt_didvid_t didvid; didvid._raw = read_txt_config_reg(txt_config_base, TXTCR_DIDVID); printf("\tDIDVID: 0x%016jx\n", didvid._raw); printf("\t vendor_id: 0x%x\n", didvid.vendor_id); printf("\t device_id: 0x%x\n", didvid.device_id); printf("\t revision_id: 0x%x\n", didvid.revision_id); /* FSBIF */ uint64_t fsbif; fsbif = read_txt_config_reg(txt_config_base, TXTCR_VER_FSBIF); printf("\tFSBIF: 0x%016jx\n", fsbif); /* QPIIF */ uint64_t qpiif; qpiif = read_txt_config_reg(txt_config_base, TXTCR_VER_QPIIF); printf("\tQPIIF: 0x%016jx\n", qpiif); /* SINIT.BASE/SIZE */ printf("\tSINIT.BASE: 0x%08jx\n", read_txt_config_reg(txt_config_base, TXTCR_SINIT_BASE)); printf("\tSINIT.SIZE: %juB (0x%jx)\n", read_txt_config_reg(txt_config_base, TXTCR_SINIT_SIZE), read_txt_config_reg(txt_config_base, TXTCR_SINIT_SIZE)); /* HEAP.BASE/SIZE */ printf("\tHEAP.BASE: 0x%08jx\n", read_txt_config_reg(txt_config_base, TXTCR_HEAP_BASE)); printf("\tHEAP.SIZE: %juB (0x%jx)\n", read_txt_config_reg(txt_config_base, TXTCR_HEAP_SIZE), read_txt_config_reg(txt_config_base, TXTCR_HEAP_SIZE)); /* DPR.BASE/SIZE */ txt_dpr_t dpr; dpr._raw = read_txt_config_reg(txt_config_base, TXTCR_DPR); printf("\tDPR: 0x%016jx\n", dpr._raw); printf("\t lock: %s\n", bit_to_str(dpr.lock)); printf("\t top: 0x%08x\n", dpr.top << 20); printf("\t size: %uMB (%uB)\n", dpr.size, dpr.size*1024*1024); /* PUBLIC.KEY */ uint8_t key[256/8]; unsigned int i = 0; do { *(uint64_t *)&key[i] = read_txt_config_reg(txt_config_base, TXTCR_PUBLIC_KEY + i); i += sizeof(uint64_t); } while ( i < sizeof(key) ); printf("\tPUBLIC.KEY:\n"); print_hex("\t ", key, sizeof(key)); printf("\n"); /* easy-to-see status of TXT and secrets */ printf("***********************************************************\n"); printf("\t TXT measured launch: %s\n", bit_to_str(sts.senter_done_sts)); printf("\t secrets flag set: %s\n", bit_to_str(e2sts.secrets_sts)); printf("***********************************************************\n"); } static void display_heap(txt_heap_t *heap) { verify_bios_data(heap); } static void display_tboot_log(void *log_base) { static char buf[512]; tboot_log_t *log = (tboot_log_t *)log_base; if ( !are_uuids_equal(&(log->uuid), &((uuid_t)TBOOT_LOG_UUID)) ) { printf("unable to find TBOOT log\n"); return; } printf("TBOOT log:\n"); printf("\t max_size=%x\n", log->max_size); printf("\t curr_pos=%x\n", log->curr_pos); printf("\t buf:\n"); /* log->buf is phys addr of buf, which will not match where mmap has */ /* map'ed us, but since it is always just past end of struct, use that */ char *log_buf = log->buf; /* log is too big for single printk(), so break it up */ for ( unsigned int curr_pos = 0; curr_pos < log->curr_pos; curr_pos += sizeof(buf)-1 ) { strncpy(buf, log_buf + curr_pos, sizeof(buf)-1); buf[sizeof(buf)-1] = '\0'; printf("%s", buf); } printf("\n"); } static bool is_txt_supported(void) { return true; } static int fd_mem; static void *buf_config_regs_read; static void *buf_config_regs_mmap; static inline uint64_t read_config_reg(uint32_t config_regs_base, uint32_t reg) { uint64_t reg_val; void *buf; (void)config_regs_base; buf = buf_config_regs_read; if ( buf == NULL ) buf = buf_config_regs_mmap; if ( buf == NULL ) return 0; reg_val = read_txt_config_reg(buf, reg); return reg_val; } bool display_heap_optin = false; static const char *short_option = "h"; static struct option longopts[] = { {"heap", 0, 0, 'p'}, {"help", 0, 0, 'h'}, {0, 0, 0, 0} }; static const char *usage_string = "txt-stat [--heap] [-h]"; static const char *option_strings[] = { "--heap:\t\tprint out heap info.\n", "-h, --help:\tprint out this help message.\n", NULL }; int main(int argc, char *argv[]) { uint64_t heap = 0; uint64_t heap_size = 0; void *buf = NULL; off_t seek_ret = -1; size_t read_ret = 0; int c; while ( (c = getopt_long(argc, (char **const)argv, short_option, longopts, NULL)) != -1 ) switch ( c ) { case 'h': print_help(usage_string, option_strings); return 0; case 'p': display_heap_optin = true; break; default: return 1; } if ( !is_txt_supported() ) { printf("Intel(r) TXT is not supported\n"); return 1; } fd_mem = open("/dev/mem", O_RDONLY); if ( fd_mem == -1 ) { printf("ERROR: cannot open /dev/mem\n"); return 1; } /* * display public config regs */ seek_ret = lseek(fd_mem, TXT_PUB_CONFIG_REGS_BASE, SEEK_SET); if ( seek_ret == -1 ) printf("ERROR: seeking public config registers failed: %s, try mmap\n", strerror(errno)); else { buf = malloc(TXT_CONFIG_REGS_SIZE); if ( buf == NULL ) printf("ERROR: out of memory, try mmap\n"); else { read_ret = read(fd_mem, buf, TXT_CONFIG_REGS_SIZE); if ( read_ret != TXT_CONFIG_REGS_SIZE ) { printf("ERROR: reading public config registers failed: %s," "try mmap\n", strerror(errno)); free(buf); buf = NULL; } else buf_config_regs_read = buf; } } /* * try mmap to display public config regs, * since public config regs should be displayed always. */ if ( buf == NULL ) { buf = mmap(NULL, TXT_CONFIG_REGS_SIZE, PROT_READ, MAP_PRIVATE, fd_mem, TXT_PUB_CONFIG_REGS_BASE); if ( buf == MAP_FAILED ) { printf("ERROR: cannot map config regs by mmap()\n"); buf = NULL; } else buf_config_regs_mmap = buf; } if ( buf ) { display_config_regs(buf); heap = read_txt_config_reg(buf, TXTCR_HEAP_BASE); heap_size = read_txt_config_reg(buf, TXTCR_HEAP_SIZE); } /* * display heap */ if ( heap && heap_size && display_heap_optin ) { seek_ret = lseek(fd_mem, heap, SEEK_SET); if ( seek_ret == -1 ) { printf("ERROR: seeking TXT heap failed by lseek(): %s, try mmap\n", strerror(errno)); goto try_mmap_heap; } buf = malloc(heap_size); if ( buf == NULL ) { printf("ERROR: out of memory, try mmap\n"); goto try_mmap_heap; } read_ret = read(fd_mem, buf, heap_size); if ( read_ret != heap_size ) { printf("ERROR: reading TXT heap failed by read(): %s, try mmap\n", strerror(errno)); free(buf); goto try_mmap_heap; } display_heap((txt_heap_t *)buf); free(buf); goto try_display_log; try_mmap_heap: buf = mmap(NULL, heap_size, PROT_READ, MAP_PRIVATE, fd_mem, heap); if ( buf == MAP_FAILED ) printf("ERROR: cannot map TXT heap by mmap()\n"); else { display_heap((txt_heap_t *)buf); munmap(buf, heap_size); } } try_display_log: if ( buf_config_regs_read ) free(buf_config_regs_read); if ( buf_config_regs_mmap ) munmap(buf_config_regs_mmap, TXT_CONFIG_REGS_SIZE); /* * display serial log from tboot memory (if exists) */ seek_ret = lseek(fd_mem, TBOOT_SERIAL_LOG_ADDR, SEEK_SET); if ( seek_ret == -1 ) { printf("ERROR: seeking TBOOT log failed by lseek()\n"); close(fd_mem); return 1; } buf = malloc(TBOOT_SERIAL_LOG_SIZE); if ( buf == NULL ) { printf("ERROR: out of memory\n"); close(fd_mem); return 1; } read_ret = read(fd_mem, buf, TBOOT_SERIAL_LOG_SIZE); if ( read_ret != TBOOT_SERIAL_LOG_SIZE ) { printf("ERROR: reading TBOOT log failed by read()\n"); free(buf); close(fd_mem); return 1; } display_tboot_log(buf); free(buf); close(fd_mem); return 0; } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */