diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Makefile | 4 | ||||
| -rw-r--r-- | lib/bitrev.c | 59 | ||||
| -rw-r--r-- | lib/crc32.c | 5 | ||||
| -rw-r--r-- | lib/fdtdec.c | 6 | ||||
| -rw-r--r-- | lib/hang.c | 47 | ||||
| -rw-r--r-- | lib/hashtable.c | 93 | ||||
| -rw-r--r-- | lib/slre.c | 724 | ||||
| -rw-r--r-- | lib/tpm.c | 581 | 
8 files changed, 1485 insertions, 34 deletions
| diff --git a/lib/Makefile b/lib/Makefile index 5d71b80e2..5d586098d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -53,7 +53,9 @@ COBJS-y += qsort.o  COBJS-$(CONFIG_SHA1) += sha1.o  COBJS-$(CONFIG_SHA256) += sha256.o  COBJS-y	+= strmhz.o +COBJS-$(CONFIG_TPM) += tpm.o  COBJS-$(CONFIG_RBTREE)	+= rbtree.o +COBJS-$(CONFIG_BITREVERSE) += bitrev.o  endif  ifdef CONFIG_SPL_BUILD @@ -70,7 +72,9 @@ COBJS-$(CONFIG_BCH) += bch.o  COBJS-y += crc32.o  COBJS-y += ctype.o  COBJS-y += div64.o +COBJS-y += hang.o  COBJS-y += linux_string.o +COBJS-$(CONFIG_REGEX) += slre.o  COBJS-y += string.o  COBJS-y += time.o  COBJS-$(CONFIG_BOOTP_PXE) += uuid.o diff --git a/lib/bitrev.c b/lib/bitrev.c new file mode 100644 index 000000000..160021a37 --- /dev/null +++ b/lib/bitrev.c @@ -0,0 +1,59 @@ +/* + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. + * + * Based on bitrev from the Linux kernel, by Akinobu Mita + */ + + +#include <linux/types.h> +#include <linux/bitrev.h> + +const u8 byte_rev_table[256] = { +	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, +	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, +	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, +	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, +	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, +	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, +	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, +	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, +	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, +	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, +	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, +	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, +	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, +	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, +	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, +	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, +	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, +	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, +	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, +	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, +	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, +	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, +	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, +	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, +	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, +	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, +	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, +	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, +	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, +	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, +	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, +	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; + +u16 bitrev16(u16 x) +{ +	return (bitrev8(x & 0xff) << 8) | bitrev8(x >> 8); +} + +/** + * bitrev32 - reverse the order of bits in a u32 value + * @x: value to be bit-reversed + */ +u32 bitrev32(u32 x) +{ +	return (bitrev16(x & 0xffff) << 16) | bitrev16(x >> 16); +} diff --git a/lib/crc32.c b/lib/crc32.c index 76205da4f..975921248 100644 --- a/lib/crc32.c +++ b/lib/crc32.c @@ -8,7 +8,9 @@   * For conditions of distribution and use, see copyright notice in zlib.h   */ -#ifndef USE_HOSTCC +#ifdef USE_HOSTCC +#include <arpa/inet.h> +#else  #include <common.h>  #endif  #include <compiler.h> @@ -256,5 +258,6 @@ void crc32_wd_buf(const unsigned char *input, unsigned int ilen,  	uint32_t crc;  	crc = crc32_wd(0, input, ilen, chunk_sz); +	crc = htonl(crc);  	memcpy(output, &crc, sizeof(crc));  } diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 403babd31..ac1fe0be2 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -65,6 +65,7 @@ static const char * const compat_names[COMPAT_COUNT] = {  	COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),  	COMPAT(GENERIC_SPI_FLASH, "spi-flash"),  	COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"), +	COMPAT(INFINEON_SLB9635_TPM, "infineon,slb9635-tpm"),  };  const char *fdtdec_get_compatible(enum fdt_compat_id id) @@ -353,10 +354,11 @@ int fdtdec_check_fdt(void)   */  int fdtdec_prepare_fdt(void)  { -	if (((uintptr_t)gd->fdt_blob & 3) || fdt_check_header(gd->fdt_blob)) { +	if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) || +	    fdt_check_header(gd->fdt_blob)) {  		printf("No valid FDT found - please append one to U-Boot "  			"binary, use u-boot-dtb.bin or define " -			"CONFIG_OF_EMBED\n"); +			"CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n");  		return -1;  	}  	return 0; diff --git a/lib/hang.c b/lib/hang.c new file mode 100644 index 000000000..fc1286c0b --- /dev/null +++ b/lib/hang.c @@ -0,0 +1,47 @@ +/* + * (C) Copyright 2013 + * Andreas Bießmann <andreas.devel@googlemail.com> + * + * This file consolidates all the different hang() functions implemented in + * u-boot. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> +#include <bootstage.h> + +/** + * hang - stop processing by staying in an endless loop + * + * The purpose of this function is to stop further execution of code cause + * something went completely wrong.  To catch this and give some feedback to + * the user one needs to catch the bootstage_error (see show_boot_progress()) + * in the board code. + */ +void hang(void) +{ +#if !defined(CONFIG_SPL_BUILD) || (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ +		defined(CONFIG_SPL_SERIAL_SUPPORT)) +	puts("### ERROR ### Please RESET the board ###\n"); +#endif +	bootstage_error(BOOTSTAGE_ID_NEED_RESET); +	for (;;) +		; +} diff --git a/lib/hashtable.c b/lib/hashtable.c index 07ebfb218..6050dd082 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -2,7 +2,7 @@   * This implementation is based on code from uClibc-0.9.30.3 but was   * modified and extended for use within U-Boot.   * - * Copyright (C) 2010 Wolfgang Denk <wd@denx.de> + * Copyright (C) 2010-2013 Wolfgang Denk <wd@denx.de>   *   * Original license header:   * @@ -57,6 +57,7 @@  #include <env_callback.h>  #include <env_flags.h>  #include <search.h> +#include <slre.h>  /*   * [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986 @@ -210,29 +211,6 @@ void hdestroy_r(struct hsearch_data *htab)   *   example for functions like hdelete().   */ -/* - * hstrstr_r - return index to entry whose key and/or data contains match - */ -int hstrstr_r(const char *match, int last_idx, ENTRY ** retval, -	      struct hsearch_data *htab) -{ -	unsigned int idx; - -	for (idx = last_idx + 1; idx < htab->size; ++idx) { -		if (htab->table[idx].used <= 0) -			continue; -		if (strstr(htab->table[idx].entry.key, match) || -		    strstr(htab->table[idx].entry.data, match)) { -			*retval = &htab->table[idx].entry; -			return idx; -		} -	} - -	__set_errno(ESRCH); -	*retval = NULL; -	return 0; -} -  int hmatch_r(const char *match, int last_idx, ENTRY ** retval,  	     struct hsearch_data *htab)  { @@ -563,6 +541,65 @@ static int cmpkey(const void *p1, const void *p2)  	return (strcmp(e1->key, e2->key));  } +static int match_string(int flag, const char *str, const char *pat, void *priv) +{ +	switch (flag & H_MATCH_METHOD) { +	case H_MATCH_IDENT: +		if (strcmp(str, pat) == 0) +			return 1; +		break; +	case H_MATCH_SUBSTR: +		if (strstr(str, pat)) +			return 1; +		break; +#ifdef CONFIG_REGEX +	case H_MATCH_REGEX: +		{ +			struct slre *slrep = (struct slre *)priv; +			struct cap caps[slrep->num_caps + 2]; + +			if (slre_match(slrep, str, strlen(str), caps)) +				return 1; +		} +		break; +#endif +	default: +		printf("## ERROR: unsupported match method: 0x%02x\n", +			flag & H_MATCH_METHOD); +		break; +	} +	return 0; +} + +static int match_entry(ENTRY *ep, int flag, +		 int argc, char * const argv[]) +{ +	int arg; +	void *priv = NULL; + +	for (arg = 1; arg < argc; ++arg) { +#ifdef CONFIG_REGEX +		struct slre slre; + +		if (slre_compile(&slre, argv[arg]) == 0) { +			printf("Error compiling regex: %s\n", slre.err_str); +			return 0; +		} + +		priv = (void *)&slre; +#endif +		if (flag & H_MATCH_KEY) { +			if (match_string(flag, ep->key, argv[arg], priv)) +				return 1; +		} +		if (flag & H_MATCH_DATA) { +			if (match_string(flag, ep->data, argv[arg], priv)) +				return 1; +		} +	} +	return 0; +} +  ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag,  		 char **resp, size_t size,  		 int argc, char * const argv[]) @@ -589,14 +626,8 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag,  		if (htab->table[i].used > 0) {  			ENTRY *ep = &htab->table[i].entry; -			int arg, found = 0; +			int found = match_entry(ep, flag, argc, argv); -			for (arg = 0; arg < argc; ++arg) { -				if (strcmp(argv[arg], ep->key) == 0) { -					found = 1; -					break; -				} -			}  			if ((argc > 0) && (found == 0))  				continue; diff --git a/lib/slre.c b/lib/slre.c new file mode 100644 index 000000000..8cdd192ea --- /dev/null +++ b/lib/slre.c @@ -0,0 +1,724 @@ +/* + * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> + * All rights reserved + * + * "THE BEER-WARE LICENSE" (Revision 42): + * Sergey Lyubka wrote this file.  As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. + */ + +/* + * Downloaded Sat Nov  5 17:43:06 CET 2011 at + * http://slre.sourceforge.net/1.0/slre.c + */ + +#ifdef SLRE_TEST +#include <stdio.h> +#include <assert.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#else +#include <common.h> +#include <linux/ctype.h> +#endif /* SLRE_TEST */ + +#include <errno.h> + +#include <slre.h> + +enum {END, BRANCH, ANY, EXACT, ANYOF, ANYBUT, OPEN, CLOSE, BOL, EOL, +	STAR, PLUS, STARQ, PLUSQ, QUEST, SPACE, NONSPACE, DIGIT}; + +#ifdef SLRE_TEST +static struct { +	const char	*name; +	int		narg; +	const char	*flags; +} opcodes[] = { +	{"END",		0, ""},		/* End of code block or program	*/ +	{"BRANCH",	2, "oo"},	/* Alternative operator, "|"	*/ +	{"ANY",		0, ""},		/* Match any character, "."	*/ +	{"EXACT",	2, "d"},	/* Match exact string		*/ +	{"ANYOF",	2, "D"},	/* Match any from set, "[]"	*/ +	{"ANYBUT",	2, "D"},	/* Match any but from set, "[^]"*/ +	{"OPEN ",	1, "i"},	/* Capture start, "("		*/ +	{"CLOSE",	1, "i"},	/* Capture end, ")"		*/ +	{"BOL",		0, ""},		/* Beginning of string, "^"	*/ +	{"EOL",		0, ""},		/* End of string, "$"		*/ +	{"STAR",	1, "o"},	/* Match zero or more times "*"	*/ +	{"PLUS",	1, "o"},	/* Match one or more times, "+"	*/ +	{"STARQ",	1, "o"},	/* Non-greedy STAR,  "*?"	*/ +	{"PLUSQ",	1, "o"},	/* Non-greedy PLUS, "+?"	*/ +	{"QUEST",	1, "o"},	/* Match zero or one time, "?"	*/ +	{"SPACE",	0, ""},		/* Match whitespace, "\s"	*/ +	{"NONSPACE",	0, ""},		/* Match non-space, "\S"	*/ +	{"DIGIT",	0, ""}		/* Match digit, "\d"		*/ +}; +#endif /* SLRE_TEST */ + +/* + * Commands and operands are all unsigned char (1 byte long). All code offsets + * are relative to current address, and positive (always point forward). Data + * offsets are absolute. Commands with operands: + * + * BRANCH offset1 offset2 + *	Try to match the code block that follows the BRANCH instruction + *	(code block ends with END). If no match, try to match code block that + *	starts at offset1. If either of these match, jump to offset2. + * + * EXACT data_offset data_length + *	Try to match exact string. String is recorded in data section from + *	data_offset, and has length data_length. + * + * OPEN capture_number + * CLOSE capture_number + *	If the user have passed 'struct cap' array for captures, OPEN + *	records the beginning of the matched substring (cap->ptr), CLOSE + *	sets the length (cap->len) for respective capture_number. + * + * STAR code_offset + * PLUS code_offset + * QUEST code_offset + *	*, +, ?, respectively. Try to gobble as much as possible from the + *	matched buffer, until code block that follows these instructions + *	matches. When the longest possible string is matched, + *	jump to code_offset + * + * STARQ, PLUSQ are non-greedy versions of STAR and PLUS. + */ + +static const char *meta_chars = "|.^$*+?()[\\"; + +#ifdef SLRE_TEST + +static void +print_character_set(FILE *fp, const unsigned char *p, int len) +{ +	int	i; + +	for (i = 0; i < len; i++) { +		if (i > 0) +			(void) fputc(',', fp); +		if (p[i] == 0) { +			i++; +			if (p[i] == 0) +				(void) fprintf(fp, "\\x%02x", p[i]); +			else +				(void) fprintf(fp, "%s", opcodes[p[i]].name); +		} else if (isprint(p[i])) { +			(void) fputc(p[i], fp); +		} else { +			(void) fprintf(fp, "\\x%02x", p[i]); +		} +	} +} + +void +slre_dump(const struct slre *r, FILE *fp) +{ +	int	i, j, ch, op, pc; + +	for (pc = 0; pc < r->code_size; pc++) { + +		op = r->code[pc]; +		(void) fprintf(fp, "%3d %s ", pc, opcodes[op].name); + +		for (i = 0; opcodes[op].flags[i] != '\0'; i++) +			switch (opcodes[op].flags[i]) { +			case 'i': +				(void) fprintf(fp, "%d ", r->code[pc + 1]); +				pc++; +				break; +			case 'o': +				(void) fprintf(fp, "%d ", +				    pc + r->code[pc + 1] - i); +				pc++; +				break; +			case 'D': +				print_character_set(fp, r->data + +				    r->code[pc + 1], r->code[pc + 2]); +				pc += 2; +				break; +			case 'd': +				(void) fputc('"', fp); +				for (j = 0; j < r->code[pc + 2]; j++) { +					ch = r->data[r->code[pc + 1] + j]; +					if (isprint(ch)) { +						(void) fputc(ch, fp); +					} else { +						(void) fprintf(fp, +							"\\x%02x", ch); +					} +				} +				(void) fputc('"', fp); +				pc += 2; +				break; +			} + +		(void) fputc('\n', fp); +	} +} +#endif /* SLRE_TEST */ + +static void +set_jump_offset(struct slre *r, int pc, int offset) +{ +	assert(offset < r->code_size); + +	if (r->code_size - offset > 0xff) +		r->err_str = "Jump offset is too big"; +	else +		r->code[pc] = (unsigned char) (r->code_size - offset); +} + +static void +emit(struct slre *r, int code) +{ +	if (r->code_size >= (int) (sizeof(r->code) / sizeof(r->code[0]))) +		r->err_str = "RE is too long (code overflow)"; +	else +		r->code[r->code_size++] = (unsigned char) code; +} + +static void +store_char_in_data(struct slre *r, int ch) +{ +	if (r->data_size >= (int) sizeof(r->data)) +		r->err_str = "RE is too long (data overflow)"; +	else +		r->data[r->data_size++] = ch; +} + +static void +exact(struct slre *r, const char **re) +{ +	int	old_data_size = r->data_size; + +	while (**re != '\0' && (strchr(meta_chars, **re)) == NULL) +		store_char_in_data(r, *(*re)++); + +	emit(r, EXACT); +	emit(r, old_data_size); +	emit(r, r->data_size - old_data_size); +} + +static int +get_escape_char(const char **re) +{ +	int	res; + +	switch (*(*re)++) { +	case 'n': +		res = '\n'; +		break; +	case 'r': +		res = '\r'; +		break; +	case 't': +		res = '\t'; +		break; +	case '0': +		res = 0; +		break; +	case 'S': +		res = NONSPACE << 8; +		break; +	case 's': +		res = SPACE << 8; +		break; +	case 'd': +		res = DIGIT << 8; +		break; +	default: +		res = (*re)[-1]; +		break; +	} + +	return res; +} + +static void +anyof(struct slre *r, const char **re) +{ +	int	esc, old_data_size = r->data_size, op = ANYOF; + +	if (**re == '^') { +		op = ANYBUT; +		(*re)++; +	} + +	while (**re != '\0') + +		switch (*(*re)++) { +		case ']': +			emit(r, op); +			emit(r, old_data_size); +			emit(r, r->data_size - old_data_size); +			return; +			/* NOTREACHED */ +			break; +		case '\\': +			esc = get_escape_char(re); +			if ((esc & 0xff) == 0) { +				store_char_in_data(r, 0); +				store_char_in_data(r, esc >> 8); +			} else { +				store_char_in_data(r, esc); +			} +			break; +		default: +			store_char_in_data(r, (*re)[-1]); +			break; +		} + +	r->err_str = "No closing ']' bracket"; +} + +static void +relocate(struct slre *r, int begin, int shift) +{ +	emit(r, END); +	memmove(r->code + begin + shift, r->code + begin, r->code_size - begin); +	r->code_size += shift; +} + +static void +quantifier(struct slre *r, int prev, int op) +{ +	if (r->code[prev] == EXACT && r->code[prev + 2] > 1) { +		r->code[prev + 2]--; +		emit(r, EXACT); +		emit(r, r->code[prev + 1] + r->code[prev + 2]); +		emit(r, 1); +		prev = r->code_size - 3; +	} +	relocate(r, prev, 2); +	r->code[prev] = op; +	set_jump_offset(r, prev + 1, prev); +} + +static void +exact_one_char(struct slre *r, int ch) +{ +	emit(r, EXACT); +	emit(r, r->data_size); +	emit(r, 1); +	store_char_in_data(r, ch); +} + +static void +fixup_branch(struct slre *r, int fixup) +{ +	if (fixup > 0) { +		emit(r, END); +		set_jump_offset(r, fixup, fixup - 2); +	} +} + +static void +compile(struct slre *r, const char **re) +{ +	int	op, esc, branch_start, last_op, fixup, cap_no, level; + +	fixup = 0; +	level = r->num_caps; +	branch_start = last_op = r->code_size; + +	for (;;) +		switch (*(*re)++) { +		case '\0': +			(*re)--; +			return; +			/* NOTREACHED */ +			break; +		case '^': +			emit(r, BOL); +			break; +		case '$': +			emit(r, EOL); +			break; +		case '.': +			last_op = r->code_size; +			emit(r, ANY); +			break; +		case '[': +			last_op = r->code_size; +			anyof(r, re); +			break; +		case '\\': +			last_op = r->code_size; +			esc = get_escape_char(re); +			if (esc & 0xff00) +				emit(r, esc >> 8); +			else +				exact_one_char(r, esc); +			break; +		case '(': +			last_op = r->code_size; +			cap_no = ++r->num_caps; +			emit(r, OPEN); +			emit(r, cap_no); + +			compile(r, re); +			if (*(*re)++ != ')') { +				r->err_str = "No closing bracket"; +				return; +			} + +			emit(r, CLOSE); +			emit(r, cap_no); +			break; +		case ')': +			(*re)--; +			fixup_branch(r, fixup); +			if (level == 0) { +				r->err_str = "Unbalanced brackets"; +				return; +			} +			return; +			/* NOTREACHED */ +			break; +		case '+': +		case '*': +			op = (*re)[-1] == '*' ? STAR : PLUS; +			if (**re == '?') { +				(*re)++; +				op = op == STAR ? STARQ : PLUSQ; +			} +			quantifier(r, last_op, op); +			break; +		case '?': +			quantifier(r, last_op, QUEST); +			break; +		case '|': +			fixup_branch(r, fixup); +			relocate(r, branch_start, 3); +			r->code[branch_start] = BRANCH; +			set_jump_offset(r, branch_start + 1, branch_start); +			fixup = branch_start + 2; +			r->code[fixup] = 0xff; +			break; +		default: +			(*re)--; +			last_op = r->code_size; +			exact(r, re); +			break; +		} +} + +int +slre_compile(struct slre *r, const char *re) +{ +	r->err_str = NULL; +	r->code_size = r->data_size = r->num_caps = r->anchored = 0; + +	if (*re == '^') +		r->anchored++; + +	emit(r, OPEN);	/* This will capture what matches full RE */ +	emit(r, 0); + +	while (*re != '\0') +		compile(r, &re); + +	if (r->code[2] == BRANCH) +		fixup_branch(r, 4); + +	emit(r, CLOSE); +	emit(r, 0); +	emit(r, END); + +	return (r->err_str == NULL ? 1 : 0); +} + +static int match(const struct slre *, int, +		const char *, int, int *, struct cap *); + +static void +loop_greedy(const struct slre *r, int pc, const char *s, int len, int *ofs) +{ +	int	saved_offset, matched_offset; + +	saved_offset = matched_offset = *ofs; + +	while (match(r, pc + 2, s, len, ofs, NULL)) { +		saved_offset = *ofs; +		if (match(r, pc + r->code[pc + 1], s, len, ofs, NULL)) +			matched_offset = saved_offset; +		*ofs = saved_offset; +	} + +	*ofs = matched_offset; +} + +static void +loop_non_greedy(const struct slre *r, int pc, const char *s, int len, int *ofs) +{ +	int	saved_offset = *ofs; + +	while (match(r, pc + 2, s, len, ofs, NULL)) { +		saved_offset = *ofs; +		if (match(r, pc + r->code[pc + 1], s, len, ofs, NULL)) +			break; +	} + +	*ofs = saved_offset; +} + +static int +is_any_of(const unsigned char *p, int len, const char *s, int *ofs) +{ +	int	i, ch; + +	ch = s[*ofs]; + +	for (i = 0; i < len; i++) +		if (p[i] == ch) { +			(*ofs)++; +			return 1; +		} + +	return 0; +} + +static int +is_any_but(const unsigned char *p, int len, const char *s, int *ofs) +{ +	int	i, ch; + +	ch = s[*ofs]; + +	for (i = 0; i < len; i++) { +		if (p[i] == ch) +			return 0; +	} + +	(*ofs)++; +	return 1; +} + +static int +match(const struct slre *r, int pc, const char *s, int len, +		int *ofs, struct cap *caps) +{ +	int	n, saved_offset, res = 1; + +	while (res && r->code[pc] != END) { + +		assert(pc < r->code_size); +		assert(pc < (int) (sizeof(r->code) / sizeof(r->code[0]))); + +		switch (r->code[pc]) { +		case BRANCH: +			saved_offset = *ofs; +			res = match(r, pc + 3, s, len, ofs, caps); +			if (res == 0) { +				*ofs = saved_offset; +				res = match(r, pc + r->code[pc + 1], +				    s, len, ofs, caps); +			} +			pc += r->code[pc + 2]; +			break; +		case EXACT: +			res = 0; +			n = r->code[pc + 2];	/* String length */ +			if (n <= len - *ofs && !memcmp(s + *ofs, r->data + +			    r->code[pc + 1], n)) { +				(*ofs) += n; +				res = 1; +			} +			pc += 3; +			break; +		case QUEST: +			res = 1; +			saved_offset = *ofs; +			if (!match(r, pc + 2, s, len, ofs, caps)) +				*ofs = saved_offset; +			pc += r->code[pc + 1]; +			break; +		case STAR: +			res = 1; +			loop_greedy(r, pc, s, len, ofs); +			pc += r->code[pc + 1]; +			break; +		case STARQ: +			res = 1; +			loop_non_greedy(r, pc, s, len, ofs); +			pc += r->code[pc + 1]; +			break; +		case PLUS: +			res = match(r, pc + 2, s, len, ofs, caps); +			if (res == 0) +				break; + +			loop_greedy(r, pc, s, len, ofs); +			pc += r->code[pc + 1]; +			break; +		case PLUSQ: +			res = match(r, pc + 2, s, len, ofs, caps); +			if (res == 0) +				break; + +			loop_non_greedy(r, pc, s, len, ofs); +			pc += r->code[pc + 1]; +			break; +		case SPACE: +			res = 0; +			if (*ofs < len && isspace(((unsigned char *)s)[*ofs])) { +				(*ofs)++; +				res = 1; +			} +			pc++; +			break; +		case NONSPACE: +			res = 0; +			if (*ofs < len && +					!isspace(((unsigned char *)s)[*ofs])) { +				(*ofs)++; +				res = 1; +			} +			pc++; +			break; +		case DIGIT: +			res = 0; +			if (*ofs < len && isdigit(((unsigned char *)s)[*ofs])) { +				(*ofs)++; +				res = 1; +			} +			pc++; +			break; +		case ANY: +			res = 0; +			if (*ofs < len) { +				(*ofs)++; +				res = 1; +			} +			pc++; +			break; +		case ANYOF: +			res = 0; +			if (*ofs < len) +				res = is_any_of(r->data + r->code[pc + 1], +					r->code[pc + 2], s, ofs); +			pc += 3; +			break; +		case ANYBUT: +			res = 0; +			if (*ofs < len) +				res = is_any_but(r->data + r->code[pc + 1], +					r->code[pc + 2], s, ofs); +			pc += 3; +			break; +		case BOL: +			res = *ofs == 0 ? 1 : 0; +			pc++; +			break; +		case EOL: +			res = *ofs == len ? 1 : 0; +			pc++; +			break; +		case OPEN: +			if (caps != NULL) +				caps[r->code[pc + 1]].ptr = s + *ofs; +			pc += 2; +			break; +		case CLOSE: +			if (caps != NULL) +				caps[r->code[pc + 1]].len = (s + *ofs) - +				    caps[r->code[pc + 1]].ptr; +			pc += 2; +			break; +		case END: +			pc++; +			break; +		default: +			printf("unknown cmd (%d) at %d\n", r->code[pc], pc); +			assert(0); +			break; +		} +	} + +	return res; +} + +int +slre_match(const struct slre *r, const char *buf, int len, +		struct cap *caps) +{ +	int	i, ofs = 0, res = 0; + +	if (r->anchored) { +		res = match(r, 0, buf, len, &ofs, caps); +	} else { +		for (i = 0; i < len && res == 0; i++) { +			ofs = i; +			res = match(r, 0, buf, len, &ofs, caps); +		} +	} + +	return res; +} + +#ifdef SLRE_TEST +#define N_CAPS	5 + +int main(int argc, char *argv[]) +{ +	struct slre	slre; +	struct cap	caps[N_CAPS]; +	unsigned char	data[1 * 1024 * 1024]; +	FILE		*fp; +	int		i, res, len; + +	if (argc < 2) { +		fprintf(stderr, "Usage: %s 'slre' <file>\n", argv[0]); +		return 1; +	} + +	fp = fopen(argv[2], "rb"); +	if (fp == NULL) { +		fprintf(stderr, "Error: cannot open %s:%s\n", +			argv[2], strerror(errno)); +		return 1; +	} + +	if (!slre_compile(&slre, argv[1])) { +		fprintf(stderr, "Error compiling slre: %s\n", slre.err_str); +		return 1; +	} +	 +	slre_dump(&slre, stderr); + +	while (fgets(data, sizeof(data), fp) != NULL) { +		len = strlen(data); + +		if ((len > 0) && (data[len-1] == '\n')) { +			data[len-1] = '\0'; +			--len; +		} + +		printf("Data = \"%s\"\n", data); + +		(void) memset(caps, 0, sizeof(caps)); + +		res = 0; + +		res = slre_match(&slre, data, len, caps); +		printf("Result [%d]: %d\n", i, res); + +		for (i = 0; i < N_CAPS; i++) { +			if (caps[i].len > 0) { +				printf("Substring %d: len=%d  [%.*s]\n", i, +					caps[i].len, +					caps[i].len, caps[i].ptr); +			} +		} +		printf("----------------------------------------------------\n"); +	} +	(void) fclose(fp); + +	return 0; +} +#endif /* SLRE_TEST */ diff --git a/lib/tpm.c b/lib/tpm.c new file mode 100644 index 000000000..42c9bea0f --- /dev/null +++ b/lib/tpm.c @@ -0,0 +1,581 @@ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <common.h> +#include <stdarg.h> +#include <tpm.h> +#include <asm/unaligned.h> + +/* Internal error of TPM command library */ +#define TPM_LIB_ERROR	((uint32_t)~0u) + +/* Useful constants */ +enum { +	COMMAND_BUFFER_SIZE		= 256, +	TPM_PUBEK_SIZE			= 256, +	TPM_REQUEST_HEADER_LENGTH	= 10, +	TPM_RESPONSE_HEADER_LENGTH	= 10, +	PCR_DIGEST_LENGTH		= 20, +}; + +/** + * Pack data into a byte string.  The data types are specified in + * the format string: 'b' means unsigned byte, 'w' unsigned word, + * 'd' unsigned double word, and 's' byte string.  The data are a + * series of offsets and values (for type byte string there are also + * lengths).  The data values are packed into the byte string + * sequentially, and so a latter value could over-write a former + * value. + * + * @param str		output string + * @param size		size of output string + * @param format	format string + * @param ...		data points + * @return 0 on success, non-0 on error + */ +int pack_byte_string(uint8_t *str, size_t size, const char *format, ...) +{ +	va_list args; +	size_t offset = 0, length = 0; +	uint8_t *data = NULL; +	uint32_t value = 0; + +	va_start(args, format); +	for (; *format; format++) { +		switch (*format) { +		case 'b': +			offset = va_arg(args, size_t); +			value = va_arg(args, int); +			length = 1; +			break; +		case 'w': +			offset = va_arg(args, size_t); +			value = va_arg(args, int); +			length = 2; +			break; +		case 'd': +			offset = va_arg(args, size_t); +			value = va_arg(args, uint32_t); +			length = 4; +			break; +		case 's': +			offset = va_arg(args, size_t); +			data = va_arg(args, uint8_t *); +			length = va_arg(args, uint32_t); +			break; +		default: +			debug("Couldn't recognize format string\n"); +			return -1; +		} + +		if (offset + length > size) +			return -1; + +		switch (*format) { +		case 'b': +			str[offset] = value; +			break; +		case 'w': +			put_unaligned_be16(value, str + offset); +			break; +		case 'd': +			put_unaligned_be32(value, str + offset); +			break; +		case 's': +			memcpy(str + offset, data, length); +			break; +		} +	} +	va_end(args); + +	return 0; +} + +/** + * Unpack data from a byte string.  The data types are specified in + * the format string: 'b' means unsigned byte, 'w' unsigned word, + * 'd' unsigned double word, and 's' byte string.  The data are a + * series of offsets and pointers (for type byte string there are also + * lengths). + * + * @param str		output string + * @param size		size of output string + * @param format	format string + * @param ...		data points + * @return 0 on success, non-0 on error + */ +int unpack_byte_string(const uint8_t *str, size_t size, const char *format, ...) +{ +	va_list args; +	size_t offset = 0, length = 0; +	uint8_t *ptr8 = NULL; +	uint16_t *ptr16 = NULL; +	uint32_t *ptr32 = NULL; + +	va_start(args, format); +	for (; *format; format++) { +		switch (*format) { +		case 'b': +			offset = va_arg(args, size_t); +			ptr8 = va_arg(args, uint8_t *); +			length = 1; +			break; +		case 'w': +			offset = va_arg(args, size_t); +			ptr16 = va_arg(args, uint16_t *); +			length = 2; +			break; +		case 'd': +			offset = va_arg(args, size_t); +			ptr32 = va_arg(args, uint32_t *); +			length = 4; +			break; +		case 's': +			offset = va_arg(args, size_t); +			ptr8 = va_arg(args, uint8_t *); +			length = va_arg(args, uint32_t); +			break; +		default: +			debug("Couldn't recognize format string\n"); +			return -1; +		} + +		if (offset + length > size) +			return -1; + +		switch (*format) { +		case 'b': +			*ptr8 = str[offset]; +			break; +		case 'w': +			*ptr16 = get_unaligned_be16(str + offset); +			break; +		case 'd': +			*ptr32 = get_unaligned_be32(str + offset); +			break; +		case 's': +			memcpy(ptr8, str + offset, length); +			break; +		} +	} +	va_end(args); + +	return 0; +} + +/** + * Get TPM command size. + * + * @param command	byte string of TPM command + * @return command size of the TPM command + */ +static uint32_t tpm_command_size(const void *command) +{ +	const size_t command_size_offset = 2; +	return get_unaligned_be32(command + command_size_offset); +} + +/** + * Get TPM response return code, which is one of TPM_RESULT values. + * + * @param response	byte string of TPM response + * @return return code of the TPM response + */ +static uint32_t tpm_return_code(const void *response) +{ +	const size_t return_code_offset = 6; +	return get_unaligned_be32(response + return_code_offset); +} + +/** + * Send a TPM command and return response's return code, and optionally + * return response to caller. + * + * @param command	byte string of TPM command + * @param response	output buffer for TPM response, or NULL if the + *			caller does not care about it + * @param size_ptr	output buffer size (input parameter) and TPM + *			response length (output parameter); this parameter + *			is a bidirectional + * @return return code of the TPM response + */ +static uint32_t tpm_sendrecv_command(const void *command, +		void *response, size_t *size_ptr) +{ +	uint8_t response_buffer[COMMAND_BUFFER_SIZE]; +	size_t response_length; +	uint32_t err; + +	if (response) { +		response_length = *size_ptr; +	} else { +		response = response_buffer; +		response_length = sizeof(response_buffer); +	} +	err = tis_sendrecv(command, tpm_command_size(command), +			response, &response_length); +	if (err) +		return TPM_LIB_ERROR; +	if (response) +		*size_ptr = response_length; + +	return tpm_return_code(response); +} + +uint32_t tpm_init(void) +{ +	uint32_t err; + +	err = tis_init(); +	if (err) +		return err; + +	return tis_open(); +} + +uint32_t tpm_startup(enum tpm_startup_type mode) +{ +	const uint8_t command[12] = { +		0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0, +	}; +	const size_t mode_offset = 10; +	uint8_t buf[COMMAND_BUFFER_SIZE]; + +	if (pack_byte_string(buf, sizeof(buf), "sw", +				0, command, sizeof(command), +				mode_offset, mode)) +		return TPM_LIB_ERROR; + +	return tpm_sendrecv_command(buf, NULL, NULL); +} + +uint32_t tpm_self_test_full(void) +{ +	const uint8_t command[10] = { +		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50, +	}; +	return tpm_sendrecv_command(command, NULL, NULL); +} + +uint32_t tpm_continue_self_test(void) +{ +	const uint8_t command[10] = { +		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53, +	}; +	return tpm_sendrecv_command(command, NULL, NULL); +} + +uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size) +{ +	const uint8_t command[101] = { +		0x0, 0xc1,		/* TPM_TAG */ +		0x0, 0x0, 0x0, 0x65,	/* parameter size */ +		0x0, 0x0, 0x0, 0xcc,	/* TPM_COMMAND_CODE */ +		/* TPM_NV_DATA_PUBLIC->... */ +		0x0, 0x18,		/* ...->TPM_STRUCTURE_TAG */ +		0, 0, 0, 0,		/* ...->TPM_NV_INDEX */ +		/* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */ +		0x0, 0x3, +		0, 0, 0, +		0x1f, +		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +		/* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */ +		0x0, 0x3, +		0, 0, 0, +		0x1f, +		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +		/* TPM_NV_ATTRIBUTES->... */ +		0x0, 0x17,		/* ...->TPM_STRUCTURE_TAG */ +		0, 0, 0, 0,		/* ...->attributes */ +		/* End of TPM_NV_ATTRIBUTES */ +		0,			/* bReadSTClear */ +		0,			/* bWriteSTClear */ +		0,			/* bWriteDefine */ +		0, 0, 0, 0,		/* size */ +	}; +	const size_t index_offset = 12; +	const size_t perm_offset = 70; +	const size_t size_offset = 77; +	uint8_t buf[COMMAND_BUFFER_SIZE]; + +	if (pack_byte_string(buf, sizeof(buf), "sddd", +				0, command, sizeof(command), +				index_offset, index, +				perm_offset, perm, +				size_offset, size)) +		return TPM_LIB_ERROR; + +	return tpm_sendrecv_command(buf, NULL, NULL); +} + +uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count) +{ +	const uint8_t command[22] = { +		0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf, +	}; +	const size_t index_offset = 10; +	const size_t length_offset = 18; +	const size_t data_size_offset = 10; +	const size_t data_offset = 14; +	uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; +	size_t response_length = sizeof(response); +	uint32_t data_size; +	uint32_t err; + +	if (pack_byte_string(buf, sizeof(buf), "sdd", +				0, command, sizeof(command), +				index_offset, index, +				length_offset, count)) +		return TPM_LIB_ERROR; +	err = tpm_sendrecv_command(buf, response, &response_length); +	if (err) +		return err; +	if (unpack_byte_string(response, response_length, "d", +				data_size_offset, &data_size)) +		return TPM_LIB_ERROR; +	if (data_size > count) +		return TPM_LIB_ERROR; +	if (unpack_byte_string(response, response_length, "s", +				data_offset, data, data_size)) +		return TPM_LIB_ERROR; + +	return 0; +} + +uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length) +{ +	const uint8_t command[256] = { +		0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd, +	}; +	const size_t command_size_offset = 2; +	const size_t index_offset = 10; +	const size_t length_offset = 18; +	const size_t data_offset = 22; +	const size_t write_info_size = 12; +	const uint32_t total_length = +		TPM_REQUEST_HEADER_LENGTH + write_info_size + length; +	uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; +	size_t response_length = sizeof(response); +	uint32_t err; + +	if (pack_byte_string(buf, sizeof(buf), "sddds", +				0, command, sizeof(command), +				command_size_offset, total_length, +				index_offset, index, +				length_offset, length, +				data_offset, data, length)) +		return TPM_LIB_ERROR; +	err = tpm_sendrecv_command(buf, response, &response_length); +	if (err) +		return err; + +	return 0; +} + +uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest) +{ +	const uint8_t command[34] = { +		0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14, +	}; +	const size_t index_offset = 10; +	const size_t in_digest_offset = 14; +	const size_t out_digest_offset = 10; +	uint8_t buf[COMMAND_BUFFER_SIZE]; +	uint8_t response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH]; +	size_t response_length = sizeof(response); +	uint32_t err; + +	if (pack_byte_string(buf, sizeof(buf), "sds", +				0, command, sizeof(command), +				index_offset, index, +				in_digest_offset, in_digest, +				PCR_DIGEST_LENGTH)) +		return TPM_LIB_ERROR; +	err = tpm_sendrecv_command(buf, response, &response_length); +	if (err) +		return err; + +	if (unpack_byte_string(response, response_length, "s", +				out_digest_offset, out_digest, +				PCR_DIGEST_LENGTH)) +		return TPM_LIB_ERROR; + +	return 0; +} + +uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count) +{ +	const uint8_t command[14] = { +		0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15, +	}; +	const size_t index_offset = 10; +	const size_t out_digest_offset = 10; +	uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; +	size_t response_length = sizeof(response); +	uint32_t err; + +	if (count < PCR_DIGEST_LENGTH) +		return TPM_LIB_ERROR; + +	if (pack_byte_string(buf, sizeof(buf), "sd", +				0, command, sizeof(command), +				index_offset, index)) +		return TPM_LIB_ERROR; +	err = tpm_sendrecv_command(buf, response, &response_length); +	if (err) +		return err; +	if (unpack_byte_string(response, response_length, "s", +				out_digest_offset, data, PCR_DIGEST_LENGTH)) +		return TPM_LIB_ERROR; + +	return 0; +} + +uint32_t tpm_tsc_physical_presence(uint16_t presence) +{ +	const uint8_t command[12] = { +		0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0, +	}; +	const size_t presence_offset = 10; +	uint8_t buf[COMMAND_BUFFER_SIZE]; + +	if (pack_byte_string(buf, sizeof(buf), "sw", +				0, command, sizeof(command), +				presence_offset, presence)) +		return TPM_LIB_ERROR; + +	return tpm_sendrecv_command(buf, NULL, NULL); +} + +uint32_t tpm_read_pubek(void *data, size_t count) +{ +	const uint8_t command[30] = { +		0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c, +	}; +	const size_t response_size_offset = 2; +	const size_t data_offset = 10; +	const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20; +	uint8_t response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE]; +	size_t response_length = sizeof(response); +	uint32_t data_size; +	uint32_t err; + +	err = tpm_sendrecv_command(command, response, &response_length); +	if (err) +		return err; +	if (unpack_byte_string(response, response_length, "d", +				response_size_offset, &data_size)) +		return TPM_LIB_ERROR; +	if (data_size < header_and_checksum_size) +		return TPM_LIB_ERROR; +	data_size -= header_and_checksum_size; +	if (data_size > count) +		return TPM_LIB_ERROR; +	if (unpack_byte_string(response, response_length, "s", +				data_offset, data, data_size)) +		return TPM_LIB_ERROR; + +	return 0; +} + +uint32_t tpm_force_clear(void) +{ +	const uint8_t command[10] = { +		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d, +	}; + +	return tpm_sendrecv_command(command, NULL, NULL); +} + +uint32_t tpm_physical_enable(void) +{ +	const uint8_t command[10] = { +		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f, +	}; + +	return tpm_sendrecv_command(command, NULL, NULL); +} + +uint32_t tpm_physical_disable(void) +{ +	const uint8_t command[10] = { +		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70, +	}; + +	return tpm_sendrecv_command(command, NULL, NULL); +} + +uint32_t tpm_physical_set_deactivated(uint8_t state) +{ +	const uint8_t command[11] = { +		0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72, +	}; +	const size_t state_offset = 10; +	uint8_t buf[COMMAND_BUFFER_SIZE]; + +	if (pack_byte_string(buf, sizeof(buf), "sb", +				0, command, sizeof(command), +				state_offset, state)) +		return TPM_LIB_ERROR; + +	return tpm_sendrecv_command(buf, NULL, NULL); +} + +uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap, +		void *cap, size_t count) +{ +	const uint8_t command[22] = { +		0x0, 0xc1,		/* TPM_TAG */ +		0x0, 0x0, 0x0, 0x16,	/* parameter size */ +		0x0, 0x0, 0x0, 0x65,	/* TPM_COMMAND_CODE */ +		0x0, 0x0, 0x0, 0x0,	/* TPM_CAPABILITY_AREA */ +		0x0, 0x0, 0x0, 0x4,	/* subcap size */ +		0x0, 0x0, 0x0, 0x0,	/* subcap value */ +	}; +	const size_t cap_area_offset = 10; +	const size_t sub_cap_offset = 18; +	const size_t cap_offset = 14; +	const size_t cap_size_offset = 10; +	uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; +	size_t response_length = sizeof(response); +	uint32_t cap_size; +	uint32_t err; + +	if (pack_byte_string(buf, sizeof(buf), "sdd", +				0, command, sizeof(command), +				cap_area_offset, cap_area, +				sub_cap_offset, sub_cap)) +		return TPM_LIB_ERROR; +	err = tpm_sendrecv_command(buf, response, &response_length); +	if (err) +		return err; +	if (unpack_byte_string(response, response_length, "d", +				cap_size_offset, &cap_size)) +		return TPM_LIB_ERROR; +	if (cap_size > response_length || cap_size > count) +		return TPM_LIB_ERROR; +	if (unpack_byte_string(response, response_length, "s", +				cap_offset, cap, cap_size)) +		return TPM_LIB_ERROR; + +	return 0; +} |