mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-16 04:29:08 +00:00
feat(core/sdbackup): improve handling of mocked SD
By default, unit tests and Emulator starts without virtual SD card. A card must be explicitly inserted in test setup.
This commit is contained in:
parent
3915171625
commit
a429da5b0e
@ -17,6 +17,9 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include "common.h"
|
||||||
#include "embed/extmod/trezorobj.h"
|
#include "embed/extmod/trezorobj.h"
|
||||||
#include "py/mpconfig.h"
|
#include "py/mpconfig.h"
|
||||||
#include "sdcard.h"
|
#include "sdcard.h"
|
||||||
@ -70,7 +73,7 @@ STATIC mp_obj_t mod_trezorio_sdcard_switcher_insert(size_t n_args,
|
|||||||
1024 * ONE_MEBIBYTE) // capacity between 1 MiB and 1 GiB
|
1024 * ONE_MEBIBYTE) // capacity between 1 MiB and 1 GiB
|
||||||
|
|
||||||
sdcard_mock.inserted = sectrue;
|
sdcard_mock.inserted = sectrue;
|
||||||
set_sdcard_mock_filename(&sdcard_mock, (int)card_sn);
|
set_sdcard_mock_filename((int)card_sn);
|
||||||
sdcard_mock.buffer = NULL;
|
sdcard_mock.buffer = NULL;
|
||||||
sdcard_mock.serial_number = card_sn;
|
sdcard_mock.serial_number = card_sn;
|
||||||
sdcard_mock.capacity_bytes = capacity_bytes;
|
sdcard_mock.capacity_bytes = capacity_bytes;
|
||||||
@ -87,7 +90,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_trezorio_sdcard_switcher_insert_obj, 1,
|
|||||||
/// """
|
/// """
|
||||||
STATIC mp_obj_t mod_trezorio_sdcard_switcher_eject() {
|
STATIC mp_obj_t mod_trezorio_sdcard_switcher_eject() {
|
||||||
sdcard_mock.inserted = secfalse;
|
sdcard_mock.inserted = secfalse;
|
||||||
sdcard_mock.buffer = NULL;
|
|
||||||
|
if (sdcard_mock.buffer != NULL) {
|
||||||
|
// TODO repetion with unix/sdcard.c code
|
||||||
|
int r = munmap(sdcard_mock.buffer, sdcard_mock.capacity_bytes);
|
||||||
|
ensure(sectrue * (r == 0), "munmap failed");
|
||||||
|
sdcard_mock.buffer = NULL;
|
||||||
|
}
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_sdcard_switcher_eject_obj,
|
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_sdcard_switcher_eject_obj,
|
||||||
|
@ -35,9 +35,10 @@
|
|||||||
#define SDCARD_SIZE sdcard_mock.capacity_bytes
|
#define SDCARD_SIZE sdcard_mock.capacity_bytes
|
||||||
#define SDCARD_BLOCKS (SDCARD_SIZE / SDCARD_BLOCK_SIZE)
|
#define SDCARD_BLOCKS (SDCARD_SIZE / SDCARD_BLOCK_SIZE)
|
||||||
|
|
||||||
static secbool sdcard_powered = secfalse;
|
|
||||||
|
|
||||||
static void sdcard_exit(void) {
|
static void sdcard_exit(void) {
|
||||||
|
if (SDCARD_BUFFER == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
int r = munmap(SDCARD_BUFFER, SDCARD_SIZE);
|
int r = munmap(SDCARD_BUFFER, SDCARD_SIZE);
|
||||||
ensure(sectrue * (r == 0), "munmap failed");
|
ensure(sectrue * (r == 0), "munmap failed");
|
||||||
SDCARD_BUFFER = NULL;
|
SDCARD_BUFFER = NULL;
|
||||||
@ -78,7 +79,7 @@ void sdcard_init(void) {
|
|||||||
for (int i = 0; i < SDCARD_SIZE; ++i) SDCARD_BUFFER[i] = 0xFF;
|
for (int i = 0; i < SDCARD_SIZE; ++i) SDCARD_BUFFER[i] = 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdcard_powered = secfalse;
|
sdcard_mock.powered = secfalse;
|
||||||
|
|
||||||
atexit(sdcard_exit);
|
atexit(sdcard_exit);
|
||||||
}
|
}
|
||||||
@ -90,19 +91,19 @@ secbool sdcard_power_on(void) {
|
|||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
sdcard_init();
|
sdcard_init();
|
||||||
sdcard_powered = sectrue;
|
sdcard_mock.powered = sectrue;
|
||||||
return sectrue;
|
return sectrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdcard_power_off(void) { sdcard_powered = secfalse; }
|
void sdcard_power_off(void) { sdcard_mock.powered = secfalse; }
|
||||||
|
|
||||||
uint64_t sdcard_get_capacity_in_bytes(void) {
|
uint64_t sdcard_get_capacity_in_bytes(void) {
|
||||||
return sdcard_powered == sectrue ? SDCARD_SIZE : 0;
|
return sdcard_mock.powered == sectrue ? SDCARD_SIZE : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
secbool sdcard_read_blocks(uint32_t *dest, uint32_t block_num,
|
secbool sdcard_read_blocks(uint32_t *dest, uint32_t block_num,
|
||||||
uint32_t num_blocks) {
|
uint32_t num_blocks) {
|
||||||
if (sectrue != sdcard_powered) {
|
if (sectrue != sdcard_mock.powered) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
if (block_num >= SDCARD_BLOCKS) {
|
if (block_num >= SDCARD_BLOCKS) {
|
||||||
@ -118,7 +119,7 @@ secbool sdcard_read_blocks(uint32_t *dest, uint32_t block_num,
|
|||||||
|
|
||||||
secbool sdcard_write_blocks(const uint32_t *src, uint32_t block_num,
|
secbool sdcard_write_blocks(const uint32_t *src, uint32_t block_num,
|
||||||
uint32_t num_blocks) {
|
uint32_t num_blocks) {
|
||||||
if (sectrue != sdcard_powered) {
|
if (sectrue != sdcard_mock.powered) {
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
if (block_num >= SDCARD_BLOCKS) {
|
if (block_num >= SDCARD_BLOCKS) {
|
||||||
|
@ -1,38 +1,26 @@
|
|||||||
#include "sdcard_emu_mock.h"
|
#include "sdcard_emu_mock.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
#include "profile.h"
|
#include "profile.h"
|
||||||
#include "sdcard.h"
|
#include "sdcard.h"
|
||||||
|
|
||||||
// default SD Card filename serves for unit testing logic which requires SD card
|
// By default, Emulator starts without mocked SD card, i.e. initially
|
||||||
// tests with emulator should call debuglink.insert_sdcard(...)
|
// sdcard.is_present() == False
|
||||||
#define SDCARD_FILENAME_DEFAULT PROFILE_DIR_DEFAULT "/trezor.sdcard_def"
|
|
||||||
|
|
||||||
// default SD card data
|
|
||||||
SDCardMock sdcard_mock = {
|
SDCardMock sdcard_mock = {
|
||||||
.inserted = sectrue,
|
.inserted = secfalse,
|
||||||
.filename = SDCARD_FILENAME_DEFAULT,
|
.powered = secfalse,
|
||||||
|
.filename = NULL,
|
||||||
.buffer = NULL,
|
.buffer = NULL,
|
||||||
.serial_number = 1,
|
.serial_number = 0,
|
||||||
.capacity_bytes = 64 * ONE_MEBIBYTE,
|
.capacity_bytes = 0,
|
||||||
.blocks = (64 * ONE_MEBIBYTE) / SDCARD_BLOCK_SIZE,
|
.blocks = 0 / SDCARD_BLOCK_SIZE,
|
||||||
.manuf_ID = 1,
|
.manuf_ID = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// "not inserted" SD card data
|
void set_sdcard_mock_filename(int serial_number) {
|
||||||
/* SDCardMock sdcard_mock = { */
|
if (sdcard_mock.serial_number == serial_number) {
|
||||||
/* .inserted = secfalse, */
|
// serial_number determines the filename, so assuming the PROFILE_DIR
|
||||||
/* .filename = NULL, */
|
// doesn't change during a lifetime of the emulator, we can skip the rename
|
||||||
/* .buffer = NULL, */
|
|
||||||
/* .serial_number = 0, */
|
|
||||||
/* .capacity_bytes = 0, */
|
|
||||||
/* .blocks = 0 / SDCARD_BLOCK_SIZE, */
|
|
||||||
/* .manuf_ID = 0, */
|
|
||||||
/* }; */
|
|
||||||
|
|
||||||
void set_sdcard_mock_filename(SDCardMock *card, int serial_number) {
|
|
||||||
if (card == NULL) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,11 +46,10 @@ void set_sdcard_mock_filename(SDCardMock *card, int serial_number) {
|
|||||||
serial_number);
|
serial_number);
|
||||||
|
|
||||||
// free the old filename
|
// free the old filename
|
||||||
if (card->filename != NULL &&
|
if (sdcard_mock.filename != NULL) {
|
||||||
strcmp(card->filename, SDCARD_FILENAME_DEFAULT) != 0) {
|
free(sdcard_mock.filename);
|
||||||
free(card->filename);
|
sdcard_mock.filename = NULL;
|
||||||
card->filename = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
card->filename = new_filename;
|
sdcard_mock.filename = new_filename;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
secbool inserted;
|
secbool inserted;
|
||||||
|
secbool powered;
|
||||||
char *filename;
|
char *filename;
|
||||||
uint8_t *buffer;
|
uint8_t *buffer;
|
||||||
uint32_t serial_number;
|
uint32_t serial_number;
|
||||||
@ -20,6 +21,6 @@ typedef struct {
|
|||||||
|
|
||||||
extern SDCardMock sdcard_mock;
|
extern SDCardMock sdcard_mock;
|
||||||
|
|
||||||
void set_sdcard_mock_filename(SDCardMock *card, int serial_number);
|
void set_sdcard_mock_filename(int serial_number);
|
||||||
|
|
||||||
#endif // __TREZOR_SDCARD_EMULATOR_MOCK_H__
|
#endif // __TREZOR_SDCARD_EMULATOR_MOCK_H__
|
||||||
|
@ -118,11 +118,12 @@ def _from_env(name: str) -> bool:
|
|||||||
@click.option("-r", "--record-dir", help="Directory where to record screen changes")
|
@click.option("-r", "--record-dir", help="Directory where to record screen changes")
|
||||||
@click.option("-s", "--slip0014", is_flag=True, help="Initialize device with SLIP-14 seed (all all all...)")
|
@click.option("-s", "--slip0014", is_flag=True, help="Initialize device with SLIP-14 seed (all all all...)")
|
||||||
@click.option("-S", "--script-gdb-file", type=click.Path(exists=True, dir_okay=False), help="Run gdb with an init file")
|
@click.option("-S", "--script-gdb-file", type=click.Path(exists=True, dir_okay=False), help="Run gdb with an init file")
|
||||||
|
@click.option("--sdcard", "sdcard_present", is_flag=True, default=False, help="Run emulator with SD card inserted")
|
||||||
@click.option("-t", "--temporary-profile", is_flag=True, help="Create an empty temporary profile")
|
@click.option("-t", "--temporary-profile", is_flag=True, help="Create an empty temporary profile")
|
||||||
@click.option("-w", "--watch", is_flag=True, help="Restart emulator if sources change")
|
@click.option("-w", "--watch", is_flag=True, help="Restart emulator if sources change")
|
||||||
@click.option("-X", "--extra-arg", "extra_args", multiple=True, help="Extra argument to pass to micropython")
|
@click.option("-X", "--extra-arg", "extra_args", multiple=True, help="Extra argument to pass to micropython")
|
||||||
# fmt: on
|
|
||||||
@click.argument("command", nargs=-1, type=click.UNPROCESSED)
|
@click.argument("command", nargs=-1, type=click.UNPROCESSED)
|
||||||
|
# fmt: on
|
||||||
def cli(
|
def cli(
|
||||||
disable_animation: bool,
|
disable_animation: bool,
|
||||||
run_command: bool,
|
run_command: bool,
|
||||||
@ -144,6 +145,7 @@ def cli(
|
|||||||
record_dir: Optional[str],
|
record_dir: Optional[str],
|
||||||
slip0014: bool,
|
slip0014: bool,
|
||||||
script_gdb_file: str | Path | None,
|
script_gdb_file: str | Path | None,
|
||||||
|
sdcard_present: bool,
|
||||||
temporary_profile: bool,
|
temporary_profile: bool,
|
||||||
watch: bool,
|
watch: bool,
|
||||||
extra_args: list[str],
|
extra_args: list[str],
|
||||||
@ -240,6 +242,7 @@ def cli(
|
|||||||
extra_args=extra_args,
|
extra_args=extra_args,
|
||||||
main_args=main_args,
|
main_args=main_args,
|
||||||
heap_size=heap_size,
|
heap_size=heap_size,
|
||||||
|
sdcard_present=sdcard_present,
|
||||||
disable_animation=disable_animation,
|
disable_animation=disable_animation,
|
||||||
workdir=SRC_DIR,
|
workdir=SRC_DIR,
|
||||||
)
|
)
|
||||||
|
@ -9,10 +9,14 @@ class TestStorageSdSeedBackup(unittest.TestCase):
|
|||||||
# TODO add more tests, also for repairing the backup card
|
# TODO add more tests, also for repairing the backup card
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
io.sdcard_switcher.insert(1)
|
||||||
self.mnemonic = (
|
self.mnemonic = (
|
||||||
b"crane mesh that gain predict open dice defy lottery toddler coin upgrade"
|
b"crane mesh that gain predict open dice defy lottery toddler coin upgrade"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
io.sdcard_switcher.eject()
|
||||||
|
|
||||||
def test_backup_and_restore(self):
|
def test_backup_and_restore(self):
|
||||||
io.sdcard.power_on()
|
io.sdcard.power_on()
|
||||||
io.fatfs.mkfs(True)
|
io.fatfs.mkfs(True)
|
||||||
|
@ -4,6 +4,11 @@ from trezor import io
|
|||||||
|
|
||||||
|
|
||||||
class TestTrezorIoSdcard(unittest.TestCase):
|
class TestTrezorIoSdcard(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
io.sdcard_switcher.insert(1)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
io.sdcard_switcher.eject()
|
||||||
|
|
||||||
def test_start(self):
|
def test_start(self):
|
||||||
self.assertTrue(io.sdcard.is_present())
|
self.assertTrue(io.sdcard.is_present())
|
||||||
@ -31,8 +36,8 @@ class TestTrezorIoSdcard(unittest.TestCase):
|
|||||||
|
|
||||||
def test_read_write(self):
|
def test_read_write(self):
|
||||||
r = bytearray(8 * 512)
|
r = bytearray(8 * 512)
|
||||||
w0 = bytearray(b'0' * (8 * 512))
|
w0 = bytearray(b"0" * (8 * 512))
|
||||||
w1 = bytearray(b'1' * (8 * 512))
|
w1 = bytearray(b"1" * (8 * 512))
|
||||||
io.sdcard.power_on()
|
io.sdcard.power_on()
|
||||||
io.sdcard.write(0, w0)
|
io.sdcard.write(0, w0)
|
||||||
io.sdcard.read(0, r)
|
io.sdcard.read(0, r)
|
||||||
@ -43,5 +48,5 @@ class TestTrezorIoSdcard(unittest.TestCase):
|
|||||||
io.sdcard.power_off()
|
io.sdcard.power_off()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -4,7 +4,14 @@ from trezor import io, sdcard
|
|||||||
|
|
||||||
fatfs = io.fatfs
|
fatfs = io.fatfs
|
||||||
|
|
||||||
|
|
||||||
class TestTrezorSdcard(unittest.TestCase):
|
class TestTrezorSdcard(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
io.sdcard_switcher.insert(1)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
io.sdcard_switcher.eject()
|
||||||
|
|
||||||
def test_power(self):
|
def test_power(self):
|
||||||
# sdcard.capacity() will return 0 if the card is not powered,
|
# sdcard.capacity() will return 0 if the card is not powered,
|
||||||
# non-zero value otherwise
|
# non-zero value otherwise
|
||||||
|
@ -232,25 +232,21 @@ class CoreEmulator(Emulator):
|
|||||||
port: Optional[int] = None,
|
port: Optional[int] = None,
|
||||||
main_args: Sequence[str] = ("-m", "main"),
|
main_args: Sequence[str] = ("-m", "main"),
|
||||||
workdir: Optional[Path] = None,
|
workdir: Optional[Path] = None,
|
||||||
sdcard: Optional[bytes] = None,
|
|
||||||
disable_animation: bool = True,
|
disable_animation: bool = True,
|
||||||
heap_size: str = "20M",
|
heap_size: str = "20M",
|
||||||
|
sdcard_present: bool = False,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
if workdir is not None:
|
if workdir is not None:
|
||||||
self.workdir = Path(workdir).resolve()
|
self.workdir = Path(workdir).resolve()
|
||||||
|
|
||||||
# FIXME does not work with switchable SD cards
|
|
||||||
# self.sdcard = self.profile_dir / "trezor.sdcard"
|
|
||||||
# if sdcard is not None:
|
|
||||||
# self.sdcard.write_bytes(sdcard)
|
|
||||||
|
|
||||||
if port:
|
if port:
|
||||||
self.port = port
|
self.port = port
|
||||||
self.disable_animation = disable_animation
|
self.disable_animation = disable_animation
|
||||||
self.main_args = list(main_args)
|
self.main_args = list(main_args)
|
||||||
self.heap_size = heap_size
|
self.heap_size = heap_size
|
||||||
|
self.sdcard_present = sdcard_present
|
||||||
|
|
||||||
def make_env(self) -> Dict[str, str]:
|
def make_env(self) -> Dict[str, str]:
|
||||||
env = super().make_env()
|
env = super().make_env()
|
||||||
@ -275,6 +271,11 @@ class CoreEmulator(Emulator):
|
|||||||
+ self.extra_args
|
+ self.extra_args
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def start(self) -> None:
|
||||||
|
super().start()
|
||||||
|
if self.sdcard_present:
|
||||||
|
self.client.debug.insert_sd_card()
|
||||||
|
|
||||||
def stop(self) -> None:
|
def stop(self) -> None:
|
||||||
super().stop()
|
super().stop()
|
||||||
for i in range(1, 17):
|
for i in range(1, 17):
|
||||||
|
Loading…
Reference in New Issue
Block a user