VbError_t VbExEcHashRW(const uint8_t **hash, int *hash_size) { static struct ec_response_vboot_hash resp; if (cros_ec_read_hash(&resp) < 0) { printf("Failed to read EC hash.\n"); return VBERROR_UNKNOWN; } /* * TODO ([email protected]): the code below isn't very tolerant * of errors. * * If the EC is busy calculating a hash, we should wait and retry * reading the hash status. * * If the hash is unavailable, the wrong type, or covers the wrong * offset/size (which we need to get from the FDT, since it's * board-specific), we should request a new hash and wait for it to * finish. Also need a flag to force it to rehash, which we'll use * after doing a firmware update. */ if (resp.status != EC_VBOOT_HASH_STATUS_DONE) { printf("EC hash wasn't finished.\n"); return VBERROR_UNKNOWN; } if (resp.hash_type != EC_VBOOT_HASH_TYPE_SHA256) { printf("EC hash was the wrong type.\n"); return VBERROR_UNKNOWN; } *hash = resp.hash_digest; *hash_size = resp.digest_size; return VBERROR_SUCCESS; }
static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct cros_ec_dev *dev; struct udevice *udev; const char *cmd; int ret = 0; if (argc < 2) return CMD_RET_USAGE; cmd = argv[1]; if (0 == strcmp("init", cmd)) { /* Remove any existing device */ ret = uclass_find_device(UCLASS_CROS_EC, 0, &udev); if (!ret) device_remove(udev); ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev); if (ret) { printf("Could not init cros_ec device (err %d)\n", ret); return 1; } return 0; } ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev); if (ret) { printf("Cannot get cros-ec device (err=%d)\n", ret); return 1; } dev = dev_get_uclass_priv(udev); if (0 == strcmp("id", cmd)) { char id[MSG_BYTES]; if (cros_ec_read_id(dev, id, sizeof(id))) { debug("%s: Could not read KBC ID\n", __func__); return 1; } printf("%s\n", id); } else if (0 == strcmp("info", cmd)) { struct ec_response_mkbp_info info; if (cros_ec_info(dev, &info)) { debug("%s: Could not read KBC info\n", __func__); return 1; } printf("rows = %u\n", info.rows); printf("cols = %u\n", info.cols); printf("switches = %#x\n", info.switches); } else if (0 == strcmp("curimage", cmd)) { enum ec_current_image image; if (cros_ec_read_current_image(dev, &image)) { debug("%s: Could not read KBC image\n", __func__); return 1; } printf("%d\n", image); } else if (0 == strcmp("hash", cmd)) { struct ec_response_vboot_hash hash; int i; if (cros_ec_read_hash(dev, &hash)) { debug("%s: Could not read KBC hash\n", __func__); return 1; } if (hash.hash_type == EC_VBOOT_HASH_TYPE_SHA256) printf("type: SHA-256\n"); else printf("type: %d\n", hash.hash_type); printf("offset: 0x%08x\n", hash.offset); printf("size: 0x%08x\n", hash.size); printf("digest: "); for (i = 0; i < hash.digest_size; i++) printf("%02x", hash.hash_digest[i]); printf("\n"); } else if (0 == strcmp("reboot", cmd)) { int region; enum ec_reboot_cmd cmd; if (argc >= 3 && !strcmp(argv[2], "cold")) cmd = EC_REBOOT_COLD; else { region = cros_ec_decode_region(argc - 2, argv + 2); if (region == EC_FLASH_REGION_RO) cmd = EC_REBOOT_JUMP_RO; else if (region == EC_FLASH_REGION_RW) cmd = EC_REBOOT_JUMP_RW; else return CMD_RET_USAGE; } if (cros_ec_reboot(dev, cmd, 0)) { debug("%s: Could not reboot KBC\n", __func__); return 1; } } else if (0 == strcmp("events", cmd)) { uint32_t events; if (cros_ec_get_host_events(dev, &events)) { debug("%s: Could not read host events\n", __func__); return 1; } printf("0x%08x\n", events); } else if (0 == strcmp("clrevents", cmd)) { uint32_t events = 0x7fffffff; if (argc >= 3) events = simple_strtol(argv[2], NULL, 0); if (cros_ec_clear_host_events(dev, events)) { debug("%s: Could not clear host events\n", __func__); return 1; } } else if (0 == strcmp("read", cmd)) { ret = do_read_write(dev, 0, argc, argv); if (ret > 0) return CMD_RET_USAGE; } else if (0 == strcmp("write", cmd)) { ret = do_read_write(dev, 1, argc, argv); if (ret > 0) return CMD_RET_USAGE; } else if (0 == strcmp("erase", cmd)) { int region = cros_ec_decode_region(argc - 2, argv + 2); uint32_t offset, size; if (region == -1) return CMD_RET_USAGE; if (cros_ec_flash_offset(dev, region, &offset, &size)) { debug("%s: Could not read region info\n", __func__); ret = -1; } else { ret = cros_ec_flash_erase(dev, offset, size); if (ret) { debug("%s: Could not erase region\n", __func__); } } } else if (0 == strcmp("regioninfo", cmd)) { int region = cros_ec_decode_region(argc - 2, argv + 2); uint32_t offset, size; if (region == -1) return CMD_RET_USAGE; ret = cros_ec_flash_offset(dev, region, &offset, &size); if (ret) { debug("%s: Could not read region info\n", __func__); } else { printf("Region: %s\n", region == EC_FLASH_REGION_RO ? "RO" : "RW"); printf("Offset: %x\n", offset); printf("Size: %x\n", size); } } else if (0 == strcmp("vbnvcontext", cmd)) { uint8_t block[EC_VBNV_BLOCK_SIZE]; char buf[3]; int i, len; unsigned long result; if (argc <= 2) { ret = cros_ec_read_vbnvcontext(dev, block); if (!ret) { printf("vbnv_block: "); for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) printf("%02x", block[i]); putc('\n'); } } else { /* * TODO(clchiou): Move this to a utility function as * cmd_spi might want to call it. */ memset(block, 0, EC_VBNV_BLOCK_SIZE); len = strlen(argv[2]); buf[2] = '\0'; for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) { if (i * 2 >= len) break; buf[0] = argv[2][i * 2]; if (i * 2 + 1 >= len) buf[1] = '0'; else buf[1] = argv[2][i * 2 + 1]; strict_strtoul(buf, 16, &result); block[i] = result; } ret = cros_ec_write_vbnvcontext(dev, block); } if (ret) { debug("%s: Could not %s VbNvContext\n", __func__, argc <= 2 ? "read" : "write"); } } else if (0 == strcmp("test", cmd)) { int result = cros_ec_test(dev); if (result) printf("Test failed with error %d\n", result); else puts("Test passed\n"); } else if (0 == strcmp("version", cmd)) { struct ec_response_get_version *p; char *build_string; ret = cros_ec_read_version(dev, &p); if (!ret) { /* Print versions */ printf("RO version: %1.*s\n", (int)sizeof(p->version_string_ro), p->version_string_ro); printf("RW version: %1.*s\n", (int)sizeof(p->version_string_rw), p->version_string_rw); printf("Firmware copy: %s\n", (p->current_image < ARRAY_SIZE(ec_current_image_name) ? ec_current_image_name[p->current_image] : "?")); ret = cros_ec_read_build_info(dev, &build_string); if (!ret) printf("Build info: %s\n", build_string); } } else if (0 == strcmp("ldo", cmd)) { uint8_t index, state; char *endp; if (argc < 3) return CMD_RET_USAGE; index = simple_strtoul(argv[2], &endp, 10); if (*argv[2] == 0 || *endp != 0) return CMD_RET_USAGE; if (argc > 3) { state = simple_strtoul(argv[3], &endp, 10); if (*argv[3] == 0 || *endp != 0) return CMD_RET_USAGE; ret = cros_ec_set_ldo(udev, index, state); } else { ret = cros_ec_get_ldo(udev, index, &state); if (!ret) { printf("LDO%d: %s\n", index, state == EC_LDO_STATE_ON ? "on" : "off"); } } if (ret) { debug("%s: Could not access LDO%d\n", __func__, index); return ret; } } else { return CMD_RET_USAGE; } if (ret < 0) { printf("Error: CROS-EC command failed (error %d)\n", ret); ret = 1; } return ret; }