1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-24 07:18:09 +00:00

feat(core/rust): make Rust buildable without Micropython

Features `micropython` and `protobuf` are defined. Protobuf implies micropython
because our protobuf impl is pretty much _for_ micropython.

The respective subdirs are included only if the matching feature is defined.

util.rs is moved to micropython because it mostly concerns micropython interop

ResultExt, useful only for ui_debug, is moved to ui::util.

A new module `trezorhal::time` is provided. It mirrors functionality of
`micropython::time` via stmlib functions.  The intended use is to always use
functions from `trezorhal::time`. The right micropython variants are used when
micropython is available, otherwise the pure stmlib versions are called.

ui::*::layout is conditional for micropython feature, because it only concerns
micropython layouts. If we want to reuse layouts defined there, we will need to
export them to not depend on Objs and Qstrs etc.
This commit is contained in:
matejcik 2022-06-08 10:31:23 +02:00 committed by matejcik
parent 7d37109eb8
commit 2aa427a6e3
32 changed files with 112 additions and 69 deletions

View File

@ -83,7 +83,7 @@ test: ## run unit tests
cd tests ; ./run_tests.sh $(TESTOPTS)
test_rust: ## run rs unit tests
cd embed/rust ; cargo test --no-default-features --features model_t$(shell echo $(TREZOR_MODEL) | tr "T" "t"),test,ui,ui_debug -- --test-threads=1
cd embed/rust ; cargo test --no-default-features --features model_t$(shell echo $(TREZOR_MODEL) | tr "TR" "tr"),test -- --test-threads=1
test_emu: ## run selected device tests from python-trezor
$(EMU_TEST) $(PYTEST) $(TESTPATH)/device_tests $(TESTOPTS)

View File

@ -704,18 +704,14 @@ def cargo_build():
profile = '--release'
else:
profile = ''
if TREZOR_MODEL in ("1",):
features = ["model_t1"]
elif TREZOR_MODEL in ("R",):
features = ["model_tr"]
else:
features = ["model_tt"]
if BITCOIN_ONLY == "1":
features.append("bitcoin_only")
features = ['micropython', 'protobuf', f'model_t{TREZOR_MODEL.lower()}']
if BITCOIN_ONLY == '1':
features.append('bitcoin_only')
if UI2:
features.append("ui")
if PYOPT == "0":
features.append("ui_debug")
features.append('ui')
if PYOPT == '0':
features.append('ui_debug')
return f'cd embed/rust; cargo build {profile} --target={RUST_TARGET} --target-dir=../../build/firmware/rust --no-default-features --features "{" ".join(features)}"'

View File

@ -665,18 +665,13 @@ RUST_LIB = 'trezor_lib'
RUST_LIBPATH = f'{RUST_LIBDIR}/lib{RUST_LIB}.a'
def cargo_build():
if TREZOR_MODEL in ('1',):
features = ["model_t1"]
elif TREZOR_MODEL in ('R',):
features = ["model_tr"]
else:
features = ["model_tt"]
if BITCOIN_ONLY == "1":
features.append("bitcoin_only")
features = ['micropython', 'protobuf', f'model_t{TREZOR_MODEL.lower()}']
if BITCOIN_ONLY == '1':
features.append('bitcoin_only')
if UI2:
features.append("ui")
if PYOPT == "0" or not FROZEN:
features.append("ui_debug")
features.append('ui')
if PYOPT == '0':
features.append('ui_debug')
return f'cd embed/rust; cargo build --profile {RUST_PROFILE} --target-dir=../../build/unix/rust --no-default-features --features "{" ".join(features)}"'

View File

@ -11,12 +11,14 @@ bitcoin_only = []
model_tt = ["touch"]
model_t1 = ["buttons"]
model_tr = ["buttons"]
micropython = []
protobuf = ["micropython"]
ui = []
ui_debug = []
buttons = []
touch = []
clippy = []
test = ["cc", "glob"]
test = ["cc", "glob", "micropython", "protobuf", "ui", "ui_debug"]
[lib]
crate-type = ["staticlib"]

View File

@ -3,7 +3,9 @@ use std::ffi::OsStr;
use std::{env, path::PathBuf, process::Command};
fn main() {
#[cfg(feature = "micropython")]
generate_qstr_bindings();
#[cfg(feature = "micropython")]
generate_micropython_bindings();
generate_trezorhal_bindings();
#[cfg(feature = "test")]
@ -18,6 +20,7 @@ fn model() -> String {
}
/// Generates Rust module that exports QSTR constants used in firmware.
#[cfg(feature = "micropython")]
fn generate_qstr_bindings() {
let out_path = env::var("OUT_DIR").unwrap();
@ -117,6 +120,7 @@ fn prepare_bindings() -> bindgen::Builder {
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
}
#[cfg(feature = "micropython")]
fn generate_micropython_bindings() {
let out_path = env::var("OUT_DIR").unwrap();
@ -269,7 +273,10 @@ fn generate_trezorhal_bindings() {
.allowlist_function("slip39_word_completion_mask")
.allowlist_function("button_sequence_to_word")
// random
.allowlist_function("random_uniform");
.allowlist_function("random_uniform")
// time
.allowlist_function("hal_delay")
.allowlist_function("hal_ticks_ms");
// Write the bindings to a file in the OUR_DIR.
bindings

View File

@ -1,7 +1,11 @@
use core::convert::{Infallible, TryInto};
use core::{
convert::{Infallible, TryInto},
num::TryFromIntError,
};
use cstr_core::CStr;
#[cfg(feature = "micropython")]
use crate::micropython::{ffi, obj::Obj, qstr::Qstr};
#[allow(clippy::enum_variant_names)] // We mimic the Python exception classnames here.
@ -11,13 +15,19 @@ pub enum Error {
OutOfRange,
MissingKwargs,
AllocationFailed,
#[cfg(feature = "micropython")]
CaughtException(Obj),
#[cfg(feature = "micropython")]
KeyError(Obj),
#[cfg(feature = "micropython")]
AttributeError(Qstr),
#[cfg(feature = "micropython")]
ValueError(&'static CStr),
#[cfg(feature = "micropython")]
ValueErrorParam(&'static CStr, Obj),
}
#[cfg(feature = "micropython")]
impl Error {
/// Create an exception instance matching the error code. The result of this
/// call should only be used to immediately raise the exception, because the
@ -67,3 +77,9 @@ impl From<Infallible> for Error {
unreachable!()
}
}
impl From<TryFromIntError> for Error {
fn from(_: TryFromIntError) -> Self {
Self::OutOfRange
}
}

View File

@ -5,8 +5,10 @@
#![allow(dead_code)]
mod error;
#[cfg(feature = "micropython")]
#[macro_use]
mod micropython;
#[cfg(feature = "protobuf")]
mod protobuf;
mod time;
#[cfg(feature = "ui_debug")]
@ -16,7 +18,6 @@ mod trezorhal;
#[cfg(feature = "ui")]
#[macro_use]
pub mod ui;
mod util;
#[cfg(not(test))]
#[cfg(any(not(feature = "test"), feature = "clippy"))]

View File

@ -16,6 +16,7 @@ pub mod qstr;
pub mod runtime;
pub mod time;
pub mod typ;
pub mod util;
#[cfg(test)]
pub mod testutil;

View File

@ -1,7 +1,4 @@
use core::{
convert::{TryFrom, TryInto},
num::TryFromIntError,
};
use core::convert::{TryFrom, TryInto};
use cstr_core::CStr;
@ -413,9 +410,3 @@ impl Obj {
}
}
}
impl From<TryFromIntError> for Error {
fn from(_: TryFromIntError) -> Self {
Self::OutOfRange
}
}

View File

@ -81,16 +81,3 @@ pub unsafe fn try_with_args_and_kwargs_inline(
};
unsafe { try_or_raise(block) }
}
pub trait ResultExt {
fn assert_if_debugging_ui(self, message: &str);
}
impl<T, E> ResultExt for Result<T, E> {
fn assert_if_debugging_ui(self, #[allow(unused)] message: &str) {
#[cfg(feature = "ui_debug")]
if self.is_err() {
panic!("{}", message);
}
}
}

View File

@ -5,8 +5,7 @@ use core::{
use crate::{
error::Error,
micropython::{buffer::Buffer, gc::Gc, list::List, map::Map, obj::Obj, qstr::Qstr},
util,
micropython::{buffer::Buffer, gc::Gc, list::List, map::Map, obj::Obj, qstr::Qstr, util},
};
use super::{

View File

@ -9,8 +9,8 @@ use crate::{
list::List,
obj::Obj,
qstr::Qstr,
util,
},
util,
};
use super::{

View File

@ -10,8 +10,8 @@ use crate::{
obj::{Obj, ObjBase},
qstr::Qstr,
typ::Type,
util,
},
util,
};
use super::{

View File

@ -3,7 +3,7 @@ use core::{
ops::{Div, Mul},
};
use crate::micropython::time;
use crate::trezorhal::time;
const MILLIS_PER_SEC: u32 = 1000;
@ -83,7 +83,6 @@ pub struct Instant {
impl Instant {
pub fn now() -> Self {
// TODO: We should move this to `micropython::time`.
Self {
millis: time::ticks_ms(),
}

View File

@ -5,3 +5,8 @@ pub mod display;
mod ffi;
pub mod random;
pub mod slip39;
#[cfg(not(feature = "micropython"))]
pub mod time;
#[cfg(feature = "micropython")]
pub use crate::micropython::time;

View File

@ -0,0 +1,13 @@
use crate::time::Duration;
use super::ffi;
pub fn ticks_ms() -> u32 {
unsafe { ffi::hal_ticks_ms() as _ }
}
pub fn sleep(delay: Duration) {
unsafe {
ffi::hal_delay(delay.to_millis() as _);
}
}

View File

@ -1,5 +1,8 @@
use super::constant;
use crate::{micropython::time, time::Duration, trezorhal::display};
use crate::{
time::Duration,
trezorhal::{display, time},
};
use super::geometry::{Offset, Point, Rect};

View File

@ -11,6 +11,7 @@ use crate::{
obj::{Obj, ObjBase},
qstr::Qstr,
typ::Type,
util,
},
time::Duration,
ui::{
@ -18,7 +19,6 @@ use crate::{
constant,
geometry::Rect,
},
util,
};
#[cfg(feature = "buttons")]

View File

@ -7,6 +7,9 @@ pub mod constant;
pub mod display;
pub mod event;
pub mod geometry;
mod util;
#[cfg(feature = "micropython")]
pub mod layout;
#[cfg(feature = "model_t1")]

View File

@ -2,7 +2,7 @@ use core::convert::TryInto;
use crate::{
error::Error,
micropython::{buffer::StrBuffer, map::Map, module::Module, obj::Obj, qstr::Qstr},
micropython::{buffer::StrBuffer, map::Map, module::Module, obj::Obj, qstr::Qstr, util},
ui::{
component::{
base::Component,
@ -15,7 +15,6 @@ use crate::{
result::{CANCELLED, CONFIRMED},
},
},
util,
};
use super::{

View File

@ -1,4 +1,6 @@
pub mod component;
pub mod constant;
pub mod layout;
pub mod theme;
#[cfg(feature = "micropython")]
pub mod layout;

View File

@ -2,7 +2,7 @@ use core::convert::TryInto;
use crate::{
error::Error,
micropython::{buffer::StrBuffer, map::Map, module::Module, obj::Obj, qstr::Qstr},
micropython::{buffer::StrBuffer, map::Map, module::Module, obj::Obj, qstr::Qstr, util},
ui::{
component::{
base::Component,
@ -15,7 +15,6 @@ use crate::{
result::{CANCELLED, CONFIRMED},
},
},
util,
};
use super::{

View File

@ -1,4 +1,6 @@
pub mod component;
pub mod constant;
pub mod layout;
pub mod theme;
#[cfg(feature = "micropython")]
pub mod layout;

View File

@ -6,8 +6,8 @@ use crate::{
component::{Event, EventCtx, TimerToken},
display::{self, Color, Font},
geometry::{Offset, Point, Rect},
util::ResultExt,
},
util::ResultExt,
};
pub const HEADER_HEIGHT: i32 = 25;

View File

@ -18,8 +18,8 @@ use crate::{
},
theme,
},
util::ResultExt,
},
util::ResultExt,
};
const MAX_LENGTH: usize = 8;

View File

@ -2,7 +2,7 @@ use core::{convert::TryInto, ops::Deref};
use crate::{
error::Error,
micropython::{buffer::StrBuffer, map::Map, module::Module, obj::Obj, qstr::Qstr},
micropython::{buffer::StrBuffer, map::Map, module::Module, obj::Obj, qstr::Qstr, util},
ui::{
component::{
base::ComponentExt,
@ -15,7 +15,6 @@ use crate::{
result::{CANCELLED, CONFIRMED, INFO},
},
},
util,
};
use super::{

View File

@ -1,5 +1,7 @@
pub mod component;
pub mod constant;
pub mod event;
pub mod layout;
pub mod theme;
#[cfg(feature = "micropython")]
pub mod layout;

View File

@ -0,0 +1,12 @@
pub trait ResultExt {
fn assert_if_debugging_ui(self, message: &str);
}
impl<T, E> ResultExt for Result<T, E> {
fn assert_if_debugging_ui(self, #[allow(unused)] message: &str) {
#[cfg(feature = "ui_debug")]
if self.is_err() {
panic!("{}", message);
}
}
}

View File

@ -1,3 +1,4 @@
#include "common.h"
#include "display.h"
#include "secbool.h"
#include "storage.h"

View File

@ -134,6 +134,7 @@ void __assert_func(const char *file, int line, const char *func,
#endif
void hal_delay(uint32_t ms) { HAL_Delay(ms); }
uint32_t hal_ticks_ms() { return HAL_GetTick(); }
// reference RM0090 section 35.12.1 Figure 413
#define USB_OTG_HS_DATA_FIFO_RAM (USB_OTG_HS_PERIPH_BASE + 0x20000U)

View File

@ -66,6 +66,7 @@ error_shutdown(const char *line1, const char *line2, const char *line3,
: __fatal_error(#expr, msg, __FILE__, __LINE__, __func__))
void hal_delay(uint32_t ms);
uint32_t hal_ticks_ms();
void clear_otg_hs_memory(void);

View File

@ -20,6 +20,7 @@
#include <SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include "common.h"
@ -116,6 +117,12 @@ error_shutdown(const char *line1, const char *line2, const char *line3,
void hal_delay(uint32_t ms) { usleep(1000 * ms); }
uint32_t hal_ticks_ms() {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
static int SDLCALL emulator_event_filter(void *userdata, SDL_Event *event) {
switch (event->type) {
case SDL_QUIT: