Merge branch 'master' into client-pin-features
This commit is contained in:
2
.github/workflows/boards_build.yml
vendored
2
.github/workflows/boards_build.yml
vendored
@@ -16,6 +16,8 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: "true"
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
target: thumbv7em-none-eabi
|
||||
|
||||
2
.github/workflows/cargo_audit.yml
vendored
2
.github/workflows/cargo_audit.yml
vendored
@@ -9,6 +9,8 @@ jobs:
|
||||
if: github.repository == 'google/OpenSK'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: "true"
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
target: thumbv7em-none-eabi
|
||||
|
||||
2
.github/workflows/cargo_check.yml
vendored
2
.github/workflows/cargo_check.yml
vendored
@@ -17,6 +17,8 @@ jobs:
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: "true"
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
target: thumbv7em-none-eabi
|
||||
|
||||
8
.github/workflows/cargo_fmt.yml
vendored
8
.github/workflows/cargo_fmt.yml
vendored
@@ -18,6 +18,8 @@ jobs:
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: "true"
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
target: thumbv7em-none-eabi
|
||||
@@ -41,6 +43,12 @@ jobs:
|
||||
with:
|
||||
command: fmt
|
||||
args: --manifest-path libraries/cbor/Cargo.toml --all -- --check
|
||||
|
||||
- name: Cargo format libraries/cbor/fuzz
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --manifest-path libraries/cbor/fuzz/Cargo.toml --all -- --check
|
||||
|
||||
- name: Cargo format libraries/crypto
|
||||
uses: actions-rs/cargo@v1
|
||||
|
||||
2
.github/workflows/cbor_test.yml
vendored
2
.github/workflows/cbor_test.yml
vendored
@@ -12,6 +12,8 @@ jobs:
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: "true"
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
target: thumbv7em-none-eabi
|
||||
|
||||
2
.github/workflows/crypto_test.yml
vendored
2
.github/workflows/crypto_test.yml
vendored
@@ -14,6 +14,8 @@ jobs:
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: "true"
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
target: thumbv7em-none-eabi
|
||||
|
||||
2
.github/workflows/opensk_build.yml
vendored
2
.github/workflows/opensk_build.yml
vendored
@@ -13,6 +13,8 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: "true"
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
target: thumbv7em-none-eabi
|
||||
|
||||
2
.github/workflows/opensk_test.yml
vendored
2
.github/workflows/opensk_test.yml
vendored
@@ -14,6 +14,8 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: "true"
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
target: thumbv7em-none-eabi
|
||||
|
||||
2
.github/workflows/python.yml
vendored
2
.github/workflows/python.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
pip install 'tockloader==1.4' pylint
|
||||
pip install 'tockloader==1.5' pylint
|
||||
- name: Register matcher
|
||||
run: echo ::add-matcher::./.github/python_matcher.json
|
||||
- name: Test code with pylint
|
||||
|
||||
2
.github/workflows/reproducible.yml
vendored
2
.github/workflows/reproducible.yml
vendored
@@ -14,6 +14,8 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: "true"
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
target: thumbv7em-none-eabi
|
||||
|
||||
14
Cargo.toml
14
Cargo.toml
@@ -10,7 +10,9 @@ license = "Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libtock = { path = "third_party/libtock-rs" }
|
||||
libtock_core = { path = "third_party/libtock-rs/core" }
|
||||
libtock_drivers = { path = "third_party/libtock-drivers" }
|
||||
lang_items = { path = "third_party/lang-items" }
|
||||
cbor = { path = "libraries/cbor" }
|
||||
crypto = { path = "libraries/crypto" }
|
||||
byteorder = { version = "1", default-features = false }
|
||||
@@ -18,12 +20,12 @@ arrayref = "0.3.6"
|
||||
subtle = { version = "2.2", default-features = false, features = ["nightly"] }
|
||||
|
||||
[features]
|
||||
debug_allocations = ["libtock/debug_allocations"]
|
||||
debug_ctap = ["crypto/derive_debug"]
|
||||
panic_console = ["libtock/panic_console"]
|
||||
std = ["cbor/std", "crypto/std", "crypto/derive_debug"]
|
||||
debug_allocations = ["lang_items/debug_allocations"]
|
||||
debug_ctap = ["crypto/derive_debug", "libtock_drivers/debug_ctap"]
|
||||
panic_console = ["lang_items/panic_console"]
|
||||
std = ["cbor/std", "crypto/std", "crypto/derive_debug", "lang_items/std"]
|
||||
ram_storage = []
|
||||
verbose = ["debug_ctap"]
|
||||
verbose = ["debug_ctap", "libtock_drivers/verbose_usb"]
|
||||
with_ctap1 = ["crypto/with_ctap1"]
|
||||
with_ctap2_1 = []
|
||||
|
||||
|
||||
68
deploy.py
68
deploy.py
@@ -255,7 +255,6 @@ class RemoveConstAction(argparse.Action):
|
||||
class OpenSKInstaller:
|
||||
|
||||
def __init__(self, args):
|
||||
colorama.init()
|
||||
self.args = args
|
||||
# Where all the TAB files should go
|
||||
self.tab_folder = os.path.join("target", "tab")
|
||||
@@ -373,6 +372,7 @@ class OpenSKInstaller:
|
||||
]
|
||||
env = os.environ.copy()
|
||||
env["RUSTFLAGS"] = " ".join(rust_flags)
|
||||
env["APP_HEAP_SIZE"] = str(APP_HEAP_SIZE)
|
||||
|
||||
command = [
|
||||
"cargo", "build", "--release", "--target={}".format(props.arch),
|
||||
@@ -453,14 +453,10 @@ class OpenSKInstaller:
|
||||
self.args.application, str(e)))
|
||||
|
||||
def get_padding(self):
|
||||
fake_header = tbfh.TBFHeader("")
|
||||
fake_header.version = 2
|
||||
fake_header.fields["header_size"] = 0x10
|
||||
fake_header.fields["total_size"] = (
|
||||
padding = tbfh.TBFHeaderPadding(
|
||||
SUPPORTED_BOARDS[self.args.board].app_address -
|
||||
SUPPORTED_BOARDS[self.args.board].padding_address)
|
||||
fake_header.fields["flags"] = 0
|
||||
return fake_header.get_binary()
|
||||
return padding.get_binary()
|
||||
|
||||
def install_tock_os(self):
|
||||
board_props = SUPPORTED_BOARDS[self.args.board]
|
||||
@@ -542,7 +538,7 @@ class OpenSKInstaller:
|
||||
tock.open()
|
||||
app_found = False
|
||||
with tock._start_communication_with_board():
|
||||
apps = [app.name for app in tock._extract_all_app_headers()]
|
||||
apps = [app.get_name() for app in tock._extract_all_app_headers()]
|
||||
app_found = expected_app in apps
|
||||
return app_found
|
||||
|
||||
@@ -581,16 +577,17 @@ class OpenSKInstaller:
|
||||
"architecture {}".format(board_props.arch)))
|
||||
app_hex = intelhex.IntelHex()
|
||||
app_hex.frombytes(
|
||||
app_tab.extract_app(board_props.arch).get_binary(),
|
||||
app_tab.extract_app(board_props.arch).get_binary(
|
||||
board_props.app_address),
|
||||
offset=board_props.app_address)
|
||||
final_hex.merge(app_hex)
|
||||
info("Generating all-merged HEX file: {}".format(dest_file))
|
||||
final_hex.tofile(dest_file, format="hex")
|
||||
|
||||
def check_prerequisites(self):
|
||||
if not tockloader.__version__.startswith("1.4."):
|
||||
if not tockloader.__version__.startswith("1.5."):
|
||||
fatal(("Your version of tockloader seems incompatible: found {}, "
|
||||
"expected 1.4.x.".format(tockloader.__version__)))
|
||||
"expected 1.5.x.".format(tockloader.__version__)))
|
||||
|
||||
if self.args.programmer == "jlink":
|
||||
assert_mandatory_binary("JLinkExe")
|
||||
@@ -619,18 +616,6 @@ class OpenSKInstaller:
|
||||
assert_python_library("intelhex")
|
||||
|
||||
def run(self):
|
||||
if self.args.listing == "boards":
|
||||
print(os.linesep.join(get_supported_boards()))
|
||||
return 0
|
||||
|
||||
if self.args.listing == "programmers":
|
||||
print(os.linesep.join(PROGRAMMERS))
|
||||
return 0
|
||||
|
||||
if self.args.listing:
|
||||
# Missing check?
|
||||
fatal("Listing {} is not implemented.".format(self.args.listing))
|
||||
|
||||
self.check_prerequisites()
|
||||
self.update_rustc_if_needed()
|
||||
|
||||
@@ -728,9 +713,23 @@ class OpenSKInstaller:
|
||||
|
||||
|
||||
def main(args):
|
||||
colorama.init()
|
||||
|
||||
# Make sure the current working directory is the right one before running
|
||||
os.chdir(os.path.realpath(os.path.dirname(__file__)))
|
||||
|
||||
if args.listing == "boards":
|
||||
print(os.linesep.join(get_supported_boards()))
|
||||
return 0
|
||||
|
||||
if args.listing == "programmers":
|
||||
print(os.linesep.join(PROGRAMMERS))
|
||||
return 0
|
||||
|
||||
if args.listing:
|
||||
# Missing check?
|
||||
fatal("Listing {} is not implemented.".format(args.listing))
|
||||
|
||||
OpenSKInstaller(args).run()
|
||||
|
||||
|
||||
@@ -874,7 +873,12 @@ if __name__ == "__main__":
|
||||
help=("When set, the output of elf2tab is appended to this file."),
|
||||
)
|
||||
|
||||
apps_group = main_parser.add_mutually_exclusive_group(required=True)
|
||||
# Start parsing to know if we're going to list things or not.
|
||||
partial_args, _ = main_parser.parse_known_args()
|
||||
|
||||
# We only need the apps_group if we have a board set
|
||||
apps_group = main_parser.add_mutually_exclusive_group(
|
||||
required=(partial_args.board is not None))
|
||||
apps_group.add_argument(
|
||||
"--no-app",
|
||||
dest="application",
|
||||
@@ -893,8 +897,22 @@ if __name__ == "__main__":
|
||||
dest="application",
|
||||
action="store_const",
|
||||
const="crypto_bench",
|
||||
help=("Compiles and installs the crypto_bench example that tests "
|
||||
help=("Compiles and installs the crypto_bench example that benchmarks "
|
||||
"the performance of the cryptographic algorithms on the board."))
|
||||
apps_group.add_argument(
|
||||
"--panic_test",
|
||||
dest="application",
|
||||
action="store_const",
|
||||
const="panic_test",
|
||||
help=("Compiles and installs the panic_test example that immediately "
|
||||
"triggers a panic."))
|
||||
apps_group.add_argument(
|
||||
"--oom_test",
|
||||
dest="application",
|
||||
action="store_const",
|
||||
const="oom_test",
|
||||
help=("Compiles and installs the oom_test example that tests the "
|
||||
"allocator until an out-of-memory error occurs."))
|
||||
|
||||
main_parser.set_defaults(features=["with_ctap1"])
|
||||
|
||||
|
||||
@@ -17,24 +17,26 @@
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
extern crate crypto;
|
||||
extern crate libtock;
|
||||
extern crate lang_items;
|
||||
extern crate libtock_drivers;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::Write;
|
||||
use crypto::{
|
||||
aes256, cbc, ecdsa, rng256, sha256, Decrypt16BytesBlock, Encrypt16BytesBlock, Hash256,
|
||||
};
|
||||
use libtock::console::Console;
|
||||
use libtock::timer;
|
||||
use libtock::timer::Timer;
|
||||
use libtock::timer::Timestamp;
|
||||
use libtock_drivers::console::Console;
|
||||
use libtock_drivers::result::FlexUnwrap;
|
||||
use libtock_drivers::timer;
|
||||
use libtock_drivers::timer::Timer;
|
||||
use libtock_drivers::timer::Timestamp;
|
||||
|
||||
fn main() {
|
||||
let mut console = Console::new();
|
||||
// Setup the timer with a dummy callback (we only care about reading the current time, but the
|
||||
// API forces us to set an alarm callback too).
|
||||
let mut with_callback = timer::with_callback(|_, _| {});
|
||||
let timer = with_callback.init().unwrap();
|
||||
let timer = with_callback.init().flex_unwrap();
|
||||
|
||||
let mut rng = rng256::TockRng256 {};
|
||||
|
||||
@@ -158,11 +160,11 @@ where
|
||||
writeln!(console, "----------------------------------------").unwrap();
|
||||
let mut count = 1;
|
||||
for _ in 0..30 {
|
||||
let start = Timestamp::<f64>::from_clock_value(timer.get_current_clock());
|
||||
let start = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
|
||||
for _ in 0..count {
|
||||
f();
|
||||
}
|
||||
let end = Timestamp::<f64>::from_clock_value(timer.get_current_clock());
|
||||
let end = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
|
||||
let elapsed = (end - start).ms();
|
||||
writeln!(
|
||||
console,
|
||||
@@ -172,6 +174,7 @@ where
|
||||
elapsed / (count as f64)
|
||||
)
|
||||
.unwrap();
|
||||
console.flush();
|
||||
if elapsed > 1000.0 {
|
||||
break;
|
||||
}
|
||||
|
||||
35
examples/oom_test.rs
Normal file
35
examples/oom_test.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate crypto;
|
||||
extern crate lang_items;
|
||||
extern crate libtock_drivers;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::Write;
|
||||
use libtock_drivers::console::Console;
|
||||
|
||||
fn main() {
|
||||
writeln!(Console::new(), "****************************************").unwrap();
|
||||
for i in 0.. {
|
||||
writeln!(Console::new(), "Allocating {} bytes...", 1 << i).unwrap();
|
||||
let x: Vec<u8> = Vec::with_capacity(1 << i);
|
||||
writeln!(Console::new(), "Allocated!").unwrap();
|
||||
drop(x);
|
||||
writeln!(Console::new(), "Dropped!").unwrap();
|
||||
}
|
||||
}
|
||||
24
examples/panic_test.rs
Normal file
24
examples/panic_test.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate crypto;
|
||||
extern crate lang_items;
|
||||
extern crate libtock_drivers;
|
||||
|
||||
fn main() {
|
||||
panic!("Bye world!")
|
||||
}
|
||||
26
libraries/cbor/fuzz/Cargo.toml
Normal file
26
libraries/cbor/fuzz/Cargo.toml
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
[package]
|
||||
name = "cbor-fuzz"
|
||||
version = "0.0.0"
|
||||
authors = ["Automatically generated"]
|
||||
publish = false
|
||||
edition = "2018"
|
||||
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
libfuzzer-sys = "0.3"
|
||||
|
||||
[dependencies.cbor]
|
||||
path = ".."
|
||||
|
||||
# Prevent this from interfering with workspaces
|
||||
[workspace]
|
||||
members = ["."]
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_target_cbor"
|
||||
path = "fuzz_targets/fuzz_target_cbor.rs"
|
||||
test = false
|
||||
doc = false
|
||||
15
libraries/cbor/fuzz/fuzz_targets/fuzz_target_cbor.rs
Normal file
15
libraries/cbor/fuzz/fuzz_targets/fuzz_target_cbor.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
#![no_main]
|
||||
#[macro_use]
|
||||
extern crate libfuzzer_sys;
|
||||
extern crate alloc;
|
||||
extern crate cbor;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
if let Ok(value) = cbor::read(data) {
|
||||
let mut result = Vec::new();
|
||||
assert!(cbor::write(value, &mut result));
|
||||
assert_eq!(result, data);
|
||||
};
|
||||
});
|
||||
@@ -10,10 +10,10 @@ license = "Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libtock = { path = "../../third_party/libtock-rs" }
|
||||
libtock_drivers = { path = "../../third_party/libtock-drivers" }
|
||||
cbor = { path = "../cbor" }
|
||||
arrayref = "0.3.6"
|
||||
subtle = { version = "2.2", default-features = false, features = ["nightly"] }
|
||||
subtle = { version = "2.2.3", default-features = false, features = ["nightly"] }
|
||||
byteorder = { version = "1", default-features = false }
|
||||
hex = { version = "0.3.2", default-features = false, optional = true }
|
||||
ring = { version = "0.16.11", optional = true }
|
||||
|
||||
@@ -21,7 +21,6 @@ extern crate subtle;
|
||||
#[macro_use]
|
||||
extern crate arrayref;
|
||||
extern crate byteorder;
|
||||
extern crate libtock;
|
||||
#[macro_use]
|
||||
extern crate cbor;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use libtock::rng;
|
||||
use libtock_drivers::rng;
|
||||
|
||||
// Lightweight RNG trait to generate uniformly distributed 256 bits.
|
||||
pub trait Rng256 {
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
diff --git a/Cargo.toml b/Cargo.toml
|
||||
index 29d9b79..30081f3 100644
|
||||
--- a/Cargo.toml
|
||||
+++ b/Cargo.toml
|
||||
@@ -6,7 +6,7 @@ license = "MIT/Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
-linked_list_allocator = "0.6.4"
|
||||
+linked_list_allocator = "0.6.6"
|
||||
|
||||
[dev-dependencies]
|
||||
corepack = { version = "0.4.0", default-features = false, features = ["alloc"] }
|
||||
@@ -1,81 +0,0 @@
|
||||
diff --git a/Cargo.toml b/Cargo.toml
|
||||
--- a/Cargo.toml
|
||||
+++ b/Cargo.toml
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
[dependencies]
|
||||
linked_list_allocator = "0.6.6"
|
||||
+
|
||||
+[features]
|
||||
+panic_console = []
|
||||
|
||||
[dev-dependencies]
|
||||
corepack = { version = "0.4.0", default-features = false, features = ["alloc"] }
|
||||
diff --git a/src/lang_items.rs b/src/lang_items.rs
|
||||
index ab2c945..deef73b 100644
|
||||
--- a/src/lang_items.rs
|
||||
+++ b/src/lang_items.rs
|
||||
@@ -18,10 +18,14 @@
|
||||
//! `rustc_main`. That's covered by the `_start` function in the root of this
|
||||
//! crate.
|
||||
|
||||
+#[cfg(feature = "panic_console")]
|
||||
+use crate::console::Console;
|
||||
use crate::led;
|
||||
use crate::timer;
|
||||
use crate::timer::Duration;
|
||||
use core::alloc::Layout;
|
||||
+#[cfg(feature = "panic_console")]
|
||||
+use core::fmt::Write;
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
#[lang = "start"]
|
||||
@@ -42,11 +46,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
-#[panic_handler]
|
||||
-fn panic_handler(_info: &PanicInfo) -> ! {
|
||||
+fn flash_all_leds() -> ! {
|
||||
- // Signal a panic using the LowLevelDebug capsule (if available).
|
||||
- super::debug::low_level_status_code(1);
|
||||
-
|
||||
// Flash all LEDs (if available).
|
||||
loop {
|
||||
for led in led::all() {
|
||||
@@ -60,6 +59,34 @@
|
||||
}
|
||||
}
|
||||
|
||||
+#[cfg(feature = "panic_console")]
|
||||
+#[panic_handler]
|
||||
+fn panic_handler(info: &PanicInfo) -> ! {
|
||||
+ // Signal a panic using the LowLevelDebug capsule (if available).
|
||||
+ super::debug::low_level_status_code(1);
|
||||
+
|
||||
+ let mut console = Console::new();
|
||||
+ writeln!(console, "{}", info).ok();
|
||||
+ // Force the kernel to report the panic cause, by reading an invalid address.
|
||||
+ // The memory protection unit should be setup by the Tock kernel to prevent apps from accessing
|
||||
+ // address zero.
|
||||
+ unsafe {
|
||||
+ core::ptr::read_volatile(0 as *const usize);
|
||||
+ }
|
||||
+ // We still flash the LEDs in case for some reason the previous line didn't cause a crash in
|
||||
+ // the kernel.
|
||||
+ flash_all_leds();
|
||||
+}
|
||||
+
|
||||
+#[cfg(not(feature = "panic_console"))]
|
||||
+#[panic_handler]
|
||||
+fn panic_handler(_info: &PanicInfo) -> ! {
|
||||
+ // Signal a panic using the LowLevelDebug capsule (if available).
|
||||
+ super::debug::low_level_status_code(1);
|
||||
+
|
||||
+ flash_all_leds();
|
||||
+}
|
||||
+
|
||||
#[alloc_error_handler]
|
||||
fn cycle_leds(_: Layout) -> ! {
|
||||
loop {
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
diff --git a/src/timer.rs b/src/timer.rs
|
||||
index ae60b07..2e7d544 100644
|
||||
--- a/src/timer.rs
|
||||
+++ b/src/timer.rs
|
||||
@@ -178,7 +178,7 @@ impl<'a> Timer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
-#[derive(Copy, Clone, Debug)]
|
||||
+#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct ClockFrequency {
|
||||
hz: usize,
|
||||
}
|
||||
@@ -196,21 +196,53 @@ pub struct ClockValue {
|
||||
}
|
||||
|
||||
impl ClockValue {
|
||||
+ pub const fn new(num_ticks: isize, clock_hz: usize) -> ClockValue {
|
||||
+ ClockValue {
|
||||
+ num_ticks,
|
||||
+ clock_frequency: ClockFrequency { hz: clock_hz },
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
pub fn num_ticks(&self) -> isize {
|
||||
self.num_ticks
|
||||
}
|
||||
|
||||
+ // Computes (value * factor) / divisor, even when value * factor >= isize::MAX.
|
||||
+ fn scale_int(value: isize, factor: isize, divisor: isize) -> isize {
|
||||
+ // As long as isize is not i64, this should be fine. If not, this is an alternative:
|
||||
+ // factor * (value / divisor) + ((value % divisor) * factor) / divisor
|
||||
+ ((value as i64 * factor as i64) / divisor as i64) as isize
|
||||
+ }
|
||||
+
|
||||
pub fn ms(&self) -> isize {
|
||||
- if self.num_ticks.abs() < isize::MAX / 1000 {
|
||||
- (1000 * self.num_ticks) / self.clock_frequency.hz() as isize
|
||||
- } else {
|
||||
- 1000 * (self.num_ticks / self.clock_frequency.hz() as isize)
|
||||
- }
|
||||
+ ClockValue::scale_int(self.num_ticks, 1000, self.clock_frequency.hz() as isize)
|
||||
}
|
||||
|
||||
pub fn ms_f64(&self) -> f64 {
|
||||
1000.0 * (self.num_ticks as f64) / (self.clock_frequency.hz() as f64)
|
||||
}
|
||||
+
|
||||
+ pub fn wrapping_add(self, duration: Duration<isize>) -> ClockValue {
|
||||
+ // This is a precision preserving formula for scaling an isize.
|
||||
+ let duration_ticks =
|
||||
+ ClockValue::scale_int(duration.ms, self.clock_frequency.hz() as isize, 1000);
|
||||
+ ClockValue {
|
||||
+ num_ticks: self.num_ticks.wrapping_add(duration_ticks),
|
||||
+ clock_frequency: self.clock_frequency,
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ pub fn wrapping_sub(self, other: ClockValue) -> Option<Duration<isize>> {
|
||||
+ if self.clock_frequency == other.clock_frequency {
|
||||
+ let clock_duration = ClockValue {
|
||||
+ num_ticks: self.num_ticks - other.num_ticks,
|
||||
+ clock_frequency: self.clock_frequency,
|
||||
+ };
|
||||
+ Some(Duration::from_ms(clock_duration.ms()))
|
||||
+ } else {
|
||||
+ None
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
pub struct Alarm {
|
||||
@@ -1,13 +0,0 @@
|
||||
diff --git a/src/lib.rs b/src/lib.rs
|
||||
index 1d4f26b..c1483e9 100644
|
||||
--- a/src/lib.rs
|
||||
+++ b/src/lib.rs
|
||||
@@ -42,7 +42,7 @@ pub mod syscalls;
|
||||
|
||||
#[cfg(not(any(target_arch = "arm", target_arch = "riscv32")))]
|
||||
#[path = "syscalls_mock.rs"]
|
||||
-mod syscalls;
|
||||
+pub mod syscalls;
|
||||
|
||||
#[cfg(any(target_arch = "arm", target_arch = "riscv32"))]
|
||||
#[global_allocator]
|
||||
@@ -1,13 +0,0 @@
|
||||
diff --git a/src/entry_point.rs b/src/entry_point.rs
|
||||
index a24958c..e907e33 100644
|
||||
--- a/src/entry_point.rs
|
||||
+++ b/src/entry_point.rs
|
||||
@@ -348,7 +348,7 @@ pub unsafe extern "C" fn rust_start(app_start: usize, stacktop: usize, app_heap_
|
||||
// Heap size is set using `elf2tab` with `--app-heap` option, which is
|
||||
// currently at 1024. If you change the `elf2tab` heap size, make sure to
|
||||
// make the corresponding change here.
|
||||
- const HEAP_SIZE: usize = 1024;
|
||||
+ const HEAP_SIZE: usize = 90000;
|
||||
|
||||
// we could have also bss_end for app_heap_start
|
||||
let app_heap_start = app_heap_break;
|
||||
@@ -1,77 +0,0 @@
|
||||
diff --git a/Cargo.toml b/Cargo.toml
|
||||
index 844e424..386a9ed 100644
|
||||
--- a/Cargo.toml
|
||||
+++ b/Cargo.toml
|
||||
@@ -6,7 +6,7 @@ license = "MIT/Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
-linked_list_allocator = "0.6.6"
|
||||
+linked_list_allocator = { version = "0.6.6", default-features = false }
|
||||
|
||||
[features]
|
||||
panic_console = []
|
||||
diff --git a/src/entry_point.rs b/src/entry_point.rs
|
||||
index 15e1d03..2fe5c40 100644
|
||||
--- a/src/entry_point.rs
|
||||
+++ b/src/entry_point.rs
|
||||
@@ -1,8 +1,10 @@
|
||||
use crate::memop;
|
||||
use crate::syscalls;
|
||||
-use crate::ALLOCATOR;
|
||||
+use core::alloc::{GlobalAlloc, Layout};
|
||||
use core::intrinsics;
|
||||
use core::ptr;
|
||||
+use core::ptr::NonNull;
|
||||
+use linked_list_allocator::Heap;
|
||||
|
||||
// _start and rust_start are the first two procedures executed when a Tock
|
||||
// application starts. _start is invoked directly by the Tock kernel; it
|
||||
@@ -357,7 +359,7 @@ pub unsafe extern "C" fn rust_start(app_start: usize, stacktop: usize, app_heap_
|
||||
// Tell the kernel the new app heap break.
|
||||
memop::set_brk(app_heap_end as *const u8);
|
||||
|
||||
- ALLOCATOR.lock().init(app_heap_start, HEAP_SIZE);
|
||||
+ HEAP.init(app_heap_start, HEAP_SIZE);
|
||||
|
||||
main(0, ptr::null());
|
||||
|
||||
@@ -365,3 +367,23 @@ pub unsafe extern "C" fn rust_start(app_start: usize, stacktop: usize, app_heap_
|
||||
syscalls::yieldk();
|
||||
}
|
||||
}
|
||||
+
|
||||
+#[cfg(any(target_arch = "arm", target_arch = "riscv32"))]
|
||||
+#[global_allocator]
|
||||
+static ALLOCATOR: TockAllocator = TockAllocator;
|
||||
+
|
||||
+static mut HEAP: Heap = Heap::empty();
|
||||
+
|
||||
+struct TockAllocator;
|
||||
+
|
||||
+unsafe impl GlobalAlloc for TockAllocator {
|
||||
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
+ HEAP.allocate_first_fit(layout)
|
||||
+ .ok()
|
||||
+ .map_or(0 as *mut u8, |allocation| allocation.as_ptr())
|
||||
+ }
|
||||
+
|
||||
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
+ HEAP.deallocate(NonNull::new_unchecked(ptr), layout)
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/lib.rs b/src/lib.rs
|
||||
index c9001bf..2f9c1c0 100644
|
||||
--- a/src/lib.rs
|
||||
+++ b/src/lib.rs
|
||||
@@ -44,10 +44,6 @@ pub mod syscalls;
|
||||
#[path = "syscalls_mock.rs"]
|
||||
pub mod syscalls;
|
||||
|
||||
-#[cfg(any(target_arch = "arm", target_arch = "riscv32"))]
|
||||
-#[global_allocator]
|
||||
-static ALLOCATOR: linked_list_allocator::LockedHeap = linked_list_allocator::LockedHeap::empty();
|
||||
-
|
||||
// Dummy structure to force importing the panic_handler and other no_std elements when nothing else
|
||||
// is imported.
|
||||
pub struct LibTock;
|
||||
@@ -1,103 +0,0 @@
|
||||
diff --git a/Cargo.toml b/Cargo.toml
|
||||
index 386a9ed..af3c5db 100644
|
||||
--- a/Cargo.toml
|
||||
+++ b/Cargo.toml
|
||||
@@ -10,6 +10,7 @@ linked_list_allocator = { version = "0.6.6", default-features = false }
|
||||
|
||||
[features]
|
||||
panic_console = []
|
||||
+debug_allocations = []
|
||||
|
||||
[dev-dependencies]
|
||||
corepack = { version = "0.4.0", default-features = false, features = ["alloc"] }
|
||||
diff --git a/src/entry_point.rs b/src/entry_point.rs
|
||||
index 2fe5c40..545d163 100644
|
||||
--- a/src/entry_point.rs
|
||||
+++ b/src/entry_point.rs
|
||||
@@ -368,22 +368,82 @@ pub unsafe extern "C" fn rust_start(app_start: usize, stacktop: usize, app_heap_
|
||||
}
|
||||
}
|
||||
|
||||
+#[cfg(feature = "debug_allocations")]
|
||||
+use core::fmt::Write;
|
||||
+#[cfg(feature = "debug_allocations")]
|
||||
+use core::sync::atomic;
|
||||
+#[cfg(feature = "debug_allocations")]
|
||||
+use core::sync::atomic::AtomicUsize;
|
||||
+
|
||||
#[cfg(any(target_arch = "arm", target_arch = "riscv32"))]
|
||||
#[global_allocator]
|
||||
-static ALLOCATOR: TockAllocator = TockAllocator;
|
||||
+static ALLOCATOR: TockAllocator = TockAllocator::new();
|
||||
|
||||
static mut HEAP: Heap = Heap::empty();
|
||||
|
||||
-struct TockAllocator;
|
||||
+// With the "debug_allocations" feature, we use `AtomicUsize` to store the
|
||||
+// statistics because:
|
||||
+// - it is `Sync`, so we can use it in a static object (the allocator),
|
||||
+// - it implements interior mutability, so we can use it in the allocator
|
||||
+// methods (that take an immutable `&self` reference).
|
||||
+struct TockAllocator {
|
||||
+ #[cfg(feature = "debug_allocations")]
|
||||
+ count: AtomicUsize,
|
||||
+ #[cfg(feature = "debug_allocations")]
|
||||
+ size: AtomicUsize,
|
||||
+}
|
||||
+
|
||||
+impl TockAllocator {
|
||||
+ const fn new() -> TockAllocator {
|
||||
+ TockAllocator {
|
||||
+ #[cfg(feature = "debug_allocations")]
|
||||
+ count: AtomicUsize::new(0),
|
||||
+ #[cfg(feature = "debug_allocations")]
|
||||
+ size: AtomicUsize::new(0),
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
|
||||
unsafe impl GlobalAlloc for TockAllocator {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
- HEAP.allocate_first_fit(layout)
|
||||
+ let ptr = HEAP
|
||||
+ .allocate_first_fit(layout)
|
||||
.ok()
|
||||
- .map_or(0 as *mut u8, |allocation| allocation.as_ptr())
|
||||
+ .map_or(ptr::null_mut(), NonNull::as_ptr);
|
||||
+ #[cfg(feature = "debug_allocations")]
|
||||
+ {
|
||||
+ self.count.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
+ self.size.fetch_add(layout.size(), atomic::Ordering::SeqCst);
|
||||
+ writeln!(
|
||||
+ crate::console::Console::new(),
|
||||
+ "alloc[{}, {}] = {:?} ({} ptrs, {} bytes)",
|
||||
+ layout.size(),
|
||||
+ layout.align(),
|
||||
+ ptr,
|
||||
+ self.count.load(atomic::Ordering::SeqCst),
|
||||
+ self.size.load(atomic::Ordering::SeqCst)
|
||||
+ )
|
||||
+ .unwrap();
|
||||
+ }
|
||||
+ ptr
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
+ #[cfg(feature = "debug_allocations")]
|
||||
+ {
|
||||
+ self.count.fetch_sub(1, atomic::Ordering::SeqCst);
|
||||
+ self.size.fetch_sub(layout.size(), atomic::Ordering::SeqCst);
|
||||
+ writeln!(
|
||||
+ crate::console::Console::new(),
|
||||
+ "dealloc[{}, {}] = {:?} ({} ptrs, {} bytes)",
|
||||
+ layout.size(),
|
||||
+ layout.align(),
|
||||
+ ptr,
|
||||
+ self.count.load(atomic::Ordering::SeqCst),
|
||||
+ self.size.load(atomic::Ordering::SeqCst)
|
||||
+ )
|
||||
+ .unwrap();
|
||||
+ }
|
||||
HEAP.deallocate(NonNull::new_unchecked(ptr), layout)
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
diff --git a/src/console.rs b/src/console.rs
|
||||
index ecd7ad1..ae1b826 100644
|
||||
--- a/src/console.rs
|
||||
+++ b/src/console.rs
|
||||
@@ -16,33 +16,63 @@ mod allow_nr {
|
||||
pub const SHARE_BUFFER: usize = 1;
|
||||
}
|
||||
|
||||
+const BUFFER_SIZE: usize = 1024;
|
||||
+
|
||||
pub struct Console {
|
||||
- allow_buffer: [u8; 64],
|
||||
+ allow_buffer: [u8; BUFFER_SIZE],
|
||||
+ count_pending: usize,
|
||||
}
|
||||
|
||||
impl Console {
|
||||
pub fn new() -> Console {
|
||||
Console {
|
||||
- allow_buffer: [0; 64],
|
||||
+ allow_buffer: [0; BUFFER_SIZE],
|
||||
+ count_pending: 0,
|
||||
}
|
||||
}
|
||||
|
||||
+ fn is_empty(&self) -> bool {
|
||||
+ self.count_pending == 0
|
||||
+ }
|
||||
+
|
||||
+ fn is_full(&self) -> bool {
|
||||
+ self.allow_buffer.len() == self.count_pending
|
||||
+ }
|
||||
+
|
||||
+ fn available_len(&self) -> usize {
|
||||
+ self.allow_buffer.len() - self.count_pending
|
||||
+ }
|
||||
+
|
||||
pub fn write<S: AsRef<[u8]>>(&mut self, text: S) {
|
||||
let mut not_written_yet = text.as_ref();
|
||||
while !not_written_yet.is_empty() {
|
||||
- let num_bytes_to_print = self.allow_buffer.len().min(not_written_yet.len());
|
||||
- self.allow_buffer[..num_bytes_to_print]
|
||||
+ let num_bytes_to_print = self.available_len().min(not_written_yet.len());
|
||||
+ self.allow_buffer[self.count_pending..(self.count_pending + num_bytes_to_print)]
|
||||
.copy_from_slice(¬_written_yet[..num_bytes_to_print]);
|
||||
- self.flush(num_bytes_to_print);
|
||||
+ self.count_pending += num_bytes_to_print;
|
||||
+
|
||||
+ if self.is_full() {
|
||||
+ self.flush();
|
||||
+ }
|
||||
+
|
||||
not_written_yet = ¬_written_yet[num_bytes_to_print..];
|
||||
}
|
||||
}
|
||||
|
||||
- fn flush(&mut self, num_bytes_to_print: usize) {
|
||||
+ pub fn flush(&mut self) {
|
||||
+ if self.is_empty() {
|
||||
+ // Don't trigger any syscall if the buffer is empty.
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ let count = self.count_pending;
|
||||
+ // Clear the buffer even in case of error, to avoid an infinite loop.
|
||||
+ self.count_pending = 0;
|
||||
+
|
||||
let result = syscalls::allow(
|
||||
DRIVER_NUMBER,
|
||||
allow_nr::SHARE_BUFFER,
|
||||
- &mut self.allow_buffer[..num_bytes_to_print],
|
||||
+ &mut self.allow_buffer[..count],
|
||||
);
|
||||
if result.is_err() {
|
||||
return;
|
||||
@@ -59,8 +89,7 @@ impl Console {
|
||||
return;
|
||||
}
|
||||
|
||||
- let result_code =
|
||||
- unsafe { syscalls::command(DRIVER_NUMBER, command_nr::WRITE, num_bytes_to_print, 0) };
|
||||
+ let result_code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::WRITE, count, 0) };
|
||||
if result_code < 0 {
|
||||
return;
|
||||
}
|
||||
@@ -69,6 +98,12 @@ impl Console {
|
||||
}
|
||||
}
|
||||
|
||||
+impl Drop for Console {
|
||||
+ fn drop(&mut self) {
|
||||
+ self.flush();
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
impl fmt::Write for Console {
|
||||
fn write_str(&mut self, string: &str) -> Result<(), fmt::Error> {
|
||||
self.write(string);
|
||||
@@ -1,9 +1,9 @@
|
||||
0b54df6d548849e24d67b9b022ca09cb33c51f078ce85d0c9c4635ffc69902e1 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840dk.bin
|
||||
949d005f9a356a031dcb0a92a703c87377489ca66869dda490d9a687c77dd723 target/nrf52840dk_merged.hex
|
||||
052eec0ae526038352b9f7573468d0cf7fb5ec331d4dc1a2df75fdbd514ea5ca third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin
|
||||
fbf5e36aa4c71a77af5d04392faf29fd6491f0597f0fa35e6c0edeb5d3c8ad26 target/nrf52840_dongle_merged.hex
|
||||
908d7f4f40936d968b91ab6e19b2406612fe8c2c273d9c0b71ef1f55116780e0 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle_dfu.bin
|
||||
1ad0c691e8c0b4df8051f0738502e34cb9dd57d449d0c01f050dae577746c3ac target/nrf52840_dongle_dfu_merged.hex
|
||||
34ecbecaebf1188277f2310fe769c8c60310d8576493242712854deb4ba1036e third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_mdk_dfu.bin
|
||||
2e0bdaf152933e7bca99c2c13e13bb14da26e71e0845e09bf97d611df34768c3 target/nrf52840_mdk_dfu_merged.hex
|
||||
6f72b3e5c35c3d73c7274b0736c4969e2bd566c77815a8e7cdd407d9edb67180 target/tab/ctap2.tab
|
||||
91a98f475cb3042dd5184598a8292edb2a414df8d967a35c8f2295826b5a161b third_party/tock/target/thumbv7em-none-eabi/release/nrf52840dk.bin
|
||||
33164f39a0b5354cdf61236c301242476284c6b96d55275aa603734054ca7928 target/nrf52840dk_merged.hex
|
||||
a5943c5311158b0f99370246d37782eb9b12fc36c56387eadb6587a3a4fe8fd5 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin
|
||||
1232b44947f302900291692690f2e94cdfb165e00e74c682433100882754a516 target/nrf52840_dongle_merged.hex
|
||||
663297e3e29b9e2a972b68cea1592aaf965d797242579bb5bca09cd73cdfb637 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle_dfu.bin
|
||||
b95ce848465523e98cf0c30f94f6430e99dc8ac4b33da5bc0d0f643523ff4b50 target/nrf52840_dongle_dfu_merged.hex
|
||||
162a05d056aafc16d4868d5c3aa10518e41299dddd60608f96954dc9cf964cd3 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_mdk_dfu.bin
|
||||
1085e1789c4429430c47d28b23a975223717eddd7c8aa23114acbc3ec2ec7080 target/nrf52840_mdk_dfu_merged.hex
|
||||
5bd063ce44e9ddcad8c4d17165a247387e4f1a9c6db81060fbb97244be1929b8 target/tab/ctap2.tab
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
29382e72d0f3c6a72ce9517211952ff29ea270193d7f0ddc48ca69009ee29925 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840dk.bin
|
||||
2c0bdb663edc88ae168ecd12b71730ab26bdc6d23b9fa832acc63cc4c91461ac target/nrf52840dk_merged.hex
|
||||
30f239390ae9bef0825731e4c82d40470fc5e9bded2bf0d942e92dbb5d4faba1 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin
|
||||
81564eab5c20f186c0583e0a31f26fcc50ec0ebd997bff6109e663cbb7d59966 target/nrf52840_dongle_merged.hex
|
||||
e3acf15d5ae3a22aecff6cc58db5fc311f538f47328d348b7ad7db7f9ab5e72c third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle_dfu.bin
|
||||
25b10d9d80d4961ea0d8373d64e883279baeff6997eb8e541d36930ec423b88b target/nrf52840_dongle_dfu_merged.hex
|
||||
cae312a26a513ada6c198fdc59b2bba3860c51726b817a9fd17a4331ee12c882 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_mdk_dfu.bin
|
||||
1077f1acf2c0d65eeda2056d907ee449bfbf7f783c253c1f92838f7ac5e11d99 target/nrf52840_mdk_dfu_merged.hex
|
||||
3c8dc97b68c5ce5030f0af3879c5f9531d69ea1404899e9dfe306d02d638e0cc target/tab/ctap2.tab
|
||||
3feb5d29a3d669107b460a00391440be4ebc5e50461f9ef3248714f4f99c070e third_party/tock/target/thumbv7em-none-eabi/release/nrf52840dk.bin
|
||||
a02f078e165373113adbaf7fa5d272e7e01134061e8212331d54f0b0a8809aaa target/nrf52840dk_merged.hex
|
||||
8eebe1c1dfe22003466c2570b3735c54c58ae91b8168582ad363ab79c9230a15 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin
|
||||
973bf7d0b6ddb37bb9698cf8f2ef3c2a3dd27cd482b7a4c02e452902394ffa37 target/nrf52840_dongle_merged.hex
|
||||
779d77071d1e629f92210ac313e230bcaea6d77c710210c1ac4b40f8085cdad7 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle_dfu.bin
|
||||
d0e7ecc1d2a45ef4c77b39720b95b3e349a0d48d7b9ca99fa591019a9f2cafee target/nrf52840_dongle_dfu_merged.hex
|
||||
f466490d6498f6c06c7c4a717eb437ba2fb06d1985532c23f145d38b9daa8259 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_mdk_dfu.bin
|
||||
d3d4a9d3442bb8cf924f553f8df7085e3d6331f1b6d9557115d485e584285d68 target/nrf52840_mdk_dfu_merged.hex
|
||||
6cda1346503867ef18d3fe7a3d32de6e22585c6134ef3347877894c5469390f5 target/tab/ctap2.tab
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
========================================
|
||||
Board: nrf52840dk
|
||||
----------------------------------------
|
||||
Min RAM size from sections in ELF: 16 bytes
|
||||
Min RAM size from sections in ELF: 20 bytes
|
||||
Number of writeable flash regions: 0
|
||||
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
||||
Entry point is in .text section
|
||||
Adding .text section. Offset: 128 (0x80). Length: 175972 (0x2af64) bytes.
|
||||
Adding .stack section. Offset: 176100 (0x2afe4). Length: 16384 (0x4000) bytes.
|
||||
Adding .text section. Offset: 128 (0x80). Length: 187792 (0x2dd90) bytes.
|
||||
Adding .stack section. Offset: 187920 (0x2de10). Length: 16384 (0x4000) bytes.
|
||||
Searching for .rel.X sections to add.
|
||||
TBF Header:
|
||||
version: 2 0x2
|
||||
@@ -16,16 +16,16 @@ TBF Header:
|
||||
|
||||
init_fn_offset: 85 0x55
|
||||
protected_size: 20 0x14
|
||||
minimum_ram_size: 107424 0x1A3A0
|
||||
minimum_ram_size: 107428 0x1A3A4
|
||||
========================================
|
||||
Board: nrf52840_dongle
|
||||
----------------------------------------
|
||||
Min RAM size from sections in ELF: 16 bytes
|
||||
Min RAM size from sections in ELF: 20 bytes
|
||||
Number of writeable flash regions: 0
|
||||
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
||||
Entry point is in .text section
|
||||
Adding .text section. Offset: 128 (0x80). Length: 175972 (0x2af64) bytes.
|
||||
Adding .stack section. Offset: 176100 (0x2afe4). Length: 16384 (0x4000) bytes.
|
||||
Adding .text section. Offset: 128 (0x80). Length: 187792 (0x2dd90) bytes.
|
||||
Adding .stack section. Offset: 187920 (0x2de10). Length: 16384 (0x4000) bytes.
|
||||
Searching for .rel.X sections to add.
|
||||
TBF Header:
|
||||
version: 2 0x2
|
||||
@@ -35,16 +35,16 @@ TBF Header:
|
||||
|
||||
init_fn_offset: 85 0x55
|
||||
protected_size: 20 0x14
|
||||
minimum_ram_size: 107424 0x1A3A0
|
||||
minimum_ram_size: 107428 0x1A3A4
|
||||
========================================
|
||||
Board: nrf52840_dongle_dfu
|
||||
----------------------------------------
|
||||
Min RAM size from sections in ELF: 16 bytes
|
||||
Min RAM size from sections in ELF: 20 bytes
|
||||
Number of writeable flash regions: 0
|
||||
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
||||
Entry point is in .text section
|
||||
Adding .text section. Offset: 128 (0x80). Length: 175972 (0x2af64) bytes.
|
||||
Adding .stack section. Offset: 176100 (0x2afe4). Length: 16384 (0x4000) bytes.
|
||||
Adding .text section. Offset: 128 (0x80). Length: 187792 (0x2dd90) bytes.
|
||||
Adding .stack section. Offset: 187920 (0x2de10). Length: 16384 (0x4000) bytes.
|
||||
Searching for .rel.X sections to add.
|
||||
TBF Header:
|
||||
version: 2 0x2
|
||||
@@ -54,16 +54,16 @@ TBF Header:
|
||||
|
||||
init_fn_offset: 85 0x55
|
||||
protected_size: 20 0x14
|
||||
minimum_ram_size: 107424 0x1A3A0
|
||||
minimum_ram_size: 107428 0x1A3A4
|
||||
========================================
|
||||
Board: nrf52840_mdk_dfu
|
||||
----------------------------------------
|
||||
Min RAM size from sections in ELF: 16 bytes
|
||||
Min RAM size from sections in ELF: 20 bytes
|
||||
Number of writeable flash regions: 0
|
||||
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
||||
Entry point is in .text section
|
||||
Adding .text section. Offset: 128 (0x80). Length: 175972 (0x2af64) bytes.
|
||||
Adding .stack section. Offset: 176100 (0x2afe4). Length: 16384 (0x4000) bytes.
|
||||
Adding .text section. Offset: 128 (0x80). Length: 187792 (0x2dd90) bytes.
|
||||
Adding .stack section. Offset: 187920 (0x2de10). Length: 16384 (0x4000) bytes.
|
||||
Searching for .rel.X sections to add.
|
||||
TBF Header:
|
||||
version: 2 0x2
|
||||
@@ -73,4 +73,4 @@ TBF Header:
|
||||
|
||||
init_fn_offset: 85 0x55
|
||||
protected_size: 20 0x14
|
||||
minimum_ram_size: 107424 0x1A3A0
|
||||
minimum_ram_size: 107428 0x1A3A4
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
========================================
|
||||
Board: nrf52840dk
|
||||
----------------------------------------
|
||||
Min RAM size from sections in ELF: 16 bytes
|
||||
Min RAM size from sections in ELF: 20 bytes
|
||||
Number of writeable flash regions: 0
|
||||
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
||||
Entry point is in .text section
|
||||
Adding .text section. Offset: 128 (0x80). Length: 176516 (0x2b184) bytes.
|
||||
Adding .stack section. Offset: 176644 (0x2b204). Length: 16384 (0x4000) bytes.
|
||||
Adding .text section. Offset: 128 (0x80). Length: 187736 (0x2dd58) bytes.
|
||||
Adding .stack section. Offset: 187864 (0x2ddd8). Length: 16384 (0x4000) bytes.
|
||||
Searching for .rel.X sections to add.
|
||||
TBF Header:
|
||||
version: 2 0x2
|
||||
@@ -16,16 +16,16 @@ TBF Header:
|
||||
|
||||
init_fn_offset: 85 0x55
|
||||
protected_size: 20 0x14
|
||||
minimum_ram_size: 107424 0x1A3A0
|
||||
minimum_ram_size: 107428 0x1A3A4
|
||||
========================================
|
||||
Board: nrf52840_dongle
|
||||
----------------------------------------
|
||||
Min RAM size from sections in ELF: 16 bytes
|
||||
Min RAM size from sections in ELF: 20 bytes
|
||||
Number of writeable flash regions: 0
|
||||
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
||||
Entry point is in .text section
|
||||
Adding .text section. Offset: 128 (0x80). Length: 176516 (0x2b184) bytes.
|
||||
Adding .stack section. Offset: 176644 (0x2b204). Length: 16384 (0x4000) bytes.
|
||||
Adding .text section. Offset: 128 (0x80). Length: 187736 (0x2dd58) bytes.
|
||||
Adding .stack section. Offset: 187864 (0x2ddd8). Length: 16384 (0x4000) bytes.
|
||||
Searching for .rel.X sections to add.
|
||||
TBF Header:
|
||||
version: 2 0x2
|
||||
@@ -35,16 +35,16 @@ TBF Header:
|
||||
|
||||
init_fn_offset: 85 0x55
|
||||
protected_size: 20 0x14
|
||||
minimum_ram_size: 107424 0x1A3A0
|
||||
minimum_ram_size: 107428 0x1A3A4
|
||||
========================================
|
||||
Board: nrf52840_dongle_dfu
|
||||
----------------------------------------
|
||||
Min RAM size from sections in ELF: 16 bytes
|
||||
Min RAM size from sections in ELF: 20 bytes
|
||||
Number of writeable flash regions: 0
|
||||
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
||||
Entry point is in .text section
|
||||
Adding .text section. Offset: 128 (0x80). Length: 176516 (0x2b184) bytes.
|
||||
Adding .stack section. Offset: 176644 (0x2b204). Length: 16384 (0x4000) bytes.
|
||||
Adding .text section. Offset: 128 (0x80). Length: 187736 (0x2dd58) bytes.
|
||||
Adding .stack section. Offset: 187864 (0x2ddd8). Length: 16384 (0x4000) bytes.
|
||||
Searching for .rel.X sections to add.
|
||||
TBF Header:
|
||||
version: 2 0x2
|
||||
@@ -54,16 +54,16 @@ TBF Header:
|
||||
|
||||
init_fn_offset: 85 0x55
|
||||
protected_size: 20 0x14
|
||||
minimum_ram_size: 107424 0x1A3A0
|
||||
minimum_ram_size: 107428 0x1A3A4
|
||||
========================================
|
||||
Board: nrf52840_mdk_dfu
|
||||
----------------------------------------
|
||||
Min RAM size from sections in ELF: 16 bytes
|
||||
Min RAM size from sections in ELF: 20 bytes
|
||||
Number of writeable flash regions: 0
|
||||
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
||||
Entry point is in .text section
|
||||
Adding .text section. Offset: 128 (0x80). Length: 176516 (0x2b184) bytes.
|
||||
Adding .stack section. Offset: 176644 (0x2b204). Length: 16384 (0x4000) bytes.
|
||||
Adding .text section. Offset: 128 (0x80). Length: 187736 (0x2dd58) bytes.
|
||||
Adding .stack section. Offset: 187864 (0x2ddd8). Length: 16384 (0x4000) bytes.
|
||||
Searching for .rel.X sections to add.
|
||||
TBF Header:
|
||||
version: 2 0x2
|
||||
@@ -73,4 +73,4 @@ TBF Header:
|
||||
|
||||
init_fn_offset: 85 0x55
|
||||
protected_size: 20 0x14
|
||||
minimum_ram_size: 107424 0x1A3A0
|
||||
minimum_ram_size: 107428 0x1A3A4
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
nightly-2020-02-03
|
||||
1
rust-toolchain
Symbolic link
1
rust-toolchain
Symbolic link
@@ -0,0 +1 @@
|
||||
third_party/libtock-rs/rust-toolchain
|
||||
74
setup-submodules.sh
Executable file
74
setup-submodules.sh
Executable file
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Ensure the script doesn't fail on Github workflows
|
||||
export TERM=${TERM:-vt100}
|
||||
done_text="$(tput bold)DONE.$(tput sgr0)"
|
||||
|
||||
set -e
|
||||
|
||||
# Ensure the submodules are pulled and up-to-date
|
||||
git submodule update --init
|
||||
|
||||
patch_conflict_detected () {
|
||||
cat <<EOF
|
||||
|
||||
This script cannot be run twice without reverting the patches.
|
||||
|
||||
To do so, follow these instructions:
|
||||
1. Commit any changes you want to save.
|
||||
2. Run the ./reset.sh script to revert all uncommitted changes.
|
||||
3. Run the ./setup.sh script again.
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Copy additional boards to the kernel.
|
||||
echo -n '[-] Copying additional boards to Tock... '
|
||||
cp -r boards/* third_party/tock/boards
|
||||
echo $done_text
|
||||
|
||||
# Apply patches to kernel. Do that in a sub-shell.
|
||||
(
|
||||
cd third_party/tock/ && \
|
||||
for p in ../../patches/tock/[0-9][0-9]-*.patch
|
||||
do
|
||||
echo -n '[-] Applying patch "'$(basename $p)'"... '
|
||||
if git apply "$p"
|
||||
then
|
||||
echo $done_text
|
||||
else
|
||||
patch_conflict_detected
|
||||
fi
|
||||
done
|
||||
)
|
||||
|
||||
# Now apply patches to libtock-rs. Do that in a sub-shell.
|
||||
#
|
||||
# Commented out as there are not patches at the moment, and the pattern fails in
|
||||
# that case.
|
||||
#(
|
||||
# cd third_party/libtock-rs/ && \
|
||||
# for p in ../../patches/libtock-rs/[0-9][0-9]-*.patch
|
||||
# do
|
||||
# echo -n '[-] Applying patch "'$(basename $p)'"... '
|
||||
# if git apply "$p"
|
||||
# then
|
||||
# echo $done_text
|
||||
# else
|
||||
# patch_conflict_detected
|
||||
# fi
|
||||
# done
|
||||
#)
|
||||
56
setup.sh
56
setup.sh
@@ -19,6 +19,9 @@ done_text="$(tput bold)DONE.$(tput sgr0)"
|
||||
|
||||
set -e
|
||||
|
||||
# Ensure the submodules are pulled and up-to-date, and apply patches
|
||||
./setup-submodules.sh
|
||||
|
||||
# Check that rustup and pip3 are installed
|
||||
check_command () {
|
||||
if ! which "$1" >/dev/null
|
||||
@@ -30,63 +33,12 @@ check_command () {
|
||||
check_command rustup " Follow the steps under https://rustup.rs/ to install it."
|
||||
check_command pip3
|
||||
|
||||
# Ensure the submodules are pulled and up-to-date
|
||||
git submodule update --init
|
||||
|
||||
patch_conflict_detected () {
|
||||
cat <<EOF
|
||||
|
||||
This script cannot be run twice without reverting the patches.
|
||||
|
||||
To do so, follow these instructions:
|
||||
1. Commit any changes you want to save.
|
||||
2. Run the ./reset.sh script to revert all uncommitted changes.
|
||||
3. Run the ./setup.sh script again.
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Copy additional boards to the kernel.
|
||||
echo -n '[-] Copying additional boards to Tock... '
|
||||
cp -r boards/* third_party/tock/boards
|
||||
echo $done_text
|
||||
|
||||
# Apply patches to kernel. Do that in a sub-shell
|
||||
(
|
||||
cd third_party/tock/ && \
|
||||
for p in ../../patches/tock/[0-9][0-9]-*.patch
|
||||
do
|
||||
echo -n '[-] Applying patch "'$(basename $p)'"... '
|
||||
if git apply "$p"
|
||||
then
|
||||
echo $done_text
|
||||
else
|
||||
patch_conflict_detected
|
||||
fi
|
||||
done
|
||||
)
|
||||
|
||||
# Now apply patches to libtock-rs. Do that in a sub-shell
|
||||
(
|
||||
cd third_party/libtock-rs/ && \
|
||||
for p in ../../patches/libtock-rs/[0-9][0-9]-*.patch
|
||||
do
|
||||
echo -n '[-] Applying patch "'$(basename $p)'"... '
|
||||
if git apply "$p"
|
||||
then
|
||||
echo $done_text
|
||||
else
|
||||
patch_conflict_detected
|
||||
fi
|
||||
done
|
||||
)
|
||||
|
||||
# Ensure we have certificates, keys, etc. so that the tests can run
|
||||
source tools/gen_key_materials.sh
|
||||
generate_crypto_materials N
|
||||
|
||||
rustup install $(head -n 1 rust-toolchain)
|
||||
pip3 install --user --upgrade 'tockloader==1.4' six intelhex
|
||||
pip3 install --user --upgrade 'tockloader==1.5' six intelhex
|
||||
rustup target add thumbv7em-none-eabi
|
||||
|
||||
# Install dependency to create applications.
|
||||
|
||||
@@ -28,7 +28,7 @@ use alloc::vec::Vec;
|
||||
use core::fmt::Write;
|
||||
use crypto::rng256::Rng256;
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
use libtock::console::Console;
|
||||
use libtock_drivers::console::Console;
|
||||
|
||||
// CTAP specification (version 20190130) section 8.1
|
||||
// TODO: Channel allocation, section 8.1.3?
|
||||
|
||||
@@ -61,8 +61,8 @@ use crypto::rng256::Rng256;
|
||||
use crypto::sha256::Sha256;
|
||||
use crypto::Hash256;
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
use libtock::console::Console;
|
||||
use libtock::timer::{Duration, Timestamp};
|
||||
use libtock_drivers::console::Console;
|
||||
use libtock_drivers::timer::{Duration, Timestamp};
|
||||
|
||||
// This flag enables or disables basic attestation for FIDO2. U2F is unaffected by
|
||||
// this setting. The basic attestation uses the signing key from key_material.rs
|
||||
@@ -688,7 +688,7 @@ where
|
||||
key_id: credential.credential_id.clone(),
|
||||
transports: None, // You can set USB as a hint here.
|
||||
};
|
||||
let user = if flags & UV_FLAG != 0 {
|
||||
let user = if (flags & UV_FLAG != 0) && (credential.user_handle.len() > 0) {
|
||||
Some(PublicKeyCredentialUserEntity {
|
||||
user_id: credential.user_handle.clone(),
|
||||
user_name: None,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
use super::{Index, Storage, StorageError, StorageResult};
|
||||
use alloc::vec::Vec;
|
||||
use libtock::syscalls;
|
||||
use libtock_core::syscalls;
|
||||
|
||||
const DRIVER_NUMBER: usize = 0x50003;
|
||||
|
||||
@@ -41,16 +41,14 @@ mod memop_nr {
|
||||
}
|
||||
|
||||
fn get_info(nr: usize, arg: usize) -> StorageResult<usize> {
|
||||
let code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::GET_INFO, nr, arg) };
|
||||
if code < 0 {
|
||||
Err(StorageError::KernelError { code })
|
||||
} else {
|
||||
Ok(code as usize)
|
||||
}
|
||||
let code = syscalls::command(DRIVER_NUMBER, command_nr::GET_INFO, nr, arg);
|
||||
code.map_err(|e| StorageError::KernelError {
|
||||
code: e.return_code,
|
||||
})
|
||||
}
|
||||
|
||||
fn memop(nr: u32, arg: usize) -> StorageResult<usize> {
|
||||
let code = unsafe { syscalls::memop(nr, arg) };
|
||||
let code = unsafe { syscalls::raw::memop(nr, arg) };
|
||||
if code < 0 {
|
||||
Err(StorageError::KernelError { code })
|
||||
} else {
|
||||
@@ -153,8 +151,9 @@ impl Storage for SyscallStorage {
|
||||
return Err(StorageError::NotAligned);
|
||||
}
|
||||
let ptr = self.read_slice(index, value.len())?.as_ptr() as usize;
|
||||
|
||||
let code = unsafe {
|
||||
syscalls::allow_ptr(
|
||||
syscalls::raw::allow(
|
||||
DRIVER_NUMBER,
|
||||
allow_nr::WRITE_SLICE,
|
||||
// We rely on the driver not writing to the slice. This should use read-only allow
|
||||
@@ -166,11 +165,14 @@ impl Storage for SyscallStorage {
|
||||
if code < 0 {
|
||||
return Err(StorageError::KernelError { code });
|
||||
}
|
||||
let code =
|
||||
unsafe { syscalls::command(DRIVER_NUMBER, command_nr::WRITE_SLICE, ptr, value.len()) };
|
||||
if code < 0 {
|
||||
return Err(StorageError::KernelError { code });
|
||||
|
||||
let code = syscalls::command(DRIVER_NUMBER, command_nr::WRITE_SLICE, ptr, value.len());
|
||||
if let Err(e) = code {
|
||||
return Err(StorageError::KernelError {
|
||||
code: e.return_code,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -178,9 +180,11 @@ impl Storage for SyscallStorage {
|
||||
let index = Index { page, byte: 0 };
|
||||
let length = self.page_size();
|
||||
let ptr = self.read_slice(index, length)?.as_ptr() as usize;
|
||||
let code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::ERASE_PAGE, ptr, length) };
|
||||
if code < 0 {
|
||||
return Err(StorageError::KernelError { code });
|
||||
let code = syscalls::command(DRIVER_NUMBER, command_nr::ERASE_PAGE, ptr, length);
|
||||
if let Err(e) = code {
|
||||
return Err(StorageError::KernelError {
|
||||
code: e.return_code,
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
extern crate libtock;
|
||||
extern crate lang_items;
|
||||
extern crate libtock_core;
|
||||
extern crate libtock_drivers;
|
||||
|
||||
pub mod embedded_flash;
|
||||
|
||||
85
src/main.rs
85
src/main.rs
@@ -22,14 +22,12 @@ extern crate byteorder;
|
||||
#[cfg(feature = "std")]
|
||||
extern crate core;
|
||||
extern crate ctap2;
|
||||
extern crate libtock;
|
||||
extern crate subtle;
|
||||
#[macro_use]
|
||||
extern crate cbor;
|
||||
extern crate crypto;
|
||||
|
||||
mod ctap;
|
||||
mod usb_ctap_hid;
|
||||
|
||||
use core::cell::Cell;
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
@@ -38,17 +36,18 @@ use crypto::rng256::TockRng256;
|
||||
use ctap::hid::{ChannelID, CtapHid, KeepaliveStatus, ProcessedPacket};
|
||||
use ctap::status_code::Ctap2StatusCode;
|
||||
use ctap::CtapState;
|
||||
use libtock::buttons;
|
||||
use libtock::buttons::ButtonState;
|
||||
use libtock_core::result::{CommandError, EALREADY};
|
||||
use libtock_drivers::buttons;
|
||||
use libtock_drivers::buttons::ButtonState;
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
use libtock::console::Console;
|
||||
use libtock::led;
|
||||
use libtock::result::TockValue;
|
||||
use libtock::syscalls;
|
||||
use libtock::timer;
|
||||
use libtock_drivers::console::Console;
|
||||
use libtock_drivers::led;
|
||||
use libtock_drivers::result::{FlexUnwrap, TockError};
|
||||
use libtock_drivers::timer;
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
use libtock::timer::Timer;
|
||||
use libtock::timer::{Duration, StopAlarmError, Timestamp};
|
||||
use libtock_drivers::timer::Timer;
|
||||
use libtock_drivers::timer::{Duration, Timestamp};
|
||||
use libtock_drivers::usb_ctap_hid;
|
||||
|
||||
const KEEPALIVE_DELAY_MS: isize = 100;
|
||||
const KEEPALIVE_DELAY: Duration<isize> = Duration::from_ms(KEEPALIVE_DELAY_MS);
|
||||
@@ -58,7 +57,7 @@ fn main() {
|
||||
// Setup the timer with a dummy callback (we only care about reading the current time, but the
|
||||
// API forces us to set an alarm callback too).
|
||||
let mut with_callback = timer::with_callback(|_, _| {});
|
||||
let timer = with_callback.init().unwrap();
|
||||
let timer = with_callback.init().flex_unwrap();
|
||||
|
||||
// Setup USB driver.
|
||||
if !usb_ctap_hid::setup() {
|
||||
@@ -70,7 +69,7 @@ fn main() {
|
||||
let mut ctap_hid = CtapHid::new();
|
||||
|
||||
let mut led_counter = 0;
|
||||
let mut last_led_increment = timer.get_current_clock();
|
||||
let mut last_led_increment = timer.get_current_clock().flex_unwrap();
|
||||
|
||||
// Main loop. If CTAP1 is used, we register button presses for U2F while receiving and waiting.
|
||||
// The way TockOS and apps currently interact, callbacks need a yield syscall to execute,
|
||||
@@ -87,11 +86,11 @@ fn main() {
|
||||
};
|
||||
});
|
||||
#[cfg(feature = "with_ctap1")]
|
||||
let mut buttons = buttons_callback.init().unwrap();
|
||||
let mut buttons = buttons_callback.init().flex_unwrap();
|
||||
#[cfg(feature = "with_ctap1")]
|
||||
// At the moment, all buttons are accepted. You can customize your setup here.
|
||||
for mut button in &mut buttons {
|
||||
button.enable().unwrap();
|
||||
button.enable().flex_unwrap();
|
||||
}
|
||||
|
||||
let mut pkt_request = [0; 64];
|
||||
@@ -105,7 +104,7 @@ fn main() {
|
||||
None => false,
|
||||
};
|
||||
|
||||
let now = timer.get_current_clock();
|
||||
let now = timer.get_current_clock().flex_unwrap();
|
||||
#[cfg(feature = "with_ctap1")]
|
||||
{
|
||||
if button_touched.get() {
|
||||
@@ -115,7 +114,7 @@ fn main() {
|
||||
// Heavy computation mostly follows a registered touch luckily. Unregistering
|
||||
// callbacks is important to not clash with those from check_user_presence.
|
||||
for mut button in &mut buttons {
|
||||
button.disable().unwrap();
|
||||
button.disable().flex_unwrap();
|
||||
}
|
||||
drop(buttons);
|
||||
drop(buttons_callback);
|
||||
@@ -153,7 +152,7 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let now = timer.get_current_clock();
|
||||
let now = timer.get_current_clock().flex_unwrap();
|
||||
if let Some(wait_duration) = now.wrapping_sub(last_led_increment) {
|
||||
if wait_duration > KEEPALIVE_DELAY {
|
||||
// Loops quickly when waiting for U2F user presence, so the next LED blink
|
||||
@@ -188,8 +187,8 @@ fn main() {
|
||||
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
fn print_packet_notice(notice_text: &str, timer: &Timer) {
|
||||
let now_us =
|
||||
(Timestamp::<f64>::from_clock_value(timer.get_current_clock()).ms() * 1000.0) as u64;
|
||||
let now = timer.get_current_clock().flex_unwrap();
|
||||
let now_us = (Timestamp::<f64>::from_clock_value(now).ms() * 1000.0) as u64;
|
||||
writeln!(
|
||||
Console::new(),
|
||||
"{} at {}.{:06} s",
|
||||
@@ -264,17 +263,17 @@ fn send_keepalive_up_needed(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn blink_leds(pattern_seed: isize) {
|
||||
for l in 0..led::count() {
|
||||
fn blink_leds(pattern_seed: usize) {
|
||||
for l in 0..led::count().flex_unwrap() {
|
||||
if (pattern_seed ^ l).count_ones() & 1 != 0 {
|
||||
led::get(l).unwrap().on();
|
||||
led::get(l).flex_unwrap().on().flex_unwrap();
|
||||
} else {
|
||||
led::get(l).unwrap().off();
|
||||
led::get(l).flex_unwrap().off().flex_unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn wink_leds(pattern_seed: isize) {
|
||||
fn wink_leds(pattern_seed: usize) {
|
||||
// This generates a "snake" pattern circling through the LEDs.
|
||||
// Fox example with 4 LEDs the sequence of lit LEDs will be the following.
|
||||
// 0 1 2 3
|
||||
@@ -287,7 +286,7 @@ fn wink_leds(pattern_seed: isize) {
|
||||
// * *
|
||||
// * * *
|
||||
// * *
|
||||
let count = led::count();
|
||||
let count = led::count().flex_unwrap();
|
||||
let a = (pattern_seed / 2) % count;
|
||||
let b = ((pattern_seed + 1) / 2) % count;
|
||||
let c = ((pattern_seed + 3) / 2) % count;
|
||||
@@ -300,22 +299,22 @@ fn wink_leds(pattern_seed: isize) {
|
||||
_ => l,
|
||||
};
|
||||
if k == a || k == b || k == c {
|
||||
led::get(l).unwrap().on();
|
||||
led::get(l).flex_unwrap().on().flex_unwrap();
|
||||
} else {
|
||||
led::get(l).unwrap().off();
|
||||
led::get(l).flex_unwrap().off().flex_unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn switch_off_leds() {
|
||||
for l in 0..led::count() {
|
||||
led::get(l).unwrap().off();
|
||||
for l in 0..led::count().flex_unwrap() {
|
||||
led::get(l).flex_unwrap().off().flex_unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn check_user_presence(cid: ChannelID) -> Result<(), Ctap2StatusCode> {
|
||||
// The timeout is N times the keepalive delay.
|
||||
const TIMEOUT_ITERATIONS: isize = ctap::TOUCH_TIMEOUT_MS / KEEPALIVE_DELAY_MS;
|
||||
const TIMEOUT_ITERATIONS: usize = ctap::TOUCH_TIMEOUT_MS as usize / KEEPALIVE_DELAY_MS as usize;
|
||||
|
||||
// First, send a keep-alive packet to notify that the keep-alive status has changed.
|
||||
send_keepalive_up_needed(cid, KEEPALIVE_DELAY)?;
|
||||
@@ -328,10 +327,10 @@ fn check_user_presence(cid: ChannelID) -> Result<(), Ctap2StatusCode> {
|
||||
ButtonState::Released => (),
|
||||
};
|
||||
});
|
||||
let mut buttons = buttons_callback.init().unwrap();
|
||||
let mut buttons = buttons_callback.init().flex_unwrap();
|
||||
// At the moment, all buttons are accepted. You can customize your setup here.
|
||||
for mut button in &mut buttons {
|
||||
button.enable().unwrap();
|
||||
button.enable().flex_unwrap();
|
||||
}
|
||||
|
||||
let mut keepalive_response = Ok(());
|
||||
@@ -343,19 +342,25 @@ fn check_user_presence(cid: ChannelID) -> Result<(), Ctap2StatusCode> {
|
||||
let mut keepalive_callback = timer::with_callback(|_, _| {
|
||||
keepalive_expired.set(true);
|
||||
});
|
||||
let mut keepalive = keepalive_callback.init().unwrap();
|
||||
let keepalive_alarm = keepalive.set_alarm(KEEPALIVE_DELAY).unwrap();
|
||||
let mut keepalive = keepalive_callback.init().flex_unwrap();
|
||||
let keepalive_alarm = keepalive.set_alarm(KEEPALIVE_DELAY).flex_unwrap();
|
||||
|
||||
// Wait for a button touch or an alarm.
|
||||
syscalls::yieldk_for(|| button_touched.get() || keepalive_expired.get());
|
||||
libtock_drivers::util::yieldk_for(|| button_touched.get() || keepalive_expired.get());
|
||||
|
||||
// Cleanup alarm callback.
|
||||
match keepalive.stop_alarm(keepalive_alarm) {
|
||||
Ok(()) => (),
|
||||
Err(TockValue::Expected(StopAlarmError::AlreadyDisabled)) => {
|
||||
assert!(keepalive_expired.get())
|
||||
Err(TockError::Command(CommandError {
|
||||
return_code: EALREADY,
|
||||
..
|
||||
})) => assert!(keepalive_expired.get()),
|
||||
Err(_e) => {
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
panic!("Unexpected error when stopping alarm: {:?}", _e);
|
||||
#[cfg(not(feature = "debug_ctap"))]
|
||||
panic!("Unexpected error when stopping alarm: <error is only visible with the debug_ctap feature>");
|
||||
}
|
||||
Err(e) => panic!("Unexpected error when stopping alarm: {:?}", e),
|
||||
}
|
||||
|
||||
// TODO: this may take arbitrary time. The keepalive_delay should be adjusted accordingly,
|
||||
@@ -374,7 +379,7 @@ fn check_user_presence(cid: ChannelID) -> Result<(), Ctap2StatusCode> {
|
||||
|
||||
// Cleanup button callbacks.
|
||||
for mut button in &mut buttons {
|
||||
button.disable().unwrap();
|
||||
button.disable().flex_unwrap();
|
||||
}
|
||||
|
||||
// Returns whether the user was present.
|
||||
|
||||
19
third_party/lang-items/Cargo.toml
vendored
Normal file
19
third_party/lang-items/Cargo.toml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "lang_items"
|
||||
version = "0.1.0"
|
||||
authors = [
|
||||
"Tock Project Developers <tock-dev@googlegroups.com>",
|
||||
"Guillaume Endignoux <guillaumee@google.com>",
|
||||
]
|
||||
license = "MIT/Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libtock_core = { path = "../../third_party/libtock-rs/core", default-features = false, features = ["alloc_init", "custom_panic_handler", "custom_alloc_error_handler"] }
|
||||
libtock_drivers = { path = "../libtock-drivers" }
|
||||
linked_list_allocator = { version = "0.8.1", default-features = false }
|
||||
|
||||
[features]
|
||||
debug_allocations = []
|
||||
panic_console = []
|
||||
std = []
|
||||
202
third_party/lang-items/LICENSE-APACHE
vendored
Normal file
202
third_party/lang-items/LICENSE-APACHE
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
25
third_party/lang-items/LICENSE-MIT
vendored
Normal file
25
third_party/lang-items/LICENSE-MIT
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2016 The Tock Project Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
109
third_party/lang-items/src/allocator.rs
vendored
Normal file
109
third_party/lang-items/src/allocator.rs
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
use crate::util;
|
||||
use core::alloc::GlobalAlloc;
|
||||
use core::alloc::Layout;
|
||||
#[cfg(any(feature = "debug_allocations", feature = "panic_console"))]
|
||||
use core::fmt::Write;
|
||||
use core::ptr;
|
||||
use core::ptr::NonNull;
|
||||
#[cfg(feature = "debug_allocations")]
|
||||
use core::sync::atomic;
|
||||
#[cfg(feature = "debug_allocations")]
|
||||
use core::sync::atomic::AtomicUsize;
|
||||
#[cfg(any(feature = "debug_allocations", feature = "panic_console"))]
|
||||
use libtock_drivers::console::Console;
|
||||
use linked_list_allocator::Heap;
|
||||
|
||||
static mut HEAP: Heap = Heap::empty();
|
||||
|
||||
#[no_mangle]
|
||||
unsafe fn libtock_alloc_init(app_heap_start: usize, app_heap_size: usize) {
|
||||
HEAP.init(app_heap_start, app_heap_size);
|
||||
}
|
||||
|
||||
// With the "debug_allocations" feature, we use `AtomicUsize` to store the
|
||||
// statistics because:
|
||||
// - it is `Sync`, so we can use it in a static object (the allocator),
|
||||
// - it implements interior mutability, so we can use it in the allocator
|
||||
// methods (that take an immutable `&self` reference).
|
||||
struct TockAllocator {
|
||||
#[cfg(feature = "debug_allocations")]
|
||||
count: AtomicUsize,
|
||||
#[cfg(feature = "debug_allocations")]
|
||||
size: AtomicUsize,
|
||||
}
|
||||
|
||||
impl TockAllocator {
|
||||
const fn new() -> TockAllocator {
|
||||
TockAllocator {
|
||||
#[cfg(feature = "debug_allocations")]
|
||||
count: AtomicUsize::new(0),
|
||||
#[cfg(feature = "debug_allocations")]
|
||||
size: AtomicUsize::new(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl GlobalAlloc for TockAllocator {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
let ptr = HEAP
|
||||
.allocate_first_fit(layout)
|
||||
.ok()
|
||||
.map_or(ptr::null_mut(), NonNull::as_ptr);
|
||||
#[cfg(feature = "debug_allocations")]
|
||||
{
|
||||
self.count.fetch_add(1, atomic::Ordering::SeqCst);
|
||||
self.size.fetch_add(layout.size(), atomic::Ordering::SeqCst);
|
||||
writeln!(
|
||||
Console::new(),
|
||||
"alloc[{}, {}] = {:?} ({} ptrs, {} bytes)",
|
||||
layout.size(),
|
||||
layout.align(),
|
||||
ptr,
|
||||
self.count.load(atomic::Ordering::SeqCst),
|
||||
self.size.load(atomic::Ordering::SeqCst)
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
ptr
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
#[cfg(feature = "debug_allocations")]
|
||||
{
|
||||
self.count.fetch_sub(1, atomic::Ordering::SeqCst);
|
||||
self.size.fetch_sub(layout.size(), atomic::Ordering::SeqCst);
|
||||
writeln!(
|
||||
Console::new(),
|
||||
"dealloc[{}, {}] = {:?} ({} ptrs, {} bytes)",
|
||||
layout.size(),
|
||||
layout.align(),
|
||||
ptr,
|
||||
self.count.load(atomic::Ordering::SeqCst),
|
||||
self.size.load(atomic::Ordering::SeqCst)
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
HEAP.deallocate(NonNull::new_unchecked(ptr), layout)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "arm", target_arch = "riscv32"))]
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: TockAllocator = TockAllocator::new();
|
||||
|
||||
#[alloc_error_handler]
|
||||
unsafe fn alloc_error_handler(_layout: Layout) -> ! {
|
||||
util::signal_oom();
|
||||
util::signal_panic();
|
||||
|
||||
#[cfg(feature = "panic_console")]
|
||||
{
|
||||
writeln!(Console::new(), "Couldn't allocate: {:?}", _layout).ok();
|
||||
// Force the kernel to report the panic cause, by reading an invalid address.
|
||||
// The memory protection unit should be setup by the Tock kernel to prevent apps from accessing
|
||||
// address zero.
|
||||
core::ptr::read_volatile(0 as *const usize);
|
||||
}
|
||||
|
||||
util::cycle_leds()
|
||||
}
|
||||
9
third_party/lang-items/src/lib.rs
vendored
Normal file
9
third_party/lang-items/src/lib.rs
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![feature(alloc_error_handler)]
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
mod allocator;
|
||||
#[cfg(not(feature = "std"))]
|
||||
mod panic_handler;
|
||||
#[cfg(not(feature = "std"))]
|
||||
mod util;
|
||||
26
third_party/lang-items/src/panic_handler.rs
vendored
Normal file
26
third_party/lang-items/src/panic_handler.rs
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
use crate::util;
|
||||
#[cfg(feature = "panic_console")]
|
||||
use core::fmt::Write;
|
||||
use core::panic::PanicInfo;
|
||||
#[cfg(feature = "panic_console")]
|
||||
use libtock_drivers::console::Console;
|
||||
|
||||
#[panic_handler]
|
||||
fn panic_handler(_info: &PanicInfo) -> ! {
|
||||
util::signal_panic();
|
||||
|
||||
#[cfg(feature = "panic_console")]
|
||||
{
|
||||
let mut console = Console::new();
|
||||
writeln!(console, "{}", _info).ok();
|
||||
console.flush();
|
||||
// Force the kernel to report the panic cause, by reading an invalid address.
|
||||
// The memory protection unit should be setup by the Tock kernel to prevent apps from accessing
|
||||
// address zero.
|
||||
unsafe {
|
||||
core::ptr::read_volatile(0 as *const usize);
|
||||
}
|
||||
}
|
||||
|
||||
util::flash_all_leds();
|
||||
}
|
||||
46
third_party/lang-items/src/util.rs
vendored
Normal file
46
third_party/lang-items/src/util.rs
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
use libtock_drivers::led;
|
||||
use libtock_drivers::timer::{self, Duration};
|
||||
|
||||
// Signal a panic using the LowLevelDebug capsule (if available).
|
||||
pub fn signal_panic() {
|
||||
let _ = libtock_core::syscalls::command1_insecure(8, 1, 1);
|
||||
}
|
||||
|
||||
// Signal an out-of-memory error using the LowLevelDebug capsule (if available).
|
||||
pub fn signal_oom() {
|
||||
let _ = libtock_core::syscalls::command1_insecure(8, 2, 1);
|
||||
}
|
||||
|
||||
pub fn flash_all_leds() -> ! {
|
||||
// Flash all LEDs (if available). All errors from syscalls are ignored: we are already inside a
|
||||
// panic handler so there is nothing much to do if simple drivers (timer, LEDs) don't work.
|
||||
loop {
|
||||
if let Ok(leds) = led::all() {
|
||||
for led in leds {
|
||||
let _ = led.on();
|
||||
}
|
||||
}
|
||||
let _ = timer::sleep(Duration::from_ms(100));
|
||||
if let Ok(leds) = led::all() {
|
||||
for led in leds {
|
||||
let _ = led.off();
|
||||
}
|
||||
}
|
||||
let _ = timer::sleep(Duration::from_ms(100));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cycle_leds() -> ! {
|
||||
// Cycle though all LEDs (if available). All errors from syscalls are ignored: we are already
|
||||
// inside an error handler so there is nothing much to do if simple drivers (timer, LEDs) don't
|
||||
// work.
|
||||
loop {
|
||||
if let Ok(leds) = led::all() {
|
||||
for led in leds {
|
||||
let _ = led.on();
|
||||
let _ = timer::sleep(Duration::from_ms(100));
|
||||
let _ = led.off();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
third_party/libtock-drivers/Cargo.toml
vendored
Normal file
16
third_party/libtock-drivers/Cargo.toml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "libtock_drivers"
|
||||
version = "0.1.0"
|
||||
authors = [
|
||||
"Tock Project Developers <tock-dev@googlegroups.com>",
|
||||
"Guillaume Endignoux <guillaumee@google.com>",
|
||||
]
|
||||
license = "MIT/Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libtock_core = { path = "../../third_party/libtock-rs/core" }
|
||||
|
||||
[features]
|
||||
debug_ctap = []
|
||||
verbose_usb = ["debug_ctap"]
|
||||
202
third_party/libtock-drivers/LICENSE-APACHE
vendored
Normal file
202
third_party/libtock-drivers/LICENSE-APACHE
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
25
third_party/libtock-drivers/LICENSE-MIT
vendored
Normal file
25
third_party/libtock-drivers/LICENSE-MIT
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2016 The Tock Project Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
170
third_party/libtock-drivers/src/buttons.rs
vendored
Normal file
170
third_party/libtock-drivers/src/buttons.rs
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
use crate::result::{OtherError, TockResult};
|
||||
use core::marker::PhantomData;
|
||||
use libtock_core::callback::{CallbackSubscription, Consumer};
|
||||
use libtock_core::syscalls;
|
||||
|
||||
const DRIVER_NUMBER: usize = 0x00003;
|
||||
|
||||
mod command_nr {
|
||||
pub const COUNT: usize = 0;
|
||||
pub const ENABLE_INTERRUPT: usize = 1;
|
||||
pub const DISABLE_INTERRUPT: usize = 2;
|
||||
pub const READ: usize = 3;
|
||||
}
|
||||
|
||||
mod subscribe_nr {
|
||||
pub const SUBSCRIBE_CALLBACK: usize = 0;
|
||||
}
|
||||
|
||||
pub fn with_callback<CB>(callback: CB) -> WithCallback<CB> {
|
||||
WithCallback { callback }
|
||||
}
|
||||
|
||||
pub struct WithCallback<CB> {
|
||||
callback: CB,
|
||||
}
|
||||
|
||||
struct ButtonConsumer;
|
||||
|
||||
impl<CB: FnMut(usize, ButtonState)> Consumer<WithCallback<CB>> for ButtonConsumer {
|
||||
fn consume(data: &mut WithCallback<CB>, button_num: usize, state: usize, _: usize) {
|
||||
(data.callback)(button_num, state.into());
|
||||
}
|
||||
}
|
||||
|
||||
impl<CB: FnMut(usize, ButtonState)> WithCallback<CB> {
|
||||
pub fn init(&mut self) -> TockResult<Buttons> {
|
||||
let count = syscalls::command(DRIVER_NUMBER, command_nr::COUNT, 0, 0)?;
|
||||
|
||||
let subscription = syscalls::subscribe::<ButtonConsumer, _>(
|
||||
DRIVER_NUMBER,
|
||||
subscribe_nr::SUBSCRIBE_CALLBACK,
|
||||
self,
|
||||
)?;
|
||||
|
||||
Ok(Buttons {
|
||||
count: count as usize,
|
||||
subscription,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Buttons<'a> {
|
||||
count: usize,
|
||||
#[allow(dead_code)] // Used in drop
|
||||
subscription: CallbackSubscription<'a>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum ButtonsError {
|
||||
NotSupported,
|
||||
SubscriptionFailed,
|
||||
}
|
||||
|
||||
impl<'a> Buttons<'a> {
|
||||
pub fn iter_mut(&mut self) -> ButtonIter {
|
||||
ButtonIter {
|
||||
curr_button: 0,
|
||||
button_count: self.count,
|
||||
lifetime: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum ButtonState {
|
||||
Pressed,
|
||||
Released,
|
||||
}
|
||||
|
||||
impl From<usize> for ButtonState {
|
||||
fn from(state: usize) -> ButtonState {
|
||||
match state {
|
||||
0 => ButtonState::Released,
|
||||
1 => ButtonState::Pressed,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> IntoIterator for &'b mut Buttons<'a> {
|
||||
type Item = ButtonHandle<'b>;
|
||||
type IntoIter = ButtonIter<'b>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ButtonIter<'a> {
|
||||
curr_button: usize,
|
||||
button_count: usize,
|
||||
lifetime: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for ButtonIter<'a> {
|
||||
type Item = ButtonHandle<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.curr_button < self.button_count {
|
||||
let item = ButtonHandle {
|
||||
button_num: self.curr_button,
|
||||
lifetime: PhantomData,
|
||||
};
|
||||
self.curr_button += 1;
|
||||
Some(item)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ButtonHandle<'a> {
|
||||
button_num: usize,
|
||||
lifetime: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a> ButtonHandle<'a> {
|
||||
pub fn enable(&mut self) -> TockResult<Button> {
|
||||
syscalls::command(
|
||||
DRIVER_NUMBER,
|
||||
command_nr::ENABLE_INTERRUPT,
|
||||
self.button_num,
|
||||
0,
|
||||
)?;
|
||||
|
||||
Ok(Button { handle: self })
|
||||
}
|
||||
|
||||
pub fn disable(&mut self) -> TockResult<()> {
|
||||
syscalls::command(
|
||||
DRIVER_NUMBER,
|
||||
command_nr::DISABLE_INTERRUPT,
|
||||
self.button_num,
|
||||
0,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Button<'a> {
|
||||
handle: &'a ButtonHandle<'a>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum ButtonError {
|
||||
ActivationFailed,
|
||||
}
|
||||
|
||||
impl<'a> Button<'a> {
|
||||
pub fn read(&self) -> TockResult<ButtonState> {
|
||||
let button_state =
|
||||
syscalls::command(DRIVER_NUMBER, command_nr::READ, self.handle.button_num, 0)?;
|
||||
match button_state {
|
||||
0 => Ok(ButtonState::Released),
|
||||
1 => Ok(ButtonState::Pressed),
|
||||
_ => Err(OtherError::ButtonsDriverInvalidState.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
113
third_party/libtock-drivers/src/console.rs
vendored
Normal file
113
third_party/libtock-drivers/src/console.rs
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
use crate::util;
|
||||
use core::cell::Cell;
|
||||
use core::fmt;
|
||||
use libtock_core::{callback, syscalls};
|
||||
|
||||
const DRIVER_NUMBER: usize = 1;
|
||||
|
||||
mod command_nr {
|
||||
pub const WRITE: usize = 1;
|
||||
}
|
||||
|
||||
mod subscribe_nr {
|
||||
pub const SET_ALARM: usize = 1;
|
||||
}
|
||||
|
||||
mod allow_nr {
|
||||
pub const SHARE_BUFFER: usize = 1;
|
||||
}
|
||||
|
||||
const BUFFER_SIZE: usize = 1024;
|
||||
|
||||
pub struct Console {
|
||||
allow_buffer: [u8; BUFFER_SIZE],
|
||||
count_pending: usize,
|
||||
}
|
||||
|
||||
impl Console {
|
||||
pub fn new() -> Console {
|
||||
Console {
|
||||
allow_buffer: [0; BUFFER_SIZE],
|
||||
count_pending: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.count_pending == 0
|
||||
}
|
||||
|
||||
fn is_full(&self) -> bool {
|
||||
self.allow_buffer.len() == self.count_pending
|
||||
}
|
||||
|
||||
fn available_len(&self) -> usize {
|
||||
self.allow_buffer.len() - self.count_pending
|
||||
}
|
||||
|
||||
pub fn write<S: AsRef<[u8]>>(&mut self, text: S) {
|
||||
let mut not_written_yet = text.as_ref();
|
||||
while !not_written_yet.is_empty() {
|
||||
let num_bytes_to_print = self.available_len().min(not_written_yet.len());
|
||||
self.allow_buffer[self.count_pending..(self.count_pending + num_bytes_to_print)]
|
||||
.copy_from_slice(¬_written_yet[..num_bytes_to_print]);
|
||||
self.count_pending += num_bytes_to_print;
|
||||
|
||||
if self.is_full() {
|
||||
self.flush();
|
||||
}
|
||||
|
||||
not_written_yet = ¬_written_yet[num_bytes_to_print..];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flush(&mut self) {
|
||||
if self.is_empty() {
|
||||
// Don't trigger any syscall if the buffer is empty.
|
||||
return;
|
||||
}
|
||||
|
||||
let count = self.count_pending;
|
||||
// Clear the buffer even in case of error, to avoid an infinite loop.
|
||||
self.count_pending = 0;
|
||||
|
||||
let result = syscalls::allow(
|
||||
DRIVER_NUMBER,
|
||||
allow_nr::SHARE_BUFFER,
|
||||
&mut self.allow_buffer[..count],
|
||||
);
|
||||
if result.is_err() {
|
||||
return;
|
||||
}
|
||||
|
||||
let is_written = Cell::new(false);
|
||||
let mut is_written_alarm = || is_written.set(true);
|
||||
let subscription = syscalls::subscribe::<callback::Identity0Consumer, _>(
|
||||
DRIVER_NUMBER,
|
||||
subscribe_nr::SET_ALARM,
|
||||
&mut is_written_alarm,
|
||||
);
|
||||
if subscription.is_err() {
|
||||
return;
|
||||
}
|
||||
|
||||
let result_code = syscalls::command(DRIVER_NUMBER, command_nr::WRITE, count, 0);
|
||||
if result_code.is_err() {
|
||||
return;
|
||||
}
|
||||
|
||||
util::yieldk_for(|| is_written.get());
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Console {
|
||||
fn drop(&mut self) {
|
||||
self.flush();
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for Console {
|
||||
fn write_str(&mut self, string: &str) -> Result<(), fmt::Error> {
|
||||
self.write(string);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
84
third_party/libtock-drivers/src/led.rs
vendored
Normal file
84
third_party/libtock-drivers/src/led.rs
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
use crate::result::{OtherError, TockError, TockResult};
|
||||
use libtock_core::syscalls;
|
||||
|
||||
const DRIVER_NUMBER: usize = 0x00002;
|
||||
|
||||
mod command_nr {
|
||||
pub const COUNT: usize = 0;
|
||||
pub const ON: usize = 1;
|
||||
pub const OFF: usize = 2;
|
||||
pub const TOGGLE: usize = 3;
|
||||
}
|
||||
|
||||
pub struct Led {
|
||||
led_num: usize,
|
||||
}
|
||||
|
||||
pub fn count() -> TockResult<usize> {
|
||||
let count = syscalls::command(DRIVER_NUMBER, command_nr::COUNT, 0, 0)?;
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
pub fn get(led_num: usize) -> TockResult<Led> {
|
||||
let led_count = count()?;
|
||||
if led_num < led_count {
|
||||
Ok(Led { led_num })
|
||||
} else {
|
||||
Err(TockError::Other(OtherError::OutOfRange))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all() -> TockResult<LedIter> {
|
||||
let led_count = count()?;
|
||||
Ok(LedIter {
|
||||
curr_led: 0,
|
||||
led_count,
|
||||
})
|
||||
}
|
||||
|
||||
impl Led {
|
||||
pub fn set_state(&self, state: bool) -> TockResult<()> {
|
||||
if state {
|
||||
self.on()
|
||||
} else {
|
||||
self.off()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on(&self) -> TockResult<()> {
|
||||
syscalls::command(DRIVER_NUMBER, command_nr::ON, self.led_num, 0)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn off(&self) -> TockResult<()> {
|
||||
syscalls::command(DRIVER_NUMBER, command_nr::OFF, self.led_num, 0)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn toggle(&self) -> TockResult<()> {
|
||||
syscalls::command(DRIVER_NUMBER, command_nr::TOGGLE, self.led_num, 0)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct LedIter {
|
||||
curr_led: usize,
|
||||
led_count: usize,
|
||||
}
|
||||
|
||||
impl Iterator for LedIter {
|
||||
type Item = Led;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.curr_led < self.led_count {
|
||||
let item = Led {
|
||||
led_num: self.curr_led,
|
||||
};
|
||||
self.curr_led += 1;
|
||||
Some(item)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
10
third_party/libtock-drivers/src/lib.rs
vendored
Normal file
10
third_party/libtock-drivers/src/lib.rs
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#![no_std]
|
||||
|
||||
pub mod buttons;
|
||||
pub mod console;
|
||||
pub mod led;
|
||||
pub mod result;
|
||||
pub mod rng;
|
||||
pub mod timer;
|
||||
pub mod usb_ctap_hid;
|
||||
pub mod util;
|
||||
133
third_party/libtock-drivers/src/result.rs
vendored
Normal file
133
third_party/libtock-drivers/src/result.rs
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
use core::fmt;
|
||||
|
||||
pub use libtock_core::result::*;
|
||||
|
||||
pub type TockResult<T> = Result<T, TockError>;
|
||||
|
||||
// We sometimes need to handle errors in a `TockResult` by calling `unwrap`. However,
|
||||
// `Result::unwrap` requires that the error type implements `core::fmt::Debug`. Under the hood,
|
||||
// this requires dynamic dispatch, which has non-negligible overhead on code size. Therefore errors
|
||||
// don't derive from `Debug` in libtock-rs.
|
||||
//
|
||||
// Instead one can call `.ok().unwrap()` which relies on `Option::unwrap` and doesn't require any
|
||||
// debugging of the error type.
|
||||
//
|
||||
// This trait allows to flexibly use `Result::unwrap` or `Option::unwrap` and is configured to do
|
||||
// so depending on the `debug_ctap` feature.
|
||||
pub trait FlexUnwrap<T> {
|
||||
fn flex_unwrap(self) -> T;
|
||||
}
|
||||
|
||||
impl<T> FlexUnwrap<T> for TockResult<T> {
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
fn flex_unwrap(self) -> T {
|
||||
self.unwrap()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "debug_ctap"))]
|
||||
fn flex_unwrap(self) -> T {
|
||||
self.ok().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum TockError {
|
||||
Subscribe(SubscribeError),
|
||||
Command(CommandError),
|
||||
Allow(AllowError),
|
||||
Format,
|
||||
Other(OtherError),
|
||||
}
|
||||
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
impl core::fmt::Debug for TockError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
TockError::Subscribe(SubscribeError {
|
||||
driver_number,
|
||||
subscribe_number,
|
||||
return_code,
|
||||
}) => f
|
||||
.debug_struct("SubscribeError")
|
||||
.field("driver", driver_number)
|
||||
.field("subscribe", subscribe_number)
|
||||
.field("return_code", return_code)
|
||||
.finish(),
|
||||
TockError::Command(CommandError {
|
||||
driver_number,
|
||||
command_number,
|
||||
arg1,
|
||||
arg2,
|
||||
return_code,
|
||||
}) => f
|
||||
.debug_struct("CommandError")
|
||||
.field("driver", driver_number)
|
||||
.field("command", command_number)
|
||||
.field("arg1", arg1)
|
||||
.field("arg2", arg2)
|
||||
.field("return_code", return_code)
|
||||
.finish(),
|
||||
TockError::Allow(AllowError {
|
||||
driver_number,
|
||||
allow_number,
|
||||
return_code,
|
||||
}) => f
|
||||
.debug_struct("AllowError")
|
||||
.field("driver", driver_number)
|
||||
.field("allow", allow_number)
|
||||
.field("return_code", return_code)
|
||||
.finish(),
|
||||
TockError::Format => f.write_str("TockError::Format"),
|
||||
TockError::Other(e) => e.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SubscribeError> for TockError {
|
||||
fn from(subscribe_error: SubscribeError) -> Self {
|
||||
TockError::Subscribe(subscribe_error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CommandError> for TockError {
|
||||
fn from(command_error: CommandError) -> Self {
|
||||
TockError::Command(command_error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AllowError> for TockError {
|
||||
fn from(allow_error: AllowError) -> Self {
|
||||
TockError::Allow(allow_error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<fmt::Error> for TockError {
|
||||
fn from(fmt::Error: fmt::Error) -> Self {
|
||||
TockError::Format
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "debug_ctap", derive(Debug))]
|
||||
pub enum OtherError {
|
||||
ButtonsDriverInvalidState,
|
||||
GpioDriverInvalidState,
|
||||
TimerDriverDurationOutOfRange,
|
||||
TimerDriverErroneousClockFrequency,
|
||||
DriversAlreadyTaken,
|
||||
OutOfRange,
|
||||
}
|
||||
|
||||
impl From<OtherError> for TockError {
|
||||
fn from(other: OtherError) -> Self {
|
||||
TockError::Other(other)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OutOfRangeError;
|
||||
|
||||
impl From<OutOfRangeError> for TockError {
|
||||
fn from(_: OutOfRangeError) -> Self {
|
||||
TockError::Other(OtherError::OutOfRange)
|
||||
}
|
||||
}
|
||||
45
third_party/libtock-drivers/src/rng.rs
vendored
Normal file
45
third_party/libtock-drivers/src/rng.rs
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
use crate::util;
|
||||
use core::cell::Cell;
|
||||
use libtock_core::{callback, syscalls};
|
||||
|
||||
const DRIVER_NUMBER: usize = 0x40001;
|
||||
|
||||
mod command_nr {
|
||||
pub const REQUEST_RNG: usize = 1;
|
||||
}
|
||||
|
||||
mod subscribe_nr {
|
||||
pub const BUFFER_FILLED: usize = 0;
|
||||
}
|
||||
|
||||
mod allow_nr {
|
||||
pub const SHARE_BUFFER: usize = 0;
|
||||
}
|
||||
|
||||
pub fn fill_buffer(buf: &mut [u8]) -> bool {
|
||||
let buf_len = buf.len();
|
||||
|
||||
let result = syscalls::allow(DRIVER_NUMBER, allow_nr::SHARE_BUFFER, buf);
|
||||
if result.is_err() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let is_filled = Cell::new(false);
|
||||
let mut is_filled_alarm = || is_filled.set(true);
|
||||
let subscription = syscalls::subscribe::<callback::Identity0Consumer, _>(
|
||||
DRIVER_NUMBER,
|
||||
subscribe_nr::BUFFER_FILLED,
|
||||
&mut is_filled_alarm,
|
||||
);
|
||||
if subscription.is_err() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let result_code = syscalls::command(DRIVER_NUMBER, command_nr::REQUEST_RNG, buf_len, 0);
|
||||
if result_code.is_err() {
|
||||
return false;
|
||||
}
|
||||
|
||||
util::yieldk_for(|| is_filled.get());
|
||||
return true;
|
||||
}
|
||||
334
third_party/libtock-drivers/src/timer.rs
vendored
Normal file
334
third_party/libtock-drivers/src/timer.rs
vendored
Normal file
@@ -0,0 +1,334 @@
|
||||
use crate::result::{FlexUnwrap, OtherError, TockError, TockResult};
|
||||
use crate::util;
|
||||
use core::cell::Cell;
|
||||
use core::isize;
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::{Add, AddAssign, Sub};
|
||||
use libtock_core::callback::{CallbackSubscription, Consumer};
|
||||
use libtock_core::result::{CommandError, EALREADY};
|
||||
use libtock_core::syscalls;
|
||||
|
||||
const DRIVER_NUMBER: usize = 0x00000;
|
||||
|
||||
mod command_nr {
|
||||
pub const IS_DRIVER_AVAILABLE: usize = 0;
|
||||
pub const GET_CLOCK_FREQUENCY: usize = 1;
|
||||
pub const GET_CLOCK_VALUE: usize = 2;
|
||||
pub const STOP_ALARM: usize = 3;
|
||||
pub const SET_ALARM: usize = 4;
|
||||
}
|
||||
|
||||
mod subscribe_nr {
|
||||
pub const SUBSCRIBE_CALLBACK: usize = 0;
|
||||
}
|
||||
|
||||
pub fn sleep(duration: Duration<isize>) -> TockResult<()> {
|
||||
let expired = Cell::new(false);
|
||||
let mut with_callback = with_callback(|_, _| expired.set(true));
|
||||
|
||||
let mut timer = with_callback.init().flex_unwrap();
|
||||
let timer_alarm = timer.set_alarm(duration).flex_unwrap();
|
||||
|
||||
util::yieldk_for(|| expired.get());
|
||||
|
||||
match timer.stop_alarm(timer_alarm) {
|
||||
Ok(())
|
||||
| Err(TockError::Command(CommandError {
|
||||
return_code: EALREADY,
|
||||
..
|
||||
})) => Ok(()),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_callback<CB>(callback: CB) -> WithCallback<'static, CB> {
|
||||
WithCallback {
|
||||
callback,
|
||||
clock_frequency: ClockFrequency { hz: 0 },
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WithCallback<'a, CB> {
|
||||
callback: CB,
|
||||
clock_frequency: ClockFrequency,
|
||||
phantom: PhantomData<&'a mut ()>,
|
||||
}
|
||||
|
||||
struct TimerEventConsumer;
|
||||
|
||||
impl<CB: FnMut(ClockValue, Alarm)> Consumer<WithCallback<'_, CB>> for TimerEventConsumer {
|
||||
fn consume(data: &mut WithCallback<CB>, clock_value: usize, alarm_id: usize, _: usize) {
|
||||
(data.callback)(
|
||||
ClockValue {
|
||||
num_ticks: clock_value as isize,
|
||||
clock_frequency: data.clock_frequency,
|
||||
},
|
||||
Alarm { alarm_id },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, CB: FnMut(ClockValue, Alarm)> WithCallback<'a, CB> {
|
||||
pub fn init(&'a mut self) -> TockResult<Timer<'a>> {
|
||||
let num_notifications =
|
||||
syscalls::command(DRIVER_NUMBER, command_nr::IS_DRIVER_AVAILABLE, 0, 0)?;
|
||||
|
||||
let clock_frequency =
|
||||
syscalls::command(DRIVER_NUMBER, command_nr::GET_CLOCK_FREQUENCY, 0, 0)?;
|
||||
|
||||
if clock_frequency == 0 {
|
||||
return Err(OtherError::TimerDriverErroneousClockFrequency.into());
|
||||
}
|
||||
|
||||
let clock_frequency = ClockFrequency {
|
||||
hz: clock_frequency,
|
||||
};
|
||||
|
||||
let subscription = syscalls::subscribe::<TimerEventConsumer, _>(
|
||||
DRIVER_NUMBER,
|
||||
subscribe_nr::SUBSCRIBE_CALLBACK,
|
||||
self,
|
||||
)?;
|
||||
|
||||
Ok(Timer {
|
||||
num_notifications,
|
||||
clock_frequency,
|
||||
subscription,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Timer<'a> {
|
||||
num_notifications: usize,
|
||||
clock_frequency: ClockFrequency,
|
||||
#[allow(dead_code)] // Used in drop
|
||||
subscription: CallbackSubscription<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Timer<'a> {
|
||||
pub fn num_notifications(&self) -> usize {
|
||||
self.num_notifications
|
||||
}
|
||||
|
||||
pub fn clock_frequency(&self) -> ClockFrequency {
|
||||
self.clock_frequency
|
||||
}
|
||||
|
||||
pub fn get_current_clock(&self) -> TockResult<ClockValue> {
|
||||
Ok(ClockValue {
|
||||
num_ticks: syscalls::command(DRIVER_NUMBER, command_nr::GET_CLOCK_VALUE, 0, 0)?
|
||||
as isize,
|
||||
clock_frequency: self.clock_frequency,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn stop_alarm(&mut self, alarm: Alarm) -> TockResult<()> {
|
||||
syscalls::command(DRIVER_NUMBER, command_nr::STOP_ALARM, alarm.alarm_id, 0)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_alarm(&mut self, duration: Duration<isize>) -> TockResult<Alarm> {
|
||||
let now = self.get_current_clock()?;
|
||||
let freq = self.clock_frequency.hz();
|
||||
let duration_ms = duration.ms() as usize;
|
||||
let ticks = match duration_ms.checked_mul(freq) {
|
||||
Some(x) => x / 1000,
|
||||
None => {
|
||||
// Divide the largest of the two operands by 1000, to improve precision of the
|
||||
// result.
|
||||
if duration_ms > freq {
|
||||
match (duration_ms / 1000).checked_mul(freq) {
|
||||
Some(y) => y,
|
||||
None => return Err(OtherError::TimerDriverDurationOutOfRange.into()),
|
||||
}
|
||||
} else {
|
||||
match (freq / 1000).checked_mul(duration_ms) {
|
||||
Some(y) => y,
|
||||
None => return Err(OtherError::TimerDriverDurationOutOfRange.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let alarm_instant = now.num_ticks() as usize + ticks;
|
||||
|
||||
let alarm_id = syscalls::command(DRIVER_NUMBER, command_nr::SET_ALARM, alarm_instant, 0)?;
|
||||
|
||||
Ok(Alarm { alarm_id })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct ClockFrequency {
|
||||
hz: usize,
|
||||
}
|
||||
|
||||
impl ClockFrequency {
|
||||
pub fn hz(&self) -> usize {
|
||||
self.hz
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ClockValue {
|
||||
num_ticks: isize,
|
||||
clock_frequency: ClockFrequency,
|
||||
}
|
||||
|
||||
impl ClockValue {
|
||||
pub const fn new(num_ticks: isize, clock_hz: usize) -> ClockValue {
|
||||
ClockValue {
|
||||
num_ticks,
|
||||
clock_frequency: ClockFrequency { hz: clock_hz },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn num_ticks(&self) -> isize {
|
||||
self.num_ticks
|
||||
}
|
||||
|
||||
// Computes (value * factor) / divisor, even when value * factor >= isize::MAX.
|
||||
fn scale_int(value: isize, factor: isize, divisor: isize) -> isize {
|
||||
// As long as isize is not i64, this should be fine. If not, this is an alternative:
|
||||
// factor * (value / divisor) + ((value % divisor) * factor) / divisor
|
||||
((value as i64 * factor as i64) / divisor as i64) as isize
|
||||
}
|
||||
|
||||
pub fn ms(&self) -> isize {
|
||||
ClockValue::scale_int(self.num_ticks, 1000, self.clock_frequency.hz() as isize)
|
||||
}
|
||||
|
||||
pub fn ms_f64(&self) -> f64 {
|
||||
1000.0 * (self.num_ticks as f64) / (self.clock_frequency.hz() as f64)
|
||||
}
|
||||
|
||||
pub fn wrapping_add(self, duration: Duration<isize>) -> ClockValue {
|
||||
// This is a precision preserving formula for scaling an isize.
|
||||
let duration_ticks =
|
||||
ClockValue::scale_int(duration.ms, self.clock_frequency.hz() as isize, 1000);
|
||||
ClockValue {
|
||||
num_ticks: self.num_ticks.wrapping_add(duration_ticks),
|
||||
clock_frequency: self.clock_frequency,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wrapping_sub(self, other: ClockValue) -> Option<Duration<isize>> {
|
||||
if self.clock_frequency == other.clock_frequency {
|
||||
let clock_duration = ClockValue {
|
||||
num_ticks: self.num_ticks - other.num_ticks,
|
||||
clock_frequency: self.clock_frequency,
|
||||
};
|
||||
Some(Duration::from_ms(clock_duration.ms()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Alarm {
|
||||
alarm_id: usize,
|
||||
}
|
||||
|
||||
impl Alarm {
|
||||
pub fn alarm_id(&self) -> usize {
|
||||
self.alarm_id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Duration<T> {
|
||||
ms: T,
|
||||
}
|
||||
|
||||
impl<T> Duration<T> {
|
||||
pub const fn from_ms(ms: T) -> Duration<T> {
|
||||
Duration { ms }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Duration<T>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
pub fn ms(&self) -> T {
|
||||
self.ms
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Sub for Duration<T>
|
||||
where
|
||||
T: Sub<Output = T>,
|
||||
{
|
||||
type Output = Duration<T>;
|
||||
|
||||
fn sub(self, other: Duration<T>) -> Duration<T> {
|
||||
Duration {
|
||||
ms: self.ms - other.ms,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Timestamp<T> {
|
||||
ms: T,
|
||||
}
|
||||
|
||||
impl<T> Timestamp<T> {
|
||||
pub const fn from_ms(ms: T) -> Timestamp<T> {
|
||||
Timestamp { ms }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Timestamp<T>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
pub fn ms(&self) -> T {
|
||||
self.ms
|
||||
}
|
||||
}
|
||||
|
||||
impl Timestamp<isize> {
|
||||
pub fn from_clock_value(value: ClockValue) -> Timestamp<isize> {
|
||||
Timestamp { ms: value.ms() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Timestamp<f64> {
|
||||
pub fn from_clock_value(value: ClockValue) -> Timestamp<f64> {
|
||||
Timestamp { ms: value.ms_f64() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Sub for Timestamp<T>
|
||||
where
|
||||
T: Sub<Output = T>,
|
||||
{
|
||||
type Output = Duration<T>;
|
||||
|
||||
fn sub(self, other: Timestamp<T>) -> Duration<T> {
|
||||
Duration::from_ms(self.ms - other.ms)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add<Duration<T>> for Timestamp<T>
|
||||
where
|
||||
T: Copy + Add<Output = T>,
|
||||
{
|
||||
type Output = Timestamp<T>;
|
||||
|
||||
fn add(self, duration: Duration<T>) -> Timestamp<T> {
|
||||
Timestamp {
|
||||
ms: self.ms + duration.ms(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AddAssign<Duration<T>> for Timestamp<T>
|
||||
where
|
||||
T: Copy + AddAssign,
|
||||
{
|
||||
fn add_assign(&mut self, duration: Duration<T>) {
|
||||
self.ms += duration.ms();
|
||||
}
|
||||
}
|
||||
@@ -12,16 +12,17 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
use crate::console::Console;
|
||||
use crate::result::TockError;
|
||||
use crate::timer;
|
||||
use crate::timer::Duration;
|
||||
use crate::util;
|
||||
use core::cell::Cell;
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
use core::fmt::Write;
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
use libtock::console::Console;
|
||||
use libtock::result::TockValue;
|
||||
use libtock::result::{EALREADY, EBUSY, SUCCESS};
|
||||
use libtock::syscalls;
|
||||
use libtock::timer;
|
||||
use libtock::timer::{Duration, StopAlarmError};
|
||||
use libtock_core::result::{CommandError, EALREADY, EBUSY, SUCCESS};
|
||||
use libtock_core::{callback, syscalls};
|
||||
|
||||
const DRIVER_NUMBER: usize = 0x20009;
|
||||
|
||||
@@ -51,13 +52,13 @@ mod allow_nr {
|
||||
}
|
||||
|
||||
pub fn setup() -> bool {
|
||||
let result = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::CHECK, 0, 0) };
|
||||
if result != 0 {
|
||||
let result = syscalls::command(DRIVER_NUMBER, command_nr::CHECK, 0, 0);
|
||||
if result.is_err() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let result = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::CONNECT, 0, 0) };
|
||||
if result != 0 {
|
||||
let result = syscalls::command(DRIVER_NUMBER, command_nr::CONNECT, 0, 0);
|
||||
if result.is_err() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -72,18 +73,22 @@ pub fn recv(buf: &mut [u8; 64]) -> bool {
|
||||
}
|
||||
|
||||
let done = Cell::new(false);
|
||||
let mut alarm = |_, _, _| done.set(true);
|
||||
let subscription = syscalls::subscribe(DRIVER_NUMBER, subscribe_nr::RECEIVE, &mut alarm);
|
||||
let mut alarm = || done.set(true);
|
||||
let subscription = syscalls::subscribe::<callback::Identity0Consumer, _>(
|
||||
DRIVER_NUMBER,
|
||||
subscribe_nr::RECEIVE,
|
||||
&mut alarm,
|
||||
);
|
||||
if subscription.is_err() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let result_code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::RECEIVE, 0, 0) };
|
||||
if result_code != 0 {
|
||||
let result_code = syscalls::command(DRIVER_NUMBER, command_nr::RECEIVE, 0, 0);
|
||||
if result_code.is_err() {
|
||||
return false;
|
||||
}
|
||||
|
||||
syscalls::yieldk_for(|| done.get());
|
||||
util::yieldk_for(|| done.get());
|
||||
true
|
||||
}
|
||||
|
||||
@@ -95,18 +100,22 @@ pub fn send(buf: &mut [u8; 64]) -> bool {
|
||||
}
|
||||
|
||||
let done = Cell::new(false);
|
||||
let mut alarm = |_, _, _| done.set(true);
|
||||
let subscription = syscalls::subscribe(DRIVER_NUMBER, subscribe_nr::TRANSMIT, &mut alarm);
|
||||
let mut alarm = || done.set(true);
|
||||
let subscription = syscalls::subscribe::<callback::Identity0Consumer, _>(
|
||||
DRIVER_NUMBER,
|
||||
subscribe_nr::TRANSMIT,
|
||||
&mut alarm,
|
||||
);
|
||||
if subscription.is_err() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let result_code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT, 0, 0) };
|
||||
if result_code != 0 {
|
||||
let result_code = syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT, 0, 0);
|
||||
if result_code.is_err() {
|
||||
return false;
|
||||
}
|
||||
|
||||
syscalls::yieldk_for(|| done.get());
|
||||
util::yieldk_for(|| done.get());
|
||||
true
|
||||
}
|
||||
|
||||
@@ -135,7 +144,7 @@ pub fn send_or_recv(buf: &mut [u8; 64]) -> SendOrRecvStatus {
|
||||
}
|
||||
|
||||
let status = Cell::new(None);
|
||||
let mut alarm = |direction, _, _| {
|
||||
let mut alarm = |direction| {
|
||||
status.set(Some(match direction {
|
||||
subscribe_nr::callback_status::TRANSMITTED => SendOrRecvStatus::Sent,
|
||||
subscribe_nr::callback_status::RECEIVED => SendOrRecvStatus::Received,
|
||||
@@ -144,19 +153,21 @@ pub fn send_or_recv(buf: &mut [u8; 64]) -> SendOrRecvStatus {
|
||||
}));
|
||||
};
|
||||
|
||||
let subscription =
|
||||
syscalls::subscribe(DRIVER_NUMBER, subscribe_nr::TRANSMIT_OR_RECEIVE, &mut alarm);
|
||||
let subscription = syscalls::subscribe::<callback::Identity1Consumer, _>(
|
||||
DRIVER_NUMBER,
|
||||
subscribe_nr::TRANSMIT_OR_RECEIVE,
|
||||
&mut alarm,
|
||||
);
|
||||
if subscription.is_err() {
|
||||
return SendOrRecvStatus::Error;
|
||||
}
|
||||
|
||||
let result_code =
|
||||
unsafe { syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT_OR_RECEIVE, 0, 0) };
|
||||
if result_code != 0 {
|
||||
let result_code = syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT_OR_RECEIVE, 0, 0);
|
||||
if result_code.is_err() {
|
||||
return SendOrRecvStatus::Error;
|
||||
}
|
||||
|
||||
syscalls::yieldk_for(|| status.get().is_some());
|
||||
util::yieldk_for(|| status.get().is_some());
|
||||
status.get().unwrap()
|
||||
}
|
||||
|
||||
@@ -166,7 +177,7 @@ pub fn recv_with_timeout(
|
||||
buf: &mut [u8; 64],
|
||||
timeout_delay: Duration<isize>,
|
||||
) -> Option<SendOrRecvStatus> {
|
||||
#[cfg(feature = "verbose")]
|
||||
#[cfg(feature = "verbose_usb")]
|
||||
writeln!(
|
||||
Console::new(),
|
||||
"Receiving packet with timeout of {}ms",
|
||||
@@ -176,7 +187,7 @@ pub fn recv_with_timeout(
|
||||
|
||||
let result = recv_with_timeout_detail(buf, timeout_delay);
|
||||
|
||||
#[cfg(feature = "verbose")]
|
||||
#[cfg(feature = "verbose_usb")]
|
||||
{
|
||||
if let Some(SendOrRecvStatus::Received) = result {
|
||||
writeln!(Console::new(), "Received packet = {:02x?}", buf as &[u8]).unwrap();
|
||||
@@ -192,7 +203,7 @@ pub fn send_or_recv_with_timeout(
|
||||
buf: &mut [u8; 64],
|
||||
timeout_delay: Duration<isize>,
|
||||
) -> Option<SendOrRecvStatus> {
|
||||
#[cfg(feature = "verbose")]
|
||||
#[cfg(feature = "verbose_usb")]
|
||||
writeln!(
|
||||
Console::new(),
|
||||
"Sending packet with timeout of {}ms = {:02x?}",
|
||||
@@ -203,7 +214,7 @@ pub fn send_or_recv_with_timeout(
|
||||
|
||||
let result = send_or_recv_with_timeout_detail(buf, timeout_delay);
|
||||
|
||||
#[cfg(feature = "verbose")]
|
||||
#[cfg(feature = "verbose_usb")]
|
||||
{
|
||||
if let Some(SendOrRecvStatus::Received) = result {
|
||||
writeln!(Console::new(), "Received packet = {:02x?}", buf as &[u8]).unwrap();
|
||||
@@ -223,7 +234,7 @@ fn recv_with_timeout_detail(
|
||||
}
|
||||
|
||||
let status = Cell::new(None);
|
||||
let mut alarm = |direction, _, _| {
|
||||
let mut alarm = |direction| {
|
||||
status.set(Some(match direction {
|
||||
subscribe_nr::callback_status::RECEIVED => SendOrRecvStatus::Received,
|
||||
// Unknown direction or "transmitted" sent by the kernel.
|
||||
@@ -231,7 +242,11 @@ fn recv_with_timeout_detail(
|
||||
}));
|
||||
};
|
||||
|
||||
let subscription = syscalls::subscribe(DRIVER_NUMBER, subscribe_nr::RECEIVE, &mut alarm);
|
||||
let subscription = syscalls::subscribe::<callback::Identity1Consumer, _>(
|
||||
DRIVER_NUMBER,
|
||||
subscribe_nr::RECEIVE,
|
||||
&mut alarm,
|
||||
);
|
||||
if subscription.is_err() {
|
||||
return Some(SendOrRecvStatus::Error);
|
||||
}
|
||||
@@ -251,17 +266,20 @@ fn recv_with_timeout_detail(
|
||||
};
|
||||
|
||||
// Trigger USB reception.
|
||||
let result_code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::RECEIVE, 0, 0) };
|
||||
if result_code != 0 {
|
||||
let result_code = syscalls::command(DRIVER_NUMBER, command_nr::RECEIVE, 0, 0);
|
||||
if result_code.is_err() {
|
||||
return Some(SendOrRecvStatus::Error);
|
||||
}
|
||||
|
||||
syscalls::yieldk_for(|| status.get().is_some() || timeout_expired.get());
|
||||
util::yieldk_for(|| status.get().is_some() || timeout_expired.get());
|
||||
|
||||
// Cleanup alarm callback.
|
||||
match timeout.stop_alarm(timeout_alarm) {
|
||||
Ok(()) => (),
|
||||
Err(TockValue::Expected(StopAlarmError::AlreadyDisabled)) => {
|
||||
Err(TockError::Command(CommandError {
|
||||
return_code: EALREADY,
|
||||
..
|
||||
})) => {
|
||||
if !timeout_expired.get() {
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
writeln!(
|
||||
@@ -271,14 +289,20 @@ fn recv_with_timeout_detail(
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
Err(e) => panic!("Unexpected error when stopping alarm: {:?}", e),
|
||||
Err(_e) => {
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
panic!("Unexpected error when stopping alarm: {:?}", _e);
|
||||
#[cfg(not(feature = "debug_ctap"))]
|
||||
panic!("Unexpected error when stopping alarm: <error is only visible with the debug_ctap feature>");
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel USB transaction if necessary.
|
||||
if status.get().is_none() {
|
||||
#[cfg(feature = "verbose")]
|
||||
#[cfg(feature = "verbose_usb")]
|
||||
writeln!(Console::new(), "Cancelling USB receive due to timeout").unwrap();
|
||||
let result_code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::CANCEL, 0, 0) };
|
||||
let result_code =
|
||||
unsafe { syscalls::raw::command(DRIVER_NUMBER, command_nr::CANCEL, 0, 0) };
|
||||
match result_code {
|
||||
// - SUCCESS means that we successfully cancelled the transaction.
|
||||
// - EALREADY means that the transaction was already completed.
|
||||
@@ -310,7 +334,7 @@ fn send_or_recv_with_timeout_detail(
|
||||
}
|
||||
|
||||
let status = Cell::new(None);
|
||||
let mut alarm = |direction, _, _| {
|
||||
let mut alarm = |direction| {
|
||||
status.set(Some(match direction {
|
||||
subscribe_nr::callback_status::TRANSMITTED => SendOrRecvStatus::Sent,
|
||||
subscribe_nr::callback_status::RECEIVED => SendOrRecvStatus::Received,
|
||||
@@ -319,8 +343,11 @@ fn send_or_recv_with_timeout_detail(
|
||||
}));
|
||||
};
|
||||
|
||||
let subscription =
|
||||
syscalls::subscribe(DRIVER_NUMBER, subscribe_nr::TRANSMIT_OR_RECEIVE, &mut alarm);
|
||||
let subscription = syscalls::subscribe::<callback::Identity1Consumer, _>(
|
||||
DRIVER_NUMBER,
|
||||
subscribe_nr::TRANSMIT_OR_RECEIVE,
|
||||
&mut alarm,
|
||||
);
|
||||
if subscription.is_err() {
|
||||
return Some(SendOrRecvStatus::Error);
|
||||
}
|
||||
@@ -340,18 +367,20 @@ fn send_or_recv_with_timeout_detail(
|
||||
};
|
||||
|
||||
// Trigger USB transmission.
|
||||
let result_code =
|
||||
unsafe { syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT_OR_RECEIVE, 0, 0) };
|
||||
if result_code != 0 {
|
||||
let result_code = syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT_OR_RECEIVE, 0, 0);
|
||||
if result_code.is_err() {
|
||||
return Some(SendOrRecvStatus::Error);
|
||||
}
|
||||
|
||||
syscalls::yieldk_for(|| status.get().is_some() || timeout_expired.get());
|
||||
util::yieldk_for(|| status.get().is_some() || timeout_expired.get());
|
||||
|
||||
// Cleanup alarm callback.
|
||||
match timeout.stop_alarm(timeout_alarm) {
|
||||
Ok(()) => (),
|
||||
Err(TockValue::Expected(StopAlarmError::AlreadyDisabled)) => {
|
||||
Err(TockError::Command(CommandError {
|
||||
return_code: EALREADY,
|
||||
..
|
||||
})) => {
|
||||
if !timeout_expired.get() {
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
writeln!(
|
||||
@@ -361,14 +390,20 @@ fn send_or_recv_with_timeout_detail(
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
Err(e) => panic!("Unexpected error when stopping alarm: {:?}", e),
|
||||
Err(_e) => {
|
||||
#[cfg(feature = "debug_ctap")]
|
||||
panic!("Unexpected error when stopping alarm: {:?}", _e);
|
||||
#[cfg(not(feature = "debug_ctap"))]
|
||||
panic!("Unexpected error when stopping alarm: <error is only visible with the debug_ctap feature>");
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel USB transaction if necessary.
|
||||
if status.get().is_none() {
|
||||
#[cfg(feature = "verbose")]
|
||||
#[cfg(feature = "verbose_usb")]
|
||||
writeln!(Console::new(), "Cancelling USB transaction due to timeout").unwrap();
|
||||
let result_code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::CANCEL, 0, 0) };
|
||||
let result_code =
|
||||
unsafe { syscalls::raw::command(DRIVER_NUMBER, command_nr::CANCEL, 0, 0) };
|
||||
match result_code {
|
||||
// - SUCCESS means that we successfully cancelled the transaction.
|
||||
// - EALREADY means that the transaction was already completed.
|
||||
9
third_party/libtock-drivers/src/util.rs
vendored
Normal file
9
third_party/libtock-drivers/src/util.rs
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
use libtock_core::syscalls;
|
||||
|
||||
pub fn yieldk_for<F: Fn() -> bool>(cond: F) {
|
||||
while !cond() {
|
||||
unsafe {
|
||||
syscalls::raw::yieldk();
|
||||
}
|
||||
}
|
||||
}
|
||||
2
third_party/libtock-rs
vendored
2
third_party/libtock-rs
vendored
Submodule third_party/libtock-rs updated: ab2c945184...828c19de92
Reference in New Issue
Block a user