diff --git a/core/embed/extmod/modtrezorui/display.h b/core/embed/extmod/modtrezorui/display.h index b53de37c5..aadf72cf0 100644 --- a/core/embed/extmod/modtrezorui/display.h +++ b/core/embed/extmod/modtrezorui/display.h @@ -21,6 +21,7 @@ #define __DISPLAY_H__ #include +#include #include #if defined TREZOR_MODEL_T diff --git a/core/embed/rust/Cargo.lock b/core/embed/rust/Cargo.lock index 6848085e1..abcb1132b 100644 --- a/core/embed/rust/Cargo.lock +++ b/core/embed/rust/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "bindgen" -version = "0.59.1" +version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453c49e5950bb0eb63bb3df640e31618846c89d5b7faa54040d76e98e0134375" +checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" dependencies = [ "bitflags", "cexpr", @@ -27,18 +27,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitvec" -version = "0.19.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - [[package]] name = "byteorder" version = "1.4.3" @@ -53,9 +41,9 @@ checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" [[package]] name = "cexpr" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db507a7679252d2276ed0dd8113c6875ec56d3089f9225b2b42c30cc1f8e5c89" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ "nom", ] @@ -93,12 +81,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - [[package]] name = "glob" version = "0.3.0" @@ -168,16 +150,20 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "nom" -version = "6.1.2" +version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" dependencies = [ - "bitvec", - "funty", "memchr", - "version_check", + "minimal-lexical", ] [[package]] @@ -204,12 +190,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" - [[package]] name = "regex" version = "1.5.6" @@ -258,12 +238,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "trezor_lib" version = "0.1.0" @@ -282,12 +256,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" -[[package]] -name = "version_check" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" - [[package]] name = "winapi" version = "0.3.9" @@ -309,9 +277,3 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" diff --git a/core/embed/rust/Cargo.toml b/core/embed/rust/Cargo.toml index cf5f4f8ca..3adfdaf2c 100644 --- a/core/embed/rust/Cargo.toml +++ b/core/embed/rust/Cargo.toml @@ -50,7 +50,7 @@ default_features = false # Build dependencies [build-dependencies.bindgen] -version = "0.59.1" +version = "0.60.1" default_features = false features = ["runtime"] diff --git a/core/embed/rust/build.rs b/core/embed/rust/build.rs index d360844fe..6e13ff9c2 100644 --- a/core/embed/rust/build.rs +++ b/core/embed/rust/build.rs @@ -5,10 +5,18 @@ use std::{env, path::PathBuf, process::Command}; fn main() { generate_qstr_bindings(); generate_micropython_bindings(); + generate_trezorhal_bindings(); #[cfg(feature = "test")] link_core_objects(); } +fn model() -> String { + match env::var("TREZOR_MODEL") { + Ok(model) => model, + Err(_) => String::from("T"), + } +} + /// Generates Rust module that exports QSTR constants used in firmware. fn generate_qstr_bindings() { let out_path = env::var("OUT_DIR").unwrap(); @@ -42,13 +50,80 @@ fn generate_qstr_bindings() { .unwrap(); } +fn prepare_bindings() -> bindgen::Builder { + let mut bindings = bindgen::Builder::default(); + + // Common include paths and defines + bindings = bindings.clang_args([ + "-I../../../crypto", + "-I../../../storage", + "-I../../vendor/micropython", + "-I../extmod/modtrezorui", // for display.h + format!("-DTREZOR_MODEL_{}", model()).as_str(), + ]); + + // Pass in correct include paths and defines. + if is_firmware() { + bindings = bindings.clang_args(&[ + "-nostdinc", + "-I../firmware", + "-I../trezorhal", + "-I../../build/firmware", + "-I../../vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Inc", + "-I../../vendor/micropython/lib/stm32lib/CMSIS/STM32F4xx/Include", + "-I../../vendor/micropython/lib/cmsis/inc", + "-DSTM32F427xx", + "-DUSE_HAL_DRIVER", + "-DSTM32_HAL_H=", + ]); + // Append gcc-arm-none-eabi's include paths. + let cc_output = Command::new("arm-none-eabi-gcc") + .arg("-E") + .arg("-Wp,-v") + .arg("-") + .output() + .expect("arm-none-eabi-gcc failed to execute"); + if !cc_output.status.success() { + panic!("arm-none-eabi-gcc failed"); + } + let include_paths = + String::from_utf8(cc_output.stderr).expect("arm-none-eabi-gcc returned invalid output"); + let include_args = include_paths + .lines() + .skip_while(|s| !s.contains("search starts here:")) + .take_while(|s| !s.contains("End of search list.")) + .filter(|s| s.starts_with(' ')) + .map(|s| format!("-I{}", s.trim())); + + bindings = bindings.clang_args(include_args); + } else { + bindings = bindings.clang_args(&[ + "-I../unix", + "-I../../build/unix", + "-I../../vendor/micropython/ports/unix", + ]); + } + + bindings + // Customize the standard types. + .use_core() + .ctypes_prefix("cty") + .size_t_is_usize(true) + // Disable the layout tests. They spew out a lot of code-style bindings, and are not too + // relevant for our use-case. + .layout_tests(false) + // Tell cargo to invalidate the built crate whenever any of the + // included header files change. + .parse_callbacks(Box::new(bindgen::CargoCallbacks)) +} + fn generate_micropython_bindings() { let out_path = env::var("OUT_DIR").unwrap(); // Tell cargo to invalidate the built crate whenever the header changes. println!("cargo:rerun-if-changed=micropython.h"); - let mut bindings = bindgen::Builder::default() + let bindings = prepare_bindings() .header("micropython.h") // obj .new_type_alias("mp_obj_t") @@ -121,74 +196,86 @@ fn generate_micropython_bindings() { .allowlist_var("mp_type_type") // module .allowlist_type("mp_obj_module_t") - .allowlist_var("mp_type_module"); + .allowlist_var("mp_type_module") + // `ffi::mp_map_t` type is not allowed to be `Clone` or `Copy` because we tie it + // to the data lifetimes with the `MapRef` type, see `src/micropython/map.rs`. + // TODO: We should disable `Clone` and `Copy` for all types and only allow-list + // the specific cases we require. + .no_copy("_mp_map_t"); - // `ffi::mp_map_t` type is not allowed to be `Clone` or `Copy` because we tie it - // to the data lifetimes with the `MapRef` type, see `src/micropython/map.rs`. - // TODO: We should disable `Clone` and `Copy` for all types and only allow-list - // the specific cases we require. - bindings = bindings.no_copy("_mp_map_t"); + // Write the bindings to a file in the OUR_DIR. + bindings + .generate() + .expect("Unable to generate bindings") + .write_to_file(PathBuf::from(out_path).join("micropython.rs")) + .unwrap(); +} - // Pass in correct include paths and defines. - if is_firmware() { - bindings = bindings.clang_args(&[ - "-nostdinc", - "-I../firmware", - "-I../trezorhal", - "-I../../build/firmware", - "-I../../vendor/micropython", - "-I../../vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Inc", - "-I../../vendor/micropython/lib/stm32lib/CMSIS/STM32F4xx/Include", - "-I../../vendor/micropython/lib/cmsis/inc", - "-DTREZOR_MODEL_T", - "-DSTM32F405xx", - "-DUSE_HAL_DRIVER", - "-DSTM32_HAL_H=", - ]); - // Append gcc-arm-none-eabi's include paths. - let cc_output = Command::new("arm-none-eabi-gcc") - .arg("-E") - .arg("-Wp,-v") - .arg("-") - .output() - .expect("arm-none-eabi-gcc failed to execute"); - if !cc_output.status.success() { - panic!("arm-none-eabi-gcc failed"); - } - let include_paths = - String::from_utf8(cc_output.stderr).expect("arm-none-eabi-gcc returned invalid output"); - let include_args = include_paths - .lines() - .skip_while(|s| !s.contains("search starts here:")) - .take_while(|s| !s.contains("End of search list.")) - .filter(|s| s.starts_with(' ')) - .map(|s| format!("-I{}", s.trim())); +fn generate_trezorhal_bindings() { + let out_path = env::var("OUT_DIR").unwrap(); - bindings = bindings.clang_args(include_args); - } else { - bindings = bindings.clang_args(&[ - "-I../unix", - "-I../../build/unix", - "-I../../vendor/micropython", - "-I../../vendor/micropython/ports/unix", - ]); - } + // Tell cargo to invalidate the built crate whenever the header changes. + println!("cargo:rerun-if-changed=trezorhal.h"); + let bindings = prepare_bindings() + .header("trezorhal.h") + // secbool + .allowlist_type("secbool") + .must_use_type("secbool") + .allowlist_var("sectrue") + .allowlist_var("secfalse") + // storage + .allowlist_var("EXTERNAL_SALT_SIZE") + .allowlist_var("FLAG_PUBLIC") + .allowlist_var("FLAGS_WRITE") + .allowlist_var("MAX_APPID") + .allowlist_type("PIN_UI_WAIT_CALLBACK") + .allowlist_function("storage_init") + .allowlist_function("storage_wipe") + .allowlist_function("storage_is_unlocked") + .allowlist_function("storage_lock") + .allowlist_function("storage_unlock") + .allowlist_function("storage_has_pin") + .allowlist_function("storage_get_pin_rem") + .allowlist_function("storage_change_pin") + .allowlist_function("storage_has") + .allowlist_function("storage_get") + .allowlist_function("storage_set") + .allowlist_function("storage_delete") + .allowlist_function("storage_set_counter") + .allowlist_function("storage_next_counter") + // display + .allowlist_function("display_init") + .allowlist_function("display_refresh") + .allowlist_function("display_backlight") + .allowlist_function("display_text") + .allowlist_function("display_text_width") + .allowlist_function("display_text_height") + .allowlist_function("display_bar") + .allowlist_function("display_bar_radius") + .allowlist_function("display_icon") + .allowlist_function("display_toif_info") + .allowlist_function("display_loader") + .allowlist_function("display_pixeldata") + .allowlist_function("display_pixeldata_dirty") + .allowlist_function("display_set_window") + .allowlist_var("DISPLAY_CMD_ADDRESS") + .allowlist_var("DISPLAY_DATA_ADDRESS") + // bip39 + .allowlist_function("mnemonic_word_completion_mask") + .allowlist_var("BIP39_WORDLIST_ENGLISH") + .allowlist_var("BIP39_WORD_COUNT") + // slip39 + .allowlist_function("slip39_word_completion_mask") + .allowlist_function("button_sequence_to_word") + // random + .allowlist_function("random_uniform"); + + // Write the bindings to a file in the OUR_DIR. bindings - // Customize the standard types. - .use_core() - .ctypes_prefix("cty") - .size_t_is_usize(true) - // Disable the layout tests. They spew out a lot of code-style bindings, and are not too - // relevant for our use-case. - .layout_tests(false) - // Tell cargo to invalidate the built crate whenever any of the - // included header files change. - .parse_callbacks(Box::new(bindgen::CargoCallbacks)) - // Write the bindings to a file in the OUR_DIR. .generate() - .expect("Unable to generate Rust Micropython bindings") - .write_to_file(PathBuf::from(out_path).join("micropython.rs")) + .expect("Unable to generate bindings") + .write_to_file(PathBuf::from(out_path).join("trezorhal.rs")) .unwrap(); } diff --git a/core/embed/rust/src/trezorhal/bip39.rs b/core/embed/rust/src/trezorhal/bip39.rs index 96be01c43..e6cae04aa 100644 --- a/core/embed/rust/src/trezorhal/bip39.rs +++ b/core/embed/rust/src/trezorhal/bip39.rs @@ -1,15 +1,7 @@ +use super::ffi; use core::cmp::Ordering; use cstr_core::CStr; -// TODO: expose from trezor-crypto via build.rs -const BIP39_WORD_COUNT: usize = 2048; - -extern "C" { - // trezor-crypto/bip39.h - fn mnemonic_word_completion_mask(prefix: *const cty::c_char, len: cty::c_int) -> u32; - pub static BIP39_WORDLIST_ENGLISH: [*const cty::c_char; BIP39_WORD_COUNT]; -} - unsafe fn from_utf8_unchecked<'a>(word: *const cty::c_char) -> &'a str { // SAFETY: caller must pass a valid 0-terminated UTF-8 string. // This assumption holds for usage on words of the BIP-39 wordlist. @@ -49,14 +41,14 @@ pub fn complete_word(prefix: &str) -> Option<&'static str> { pub fn word_completion_mask(prefix: &str) -> u32 { // SAFETY: `mnemonic_word_completion_mask` shouldn't retain nor modify the // passed byte string, making the call safe. - unsafe { mnemonic_word_completion_mask(prefix.as_ptr() as _, prefix.len() as _) } + unsafe { ffi::mnemonic_word_completion_mask(prefix.as_ptr() as _, prefix.len() as _) } } pub struct Wordlist(&'static [*const cty::c_char]); impl Wordlist { pub fn all() -> Self { - Self(unsafe { &BIP39_WORDLIST_ENGLISH }) + Self(unsafe { &ffi::BIP39_WORDLIST_ENGLISH }) } pub const fn empty() -> Self { @@ -105,6 +97,8 @@ impl Wordlist { mod tests { use super::*; + const BIP39_WORD_COUNT: usize = ffi::BIP39_WORD_COUNT as usize; + #[test] fn test_prefix_cmp() { assert_eq!(unsafe { prefix_cmp("", "".as_ptr() as _) }, Ordering::Equal); diff --git a/core/embed/rust/src/trezorhal/display.rs b/core/embed/rust/src/trezorhal/display.rs index f470b531d..08cb446c3 100644 --- a/core/embed/rust/src/trezorhal/display.rs +++ b/core/embed/rust/src/trezorhal/display.rs @@ -1,62 +1,6 @@ +use super::ffi; use core::ptr; -extern "C" { - // trezorhal/display.c - fn display_backlight(val: cty::c_int) -> cty::c_int; - fn display_text( - x: cty::c_int, - y: cty::c_int, - text: *const cty::c_char, - textlen: cty::c_int, - font: cty::c_int, - fgcolor: cty::uint16_t, - bgcolor: cty::uint16_t, - ); - fn display_text_width( - text: *const cty::c_char, - textlen: cty::c_int, - font: cty::c_int, - ) -> cty::c_int; - fn display_text_height(font: cty::c_int) -> cty::c_int; - fn display_bar(x: cty::c_int, y: cty::c_int, w: cty::c_int, h: cty::c_int, c: cty::uint16_t); - fn display_bar_radius( - x: cty::c_int, - y: cty::c_int, - w: cty::c_int, - h: cty::c_int, - c: cty::uint16_t, - b: cty::uint16_t, - r: cty::uint8_t, - ); - fn display_icon( - x: cty::c_int, - y: cty::c_int, - w: cty::c_int, - h: cty::c_int, - data: *const cty::c_void, - len: cty::uint32_t, - fgcolor: cty::uint16_t, - bgcolor: cty::uint16_t, - ); - fn display_toif_info( - data: *const cty::uint8_t, - len: cty::uint32_t, - out_w: *mut cty::uint16_t, - out_h: *mut cty::uint16_t, - out_grayscale: *mut bool, - ) -> bool; - fn display_loader( - progress: cty::uint16_t, - indeterminate: bool, - yoffset: cty::c_int, - fgcolor: cty::uint16_t, - bgcolor: cty::uint16_t, - icon: *const cty::uint8_t, - iconlen: cty::uint32_t, - iconfgcolor: cty::uint16_t, - ); -} - pub struct ToifInfo { pub width: u16, pub height: u16, @@ -64,12 +8,12 @@ pub struct ToifInfo { } pub fn backlight(val: i32) -> i32 { - unsafe { display_backlight(val) } + unsafe { ffi::display_backlight(val) } } pub fn text(baseline_x: i32, baseline_y: i32, text: &str, font: i32, fgcolor: u16, bgcolor: u16) { unsafe { - display_text( + ffi::display_text( baseline_x, baseline_y, text.as_ptr() as _, @@ -82,7 +26,7 @@ pub fn text(baseline_x: i32, baseline_y: i32, text: &str, font: i32, fgcolor: u1 } pub fn text_width(text: &str, font: i32) -> i32 { - unsafe { display_text_width(text.as_ptr() as _, text.len() as _, font) } + unsafe { ffi::display_text_width(text.as_ptr() as _, text.len() as _, font) } } pub fn char_width(ch: char, font: i32) -> i32 { @@ -92,20 +36,20 @@ pub fn char_width(ch: char, font: i32) -> i32 { } pub fn text_height(font: i32) -> i32 { - unsafe { display_text_height(font) } + unsafe { ffi::display_text_height(font) } } pub fn bar(x: i32, y: i32, w: i32, h: i32, fgcolor: u16) { - unsafe { display_bar(x, y, w, h, fgcolor) } + unsafe { ffi::display_bar(x, y, w, h, fgcolor) } } pub fn bar_radius(x: i32, y: i32, w: i32, h: i32, fgcolor: u16, bgcolor: u16, radius: u8) { - unsafe { display_bar_radius(x, y, w, h, fgcolor, bgcolor, radius) } + unsafe { ffi::display_bar_radius(x, y, w, h, fgcolor, bgcolor, radius) } } pub fn icon(x: i32, y: i32, w: i32, h: i32, data: &[u8], fgcolor: u16, bgcolor: u16) { unsafe { - display_icon( + ffi::display_icon( x, y, w, @@ -123,7 +67,7 @@ pub fn toif_info(data: &[u8]) -> Result { let mut height: cty::uint16_t = 0; let mut grayscale: bool = false; if unsafe { - display_toif_info( + ffi::display_toif_info( data.as_ptr() as _, data.len() as _, &mut width, @@ -151,7 +95,7 @@ pub fn loader( iconfgcolor: u16, ) { unsafe { - display_loader( + ffi::display_loader( progress, indeterminate, yoffset, diff --git a/core/embed/rust/src/trezorhal/ffi.rs b/core/embed/rust/src/trezorhal/ffi.rs new file mode 100644 index 000000000..bc2e925a5 --- /dev/null +++ b/core/embed/rust/src/trezorhal/ffi.rs @@ -0,0 +1,5 @@ +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] +#![allow(dead_code)] + +include!(concat!(env!("OUT_DIR"), "/trezorhal.rs")); diff --git a/core/embed/rust/src/trezorhal/mod.rs b/core/embed/rust/src/trezorhal/mod.rs index b75deffb7..72c20fa29 100644 --- a/core/embed/rust/src/trezorhal/mod.rs +++ b/core/embed/rust/src/trezorhal/mod.rs @@ -2,5 +2,6 @@ pub mod bip39; pub mod common; #[cfg(feature = "ui")] pub mod display; +mod ffi; pub mod random; pub mod slip39; diff --git a/core/embed/rust/src/trezorhal/random.rs b/core/embed/rust/src/trezorhal/random.rs index 6b73f6c07..8f64b0773 100644 --- a/core/embed/rust/src/trezorhal/random.rs +++ b/core/embed/rust/src/trezorhal/random.rs @@ -1,10 +1,5 @@ -extern "C" { - // trezor-crypto/rand.h - fn random_uniform(n: u32) -> u32; -} - pub fn uniform(n: u32) -> u32 { - unsafe { random_uniform(n) } + unsafe { super::ffi::random_uniform(n) } } pub fn shuffle(slice: &mut [T]) { diff --git a/core/embed/rust/src/trezorhal/slip39.rs b/core/embed/rust/src/trezorhal/slip39.rs index ace10c70f..7ccaba95b 100644 --- a/core/embed/rust/src/trezorhal/slip39.rs +++ b/core/embed/rust/src/trezorhal/slip39.rs @@ -1,12 +1,6 @@ use cstr_core::CStr; -mod ffi { - extern "C" { - // trezor-crypto/slip39.h - pub fn slip39_word_completion_mask(prefix: u16) -> u16; - pub fn button_sequence_to_word(sequence: u16) -> *const cty::c_char; - } -} +use super::ffi; /// Calculates which buttons still can be pressed after some already were. /// Returns a 9-bit bitmask, where each bit specifies which buttons diff --git a/core/embed/rust/trezorhal.h b/core/embed/rust/trezorhal.h new file mode 100644 index 000000000..18cc77fba --- /dev/null +++ b/core/embed/rust/trezorhal.h @@ -0,0 +1,7 @@ +#include "display.h" +#include "secbool.h" +#include "storage.h" + +#include "bip39.h" +#include "rand.h" +#include "slip39.h"