Skip to content

Commit da6e70d

Browse files
committed
test: add option for the simulator to write to file.
If the env variable FAKE_MEMORY_FILEPATH is provided, the simulator will write to file using three different files: - ${FAKE_MEMORY_FILEPATH}_shared - ${FAKE_MEMORY_FILEPATH}_app - ${FAKE_MEMORY_FILEPATH}_eeprom mimicking the behaviour used when reading/writing to memory. This allows us to re-launch the simulator after making changes in the BBApp (e.g. renaming the device, accounts etc) while testing, simulating the effect that unplugging/replugging a device would have.
1 parent da0aa9c commit da6e70d

File tree

2 files changed

+126
-0
lines changed

2 files changed

+126
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ customers cannot upgrade their bootloader, its changes are recorded separately.
1313
- simulator: enable Test Merchant for payment requests
1414
- simulator: simulate a Nova device
1515
- Add API call to fetch multiple xpubs at once
16+
- Add the option for the simulator to write its memory to file.
1617

1718
### 9.23.1
1819
- EVM: add HyperEVM (HYPE) and SONIC (S) to known networks

test/hardware-fakes/src/fake_memory.c

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,60 @@
1818
#include <memory/memory_shared.h>
1919
#include <stdio.h>
2020
#include <string.h>
21+
#include <sys/stat.h>
22+
#include <stdlib.h>
23+
24+
25+
#define FAKE_MEMORY_ENV_VAR "FAKE_MEMORY_FILEPATH"
26+
#define SHARED_SUFFIX "shared"
27+
#define APP_SUFFIX "app"
28+
#define EEPROM_SUFFIX "eeprom"
2129

2230
static uint8_t _memory_shared_data[FLASH_SHARED_DATA_LEN] = {0};
2331
static uint8_t _memory_app_data[FLASH_APPDATA_LEN] = {0};
2432
static uint8_t _memory_smarteeprom[SMARTEEPROM_RESERVED_FLASH_PAGES * FLASH_PAGE_SIZE] = {0};
2533

34+
static void _init_file_if_needed(
35+
const char* base_path,
36+
const char* suffix,
37+
const uint8_t* data,
38+
size_t data_size)
39+
{
40+
char path[512];
41+
if (snprintf(path, sizeof(path), "%s_%s", base_path, suffix) >= sizeof(path)) {
42+
fprintf(stderr, "file path %s_%s too long\n", base_path, suffix);
43+
exit(EXIT_FAILURE);
44+
}
45+
46+
struct stat st;
47+
if (stat(path, &st) == 0) {
48+
return; // The file already exists, do nothing.
49+
}
50+
51+
FILE* f = fopen(path, "wb");
52+
if (f) {
53+
fwrite(data, 1, data_size, f);
54+
fclose(f);
55+
} else {
56+
fprintf(stderr, "error: could not create fake memory file %s\n", path);
57+
exit(EXIT_FAILURE);
58+
}
59+
}
60+
2661
void fake_memory_factoryreset(void)
2762
{
2863
memset(_memory_shared_data, 0xff, sizeof(_memory_shared_data));
2964
memset(_memory_app_data, 0xff, sizeof(_memory_app_data));
3065
memset(_memory_smarteeprom, 0xff, sizeof(_memory_smarteeprom));
66+
67+
const char* base_path = getenv(FAKE_MEMORY_ENV_VAR);
68+
if (base_path) {
69+
_init_file_if_needed(base_path, SHARED_SUFFIX, _memory_shared_data, sizeof(_memory_shared_data));
70+
_init_file_if_needed(base_path, APP_SUFFIX, _memory_app_data, sizeof(_memory_app_data));
71+
_init_file_if_needed(base_path, EEPROM_SUFFIX, _memory_smarteeprom, sizeof(_memory_smarteeprom));
72+
}
3173
}
74+
3275
#define ALLOWED_HASH \
3376
"\x1e\x4a\xa8\x36\x4e\x93\x5c\x07\x85\xe4\xf8\x91\x20\x83\x07\xd8\x32\xf7\x88\x17\x2e\x4b\xf6" \
3477
"\x16\x21\xde\x6d\xf9\xec\x3c\x21\x5f"
@@ -63,8 +106,78 @@ static uint8_t* _get_memory(uint32_t base)
63106
}
64107
}
65108

109+
static void _write_file_chunk(const char* suffix, uint32_t offset, const uint8_t* chunk, size_t len)
110+
{
111+
char path[512];
112+
const char* base_path = getenv(FAKE_MEMORY_ENV_VAR);
113+
if (!base_path) {
114+
return;
115+
}
116+
if (snprintf(path, sizeof(path), "%s_%s", base_path, suffix) >= sizeof(path)) {
117+
fprintf(stderr, "file path %s_%s too long\n", base_path, suffix);
118+
exit(EXIT_FAILURE);
119+
}
120+
FILE* f = fopen(path, "r+b");
121+
if (!f) {
122+
fprintf(stderr, "error: fake memory file %s not found\n", path);
123+
exit(EXIT_FAILURE);
124+
}
125+
fseek(f, offset, SEEK_SET);
126+
fwrite(chunk, 1, len, f);
127+
fclose(f);
128+
}
129+
130+
static void _read_file_chunk(const char* suffix, uint32_t offset, uint8_t* chunk, size_t len)
131+
{
132+
char path[512];
133+
const char* base_path = getenv(FAKE_MEMORY_ENV_VAR);
134+
if (!base_path) {
135+
return;
136+
}
137+
if (snprintf(path, sizeof(path), "%s_%s", base_path, suffix) >= sizeof(path)) {
138+
fprintf(stderr, "file path %s_%s too long\n", base_path, suffix);
139+
exit(EXIT_FAILURE);
140+
}
141+
FILE* f = fopen(path, "rb");
142+
if (!f) {
143+
fprintf(stderr, "error: fake memory file %s not found\n", path);
144+
exit(EXIT_FAILURE);
145+
}
146+
fseek(f, offset, SEEK_SET);
147+
fread(chunk, 1, len, f);
148+
fclose(f);
149+
}
150+
66151
bool memory_write_to_address_fake(uint32_t base, uint32_t addr, const uint8_t* chunk)
67152
{
153+
const char* base_path = getenv(FAKE_MEMORY_ENV_VAR);
154+
155+
if (base_path) {
156+
size_t len = CHUNK_SIZE;
157+
const char* suffix = NULL;
158+
switch (base) {
159+
case FLASH_SHARED_DATA_START:
160+
suffix = SHARED_SUFFIX;
161+
break;
162+
case FLASH_APPDATA_START:
163+
suffix = APP_SUFFIX;
164+
break;
165+
case FLASH_SMARTEEPROM_START:
166+
suffix = EEPROM_SUFFIX;
167+
break;
168+
default:
169+
return false;
170+
}
171+
if (chunk == NULL) {
172+
uint8_t empty[CHUNK_SIZE];
173+
memset(empty, 0xff, CHUNK_SIZE);
174+
_write_file_chunk(suffix, addr, empty, len);
175+
} else {
176+
_write_file_chunk(suffix, addr, chunk, len);
177+
}
178+
return true;
179+
}
180+
68181
if (chunk == NULL) {
69182
memset(_get_memory(base) + addr, 0xff, (size_t)CHUNK_SIZE);
70183
} else {
@@ -80,11 +193,23 @@ bool memory_write_chunk_fake(uint32_t chunk_num, const uint8_t* chunk)
80193

81194
void memory_read_chunk_fake(uint32_t chunk_num, uint8_t* chunk_out)
82195
{
196+
const char* base_path = getenv(FAKE_MEMORY_ENV_VAR);
197+
if (base_path) {
198+
_read_file_chunk(APP_SUFFIX, chunk_num * (size_t)CHUNK_SIZE, chunk_out, (size_t)CHUNK_SIZE);
199+
return;
200+
}
201+
83202
memcpy(chunk_out, _memory_app_data + chunk_num * (size_t)CHUNK_SIZE, (size_t)CHUNK_SIZE);
84203
}
85204

86205
void memory_read_shared_bootdata_fake(uint8_t* chunk_out)
87206
{
207+
const char* base_path = getenv(FAKE_MEMORY_ENV_VAR);
208+
if (base_path) {
209+
_read_file_chunk(SHARED_SUFFIX, 0, chunk_out, (size_t)FLASH_SHARED_DATA_LEN);
210+
return;
211+
}
212+
88213
memcpy(chunk_out, _memory_shared_data, (size_t)FLASH_SHARED_DATA_LEN);
89214
}
90215

0 commit comments

Comments
 (0)