int last_stage_init(void)
{
#ifndef CONFIG_SPL_BUILD
	ccdc_eth_init();
#endif
	if (tpm_init() || tpm_startup(TPM_ST_CLEAR) ||
	    tpm_continue_self_test()) {
		return 1;
	}

	mdelay(37);

	flush_keys();
	load_and_run_keyprog();

	return 0;
}
Example #2
0
static int do_tpm_startup(cmd_tbl_t *cmdtp, int flag,
		int argc, char * const argv[])
{
	enum tpm_startup_type mode;

	if (argc != 2)
		return CMD_RET_USAGE;
	if (!strcasecmp("TPM_ST_CLEAR", argv[1])) {
		mode = TPM_ST_CLEAR;
	} else if (!strcasecmp("TPM_ST_STATE", argv[1])) {
		mode = TPM_ST_STATE;
	} else if (!strcasecmp("TPM_ST_DEACTIVATED", argv[1])) {
		mode = TPM_ST_DEACTIVATED;
	} else {
		printf("Couldn't recognize mode string: %s\n", argv[1]);
		return CMD_RET_FAILURE;
	}

	return convert_return_code(tpm_startup(mode));
}
Example #3
0
int tpm_get_timeouts(struct tpm_chip *chip)
{
	struct tpm_cmd_t tpm_cmd;
	unsigned long new_timeout[4];
	unsigned long old_timeout[4];
	struct duration_t *duration_cap;
	ssize_t rc;

	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
		/* Fixed timeouts for TPM2 */
		chip->timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
		chip->timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
		chip->timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
		chip->timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
		chip->duration[TPM_SHORT] =
		    msecs_to_jiffies(TPM2_DURATION_SHORT);
		chip->duration[TPM_MEDIUM] =
		    msecs_to_jiffies(TPM2_DURATION_MEDIUM);
		chip->duration[TPM_LONG] =
		    msecs_to_jiffies(TPM2_DURATION_LONG);
		return 0;
	}

	tpm_cmd.header.in = tpm_getcap_header;
	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
			      NULL);

	if (rc == TPM_ERR_INVALID_POSTINIT) {
		/* The TPM is not started, we are the first to talk to it.
		   Execute a startup command. */
		dev_info(&chip->dev, "Issuing TPM_STARTUP");
		if (tpm_startup(chip, TPM_ST_CLEAR))
			return rc;

		tpm_cmd.header.in = tpm_getcap_header;
		tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
		tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
		rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
				      0, NULL);
	}
	if (rc) {
		dev_err(&chip->dev,
			"A TPM error (%zd) occurred attempting to determine the timeouts\n",
			rc);
		goto duration;
	}

	if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
	    be32_to_cpu(tpm_cmd.header.out.length)
	    != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32))
		return -EINVAL;

	old_timeout[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a);
	old_timeout[1] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.b);
	old_timeout[2] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.c);
	old_timeout[3] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.d);
	memcpy(new_timeout, old_timeout, sizeof(new_timeout));

	/*
	 * Provide ability for vendor overrides of timeout values in case
	 * of misreporting.
	 */
	if (chip->ops->update_timeouts != NULL)
		chip->timeout_adjusted =
			chip->ops->update_timeouts(chip, new_timeout);

	if (!chip->timeout_adjusted) {
		/* Don't overwrite default if value is 0 */
		if (new_timeout[0] != 0 && new_timeout[0] < 1000) {
			int i;

			/* timeouts in msec rather usec */
			for (i = 0; i != ARRAY_SIZE(new_timeout); i++)
				new_timeout[i] *= 1000;
			chip->timeout_adjusted = true;
		}
	}

	/* Report adjusted timeouts */
	if (chip->timeout_adjusted) {
		dev_info(&chip->dev,
			 HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n",
			 old_timeout[0], new_timeout[0],
			 old_timeout[1], new_timeout[1],
			 old_timeout[2], new_timeout[2],
			 old_timeout[3], new_timeout[3]);
	}

	chip->timeout_a = usecs_to_jiffies(new_timeout[0]);
	chip->timeout_b = usecs_to_jiffies(new_timeout[1]);
	chip->timeout_c = usecs_to_jiffies(new_timeout[2]);
	chip->timeout_d = usecs_to_jiffies(new_timeout[3]);

duration:
	tpm_cmd.header.in = tpm_getcap_header;
	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;

	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
			      "attempting to determine the durations");
	if (rc)
		return rc;

	if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
	    be32_to_cpu(tpm_cmd.header.out.length)
	    != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32))
		return -EINVAL;

	duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
	chip->duration[TPM_SHORT] =
	    usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short));
	chip->duration[TPM_MEDIUM] =
	    usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium));
	chip->duration[TPM_LONG] =
	    usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long));

	/* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
	 * value wrong and apparently reports msecs rather than usecs. So we
	 * fix up the resulting too-small TPM_SHORT value to make things work.
	 * We also scale the TPM_MEDIUM and -_LONG values by 1000.
	 */
	if (chip->duration[TPM_SHORT] < (HZ / 100)) {
		chip->duration[TPM_SHORT] = HZ;
		chip->duration[TPM_MEDIUM] *= 1000;
		chip->duration[TPM_LONG] *= 1000;
		chip->duration_adjusted = true;
		dev_info(&chip->dev, "Adjusting TPM timeout parameters.");
	}
	return 0;
}
Example #4
0
u32 tpm_resume(struct udevice *dev)
{
	return tpm_startup(dev, TPM_ST_STATE);
}