# HG changeset patch # User Joseph Cihula # Date 1188343670 25200 # Node ID 5648dc802679e6f298b9d4f7feb5c294c75b4bc9 # Parent de942f6fa6b318009d10a3d3fc86fdd70f45bd75 Intel(R) Trusted Execution Technology (Intel(R) TXT) support for Xen sboot files. Signed-off-by: Joseph Cihula Signed-off-by: Jimmy Wei Signed-off-by: Shane Wang Signed-off-by: Zhai Edwin diff -r de942f6fa6b3 -r 5648dc802679 sboot/COPYING --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/COPYING Tue Aug 28 16:27:50 2007 -0700 @@ -0,0 +1,3 @@ +Files which do not contain any copyright information are assumed to conform +to the license and copyright information in the ../xen/COPYING file. Those +containing license and/or copyright information are as specified. diff -r de942f6fa6b3 -r 5648dc802679 sboot/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/Makefile Tue Aug 28 16:27:50 2007 -0700 @@ -0,0 +1,95 @@ +export BASEDIR := $(CURDIR) + +.PHONY: default +default: build + +.PHONY: dist +dist: install + +.PHONY: build install clean distclean cscope TAGS tags +build install debug clean distclean cscope TAGS tags:: + $(MAKE) -f Rules.mk _$@ + +.PHONY: _build +_build: $(TARGET).gz + $(MAKE) -C tools build + +.PHONY: _install +_install: $(TARGET).gz + [ -d $(DESTDIR)/boot ] || $(INSTALL_DIR) $(DESTDIR)/boot + $(INSTALL_DATA) $(TARGET).gz $(DESTDIR)/boot/$(notdir $(TARGET)).gz + $(INSTALL_DATA) $(TARGET)-syms $(DESTDIR)/boot/$(notdir $(TARGET))-syms + $(MAKE) -C tools install + +.PHONY: _debug +_debug: + objdump -D -S $(TARGET)-syms > $(TARGET).s + +.PHONY: _clean +_clean: + $(MAKE) -f $(BASEDIR)/Rules.mk -C common clean + $(MAKE) -f $(BASEDIR)/Rules.mk -C txt clean + $(MAKE) -C tools clean + rm -f $(TARGET)* *~ core + +.PHONY: _distclean +_distclean: clean + rm -f tags TAGS cscope.files cscope.in.out cscope.out cscope.po.out + +$(TARGET).gz: $(TARGET) + gzip -f -9 < $< > $@.new + mv $@.new $@ + +$(TARGET): dummy + [ -e include/asm ] || mkdir include/asm + [ -e include/asm/types.h ] || \ + ln -sf $(BASEDIR)/include/types.h $(BASEDIR)/include/asm/types.h + $(MAKE) -f $(BASEDIR)/Rules.mk -C common $(TARGET) + +dummy: + +SUBDIRS = common txt +define all_sources + ( find $(SUBDIRS) -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,EXPORT_SYMBOL_GPL \ + --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 + +.PHONY: _cscope +_cscope: + $(all_sources) > cscope.files + cscope -k -b -q + +.PHONY: MAP +MAP: + $(NM) -n $(TARGET)-syms | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' > System.map +.PHONY: _MAP + +.PHONY: FORCE +FORCE: + +%.o %.i: %.c FORCE + $(MAKE) -f $(BASEDIR)/Rules.mk -C $(*D) $(@F) + +%.o %.s: %.S FORCE + $(MAKE) -f $(BASEDIR)/Rules.mk -C $(*D) $(@F) + +%/: FORCE + $(MAKE) -f $(BASEDIR)/Rules.mk -C $* built_in.o diff -r de942f6fa6b3 -r 5648dc802679 sboot/Rules.mk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/Rules.mk Tue Aug 28 16:27:50 2007 -0700 @@ -0,0 +1,103 @@ +# +# If you change any of these configuration options then you must +# 'make clean' before rebuilding. +# +verbose ?= n + +XEN_ROOT=$(BASEDIR)/.. + +# to use our include hierarchy +EXTRA_PREFIX := $(XEN_ROOT)/sboot + +include $(XEN_ROOT)/Config.mk + +# Hardcoded configuration implications and dependencies. +# Do this is a neater way if it becomes unwieldy. +ifeq ($(debug),y) +verbose := y +endif + +TARGET := $(BASEDIR)/sboot + +HDRS := $(wildcard $(BASEDIR)/include/*.h) +HDRS += $(wildcard $(BASEDIR)/include/txt/*.h) + +# Note that link order matters! +ALL_OBJS-y += $(BASEDIR)/common/built_in.o +ALL_OBJS-y += $(BASEDIR)/txt/built_in.o +ALL_OBJS := $(ALL_OBJS-y) + + +CFLAGS := $(shell echo $(CFLAGS) | sed -e s/-m64/-m32/) +LDFLAGS_DIRECT := -melf_i386 + +CFLAGS-y += -g -Werror +CFLAGS-$(verbose) += -DVERBOSE +CFLAGS-y += -nostdinc +CFLAGS-y += -fno-builtin -fno-common -fno-strict-aliasing +CFLAGS-y += -pipe +CFLAGS-y += -iwithprefix include -I$(BASEDIR)/include +# Prevent floating-point variables from creeping into Xen. +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,) +CFLAGS += -DBUILD_ARCH_$(XEN_COMPILE_ARCH) + +CFLAGS := $(strip $(CFLAGS) $(CFLAGS-y)) + +AFLAGS-y += -D__ASSEMBLY__ + +# Most CFLAGS are safe for assembly files: +# -std=gnu{89,99} gets confused by #-prefixed end-of-line comments +AFLAGS := $(strip $(AFLAGS) $(AFLAGS-y)) +AFLAGS += $(patsubst -std=gnu%,,$(CFLAGS)) + +# LDFLAGS are only passed directly to $(LD) +LDFLAGS := $(strip $(LDFLAGS) $(LDFLAGS_DIRECT)) + +include Makefile + +# Ensure each subdirectory has exactly one trailing slash. +subdir-n := $(patsubst %,%/,$(patsubst %/,%,$(subdir-n))) +subdir-y := $(patsubst %,%/,$(patsubst %/,%,$(subdir-y))) + +# Add explicitly declared subdirectories to the object list. +obj-y += $(patsubst %/,%/built_in.o,$(subdir-y)) + +# Add implicitly declared subdirectories (in the object list) to the +# subdirectory list, and rewrite the object-list entry. +subdir-y += $(filter %/,$(obj-y)) +obj-y := $(patsubst %/,%/built-in.o,$(obj-y)) + +subdir-all := $(subdir-y) $(subdir-n) + +built_in.o: $(obj-y) + $(LD) $(LDFLAGS) -r -o $@ $^ + +# Force execution of pattern rules (for which PHONY cannot be directly used). +.PHONY: FORCE +FORCE: + +%/built_in.o: FORCE + $(MAKE) -f $(BASEDIR)/Rules.mk -C $* built_in.o + +.PHONY: clean +clean:: $(addprefix _clean_, $(subdir-all)) + rm -f *.o *~ core +_clean_%/: FORCE + $(MAKE) -f $(BASEDIR)/Rules.mk -C $* clean + +%.o: %.c $(HDRS) Makefile + $(CC) $(CFLAGS) -c $< -o $@ + +%.o: %.S $(HDRS) Makefile + $(CC) $(AFLAGS) -c $< -o $@ + +%.i: %.c $(HDRS) Makefile + $(CPP) $(CFLAGS) $< -o $@ + +# -std=gnu{89,99} gets confused by # as an end-of-line comment marker +%.s: %.S $(HDRS) Makefile + $(CPP) $(AFLAGS) $< -o $@ diff -r de942f6fa6b3 -r 5648dc802679 sboot/common/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/common/Makefile Tue Aug 28 16:27:50 2007 -0700 @@ -0,0 +1,38 @@ +obj-y += boot.o +obj-y += sboot.o +obj-y += string.o +obj-y += tpm.o +obj-y += lib.o +obj-y += vsprintf.o +obj-y += early_printk.o +obj-y += elf.o +obj-y += e820.o +obj-y += acpi.o + +SYMBOLS = $(BASEDIR)/../xen/tools/symbols +MKELF = $(BASEDIR)/../xen/arch/x86/boot/mkelf32 + +$(TARGET): $(TARGET)-syms $(MKELF) + $(MKELF) $(TARGET)-syms $(TARGET) 0x100000 \ + `$(NM) -nr $(TARGET)-syms | head -n 1 | sed -e 's/^\([^ ]*\).*/0x\1/'` + +$(TARGET)-syms: $(ALL_OBJS) sboot.lds + $(MAKE) -f $(BASEDIR)/Rules.mk $(BASEDIR)/common/symbols-dummy.o + $(LD) $(LDFLAGS) -T sboot.lds -N $(ALL_OBJS) \ + $(BASEDIR)/common/symbols-dummy.o -o $(@D)/.$(@F).0 + $(NM) -n $(@D)/.$(@F).0 | $(SYMBOLS) >$(@D)/.$(@F).0.S + $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).0.o + $(LD) $(LDFLAGS) -T sboot.lds -N $(ALL_OBJS) \ + $(@D)/.$(@F).0.o -o $(@D)/.$(@F).1 + $(NM) -n $(@D)/.$(@F).1 | $(SYMBOLS) >$(@D)/.$(@F).1.S + $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).1.o + $(LD) $(LDFLAGS) -T sboot.lds -N $(ALL_OBJS) $(@D)/.$(@F).1.o -o $@ + rm -f $(@D)/.$(@F).[0-9]* + +sboot.lds: sboot.lds.S $(HDRS) + $(CC) -P -E -Ui386 $(AFLAGS) -o $@ $< + +.PHONY: clean +clean:: + rm -f sboot.lds + rm -f $(BASEDIR)/.sboot-syms.[0-9]* diff -r de942f6fa6b3 -r 5648dc802679 sboot/common/acpi.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/common/acpi.c Tue Aug 28 16:27:50 2007 -0700 @@ -0,0 +1,244 @@ +/* + * from xen/arch/x86/acpi/boot.c + * drivers/acpi/tables.c + * + * Copyright(c) 2007 Intel Corporation. All rights reserved. + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * Copyright (C) 2001 Jun Nakajima + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include + +#define ACPI_DMAR_TABLE_SIG "DMAR" +#define ACPI_MCFG_TABLE_SIG "MCFG" +#define ACPI_RSDP_TABLE_SIG "RSD PTR " +#define ACPI_XSDT_TABLE_SIG "XSDT" +#define ACPI_RSDT_TABLE_SIG "RSDT" +#define ACPI_MADT_TABLE_SIG "APIC" + + +static unsigned long acpi_scan_rsdp(unsigned long start, unsigned long length) +{ + unsigned long sig_len = sizeof(ACPI_RSDP_TABLE_SIG) - 1; + + /* + * Scan all 16-byte boundaries of the physical memory region for the + * RSDP signature. + */ + for ( ; length > 0; length -= 16, start += 16 ) { + if ( memcmp((void *)start, ACPI_RSDP_TABLE_SIG, sig_len) ) + continue; + return start; + } + + return 0; +} + +static unsigned long acpi_find_rsdp(void) +{ + unsigned long rsdp_phys = 0; + + /* + * Scan memory looking for the RSDP signature. First search EBDA (low + * memory) paragraphs and then search upper memory (E0000-FFFFF). + */ + rsdp_phys = acpi_scan_rsdp(0, 0x400); + if ( !rsdp_phys ) + rsdp_phys = acpi_scan_rsdp(0xE0000, 0x20000); + + return rsdp_phys; +} + +static int acpi_table_compute_checksum(const u8 *table_pointer, + unsigned long length) +{ + unsigned long sum = 0; + + if ( !table_pointer || !length ) + return -1; + + while ( length-- ) + sum += *table_pointer++; + + return (sum & 0xFF); +} + +static unsigned long acpi_get_table(const acpi_table_rsdp_t *rsdp, + const char* sig) +{ + acpi_table_header_t *header = NULL; + unsigned int i, sdt_count = 0; + + if ( !rsdp || !sig ) + return 0; + + /* First check XSDT (but only on ACPI 2.0-compatible systems) */ + if ( (rsdp->revision >= 2) && + (((acpi20_table_rsdp_t *)rsdp)->xsdt_address) ) { + acpi_table_xsdt_t *xsdt = NULL; + xsdt = (acpi_table_xsdt_t *)(uint32_t) + (((acpi20_table_rsdp_t *)rsdp)->xsdt_address); + header = &xsdt->header; + + if ( memcmp(header->signature, ACPI_XSDT_TABLE_SIG, 4) ) { + printk("XSDT signature incorrect\n"); + return 0; + } + + if ( acpi_table_compute_checksum((u8 *)header, header->length) ) { + printk("Invalid XSDT checksum\n"); + return 0; + } + printk("Seek in XSDT...\n"); + sdt_count = + (header->length - sizeof(acpi_table_header_t)) >> 3; + + for ( i = 0; i < sdt_count; i++ ) { + header = (acpi_table_header_t *)(uint32_t)xsdt->entry[i]; + printk("entry[%d] sig = %c%c%c%c\n", i, + header->signature[0], header->signature[1], + header->signature[2], header->signature[3]); + if ( !memcmp(sig, &header->signature, + strnlen(sig, sizeof(header->signature))) ) + return (unsigned long)header; + } + } + /* Then check RSDT */ + if ( rsdp->rsdt_address ) { + acpi_table_rsdt_t *rsdt = NULL; + rsdt = (acpi_table_rsdt_t *)rsdp->rsdt_address; + header = &rsdt->header; + + if ( memcmp(header->signature, ACPI_RSDT_TABLE_SIG, 4) ) { + printk("RSDT signature incorrect\n"); + return 0; + } + + if ( acpi_table_compute_checksum((u8 *)header, header->length) ) { + printk("Invalid RSDT checksum\n"); + return 0; + } + printk("Seek in RSDT...\n"); + sdt_count = + (header->length - sizeof(acpi_table_header_t)) >> 2; + + for ( i = 0; i < sdt_count; i++ ) { + header = (acpi_table_header_t *)rsdt->entry[i]; + printk("entry[%d] sig = %c%c%c%c\n", i, + header->signature[0], header->signature[1], + header->signature[2], header->signature[3]); + if ( !memcmp(sig, (char *)&header->signature, + strnlen(sig, sizeof(header->signature))) ) + return (unsigned long)header; + } + } + printk("Not find required table entry.\n"); + return 0; +} + +static uint32_t get_acpi_table(const char* sig) +{ + acpi_table_rsdp_t *rsdp = NULL; + int result = 0; + + /* Locate the Root System Description Table (RSDP) */ + + rsdp = (acpi_table_rsdp_t *)acpi_find_rsdp(); + if ( !rsdp ) { + printk("Unable to locate RSDP\n"); + return 0; + } + + printk("RSDP (v%3.3d %6.6s) @ 0x%p\n", + rsdp->revision, rsdp->oem_id, (void *)rsdp); + + if ( rsdp->revision < 2 ) + result = + acpi_table_compute_checksum((u8 *)rsdp, + sizeof(acpi_table_rsdp_t)); + else + result = + acpi_table_compute_checksum((u8 *)rsdp, + ((acpi20_table_rsdp_t *) + rsdp)->length); + + if ( result ) { + printk("ERROR: Invalid checksum for RSDP\n"); + return 0; + } + + /* Locate and map the System Description table (RSDT/XSDT) */ + + return acpi_get_table(rsdp, sig); +} + +static uint32_t get_acpi_table_entry(uint32_t start, uint32_t size, int type) +{ + acpi_table_entry_header_t *header = NULL; + + if ( start == 0 || size == 0 ) + return 0; + + while ( size > sizeof(acpi_table_entry_header_t) ) { + header = (acpi_table_entry_header_t *)start; + if ( header->length > size ) + break; + + if ( header->type == type ) + return start; + + size -= header->length; + start += header->length; + } + + return 0; +} + +uint32_t get_acpi_dmar_table(void) +{ + return get_acpi_table(ACPI_DMAR_TABLE_SIG); +} + +uint32_t get_acpi_mcfg_table(void) +{ + return get_acpi_table(ACPI_MCFG_TABLE_SIG); +} + +uint32_t get_acpi_ioapic_table(void) +{ + acpi_table_madt_t *madt; + madt = (acpi_table_madt_t *)get_acpi_table(ACPI_MADT_TABLE_SIG); + + if ( madt == 0 ) { + printk("Unable to locate madt table\n"); + return 0; + } + + return get_acpi_table_entry( + (uint32_t)madt + sizeof(acpi_table_madt_t), + madt->header.length - sizeof(acpi_table_madt_t), + ACPI_MADT_IOAPIC); +} diff -r de942f6fa6b3 -r 5648dc802679 sboot/common/boot.S --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/common/boot.S Tue Aug 28 16:27:50 2007 -0700 @@ -0,0 +1,379 @@ +/* + * boot.S: assembly bootstrapping code for sboot module + * + * 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 + +#define BSP_STACK_SIZE 4096 +#define AP_STACK_SIZE 128 +#define NR_IDT_ENTRIES 32 + +#define cs_sel 1<<3 +#define ds_sel 2<<3 +#define cs16_sel 4<<3 + + .text + +ENTRY(start) +ENTRY(_start) +ENTRY(_stext) + jmp __copy_self + + .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) + + +__copy_self: + /* copy ourselves to lower memory first */ + mov $_stext,%ecx + mov $0x100000,%edi +1: mov (%edi),%eax + mov %eax,(%ecx) + add $0x04,%ecx + add $0x04,%edi + cmp $_end,%ecx + jle 1b + lea __start,%eax + jmp *%eax + +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 + +#if 0 + /* Initialize BSS (no nasty surprises!) */ + mov $__bss_start,%edi + mov $_end,%ecx + sub %edi,%ecx + xor %eax,%eax + rep stosb +#endif + + /* pass multiboot info struct and call measured launch code */ + push %ebx + call begin_launch + +/* + * vmexit handler + */ +ENTRY(vmx_asm_vmexit_handler) + call vmx_vmexit_handler + +ENTRY(_mini_guest) +1: hlt + jmp 1b + +compat_mode_entry: + /* Disable paging and therefore leave 64 bit mode. */ + movl %cr0, %eax + andl $~X86_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 */ + +ENTRY(shutdown_entry32) + /* restore sboot context */ + cli + lgdt %cs:gdt_descr + mov $(ds_sel),%ecx + mov %ecx,%ds + mov %ecx,%es + mov %ecx,%fs + mov %ecx,%gs + mov %ecx,%ss + +#if 0 +/* set the tr? */ + mov $0x18, %eax + ltr %ax +#endif + + ljmp $(cs_sel),$(1f) +1: leal bsp_stack,%esp + + /* Reset EFLAGS (subsumes CLI and CLD). */ + pushl $0x0 + popf + + /* disable paging */ + mov %cr0, %eax + and $~X86_CR0_PG, %eax + mov %eax, %cr0 + jmp 1f + +1: /* restore cr4 */ + mov $0x4000, %eax + mov %eax, %cr4 + + /* true shutdown work for sboot */ + call txt_shutdown + ud2 + +/* + * 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) + # this really needs to use cpuid offset from ap_stacks to allow simult +1: leal ap_stacks,%esp + + # get initial APIC ID for this processor + mov $0x01,%eax + xor %ebx,%ebx + cpuid + shr $24,%ebx + and $0xff,%ebx + + push %ebx + call txt_cpu_wakeup + + +/* + * entry point for switch to real mode and jump + * entry point in %ebx + */ +ENTRY(_prot_to_real) + cli + mov %ebx, %eax + and $0xffff0, %eax + shr $4, %eax + mov %ax, _real_mode_entry_point + 4 + and $0xf, %ebx + mov %ebx, _real_mode_entry_point +# lidt real_idt_desc + xor %eax, %eax + ljmp $(cs16_sel), $(1f) +1: mov %eax, %cr0 + .byte 0x66 + .byte 0x67 + ljmp *_real_mode_entry_point + + +/* + * 64b entry point + */ +ENTRY(shutdown_entry64) +#ifdef BUILD_ARCH_x86_64 + .code64 + cli + 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 +#endif + +/* + * interrupt handler + */ + +int_handler: + iret + + + +/* + * descriptors and descriptor tables + */ + + .align 8 + +/* GDT */ +gdt_descr: + .word gdt_table_end - gdt_table - 1 + .long gdt_table + .word 0 + + .align PAGE_SIZE, 0 + +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 TBD: need set D/B? */ +cs16_desc: /* cs16 */ + .word 0xffff /* limit = 4GB */ + .word 0x00 /* base = 0 */ + .word 0x9b00 /* read + exec + accessed */ + .word 0x008f /* granularity = 4096, D = 0 */ + /* end (unused) */ + .quad 0x0000000000000000 +gdt_table_end: + + +#if 0 +/* IDT */ +idt_descr: + .word idt_table_end - idt_table - 1 + .long idt_table + .word 0 + +idt_table: + .rept NR_IDT_ENTRIES + .word int_handler + .word cs_sel + .word 0x8e00 /* present, DPL=0, 32b, interrupt */ + .word 0x00 + .endr +idt_table_end: +#endif + + +/* + * 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 +ENTRY(ap_vmcs) + .fill 1*PAGE_SIZE,1,0 +ENTRY(vmcs_end) + + +/* + * misc. bss data + */ +.section ".bss" +_real_mode_entry_point: + .long 0 + .word 0 + + +/* + * shared data page with kernel (i.e. Xen) + * this needs to be kept in sync with mle_kernel_shared_t in sboot.h + * (put at end so that not split e820 region for sboot) + */ +.section ".mle_kernel_shared","w" + .align PAGE_SIZE, 0 + +ENTRY(_mle_kernel_shared) + mks_uuid: .fill 20,1,0 + mks_version: .long 0 + mks_log_addr: .long 0 + mks_shutdown_entry32: .long 0 + mks_shutdown_entry64: .long 0 + mks_shutdown_type: .long 0 + .align PAGE_SIZE, 0 + +ENTRY(_end) diff -r de942f6fa6b3 -r 5648dc802679 sboot/common/e820.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/common/e820.c Tue Aug 28 16:27:50 2007 -0700 @@ -0,0 +1,610 @@ +/* + * e820.c: support functions for manipulating the e820 table + * + * 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 + +/* + * copy of bootloader/BIOS e820 table with adjusted entries + * this version will replace original in mbi + */ +#define MAX_E820_ENTRIES 128 +static int g_nr_map; +static memory_map_t g_copy_e820_map[MAX_E820_ENTRIES]; + +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; +} + +/* + * 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) +{ + int i; + + for ( i = 0; i < nr_map; i++ ) { + memory_map_t *entry = &e820[i]; + uint64_t base_addr, length; + + base_addr = combine64b(entry->base_addr_low, entry->base_addr_high); + length = combine64b(entry->length_low, entry->length_high); + + printk("\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, int *nr_map, int pos, + uint64_t addr, uint64_t size, + uint32_t type) +{ + int i; + + /* no more room */ + if ( *nr_map + 1 > MAX_E820_ENTRIES ) + return false; + + /* shift (copy) everything up one entry */ + for (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, int *nr_map, int pos) +{ + int i; + + /* shift (copy) everything down one entry */ + for (i = pos; i < *nr_map - 1; i++) + e820map[i] = e820map[i+1]; + + (*nr_map)--; +} + +static bool protect_region(memory_map_t *e820map, int *nr_map, + uint64_t new_addr, uint64_t new_size, + uint32_t new_type) +{ + int i; + uint64_t addr, tmp_addr, size, tmp_size; + uint32_t type; + + if ( new_size == 0 ) + return true; + + /* find where our region belongs in the table and insert it */ + for (i = 0; i < *nr_map; i++) { + addr = combine64b(e820map[i].base_addr_low, e820map[i].base_addr_high); + size = combine64b(e820map[i].length_low, e820map[i].length_high); + 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 = combine64b(e820map[i].base_addr_low, + e820map[i].base_addr_high); + 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 = combine64b(e820map[i].base_addr_low, e820map[i].base_addr_high); + tmp_size = combine64b(e820map[i].length_low, e820map[i].length_high); + + /* 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 = combine64b(e820map[i].base_addr_low, + e820map[i].base_addr_high); + tmp_size = combine64b(e820map[i].length_low, e820map[i].length_high); + } + + /* finally, if our region partially overlaps an existing region, */ + /* then truncate the existing region */ + if ( i < *nr_map ) { + tmp_addr = combine64b(e820map[i].base_addr_low, + e820map[i].base_addr_high); + tmp_size = combine64b(e820map[i].length_low, e820map[i].length_high); + 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; +} + +/* + * 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(multiboot_info_t *mbi) +{ + uint32_t entry_offset; + + if ( mbi->flags & MBI_MEMMAP ) { + uint64_t previous_base, previous_length, current_base; + printk("original e820 map:\n"); + print_map((memory_map_t *)mbi->mmap_addr, + mbi->mmap_length/sizeof(memory_map_t)); + + g_nr_map = 0; + entry_offset = 0; + + previous_base = 0; + previous_length = 0; + + while ( entry_offset < mbi->mmap_length && + g_nr_map < MAX_E820_ENTRIES ) { + memory_map_t *entry, *new_entry; + + entry = (memory_map_t *)(mbi->mmap_addr + entry_offset); + new_entry = &g_copy_e820_map[g_nr_map]; + + /* make exact copy except fix size to size of entry struct */ + /* (Xen ignores any extra data above this anyway) */ + *new_entry = *entry; + new_entry->size = sizeof(*new_entry) - sizeof(new_entry->size); + + /* get base address of current entry */ + current_base = combine64b(new_entry->base_addr_low, + new_entry->base_addr_high); + + /* check g_copy_e820_map is ordered and not overlapping */ + if ( previous_base + previous_length > current_base ) + return false; + + /* remember previous entry before going to the next one */ + previous_base = current_base; + previous_length = combine64b(new_entry->length_low, + new_entry->length_high); + + g_nr_map++; + + entry_offset += entry->size + sizeof(entry->size); + } + if ( g_nr_map == MAX_E820_ENTRIES ) { + printk("Too many e820 entries\n"); + return false; + } + } + else if ( mbi->flags & MBI_MEMLIMITS ) { + printk("no e820 map, mem_lower=%x, mem_upper=%x\n", + mbi->mem_lower, mbi->mem_upper); + + /* 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 = mbi->mem_lower << 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)mbi->mem_upper << 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("no e820 map nor memory limits provided\n"); + return false; + } + + return true; +} + +void replace_e820_map(multiboot_info_t *mbi) +{ + /* replace original with the copy */ + mbi->mmap_addr = (uint32_t)g_copy_e820_map; + mbi->mmap_length = g_nr_map * sizeof(memory_map_t); + mbi->flags |= MBI_MEMMAP; /* in case only MBI_MEMLIMITS was set */ +} + +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; + int i; + bool gap = true; /* suppose there is always a virtual gap at first */ + + e820_base = 0; + e820_length = 0; + + for ( 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 = combine64b(e820_entry->base_addr_low, + e820_entry->base_addr_high) - e820_base; + type = E820_GAP; + } + else { + /* deal with the normal item in e820 map */ + e820_base = combine64b(e820_entry->base_addr_low, + e820_entry->base_addr_high); + e820_length = combine64b(e820_entry->length_low, + e820_entry->length_high); + 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(" (range from %016Lx to %016Lx is in ", base, base + length); + switch (ret) { + case E820_RAM: + printk("E820_RAM)\n"); break; + case E820_RESERVED: + printk("E820_RESERVED)\n"); break; + case E820_ACPI: + printk("E820_ACPI)\n"); break; + case E820_NVS: + printk("E820_NVS)\n"); break; + case E820_UNUSABLE: + printk("E820_UNUSABLE)\n"); break; + case E820_GAP: + printk("E820_GAP)\n"); break; + case E820_MIXED: + printk("E820_MIXED)\n"); break; + default: + printk("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; + uint32_t i; + + if ( length == 0 ) + return true; + + end = base + length; + + /* find where our region should cover the ram in e820 */ + for (i = 0; i < g_nr_map; i++) { + e820_entry = &g_copy_e820_map[i]; + e820_base = combine64b(e820_entry->base_addr_low, + e820_entry->base_addr_high); + e820_length = combine64b(e820_entry->length_low, + e820_entry->length_high); + 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("we should never get here\n"); + return false; + } + } + + return true; +} + +void print_e820_map(void) +{ + print_map(g_copy_e820_map, g_nr_map); +} + +uint64_t get_max_ram(multiboot_info_t *mbi) +{ + uint32_t entry_offset; + memory_map_t *entry; + uint64_t max_ram, base, len; + + if ( mbi->flags & MBI_MEMMAP ) { + /* find highest RAM region */ + entry_offset = 0; + max_ram = 0; + while ( entry_offset < mbi->mmap_length ) { + entry = (memory_map_t *)(mbi->mmap_addr + entry_offset); + if ( entry->type == E820_RAM ) { + base = combine64b(entry->base_addr_low, entry->base_addr_high); + len = combine64b(entry->length_low, entry->length_high); + if ( base + len > max_ram ) + max_ram = base + len; + } + entry_offset += entry->size + sizeof(entry->size); + } + return max_ram; + } + else if ( mbi->flags & MBI_MEMLIMITS ) + return (uint64_t)mbi->mem_upper << 10; + else { + printk("no e820 map nor mem limits provided\n"); + return 0; + } +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r de942f6fa6b3 -r 5648dc802679 sboot/common/early_printk.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/common/early_printk.c Tue Aug 28 16:27:50 2007 -0700 @@ -0,0 +1,167 @@ +/* + * early_printk.c: printk to serial for very early boot stages + * + * Copyright (c) 2006-2007, Intel Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DEFINE_SPINLOCK(print_lock); + +/* + * logging support + */ +/* initialize it so that it doesn't get put in bss, which is zero'ed on */ +/* entry to measured environment */ +static sb_log_t _log = { + uuid : SB_LOG_UUID, + max_size : 0, + curr_pos : 0, + buf : "", +}; +sb_log_t *g_log = &_log; + +void init_log(void) +{ + g_log = &_log; + g_log->max_size = sizeof(g_log->buf); + + /* if we're calling this post-launch, verify that curr_pos is valid */ + if ( g_log->curr_pos > sizeof(g_log->buf) ) + g_log->curr_pos = 0; +} + +static void write_log(const char *s, unsigned int n) +{ + if ( n > g_log->max_size ) + return; + + /* wrap to beginning if too big to fit */ + if ( g_log->curr_pos + n > g_log->max_size ) + g_log->curr_pos = 0; + + memcpy(&g_log->buf[g_log->curr_pos], s, n); + g_log->curr_pos += n; + + /* if the string wasn't NULL-terminated, then NULL-terminate the log */ + if ( s[n-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 print_log(void) +{ + printk("g_log:\n"); + printk("\t uuid="); print_uuid(&g_log->uuid); printk("\n"); + printk("\t max_size=%x\n", g_log->max_size); + printk("\t curr_pos=%x\n", g_log->curr_pos); +} + + +/* + * serial support from linux.../arch/x86_64/kernel/early_printk.c + * + * this code does not initialize the serial port and assumes COM1, so + * it will only display if GRUB has been configured for output to COM1 + */ + +#define early_serial_base 0x3f8 /* ttyS0 */ + +#define XMTRDY 0x20 + +#define DLAB 0x80 + +#define TXR 0 /* Transmit register (WRITE) */ +#define RXR 0 /* Receive register (READ) */ +#define IER 1 /* Interrupt Enable */ +#define IIR 2 /* Interrupt ID */ +#define FCR 2 /* FIFO control */ +#define LCR 3 /* Line control */ +#define MCR 4 /* Modem control */ +#define LSR 5 /* Line Status */ +#define MSR 6 /* Modem Status */ +#define DLL 0 /* Divisor Latch Low */ +#define DLH 1 /* Divisor latch High */ + +static int early_serial_putc(unsigned char ch) +{ + unsigned timeout = 0xffff; + while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) + cpu_relax(); + outb(ch, early_serial_base + TXR); + return timeout ? 0 : -1; +} + +static void early_serial_write(const char *s, unsigned int n) +{ + while (*s && n-- > 0) { + early_serial_putc(*s); + if (*s == '\n') + early_serial_putc('\r'); + s++; + } +} + +void early_serial_printk(const char *fmt, ...) +{ + char buf[256]; + int n; + va_list ap; + static bool last_line_cr = true; + + memset(buf, '\0', sizeof(buf)); + va_start(ap, fmt); + n = vscnprintf(buf, sizeof(buf), fmt, ap); + spin_lock(&print_lock); + /* prepend "SBOOT: " if the last line that was printed ended with a '\n' */ + if ( last_line_cr ) { + early_serial_write("SBOOT: ", 8); + write_log("SBOOT: ", 8); + } + last_line_cr = (n > 0 && buf[n-1] == '\n'); + early_serial_write(buf, n); + write_log(buf, n); + spin_unlock(&print_lock); + va_end(ap); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r de942f6fa6b3 -r 5648dc802679 sboot/common/elf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/common/elf.c Tue Aug 28 16:27:50 2007 -0700 @@ -0,0 +1,390 @@ +/* + * elf.c: support functions for manipulating ELF binaries + * + * 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 + +#if 0 +static void print_mbi(multiboot_info_t *mbi) +{ + /* print mbi for debug */ + int i; + printk("print mbi ...\n"); + printk("flags = %x\n", mbi->flags); + if ((mbi->flags) & ( 1<<0 )) + printk("mem_lower = %uKB, mem_upper = %uKB\n", mbi->mem_lower, + mbi->mem_upper); + if ((mbi->flags) & ( 1<<1 )) + printk("boot_device = %x\n", mbi->boot_device); + if ((mbi->flags) & ( 1<<2 )) + printk("cmdline = %s\n", (char *)mbi->cmdline); + if ((mbi->flags) & ( 1<<3 )) { + printk("mods_count = %x, mods_addr = %x\n", mbi->mods_count, + mbi->mods_addr); + for ( i=0; imods_count; i++ ) { + module_t *p = (module_t *)(mbi->mods_addr + i*sizeof(module_t)); + printk("\t i = %x, mod_start = %x, mod_end = %x, string = %x, " + "string = %s\n", i, p->mod_start, p->mod_end, p->string, + (char *)p->string); + } + } + if ((mbi->flags) & ( 1<<4 )) { + aout_symbol_table_t *p = &(mbi->u.aout_sym); + printk("tabsize = %x, strsize = %x, addr = %x\n", p->tabsize, + p->strsize, p->addr); + } + if ((mbi->flags) & ( 1<<5 )) { + elf_section_header_table_t *p = &(mbi->u.elf_sec); + printk("num = %x, size = %x, addr = %x, shndx = %x\n", p->num, + p->size, p->addr, p->shndx); + } + if ((mbi->flags) & ( 1<<6 )) { + memory_map_t *p; + printk("mmap_length = %x, mmap_addr = %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("size = %x, base_addr = 0x%x%x, length = 0x%x%x, " + "type = %x\n", p->size, p->base_addr_high, + p->base_addr_low, p->length_high, p->length_low, p->type); + } + } +} +#endif + +static bool is_mods_valid(multiboot_info_t *mbi) +{ + if (mbi == NULL) { + printk("Error: Mbi pointer is zero.\n"); + return false; + } + + if (!((mbi->flags) & (1<<3))) { + printk("Error: Mods in mbi is invalid.\n"); + return false; + } + + return true; +} + +static bool is_elf_image(const void *image, const size_t size) +{ + elf_header_t *elf; + + if (image == NULL) { + printk("Error: Pointer is zero.\n"); + return false; + } + + /* check size */ + if (sizeof(elf_header_t) > size) { + printk("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("Error: ELF magic number is not matched.\n"); + return false; + } + + /* check data encoding in ELF */ + if (elf->e_ident[EI_DATA] != ELFDATA2LSB) { + printk("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("Error: ELF image is not executable.\n"); + return false; + } + + /* check ELF image is for IA? */ + if (elf->e_machine != EM_386) { + printk("Error: ELF image is not for IA.\n"); + return false; + } + + /* check ELF version is valid? */ + if (elf->e_version != EV_CURRENT) { + printk("Error: ELF version is invalid.\n"); + return false; + } + + if (sizeof(elf_program_header_t) > elf->e_phentsize) { + printk("Error: Program size is smaller than program " + "header size.\n"); + return false; + } + + return true; +} + +static bool get_elf_image_range(const elf_header_t *elf, void **start, + void **end) +{ + int i; + uint32_t u_start, u_end; + + if (elf == NULL) { + printk("Error: ELF header pointer is zero.\n"); + return false; + } + + /* assumed that already passed is_elf_image() check */ + + if ((start == NULL) || (end == NULL)) { + printk("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; + } +} + +static bool move_modules_backward(multiboot_info_t *mbi, void *dest) +{ + module_t *m, *first_module, *last_module; + int i; + size_t size; + void *src; + uint32_t shift; + + if (mbi == NULL) { + printk("Error: Mbi pointer is zero.\n"); + return false; + } + + if (!is_mods_valid(mbi)) + return false; + + if (mbi->mods_count < 1) { + printk("Warning: There is no module need to move.\n"); + return true; + } + + first_module = (module_t *)mbi->mods_addr; + src = (void *)first_module->mod_start; + + last_module = (module_t *)(mbi->mods_addr + + (mbi->mods_count - 1)*sizeof(module_t)); + size = last_module->mod_end - first_module->mod_start; + shift = dest - src; + + for (i = 0; imods_count; i++) { + m = (module_t *)(mbi->mods_addr + i*sizeof(module_t)); + + m->mod_start += shift; + m->mod_end += shift; + } + memmove(dest, src, size); + + return true; +} + +static void* delete_module(multiboot_info_t *mbi, const int module_index) +{ + module_t *m; + + if (mbi == NULL) { + printk("Error: Mbi pointer is zero.\n"); + return NULL; + } + + if (module_index < -1) { + printk("Error: Module index for deleting is wrong.\n"); + return NULL; + } + + if (mbi->mods_count <= 0) { + printk("Error: Module count incorrect for module deleting.\n"); + return NULL; + } + + if ((module_index > -1) && (module_index >= mbi->mods_count)) { + printk("Error: Module index greater than the module count.\n"); + return NULL; + } + + if (module_index != -1) { + printk("Error: Only deleting kernel is supported so far.\n"); + return NULL; + } + + if (!is_mods_valid(mbi)) + return false; + + /* delete kernel */ + m = (module_t *)mbi->mods_addr; + mbi->mods_addr += sizeof(module_t); + mbi->mods_count--; + mbi->cmdline = m->string; + mbi->flags |= MBI_CMDLINE; + return (void *)(m->mod_start); +} + +static bool expand_elf_image(const elf_header_t *elf, void **entry_point) +{ + int i; + + if (elf == NULL) { + printk("Error: ELF header pointer is zero.\n"); + return false; + } + + if (entry_point == NULL) { + printk("Error: Output 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) { + 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; +} + +int launch_xen(multiboot_info_t *mbi, void **kernel_entry_point) +{ + module_t *m; + void *xen_base, *xen_expanded_start, *xen_expanded_end, *xen_entry_point; + elf_header_t *xen_as_elf; + size_t xen_size; + + if (mbi == NULL) { + printk("Error: Mbi pointer is zero.\n"); + return -1; + } + + if (!is_mods_valid(mbi)) + return -1; + + m = (module_t *)mbi->mods_addr; + + xen_base = (void *)m->mod_start; + xen_size = m->mod_end - m->mod_start; + + if (!is_elf_image(xen_base, xen_size)) + return -1; + + xen_as_elf = (elf_header_t *)xen_base; + + if (!get_elf_image_range(xen_as_elf, &xen_expanded_start, + &xen_expanded_end)) + return -1; + + xen_expanded_end = (void *)(((uint32_t)xen_expanded_end + PAGE_SIZE) & + PAGE_MASK); + + if (!move_modules_backward(mbi, xen_expanded_end)) + return -1; + + xen_base = delete_module(mbi, -1); + if (xen_base == NULL) + return -1; + + xen_as_elf = (elf_header_t *)xen_base; + + if (!expand_elf_image(xen_as_elf, &xen_entry_point)) + return -1; + + *kernel_entry_point = xen_entry_point; + /* jump to xen start entry */ + __asm__ __volatile__ ( + " jmp *%%ecx; " + " ud2; " + :: "a" (MB_MAGIC), "b" (mbi), "c" (xen_entry_point)); + + return 0; +} + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r de942f6fa6b3 -r 5648dc802679 sboot/common/lib.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/common/lib.c Tue Aug 28 16:27:50 2007 -0700 @@ -0,0 +1,40 @@ + +#include + +/* for inc/ctype.h */ +unsigned char _ctype[] = { +_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */ +_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */ +_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */ +_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */ +_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */ +_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */ + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + */ diff -r de942f6fa6b3 -r 5648dc802679 sboot/common/sboot.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/common/sboot.c Tue Aug 28 16:27:50 2007 -0700 @@ -0,0 +1,291 @@ +/* + * sboot.c: main entry point and "generic" routines for measured launch + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int launch_xen(multiboot_info_t *mbi, void **kernel_entry_point); + +extern char _start[]; /* start of sboot */ +extern char _end[]; /* end of sboot */ + +/* multiboot struct saved so that post_launch() can use it */ +static multiboot_info_t *g_mbi; + +/* entry point for next module, i.e. Xen */ +static void *g_kernel_entry_point; + +/* MLE/kernel shared data page (in boot.S) */ +extern mle_kernel_shared_t _mle_kernel_shared; + +static bool 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 bool prepare_platform(void) +{ + return txt_prepare_platform(); +} + +static bool launch_environment(multiboot_info_t *mbi) +{ + return txt_launch_environment(mbi); +} + +static void print_mle_kernel(mle_kernel_shared_t *mle_kernel_shared) +{ + printk("mle_kernel_shared data:\n"); + printk("\t uuid="); print_uuid(&(mle_kernel_shared->uuid)); + printk("\n"); + printk("\t version=%x\n", mle_kernel_shared->version); + printk("\t log_addr=%x\n", mle_kernel_shared->log_addr); + printk("\t shutdown_entry32=0x%x\n", mle_kernel_shared->shutdown_entry32); + printk("\t shutdown_entry64=0x%x\n", mle_kernel_shared->shutdown_entry64); + printk("\t shutdown_type=%x\n", mle_kernel_shared->shutdown_type); +} + +static void post_launch(void) +{ + uint64_t base, size; + module_t *m; + int i; + extern void shutdown_entry32(void); + extern void shutdown_entry64(void); + extern sb_log_t *g_log; + + /* TBD: need to handle errors here by tearing down */ + + printk("measured launch succeeded\n"); + + txt_post_launch(); + + if ( !copy_e820_map(g_mbi) ) + goto launch_xen; + + if ( !txt_protect_mem_regions() ) + goto launch_xen; + + /* verify e820 map to make sure each module is OK in e820 map */ + /* check modules in mbi should be in RAM */ + if ( (g_mbi->flags) & (1 << 3) ) { + for ( i = 0; i < g_mbi->mods_count; i++ ) { + m = (module_t *)(g_mbi->mods_addr + i*sizeof(module_t)); + base = m->mod_start; + size = m->mod_end - m->mod_start; + printk("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(": failed.\n"); + goto launch_xen; + } + else + printk(": succeeded.\n"); + } + } + /* check sboot and the page table */ + base = (uint64_t)((unsigned long)&_start - 3*PAGE_SIZE); + size = (uint64_t)((unsigned long)&_end - base); + printk("verifying sboot and its page table (%Lx - %Lx) in e820 table\n\t", + base, (base + size - 1)); + if ( e820_check_region(base, size) != E820_RAM ) { + printk(": failed.\n"); + /* TBD: un-comment when new SINIT is released */ + /* goto launch_xen; */ + } + else + printk(": succeeded.\n"); + + /* protect ourselves and the page table we created */ + base = (uint64_t)((unsigned long)&_start - 3*PAGE_SIZE); + size = (uint64_t)(unsigned long)&_end - base; + printk("protecting sboot (%Lx - %Lx) in e820 table\n", base, + (base + size - 1)); + if ( !e820_protect_region(base, size, E820_UNUSABLE) ) + goto launch_xen; + + /* mark the shared MLE/kernel page as E820_RESERVED */ + /* (xen will change it to E820_UNUSABLE when it finds it) */ + base = (uint32_t)&_mle_kernel_shared; + size = PAGE_SIZE; + printk("protecting MLE/kernel shared (%Lx - %Lx) in e820 table\n", + base, (base + size - 1)); + if ( !e820_protect_region(base, size, E820_RESERVED) ) + goto launch_xen; + + /* replace map in mbi with copy */ + replace_e820_map(g_mbi); + + printk("adjusted e820 map:\n"); + print_e820_map(); + + /* + * init MLE/kernel shared data page + */ + memset(&_mle_kernel_shared, 0, PAGE_SIZE); + _mle_kernel_shared.uuid = mle_kernel_shared_uuid; + _mle_kernel_shared.version = 0x01; + _mle_kernel_shared.log_addr = (uint32_t)g_log; + _mle_kernel_shared.shutdown_entry32 = (uint32_t)shutdown_entry32; + _mle_kernel_shared.shutdown_entry64 = (uint32_t)shutdown_entry64; + print_mle_kernel(&_mle_kernel_shared); + print_log(); + +launch_xen: + launch_xen(g_mbi, &g_kernel_entry_point); +} + +#define __STR(...) #__VA_ARGS__ +#define STR(...) __STR(__VA_ARGS__) + +void cpu_wakeup(uint32_t cpuid, uint32_t sipi_vec) +{ + extern void _prot_to_real(void); + + printk("cpu %x waking up, SIPI vector=%x\n", cpuid, sipi_vec); + + /* change to real mode and then jump to SIPI vector */ + __asm__ __volatile__ ( + "jmp "STR(_prot_to_real) :: "b" (sipi_vec)); +} + +multiboot_info_t* begin_launch(multiboot_info_t *mbi) +{ + unsigned long apicbase; + + init_log(); + + printk("***************************************\n"); + printk("begin launch()\n"); + + /* we should only be executing on the BSP */ + rdmsrl(MSR_IA32_APICBASE, apicbase); + if ( !(apicbase & MSR_IA32_APICBASE_BSP) ) { + printk("entry processor is not BSP\n"); + goto failed; + } + + /* 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 */ + + /* need to verify that platform can perform measured launch */ + if ( !verify_platform() ) + goto failed; + + /* this is being called post-measured launch */ + if ( is_launched() ) { + post_launch(); + } + + /* print any errors on last boot, which must be from TXT launch */ + txt_get_error(); + + /* make the CPU ready for measured launch */ + if ( !prepare_cpu() ) + goto failed; + + /* make the platform ready for measured launch */ + if ( !prepare_platform() ) + goto failed; + + /* save for post_launch */ + g_mbi = mbi; + + /* launch the measured environment */ + if ( !launch_environment(mbi) ) + goto failed; + + /* for Intel(r) TXT, we will never get here */ + printk("we should never get here\n"); + return mbi; + + failed: + launch_xen(mbi, &g_kernel_entry_point); + return mbi; +} + +void shutdown_system(uint32_t shutdown_type) +{ + long empty_idt[2] = {0, 0}; + + printk("shutdown_system() called for shutdown_type=%x\n", shutdown_type); + + if ( shutdown_type == SB_SHUTDOWN_REBOOT ) { + /* just triple fault by loading 0-size IDT then generating intrrupt */ + __asm__ __volatile__("lidt (%0)" : : "r" (&empty_idt)); + __asm__ __volatile__("int3"); + } + else { + for ( ; ; ) + __asm__ __volatile__ ( "hlt" ); + } +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r de942f6fa6b3 -r 5648dc802679 sboot/common/sboot.lds.S --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/common/sboot.lds.S Tue Aug 28 16:27:50 2007 -0700 @@ -0,0 +1,55 @@ +/* ld script to make i386 Linux kernel + * Written by Martin Mares + * Modified for i386 Xen by Keir Fraser + * Modified for sboot 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 +{ + . = SBOOT_BASE_ADDR; /* 0x70000 */ + + _stext = .; /* text */ + _mle_start = .; /* beginning of MLE pages */ + + .text : { + *(.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) + CONSTRUCTORS + } + + . = ALIGN(4096); + + __bss_start = .; /* BSS */ + .bss : { + *(.bss.stack_aligned) + *(.bss.page_aligned) + *(.bss) + *(.mle_kernel_shared) + } + + _end = . ; +} diff -r de942f6fa6b3 -r 5648dc802679 sboot/common/string.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/common/string.c Tue Aug 28 16:27:50 2007 -0700 @@ -0,0 +1,68 @@ +/* + * linux/lib/string.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include + +#ifndef __HAVE_ARCH_STRNLEN +/** + * strnlen - Find the length of a length-limited string + * @s: The string to be sized + * @count: The maximum number of bytes to search + */ +size_t strnlen(const char * s, size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} +#endif + +#ifndef __HAVE_ARCH_MEMMOVE +/** + * memmove - Copy one area of memory to another + * @dest: Where to copy to + * @src: Where to copy from + * @count: The size of the area. + * + * Unlike memcpy(), memmove() copes with overlapping areas. + */ +void * memmove(void * dest,const void *src,size_t count) +{ + char *tmp, *s; + + if (dest <= src) { + tmp = (char *) dest; + s = (char *) src; + while (count--) + *tmp++ = *s++; + } + else { + tmp = (char *) dest + count; + s = (char *) src + count; + while (count--) + *--tmp = *--s; + } + + return dest; +} +#endif + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 8 + * tab-width: 8 + * indent-tabs-mode: t + * End: + */ diff -r de942f6fa6b3 -r 5648dc802679 sboot/common/symbols-dummy.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/common/symbols-dummy.c Tue Aug 28 16:27:50 2007 -0700 @@ -0,0 +1,16 @@ +/* + * symbols-dummy.c: dummy symbol-table definitions for the inital partial + * link of the hypervisor image. + */ + +#include +#include + +unsigned long symbols_addresses[1]; +unsigned long symbols_num_syms; +u8 symbols_names[1]; + +u8 symbols_token_table[1]; +u16 symbols_token_index[1]; + +unsigned long symbols_markers[1]; diff -r de942f6fa6b3 -r 5648dc802679 sboot/common/tpm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sboot/common/tpm.c Tue Aug 28 16:27:50 2007 -0700 @@ -0,0 +1,3113 @@ +/* + * tpm.c: TPM-related support functions + * + * 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 + +#define TPM_TAG_RQU_COMMAND 0x00C1 +#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 readb(x) (*(volatile char *)(x)) +#define writeb(d,x) (*(volatile char *)(x) = (d)) + +/* + * 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 { + 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 */ + } __attribute__ ((packed)); +} tpm_reg_access_t; + +/* TPM_STS_x */ +#define TPM_REG_STS 0x18 +typedef union { + u8 _raw[3]; /* 3-byte reg */ + struct { + u8 reserved1 : 1; + u8 response_retry : 1; /* WO, 1=re-send response */ + u8 reserved2 : 1; + 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 */ + } __attribute__ ((packed)); +} 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; + +/* + * 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 void _read_tpm_reg(int locality, u32 reg, u8 *_raw, size_t size) +{ + size_t i; + for ( i = 0; i < size; i++ ) + _raw[i] = readb((TPM_LOCALITY_BASE_N(locality) | reg) + i); +} + +static void _write_tpm_reg(int locality, u32 reg, u8 *_raw, size_t size) +{ + size_t i; + for ( i = 0; i < size; i++ ) + writeb(_raw[i], (TPM_LOCALITY_BASE_N(locality) | reg) + 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) +{ + uint32_t i; + for ( i = 0; i < count; i++ ) + out[i] = in[count - i - 1]; +} + +#define TPM_VALIDATE_LOCALITY_TIME_OUT 0x100 + +static bool tpm_validate_locality(uint32_t locality) +{ + tpm_reg_access_t reg_acc; + uint32_t i; + + for ( i = 0; i < TPM_VALIDATE_LOCALITY_TIME_OUT; 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(); + } + + return false; +} + +#define TPM_ACTIVE_LOCALITY_TIME_OUT 0x800 +#define TPM_STS_VALID_TIME_OUT 0x100 +#define TPM_CMD_READY_TIME_OUT 0x100 +#define TPM_CMD_WRITE_TIME_OUT 0x100 +#define TPM_DATA_AVAIL_TIME_OUT 0x100 +#define TPM_RSP_READ_TIME_OUT 0x100 + +static uint32_t 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); + printk("TPM: Access reg content: 0x%02x\n", (uint32_t)reg_acc._raw[0]); + if ( reg_acc.tpm_reg_valid_sts == 0 ) { + printk("TPM: Access reg not valid\n"); + return TPM_FAIL; + } + + /* 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); + + for ( i = TPM_ACTIVE_LOCALITY_TIME_OUT; i > 0; i-- ) { + read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + if ( reg_acc.active_locality == 1 ) + break; + else + cpu_relax(); + } + + if ( i <= 0 ) { + printk("TPM: request use timeout\n"); + return TPM_FAIL; + } + + /* ensure the contents of the STATUS register are valid */ + for ( i = TPM_STS_VALID_TIME_OUT; i > 0; i-- ) { + read_tpm_reg(locality, TPM_REG_STS, ®_sts); + if ( reg_sts.sts_valid == 1 ) + break; + else + cpu_relax(); + } + + if ( i <= 0 ) { + printk("TPM: status register not valid\n"); + goto RelinquishControl; + } + + /* write 1 to TPM_STS_x.commandReady to let TPM enter the ready status */ + memset((void *)®_sts, 0, sizeof(reg_sts)); + reg_sts.command_ready = 1; + write_tpm_reg(locality, TPM_REG_STS, ®_sts); + + /* ensure the TPM is ready to accept a command */ + printk("TPM: wait for cmd ready "); + for ( i = TPM_CMD_READY_TIME_OUT; i > 0; i-- ) { + read_tpm_reg(locality, TPM_REG_STS, ®_sts); + printk("."); + if ( reg_sts.command_ready == 1 ) + break; + else + cpu_relax(); + } + printk("\n"); + + if ( i <= 0 ) { + printk("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("TPM: tpm timeout for command_ready\n"); + goto RelinquishControl; + } + return TPM_SUCCESS; + +RelinquishControl: + /* deactivate current locality */ + reg_acc._raw[0] = 0; + reg_acc.active_locality = 1; + write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + + return TPM_FAIL; +} + +/* + * locality : TPM locality (0 - 3) + * in : All bytes for a single TPM command, including TAG, SIZE, + * ORDINAL, and other arguments. All data should be in big-endian + * style. The in MUST NOT be NULL, containing at least 10 bytes. + * 0 1 2 3 4 5 6 7 8 9 10 ... + * ------------------------------------------------------------- + * | TAG | SIZE | ORDINAL | arguments ... + * ------------------------------------------------------------- + * in_size : The size of the whole command contained within the in buffer. + * It should equal to the SIZE contained in the in buffer. + * out : All bytes of the TPM response to a single command. All data + * within it will be in big-endian style. The out MUST not be + * NULL, and will return at least 10 bytes. + * 0 1 2 3 4 5 6 7 8 9 10 ... + * ------------------------------------------------------------- + * | TAG | SIZE | RETURN CODE | other data ... + * ------------------------------------------------------------- + * out_size : In/out paramter. As in, it is the size of the out buffer; + * as out, it is the size of the response within the out buffer. + * The out_size MUST NOT be NULL. + * return : 0 = success; if not 0, it equal to the RETURN CODE in out buf. + */ +#define CMD_HEAD_SIZE 10 +#define RSP_HEAD_SIZE 10 +#define CMD_SIZE_OFFSET 2 +#define CMD_ORD_OFFSET 6 +#define RSP_SIZE_OFFSET 2 +#define RSP_RST_OFFSET 6 + +static uint32_t tpm_write_cmd_fifo(uint32_t locality, uint8_t *in, + uint32_t in_size, uint8_t *out, + uint32_t *out_size) +{ + uint32_t i, rsp_size, offset, ret; + uint16_t row_size; + tpm_reg_access_t reg_acc; + tpm_reg_sts_t reg_sts; + + if ( locality >= TPM_NR_LOCALITIES ) { + printk("TPM: Invalid parameter\n"); + return TPM_BAD_PARAMETER; + } + if ( in == NULL || out == NULL || out_size == NULL ) { + printk("TPM: Invalid parameter\n"); + return TPM_BAD_PARAMETER; + } + if ( in_size < CMD_HEAD_SIZE || *out_size < RSP_HEAD_SIZE ) { + printk("TPM: in/out buf size must be larger than 10 bytes.\n"); + return TPM_BAD_PARAMETER; + } + + if ( !tpm_validate_locality(locality) ) { + printk("TPM: Locality %d is not opened.\n", locality); + return TPM_FAIL; + } + + ret = tpm_wait_cmd_ready(locality); + if ( ret != TPM_SUCCESS ) + return ret; + + { + uint32_t i; + printk("TPM: cmd size = %d\nTPM: cmd content: ", in_size); + for ( i = 0; i < in_size; i++ ) { + if ( i % 16 == 0 ) + printk("\nTPM: \t"); + printk("%02x ", (uint32_t)in[i]); + } + printk("\n"); + } + + /* write the command to the TPM FIFO */ + offset = 0; + do { + for ( i = TPM_CMD_WRITE_TIME_OUT; i > 0; i-- ) { + 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(); + } + if ( i <= 0 ) { + printk("TPM: write cmd timeout.\n"); + ret = TPM_FAIL; + 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 ); + + /* 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 */ + for ( i = TPM_DATA_AVAIL_TIME_OUT; i > 0; i-- ) { + read_tpm_reg(locality,TPM_REG_STS, ®_sts); + if ( reg_sts.data_avail == 1 ) + break; + else + cpu_relax(); + } + if ( i <= 0 ) { + printk("TPM: wait for data available timeout.\n"); + ret = TPM_FAIL; + goto RelinquishControl; + } + + rsp_size = 0; + offset = 0; + do { + /* find out how many bytes the TPM returned in a row */ + for ( i = TPM_RSP_READ_TIME_OUT; i > 0; i-- ) { + read_tpm_reg(locality, TPM_REG_STS, ®_sts); + row_size = reg_sts.burst_count; + if ( row_size > 0 ) + break; + else + cpu_relax(); + } + if ( i <= 0 ) { + printk("TPM: read rsp timeout.\n"); + ret = TPM_FAIL; + 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 ) { + 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; + + /* out buffer contains the complete outgoing data, get return code */ + reverse_copy(&ret, &out[RSP_RST_OFFSET], sizeof(ret)); + + { + uint32_t i; + printk("TPM: response size = %d\n", *out_size); + printk("TPM: response content: "); + for ( i = 0; i < *out_size; i++ ) { + if ( i % 16 == 0 ) + printk("\nTPM: \t"); + printk("%02x ", (uint32_t)out[i]); + } + printk("\n"); + } + +RelinquishControl: + /* deactivate current locality */ + reg_acc._raw[0] = 0; + reg_acc.active_locality = 1; + write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + + return ret; +} + +/* + * The tpm_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) + * 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 tpm_submit_cmd(uint32_t locality, uint32_t cmd, + uint32_t arg_size, uint32_t *out_size) +{ + uint32_t ret; + uint16_t tag = TPM_TAG_RQU_COMMAND; + uint32_t cmd_size, rsp_size = 0; + + if ( out_size == NULL ) { + printk("TPM: invalid param for tpm_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("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_ORD_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; + ret = tpm_write_cmd_fifo(locality, cmd_buf, cmd_size, rsp_buf, &rsp_size); + + /* + * 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; + + 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; +} + +uint32_t tpm_pcr_read(uint32_t locality, uint32_t pcr, tpm_pcr_value_t *out) +{ + uint32_t ret, out_size = sizeof(*out); + + if ( out == NULL ) + return TPM_BAD_PARAMETER; + if ( pcr >= TPM_NR_PCRS ) + return TPM_BAD_PARAMETER; + + /* copy pcr into buf in reversed byte order */ + reverse_copy(WRAPPER_IN_BUF, &pcr, sizeof(pcr)); + + ret = tpm_submit_cmd(locality, TPM_ORD_PCR_READ, sizeof(pcr), &out_size); + + printk("TPM: Pcr %d Read return value = %08X\n", pcr, ret); + if ( ret != TPM_SUCCESS ) + return ret; + + if ( out_size > sizeof(*out) ) + out_size = sizeof(*out); + memcpy((void *)out, WRAPPER_OUT_BUF, out_size); + + { + uint32_t i; + printk("TPM: "); + for ( i = 0; i < out_size; i++ ) + printk("%02X ", (uint32_t)out->digest[i]); + printk("\n"); + } + + return ret; +} + +uint32_t tpm_pcr_extend(uint32_t locality, uint32_t pcr, + const tpm_digest_t* in, tpm_pcr_value_t* out) +{ + uint32_t ret, in_size = 0, out_size; + + if ( in == NULL ) + return TPM_BAD_PARAMETER; + if ( pcr >= TPM_NR_PCRS ) + return TPM_BAD_PARAMETER; + 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(*in)); + in_size += sizeof(*in); + + ret = tpm_submit_cmd(locality, TPM_ORD_PCR_EXTEND, in_size, &out_size); + + printk("TPM: Pcr %d extend, return value = %08X\n", pcr, ret); + if ( ret != TPM_SUCCESS ) + return ret; + + if ( out != NULL && out_size > 0 ) { + out_size = (out_size > sizeof(*out)) ? sizeof(*out) : out_size; + memcpy((void *)out, WRAPPER_OUT_BUF, out_size); + } + + { + uint32_t i; + printk("TPM: "); + for ( i = 0; i < out_size; i++ ) + printk("%02X ", (uint32_t)out->digest[i]); + printk("\n"); + } + + return ret; +} + +typedef struct { + uint16_t size_of_select; + uint8_t pcr_select[3]; +} __attribute__ ((packed)) tpm_pcr_selection_t; + +uint32_t tpm_pcr_reset(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 ) + return TPM_BAD_PARAMETER; + + /* 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 = tpm_submit_cmd(locality, TPM_ORD_PCR_RESET, in_size, &out_size); + + printk("TPM: Pcr %d reset, return value = %08X\n", pcr, ret); + + return ret; +} + +uint32_t tpm_nv_read_value(uint32_t locality, tpm_nv_index_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 ) + return TPM_BAD_PARAMETER; + if ( *data_size == 0 ) + return TPM_BAD_PARAMETER; + 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 = tpm_submit_cmd(locality, TPM_ORD_NV_READ_VALUE, in_size, &out_size); + + printk("TPM: read nv index %08x from offset %08x, return value = %08X\n", + index, offset, ret); + if ( ret != TPM_SUCCESS ) + return ret; + + { + uint32_t i; + printk("TPM: "); + for ( i = 0; i < out_size; i++ ) + printk("%02X ", (uint32_t)WRAPPER_OUT_BUF[i]); + printk("\n"); + } + + if ( out_size <= sizeof(*data_size) ) { + *data_size = 0; + return ret; + } + + 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 ret; +} + +uint32_t tpm_nv_write_value(uint32_t locality, tpm_nv_index_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 ) + return TPM_BAD_PARAMETER; + if ( data_size == 0 || data_size > TPM_NV_WRITE_VALUE_DATA_SIZE_MAX ) + return TPM_BAD_PARAMETER; + + /* 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 = tpm_submit_cmd(locality, TPM_ORD_NV_WRITE_VALUE, + in_size, &out_size); + + printk("TPM: write nv %08x, offset %08x, %08x bytes, return = %08X\n", + index, offset, data_size, ret); + + return ret; +} + +/* ensure TPM is ready to accept commands */ +bool is_tpm_ready(uint32_t locality) +{ + tpm_reg_access_t reg_acc; + + if ( !tpm_validate_locality(locality) ) { + printk("TPM is not available.\n"); + return false; + } + + /* + * must ensure TPM_ACCESS_0.activeLocality bit is clear + * (: locality is not active) + */ + read_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + if ( reg_acc.active_locality != 0 ) { + /* make inactive by writing a 1 */ + reg_acc.active_locality = 1; + write_tpm_reg(locality, TPM_REG_ACCESS, ®_acc); + } + + printk("TPM is ready\n"); + + return true; +} + +#define TPM_CAP_VERSION_VAL 0x1A + +typedef uint16_t tpm_structure_tag_t; + +typedef struct { + uint8_t major; + uint8_t minor; + uint8_t rev_major; + uint8_t rev_minor; +} __attribute__ ((packed)) tpm_version_t; + +typedef struct { + 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[]; +} __attribute__ ((packed)) tpm_cap_version_info_t; + +/* get tpm module version */ +uint32_t tpm_get_version(uint8_t *major, uint8_t *minor) +{ + uint32_t ret, in_size = 0, out_size; + uint32_t cap_area = TPM_CAP_VERSION_VAL; + uint32_t sub_cap_size = 0; + uint32_t resp_size = 0; + tpm_cap_version_info_t *cap_version; + + if ( major == NULL || minor == NULL ) + return TPM_BAD_PARAMETER; + + reverse_copy(WRAPPER_IN_BUF, &cap_area, sizeof(cap_area)); + in_size += sizeof(cap_area); + reverse_copy(WRAPPER_IN_BUF + in_size, &sub_cap_size, sizeof(sub_cap_size)); + in_size += sizeof(sub_cap_size); + + out_size = sizeof(resp_size) + sizeof(tpm_cap_version_info_t); + ret = tpm_submit_cmd(0, TPM_ORD_GET_CAPABILITY, in_size, &out_size); + + printk("TPM: get version, return value = %08X\n", ret); + if ( ret != TPM_SUCCESS ) + return ret; + + { + uint32_t i; + printk("TPM: "); + for ( i = 0; i < out_size; i++ ) + printk("%02X ", (uint32_t)WRAPPER_OUT_BUF[i]); + printk("\n"); + } + + reverse_copy(&resp_size, WRAPPER_OUT_BUF, sizeof(resp_size)); + cap_version = (tpm_cap_version_info_t *) (WRAPPER_OUT_BUF + sizeof(resp_size)); + *major = cap_version->version.major; + *minor = cap_version->version.minor; + + 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