summaryrefslogtreecommitdiff
path: root/board/cr50/usb_spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/cr50/usb_spi.c')
-rw-r--r--board/cr50/usb_spi.c766
1 files changed, 0 insertions, 766 deletions
diff --git a/board/cr50/usb_spi.c b/board/cr50/usb_spi.c
deleted file mode 100644
index 66083de4b1..0000000000
--- a/board/cr50/usb_spi.c
+++ /dev/null
@@ -1,766 +0,0 @@
-/* Copyright 2016 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "byteorder.h"
-#include "ccd_config.h"
-#include "cryptoc/sha256.h"
-#include "console.h"
-#include "dcrypto.h"
-#include "extension.h"
-#include "gpio.h"
-#include "hooks.h"
-#include "physical_presence.h"
-#include "registers.h"
-#include "spi.h"
-#include "spi_flash.h"
-#include "system.h"
-#include "task.h"
-#include "timer.h"
-#include "tpm_registers.h"
-#include "tpm_vendor_cmds.h"
-#include "usb_spi.h"
-
-#define CPRINTS(format, args...) cprints(CC_USB, format, ## args)
-
-/* Don't hash more than this at once */
-#define MAX_SPI_HASH_SIZE (4 * 1024 * 1024)
-
-/*
- * Buffer size to use for reading and hashing. This must be a multiple of the
- * SHA256 block size (64 bytes) and at least 4 less than the maximum SPI
- * transaction size for H1 (0x80 bytes). So, 64.
- */
-#define SPI_HASH_CHUNK_SIZE 64
-
-/* Timeout for auto-disabling SPI hash device, in microseconds */
-#define SPI_HASH_TIMEOUT_US (60 * SECOND)
-
-/* Current device for SPI hashing */
-static uint8_t spi_hash_device = USB_SPI_DISABLE;
-
-/*
- * Do we need to use NPCX7 gang programming mode?
- *
- * If 0, then we hold the EC in reset the whole time we've acquired the SPI
- * bus, to keep the EC from accessing it.
- *
- * If 1, then:
- *
- * When we acquire the EC SPI bus, we need to reset the EC, assert the
- * gang programmer enable, then take the EC out of reset so its boot ROM
- * can map the EC's internal SPI bus to the EC gang programmer pins.
- *
- * When we relinquish the EC SPI bus, we need to reset the EC again while
- * keeping gang programmer deasserted, then take the EC out of reset. The
- * EC will then boot normally.
- */
-static uint8_t use_npcx_gang_mode;
-
-/*
- * Device and gang mode selected by last spihash command, for use by
- * spi_hash_pp_done().
- */
-static uint8_t new_device;
-static uint8_t new_gang_mode;
-
-static void spi_hash_inactive_timeout(void);
-DECLARE_DEFERRED(spi_hash_inactive_timeout);
-
-/*****************************************************************************/
-/*
- * Mutex and variable for tracking whether the SPI bus is used by the USB
- * connection or hashing commands.
- *
- * Access these ONLY through set_spi_bus_user() and get_spi_bus_user(), to
- * ensure thread-safe access to the SPI bus.
- */
-static struct mutex spi_bus_user_mutex;
-static enum spi_bus_user_t {
- SPI_BUS_USER_NONE = 0,
- SPI_BUS_USER_USB,
- SPI_BUS_USER_HASH
-} spi_bus_user = SPI_BUS_USER_NONE;
-
-/**
- * Set who's using the SPI bus.
- *
- * This is thread-safe and will not block if someone owns the bus. You can't
- * take the bus if someone else has it, and you can only free it if you hold
- * it. It has no extra effect if you already own the bus.
- *
- * @param user What bus user is asking?
- * @param want_bus Do we want the bus (!=0) or no longer want it (==0)?
- *
- * @return EC_SUCCESS, or non-zero error code.
- */
-static int set_spi_bus_user(enum spi_bus_user_t user, int want_bus)
-{
- int rv = EC_SUCCESS;
-
- /*
- * Serialize access to bus user variable, but don't mutex lock the
- * entire bus because that would freeze USB or the console instead of
- * just failing.
- */
- mutex_lock(&spi_bus_user_mutex);
-
- if (want_bus) {
- /* Can only take the bus if it's free or we already own it */
- if (spi_bus_user == SPI_BUS_USER_NONE)
- spi_bus_user = user;
- else if (spi_bus_user != user)
- rv = EC_ERROR_BUSY;
- } else {
- /* Can only free the bus if it was ours */
- if (spi_bus_user == user)
- spi_bus_user = SPI_BUS_USER_NONE;
- else
- rv = EC_ERROR_BUSY;
- }
-
- mutex_unlock(&spi_bus_user_mutex);
-
- return rv;
-}
-
-/**
- * Get the current SPI bus user.
- */
-static enum spi_bus_user_t get_spi_bus_user(void)
-{
- return spi_bus_user;
-}
-
-/*****************************************************************************/
-/* Methods to enable / disable the SPI bus and pin mux */
-
-static void disable_ec_ap_spi(void)
-{
- int was_ap_spi_en = gpio_get_level(GPIO_AP_FLASH_SELECT);
-
- /* Disable EC SPI access. */
- gpio_set_level(GPIO_EC_FLASH_SELECT, 0);
-
- /* Disable AP SPI access. */
- if (was_ap_spi_en) {
- /*
- * The fact that AP SPI access was enabled means that the EC was
- * held in reset. Therefore, it needs to be released here.
- */
- gpio_set_level(GPIO_AP_FLASH_SELECT, 0);
- deassert_ec_rst();
- deassert_sys_rst();
- }
-}
-
-static void enable_ec_spi(void)
-{
- /* Select EC flash */
- gpio_set_level(GPIO_AP_FLASH_SELECT, 0);
- gpio_set_level(GPIO_EC_FLASH_SELECT, 1);
-
- /*
- * Note that we don't hold the EC in reset here. This is because some
- * ECs with internal SPI flash cannot be held in reset in order to
- * access the flash.
- */
-}
-
-static void enable_ap_spi(void)
-{
- /* Select AP flash */
- gpio_set_level(GPIO_AP_FLASH_SELECT, 1);
- gpio_set_level(GPIO_EC_FLASH_SELECT, 0);
-
- /*
- * On some systems SYS_RST_L is not level sensitive, so the only way to
- * be sure we're holding the AP in reset is to hold the EC in reset.
- */
- assert_ec_rst();
-}
-
-/**
- * Enable the pin mux to the SPI master port.
- */
-static void enable_spi_pinmux(void)
-{
- GWRITE_FIELD(PINMUX, DIOA4_CTL, PD, 0); /* SPI_MOSI */
- GWRITE_FIELD(PINMUX, DIOA8_CTL, PD, 0); /* SPI_CLK */
-
- /* Connect DIO A4, A8, and A14 to the SPI peripheral */
- GWRITE(PINMUX, DIOA4_SEL, 0); /* SPI_MOSI */
- GWRITE(PINMUX, DIOA8_SEL, 0); /* SPI_CS_L */
- GWRITE(PINMUX, DIOA14_SEL, 0); /* SPI_CLK */
- /* Set SPI_CS to be an internal pull up */
- GWRITE_FIELD(PINMUX, DIOA14_CTL, PU, 1);
-
- CPRINTS("%s: %s", __func__,
- gpio_get_level(GPIO_AP_FLASH_SELECT) ? "AP" : "EC");
-
- spi_enable(CONFIG_SPI_FLASH_PORT, 1);
-}
-
-/**
- * Disable the pin mux to the SPI master port.
- */
-static void disable_spi_pinmux(void)
-{
- spi_enable(CONFIG_SPI_FLASH_PORT, 0);
-
- /* Disconnect SPI peripheral to tri-state pads */
- /* Disable internal pull up */
- GWRITE_FIELD(PINMUX, DIOA14_CTL, PU, 0);
- /* TODO: Implement way to get the gpio */
- ASSERT(GREAD(PINMUX, GPIO0_GPIO7_SEL) == GC_PINMUX_DIOA4_SEL);
- ASSERT(GREAD(PINMUX, GPIO0_GPIO8_SEL) == GC_PINMUX_DIOA8_SEL);
- ASSERT(GREAD(PINMUX, GPIO0_GPIO9_SEL) == GC_PINMUX_DIOA14_SEL);
-
- GWRITE_FIELD(PINMUX, DIOA4_CTL, PD, 1); /* SPI_MOSI */
- GWRITE_FIELD(PINMUX, DIOA8_CTL, PD, 1); /* SPI_CLK */
-
- /* Set SPI MOSI, CLK, and CS_L as inputs */
- GWRITE(PINMUX, DIOA4_SEL, GC_PINMUX_GPIO0_GPIO7_SEL);
- GWRITE(PINMUX, DIOA8_SEL, GC_PINMUX_GPIO0_GPIO8_SEL);
- GWRITE(PINMUX, DIOA14_SEL, GC_PINMUX_GPIO0_GPIO9_SEL);
-}
-
-/*****************************************************************************/
-/* USB SPI methods */
-
-int usb_spi_board_enable(struct usb_spi_config const *config)
-{
- int host = config->state->enabled_host;
-
- /* Make sure we're allowed to enable the requested device */
- if (host == USB_SPI_EC) {
- if (!ccd_is_cap_enabled(CCD_CAP_EC_FLASH)) {
- CPRINTS("%s: EC access denied", __func__);
- return EC_ERROR_ACCESS_DENIED;
- }
- } else if (host == USB_SPI_AP) {
- if (!ccd_is_cap_enabled(CCD_CAP_AP_FLASH)) {
- CPRINTS("%s: AP access denied", __func__);
- return EC_ERROR_ACCESS_DENIED;
- }
- } else {
- CPRINTS("%s: device %d not supported", __func__, host);
- return EC_ERROR_INVAL;
- }
-
- if (set_spi_bus_user(SPI_BUS_USER_USB, 1) != EC_SUCCESS) {
- CPRINTS("%s: bus in use", __func__);
- return EC_ERROR_BUSY;
- }
-
- disable_ec_ap_spi();
-
- /*
- * Only need to check EC vs. AP, because other hosts were ruled out
- * above.
- */
- if (host == USB_SPI_EC)
- enable_ec_spi();
- else
- enable_ap_spi();
-
- enable_spi_pinmux();
- return EC_SUCCESS;
-}
-
-void usb_spi_board_disable(struct usb_spi_config const *config)
-{
- CPRINTS("%s", __func__);
-
- /* Only disable the SPI bus if we own it */
- if (get_spi_bus_user() != SPI_BUS_USER_USB)
- return;
-
- disable_spi_pinmux();
- disable_ec_ap_spi();
- set_spi_bus_user(SPI_BUS_USER_USB, 0);
-}
-
-int usb_spi_interface(struct usb_spi_config const *config,
- struct usb_setup_packet *req)
-{
- if (req->bmRequestType != (USB_DIR_OUT |
- USB_TYPE_VENDOR |
- USB_RECIP_INTERFACE))
- return 1;
-
- if (req->wValue != 0 ||
- req->wIndex != config->interface ||
- req->wLength != 0)
- return 1;
-
- if (!config->state->enabled_device)
- return 1;
-
- switch (req->bRequest) {
- case USB_SPI_REQ_ENABLE_AP:
- config->state->enabled_host = USB_SPI_AP;
- break;
- case USB_SPI_REQ_ENABLE_EC:
- config->state->enabled_host = USB_SPI_EC;
- break;
- case USB_SPI_REQ_ENABLE:
- CPRINTS("%s: Must specify target", __func__);
- /* Fall through... */
- case USB_SPI_REQ_DISABLE:
- config->state->enabled_host = USB_SPI_DISABLE;
- break;
-
- default:
- return 1;
- }
-
- /*
- * Our state has changed, call the deferred function to handle the
- * state change.
- */
- hook_call_deferred(config->deferred, 0);
- return 0;
-}
-
-/*****************************************************************************/
-/* Hashing support */
-
-/**
- * Returns the content of SPI flash
- *
- * @param buf_usr Buffer to write flash contents
- * @param offset Flash offset to start reading from
- * @param bytes Number of bytes to read.
- *
- * @return EC_SUCCESS, or non-zero if any error.
- */
-int spi_read_chunk(uint8_t *buf_usr, unsigned int offset, unsigned int bytes)
-{
- uint8_t cmd[4];
-
- if (bytes > SPI_HASH_CHUNK_SIZE)
- return EC_ERROR_INVAL;
-
- cmd[0] = SPI_FLASH_READ;
- cmd[1] = (offset >> 16) & 0xFF;
- cmd[2] = (offset >> 8) & 0xFF;
- cmd[3] = offset & 0xFF;
-
- return spi_transaction(SPI_FLASH_DEVICE, cmd, 4, buf_usr, bytes);
-}
-
-/**
- * Reset EC out of gang programming mode if needed.
- */
-static void spi_hash_stop_ec_device(void)
-{
- /* If device is not currently EC, nothing to do */
- if (spi_hash_device != USB_SPI_EC)
- return;
-
- if (use_npcx_gang_mode) {
- /*
- * EC was in gang mode. Pulse reset without asserting gang
- * programmer enable, so that when we take the EC out of reset
- * it will boot normally.
- */
- assert_ec_rst();
- usleep(200);
- use_npcx_gang_mode = 0;
- }
-
- /*
- * Release EC from reset (either from above, or because gang progamming
- * mode was disabled so the EC was held in reset during SPI access).
- */
- deassert_ec_rst();
-}
-
-/**
- * Disable SPI hashing mode.
- *
- * @return Vendor command return code.
- */
-static enum vendor_cmd_rc spi_hash_disable(void)
-{
- if (spi_hash_device == USB_SPI_DISABLE)
- return VENDOR_RC_SUCCESS;
-
- /* Can't disable SPI if we don't own it */
- if (get_spi_bus_user() != SPI_BUS_USER_HASH)
- return VENDOR_RC_NOT_ALLOWED;
-
- /* Disable the SPI bus and chip select */
- disable_spi_pinmux();
- disable_ec_ap_spi();
-
- /* Stop the EC device, if it was active */
- spi_hash_stop_ec_device();
-
- /* Release the bus */
- spi_hash_device = USB_SPI_DISABLE;
- new_device = USB_SPI_DISABLE;
- new_gang_mode = 0;
- set_spi_bus_user(SPI_BUS_USER_HASH, 0);
-
- /* Disable inactivity timer to turn hashing mode off */
- hook_call_deferred(&spi_hash_inactive_timeout_data, -1);
-
- CPRINTS("%s", __func__);
- return VENDOR_RC_SUCCESS;
-}
-
-/**
- * Deferred function to disable SPI hash mode on inactivity.
- */
-static void spi_hash_inactive_timeout(void)
-{
- spi_hash_disable();
-}
-
-/**
- * Callback to set up the new SPI device after physical presence check.
- */
-static void spi_hash_pp_done(void)
-{
- /* Acquire the bus */
- if (set_spi_bus_user(SPI_BUS_USER_HASH, 1)) {
- CPRINTS("%s: bus busy", __func__);
- return;
- }
-
- /* Clear previous enable if needed */
- if (spi_hash_device != USB_SPI_DISABLE)
- disable_ec_ap_spi();
-
- /* Set up new device */
- if (new_device == USB_SPI_AP) {
- /* Stop the EC device, if it was previously active */
- spi_hash_stop_ec_device();
-
- enable_ap_spi();
- } else {
- /* Force the EC into reset and enable EC SPI bus */
- assert_ec_rst();
- enable_ec_spi();
-
- /*
- * If EC is headed into gang programmer mode, need to release
- * EC from reset after acquiring the bus. EC_FLASH_SELECT runs
- * to the EC's GP_SEL_ODL signal, which is what enables gang
- * programmer mode.
- */
- if (new_gang_mode) {
- usleep(200);
- deassert_ec_rst();
- use_npcx_gang_mode = 1;
- }
- }
-
- enable_spi_pinmux();
- spi_hash_device = new_device;
-
- /* Start inactivity timer to turn hashing mode off */
- hook_call_deferred(&spi_hash_inactive_timeout_data,
- SPI_HASH_TIMEOUT_US);
-
- CPRINTS("%s: %s", __func__,
- (spi_hash_device == USB_SPI_AP ? "AP" : "EC"));
-}
-
-/* Process vendor subcommand dealing with Physical presence polling. */
-static enum vendor_cmd_rc spihash_pp_poll(void *buf,
- size_t input_size,
- size_t *response_size)
-{
- char *buffer = buf;
-
- if (spi_hash_device != USB_SPI_DISABLE) {
- buffer[0] = CCD_PP_DONE;
- } else {
- switch (physical_presense_fsm_state()) {
- case PP_AWAITING_PRESS:
- buffer[0] = CCD_PP_AWAITING_PRESS;
- break;
- case PP_BETWEEN_PRESSES:
- buffer[0] = CCD_PP_BETWEEN_PRESSES;
- break;
- default:
- buffer[0] = CCD_PP_CLOSED;
- break;
- }
- }
- *response_size = 1;
- return VENDOR_RC_SUCCESS;
-}
-
-/**
- * Set the SPI hashing device.
- *
- * @param dev Device (enum usb_spi)
- * @param gang_mode If non-zero, EC uses gang mode
- *
- * @return Vendor command return code
- */
-static enum vendor_cmd_rc spi_hash_set_device(int dev, int gang_mode,
- uint8_t *response_buf,
- size_t *response_size)
-{
- *response_size = 0;
-
- if (dev == spi_hash_device)
- return VENDOR_RC_SUCCESS;
-
- /* Enabling requires permission */
- if (!(ccd_is_cap_enabled(CCD_CAP_FLASH_READ)))
- return VENDOR_RC_NOT_ALLOWED;
-
- new_device = dev;
- new_gang_mode = gang_mode;
-
- /* Handle enabling */
- if (spi_hash_device == USB_SPI_DISABLE &&
- !(ccd_is_cap_enabled(CCD_CAP_AP_FLASH) &&
- ccd_is_cap_enabled(CCD_CAP_EC_FLASH))) {
- /*
- * We were disabled, and CCD does not grant permission
- * to both flash chips. So we need physical presence
- * to take the SPI bus. That prevents a malicious
- * peripheral from using this to reset the device.
- *
- * Technically, we could track the chips separately,
- * and only require physical presence the first time we
- * check a chip which CCD doesn't grant access to. But
- * that's more bookkeeping, so for now the only way to
- * skip physical presence is to have access to both.
- */
- int rv = physical_detect_start(0, spi_hash_pp_done);
-
- if (rv == EC_SUCCESS)
- return VENDOR_RC_IN_PROGRESS;
-
- *response_size = 1;
- response_buf[0] = rv;
-
- return VENDOR_RC_INTERNAL_ERROR;
- }
-
- /*
- * If we're still here, we already own the SPI bus, and are
- * changing which chip we're looking at. Update hash device
- * directly; no new physical presence required.
- */
- spi_hash_pp_done();
- return VENDOR_RC_SUCCESS;
-}
-
-static enum vendor_cmd_rc spi_hash_dump(uint8_t *dest, uint32_t offset,
- uint32_t size)
-{
- /* Fail if we don't own the bus */
- if (get_spi_bus_user() != SPI_BUS_USER_HASH) {
- CPRINTS("%s: not enabled", __func__);
- return VENDOR_RC_NOT_ALLOWED;
- }
-
- /* Bump inactivity timer to turn hashing mode off */
- hook_call_deferred(&spi_hash_inactive_timeout_data,
- SPI_HASH_TIMEOUT_US);
-
- if (size > SPI_HASH_MAX_RESPONSE_BYTES)
- return VENDOR_RC_BOGUS_ARGS;
-
- if (spi_read_chunk(dest, offset, size) != EC_SUCCESS) {
- CPRINTS("%s: read error at 0x%x", __func__, offset);
- return VENDOR_RC_READ_FLASH_FAIL;
- }
-
- return VENDOR_RC_SUCCESS;
-}
-
-static enum vendor_cmd_rc spi_hash_sha256(uint8_t *dest, uint32_t offset,
- uint32_t size)
-{
- HASH_CTX sha;
- uint8_t data[SPI_HASH_CHUNK_SIZE];
- int chunk_size = SPI_HASH_CHUNK_SIZE;
- int chunks = 0;
-
- /* Fail if we don't own the bus */
- if (get_spi_bus_user() != SPI_BUS_USER_HASH) {
- CPRINTS("%s: not enabled", __func__);
- return VENDOR_RC_NOT_ALLOWED;
- }
-
- /* Bump inactivity timer to turn hashing mode off */
- hook_call_deferred(&spi_hash_inactive_timeout_data,
- SPI_HASH_TIMEOUT_US);
-
- if (size > MAX_SPI_HASH_SIZE)
- return VENDOR_RC_BOGUS_ARGS;
-
- CPRINTS("%s: 0x%x 0x%x", __func__, offset, size);
-
- DCRYPTO_SHA256_init(&sha, 0);
-
- for (chunks = 0; size > 0; chunks++) {
- int this_chunk = MIN(size, chunk_size);
- /* Read the data */
- if (spi_read_chunk(data, offset, this_chunk) != EC_SUCCESS) {
- CPRINTS("%s: read error at 0x%x", __func__, offset);
- return VENDOR_RC_READ_FLASH_FAIL;
- }
-
- /* Update hash */
- HASH_update(&sha, data, this_chunk);
-
- /* Give other things a chance to happen */
- if (!(chunks % 128))
- msleep(1);
-
- size -= this_chunk;
- offset += this_chunk;
- }
-
- memcpy(dest, HASH_final(&sha), SHA256_DIGEST_SIZE);
-
- CPRINTS("%s: done", __func__);
- return VENDOR_RC_SUCCESS;
-}
-
-/*
- * TPM Vendor command handler for SPI hash commands which need to be available
- * both through CLI and over /dev/tpm0.
- */
-static enum vendor_cmd_rc spi_hash_vendor(enum vendor_cmd_cc code,
- void *buf,
- size_t input_size,
- size_t *response_size)
-{
- const struct vendor_cc_spi_hash_request *req = buf;
- enum vendor_cmd_rc rc;
-
- /* Default to no response data */
- *response_size = 0;
-
- /* Pick what to do based on subcommand. */
- switch (req->subcmd) {
- case SPI_HASH_SUBCMD_DISABLE:
- /* Handle disabling */
- return spi_hash_disable();
- case SPI_HASH_SUBCMD_AP:
- return spi_hash_set_device(USB_SPI_AP, 0, buf, response_size);
- case SPI_HASH_SUBCMD_EC:
- return spi_hash_set_device(USB_SPI_EC,
- !!(req->flags &
- SPI_HASH_FLAG_EC_GANG),
- buf, response_size);
- case SPI_HASH_SUBCMD_SHA256:
- *response_size = SHA256_DIGEST_SIZE;
- rc = spi_hash_sha256(buf, req->offset, req->size);
- if (rc != VENDOR_RC_SUCCESS)
- *response_size = 0;
- return rc;
- case SPI_HASH_SUBCMD_DUMP:
- /* Save size before we overwrite it with data */
- *response_size = req->size;
- rc = spi_hash_dump(buf, req->offset, req->size);
- if (rc != VENDOR_RC_SUCCESS)
- *response_size = 0;
- return rc;
- case SPI_HASH_PP_POLL:
- return spihash_pp_poll(buf, input_size, response_size);
-
- default:
- CPRINTS("%s:%d - unknown subcommand %d",
- __func__, __LINE__, req->subcmd);
- *response_size = 0;
- return VENDOR_RC_NO_SUCH_SUBCOMMAND;
- }
-}
-DECLARE_VENDOR_COMMAND(VENDOR_CC_SPI_HASH, spi_hash_vendor);
-
-/**
- * Wrapper for hash commands which are passed through the TPM task context.
- */
-static int hash_command_wrapper(int argc, char *argv[])
-{
- int rv;
- struct vendor_cc_spi_hash_request req;
- struct tpm_cmd_header *tpm_header;
- const size_t command_size = sizeof(*tpm_header) +
- MAX(sizeof(req), SPI_HASH_MAX_RESPONSE_BYTES);
- uint8_t buf[command_size];
- uint8_t *p;
- uint32_t return_code;
-
- /* If no args, just return */
- if (argc < 2) {
- ccprintf("SPI hash device: %s\n",
- (spi_hash_device ?
- (spi_hash_device == USB_SPI_AP ? "AP" : "EC") :
- "disable"));
- return EC_SUCCESS;
- }
-
- /* Parse args into stack-based struct */
- memset(&req, 0, sizeof(req));
- if (!strcasecmp(argv[1], "AP")) {
- req.subcmd = SPI_HASH_SUBCMD_AP;
- } else if (!strcasecmp(argv[1], "EC")) {
- req.subcmd = SPI_HASH_SUBCMD_EC;
- if (argc > 2 && !strcasecmp(argv[2], "gang"))
- req.flags |= SPI_HASH_FLAG_EC_GANG;
- } else if (!strcasecmp(argv[1], "disable")) {
- req.subcmd = SPI_HASH_SUBCMD_DISABLE;
- } else if (argc == 3) {
- req.subcmd = SPI_HASH_SUBCMD_SHA256;
- rv = parse_offset_size(argc, argv, 1, &req.offset, &req.size);
- if (rv)
- return rv;
- } else if (argc == 4 && !strcasecmp(argv[1], "dump")) {
- req.subcmd = SPI_HASH_SUBCMD_DUMP;
- rv = parse_offset_size(argc, argv, 2, &req.offset, &req.size);
- if (rv)
- return rv;
- } else {
- return EC_ERROR_PARAM1;
- }
-
- /* Build the extension command */
- tpm_header = (struct tpm_cmd_header *)buf;
- tpm_header->tag = htobe16(0x8001); /* TPM_ST_NO_SESSIONS */
- tpm_header->size = htobe32(command_size);
- tpm_header->command_code = htobe32(TPM_CC_VENDOR_BIT_MASK);
- tpm_header->subcommand_code = htobe16(VENDOR_CC_SPI_HASH);
- /* Copy request data */
- p = (uint8_t *)(tpm_header + 1);
- memcpy(p, &req, sizeof(req));
-
- tpm_alt_extension(tpm_header, command_size);
-
- /*
- * Return status in the command code field now, in case of error,
- * error code is the first byte after the header.
- */
- return_code = be32toh(tpm_header->command_code);
-
- if ((return_code != EC_SUCCESS) &&
- ((return_code - VENDOR_RC_ERR) != VENDOR_RC_IN_PROGRESS)) {
- rv = p[0];
- } else {
- rv = EC_SUCCESS;
-
- if (req.subcmd == SPI_HASH_SUBCMD_DUMP)
- ccprintf("data: %ph\n", HEX_BUF(p, req.size));
- else if (req.subcmd == SPI_HASH_SUBCMD_SHA256)
- ccprintf("hash: %ph\n", HEX_BUF(p, 32));
- }
-
- return rv;
-}
-DECLARE_SAFE_CONSOLE_COMMAND(spihash, hash_command_wrapper,
- "ap | ec [gang] | disable | [dump] <offset> <size>",
- "Hash SPI flash via TPM vendor command");