/* * errors.c: parse and return status of Intel(r) TXT error codes * * Copyright (c) 2003-2011, Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include static void display_errors(void) { txt_errorcode_t err; txt_ests_t ests; txt_e2sts_t e2sts; txt_errorcode_sw_t sw_err; acmod_error_t acmod_err; /* * display TXT.ERRORODE error */ err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE); if (err._raw == 0 || err._raw == 0xc0000001 || err._raw == 0xc0000009) printk(TBOOT_INFO"TXT.ERRORCODE: 0x%Lx\n", err._raw); else printk(TBOOT_ERR"TXT.ERRORCODE: 0x%Lx\n", err._raw); /* AC module error (don't know how to parse other errors) */ if ( err.valid ) { if ( err.external == 0 ) /* processor error */ printk(TBOOT_ERR"\t processor error 0x%x\n", (uint32_t)err.type); else { /* external SW error */ sw_err._raw = err.type; if ( sw_err.src == 1 ) /* unknown SW error */ printk(TBOOT_ERR"unknown SW error 0x%x:0x%x\n", sw_err.err1, sw_err.err2); else { /* ACM error */ acmod_err._raw = sw_err._raw; if ( acmod_err._raw == 0x0 || acmod_err._raw == 0x1 || acmod_err._raw == 0x9 ) printk(TBOOT_INFO"AC module error : acm_type=0x%x, progress=0x%02x, " "error=0x%x\n", acmod_err.acm_type, acmod_err.progress, acmod_err.error); else printk(TBOOT_ERR"AC module error : acm_type=0x%x, progress=0x%02x, " "error=0x%x\n", acmod_err.acm_type, acmod_err.progress, acmod_err.error); /* error = 0x0a, progress = 0x0d => TPM error */ if ( acmod_err.error == 0x0a && acmod_err.progress == 0x0d ) printk(TBOOT_ERR"TPM error code = 0x%x\n", acmod_err.tpm_err); /* progress = 0x10 => LCP2 error */ else if ( acmod_err.progress == 0x10 && acmod_err.lcp_minor != 0 ) printk(TBOOT_ERR"LCP2 error: minor error = 0x%x, index = %u\n", acmod_err.lcp_minor, acmod_err.lcp_index); } } } /* * display TXT.ESTS error */ ests = (txt_ests_t)read_pub_config_reg(TXTCR_ESTS); if (ests._raw == 0) printk(TBOOT_INFO"TXT.ESTS: 0x%Lx\n", ests._raw); else printk(TBOOT_ERR"TXT.ESTS: 0x%Lx\n", ests._raw); /* * display TXT.E2STS error */ e2sts = (txt_e2sts_t)read_pub_config_reg(TXTCR_E2STS); if (e2sts._raw == 0 || e2sts._raw == 0x200000000) printk(TBOOT_INFO"TXT.E2STS: 0x%Lx\n", e2sts._raw); else printk(TBOOT_ERR"TXT.E2STS: 0x%Lx\n", e2sts._raw); } bool txt_get_error(void) { txt_errorcode_t err; display_errors(); err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE); if ( err.valid ) return false; else return true; } #define CLASS_ACM_ENTRY 0x1 enum ENUM_ACM_ENTRY { ERR_LAUNCH = 1, ERR_NEM_ENABLED, ERR_CPU_LT_TYPE, ERR_DEV_ID, ERR_CPU_ID, ERR_NO_UCODE_UPDATE , ERR_DEBUG_MCU, ERR_DMI_LINK_DOWN, ERR_ACM_REVOKED, ERR_TPM_DOUBLE_AUX }; #define CLASS_TPM_ACCESS 0x4 enum ENUM_TPM_ACCESS { ERR_OK, /* Indicator of successful execution of the function.*/ ERR_TPM_ERROR, /* TPM returned an error */ ERR_LOCALITY, ERR_ACC_INVLD, ERR_NV_UNLOCKED, /* TPM NV RAM not locked */ ERR_TPM_DISABLED, /* TPM is disabled */ ERR_TPM_DEACTIVATED, /* TPM is deactivated */ ERR_TPM_NV_INDEX_INVALID, /* TPM NV indices incorrectly defined */ ERR_TPM_INCOMPET_BIOSAC, /* Incompatible BIOS ACM */ ERR_TPM_INCOMPET_AUXREV, /* Incompatible AUX revision */ ERR_TPM_INBUF_TOO_SHORT, /* Input buffer is too short */ ERR_TPM_OUTBUF_TOO_SHORT, /* Output buffer is too short */ ERR_TPM_NV_PO_INDEX_INVALID = 0x10, /* * Errors returned by TPM driver */ ERR_OUTPUT_BUFFER_TOO_SHORT = 0x1B, /* Output buffer for the TPM response to short */ ERR_INVALID_INPUT_PARA = 0x1C, /* Input parameter for the function invalid */ ERR_INVALID_RESPONSE_WR = 0x1D, /* The response from the TPM was invalid */ ERR_INVALID_RESPONSE_RD = 0x1E, /* The response from the TPM was invalid */ ERR_RESPONSE_TIMEOUT = 0x1F /* Time out for TPM response */ }; #define CLASS_MISC_CONFIG 0x8 enum ENUM_MISC_CONFIG { ERR_INTERRUPT = 1, ERR_FORBIDDEN_BY_OWNER = 0x10, ERR_TOOL_LAUNCH, ERR_CANNOT_REVERSE, ERR_ALREADY_REVOKED, ERR_INVALID_RETURN_ADDR, ERR_NO_TPM, }; void txt_get_racm_error(void) { txt_errorcode_t err; acmod_error_t acmod_err; /* * display TXT.ERRORODE error */ err = (txt_errorcode_t)read_pub_config_reg(TXTCR_ERRORCODE); /* AC module error (don't know how to parse other errors) */ if ( err.valid == 0 ) { printk(TBOOT_ERR "Cannot retrieve status - ERRORSTS register is not valid.\n"); return; } if ( err.external == 0 ) { /* processor error */ printk(TBOOT_ERR"CPU generated error 0x%x\n", (uint32_t)err.type); return; } acmod_err._raw = err.type; if ( acmod_err.src == 1 ) { printk(TBOOT_ERR"Unknown SW error.\n"); return; } if ( acmod_err.acm_type != 0x9 ) { printk(TBOOT_ERR "Cannot retrieve status - wrong ACM type in ERRORSTS register.\n"); return; } if ( acmod_err.progress == CLASS_ACM_ENTRY && acmod_err.error == ERR_TPM_DOUBLE_AUX ) { printk(TBOOT_ERR "Nothing to do: double AUX index is not valid TXT configuration.\n"); return; } if ( acmod_err.progress == CLASS_TPM_ACCESS && acmod_err.error == ERR_TPM_NV_INDEX_INVALID ) { printk(TBOOT_ERR "Nothing to do: invalid AUX index attributes.\n"); return; } if ( acmod_err.progress == CLASS_TPM_ACCESS && acmod_err.error == ERR_TPM_NV_PO_INDEX_INVALID ) { printk(TBOOT_ERR "Error: invalid PO index attributes.\n"); return; } if ( acmod_err.progress == CLASS_MISC_CONFIG && acmod_err.error == ERR_ALREADY_REVOKED ) { printk(TBOOT_ERR "Nothing to do: already revoked.\n"); return; } if ( acmod_err.progress == CLASS_MISC_CONFIG && acmod_err.error == ERR_FORBIDDEN_BY_OWNER ) { printk(TBOOT_ERR "Error: revocation forbidden by owner.\n"); return; } if ( acmod_err.progress == CLASS_MISC_CONFIG && acmod_err.error == ERR_CANNOT_REVERSE ) { printk(TBOOT_ERR "Error: cannot decrement revocation version.\n"); return; } if ( acmod_err.progress == CLASS_MISC_CONFIG && acmod_err.error == ERR_INVALID_RETURN_ADDR ) { printk(TBOOT_ERR "Error: invalid input address of return point.\n"); return; } if ( acmod_err.progress == CLASS_MISC_CONFIG && acmod_err.error == ERR_NO_TPM ) { printk(TBOOT_ERR "Nothing to do: No TPM present.\n"); return; } if ( acmod_err.progress == 0 && acmod_err.error == 0 ) { printk(TBOOT_INFO "Success: Revocation completed.\n"); return; } printk(TBOOT_ERR"RACM generated error 0x%Lx.\n", err._raw); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */