From ffe3a9d423a431fcf12e15120ab7b46ccb335c54 Mon Sep 17 00:00:00 2001 From: Jaedon Kim Date: Wed, 10 Jan 2024 01:16:46 +0000 Subject: [PATCH] [chip,dv] flash_ctrl memory protection test Test for multi mp region and their priority. Test verified in simulation platform. sival target will be added in the subsequent PR. Signed-off-by: Jaedon Kim --- hw/top_earlgrey/dv/chip_sim_cfg.hjson | 6 + sw/device/tests/BUILD | 25 ++ .../tests/flash_ctrl_mem_protection_test.c | 214 ++++++++++++++++++ 3 files changed, 245 insertions(+) create mode 100644 sw/device/tests/flash_ctrl_mem_protection_test.c diff --git a/hw/top_earlgrey/dv/chip_sim_cfg.hjson b/hw/top_earlgrey/dv/chip_sim_cfg.hjson index 31b1e72a5d4f4..93fba71cf042a 100644 --- a/hw/top_earlgrey/dv/chip_sim_cfg.hjson +++ b/hw/top_earlgrey/dv/chip_sim_cfg.hjson @@ -2073,6 +2073,12 @@ en_run_modes: ["sw_test_mode_test_rom"] run_opts: ["+use_otp_image=OtpTypeCustom"] } + { + name: chip_sw_flash_ctrl_mem_protection + uvm_test_seq: chip_sw_base_vseq + sw_images: ["//sw/device/tests:flash_ctrl_mem_protection_test:1:new_rules"] + en_run_modes: ["sw_test_mode_test_rom"] + } ] // List of regressions. diff --git a/sw/device/tests/BUILD b/sw/device/tests/BUILD index ad3a62d374051..fcb510f83e440 100644 --- a/sw/device/tests/BUILD +++ b/sw/device/tests/BUILD @@ -1654,6 +1654,31 @@ opentitan_test( ], ) +opentitan_test( + name = "flash_ctrl_mem_protection_test", + srcs = ["flash_ctrl_mem_protection_test.c"], + exec_env = dicts.add( + EARLGREY_TEST_ENVS, + { + "//hw/top_earlgrey:silicon_creator": None, + "//hw/top_earlgrey:silicon_owner_sival_rom_ext": None, + }, + ), + silicon = silicon_params(tags = ["broken"]), + verilator = new_verilator_params(timeout = "long"), + deps = [ + "//hw/top_earlgrey/ip/flash_ctrl/data/autogen:flash_ctrl_regs", + "//hw/top_earlgrey/sw/autogen:top_earlgrey", + "//sw/device/lib/base:macros", + "//sw/device/lib/base:memory", + "//sw/device/lib/base:mmio", + "//sw/device/lib/dif:flash_ctrl", + "//sw/device/lib/runtime:log", + "//sw/device/lib/testing:flash_ctrl_testutils", + "//sw/device/lib/testing/test_framework:ottf_main", + ], +) + opentitan_test( name = "flash_ctrl_rma_test", srcs = ["flash_ctrl_rma_test.c"], diff --git a/sw/device/tests/flash_ctrl_mem_protection_test.c b/sw/device/tests/flash_ctrl_mem_protection_test.c new file mode 100644 index 0000000000000..f5eada1416506 --- /dev/null +++ b/sw/device/tests/flash_ctrl_mem_protection_test.c @@ -0,0 +1,214 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "sw/device/lib/base/macros.h" +#include "sw/device/lib/base/memory.h" +#include "sw/device/lib/base/mmio.h" +#include "sw/device/lib/dif/dif_base.h" +#include "sw/device/lib/dif/dif_flash_ctrl.h" +#include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/testing/flash_ctrl_testutils.h" +#include "sw/device/lib/testing/test_framework/check.h" +#include "sw/device/lib/testing/test_framework/ottf_main.h" + +#include "flash_ctrl_regs.h" +#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" + +/** + * FLASH_CTRL memory protection test + * + * This test checks multiple memory protection regions and priority in case + * any regions overlap. + * + * Test programs regions as follows. + * + * region | bank | page start | page end | rd_en | prog_en | erase_en | + * -------------------------------------------------------------------: + * 0 | 1 | 12 | 13 | True | False | True | + * 3 | 1 | 11 | 14 | False | True | True | + * 7 | 1 | 10 | 15 | True | True | True | + * + * As you see, these regions intentionally overlap each other. + * For any overlaping regions the lower region has priority. + * To check this attribute, test will program higher region first. + * Test programs Region 7, 3 and 0 in order and checks + * write and read back based on each region's attribute. + */ +OTTF_DEFINE_TEST_CONFIG(); + +static dif_flash_ctrl_state_t flash; + +typedef struct test { + /** + * Memory protection(MP) region number + */ + uint32_t region_index; + /** + * Write data per each page. + * Full size of write data per page (2KB) is generated by + * loop: + * j = 0; j < words_per_page (256); j++ + * randomdata + j + */ + uint32_t randomdata[6]; + /** + * Page start index per each MP region. + */ + uint32_t page_start; + /** + * Write permission per each page. + */ + bool write_permission[6]; + /** + * Read permission per each page. + */ + bool read_permission[6]; + /** + * MP region config property. + */ + dif_flash_ctrl_data_region_properties_t data_region; +} test_t; + +#define BANK1_START_PAGE 256 +#define START_PAGE_ADDR \ + TOP_EARLGREY_FLASH_CTRL_MEM_BASE_ADDR + FLASH_CTRL_PARAM_BYTES_PER_BANK + +static const test_t kRegion[] = { + {.region_index = 0, + .randomdata = {0x77777770, 0x66666660}, + .page_start = 12, + .write_permission = {false, false}, + .read_permission = {true, true}, + .data_region = + { + .base = BANK1_START_PAGE + 12, + .size = 2, + .properties = + { + .rd_en = kMultiBitBool4True, + .prog_en = kMultiBitBool4False, + .erase_en = kMultiBitBool4True, + .scramble_en = kMultiBitBool4True, + .ecc_en = kMultiBitBool4True, + .high_endurance_en = kMultiBitBool4False, + }, + }}, + {.region_index = 3, + .randomdata = {0x88888880, 0x77777770, 0x66666660, 0x55555550}, + .page_start = 11, + .write_permission = {true, true, true, true}, + .read_permission = {false, false, false, false}, + .data_region = + { + .base = BANK1_START_PAGE + 11, + .size = 4, + .properties = + { + .rd_en = kMultiBitBool4False, + .prog_en = kMultiBitBool4True, + .erase_en = kMultiBitBool4True, + .scramble_en = kMultiBitBool4True, + .ecc_en = kMultiBitBool4True, + .high_endurance_en = kMultiBitBool4False, + }, + }}, + {.region_index = 7, + .randomdata = {0xaaaaaaa0, 0xbbbbbbb0, 0xccccccc0, 0xddddddd0, 0xeeeeeee0, + 0x99999990}, + .page_start = 10, + .write_permission = {true, true, true, true, true, true}, + .read_permission = {true, true, true, true, true, true}, + .data_region = + { + .base = BANK1_START_PAGE + 10, + .size = 6, + .properties = + { + .rd_en = kMultiBitBool4True, + .prog_en = kMultiBitBool4True, + .erase_en = kMultiBitBool4True, + .scramble_en = kMultiBitBool4True, + .ecc_en = kMultiBitBool4True, + .high_endurance_en = kMultiBitBool4False, + }, + }}, +}; + +/** + * Memory write and readback test + * For each MP region, this function check write and read permission + * based on MP region properties and priority of each MP region. + */ +static void test_mem_access(test_t region) { + uint32_t page_size = region.data_region.size; + uintptr_t start_epage = + (uintptr_t)(START_PAGE_ADDR + + FLASH_CTRL_PARAM_BYTES_PER_PAGE * region.page_start); + uint32_t wdata[FLASH_CTRL_PARAM_WORDS_PER_PAGE]; + + for (uint32_t i = 0; i < page_size; i++) { + for (size_t j = 0; j < ARRAYSIZE(wdata); j++) + wdata[j] = region.randomdata[i] + j; + if (region.write_permission[i]) { + CHECK_STATUS_OK(flash_ctrl_testutils_erase_page( + &flash, start_epage, + /*partition_id=*/0, kDifFlashCtrlPartitionTypeData)); + CHECK_STATUS_OK(flash_ctrl_testutils_write(&flash, start_epage, + /*partition_id=*/0, wdata, + kDifFlashCtrlPartitionTypeData, + ARRAYSIZE(wdata))); + LOG_INFO("test_mem_access: page %d write complete", + region.page_start + i); + } else { + CHECK_STATUS_NOT_OK(flash_ctrl_testutils_write( + &flash, start_epage, + /*partition_id=*/0, wdata, kDifFlashCtrlPartitionTypeData, + ARRAYSIZE(wdata))); + LOG_INFO("test_mem_access: page %d write is not allowed", + region.page_start + i); + } + uint32_t rdata[FLASH_CTRL_PARAM_WORDS_PER_PAGE]; + + if (region.read_permission[i]) { + CHECK_STATUS_OK(flash_ctrl_testutils_read( + &flash, start_epage, /*partition_id=*/0, rdata, + kDifFlashCtrlPartitionTypeData, ARRAYSIZE(rdata), + /*delay=*/1)); + CHECK_ARRAYS_EQ(rdata, wdata, ARRAYSIZE(rdata)); + LOG_INFO("test_mem_access: page %d read check complete", + region.page_start + i); + } else { + CHECK_STATUS_NOT_OK(flash_ctrl_testutils_read( + &flash, start_epage, /*partition_id=*/0, rdata, + kDifFlashCtrlPartitionTypeData, ARRAYSIZE(rdata), + /*delay=*/1)); + LOG_INFO("test_mem_access: page %d read is not allowed", + region.page_start + i); + } + start_epage += (uintptr_t)FLASH_CTRL_PARAM_BYTES_PER_PAGE; + } +} + +bool test_main(void) { + LOG_INFO("flash mp test start!"); + CHECK_DIF_OK(dif_flash_ctrl_init_state( + &flash, mmio_region_from_addr(TOP_EARLGREY_FLASH_CTRL_CORE_BASE_ADDR))); + + // Set up default access for data partitions. + CHECK_STATUS_OK(flash_ctrl_testutils_default_region_access( + &flash, /*rd_en=*/true, /*prog_en=*/true, /*erase_en=*/true, + /*scramble_en=*/false, /*ecc_en=*/false, /*high_endurance_en=*/false)); + + // Program starts from kRegion[2], kRegion[1], and kRegion[0] in order. + for (int i = 2; i >= 0; i--) { + CHECK_DIF_OK(dif_flash_ctrl_set_data_region_properties( + &flash, kRegion[i].region_index, kRegion[i].data_region)); + CHECK_DIF_OK(dif_flash_ctrl_set_data_region_enablement( + &flash, kRegion[i].region_index, kDifToggleEnabled)); + test_mem_access(kRegion[i]); + } + + LOG_INFO("test done"); + return true; +}