diff --git a/src/drivers/i2c/tpm/Makefile.inc b/src/drivers/i2c/tpm/Makefile.inc index e06097f774..55c01def17 100644 --- a/src/drivers/i2c/tpm/Makefile.inc +++ b/src/drivers/i2c/tpm/Makefile.inc @@ -1,2 +1,3 @@ ramstage-$(CONFIG_I2C_TPM) += tis.c tpm.c romstage-$(CONFIG_I2C_TPM) += tis.c tpm.c +verstage-$(CONFIG_I2C_TPM) += tis.c tpm.c \ No newline at end of file diff --git a/src/include/antirollback.h b/src/include/antirollback.h index dd0de32aef..0473e2446c 100644 --- a/src/include/antirollback.h +++ b/src/include/antirollback.h @@ -6,133 +6,39 @@ * stored in the TPM NVRAM. */ -#ifndef VBOOT_REFERENCE_ROLLBACK_INDEX_H_ -#define VBOOT_REFERENCE_ROLLBACK_INDEX_H_ +#ifndef ANTIROLLBACK_H_ +#define ANTIROLLBACK_H_ -#include "sysincludes.h" -#include "tss_constants.h" +#include "2sysincludes.h" +#include <2api.h> +#include "tpm_lite/tss_constants.h" /* TPM NVRAM location indices. */ #define FIRMWARE_NV_INDEX 0x1007 -#define KERNEL_NV_INDEX 0x1008 -/* This is just an opaque space for backup purposes */ -#define BACKUP_NV_INDEX 0x1009 -#define BACKUP_NV_SIZE 16 - /* Structure definitions for TPM spaces */ -/* Kernel space - KERNEL_NV_INDEX, locked with physical presence. */ -#define ROLLBACK_SPACE_KERNEL_VERSION 2 -#define ROLLBACK_SPACE_KERNEL_UID 0x4752574C /* 'GRWL' */ - -typedef struct RollbackSpaceKernel { - /* Struct version, for backwards compatibility */ - uint8_t struct_version; - /* Unique ID to detect space redefinition */ - uint32_t uid; - /* Kernel versions */ - uint32_t kernel_versions; - /* Reserved for future expansion */ - uint8_t reserved[3]; - /* Checksum (v2 and later only) */ - uint8_t crc8; -} __attribute__((packed)) RollbackSpaceKernel; - /* Flags for firmware space */ + /* * Last boot was developer mode. TPM ownership is cleared when transitioning * to/from developer mode. */ #define FLAG_LAST_BOOT_DEVELOPER 0x01 -/* - * Some systems may not have a dedicated dev-mode switch, but enter and leave - * dev-mode through some recovery-mode magic keypresses. For those systems, the - * dev-mode "switch" state is in this bit (0=normal, 1=dev). To make it work, a - * new flag is passed to VbInit(), indicating that the system lacks a physical - * dev-mode switch. If a physical switch is present, this bit is ignored. - */ -#define FLAG_VIRTUAL_DEV_MODE_ON 0x02 - -/* Firmware space - FIRMWARE_NV_INDEX, locked with global lock. */ -#define ROLLBACK_SPACE_FIRMWARE_VERSION 2 - -typedef struct RollbackSpaceFirmware { - /* Struct version, for backwards compatibility */ - uint8_t struct_version; - /* Flags (see FLAG_* above) */ - uint8_t flags; - /* Firmware versions */ - uint32_t fw_versions; - /* Reserved for future expansion */ - uint8_t reserved[3]; - /* Checksum (v2 and later only) */ - uint8_t crc8; -} __attribute__((packed)) RollbackSpaceFirmware; - /* All functions return TPM_SUCCESS (zero) if successful, non-zero if error */ -/* - * These functions are called from VbInit(). They cannot use global - * variables. - */ - -uint32_t RollbackS3Resume(void); - -/* - * These functions are callable from VbSelectFirmware(). They cannot use - * global variables. - */ - -/** - * This must be called. - */ -uint32_t RollbackFirmwareSetup(int is_hw_dev, - int disable_dev_request, - int clear_tpm_owner_request, - /* two outputs on success */ - int *is_virt_dev, uint32_t *tpm_version); +uint32_t antirollback_read_space_firmware(struct vb2_context *ctx); /** * Write may be called if the versions change. */ -uint32_t RollbackFirmwareWrite(uint32_t version); +uint32_t antirollback_write_space_firmware(struct vb2_context *ctx); /** * Lock must be called. */ -uint32_t RollbackFirmwareLock(void); - -/* - * These functions are callable from VbSelectAndLoadKernel(). They may use - * global variables. - */ - -/** - * Read stored kernel version. - */ -uint32_t RollbackKernelRead(uint32_t *version); - -/** - * Write stored kernel version. - */ -uint32_t RollbackKernelWrite(uint32_t version); - -/** - * Read backup data. - */ -uint32_t RollbackBackupRead(uint8_t *raw); - -/** - * Write backup data. - */ -uint32_t RollbackBackupWrite(uint8_t *raw); - -/** - * Lock must be called. Internally, it's ignored in recovery mode. - */ -uint32_t RollbackKernelLock(int recovery_mode); +uint32_t antirollback_lock_space_firmware(void); /****************************************************************************/ @@ -144,23 +50,23 @@ uint32_t RollbackKernelLock(int recovery_mode); /** * Issue a TPM_Clear and reenable/reactivate the TPM. */ -uint32_t TPMClearAndReenable(void); +uint32_t tpm_clear_and_reenable(void); /** - * Like TlclWrite(), but checks for write errors due to hitting the 64-write + * Like tlcl_write(), but checks for write errors due to hitting the 64-write * limit and clears the TPM when that happens. This can only happen when the * TPM is unowned, so it is OK to clear it (and we really have no choice). * This is not expected to happen frequently, but it could happen. */ -uint32_t SafeWrite(uint32_t index, const void *data, uint32_t length); +uint32_t safe_write(uint32_t index, const void *data, uint32_t length); /** - * Similarly to SafeWrite(), this ensures we don't fail a DefineSpace because + * Similarly to safe_write(), this ensures we don't fail a DefineSpace because * we hit the TPM write limit. This is even less likely to happen than with * writes because we only define spaces once at initialization, but we'd rather * be paranoid about this. */ -uint32_t SafeDefineSpace(uint32_t index, uint32_t perm, uint32_t size); +uint32_t safe_define_space(uint32_t index, uint32_t perm, uint32_t size); /** * Perform one-time initializations. @@ -169,19 +75,11 @@ uint32_t SafeDefineSpace(uint32_t index, uint32_t perm, uint32_t size); * nvLocked bit and ensures the physical presence command is enabled and * locked. */ -uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware *rsf, - RollbackSpaceKernel *rsk); +uint32_t factory_initialize_tpm(struct vb2_context *ctx); /** - * Start the TPM and establish the root of trust for the anti-rollback - * mechanism. + * Start the TPM and establish the root of trust for the antirollback mechanism. */ -uint32_t SetupTPM(int developer_mode, int disable_dev_request, - int clear_tpm_owner_request, RollbackSpaceFirmware *rsf); +uint32_t setup_tpm(struct vb2_context *ctx); -/** - * Utility function to turn the virtual dev-mode flag on or off. 0=off, 1=on. - */ -uint32_t SetVirtualDevMode(int val); - -#endif /* VBOOT_REFERENCE_ROLLBACK_INDEX_H_ */ +#endif /* ANTIROLLBACK_H_ */ diff --git a/src/include/tpm_lite/tlcl.h b/src/include/tpm_lite/tlcl.h index 5373120066..77245922c9 100644 --- a/src/include/tpm_lite/tlcl.h +++ b/src/include/tpm_lite/tlcl.h @@ -21,45 +21,27 @@ /** * Call this first. Returns 0 if success, nonzero if error. */ -uint32_t TlclLibInit(void); - -/** - * Call this on shutdown. Returns 0 if success, nonzero if error. - */ -uint32_t TlclLibClose(void); - -/* Low-level operations */ +uint32_t tlcl_lib_init(void); /** * Perform a raw TPM request/response transaction. */ -uint32_t TlclSendReceive(const uint8_t *request, uint8_t *response, +uint32_t tlcl_send_receive(const uint8_t *request, uint8_t *response, int max_length); -/** - * Return the size of a TPM request or response packet. - */ -int TlclPacketSize(const uint8_t *packet); - /* Commands */ /** * Send a TPM_Startup(ST_CLEAR). The TPM error code is returned (0 for * success). */ -uint32_t TlclStartup(void); - -/** - * Save the TPM state. Normally done by the kernel before a suspend, included - * here for tests. The TPM error code is returned (0 for success). - */ -uint32_t TlclSaveState(void); +uint32_t tlcl_startup(void); /** * Resume by sending a TPM_Startup(ST_STATE). The TPM error code is returned * (0 for success). */ -uint32_t TlclResume(void); +uint32_t tlcl_resume(void); /** * Run the self test. @@ -67,143 +49,89 @@ uint32_t TlclResume(void); * Note---this is synchronous. To run this in parallel with other firmware, * use ContinueSelfTest(). The TPM error code is returned. */ -uint32_t TlclSelfTestFull(void); +uint32_t tlcl_self_test_full(void); /** * Run the self test in the background. */ -uint32_t TlclContinueSelfTest(void); +uint32_t tlcl_continue_self_test(void); /** * Define a space with permission [perm]. [index] is the index for the space, * [size] the usable data size. The TPM error code is returned. */ -uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size); +uint32_t tlcl_define_space(uint32_t index, uint32_t perm, uint32_t size); /** * Write [length] bytes of [data] to space at [index]. The TPM error code is * returned. */ -uint32_t TlclWrite(uint32_t index, const void *data, uint32_t length); +uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length); /** * Read [length] bytes from space at [index] into [data]. The TPM error code * is returned. */ -uint32_t TlclRead(uint32_t index, void *data, uint32_t length); - -/** - * Read PCR at [index] into [data]. [length] must be TPM_PCR_DIGEST or - * larger. The TPM error code is returned. - */ -uint32_t TlclPCRRead(uint32_t index, void *data, uint32_t length); - -/** - * Write-lock space at [index]. The TPM error code is returned. - */ -uint32_t TlclWriteLock(uint32_t index); - -/** - * Read-lock space at [index]. The TPM error code is returned. - */ -uint32_t TlclReadLock(uint32_t index); +uint32_t tlcl_read(uint32_t index, void *data, uint32_t length); /** * Assert physical presence in software. The TPM error code is returned. */ -uint32_t TlclAssertPhysicalPresence(void); +uint32_t tlcl_assert_physical_presence(void); /** * Enable the physical presence command. The TPM error code is returned. */ -uint32_t TlclPhysicalPresenceCMDEnable(void); +uint32_t tlcl_physical_presence_cmd_enable(void); /** * Finalize the physical presence settings: sofware PP is enabled, hardware PP * is disabled, and the lifetime lock is set. The TPM error code is returned. */ -uint32_t TlclFinalizePhysicalPresence(void); - -uint32_t TlclAssertPhysicalPresenceResult(void); - -/** - * Turn off physical presence and locks it off until next reboot. The TPM - * error code is returned. - */ -uint32_t TlclLockPhysicalPresence(void); +uint32_t tlcl_finalize_physical_presence(void); /** * Set the nvLocked bit. The TPM error code is returned. */ -uint32_t TlclSetNvLocked(void); - -/** - * Return 1 if the TPM is owned, 0 otherwise. - */ -int TlclIsOwned(void); +uint32_t tlcl_set_nv_locked(void); /** * Issue a ForceClear. The TPM error code is returned. */ -uint32_t TlclForceClear(void); +uint32_t tlcl_force_clear(void); /** * Issue a PhysicalEnable. The TPM error code is returned. */ -uint32_t TlclSetEnable(void); - -/** - * Issue a PhysicalDisable. The TPM error code is returned. - */ -uint32_t TlclClearEnable(void); +uint32_t tlcl_set_enable(void); /** * Issue a SetDeactivated. Pass 0 to activate. Returns result code. */ -uint32_t TlclSetDeactivated(uint8_t flag); +uint32_t tlcl_set_deactivated(uint8_t flag); /** * Get flags of interest. Pointers for flags you aren't interested in may * be NULL. The TPM error code is returned. */ -uint32_t TlclGetFlags(uint8_t *disable, uint8_t *deactivated, - uint8_t *nvlocked); +uint32_t tlcl_get_flags(uint8_t *disable, uint8_t *deactivated, + uint8_t *nvlocked); /** * Set the bGlobalLock flag, which only a reboot can clear. The TPM error * code is returned. */ -uint32_t TlclSetGlobalLock(void); +uint32_t tlcl_set_global_lock(void); /** * Perform a TPM_Extend. */ -uint32_t TlclExtend(int pcr_num, const uint8_t *in_digest, uint8_t *out_digest); - -/** - * Get the permission bits for the NVRAM space with |index|. - */ -uint32_t TlclGetPermissions(uint32_t index, uint32_t *permissions); +uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest, + uint8_t *out_digest); /** * Get the entire set of permanent flags. */ -uint32_t TlclGetPermanentFlags(TPM_PERMANENT_FLAGS *pflags); - -/** - * Get the entire set of volatile (ST_CLEAR) flags. - */ -uint32_t TlclGetSTClearFlags(TPM_STCLEAR_FLAGS *pflags); - -/** - * Get the ownership flag. The TPM error code is returned. - */ -uint32_t TlclGetOwnership(uint8_t *owned); - -/** - * Request [length] bytes from TPM RNG to be stored in [data]. Actual number of - * bytes read is stored in [size]. The TPM error code is returned. - */ -uint32_t TlclGetRandom(uint8_t *data, uint32_t length, uint32_t *size); +uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS *pflags); #endif /* TPM_LITE_TLCL_H_ */ diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc index 472bd8d8cc..beb3abe168 100644 --- a/src/lib/Makefile.inc +++ b/src/lib/Makefile.inc @@ -33,7 +33,6 @@ verstage-$(CONFIG_COMMON_CBFS_SPI_WRAPPER) += cbfs_spi.c verstage-y += tlcl.c verstage-$(CONFIG_GENERIC_UDELAY) += timer.c - romstage-y += memchr.c romstage-y += memcmp.c $(foreach arch,$(ARCH_SUPPORTED),\ diff --git a/src/lib/tlcl.c b/src/lib/tlcl.c index bf2d27f99c..3cfc40841a 100644 --- a/src/lib/tlcl.c +++ b/src/lib/tlcl.c @@ -14,453 +14,313 @@ * time. */ -#include "sysincludes.h" - -#include "tlcl.h" +#include <2api.h> +#include <2sysincludes.h> +#include +#include +#include #include "tlcl_internal.h" #include "tlcl_structures.h" -#include "utility.h" -#include "vboot_api.h" #ifdef FOR_TEST -/* Allow unit testing implementation of TlclSendReceive() */ -#undef CHROMEOS_ENVIRONMENT +#include +#define VBDEBUG(format, args...) printf(format, ## args) +#else +#include +#define VBDEBUG(format, args...) printk(BIOS_DEBUG, format, ## args) #endif +static int tpm_send_receive(const uint8_t *request, + uint32_t request_length, + uint8_t *response, + uint32_t *response_length) +{ + size_t len = *response_length; + if (tis_sendrecv(request, request_length, response, &len)) + return VB2_ERROR_UNKNOWN; + /* check 64->32bit overflow and (re)check response buffer overflow */ + if (len > *response_length) + return VB2_ERROR_UNKNOWN; + *response_length = len; + return VB2_SUCCESS; +} + /* Sets the size field of a TPM command. */ -static inline void SetTpmCommandSize(uint8_t* buffer, uint32_t size) { - ToTpmUint32(buffer + sizeof(uint16_t), size); +static inline void set_tpm_command_size(uint8_t* buffer, uint32_t size) { + to_tpm_uint32(buffer + sizeof(uint16_t), size); } /* Gets the size field of a TPM command. */ __attribute__((unused)) -static inline int TpmCommandSize(const uint8_t* buffer) { - uint32_t size; - FromTpmUint32(buffer + sizeof(uint16_t), &size); - return (int) size; -} - -/* Gets the size field of a TPM request or response. */ -int TlclPacketSize(const uint8_t* packet) { - return TpmCommandSize(packet); +static inline int tpm_command_size(const uint8_t* buffer) { + uint32_t size; + from_tpm_uint32(buffer + sizeof(uint16_t), &size); + return (int) size; } /* Gets the code field of a TPM command. */ -static inline int TpmCommandCode(const uint8_t* buffer) { - uint32_t code; - FromTpmUint32(buffer + sizeof(uint16_t) + sizeof(uint32_t), &code); - return code; +static inline int tpm_command_code(const uint8_t* buffer) { + uint32_t code; + from_tpm_uint32(buffer + sizeof(uint16_t) + sizeof(uint32_t), &code); + return code; } /* Gets the return code field of a TPM result. */ -static inline int TpmReturnCode(const uint8_t* buffer) { - return TpmCommandCode(buffer); +static inline int tpm_return_code(const uint8_t* buffer) { + return tpm_command_code(buffer); } /* Like TlclSendReceive below, but do not retry if NEEDS_SELFTEST or * DOING_SELFTEST errors are returned. */ -static uint32_t TlclSendReceiveNoRetry(const uint8_t* request, - uint8_t* response, int max_length) { +static uint32_t tlcl_send_receive_no_retry(const uint8_t* request, + uint8_t* response, int max_length) { + uint32_t response_length = max_length; + uint32_t result; - uint32_t response_length = max_length; - uint32_t result; + result = tpm_send_receive(request, tpm_command_size(request), + response, &response_length); + if (0 != result) { + /* Communication with TPM failed, so response is garbage */ + VBDEBUG("TPM: command 0x%x send/receive failed: 0x%x\n", + tpm_command_code(request), result); + return result; + } + /* Otherwise, use the result code from the response */ + result = tpm_return_code(response); -#ifdef EXTRA_LOGGING - VBDEBUG(("TPM: command: %x%x %x%x%x%x %x%x%x%x\n", - request[0], request[1], - request[2], request[3], request[4], request[5], - request[6], request[7], request[8], request[9])); -#endif + /* TODO: add paranoia about returned response_length vs. max_length + * (and possibly expected length from the response header). See + * crosbug.com/17017 */ - result = VbExTpmSendReceive(request, TpmCommandSize(request), - response, &response_length); - if (0 != result) { - /* Communication with TPM failed, so response is garbage */ - VBDEBUG(("TPM: command 0x%x send/receive failed: 0x%x\n", - TpmCommandCode(request), result)); - return result; - } - /* Otherwise, use the result code from the response */ - result = TpmReturnCode(response); + VBDEBUG("TPM: command 0x%x returned 0x%x\n", + tpm_command_code(request), result); - /* TODO: add paranoia about returned response_length vs. max_length - * (and possibly expected length from the response header). See - * crosbug.com/17017 */ - -#ifdef EXTRA_LOGGING - VBDEBUG(("TPM: response: %x%x %x%x%x%x %x%x%x%x\n", - response[0], response[1], - response[2], response[3], response[4], response[5], - response[6], response[7], response[8], response[9])); -#endif - - VBDEBUG(("TPM: command 0x%x returned 0x%x\n", - TpmCommandCode(request), result)); - - return result; +return result; } /* Sends a TPM command and gets a response. Returns 0 if success or the TPM - * error code if error. In the firmware, waits for the self test to complete - * if needed. In the host, reports the first error without retries. */ -uint32_t TlclSendReceive(const uint8_t* request, uint8_t* response, - int max_length) { - uint32_t result = TlclSendReceiveNoRetry(request, response, max_length); - /* When compiling for the firmware, hide command failures due to the self - * test not having run or completed. */ -#ifndef CHROMEOS_ENVIRONMENT - /* If the command fails because the self test has not completed, try it - * again after attempting to ensure that the self test has completed. */ - if (result == TPM_E_NEEDS_SELFTEST || result == TPM_E_DOING_SELFTEST) { - result = TlclContinueSelfTest(); - if (result != TPM_SUCCESS) { - return result; - } + * error code if error. Waits for the self test to complete if needed. */ +uint32_t tlcl_send_receive(const uint8_t* request, uint8_t* response, + int max_length) { + uint32_t result = tlcl_send_receive_no_retry(request, response, + max_length); + /* If the command fails because the self test has not completed, try it + * again after attempting to ensure that the self test has completed. */ + if (result == TPM_E_NEEDS_SELFTEST || result == TPM_E_DOING_SELFTEST) { + result = tlcl_continue_self_test(); + if (result != TPM_SUCCESS) + return result; #if defined(TPM_BLOCKING_CONTINUESELFTEST) || defined(VB_RECOVERY_MODE) - /* Retry only once */ - result = TlclSendReceiveNoRetry(request, response, max_length); + /* Retry only once */ + result = tlcl_send_receive_no_retry(request, response, + max_length); #else - /* This needs serious testing. The TPM specification says: "iii. The - * caller MUST wait for the actions of TPM_ContinueSelfTest to complete - * before reissuing the command C1." But, if ContinueSelfTest is - * non-blocking, how do we know that the actions have completed other than - * trying again? */ - do { - result = TlclSendReceiveNoRetry(request, response, max_length); - } while (result == TPM_E_DOING_SELFTEST); + /* This needs serious testing. The TPM specification says: "iii. + * The caller MUST wait for the actions of TPM_ContinueSelfTest + * to complete before reissuing the command C1." But, if + * ContinueSelfTest is non-blocking, how do we know that the + * actions have completed other than trying again? */ + do { + result = tlcl_send_receive_no_retry(request, response, + max_length); + } while (result == TPM_E_DOING_SELFTEST); #endif - } -#endif /* ! defined(CHROMEOS_ENVIRONMENT) */ - return result; + } + return result; } /* Sends a command and returns the error code. */ -static uint32_t Send(const uint8_t* command) { - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - return TlclSendReceive(command, response, sizeof(response)); +static uint32_t send(const uint8_t* command) { + uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; + return tlcl_send_receive(command, response, sizeof(response)); } /* Exported functions. */ -uint32_t TlclLibInit(void) { - return VbExTpmInit(); +uint32_t tlcl_lib_init(void) { + if (tis_init()) + return VB2_ERROR_UNKNOWN; + if (tis_open()) + return VB2_ERROR_UNKNOWN; + return VB2_SUCCESS; } -uint32_t TlclLibClose(void) { - return VbExTpmClose(); +uint32_t tlcl_startup(void) { + VBDEBUG("TPM: Startup\n"); + return send(tpm_startup_cmd.buffer); } -uint32_t TlclStartup(void) { - VBDEBUG(("TPM: Startup\n")); - return Send(tpm_startup_cmd.buffer); +uint32_t tlcl_resume(void) { + VBDEBUG("TPM: Resume\n"); + return send(tpm_resume_cmd.buffer); } -uint32_t TlclSaveState(void) { - VBDEBUG(("TPM: SaveState\n")); - return Send(tpm_savestate_cmd.buffer); +uint32_t tlcl_self_test_full(void) +{ + VBDEBUG("TPM: Self test full\n"); + return send(tpm_selftestfull_cmd.buffer); } -uint32_t TlclResume(void) { - VBDEBUG(("TPM: Resume\n")); - return Send(tpm_resume_cmd.buffer); +uint32_t tlcl_continue_self_test(void) +{ + uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; + VBDEBUG("TPM: Continue self test\n"); + /* Call the No Retry version of SendReceive to avoid recursion. */ + return tlcl_send_receive_no_retry(tpm_continueselftest_cmd.buffer, + response, sizeof(response)); } -uint32_t TlclSelfTestFull(void) { - VBDEBUG(("TPM: Self test full\n")); - return Send(tpm_selftestfull_cmd.buffer); +uint32_t tlcl_define_space(uint32_t index, uint32_t perm, uint32_t size) +{ + struct s_tpm_nv_definespace_cmd cmd; + VBDEBUG("TPM: TlclDefineSpace(0x%x, 0x%x, %d)\n", index, perm, size); + memcpy(&cmd, &tpm_nv_definespace_cmd, sizeof(cmd)); + to_tpm_uint32(cmd.buffer + tpm_nv_definespace_cmd.index, index); + to_tpm_uint32(cmd.buffer + tpm_nv_definespace_cmd.perm, perm); + to_tpm_uint32(cmd.buffer + tpm_nv_definespace_cmd.size, size); + return send(cmd.buffer); } -uint32_t TlclContinueSelfTest(void) { - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - VBDEBUG(("TPM: Continue self test\n")); - /* Call the No Retry version of SendReceive to avoid recursion. */ - return TlclSendReceiveNoRetry(tpm_continueselftest_cmd.buffer, - response, sizeof(response)); +uint32_t tlcl_write(uint32_t index, const void* data, uint32_t length) +{ + struct s_tpm_nv_write_cmd cmd; + uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; + const int total_length = + kTpmRequestHeaderLength + kWriteInfoLength + length; + + VBDEBUG("TPM: tlcl_write(0x%x, %d)\n", index, length); + memcpy(&cmd, &tpm_nv_write_cmd, sizeof(cmd)); + assert(total_length <= TPM_LARGE_ENOUGH_COMMAND_SIZE); + set_tpm_command_size(cmd.buffer, total_length); + + to_tpm_uint32(cmd.buffer + tpm_nv_write_cmd.index, index); + to_tpm_uint32(cmd.buffer + tpm_nv_write_cmd.length, length); + memcpy(cmd.buffer + tpm_nv_write_cmd.data, data, length); + + return tlcl_send_receive(cmd.buffer, response, sizeof(response)); } -uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size) { - struct s_tpm_nv_definespace_cmd cmd; - VBDEBUG(("TPM: TlclDefineSpace(0x%x, 0x%x, %d)\n", index, perm, size)); - Memcpy(&cmd, &tpm_nv_definespace_cmd, sizeof(cmd)); - ToTpmUint32(cmd.buffer + tpm_nv_definespace_cmd.index, index); - ToTpmUint32(cmd.buffer + tpm_nv_definespace_cmd.perm, perm); - ToTpmUint32(cmd.buffer + tpm_nv_definespace_cmd.size, size); - return Send(cmd.buffer); +uint32_t tlcl_read(uint32_t index, void* data, uint32_t length) +{ + struct s_tpm_nv_read_cmd cmd; + uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; + uint32_t result_length; + uint32_t result; + + VBDEBUG("TPM: tlcl_read(0x%x, %d)\n", index, length); + memcpy(&cmd, &tpm_nv_read_cmd, sizeof(cmd)); + to_tpm_uint32(cmd.buffer + tpm_nv_read_cmd.index, index); + to_tpm_uint32(cmd.buffer + tpm_nv_read_cmd.length, length); + + result = tlcl_send_receive(cmd.buffer, response, sizeof(response)); + if (result == TPM_SUCCESS && length > 0) { + uint8_t* nv_read_cursor = response + kTpmResponseHeaderLength; + from_tpm_uint32(nv_read_cursor, &result_length); + nv_read_cursor += sizeof(uint32_t); + memcpy(data, nv_read_cursor, result_length); + } + + return result; } -uint32_t TlclWrite(uint32_t index, const void* data, uint32_t length) { - struct s_tpm_nv_write_cmd cmd; - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - const int total_length = - kTpmRequestHeaderLength + kWriteInfoLength + length; - VBDEBUG(("TPM: TlclWrite(0x%x, %d)\n", index, length)); - Memcpy(&cmd, &tpm_nv_write_cmd, sizeof(cmd)); - VbAssert(total_length <= TPM_LARGE_ENOUGH_COMMAND_SIZE); - SetTpmCommandSize(cmd.buffer, total_length); - - ToTpmUint32(cmd.buffer + tpm_nv_write_cmd.index, index); - ToTpmUint32(cmd.buffer + tpm_nv_write_cmd.length, length); - Memcpy(cmd.buffer + tpm_nv_write_cmd.data, data, length); - - return TlclSendReceive(cmd.buffer, response, sizeof(response)); +uint32_t tlcl_assert_physical_presence(void) { + VBDEBUG("TPM: Asserting physical presence\n"); + return send(tpm_ppassert_cmd.buffer); } -uint32_t TlclRead(uint32_t index, void* data, uint32_t length) { - struct s_tpm_nv_read_cmd cmd; - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - uint32_t result_length; - uint32_t result; - - VBDEBUG(("TPM: TlclRead(0x%x, %d)\n", index, length)); - Memcpy(&cmd, &tpm_nv_read_cmd, sizeof(cmd)); - ToTpmUint32(cmd.buffer + tpm_nv_read_cmd.index, index); - ToTpmUint32(cmd.buffer + tpm_nv_read_cmd.length, length); - - result = TlclSendReceive(cmd.buffer, response, sizeof(response)); - if (result == TPM_SUCCESS && length > 0) { - uint8_t* nv_read_cursor = response + kTpmResponseHeaderLength; - FromTpmUint32(nv_read_cursor, &result_length); - nv_read_cursor += sizeof(uint32_t); - Memcpy(data, nv_read_cursor, result_length); - } - - return result; +uint32_t tlcl_physical_presence_cmd_enable(void) { + VBDEBUG("TPM: Enable the physical presence command\n"); + return send(tpm_ppenable_cmd.buffer); } -uint32_t TlclPCRRead(uint32_t index, void* data, uint32_t length) { - struct s_tpm_pcr_read_cmd cmd; - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - uint32_t result; - - VBDEBUG(("TPM: TlclPCRRead(0x%x, %d)\n", index, length)); - if (length < kPcrDigestLength) { - return TPM_E_IOERROR; - } - Memcpy(&cmd, &tpm_pcr_read_cmd, sizeof(cmd)); - ToTpmUint32(cmd.buffer + tpm_pcr_read_cmd.pcrNum, index); - - result = TlclSendReceive(cmd.buffer, response, sizeof(response)); - if (result == TPM_SUCCESS) { - uint8_t* pcr_read_cursor = response + kTpmResponseHeaderLength; - Memcpy(data, pcr_read_cursor, kPcrDigestLength); - } - - return result; +uint32_t tlcl_finalize_physical_presence(void) { + VBDEBUG("TPM: Enable PP cmd, disable HW pp, and set lifetime lock\n"); + return send(tpm_finalizepp_cmd.buffer); } -uint32_t TlclWriteLock(uint32_t index) { - VBDEBUG(("TPM: Write lock 0x%x\n", index)); - return TlclWrite(index, NULL, 0); +uint32_t tlcl_set_nv_locked(void) { + VBDEBUG("TPM: Set NV locked\n"); + return tlcl_define_space(TPM_NV_INDEX_LOCK, 0, 0); } -uint32_t TlclReadLock(uint32_t index) { - VBDEBUG(("TPM: Read lock 0x%x\n", index)); - return TlclRead(index, NULL, 0); +uint32_t tlcl_force_clear(void) { + VBDEBUG("TPM: Force clear\n"); + return send(tpm_forceclear_cmd.buffer); } -uint32_t TlclAssertPhysicalPresence(void) { - VBDEBUG(("TPM: Asserting physical presence\n")); - return Send(tpm_ppassert_cmd.buffer); +uint32_t tlcl_set_enable(void) { + VBDEBUG("TPM: Enabling TPM\n"); + return send(tpm_physicalenable_cmd.buffer); } -uint32_t TlclPhysicalPresenceCMDEnable(void) { - VBDEBUG(("TPM: Enable the physical presence command\n")); - return Send(tpm_ppenable_cmd.buffer); +uint32_t tlcl_set_deactivated(uint8_t flag) +{ + struct s_tpm_physicalsetdeactivated_cmd cmd; + VBDEBUG("TPM: SetDeactivated(%d)\n", flag); + memcpy(&cmd, &tpm_physicalsetdeactivated_cmd, sizeof(cmd)); + *(cmd.buffer + cmd.deactivated) = flag; + return send(cmd.buffer); } -uint32_t TlclFinalizePhysicalPresence(void) { - VBDEBUG(("TPM: Enable PP cmd, disable HW pp, and set lifetime lock\n")); - return Send(tpm_finalizepp_cmd.buffer); +uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS* pflags) +{ + uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; + uint32_t size; + uint32_t result = tlcl_send_receive(tpm_getflags_cmd.buffer, response, + sizeof(response)); + if (result != TPM_SUCCESS) + return result; + from_tpm_uint32(response + kTpmResponseHeaderLength, &size); + assert(size == sizeof(TPM_PERMANENT_FLAGS)); + memcpy(pflags, response + kTpmResponseHeaderLength + sizeof(size), + sizeof(TPM_PERMANENT_FLAGS)); + return result; } -uint32_t TlclAssertPhysicalPresenceResult(void) { - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - return TlclSendReceive(tpm_ppassert_cmd.buffer, response, sizeof(response)); +uint32_t tlcl_get_flags(uint8_t* disable, uint8_t* deactivated, + uint8_t *nvlocked) +{ + TPM_PERMANENT_FLAGS pflags; + uint32_t result = tlcl_get_permanent_flags(&pflags); + if (result == TPM_SUCCESS) { + if (disable) + *disable = pflags.disable; + if (deactivated) + *deactivated = pflags.deactivated; + if (nvlocked) + *nvlocked = pflags.nvLocked; + VBDEBUG("TPM: flags disable=%d, deactivated=%d, nvlocked=%d\n", + pflags.disable, pflags.deactivated, pflags.nvLocked); + } + return result; } -uint32_t TlclLockPhysicalPresence(void) { - VBDEBUG(("TPM: Lock physical presence\n")); - return Send(tpm_pplock_cmd.buffer); +uint32_t tlcl_set_global_lock(void) +{ + uint32_t x; + VBDEBUG("TPM: Set global lock\n"); + return tlcl_write(TPM_NV_INDEX0, (uint8_t*) &x, 0); } -uint32_t TlclSetNvLocked(void) { - VBDEBUG(("TPM: Set NV locked\n")); - return TlclDefineSpace(TPM_NV_INDEX_LOCK, 0, 0); -} - -int TlclIsOwned(void) { - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE + TPM_PUBEK_SIZE]; - uint32_t result; - result = TlclSendReceive(tpm_readpubek_cmd.buffer, - response, sizeof(response)); - return (result != TPM_SUCCESS); -} - -uint32_t TlclForceClear(void) { - VBDEBUG(("TPM: Force clear\n")); - return Send(tpm_forceclear_cmd.buffer); -} - -uint32_t TlclSetEnable(void) { - VBDEBUG(("TPM: Enabling TPM\n")); - return Send(tpm_physicalenable_cmd.buffer); -} - -uint32_t TlclClearEnable(void) { - VBDEBUG(("TPM: Disabling TPM\n")); - return Send(tpm_physicaldisable_cmd.buffer); -} - -uint32_t TlclSetDeactivated(uint8_t flag) { - struct s_tpm_physicalsetdeactivated_cmd cmd; - VBDEBUG(("TPM: SetDeactivated(%d)\n", flag)); - Memcpy(&cmd, &tpm_physicalsetdeactivated_cmd, sizeof(cmd)); - *(cmd.buffer + cmd.deactivated) = flag; - return Send(cmd.buffer); -} - -uint32_t TlclGetPermanentFlags(TPM_PERMANENT_FLAGS* pflags) { - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - uint32_t size; - uint32_t result = - TlclSendReceive(tpm_getflags_cmd.buffer, response, sizeof(response)); - if (result != TPM_SUCCESS) - return result; - FromTpmUint32(response + kTpmResponseHeaderLength, &size); - /* TODO(crbug.com/379255): This fails. Find out why. - * VbAssert(size == sizeof(TPM_PERMANENT_FLAGS)); - */ - Memcpy(pflags, - response + kTpmResponseHeaderLength + sizeof(size), - sizeof(TPM_PERMANENT_FLAGS)); - return result; -} - -uint32_t TlclGetSTClearFlags(TPM_STCLEAR_FLAGS* vflags) { - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - uint32_t size; - uint32_t result = - TlclSendReceive(tpm_getstclearflags_cmd.buffer, response, sizeof(response)); - if (result != TPM_SUCCESS) - return result; - FromTpmUint32(response + kTpmResponseHeaderLength, &size); - /* Ugly assertion, but the struct is padded up by one byte. */ - /* TODO(crbug.com/379255): This fails. Find out why. - * VbAssert(size == 7 && sizeof(TPM_STCLEAR_FLAGS) - 1 == 7); - */ - Memcpy(vflags, - response + kTpmResponseHeaderLength + sizeof(size), - sizeof(TPM_STCLEAR_FLAGS)); - return result; -} - -uint32_t TlclGetFlags(uint8_t* disable, - uint8_t* deactivated, - uint8_t *nvlocked) { - TPM_PERMANENT_FLAGS pflags; - uint32_t result = TlclGetPermanentFlags(&pflags); - if (result == TPM_SUCCESS) { - if (disable) - *disable = pflags.disable; - if (deactivated) - *deactivated = pflags.deactivated; - if (nvlocked) - *nvlocked = pflags.nvLocked; - VBDEBUG(("TPM: Got flags disable=%d, deactivated=%d, nvlocked=%d\n", - pflags.disable, pflags.deactivated, pflags.nvLocked)); - } - return result; -} - -uint32_t TlclSetGlobalLock(void) { - uint32_t x; - VBDEBUG(("TPM: Set global lock\n")); - return TlclWrite(TPM_NV_INDEX0, (uint8_t*) &x, 0); -} - -uint32_t TlclExtend(int pcr_num, const uint8_t* in_digest, - uint8_t* out_digest) { - struct s_tpm_extend_cmd cmd; - uint8_t response[kTpmResponseHeaderLength + kPcrDigestLength]; - uint32_t result; - - Memcpy(&cmd, &tpm_extend_cmd, sizeof(cmd)); - ToTpmUint32(cmd.buffer + tpm_extend_cmd.pcrNum, pcr_num); - Memcpy(cmd.buffer + cmd.inDigest, in_digest, kPcrDigestLength); - - result = TlclSendReceive(cmd.buffer, response, sizeof(response)); - if (result != TPM_SUCCESS) - return result; - - Memcpy(out_digest, response + kTpmResponseHeaderLength, kPcrDigestLength); - return result; -} - -uint32_t TlclGetPermissions(uint32_t index, uint32_t* permissions) { - struct s_tpm_getpermissions_cmd cmd; - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - uint8_t* nvdata; - uint32_t result; - uint32_t size; - - Memcpy(&cmd, &tpm_getpermissions_cmd, sizeof(cmd)); - ToTpmUint32(cmd.buffer + tpm_getpermissions_cmd.index, index); - result = TlclSendReceive(cmd.buffer, response, sizeof(response)); - if (result != TPM_SUCCESS) - return result; - - nvdata = response + kTpmResponseHeaderLength + sizeof(size); - FromTpmUint32(nvdata + kNvDataPublicPermissionsOffset, permissions); - return result; -} - -uint32_t TlclGetOwnership(uint8_t* owned) { - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - uint32_t size; - uint32_t result = - TlclSendReceive(tpm_getownership_cmd.buffer, response, sizeof(response)); - if (result != TPM_SUCCESS) - return result; - FromTpmUint32(response + kTpmResponseHeaderLength, &size); - /* TODO(crbug.com/379255): This fails. Find out why. - * VbAssert(size == sizeof(*owned)); - */ - Memcpy(owned, - response + kTpmResponseHeaderLength + sizeof(size), - sizeof(*owned)); - return result; -} - -uint32_t TlclGetRandom(uint8_t* data, uint32_t length, uint32_t *size) { - struct s_tpm_get_random_cmd cmd; - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - uint32_t result; - - VBDEBUG(("TPM: TlclGetRandom(%d)\n", length)); - Memcpy(&cmd, &tpm_get_random_cmd, sizeof(cmd)); - ToTpmUint32(cmd.buffer + tpm_get_random_cmd.bytesRequested, length); - /* There must be room in the response buffer for the bytes. */ - if (length > TPM_LARGE_ENOUGH_COMMAND_SIZE - kTpmResponseHeaderLength - - sizeof(uint32_t)) { - return TPM_E_IOERROR; - } - - result = TlclSendReceive(cmd.buffer, response, sizeof(response)); - if (result == TPM_SUCCESS) { - uint8_t* get_random_cursor; - FromTpmUint32(response + kTpmResponseHeaderLength, size); - - /* There must be room in the target buffer for the bytes. */ - if (*size > length) { - return TPM_E_RESPONSE_TOO_LARGE; - } - get_random_cursor = response + kTpmResponseHeaderLength - + sizeof(uint32_t); - Memcpy(data, get_random_cursor, *size); - } - - return result; +uint32_t tlcl_extend(int pcr_num, const uint8_t* in_digest, + uint8_t* out_digest) +{ + struct s_tpm_extend_cmd cmd; + uint8_t response[kTpmResponseHeaderLength + kPcrDigestLength]; + uint32_t result; + + memcpy(&cmd, &tpm_extend_cmd, sizeof(cmd)); + to_tpm_uint32(cmd.buffer + tpm_extend_cmd.pcrNum, pcr_num); + memcpy(cmd.buffer + cmd.inDigest, in_digest, kPcrDigestLength); + + result = tlcl_send_receive(cmd.buffer, response, sizeof(response)); + if (result != TPM_SUCCESS) + return result; + + memcpy(out_digest, response + kTpmResponseHeaderLength, + kPcrDigestLength); + return result; } diff --git a/src/lib/tlcl_internal.h b/src/lib/tlcl_internal.h index 51fe6ef3f0..8261b0d0e1 100644 --- a/src/lib/tlcl_internal.h +++ b/src/lib/tlcl_internal.h @@ -18,44 +18,44 @@ /* - * Conversion functions. ToTpmTYPE puts a value of type TYPE into a TPM - * command buffer. FromTpmTYPE gets a value of type TYPE from a TPM command + * Conversion functions. to_tpm_TYPE puts a value of type TYPE into a TPM + * command buffer. from_tpm_TYPE gets a value of type TYPE from a TPM command * buffer into a variable. */ __attribute__((unused)) -static inline void ToTpmUint32(uint8_t *buffer, uint32_t x) { - buffer[0] = (uint8_t)(x >> 24); - buffer[1] = (uint8_t)((x >> 16) & 0xff); - buffer[2] = (uint8_t)((x >> 8) & 0xff); - buffer[3] = (uint8_t)(x & 0xff); +static inline void to_tpm_uint32(uint8_t *buffer, uint32_t x) { + buffer[0] = (uint8_t)(x >> 24); + buffer[1] = (uint8_t)((x >> 16) & 0xff); + buffer[2] = (uint8_t)((x >> 8) & 0xff); + buffer[3] = (uint8_t)(x & 0xff); } /* * See comment for above function. */ __attribute__((unused)) -static inline void FromTpmUint32(const uint8_t *buffer, uint32_t *x) { - *x = ((buffer[0] << 24) | - (buffer[1] << 16) | - (buffer[2] << 8) | - buffer[3]); +static inline void from_tpm_uint32(const uint8_t *buffer, uint32_t *x) { + *x = ((buffer[0] << 24) | + (buffer[1] << 16) | + (buffer[2] << 8) | + buffer[3]); } /* * See comment for above function. */ __attribute__((unused)) -static inline void ToTpmUint16(uint8_t *buffer, uint16_t x) { - buffer[0] = (uint8_t)(x >> 8); - buffer[1] = (uint8_t)(x & 0xff); +static inline void to_tpm_uint16(uint8_t *buffer, uint16_t x) { + buffer[0] = (uint8_t)(x >> 8); + buffer[1] = (uint8_t)(x & 0xff); } /* * See comment for above function. */ __attribute__((unused)) -static inline void FromTpmUint16(const uint8_t *buffer, uint16_t *x) { - *x = (buffer[0] << 8) | buffer[1]; +static inline void from_tpm_uint16(const uint8_t *buffer, uint16_t *x) { + *x = (buffer[0] << 8) | buffer[1]; } #endif /* TPM_LITE_TLCL_INTERNAL_H_ */ diff --git a/src/soc/nvidia/tegra124/Makefile.inc b/src/soc/nvidia/tegra124/Makefile.inc index 9ed7669aea..8966168a78 100644 --- a/src/soc/nvidia/tegra124/Makefile.inc +++ b/src/soc/nvidia/tegra124/Makefile.inc @@ -28,7 +28,10 @@ verstage-y += spi.c verstage-y += timer.c verstage-$(CONFIG_DRIVERS_UART) += uart.c verstage-y += ../tegra/gpio.c +verstage-y += ../tegra/i2c.c verstage-y += ../tegra/pinmux.c +verstage-y += clock.c +verstage-y += i2c.c romstage-y += cbfs.c romstage-y += cbmem.c diff --git a/src/soc/nvidia/tegra124/bootblock.c b/src/soc/nvidia/tegra124/bootblock.c index aec914532e..22e7ba8557 100644 --- a/src/soc/nvidia/tegra124/bootblock.c +++ b/src/soc/nvidia/tegra124/bootblock.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -27,6 +28,78 @@ #include "pinmux.h" #include "power.h" #include "verstage.h" +#include +#include +#include +#include +static struct clk_rst_ctlr *clk_rst = (void *)TEGRA_CLK_RST_BASE; + +static void setup_pinmux(void) +{ + // Write protect. + gpio_input_pullup(GPIO(R1)); + // Recovery mode. + gpio_input_pullup(GPIO(Q7)); + // Lid switch. + gpio_input_pullup(GPIO(R4)); + // Power switch. + gpio_input_pullup(GPIO(Q0)); + // Developer mode. + gpio_input_pullup(GPIO(Q6)); + // EC in RW. + gpio_input_pullup(GPIO(U4)); + + // route PU4/5 to GMI to remove conflict w/PWM1/2. + pinmux_set_config(PINMUX_GPIO_PU4_INDEX, PINMUX_GPIO_PU4_FUNC_NOR); + pinmux_set_config(PINMUX_GPIO_PU5_INDEX, PINMUX_GPIO_PU5_FUNC_NOR); + + // SOC and TPM reset GPIO, active low. + gpio_output(GPIO(I5), 1); + + // SPI1 MOSI + pinmux_set_config(PINMUX_ULPI_CLK_INDEX, PINMUX_ULPI_CLK_FUNC_SPI1 | + PINMUX_PULL_NONE | + PINMUX_INPUT_ENABLE); + // SPI1 MISO + pinmux_set_config(PINMUX_ULPI_DIR_INDEX, PINMUX_ULPI_DIR_FUNC_SPI1 | + PINMUX_PULL_NONE | + PINMUX_INPUT_ENABLE); + // SPI1 SCLK + pinmux_set_config(PINMUX_ULPI_NXT_INDEX, PINMUX_ULPI_NXT_FUNC_SPI1 | + PINMUX_PULL_NONE | + PINMUX_INPUT_ENABLE); + // SPI1 CS0 + pinmux_set_config(PINMUX_ULPI_STP_INDEX, PINMUX_ULPI_STP_FUNC_SPI1 | + PINMUX_PULL_NONE | + PINMUX_INPUT_ENABLE); + + // I2C3 (cam) clock. + pinmux_set_config(PINMUX_CAM_I2C_SCL_INDEX, + PINMUX_CAM_I2C_SCL_FUNC_I2C3 | PINMUX_INPUT_ENABLE); + // I2C3 (cam) data. + pinmux_set_config(PINMUX_CAM_I2C_SDA_INDEX, + PINMUX_CAM_I2C_SDA_FUNC_I2C3 | PINMUX_INPUT_ENABLE); + + // switch unused pin to GPIO + gpio_set_mode(GPIO(X3), GPIO_MODE_GPIO); + gpio_set_mode(GPIO(X4), GPIO_MODE_GPIO); + gpio_set_mode(GPIO(X5), GPIO_MODE_GPIO); + gpio_set_mode(GPIO(X6), GPIO_MODE_GPIO); + gpio_set_mode(GPIO(X7), GPIO_MODE_GPIO); + gpio_set_mode(GPIO(W3), GPIO_MODE_GPIO); +} + +static void configure_ec_spi_bus(void) +{ + clock_configure_source(sbc1, CLK_M, 3000); +} + +static void configure_tpm_i2c_bus(void) +{ + clock_configure_i2c_scl_freq(i2c3, PLLP, 400); + + i2c_init(2); +} void main(void) { @@ -70,9 +143,13 @@ void main(void) PINMUX_PWR_INT_N_FUNC_PMICINTR | PINMUX_INPUT_ENABLE); - if (IS_ENABLED(CONFIG_VBOOT2_VERIFY_FIRMWARE)) + if (IS_ENABLED(CONFIG_VBOOT2_VERIFY_FIRMWARE)) { + clock_enable_clear_reset(0, CLK_H_SBC1, CLK_U_I2C3, 0, 0, 0); + setup_pinmux(); + configure_ec_spi_bus(); + configure_tpm_i2c_bus(); entry = (void *)verstage_vboot_main; - else + } else entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, "fallback/romstage"); ASSERT(entry); diff --git a/src/vendorcode/google/chromeos/Makefile.inc b/src/vendorcode/google/chromeos/Makefile.inc index cb3d9a68b8..4438a92545 100644 --- a/src/vendorcode/google/chromeos/Makefile.inc +++ b/src/vendorcode/google/chromeos/Makefile.inc @@ -101,6 +101,7 @@ VERSTAGE_LIB = $(obj)/vendorcode/google/chromeos/verstage.a INCLUDES += -I$(VB_SOURCE)/firmware/2lib/include INCLUDES += -I$(VB_SOURCE)/firmware/include verstage-y += vboot_main.c fmap.c chromeos.c +verstage-y += antirollback.c vbnv_ec.c VB_FIRMWARE_ARCH := $(ARCHDIR-$(ARCH-VERSTAGE-y)) VB2_LIB = $(obj)/external/vboot_reference/vboot_fw2.a diff --git a/src/vendorcode/google/chromeos/antirollback.c b/src/vendorcode/google/chromeos/antirollback.c index 306e90329b..020a06abb2 100644 --- a/src/vendorcode/google/chromeos/antirollback.c +++ b/src/vendorcode/google/chromeos/antirollback.c @@ -6,261 +6,118 @@ * stored in the TPM NVRAM. */ -#include "sysincludes.h" - -#include "crc8.h" -#include "rollback_index.h" -#include "tlcl.h" -#include "tss_constants.h" -#include "utility.h" -#include "vboot_api.h" +#include <2api.h> +#include <2sysincludes.h> +#include +#include +#include #ifndef offsetof #define offsetof(A,B) __builtin_offsetof(A,B) #endif -/* - * Provide protoypes for functions not in the header file. These prototypes - * fix -Wmissing-prototypes warnings. - */ -uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf); -uint32_t WriteSpaceFirmware(RollbackSpaceFirmware *rsf); -uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk); -uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk); - #ifdef FOR_TEST -/* - * Compiling for unit test, so we need the real implementations of - * rollback functions. The unit test mocks the underlying tlcl - * functions, so this is ok to run on the host. - */ -#undef CHROMEOS_ENVIRONMENT -#undef DISABLE_ROLLBACK_TPM +#include +#define VBDEBUG(format, args...) printf(format, ## args) +#else +#include +#define VBDEBUG(format, args...) \ + printk(BIOS_INFO, "%s():%d: " format, __func__, __LINE__, ## args) #endif -#define RETURN_ON_FAILURE(tpm_command) do { \ +#define RETURN_ON_FAILURE(tpm_cmd) do { \ uint32_t result_; \ - if ((result_ = (tpm_command)) != TPM_SUCCESS) { \ - VBDEBUG(("Rollback: %08x returned by " #tpm_command \ - "\n", (int)result_)); \ + if ((result_ = (tpm_cmd)) != TPM_SUCCESS) { \ + VBDEBUG("Antirollback: %08x returned by " #tpm_cmd \ + "\n", (int)result_); \ return result_; \ } \ } while (0) -uint32_t TPMClearAndReenable(void) +uint32_t tpm_clear_and_reenable(void) { - VBDEBUG(("TPM: Clear and re-enable\n")); - RETURN_ON_FAILURE(TlclForceClear()); - RETURN_ON_FAILURE(TlclSetEnable()); - RETURN_ON_FAILURE(TlclSetDeactivated(0)); + VBDEBUG("TPM: Clear and re-enable\n"); + RETURN_ON_FAILURE(tlcl_force_clear()); + RETURN_ON_FAILURE(tlcl_set_enable()); + RETURN_ON_FAILURE(tlcl_set_deactivated(0)); return TPM_SUCCESS; } -uint32_t SafeWrite(uint32_t index, const void *data, uint32_t length) +uint32_t safe_write(uint32_t index, const void *data, uint32_t length) { - uint32_t result = TlclWrite(index, data, length); + uint32_t result = tlcl_write(index, data, length); if (result == TPM_E_MAXNVWRITES) { - RETURN_ON_FAILURE(TPMClearAndReenable()); - return TlclWrite(index, data, length); + RETURN_ON_FAILURE(tpm_clear_and_reenable()); + return tlcl_write(index, data, length); } else { return result; } } -uint32_t SafeDefineSpace(uint32_t index, uint32_t perm, uint32_t size) +uint32_t safe_define_space(uint32_t index, uint32_t perm, uint32_t size) { - uint32_t result = TlclDefineSpace(index, perm, size); + uint32_t result = tlcl_define_space(index, perm, size); if (result == TPM_E_MAXNVWRITES) { - RETURN_ON_FAILURE(TPMClearAndReenable()); - return TlclDefineSpace(index, perm, size); + RETURN_ON_FAILURE(tpm_clear_and_reenable()); + return tlcl_define_space(index, perm, size); } else { return result; } } -/* Functions to read and write firmware and kernel spaces. */ -uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf) +static uint32_t read_space_firmware(struct vb2_context *ctx) { - uint32_t r; int attempts = 3; while (attempts--) { - r = TlclRead(FIRMWARE_NV_INDEX, rsf, - sizeof(RollbackSpaceFirmware)); - if (r != TPM_SUCCESS) - return r; + RETURN_ON_FAILURE(tlcl_read(FIRMWARE_NV_INDEX, ctx->secdata, + VB2_SECDATA_SIZE)); - /* - * No CRC in this version, so we'll create one when we write - * it. Note that we're marking this as version 2, not - * ROLLBACK_SPACE_FIRMWARE_VERSION, because version 2 just - * added the CRC. Later versions will need to set default - * values for any extra fields explicitly (probably here). - */ - if (rsf->struct_version < 2) { - /* Danger Will Robinson! Danger! */ - rsf->struct_version = 2; - return TPM_SUCCESS; - } - - /* - * If the CRC is good, we're done. If it's bad, try a couple - * more times to see if it gets better before we give up. It - * could just be noise. - */ - if (rsf->crc8 == Crc8(rsf, - offsetof(RollbackSpaceFirmware, crc8))) + if (vb2api_secdata_check(ctx) == VB2_SUCCESS) return TPM_SUCCESS; - VBDEBUG(("TPM: %s() - bad CRC\n", __func__)); + VBDEBUG("TPM: %s() - bad CRC\n", __func__); } - VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__)); + VBDEBUG("TPM: %s() - too many bad CRCs, giving up\n", __func__); return TPM_E_CORRUPTED_STATE; } -uint32_t WriteSpaceFirmware(RollbackSpaceFirmware *rsf) +static uint32_t write_space_firmware(struct vb2_context *ctx) { - RollbackSpaceFirmware rsf2; + uint8_t secdata[VB2_SECDATA_SIZE]; uint32_t r; int attempts = 3; - /* All writes should use struct_version 2 or greater. */ - if (rsf->struct_version < 2) - rsf->struct_version = 2; - rsf->crc8 = Crc8(rsf, offsetof(RollbackSpaceFirmware, crc8)); - + memcpy(secdata, ctx->secdata, VB2_SECDATA_SIZE); while (attempts--) { - r = SafeWrite(FIRMWARE_NV_INDEX, rsf, - sizeof(RollbackSpaceFirmware)); + r = safe_write(FIRMWARE_NV_INDEX, secdata, VB2_SECDATA_SIZE); /* Can't write, not gonna try again */ if (r != TPM_SUCCESS) return r; /* Read it back to be sure it got the right values. */ - r = ReadSpaceFirmware(&rsf2); /* This checks the CRC */ - if (r == TPM_SUCCESS) + r = read_space_firmware(ctx); + if (r == TPM_SUCCESS && memcmp(secdata, ctx->secdata, + VB2_SECDATA_SIZE) == 0) return r; - VBDEBUG(("TPM: %s() - bad CRC\n", __func__)); + VBDEBUG("TPM: %s() failed\n", __func__); /* Try writing it again. Maybe it was garbled on the way out. */ } - VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__)); + VBDEBUG("TPM: %s() - too many failures, giving up\n", __func__); return TPM_E_CORRUPTED_STATE; } -uint32_t SetVirtualDevMode(int val) +uint32_t factory_initialize_tpm(struct vb2_context *ctx) { - RollbackSpaceFirmware rsf; - - VBDEBUG(("TPM: Entering %s()\n", __func__)); - if (TPM_SUCCESS != ReadSpaceFirmware(&rsf)) - return VBERROR_TPM_FIRMWARE_SETUP; - - VBDEBUG(("TPM: flags were 0x%02x\n", rsf.flags)); - if (val) - rsf.flags |= FLAG_VIRTUAL_DEV_MODE_ON; - else - rsf.flags &= ~FLAG_VIRTUAL_DEV_MODE_ON; - /* - * NOTE: This doesn't update the FLAG_LAST_BOOT_DEVELOPER bit. That - * will be done by SetupTPM() on the next boot. - */ - VBDEBUG(("TPM: flags are now 0x%02x\n", rsf.flags)); - - if (TPM_SUCCESS != WriteSpaceFirmware(&rsf)) - return VBERROR_TPM_SET_BOOT_MODE_STATE; - - VBDEBUG(("TPM: Leaving %s()\n", __func__)); - return VBERROR_SUCCESS; -} - -uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk) -{ - uint32_t r; - int attempts = 3; - - while (attempts--) { - r = TlclRead(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel)); - if (r != TPM_SUCCESS) - return r; - - /* - * No CRC in this version, so we'll create one when we write - * it. Note that we're marking this as version 2, not - * ROLLBACK_SPACE_KERNEL_VERSION, because version 2 just added - * the CRC. Later versions will need to set default values for - * any extra fields explicitly (probably here). - */ - if (rsk->struct_version < 2) { - /* Danger Will Robinson! Danger! */ - rsk->struct_version = 2; - return TPM_SUCCESS; - } - - /* - * If the CRC is good, we're done. If it's bad, try a couple - * more times to see if it gets better before we give up. It - * could just be noise. - */ - if (rsk->crc8 == Crc8(rsk, offsetof(RollbackSpaceKernel, crc8))) - return TPM_SUCCESS; - - VBDEBUG(("TPM: %s() - bad CRC\n", __func__)); - } - - VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__)); - return TPM_E_CORRUPTED_STATE; -} - -uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk) -{ - RollbackSpaceKernel rsk2; - uint32_t r; - int attempts = 3; - - /* All writes should use struct_version 2 or greater. */ - if (rsk->struct_version < 2) - rsk->struct_version = 2; - rsk->crc8 = Crc8(rsk, offsetof(RollbackSpaceKernel, crc8)); - - while (attempts--) { - r = SafeWrite(KERNEL_NV_INDEX, rsk, - sizeof(RollbackSpaceKernel)); - /* Can't write, not gonna try again */ - if (r != TPM_SUCCESS) - return r; - - /* Read it back to be sure it got the right values. */ - r = ReadSpaceKernel(&rsk2); /* This checks the CRC */ - if (r == TPM_SUCCESS) - return r; - - VBDEBUG(("TPM: %s() - bad CRC\n", __func__)); - /* Try writing it again. Maybe it was garbled on the way out. */ - } - - VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__)); - return TPM_E_CORRUPTED_STATE; -} - -uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware *rsf, - RollbackSpaceKernel *rsk) -{ - static const RollbackSpaceFirmware rsf_init = { - .struct_version = ROLLBACK_SPACE_FIRMWARE_VERSION, - }; - static const RollbackSpaceKernel rsk_init = { - .struct_version = ROLLBACK_SPACE_KERNEL_VERSION, - .uid = ROLLBACK_SPACE_KERNEL_UID, - }; TPM_PERMANENT_FLAGS pflags; uint32_t result; - VBDEBUG(("TPM: One-time initialization\n")); + VBDEBUG("TPM: factory initialization\n"); /* * Do a full test. This only happens the first time the device is @@ -270,11 +127,11 @@ uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware *rsf, * test---specifically the ones that set lifetime flags, and are only * executed once per physical TPM. */ - result = TlclSelfTestFull(); + result = tlcl_self_test_full(); if (result != TPM_SUCCESS) return result; - result = TlclGetPermanentFlags(&pflags); + result = tlcl_get_permanent_flags(&pflags); if (result != TPM_SUCCESS) return result; @@ -282,11 +139,11 @@ uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware *rsf, * TPM may come from the factory without physical presence finalized. * Fix if necessary. */ - VBDEBUG(("TPM: physicalPresenceLifetimeLock=%d\n", - pflags.physicalPresenceLifetimeLock)); + VBDEBUG("TPM: physicalPresenceLifetimeLock=%d\n", + pflags.physicalPresenceLifetimeLock); if (!pflags.physicalPresenceLifetimeLock) { - VBDEBUG(("TPM: Finalizing physical presence\n")); - RETURN_ON_FAILURE(TlclFinalizePhysicalPresence()); + VBDEBUG("TPM: Finalizing physical presence\n"); + RETURN_ON_FAILURE(tlcl_finalize_physical_presence()); } /* @@ -294,40 +151,27 @@ uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware *rsf, * execution of a TPM_NV_DefineSpace with the handle of * TPM_NV_INDEX_LOCK. Here we create that space if it doesn't already * exist. */ - VBDEBUG(("TPM: nvLocked=%d\n", pflags.nvLocked)); + VBDEBUG("TPM: nvLocked=%d\n", pflags.nvLocked); if (!pflags.nvLocked) { - VBDEBUG(("TPM: Enabling NV locking\n")); - RETURN_ON_FAILURE(TlclSetNvLocked()); + VBDEBUG("TPM: Enabling NV locking\n"); + RETURN_ON_FAILURE(tlcl_set_nv_locked()); } /* Clear TPM owner, in case the TPM is already owned for some reason. */ - VBDEBUG(("TPM: Clearing owner\n")); - RETURN_ON_FAILURE(TPMClearAndReenable()); + VBDEBUG("TPM: Clearing owner\n"); + RETURN_ON_FAILURE(tpm_clear_and_reenable()); - /* Initializes the firmware and kernel spaces */ - Memcpy(rsf, &rsf_init, sizeof(RollbackSpaceFirmware)); - Memcpy(rsk, &rsk_init, sizeof(RollbackSpaceKernel)); - - /* Define the backup space. No need to initialize it, though. */ - RETURN_ON_FAILURE(SafeDefineSpace( - BACKUP_NV_INDEX, TPM_NV_PER_PPWRITE, BACKUP_NV_SIZE)); - - /* Define and initialize the kernel space */ - RETURN_ON_FAILURE(SafeDefineSpace(KERNEL_NV_INDEX, TPM_NV_PER_PPWRITE, - sizeof(RollbackSpaceKernel))); - RETURN_ON_FAILURE(WriteSpaceKernel(rsk)); - - /* Do the firmware space last, so we retry if we don't get this far. */ - RETURN_ON_FAILURE(SafeDefineSpace( - FIRMWARE_NV_INDEX, - TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE, - sizeof(RollbackSpaceFirmware))); - RETURN_ON_FAILURE(WriteSpaceFirmware(rsf)); + /* Defines and sets vb2 secdata space */ + vb2api_secdata_create(ctx); + RETURN_ON_FAILURE(safe_define_space(FIRMWARE_NV_INDEX, + TPM_NV_PER_GLOBALLOCK | + TPM_NV_PER_PPWRITE, + VB2_SECDATA_SIZE)); + RETURN_ON_FAILURE(write_space_firmware(ctx)); return TPM_SUCCESS; } - /* * SetupTPM starts the TPM and establishes the root of trust for the * anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a @@ -348,329 +192,107 @@ uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware *rsf, * to the TPM flashram at every reboot or wake-up, because of concerns about * the durability of the NVRAM. */ -uint32_t SetupTPM(int developer_mode, int disable_dev_request, - int clear_tpm_owner_request, RollbackSpaceFirmware* rsf) +uint32_t setup_tpm(struct vb2_context *ctx) { - uint8_t in_flags; uint8_t disable; uint8_t deactivated; uint32_t result; - uint32_t versions; - RETURN_ON_FAILURE(TlclLibInit()); + RETURN_ON_FAILURE(tlcl_lib_init()); #ifdef TEGRA_SOFT_REBOOT_WORKAROUND - result = TlclStartup(); + result = tlcl_startup(); if (result == TPM_E_INVALID_POSTINIT) { /* * Some prototype hardware doesn't reset the TPM on a CPU * reset. We do a hard reset to get around this. */ - VBDEBUG(("TPM: soft reset detected\n", result)); + VBDEBUG("TPM: soft reset detected\n", result); return TPM_E_MUST_REBOOT; } else if (result != TPM_SUCCESS) { - VBDEBUG(("TPM: TlclStartup returned %08x\n", result)); + VBDEBUG("TPM: tlcl_startup returned %08x\n", result); return result; } #else - RETURN_ON_FAILURE(TlclStartup()); + RETURN_ON_FAILURE(tlcl_startup()); #endif - /* - * Some TPMs start the self test automatically at power on. In that case we - * don't need to call ContinueSelfTest. On some (other) TPMs, - * ContinueSelfTest may block. In that case, we definitely don't want to - * call it here. For TPMs in the intersection of these two sets, we're - * screwed. (In other words: TPMs that require manually starting the - * self-test AND block will have poor performance until we split - * TlclSendReceive() into Send() and Receive(), and have a state machine to - * control setup.) - * - * This comment is likely to become obsolete in the near future, so don't - * trust it. It may have not been updated. - */ + /* + * Some TPMs start the self test automatically at power on. In that case + * we don't need to call ContinueSelfTest. On some (other) TPMs, + * continue_self_test may block. In that case, we definitely don't want + * to call it here. For TPMs in the intersection of these two sets, we + * are screwed. (In other words: TPMs that require manually starting the + * self-test AND block will have poor performance until we split + * tlcl_send_receive() into send() and receive(), and have a state + * machine to control setup.) + * + * This comment is likely to become obsolete in the near future, so + * don't trust it. It may have not been updated. + */ #ifdef TPM_MANUAL_SELFTEST #ifdef TPM_BLOCKING_CONTINUESELFTEST #warning "lousy TPM!" #endif - RETURN_ON_FAILURE(TlclContinueSelfTest()); + RETURN_ON_FAILURE(tlcl_continue_self_test()); #endif - result = TlclAssertPhysicalPresence(); + result = tlcl_assert_physical_presence(); if (result != TPM_SUCCESS) { /* * It is possible that the TPM was delivered with the physical * presence command disabled. This tries enabling it, then * tries asserting PP again. */ - RETURN_ON_FAILURE(TlclPhysicalPresenceCMDEnable()); - RETURN_ON_FAILURE(TlclAssertPhysicalPresence()); + RETURN_ON_FAILURE(tlcl_physical_presence_cmd_enable()); + RETURN_ON_FAILURE(tlcl_assert_physical_presence()); } /* Check that the TPM is enabled and activated. */ - RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated, NULL)); + RETURN_ON_FAILURE(tlcl_get_flags(&disable, &deactivated, NULL)); if (disable || deactivated) { - VBDEBUG(("TPM: disabled (%d) or deactivated (%d). Fixing...\n", - disable, deactivated)); - RETURN_ON_FAILURE(TlclSetEnable()); - RETURN_ON_FAILURE(TlclSetDeactivated(0)); - VBDEBUG(("TPM: Must reboot to re-enable\n")); + VBDEBUG("TPM: disabled (%d) or deactivated (%d). Fixing...\n", + disable, deactivated); + RETURN_ON_FAILURE(tlcl_set_enable()); + RETURN_ON_FAILURE(tlcl_set_deactivated(0)); + VBDEBUG("TPM: Must reboot to re-enable\n"); return TPM_E_MUST_REBOOT; } + VBDEBUG("TPM: SetupTPM() succeeded\n"); + return TPM_SUCCESS; +} + +uint32_t antirollback_read_space_firmware(struct vb2_context *ctx) +{ + uint32_t rv; + + rv = setup_tpm(ctx); + if (rv) + return rv; + /* Read the firmware space. */ - result = ReadSpaceFirmware(rsf); - if (TPM_E_BADINDEX == result) { - RollbackSpaceKernel rsk; - + rv = read_space_firmware(ctx); + if (rv == TPM_E_BADINDEX) { /* - * This is the first time we've run, and the TPM has not been - * initialized. Initialize it. + * This seems the first time we've run. Initialize the TPM. */ - VBDEBUG(("TPM: Not initialized yet.\n")); - RETURN_ON_FAILURE(OneTimeInitializeTPM(rsf, &rsk)); - } else if (TPM_SUCCESS != result) { - VBDEBUG(("TPM: Firmware space in a bad state; giving up.\n")); + VBDEBUG("TPM: Not initialized yet.\n"); + RETURN_ON_FAILURE(factory_initialize_tpm(ctx)); + } else if (rv != TPM_SUCCESS) { + VBDEBUG("TPM: Firmware space in a bad state; giving up.\n"); + //RETURN_ON_FAILURE(factory_initialize_tpm(ctx)); return TPM_E_CORRUPTED_STATE; } - Memcpy(&versions, &rsf->fw_versions, sizeof(versions)); - VBDEBUG(("TPM: Firmware space sv%d f%x v%x\n", - rsf->struct_version, rsf->flags, versions)); - in_flags = rsf->flags; - /* If we've been asked to clear the virtual dev-mode flag, do so now */ - if (disable_dev_request) { - rsf->flags &= ~FLAG_VIRTUAL_DEV_MODE_ON; - VBDEBUG(("TPM: Clearing virt dev-switch: f%x\n", rsf->flags)); - } - - /* - * The developer_mode value that's passed in is only set by a hardware - * dev-switch. We should OR it with the virtual switch, whether or not - * the virtual switch is used. If it's not used, it shouldn't change, - * so it doesn't matter. - */ - if (rsf->flags & FLAG_VIRTUAL_DEV_MODE_ON) - developer_mode = 1; - - /* - * Clear ownership if developer flag has toggled, or if an owner-clear - * has been requested. - */ - if ((developer_mode ? FLAG_LAST_BOOT_DEVELOPER : 0) != - (in_flags & FLAG_LAST_BOOT_DEVELOPER)) { - VBDEBUG(("TPM: Developer flag changed; clearing owner.\n")); - RETURN_ON_FAILURE(TPMClearAndReenable()); - } else if (clear_tpm_owner_request) { - VBDEBUG(("TPM: Clearing owner as specifically requested.\n")); - RETURN_ON_FAILURE(TPMClearAndReenable()); - } - - if (developer_mode) - rsf->flags |= FLAG_LAST_BOOT_DEVELOPER; - else - rsf->flags &= ~FLAG_LAST_BOOT_DEVELOPER; - - - /* If firmware space is dirty, flush it back to the TPM */ - if (rsf->flags != in_flags) { - VBDEBUG(("TPM: Updating firmware space.\n")); - RETURN_ON_FAILURE(WriteSpaceFirmware(rsf)); - } - - VBDEBUG(("TPM: SetupTPM() succeeded\n")); return TPM_SUCCESS; } - -#ifdef DISABLE_ROLLBACK_TPM -/* Dummy implementations which don't support TPM rollback protection */ - -uint32_t RollbackS3Resume(void) +uint32_t antirollback_write_space_firmware(struct vb2_context *ctx) { -#ifndef CHROMEOS_ENVIRONMENT - /* - * Initialize the TPM, but ignore return codes. In ChromeOS - * environment, don't even talk to the TPM. - */ - TlclLibInit(); - TlclResume(); -#endif - return TPM_SUCCESS; + return write_space_firmware(ctx); } -uint32_t RollbackFirmwareSetup(int is_hw_dev, - int disable_dev_request, - int clear_tpm_owner_request, - int *is_virt_dev, uint32_t *version) +uint32_t antirollback_lock_space_firmware() { -#ifndef CHROMEOS_ENVIRONMENT - /* - * Initialize the TPM, but ignores return codes. In ChromeOS - * environment, don't even talk to the TPM. - */ - TlclLibInit(); - TlclStartup(); - TlclContinueSelfTest(); -#endif - *is_virt_dev = 0; - *version = 0; - return TPM_SUCCESS; + return tlcl_set_global_lock(); } - -uint32_t RollbackFirmwareWrite(uint32_t version) -{ - return TPM_SUCCESS; -} - -uint32_t RollbackFirmwareLock(void) -{ - return TPM_SUCCESS; -} - -uint32_t RollbackKernelRead(uint32_t* version) -{ - *version = 0; - return TPM_SUCCESS; -} - -uint32_t RollbackKernelWrite(uint32_t version) -{ - return TPM_SUCCESS; -} - -uint32_t RollbackBackupRead(uint8_t *raw) -{ - return TPM_SUCCESS; -} - -uint32_t RollbackBackupWrite(uint8_t *raw) -{ - return TPM_SUCCESS; -} - -uint32_t RollbackKernelLock(int recovery_mode) -{ - return TPM_SUCCESS; -} - -#else - -uint32_t RollbackS3Resume(void) -{ - uint32_t result; - RETURN_ON_FAILURE(TlclLibInit()); - result = TlclResume(); - if (result == TPM_E_INVALID_POSTINIT) { - /* - * We're on a platform where the TPM maintains power in S3, so - * it's already initialized. - */ - return TPM_SUCCESS; - } - return result; -} - -uint32_t RollbackFirmwareSetup(int is_hw_dev, - int disable_dev_request, - int clear_tpm_owner_request, - int *is_virt_dev, uint32_t *version) -{ - RollbackSpaceFirmware rsf; - - /* Set version to 0 in case we fail */ - *version = 0; - - RETURN_ON_FAILURE(SetupTPM(is_hw_dev, disable_dev_request, - clear_tpm_owner_request, &rsf)); - Memcpy(version, &rsf.fw_versions, sizeof(*version)); - *is_virt_dev = (rsf.flags & FLAG_VIRTUAL_DEV_MODE_ON) ? 1 : 0; - VBDEBUG(("TPM: RollbackFirmwareSetup %x\n", (int)*version)); - return TPM_SUCCESS; -} - -uint32_t RollbackFirmwareWrite(uint32_t version) -{ - RollbackSpaceFirmware rsf; - uint32_t old_version; - - RETURN_ON_FAILURE(ReadSpaceFirmware(&rsf)); - Memcpy(&old_version, &rsf.fw_versions, sizeof(old_version)); - VBDEBUG(("TPM: RollbackFirmwareWrite %x --> %x\n", (int)old_version, - (int)version)); - Memcpy(&rsf.fw_versions, &version, sizeof(version)); - return WriteSpaceFirmware(&rsf); -} - -uint32_t RollbackFirmwareLock(void) -{ - return TlclSetGlobalLock(); -} - -uint32_t RollbackKernelRead(uint32_t* version) -{ - RollbackSpaceKernel rsk; - uint32_t perms, uid; - - /* - * Read the kernel space and verify its permissions. If the kernel - * space has the wrong permission, or it doesn't contain the right - * identifier, we give up. This will need to be fixed by the - * recovery kernel. We have to worry about this because at any time - * (even with PP turned off) the TPM owner can remove and redefine a - * PP-protected space (but not write to it). - */ - RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); - RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_NV_INDEX, &perms)); - Memcpy(&uid, &rsk.uid, sizeof(uid)); - if (TPM_NV_PER_PPWRITE != perms || ROLLBACK_SPACE_KERNEL_UID != uid) - return TPM_E_CORRUPTED_STATE; - - Memcpy(version, &rsk.kernel_versions, sizeof(*version)); - VBDEBUG(("TPM: RollbackKernelRead %x\n", (int)*version)); - return TPM_SUCCESS; -} - -uint32_t RollbackKernelWrite(uint32_t version) -{ - RollbackSpaceKernel rsk; - uint32_t old_version; - RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); - Memcpy(&old_version, &rsk.kernel_versions, sizeof(old_version)); - VBDEBUG(("TPM: RollbackKernelWrite %x --> %x\n", - (int)old_version, (int)version)); - Memcpy(&rsk.kernel_versions, &version, sizeof(version)); - return WriteSpaceKernel(&rsk); -} - -/* - * We don't really care whether the TPM owner has been messing with this or - * not. We lock it along with the Kernel space just to avoid problems, but it's - * only useful in dev-mode and only when the battery has been drained - * completely. There aren't any security issues. It's just in the TPM because - * we don't have any other place to keep it. - */ -uint32_t RollbackBackupRead(uint8_t *raw) -{ - uint32_t r; - r = TlclRead(BACKUP_NV_INDEX, raw, BACKUP_NV_SIZE); - VBDEBUG(("TPM: %s returning 0x%x\n", __func__, r)); - return r; -} - -uint32_t RollbackBackupWrite(uint8_t *raw) -{ - uint32_t r; - r = TlclWrite(BACKUP_NV_INDEX, raw, BACKUP_NV_SIZE); - VBDEBUG(("TPM: %s returning 0x%x\n", __func__, r)); - return r; -} - -uint32_t RollbackKernelLock(int recovery_mode) -{ - if (recovery_mode) - return TPM_SUCCESS; - else - return TlclLockPhysicalPresence(); -} - -#endif /* DISABLE_ROLLBACK_TPM */ diff --git a/src/vendorcode/google/chromeos/vboot_main.c b/src/vendorcode/google/chromeos/vboot_main.c index 8251cfd9b4..252dfb1bf8 100644 --- a/src/vendorcode/google/chromeos/vboot_main.c +++ b/src/vendorcode/google/chromeos/vboot_main.c @@ -1,10 +1,14 @@ #include <2api.h> #include <2struct.h> +#include +#include #include #include #include #include #include +#include +#include #include #include "chromeos.h" @@ -64,8 +68,12 @@ void vb2ex_printf(const char *func, const char *fmt, ...) int vb2ex_tpm_clear_owner(struct vb2_context *ctx) { - VBDEBUG("Clearing owner\n"); - return VB2_ERROR_UNKNOWN; + uint32_t rv; + VBDEBUG("Clearing TPM owner\n"); + rv = tpm_clear_and_reenable(); + if (rv) + return VB2_ERROR_EX_TPM_CLEAR_OWNER; + return VB2_SUCCESS; } int vb2ex_read_resource(struct vb2_context *ctx, @@ -222,6 +230,54 @@ static void enter_stage(struct cbfs_stage *stage) stage_exit((void *)(uintptr_t)stage->entry); } +enum { + L2CTLR_ECC_PARITY = 0x1 << 21, + L2CTLR_TAG_RAM_LATENCY_MASK = 0x7 << 6, + L2CTLR_TAG_RAM_LATENCY_CYCLES_3 = 2 << 6, + L2CTLR_DATA_RAM_LATENCY_MASK = 0x7 << 0, + L2CTLR_DATA_RAM_LATENCY_CYCLES_3 = 2 << 0 +}; + +enum { + L2ACTLR_FORCE_L2_LOGIC_CLOCK_ENABLE_ACTIVE = 0x1 << 27, + L2ACTLR_ENABLE_HAZARD_DETECT_TIMEOUT = 0x1 << 7, + L2ACTLR_DISABLE_CLEAN_EVICT_PUSH_EXTERNAL = 0x1 << 3 +}; + +/* Configures L2 Control Register to use 3 cycles for DATA/TAG RAM latency. */ +static void configure_l2ctlr(void) +{ + uint32_t val; + + val = read_l2ctlr(); + val &= ~(L2CTLR_DATA_RAM_LATENCY_MASK | L2CTLR_TAG_RAM_LATENCY_MASK); + val |= (L2CTLR_DATA_RAM_LATENCY_CYCLES_3 | L2CTLR_TAG_RAM_LATENCY_CYCLES_3 | + L2CTLR_ECC_PARITY); + write_l2ctlr(val); +} + +/* Configures L2 Auxiliary Control Register for Cortex A15. */ +static void configure_l2actlr(void) +{ + uint32_t val; + + val = read_l2actlr(); + val |= (L2ACTLR_DISABLE_CLEAN_EVICT_PUSH_EXTERNAL | + L2ACTLR_ENABLE_HAZARD_DETECT_TIMEOUT | + L2ACTLR_FORCE_L2_LOGIC_CLOCK_ENABLE_ACTIVE); + write_l2actlr(val); +} + +static void enable_cache(void) +{ + mmu_init(); + mmu_config_range(0, CONFIG_SYS_SDRAM_BASE >> 20, DCACHE_OFF); + mmu_config_range(0x40000000 >> 20, 2, DCACHE_WRITEBACK); + mmu_disable_range(0, 1); + VBDEBUG("Enabling cache\n"); + dcache_mmu_enable(); +} + /** * Save non-volatile and/or secure data if needed. */ @@ -229,16 +285,24 @@ static void save_if_needed(struct vb2_context *ctx) { if (ctx->flags & VB2_CONTEXT_NVDATA_CHANGED) { VBDEBUG("Saving nvdata\n"); - //save_vbnv(ctx->nvdata); + save_vbnv(ctx->nvdata); ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED; } if (ctx->flags & VB2_CONTEXT_SECDATA_CHANGED) { VBDEBUG("Saving secdata\n"); - //antirollback_write_space_firmware(ctx); + antirollback_write_space_firmware(ctx); ctx->flags &= ~VB2_CONTEXT_SECDATA_CHANGED; } } +/** + * Load and verify the next stage from RW image and jump to it + * + * If validation fails, it exits to romstage for recovery or reboots. + * + * TODO: Avoid loading a stage twice (once in hash_body & again in load_stage). + * when per-stage verification is ready. + */ void __attribute__((noinline)) select_firmware(void) { struct vb2_context ctx; @@ -248,7 +312,12 @@ void __attribute__((noinline)) select_firmware(void) struct cbfs_stage *stage; int rv; + /* Do minimum to enable cache and run vboot at full speed */ + configure_l2ctlr(); + configure_l2actlr(); console_init(); + exception_init(); + enable_cache(); /* Set up context */ memset(&ctx, 0, sizeof(ctx)); @@ -257,12 +326,12 @@ void __attribute__((noinline)) select_firmware(void) memset(ctx.workbuf, 0, ctx.workbuf_size); /* Read nvdata from a non-volatile storage */ - //read_vbnv(ctx.nvdata); + read_vbnv(ctx.nvdata); /* Read secdata from TPM. Initialize TPM if secdata not found. We don't * check the return value here because vb2api_fw_phase1 will catch * invalid secdata and tell us what to do (=reboot). */ - //antirollback_read_space_firmware(&ctx); + antirollback_read_space_firmware(&ctx); if (get_developer_mode_switch()) ctx.flags |= VB2_CONTEXT_FORCE_DEVELOPER_MODE;