| /* |
| * Copyright (c) 2011 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. |
| * |
| * Alternatively, this software may be distributed under the terms of the |
| * GNU General Public License ("GPL") version 2 as published by the Free |
| * Software Foundation. |
| */ |
| |
| /* |
| * Debug commands for testing basic verified-boot related utilities. |
| */ |
| |
| #include <common.h> |
| #include <command.h> |
| #include <chromeos/cros_gpio.h> |
| #include <chromeos/fdt_decode.h> |
| #include <chromeos/firmware_storage.h> |
| #include <chromeos/memory_wipe.h> |
| #include <vboot_api.h> |
| |
| /* |
| * TODO: Pick a better region for test instead of GBB. |
| * We now test the region of GBB. |
| */ |
| #define TEST_FW_START 0xc1000 |
| #define DEFAULT_TEST_FW_LENGTH 0x1000 |
| |
| static int do_vboot_test_fwrw(cmd_tbl_t *cmdtp, |
| int flag, int argc, char * const argv[]) |
| { |
| int ret = 0; |
| firmware_storage_t file; |
| uint32_t test_length, i; |
| uint8_t *original_buf, *target_buf, *verify_buf; |
| uint64_t t0, t1; |
| |
| switch (argc) { |
| case 1: /* if no argument given, use the default length */ |
| test_length = DEFAULT_TEST_FW_LENGTH; |
| break; |
| case 2: /* use argument */ |
| test_length = simple_strtoul(argv[1], NULL, 16); |
| if (!test_length) { |
| VbExDebug("The first argument is not a number!\n"); |
| return cmd_usage(cmdtp); |
| } |
| break; |
| default: |
| return cmd_usage(cmdtp); |
| } |
| |
| /* Allocate the buffer and fill the target test pattern. */ |
| original_buf = VbExMalloc(test_length); |
| target_buf = VbExMalloc(test_length); |
| verify_buf = VbExMalloc(test_length); |
| |
| /* Fill the target test pattern. */ |
| for (i = 0; i < test_length; i++) |
| target_buf[i] = i & 0xff; |
| |
| /* Open firmware storage device. */ |
| if (firmware_storage_open_spi(&file)) { |
| VbExDebug("Failed to open firmware device!\n"); |
| return 1; |
| } |
| |
| t0 = VbExGetTimer(); |
| if (file.read(&file, TEST_FW_START, test_length, original_buf)) { |
| VbExDebug("Failed to read firmware!\n"); |
| goto out; |
| } |
| t1 = VbExGetTimer(); |
| VbExDebug("test_fwrw: fw_read, length: %#x, time: %llu\n", |
| test_length, t1 - t0); |
| |
| t0 = VbExGetTimer(); |
| ret = file.write(&file, TEST_FW_START, test_length, target_buf); |
| t1 = VbExGetTimer(); |
| VbExDebug("test_fwrw: fw_write, length: %#x, time: %llu\n", |
| test_length, t1 - t0); |
| |
| if (ret) { |
| VbExDebug("Failed to write firmware!\n"); |
| ret = 1; |
| } else { |
| /* Read back and verify the data. */ |
| file.read(&file, TEST_FW_START, test_length, verify_buf); |
| if (memcmp(target_buf, verify_buf, test_length) != 0) { |
| VbExDebug("Verify failed. The target data wrote " |
| "wrong.\n"); |
| ret = 1; |
| } |
| } |
| |
| /* Write the original data back. */ |
| if (file.write(&file, TEST_FW_START, test_length, original_buf)) { |
| VbExDebug("Failed to write the original data back. The " |
| "firmware may now be corrupt.\n"); |
| |
| } |
| |
| out: |
| file.close(&file); |
| |
| VbExFree(original_buf); |
| VbExFree(target_buf); |
| VbExFree(verify_buf); |
| |
| if (ret == 0) |
| VbExDebug("Read and write firmware test SUCCESS.\n"); |
| |
| return ret; |
| } |
| |
| static int do_vboot_test_memwipe(cmd_tbl_t *cmdtp, |
| int flag, int argc, char * const argv[]) |
| { |
| memory_wipe_t wipe; |
| char s[] = "ABCDEFGHIJ"; |
| const char r[] = "\0BCDE\0GHIJ"; |
| const size_t size = strlen(s); |
| uintptr_t base = (uintptr_t)s; |
| |
| memory_wipe_init(&wipe); |
| memory_wipe_add(&wipe, base + 0, base + 1); |
| /* Result: -BCDEFGHIJ */ |
| memory_wipe_sub(&wipe, base + 1, base + 2); |
| /* Result: -BCDEFGHIJ */ |
| memory_wipe_add(&wipe, base + 1, base + 2); |
| /* Result: --CDEFGHIJ */ |
| memory_wipe_sub(&wipe, base + 1, base + 2); |
| /* Result: -BCDEFGHIJ */ |
| memory_wipe_add(&wipe, base + 0, base + 2); |
| /* Result: --CDEFGHIJ */ |
| memory_wipe_sub(&wipe, base + 1, base + 3); |
| /* Result: -BCDEFGHIJ */ |
| memory_wipe_add(&wipe, base + 4, base + 6); |
| /* Result: -BCD--GHIJ */ |
| memory_wipe_add(&wipe, base + 3, base + 4); |
| /* Result: -BC---GHIJ */ |
| memory_wipe_sub(&wipe, base + 3, base + 7); |
| /* Result: -BCDEFGHIJ */ |
| memory_wipe_add(&wipe, base + 2, base + 8); |
| /* Result: -B------IJ */ |
| memory_wipe_sub(&wipe, base + 1, base + 9); |
| /* Result: -BCDEFGHIJ */ |
| memory_wipe_add(&wipe, base + 4, base + 7); |
| /* Result: -BCD---HIJ */ |
| memory_wipe_sub(&wipe, base + 3, base + 5); |
| /* Result: -BCDE--HIJ */ |
| memory_wipe_sub(&wipe, base + 6, base + 8); |
| /* Result: -BCDE-GHIJ */ |
| memory_wipe_execute(&wipe); |
| |
| if (memcmp(s, r, size)) { |
| int i; |
| |
| VbExDebug("Expected: "); |
| for (i = 0; i < size; i++) |
| VbExDebug("%c", r[i] ? r[i] : '-'); |
| VbExDebug("\nGot: "); |
| for (i = 0; i < size; i++) |
| VbExDebug("%c", s[i] ? s[i] : '-'); |
| VbExDebug("\nFailed to wipe the expected regions!\n"); |
| return 1; |
| } |
| |
| VbExDebug("Memory wipe test SUCCESS!\n"); |
| return 0; |
| } |
| |
| static int do_vboot_test_gpio(cmd_tbl_t *cmdtp, |
| int flag, int argc, char * const argv[]) |
| { |
| cros_gpio_t gpio; |
| int i; |
| |
| for (i = 0; i < CROS_GPIO_MAX_GPIO; i++) { |
| if (cros_gpio_fetch(i, &gpio)) { |
| VbExDebug("Failed to fetch GPIO, %d!\n", i); |
| return 1; |
| } |
| if (cros_gpio_dump(&gpio)) { |
| VbExDebug("Failed to dump GPIO, %d!\n", i); |
| return 1; |
| } |
| } |
| return 0; |
| } |
| |
| static int do_vboot_test_all(cmd_tbl_t *cmdtp, |
| int flag, int argc, char * const argv[]) |
| { |
| int ret = 0; |
| |
| ret |= do_vboot_test_fwrw(cmdtp, flag, argc, argv); |
| ret |= do_vboot_test_memwipe(cmdtp, flag, argc, argv); |
| ret |= do_vboot_test_gpio(cmdtp, flag, argc, argv); |
| |
| return ret; |
| } |
| |
| static cmd_tbl_t cmd_vboot_test_sub[] = { |
| U_BOOT_CMD_MKENT(all, 0, 1, do_vboot_test_all, "", ""), |
| U_BOOT_CMD_MKENT(fwrw, 0, 1, do_vboot_test_fwrw, "", ""), |
| U_BOOT_CMD_MKENT(memwipe, 0, 1, do_vboot_test_memwipe, "", ""), |
| U_BOOT_CMD_MKENT(gpio, 0, 1, do_vboot_test_gpio, "", ""), |
| }; |
| |
| static int do_vboot_test(cmd_tbl_t *cmdtp, |
| int flag, int argc, char * const argv[]) |
| { |
| cmd_tbl_t *c; |
| |
| if (argc < 2) |
| return cmd_usage(cmdtp); |
| argc--; |
| argv++; |
| |
| c = find_cmd_tbl(argv[0], &cmd_vboot_test_sub[0], |
| ARRAY_SIZE(cmd_vboot_test_sub)); |
| if (c) |
| return c->cmd(c, flag, argc, argv); |
| else |
| return cmd_usage(cmdtp); |
| } |
| |
| U_BOOT_CMD(vboot_test, CONFIG_SYS_MAXARGS, 1, do_vboot_test, |
| "Perform tests for basic vboot related utilities", |
| "all - perform all tests\n" |
| "vboot_test fwrw [length] - test the firmware read/write\n" |
| "vboot_test memwipe - test the memory wipe functions\n" |
| "vboot_test gpio - print the status of gpio\n" |
| ); |
| |