From a4fd7e0b47e8903eac08906e17a3363bb60605fc Mon Sep 17 00:00:00 2001 From: tychovrahe Date: Tue, 13 Feb 2024 16:18:26 +0100 Subject: [PATCH] fixup! sd card test --- core/SConscript.firmware | 1 + core/embed/firmware/main.c | 143 +++++++++++++++++++++++++- core/embed/firmware/prodtest_common.c | 102 ++++++++++++++++++ core/embed/firmware/prodtest_common.h | 34 ++++++ 4 files changed, 275 insertions(+), 5 deletions(-) create mode 100644 core/embed/firmware/prodtest_common.c create mode 100644 core/embed/firmware/prodtest_common.h diff --git a/core/SConscript.firmware b/core/SConscript.firmware index 23d4959e7..db5a707ff 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -351,6 +351,7 @@ SOURCE_FIRMWARE = [ 'embed/firmware/mphalport.c', 'embed/firmware/nlrthumb.c', 'embed/firmware/startup.S', + 'embed/firmware/prodtest_common.c', ] CPPDEFINES_MOD += ['USE_SVC_SHUTDOWN'] diff --git a/core/embed/firmware/main.c b/core/embed/firmware/main.c index a32992a19..d192d11fb 100644 --- a/core/embed/firmware/main.c +++ b/core/embed/firmware/main.c @@ -49,6 +49,7 @@ #include "random_delays.h" #include "rust_ui.h" #include "sdcard.h" +#include "prodtest_common.h" #include TREZOR_BOARD @@ -91,6 +92,102 @@ #endif +#include "usb.h" + +secbool startswith(const char *s, const char *prefix) { + return sectrue * (0 == strncmp(s, prefix, strlen(prefix))); +} + +static void vcp_intr(void) { + display_clear(); + ensure(secfalse, "vcp_intr"); +} + +void vcp_readline(char *buf, size_t len) { + uint32_t ticks_start = hal_ticks_ms(); + int received = 0; + for (;;) { + char c; + int r = usb_vcp_read(VCP_IFACE, (uint8_t*)&c, 1); + + if (r<= 0) { + if (received == 0 && hal_ticks_ms() - ticks_start > 1) { + break; + } + continue; + } + + received++; + + if (c == '\r') { + vcp_puts("\r\n", 2); + break; + } + if (c < 32 || c > 126) { // not printable + continue; + } + if (len > 1) { // leave space for \0 + *buf = c; + buf++; + len--; + vcp_puts(&c, 1); + } + } + if (len > 0) { + *buf = '\0'; + } +} + +static void usb_init_all(void) { + enum { + VCP_PACKET_LEN = 64, + VCP_BUFFER_LEN = 1024, + }; + + static const usb_dev_info_t dev_info = { + .device_class = 0xEF, // Composite Device Class + .device_subclass = 0x02, // Common Class + .device_protocol = 0x01, // Interface Association Descriptor + .vendor_id = 0x1209, + .product_id = 0x53C1, + .release_num = 0x0400, + .manufacturer = "SatoshiLabs", + .product = "TREZOR", + .serial_number = "000000000000", + .interface = "TREZOR Interface", + .usb21_enabled = secfalse, + .usb21_landing = secfalse, + }; + + static uint8_t tx_packet[VCP_PACKET_LEN]; + static uint8_t tx_buffer[VCP_BUFFER_LEN]; + static uint8_t rx_packet[VCP_PACKET_LEN]; + static uint8_t rx_buffer[VCP_BUFFER_LEN]; + + static const usb_vcp_info_t vcp_info = { + .tx_packet = tx_packet, + .tx_buffer = tx_buffer, + .rx_packet = rx_packet, + .rx_buffer = rx_buffer, + .tx_buffer_len = VCP_BUFFER_LEN, + .rx_buffer_len = VCP_BUFFER_LEN, + .rx_intr_fn = vcp_intr, + .rx_intr_byte = 3, // Ctrl-C + .iface_num = VCP_IFACE, + .data_iface_num = 0x01, + .ep_cmd = 0x82, + .ep_in = 0x81, + .ep_out = 0x01, + .polling_interval = 10, + .max_packet_len = VCP_PACKET_LEN, + }; + + usb_init(&dev_info); + ensure(usb_vcp_add(&vcp_info), "usb_vcp_add"); + usb_start(); +} + + bool check_cnt(const flash_area_t * area, int * cnt){ // assuming one subarea @@ -256,10 +353,12 @@ int main(void) { ensure(sectrue * (zkp_context_init() == 0), NULL); #endif + usb_init_all(); + sdcard_init(); - int cnt_success; + int cnt_; int cnt_fail; if (!check_cnt(&STORAGE_AREAS[0], &cnt_success)) { @@ -344,12 +443,46 @@ int main(void) { sdtest_update(cnt_success, cnt_fail); - uint32_t ticks_diff = hal_ticks_ms() - ticks; - int delay = 10000 - ticks_diff; + char line[2048]; // expecting hundreds of bytes represented as hexadecimal + // characters + + for (;;) { + + vcp_readline(line, sizeof(line)); + + if (startswith(line, "PING")) { + vcp_println("SUCCESS: %d, FAIL: %d", cnt_success, cnt_fail); + + } else if (startswith(line, "RESET")) { + (void)!flash_area_erase(&STORAGE_AREAS[0], NULL); + (void)!flash_area_erase(&STORAGE_AREAS[1], NULL); + cnt_success = 0; + cnt_fail = 0; + sdtest_update(cnt_success, cnt_fail); + vcp_println("OK"); + }else if (startswith(line, "STOP")) { + vcp_println("SUCCESS: %d, FAIL: %d", cnt_success, cnt_fail); + (void)!flash_area_erase(&STORAGE_AREAS[0], NULL); + (void)!flash_area_erase(&STORAGE_AREAS[1], NULL); + vcp_println("ERASED"); + cnt_success = 0; + cnt_fail = 0; + sdtest_update(cnt_success, cnt_fail); + vcp_println("SUCCESS: %d, FAIL: %d", cnt_success, cnt_fail); + vcp_println("HALT"); + for(;;); + } + + uint32_t ticks_diff = hal_ticks_ms() - ticks; - if (delay > 0) { - hal_delay(delay); + int delay = 10000 - ticks_diff; + + if (delay > 0) { + hal_delay(1); + } else { + break; + } } } diff --git a/core/embed/firmware/prodtest_common.c b/core/embed/firmware/prodtest_common.c new file mode 100644 index 000000000..a56607a0c --- /dev/null +++ b/core/embed/firmware/prodtest_common.c @@ -0,0 +1,102 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "prodtest_common.h" +#include "mini_printf.h" +#include "usb.h" + +void vcp_puts(const char *s, size_t len) { + int r = usb_vcp_write_blocking(VCP_IFACE, (const uint8_t *)s, len, -1); + (void)r; +} + +void vcp_print(const char *fmt, ...) { + static char buf[128]; + va_list va; + va_start(va, fmt); + int r = mini_vsnprintf(buf, sizeof(buf), fmt, va); + va_end(va); + vcp_puts(buf, r); +} + +void vcp_println(const char *fmt, ...) { + static char buf[128]; + va_list va; + va_start(va, fmt); + int r = mini_vsnprintf(buf, sizeof(buf), fmt, va); + va_end(va); + vcp_puts(buf, r); + vcp_puts("\r\n", 2); +} + +void vcp_println_hex(uint8_t *data, uint16_t len) { + for (int i = 0; i < len; i++) { + vcp_print("%02X", data[i]); + } + vcp_puts("\r\n", 2); +} + +static uint16_t get_byte_from_hex(const char **hex) { + uint8_t result = 0; + + // Skip whitespace. + while (**hex == ' ') { + *hex += 1; + } + + for (int i = 0; i < 2; i++) { + result <<= 4; + char c = **hex; + if (c >= '0' && c <= '9') { + result |= c - '0'; + } else if (c >= 'A' && c <= 'F') { + result |= c - 'A' + 10; + } else if (c >= 'a' && c <= 'f') { + result |= c - 'a' + 10; + } else if (c == '\0') { + return 0x100; + } else { + return 0xFFFF; + } + *hex += 1; + } + return result; +} + +int get_from_hex(uint8_t *buf, uint16_t buf_len, const char *hex) { + int len = 0; + uint16_t b = get_byte_from_hex(&hex); + for (len = 0; len < buf_len && b <= 0xff; ++len) { + buf[len] = b; + b = get_byte_from_hex(&hex); + } + + if (b == 0x100) { + // Success. + return len; + } + + if (b > 0xff) { + // Non-hexadecimal character. + return -1; + } + + // Buffer too small. + return -2; +} diff --git a/core/embed/firmware/prodtest_common.h b/core/embed/firmware/prodtest_common.h new file mode 100644 index 000000000..bd0f33747 --- /dev/null +++ b/core/embed/firmware/prodtest_common.h @@ -0,0 +1,34 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef PRODTEST_COMMON_H +#define PRODTEST_COMMON_H + +#include +#include + +enum { VCP_IFACE = 0x00 }; + +void vcp_puts(const char *s, size_t len); +void vcp_print(const char *fmt, ...); +void vcp_println(const char *fmt, ...); +void vcp_println_hex(uint8_t *data, uint16_t len); +int get_from_hex(uint8_t *buf, uint16_t buf_len, const char *hex); + +#endif