/* Copyright 2020 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 #include "flash.h" #include "mpu.h" #include "string.h" #include "test_util.h" struct rollback_info { int region_0_offset; int region_1_offset; uint32_t region_size_bytes; }; /* These values are intentionally hardcoded here instead of using the chip * config headers, so that if the headers are accidentally changed we can catch * it. */ #if defined(CHIP_VARIANT_STM32F412) struct rollback_info rollback_info = { .region_0_offset = 0x20000, .region_1_offset = 0x40000, .region_size_bytes = 128 * 1024, }; #elif defined(CHIP_VARIANT_STM32H7X3) struct rollback_info rollback_info = { .region_0_offset = 0xC0000, .region_1_offset = 0xE0000, .region_size_bytes = 128 * 1024, }; #else #error "Rollback info not defined for this chip. Please add it." #endif test_static int read_rollback_region(const struct rollback_info *info, int region) { int i; char data; uint32_t bytes_read = 0; int offset = region == 0 ? info->region_0_offset : info->region_1_offset; for (i = 0; i < info->region_size_bytes; i++) { if (crec_flash_read(offset + i, sizeof(data), &data) == EC_SUCCESS) bytes_read++; } return bytes_read; } test_static int _test_lock_rollback(const struct rollback_info *info, int region) { int rv; /* * We expect the MPU to have already been enabled during the * initialization process (mpu_pre_init). */ rv = mpu_lock_rollback(0); TEST_EQ(rv, EC_SUCCESS, "%d"); /* unlocked we should be able to read both regions */ rv = read_rollback_region(info, 0); TEST_EQ(rv, rollback_info.region_size_bytes, "%d"); rv = read_rollback_region(info, 1); TEST_EQ(rv, rollback_info.region_size_bytes, "%d"); rv = mpu_lock_rollback(1); TEST_EQ(rv, EC_SUCCESS, "%d"); /* TODO(b/156112448): Validate that it actually reboots with the correct * data access violation. */ read_rollback_region(info, region); /* Should not get here. Should reboot with: * * Data access violation, mfar = XXX * * where XXX = start of rollback */ TEST_ASSERT(false); return EC_ERROR_UNKNOWN; } test_static int test_lock_rollback_region_0(void) { /* This call should never return due to panic. */ return _test_lock_rollback(&rollback_info, 0); } test_static int test_lock_rollback_region_1(void) { /* This call should never return due to panic. */ return _test_lock_rollback(&rollback_info, 1); } void run_test(int argc, char **argv) { if (argc < 2) { ccprintf("usage: runtest [region0|region1]\n"); return; } ccprintf("Running rollback test\n"); /* * TODO(b/156112448): For now you have to run the test separately for * each region. */ if (strncmp(argv[1], "region0", 7) == 0) RUN_TEST(test_lock_rollback_region_0); else if (strncmp(argv[1], "region1", 7) == 0) RUN_TEST(test_lock_rollback_region_1); test_print_result(); }