From 2ef7ca029f8ac394fc25434f13fe5aa21f3b51e7 Mon Sep 17 00:00:00 2001 From: Anthony Chen Date: Thu, 22 Aug 2024 04:34:37 -0700 Subject: [PATCH 1/3] [opentitanlib] support TX direction in SPI console This updates the console module to support TX direction by issuing upload commands. The write address of the last data chunk will be set to a special address, informing Device that the transmission is completed and Device can stop its busy wait state for further upload commands. Signed-off-by: Anthony Chen --- sw/host/opentitanlib/src/console/spi.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/sw/host/opentitanlib/src/console/spi.rs b/sw/host/opentitanlib/src/console/spi.rs index e3ef9000d1b5e..93e2c79694ac9 100644 --- a/sw/host/opentitanlib/src/console/spi.rs +++ b/sw/host/opentitanlib/src/console/spi.rs @@ -25,6 +25,8 @@ impl<'a> SpiConsoleDevice<'a> { const SPI_FLASH_READ_BUFFER_SIZE: u32 = 2048; const SPI_MAX_DATA_LENGTH: usize = 2036; const SPI_FRAME_MAGIC_NUMBER: u32 = 0xa5a5beef; + const SPI_FLASH_PAYLOAD_BUFFER_SIZE: usize = 256; + const SPI_TX_LAST_CHUNK_MAGIC_ADDRESS: u32 = 0x100; pub fn new(spi: &'a dyn Target) -> Result { let mut flash = SpiFlash { @@ -112,4 +114,27 @@ impl<'a> ConsoleDevice for SpiConsoleDevice<'a> { Ok(i) } + + fn console_write(&self, buf: &[u8]) -> Result<()> { + let buf_len: usize = buf.len(); + let mut written_data_len: usize = 0; + while written_data_len < buf_len { + let mut write_address = SpiConsoleDevice::SPI_TX_LAST_CHUNK_MAGIC_ADDRESS; + let mut data_len: usize = buf_len - written_data_len; + + if data_len > SpiConsoleDevice::SPI_FLASH_PAYLOAD_BUFFER_SIZE { + data_len = SpiConsoleDevice::SPI_FLASH_PAYLOAD_BUFFER_SIZE; + write_address = 0; + } + + self.flash.program( + self.spi, + write_address, + &buf[written_data_len..written_data_len + data_len], + )?; + written_data_len += data_len; + } + + Ok(()) + } } From f826030878434438c324640b49f844f74209db72 Mon Sep 17 00:00:00 2001 From: Anthony Chen Date: Thu, 22 Aug 2024 05:13:11 -0700 Subject: [PATCH 2/3] [ottf] add support for reading data via SPI device console This adds support for reading data via the OTTF SPI device console. Device keeps waiting spi upload commands and then transfers data in chunks until a transmission complete signal (special address) is received. Signed-off-by: Anthony Chen --- .../lib/testing/test_framework/ottf_console.c | 28 +++++++++++++++++++ .../lib/testing/test_framework/ottf_console.h | 15 ++++++++++ 2 files changed, 43 insertions(+) diff --git a/sw/device/lib/testing/test_framework/ottf_console.c b/sw/device/lib/testing/test_framework/ottf_console.c index 013e2446df21b..44c8ad514e135 100644 --- a/sw/device/lib/testing/test_framework/ottf_console.c +++ b/sw/device/lib/testing/test_framework/ottf_console.c @@ -296,3 +296,31 @@ status_t ottf_console_flow_control(const dif_uart_t *uart, } uint32_t ottf_console_get_flow_control_irqs(void) { return flow_control_irqs; } + +static bool spi_tx_last_data_chunk(upload_info_t *info) { + const static size_t kSpiTxTerminateMagicAddress = 0x100; + return info->address == kSpiTxTerminateMagicAddress; +} + +size_t ottf_console_spi_device_read(size_t buf_size, uint8_t *const buf) { + size_t received_data_len = 0; + upload_info_t info; + memset(&info, 0, sizeof(upload_info_t)); + while (!spi_tx_last_data_chunk(&info)) { + CHECK_STATUS_OK( + spi_device_testutils_wait_for_upload(&ottf_console_spi_device, &info)); + if (received_data_len < buf_size) { + size_t remaining_buf_size = buf_size - received_data_len; + size_t bytes_to_copy = remaining_buf_size < info.data_len + ? remaining_buf_size + : info.data_len; + memcpy(buf + received_data_len, info.data, bytes_to_copy); + } + + received_data_len += info.data_len; + CHECK_DIF_OK(dif_spi_device_set_flash_status_registers( + &ottf_console_spi_device, 0x00)); + } + + return received_data_len; +} diff --git a/sw/device/lib/testing/test_framework/ottf_console.h b/sw/device/lib/testing/test_framework/ottf_console.h index 4f785e51fb272..ba42639c75be4 100644 --- a/sw/device/lib/testing/test_framework/ottf_console.h +++ b/sw/device/lib/testing/test_framework/ottf_console.h @@ -94,4 +94,19 @@ bool ottf_console_flow_control_isr(uint32_t *exc_info); */ uint32_t ottf_console_get_flow_control_irqs(void); +/** + * Read data from the host via the OTTF SPI device console into a provided + * buffer. + * + * The function waits for spi upload commands, then transfers data in chunks + * until a transmission complete signal is received. If the size of data sent + * from the host is greater than the provided buffer, then the excess data will + * be discarded. + * + * @param buf_size The size, in bytes, of the `buf`. + * @param[out] buf A pointer to the location where the data should be stored. + * @return The number of bytes actually received from the host. + */ +size_t ottf_console_spi_device_read(size_t buf_size, uint8_t *const buf); + #endif // OPENTITAN_SW_DEVICE_LIB_TESTING_TEST_FRAMEWORK_OTTF_CONSOLE_H_ From 1adb01a851aebbe09c8bc73280e7eb89aa2580b2 Mon Sep 17 00:00:00 2001 From: Anthony Chen Date: Thu, 22 Aug 2024 05:22:30 -0700 Subject: [PATCH 3/3] [test] add TX test cases for spi_device OTTF console This tests the OTTF spi_device console in TX direction. Signed-off-by: Anthony Chen --- .../tests/spi_device_ottf_console_test.c | 47 ++++++++++++++++--- .../chip/spi_device_ottf_console/src/main.rs | 27 ++++++++++- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/sw/device/tests/spi_device_ottf_console_test.c b/sw/device/tests/spi_device_ottf_console_test.c index f18bcabd7406a..4b0f857275f94 100644 --- a/sw/device/tests/spi_device_ottf_console_test.c +++ b/sw/device/tests/spi_device_ottf_console_test.c @@ -4,7 +4,9 @@ #include "sw/device/lib/dif/dif_spi_device.h" #include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/testing/spi_device_testutils.h" #include "sw/device/lib/testing/test_framework/check.h" +#include "sw/device/lib/testing/test_framework/ottf_console.h" #include "sw/device/lib/testing/test_framework/ottf_main.h" #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" @@ -93,22 +95,53 @@ static const char kTest4KbDataStr[] = "B30518D571FDD6D38E0477F6CB83C7729A45494F5D7805CCC1432C816B7D8CB089CEA56216" "9489E4F80E70FA685F39E1CD0AD7AD703C2E9601D442004F3D4CE043F0E84007FB7438FE82" "DF4D9304C90B48BB25762DD29D"; + +static uint8_t input_buf[5120]; + bool test_main(void) { - LOG_INFO("Sending empty string..."); + LOG_INFO("Sending empty string to Host..."); LOG_INFO(""); - LOG_INFO("Sending test string..."); + LOG_INFO("Sending test string to Host..."); LOG_INFO("%s", kTestStr); - LOG_INFO("Sending 64B data..."); + LOG_INFO("SYNC: Waiting for console data"); + size_t received_data_len = + ottf_console_spi_device_read(sizeof(input_buf), input_buf); + CHECK(received_data_len == sizeof(kTestStr)); + CHECK_ARRAYS_EQ(input_buf, kTestStr, ARRAYSIZE(kTestStr)); + + LOG_INFO("Sending 64B data to Host..."); LOG_INFO("%s", kTest64bDataStr); - LOG_INFO("Sending 256B data..."); + LOG_INFO("SYNC: Waiting for console data"); + received_data_len = + ottf_console_spi_device_read(sizeof(input_buf), input_buf); + CHECK(received_data_len == sizeof(kTest64bDataStr)); + CHECK_ARRAYS_EQ(input_buf, kTest64bDataStr, ARRAYSIZE(kTest64bDataStr)); + + LOG_INFO("Sending 256B data to Host..."); LOG_INFO("%s", kTest256bDataStr); - LOG_INFO("Sending 1KB data..."); + LOG_INFO("SYNC: Waiting for console data"); + received_data_len = + ottf_console_spi_device_read(sizeof(input_buf), input_buf); + CHECK(received_data_len == sizeof(kTest256bDataStr)); + CHECK_ARRAYS_EQ(input_buf, kTest256bDataStr, ARRAYSIZE(kTest256bDataStr)); + + LOG_INFO("Sending 1KB data to Host..."); for (int i = 1; i <= 2; i++) { LOG_INFO("Round: %d", i); LOG_INFO("%s", kTest1KbDataStr); + LOG_INFO("SYNC: Waiting for console data"); + received_data_len = + ottf_console_spi_device_read(sizeof(input_buf), input_buf); + CHECK(received_data_len == sizeof(kTest1KbDataStr)); + CHECK_ARRAYS_EQ(input_buf, kTest1KbDataStr, ARRAYSIZE(kTest1KbDataStr)); } - LOG_INFO("Sending 4KB data..."); - LOG_INFO("%s", kTest4KbDataStr); + LOG_INFO("Sending 4KB data to Host..."); + LOG_INFO("%s", kTest4KbDataStr); + LOG_INFO("SYNC: Waiting for console data"); + received_data_len = + ottf_console_spi_device_read(sizeof(input_buf), input_buf); + CHECK(received_data_len == sizeof(kTest4KbDataStr)); + CHECK_ARRAYS_EQ(input_buf, kTest4KbDataStr, ARRAYSIZE(kTest4KbDataStr)); return true; } diff --git a/sw/host/tests/chip/spi_device_ottf_console/src/main.rs b/sw/host/tests/chip/spi_device_ottf_console/src/main.rs index 7a2c446196767..9a7dbb5c543f3 100644 --- a/sw/host/tests/chip/spi_device_ottf_console/src/main.rs +++ b/sw/host/tests/chip/spi_device_ottf_console/src/main.rs @@ -12,6 +12,7 @@ use std::time::Duration; use opentitanlib::app::TransportWrapper; use opentitanlib::console::spi::SpiConsoleDevice; use opentitanlib::execute_test; +use opentitanlib::io::console::ConsoleDevice; use opentitanlib::test_utils; use opentitanlib::test_utils::init::InitializeTest; use opentitanlib::uart::console::{ExitStatus, UartConsole}; @@ -34,6 +35,8 @@ struct Opts { firmware_elf: PathBuf, } +const SYNC_MSG: &str = r"SYNC:.*\r\n"; + fn spi_device_console_test(opts: &Opts, transport: &TransportWrapper) -> Result<()> { let mut console = UartConsole { timeout: Some(opts.timeout), @@ -54,20 +57,40 @@ fn spi_device_console_test(opts: &Opts, transport: &TransportWrapper) -> Result< let mut data = test_utils::object::symbol_data(&object, "kTestStr")?; let mut data_str = std::str::from_utf8(&data)?.trim_matches(char::from(0)); _ = UartConsole::wait_for(&spi_console_device, data_str, opts.timeout)?; + log::info!("Sending test string to Device..."); + _ = UartConsole::wait_for(&spi_console_device, SYNC_MSG, opts.timeout)?; + spi_console_device.console_write(&data)?; + data = test_utils::object::symbol_data(&object, "kTest64bDataStr")?; data_str = std::str::from_utf8(&data)?.trim_matches(char::from(0)); _ = UartConsole::wait_for(&spi_console_device, data_str, opts.timeout)?; + log::info!("Sending 64B data to Device..."); + _ = UartConsole::wait_for(&spi_console_device, SYNC_MSG, opts.timeout)?; + spi_console_device.console_write(&data)?; + data = test_utils::object::symbol_data(&object, "kTest256bDataStr")?; data_str = std::str::from_utf8(&data)?.trim_matches(char::from(0)); _ = UartConsole::wait_for(&spi_console_device, data_str, opts.timeout)?; + log::info!("Sending 256 data to Device..."); + _ = UartConsole::wait_for(&spi_console_device, SYNC_MSG, opts.timeout)?; + spi_console_device.console_write(&data)?; + data = test_utils::object::symbol_data(&object, "kTest1KbDataStr")?; data_str = std::str::from_utf8(&data)?.trim_matches(char::from(0)); // 1KB data will be sent twice. - _ = UartConsole::wait_for(&spi_console_device, data_str, opts.timeout)?; - _ = UartConsole::wait_for(&spi_console_device, data_str, opts.timeout)?; + for _round in 0..2 { + _ = UartConsole::wait_for(&spi_console_device, data_str, opts.timeout)?; + log::info!("Sending 1KB data to Device..."); + _ = UartConsole::wait_for(&spi_console_device, SYNC_MSG, opts.timeout)?; + spi_console_device.console_write(&data)?; + } + data = test_utils::object::symbol_data(&object, "kTest4KbDataStr")?; data_str = std::str::from_utf8(&data)?.trim_matches(char::from(0)); _ = UartConsole::wait_for(&spi_console_device, data_str, opts.timeout)?; + log::info!("Sending 4KB data to Device..."); + _ = UartConsole::wait_for(&spi_console_device, SYNC_MSG, opts.timeout)?; + spi_console_device.console_write(&data)?; let result = console.interact(&spi_console_device, None, Some(&mut stdout))?; match result {