Merge pull request #123 from gendx/libtock-core
Update libtock dependency to libtock-core
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 }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: "true"
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
target: thumbv7em-none-eabi
|
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'
|
if: github.repository == 'google/OpenSK'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: "true"
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
target: thumbv7em-none-eabi
|
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
|
runs-on: ubuntu-18.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: "true"
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
target: thumbv7em-none-eabi
|
target: thumbv7em-none-eabi
|
||||||
|
|||||||
2
.github/workflows/cargo_fmt.yml
vendored
2
.github/workflows/cargo_fmt.yml
vendored
@@ -18,6 +18,8 @@ jobs:
|
|||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-18.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: "true"
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
target: thumbv7em-none-eabi
|
target: thumbv7em-none-eabi
|
||||||
|
|||||||
2
.github/workflows/cbor_test.yml
vendored
2
.github/workflows/cbor_test.yml
vendored
@@ -12,6 +12,8 @@ jobs:
|
|||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-18.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: "true"
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
target: thumbv7em-none-eabi
|
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
|
runs-on: ubuntu-18.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: "true"
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
target: thumbv7em-none-eabi
|
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 }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: "true"
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
target: thumbv7em-none-eabi
|
target: thumbv7em-none-eabi
|
||||||
|
|||||||
2
.github/workflows/opensk_test.yml
vendored
2
.github/workflows/opensk_test.yml
vendored
@@ -14,6 +14,8 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: "true"
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
target: thumbv7em-none-eabi
|
target: thumbv7em-none-eabi
|
||||||
|
|||||||
2
.github/workflows/reproducible.yml
vendored
2
.github/workflows/reproducible.yml
vendored
@@ -14,6 +14,8 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: "true"
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
target: thumbv7em-none-eabi
|
target: thumbv7em-none-eabi
|
||||||
|
|||||||
14
Cargo.toml
14
Cargo.toml
@@ -10,7 +10,9 @@ license = "Apache-2.0"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[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" }
|
cbor = { path = "libraries/cbor" }
|
||||||
crypto = { path = "libraries/crypto" }
|
crypto = { path = "libraries/crypto" }
|
||||||
byteorder = { version = "1", default-features = false }
|
byteorder = { version = "1", default-features = false }
|
||||||
@@ -18,12 +20,12 @@ arrayref = "0.3.6"
|
|||||||
subtle = { version = "2.2", default-features = false, features = ["nightly"] }
|
subtle = { version = "2.2", default-features = false, features = ["nightly"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
debug_allocations = ["libtock/debug_allocations"]
|
debug_allocations = ["lang_items/debug_allocations"]
|
||||||
debug_ctap = ["crypto/derive_debug"]
|
debug_ctap = ["crypto/derive_debug", "libtock_drivers/debug_ctap"]
|
||||||
panic_console = ["libtock/panic_console"]
|
panic_console = ["lang_items/panic_console"]
|
||||||
std = ["cbor/std", "crypto/std", "crypto/derive_debug"]
|
std = ["cbor/std", "crypto/std", "crypto/derive_debug", "lang_items/std"]
|
||||||
ram_storage = []
|
ram_storage = []
|
||||||
verbose = ["debug_ctap"]
|
verbose = ["debug_ctap", "libtock_drivers/verbose_usb"]
|
||||||
with_ctap1 = ["crypto/with_ctap1"]
|
with_ctap1 = ["crypto/with_ctap1"]
|
||||||
with_ctap2_1 = []
|
with_ctap2_1 = []
|
||||||
|
|
||||||
|
|||||||
17
deploy.py
17
deploy.py
@@ -373,6 +373,7 @@ class OpenSKInstaller:
|
|||||||
]
|
]
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env["RUSTFLAGS"] = " ".join(rust_flags)
|
env["RUSTFLAGS"] = " ".join(rust_flags)
|
||||||
|
env["APP_HEAP_SIZE"] = str(APP_HEAP_SIZE)
|
||||||
|
|
||||||
command = [
|
command = [
|
||||||
"cargo", "build", "--release", "--target={}".format(props.arch),
|
"cargo", "build", "--release", "--target={}".format(props.arch),
|
||||||
@@ -893,8 +894,22 @@ if __name__ == "__main__":
|
|||||||
dest="application",
|
dest="application",
|
||||||
action="store_const",
|
action="store_const",
|
||||||
const="crypto_bench",
|
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."))
|
"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"])
|
main_parser.set_defaults(features=["with_ctap1"])
|
||||||
|
|
||||||
|
|||||||
@@ -17,24 +17,26 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
extern crate crypto;
|
extern crate crypto;
|
||||||
extern crate libtock;
|
extern crate lang_items;
|
||||||
|
extern crate libtock_drivers;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
use crypto::{
|
use crypto::{
|
||||||
aes256, cbc, ecdsa, rng256, sha256, Decrypt16BytesBlock, Encrypt16BytesBlock, Hash256,
|
aes256, cbc, ecdsa, rng256, sha256, Decrypt16BytesBlock, Encrypt16BytesBlock, Hash256,
|
||||||
};
|
};
|
||||||
use libtock::console::Console;
|
use libtock_drivers::console::Console;
|
||||||
use libtock::timer;
|
use libtock_drivers::result::FlexUnwrap;
|
||||||
use libtock::timer::Timer;
|
use libtock_drivers::timer;
|
||||||
use libtock::timer::Timestamp;
|
use libtock_drivers::timer::Timer;
|
||||||
|
use libtock_drivers::timer::Timestamp;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut console = Console::new();
|
let mut console = Console::new();
|
||||||
// Setup the timer with a dummy callback (we only care about reading the current time, but the
|
// 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).
|
// API forces us to set an alarm callback too).
|
||||||
let mut with_callback = timer::with_callback(|_, _| {});
|
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 {};
|
let mut rng = rng256::TockRng256 {};
|
||||||
|
|
||||||
@@ -158,11 +160,11 @@ where
|
|||||||
writeln!(console, "----------------------------------------").unwrap();
|
writeln!(console, "----------------------------------------").unwrap();
|
||||||
let mut count = 1;
|
let mut count = 1;
|
||||||
for _ in 0..30 {
|
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 {
|
for _ in 0..count {
|
||||||
f();
|
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();
|
let elapsed = (end - start).ms();
|
||||||
writeln!(
|
writeln!(
|
||||||
console,
|
console,
|
||||||
@@ -172,6 +174,7 @@ where
|
|||||||
elapsed / (count as f64)
|
elapsed / (count as f64)
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
console.flush();
|
||||||
if elapsed > 1000.0 {
|
if elapsed > 1000.0 {
|
||||||
break;
|
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!")
|
||||||
|
}
|
||||||
@@ -10,10 +10,10 @@ license = "Apache-2.0"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libtock = { path = "../../third_party/libtock-rs" }
|
libtock_drivers = { path = "../../third_party/libtock-drivers" }
|
||||||
cbor = { path = "../cbor" }
|
cbor = { path = "../cbor" }
|
||||||
arrayref = "0.3.6"
|
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 }
|
byteorder = { version = "1", default-features = false }
|
||||||
hex = { version = "0.3.2", default-features = false, optional = true }
|
hex = { version = "0.3.2", default-features = false, optional = true }
|
||||||
ring = { version = "0.16.11", optional = true }
|
ring = { version = "0.16.11", optional = true }
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ extern crate subtle;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate arrayref;
|
extern crate arrayref;
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate libtock;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate cbor;
|
extern crate cbor;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use libtock::rng;
|
use libtock_drivers::rng;
|
||||||
|
|
||||||
// Lightweight RNG trait to generate uniformly distributed 256 bits.
|
// Lightweight RNG trait to generate uniformly distributed 256 bits.
|
||||||
pub trait Rng256 {
|
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
|
91a98f475cb3042dd5184598a8292edb2a414df8d967a35c8f2295826b5a161b third_party/tock/target/thumbv7em-none-eabi/release/nrf52840dk.bin
|
||||||
9726082139399889fde1d5aa4005596eecd60726201e02a522aa25870109d252 target/nrf52840dk_merged.hex
|
120028d4e4266aff8123db544d99d5d67594c1e7bebdfe3e4172bd20716fb34b target/nrf52840dk_merged.hex
|
||||||
052eec0ae526038352b9f7573468d0cf7fb5ec331d4dc1a2df75fdbd514ea5ca third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin
|
a5943c5311158b0f99370246d37782eb9b12fc36c56387eadb6587a3a4fe8fd5 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin
|
||||||
5cf5599d001a9f7be80132b3e83c2a5e28e9c6a70b79058b266a23527e754d41 target/nrf52840_dongle_merged.hex
|
0aae44b66ed6c8a134809446e95efb3d276182823db20755d0b45baa7cfd6efd target/nrf52840_dongle_merged.hex
|
||||||
908d7f4f40936d968b91ab6e19b2406612fe8c2c273d9c0b71ef1f55116780e0 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle_dfu.bin
|
663297e3e29b9e2a972b68cea1592aaf965d797242579bb5bca09cd73cdfb637 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle_dfu.bin
|
||||||
69524a8538ae65637dfaf8709b9cfb4730858dea56d96ae304163d6f5d0dabe0 target/nrf52840_dongle_dfu_merged.hex
|
fadd8a863c8828ceb18a8e3224fedc32261befb5af3b04dfd7cc3d9bccc6cc64 target/nrf52840_dongle_dfu_merged.hex
|
||||||
34ecbecaebf1188277f2310fe769c8c60310d8576493242712854deb4ba1036e third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_mdk_dfu.bin
|
162a05d056aafc16d4868d5c3aa10518e41299dddd60608f96954dc9cf964cd3 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_mdk_dfu.bin
|
||||||
276bec775183524eb7dbbd107416d90dbadb853771deaa8f49f1baf9d0f216e1 target/nrf52840_mdk_dfu_merged.hex
|
2495d4aa2f86da9308b1024490513272294e3cb2652d366a56de13dcd92bc1d1 target/nrf52840_mdk_dfu_merged.hex
|
||||||
8e7ad6778dbb86e13613a30487c41b9086f7fe55dc0db234968eb52750b8a94c target/tab/ctap2.tab
|
e0ed5715b4df3850d6899e158fef24052cc056f641083950094afbf0aa8c5cd5 target/tab/ctap2.tab
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
29382e72d0f3c6a72ce9517211952ff29ea270193d7f0ddc48ca69009ee29925 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840dk.bin
|
3feb5d29a3d669107b460a00391440be4ebc5e50461f9ef3248714f4f99c070e third_party/tock/target/thumbv7em-none-eabi/release/nrf52840dk.bin
|
||||||
f48b98125b06b81ba3c62657bfd9aee9c2b81a1307173d2a73f110f7cdb29513 target/nrf52840dk_merged.hex
|
3c4dde09e8e6082a15bbf9d9eedd12de63f70d85c240292aea246f2d83c54f07 target/nrf52840dk_merged.hex
|
||||||
30f239390ae9bef0825731e4c82d40470fc5e9bded2bf0d942e92dbb5d4faba1 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin
|
8eebe1c1dfe22003466c2570b3735c54c58ae91b8168582ad363ab79c9230a15 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin
|
||||||
97f0998c06c622c92a4504b6f416f548e5b47a1a9b592c6a98ca338450990419 target/nrf52840_dongle_merged.hex
|
a5e4ce40777ca4de31377bd60dddb92da172afef6ddcbc48c58f43b77809ac26 target/nrf52840_dongle_merged.hex
|
||||||
e3acf15d5ae3a22aecff6cc58db5fc311f538f47328d348b7ad7db7f9ab5e72c third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle_dfu.bin
|
779d77071d1e629f92210ac313e230bcaea6d77c710210c1ac4b40f8085cdad7 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle_dfu.bin
|
||||||
bf5a5745d76eeeb38908f6179d5ba07ac2578dd1b55f95e9440cdf893d850ffc target/nrf52840_dongle_dfu_merged.hex
|
ccacb03f5140bb334843a42d40e9ad3ec56bbf76fdac023bd8d1c9457dc5c228 target/nrf52840_dongle_dfu_merged.hex
|
||||||
cae312a26a513ada6c198fdc59b2bba3860c51726b817a9fd17a4331ee12c882 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_mdk_dfu.bin
|
f466490d6498f6c06c7c4a717eb437ba2fb06d1985532c23f145d38b9daa8259 third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_mdk_dfu.bin
|
||||||
6b2da0ff3af55e7fe86177a8d795baab3752a59c55bf0bb0af2fcfec1c983e57 target/nrf52840_mdk_dfu_merged.hex
|
a165294acddacd95747d064aff4ecf37654bfa107df49151dbbaf25907468ab4 target/nrf52840_mdk_dfu_merged.hex
|
||||||
26706e2fefe6894ffbaa0681454aeda24c69d8aeb5289f8c0e4428cdc7c4fc59 target/tab/ctap2.tab
|
54074445657b1842d8c005bb94897c6a60d76c6bfc9b6f9cecac930d3485b930 target/tab/ctap2.tab
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
========================================
|
========================================
|
||||||
Board: nrf52840dk
|
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
|
Number of writeable flash regions: 0
|
||||||
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
||||||
Entry point is in .text section
|
Entry point is in .text section
|
||||||
Adding .text section. Offset: 128 (0x80). Length: 179332 (0x2bc84) bytes.
|
Adding .text section. Offset: 128 (0x80). Length: 187792 (0x2dd90) bytes.
|
||||||
Adding .stack section. Offset: 179460 (0x2bd04). Length: 16384 (0x4000) bytes.
|
Adding .stack section. Offset: 187920 (0x2de10). Length: 16384 (0x4000) bytes.
|
||||||
Searching for .rel.X sections to add.
|
Searching for .rel.X sections to add.
|
||||||
TBF Header:
|
TBF Header:
|
||||||
version: 2 0x2
|
version: 2 0x2
|
||||||
@@ -16,16 +16,16 @@ TBF Header:
|
|||||||
|
|
||||||
init_fn_offset: 85 0x55
|
init_fn_offset: 85 0x55
|
||||||
protected_size: 20 0x14
|
protected_size: 20 0x14
|
||||||
minimum_ram_size: 107424 0x1A3A0
|
minimum_ram_size: 107428 0x1A3A4
|
||||||
========================================
|
========================================
|
||||||
Board: nrf52840_dongle
|
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
|
Number of writeable flash regions: 0
|
||||||
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
||||||
Entry point is in .text section
|
Entry point is in .text section
|
||||||
Adding .text section. Offset: 128 (0x80). Length: 179332 (0x2bc84) bytes.
|
Adding .text section. Offset: 128 (0x80). Length: 187792 (0x2dd90) bytes.
|
||||||
Adding .stack section. Offset: 179460 (0x2bd04). Length: 16384 (0x4000) bytes.
|
Adding .stack section. Offset: 187920 (0x2de10). Length: 16384 (0x4000) bytes.
|
||||||
Searching for .rel.X sections to add.
|
Searching for .rel.X sections to add.
|
||||||
TBF Header:
|
TBF Header:
|
||||||
version: 2 0x2
|
version: 2 0x2
|
||||||
@@ -35,16 +35,16 @@ TBF Header:
|
|||||||
|
|
||||||
init_fn_offset: 85 0x55
|
init_fn_offset: 85 0x55
|
||||||
protected_size: 20 0x14
|
protected_size: 20 0x14
|
||||||
minimum_ram_size: 107424 0x1A3A0
|
minimum_ram_size: 107428 0x1A3A4
|
||||||
========================================
|
========================================
|
||||||
Board: nrf52840_dongle_dfu
|
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
|
Number of writeable flash regions: 0
|
||||||
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
||||||
Entry point is in .text section
|
Entry point is in .text section
|
||||||
Adding .text section. Offset: 128 (0x80). Length: 179332 (0x2bc84) bytes.
|
Adding .text section. Offset: 128 (0x80). Length: 187792 (0x2dd90) bytes.
|
||||||
Adding .stack section. Offset: 179460 (0x2bd04). Length: 16384 (0x4000) bytes.
|
Adding .stack section. Offset: 187920 (0x2de10). Length: 16384 (0x4000) bytes.
|
||||||
Searching for .rel.X sections to add.
|
Searching for .rel.X sections to add.
|
||||||
TBF Header:
|
TBF Header:
|
||||||
version: 2 0x2
|
version: 2 0x2
|
||||||
@@ -54,16 +54,16 @@ TBF Header:
|
|||||||
|
|
||||||
init_fn_offset: 85 0x55
|
init_fn_offset: 85 0x55
|
||||||
protected_size: 20 0x14
|
protected_size: 20 0x14
|
||||||
minimum_ram_size: 107424 0x1A3A0
|
minimum_ram_size: 107428 0x1A3A4
|
||||||
========================================
|
========================================
|
||||||
Board: nrf52840_mdk_dfu
|
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
|
Number of writeable flash regions: 0
|
||||||
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
||||||
Entry point is in .text section
|
Entry point is in .text section
|
||||||
Adding .text section. Offset: 128 (0x80). Length: 179332 (0x2bc84) bytes.
|
Adding .text section. Offset: 128 (0x80). Length: 187792 (0x2dd90) bytes.
|
||||||
Adding .stack section. Offset: 179460 (0x2bd04). Length: 16384 (0x4000) bytes.
|
Adding .stack section. Offset: 187920 (0x2de10). Length: 16384 (0x4000) bytes.
|
||||||
Searching for .rel.X sections to add.
|
Searching for .rel.X sections to add.
|
||||||
TBF Header:
|
TBF Header:
|
||||||
version: 2 0x2
|
version: 2 0x2
|
||||||
@@ -73,4 +73,4 @@ TBF Header:
|
|||||||
|
|
||||||
init_fn_offset: 85 0x55
|
init_fn_offset: 85 0x55
|
||||||
protected_size: 20 0x14
|
protected_size: 20 0x14
|
||||||
minimum_ram_size: 107424 0x1A3A0
|
minimum_ram_size: 107428 0x1A3A4
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
========================================
|
========================================
|
||||||
Board: nrf52840dk
|
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
|
Number of writeable flash regions: 0
|
||||||
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
||||||
Entry point is in .text section
|
Entry point is in .text section
|
||||||
Adding .text section. Offset: 128 (0x80). Length: 178788 (0x2ba64) bytes.
|
Adding .text section. Offset: 128 (0x80). Length: 187752 (0x2dd68) bytes.
|
||||||
Adding .stack section. Offset: 178916 (0x2bae4). Length: 16384 (0x4000) bytes.
|
Adding .stack section. Offset: 187880 (0x2dde8). Length: 16384 (0x4000) bytes.
|
||||||
Searching for .rel.X sections to add.
|
Searching for .rel.X sections to add.
|
||||||
TBF Header:
|
TBF Header:
|
||||||
version: 2 0x2
|
version: 2 0x2
|
||||||
@@ -16,16 +16,16 @@ TBF Header:
|
|||||||
|
|
||||||
init_fn_offset: 85 0x55
|
init_fn_offset: 85 0x55
|
||||||
protected_size: 20 0x14
|
protected_size: 20 0x14
|
||||||
minimum_ram_size: 107424 0x1A3A0
|
minimum_ram_size: 107428 0x1A3A4
|
||||||
========================================
|
========================================
|
||||||
Board: nrf52840_dongle
|
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
|
Number of writeable flash regions: 0
|
||||||
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
||||||
Entry point is in .text section
|
Entry point is in .text section
|
||||||
Adding .text section. Offset: 128 (0x80). Length: 178788 (0x2ba64) bytes.
|
Adding .text section. Offset: 128 (0x80). Length: 187752 (0x2dd68) bytes.
|
||||||
Adding .stack section. Offset: 178916 (0x2bae4). Length: 16384 (0x4000) bytes.
|
Adding .stack section. Offset: 187880 (0x2dde8). Length: 16384 (0x4000) bytes.
|
||||||
Searching for .rel.X sections to add.
|
Searching for .rel.X sections to add.
|
||||||
TBF Header:
|
TBF Header:
|
||||||
version: 2 0x2
|
version: 2 0x2
|
||||||
@@ -35,16 +35,16 @@ TBF Header:
|
|||||||
|
|
||||||
init_fn_offset: 85 0x55
|
init_fn_offset: 85 0x55
|
||||||
protected_size: 20 0x14
|
protected_size: 20 0x14
|
||||||
minimum_ram_size: 107424 0x1A3A0
|
minimum_ram_size: 107428 0x1A3A4
|
||||||
========================================
|
========================================
|
||||||
Board: nrf52840_dongle_dfu
|
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
|
Number of writeable flash regions: 0
|
||||||
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
||||||
Entry point is in .text section
|
Entry point is in .text section
|
||||||
Adding .text section. Offset: 128 (0x80). Length: 178788 (0x2ba64) bytes.
|
Adding .text section. Offset: 128 (0x80). Length: 187752 (0x2dd68) bytes.
|
||||||
Adding .stack section. Offset: 178916 (0x2bae4). Length: 16384 (0x4000) bytes.
|
Adding .stack section. Offset: 187880 (0x2dde8). Length: 16384 (0x4000) bytes.
|
||||||
Searching for .rel.X sections to add.
|
Searching for .rel.X sections to add.
|
||||||
TBF Header:
|
TBF Header:
|
||||||
version: 2 0x2
|
version: 2 0x2
|
||||||
@@ -54,16 +54,16 @@ TBF Header:
|
|||||||
|
|
||||||
init_fn_offset: 85 0x55
|
init_fn_offset: 85 0x55
|
||||||
protected_size: 20 0x14
|
protected_size: 20 0x14
|
||||||
minimum_ram_size: 107424 0x1A3A0
|
minimum_ram_size: 107428 0x1A3A4
|
||||||
========================================
|
========================================
|
||||||
Board: nrf52840_mdk_dfu
|
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
|
Number of writeable flash regions: 0
|
||||||
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
Adding .crt0_header section. Offset: 64 (0x40). Length: 64 (0x40) bytes.
|
||||||
Entry point is in .text section
|
Entry point is in .text section
|
||||||
Adding .text section. Offset: 128 (0x80). Length: 178788 (0x2ba64) bytes.
|
Adding .text section. Offset: 128 (0x80). Length: 187752 (0x2dd68) bytes.
|
||||||
Adding .stack section. Offset: 178916 (0x2bae4). Length: 16384 (0x4000) bytes.
|
Adding .stack section. Offset: 187880 (0x2dde8). Length: 16384 (0x4000) bytes.
|
||||||
Searching for .rel.X sections to add.
|
Searching for .rel.X sections to add.
|
||||||
TBF Header:
|
TBF Header:
|
||||||
version: 2 0x2
|
version: 2 0x2
|
||||||
@@ -73,4 +73,4 @@ TBF Header:
|
|||||||
|
|
||||||
init_fn_offset: 85 0x55
|
init_fn_offset: 85 0x55
|
||||||
protected_size: 20 0x14
|
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
|
||||||
|
#)
|
||||||
54
setup.sh
54
setup.sh
@@ -19,6 +19,9 @@ done_text="$(tput bold)DONE.$(tput sgr0)"
|
|||||||
|
|
||||||
set -e
|
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 that rustup and pip3 are installed
|
||||||
check_command () {
|
check_command () {
|
||||||
if ! which "$1" >/dev/null
|
if ! which "$1" >/dev/null
|
||||||
@@ -30,57 +33,6 @@ check_command () {
|
|||||||
check_command rustup " Follow the steps under https://rustup.rs/ to install it."
|
check_command rustup " Follow the steps under https://rustup.rs/ to install it."
|
||||||
check_command pip3
|
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
|
# Ensure we have certificates, keys, etc. so that the tests can run
|
||||||
source tools/gen_key_materials.sh
|
source tools/gen_key_materials.sh
|
||||||
generate_crypto_materials N
|
generate_crypto_materials N
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ use alloc::vec::Vec;
|
|||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
use crypto::rng256::Rng256;
|
use crypto::rng256::Rng256;
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
use libtock::console::Console;
|
use libtock_drivers::console::Console;
|
||||||
|
|
||||||
// CTAP specification (version 20190130) section 8.1
|
// CTAP specification (version 20190130) section 8.1
|
||||||
// TODO: Channel allocation, section 8.1.3?
|
// TODO: Channel allocation, section 8.1.3?
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ use crypto::rng256::Rng256;
|
|||||||
use crypto::sha256::Sha256;
|
use crypto::sha256::Sha256;
|
||||||
use crypto::Hash256;
|
use crypto::Hash256;
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
use libtock::console::Console;
|
use libtock_drivers::console::Console;
|
||||||
use libtock::timer::{Duration, Timestamp};
|
use libtock_drivers::timer::{Duration, Timestamp};
|
||||||
use subtle::ConstantTimeEq;
|
use subtle::ConstantTimeEq;
|
||||||
|
|
||||||
// This flag enables or disables basic attestation for FIDO2. U2F is unaffected by
|
// This flag enables or disables basic attestation for FIDO2. U2F is unaffected by
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
use super::{Index, Storage, StorageError, StorageResult};
|
use super::{Index, Storage, StorageError, StorageResult};
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use libtock::syscalls;
|
use libtock_core::syscalls;
|
||||||
|
|
||||||
const DRIVER_NUMBER: usize = 0x50003;
|
const DRIVER_NUMBER: usize = 0x50003;
|
||||||
|
|
||||||
@@ -41,16 +41,14 @@ mod memop_nr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_info(nr: usize, arg: usize) -> StorageResult<usize> {
|
fn get_info(nr: usize, arg: usize) -> StorageResult<usize> {
|
||||||
let code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::GET_INFO, nr, arg) };
|
let code = syscalls::command(DRIVER_NUMBER, command_nr::GET_INFO, nr, arg);
|
||||||
if code < 0 {
|
code.map_err(|e| StorageError::KernelError {
|
||||||
Err(StorageError::KernelError { code })
|
code: e.return_code,
|
||||||
} else {
|
})
|
||||||
Ok(code as usize)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn memop(nr: u32, arg: usize) -> StorageResult<usize> {
|
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 {
|
if code < 0 {
|
||||||
Err(StorageError::KernelError { code })
|
Err(StorageError::KernelError { code })
|
||||||
} else {
|
} else {
|
||||||
@@ -153,8 +151,9 @@ impl Storage for SyscallStorage {
|
|||||||
return Err(StorageError::NotAligned);
|
return Err(StorageError::NotAligned);
|
||||||
}
|
}
|
||||||
let ptr = self.read_slice(index, value.len())?.as_ptr() as usize;
|
let ptr = self.read_slice(index, value.len())?.as_ptr() as usize;
|
||||||
|
|
||||||
let code = unsafe {
|
let code = unsafe {
|
||||||
syscalls::allow_ptr(
|
syscalls::raw::allow(
|
||||||
DRIVER_NUMBER,
|
DRIVER_NUMBER,
|
||||||
allow_nr::WRITE_SLICE,
|
allow_nr::WRITE_SLICE,
|
||||||
// We rely on the driver not writing to the slice. This should use read-only allow
|
// 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 {
|
if code < 0 {
|
||||||
return Err(StorageError::KernelError { code });
|
return Err(StorageError::KernelError { code });
|
||||||
}
|
}
|
||||||
let code =
|
|
||||||
unsafe { syscalls::command(DRIVER_NUMBER, command_nr::WRITE_SLICE, ptr, value.len()) };
|
let code = syscalls::command(DRIVER_NUMBER, command_nr::WRITE_SLICE, ptr, value.len());
|
||||||
if code < 0 {
|
if let Err(e) = code {
|
||||||
return Err(StorageError::KernelError { code });
|
return Err(StorageError::KernelError {
|
||||||
|
code: e.return_code,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,9 +180,11 @@ impl Storage for SyscallStorage {
|
|||||||
let index = Index { page, byte: 0 };
|
let index = Index { page, byte: 0 };
|
||||||
let length = self.page_size();
|
let length = self.page_size();
|
||||||
let ptr = self.read_slice(index, length)?.as_ptr() as usize;
|
let ptr = self.read_slice(index, length)?.as_ptr() as usize;
|
||||||
let code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::ERASE_PAGE, ptr, length) };
|
let code = syscalls::command(DRIVER_NUMBER, command_nr::ERASE_PAGE, ptr, length);
|
||||||
if code < 0 {
|
if let Err(e) = code {
|
||||||
return Err(StorageError::KernelError { code });
|
return Err(StorageError::KernelError {
|
||||||
|
code: e.return_code,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
extern crate libtock;
|
extern crate lang_items;
|
||||||
|
extern crate libtock_core;
|
||||||
|
extern crate libtock_drivers;
|
||||||
|
|
||||||
pub mod embedded_flash;
|
pub mod embedded_flash;
|
||||||
|
|||||||
85
src/main.rs
85
src/main.rs
@@ -22,14 +22,12 @@ extern crate byteorder;
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
extern crate core;
|
extern crate core;
|
||||||
extern crate ctap2;
|
extern crate ctap2;
|
||||||
extern crate libtock;
|
|
||||||
extern crate subtle;
|
extern crate subtle;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate cbor;
|
extern crate cbor;
|
||||||
extern crate crypto;
|
extern crate crypto;
|
||||||
|
|
||||||
mod ctap;
|
mod ctap;
|
||||||
mod usb_ctap_hid;
|
|
||||||
|
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
@@ -38,17 +36,18 @@ use crypto::rng256::TockRng256;
|
|||||||
use ctap::hid::{ChannelID, CtapHid, KeepaliveStatus, ProcessedPacket};
|
use ctap::hid::{ChannelID, CtapHid, KeepaliveStatus, ProcessedPacket};
|
||||||
use ctap::status_code::Ctap2StatusCode;
|
use ctap::status_code::Ctap2StatusCode;
|
||||||
use ctap::CtapState;
|
use ctap::CtapState;
|
||||||
use libtock::buttons;
|
use libtock_core::result::{CommandError, EALREADY};
|
||||||
use libtock::buttons::ButtonState;
|
use libtock_drivers::buttons;
|
||||||
|
use libtock_drivers::buttons::ButtonState;
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
use libtock::console::Console;
|
use libtock_drivers::console::Console;
|
||||||
use libtock::led;
|
use libtock_drivers::led;
|
||||||
use libtock::result::TockValue;
|
use libtock_drivers::result::{FlexUnwrap, TockError};
|
||||||
use libtock::syscalls;
|
use libtock_drivers::timer;
|
||||||
use libtock::timer;
|
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
use libtock::timer::Timer;
|
use libtock_drivers::timer::Timer;
|
||||||
use libtock::timer::{Duration, StopAlarmError, Timestamp};
|
use libtock_drivers::timer::{Duration, Timestamp};
|
||||||
|
use libtock_drivers::usb_ctap_hid;
|
||||||
|
|
||||||
const KEEPALIVE_DELAY_MS: isize = 100;
|
const KEEPALIVE_DELAY_MS: isize = 100;
|
||||||
const KEEPALIVE_DELAY: Duration<isize> = Duration::from_ms(KEEPALIVE_DELAY_MS);
|
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
|
// 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).
|
// API forces us to set an alarm callback too).
|
||||||
let mut with_callback = timer::with_callback(|_, _| {});
|
let mut with_callback = timer::with_callback(|_, _| {});
|
||||||
let timer = with_callback.init().unwrap();
|
let timer = with_callback.init().flex_unwrap();
|
||||||
|
|
||||||
// Setup USB driver.
|
// Setup USB driver.
|
||||||
if !usb_ctap_hid::setup() {
|
if !usb_ctap_hid::setup() {
|
||||||
@@ -70,7 +69,7 @@ fn main() {
|
|||||||
let mut ctap_hid = CtapHid::new();
|
let mut ctap_hid = CtapHid::new();
|
||||||
|
|
||||||
let mut led_counter = 0;
|
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.
|
// 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,
|
// The way TockOS and apps currently interact, callbacks need a yield syscall to execute,
|
||||||
@@ -87,11 +86,11 @@ fn main() {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
#[cfg(feature = "with_ctap1")]
|
#[cfg(feature = "with_ctap1")]
|
||||||
let mut buttons = buttons_callback.init().unwrap();
|
let mut buttons = buttons_callback.init().flex_unwrap();
|
||||||
#[cfg(feature = "with_ctap1")]
|
#[cfg(feature = "with_ctap1")]
|
||||||
// At the moment, all buttons are accepted. You can customize your setup here.
|
// At the moment, all buttons are accepted. You can customize your setup here.
|
||||||
for mut button in &mut buttons {
|
for mut button in &mut buttons {
|
||||||
button.enable().unwrap();
|
button.enable().flex_unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut pkt_request = [0; 64];
|
let mut pkt_request = [0; 64];
|
||||||
@@ -105,7 +104,7 @@ fn main() {
|
|||||||
None => false,
|
None => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let now = timer.get_current_clock();
|
let now = timer.get_current_clock().flex_unwrap();
|
||||||
#[cfg(feature = "with_ctap1")]
|
#[cfg(feature = "with_ctap1")]
|
||||||
{
|
{
|
||||||
if button_touched.get() {
|
if button_touched.get() {
|
||||||
@@ -115,7 +114,7 @@ fn main() {
|
|||||||
// Heavy computation mostly follows a registered touch luckily. Unregistering
|
// Heavy computation mostly follows a registered touch luckily. Unregistering
|
||||||
// callbacks is important to not clash with those from check_user_presence.
|
// callbacks is important to not clash with those from check_user_presence.
|
||||||
for mut button in &mut buttons {
|
for mut button in &mut buttons {
|
||||||
button.disable().unwrap();
|
button.disable().flex_unwrap();
|
||||||
}
|
}
|
||||||
drop(buttons);
|
drop(buttons);
|
||||||
drop(buttons_callback);
|
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 let Some(wait_duration) = now.wrapping_sub(last_led_increment) {
|
||||||
if wait_duration > KEEPALIVE_DELAY {
|
if wait_duration > KEEPALIVE_DELAY {
|
||||||
// Loops quickly when waiting for U2F user presence, so the next LED blink
|
// Loops quickly when waiting for U2F user presence, so the next LED blink
|
||||||
@@ -188,8 +187,8 @@ fn main() {
|
|||||||
|
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
fn print_packet_notice(notice_text: &str, timer: &Timer) {
|
fn print_packet_notice(notice_text: &str, timer: &Timer) {
|
||||||
let now_us =
|
let now = timer.get_current_clock().flex_unwrap();
|
||||||
(Timestamp::<f64>::from_clock_value(timer.get_current_clock()).ms() * 1000.0) as u64;
|
let now_us = (Timestamp::<f64>::from_clock_value(now).ms() * 1000.0) as u64;
|
||||||
writeln!(
|
writeln!(
|
||||||
Console::new(),
|
Console::new(),
|
||||||
"{} at {}.{:06} s",
|
"{} at {}.{:06} s",
|
||||||
@@ -264,17 +263,17 @@ fn send_keepalive_up_needed(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blink_leds(pattern_seed: isize) {
|
fn blink_leds(pattern_seed: usize) {
|
||||||
for l in 0..led::count() {
|
for l in 0..led::count().flex_unwrap() {
|
||||||
if (pattern_seed ^ l).count_ones() & 1 != 0 {
|
if (pattern_seed ^ l).count_ones() & 1 != 0 {
|
||||||
led::get(l).unwrap().on();
|
led::get(l).flex_unwrap().on().flex_unwrap();
|
||||||
} else {
|
} 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.
|
// This generates a "snake" pattern circling through the LEDs.
|
||||||
// Fox example with 4 LEDs the sequence of lit LEDs will be the following.
|
// Fox example with 4 LEDs the sequence of lit LEDs will be the following.
|
||||||
// 0 1 2 3
|
// 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 a = (pattern_seed / 2) % count;
|
||||||
let b = ((pattern_seed + 1) / 2) % count;
|
let b = ((pattern_seed + 1) / 2) % count;
|
||||||
let c = ((pattern_seed + 3) / 2) % count;
|
let c = ((pattern_seed + 3) / 2) % count;
|
||||||
@@ -300,22 +299,22 @@ fn wink_leds(pattern_seed: isize) {
|
|||||||
_ => l,
|
_ => l,
|
||||||
};
|
};
|
||||||
if k == a || k == b || k == c {
|
if k == a || k == b || k == c {
|
||||||
led::get(l).unwrap().on();
|
led::get(l).flex_unwrap().on().flex_unwrap();
|
||||||
} else {
|
} else {
|
||||||
led::get(l).unwrap().off();
|
led::get(l).flex_unwrap().off().flex_unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn switch_off_leds() {
|
fn switch_off_leds() {
|
||||||
for l in 0..led::count() {
|
for l in 0..led::count().flex_unwrap() {
|
||||||
led::get(l).unwrap().off();
|
led::get(l).flex_unwrap().off().flex_unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_user_presence(cid: ChannelID) -> Result<(), Ctap2StatusCode> {
|
fn check_user_presence(cid: ChannelID) -> Result<(), Ctap2StatusCode> {
|
||||||
// The timeout is N times the keepalive delay.
|
// 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.
|
// First, send a keep-alive packet to notify that the keep-alive status has changed.
|
||||||
send_keepalive_up_needed(cid, KEEPALIVE_DELAY)?;
|
send_keepalive_up_needed(cid, KEEPALIVE_DELAY)?;
|
||||||
@@ -328,10 +327,10 @@ fn check_user_presence(cid: ChannelID) -> Result<(), Ctap2StatusCode> {
|
|||||||
ButtonState::Released => (),
|
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.
|
// At the moment, all buttons are accepted. You can customize your setup here.
|
||||||
for mut button in &mut buttons {
|
for mut button in &mut buttons {
|
||||||
button.enable().unwrap();
|
button.enable().flex_unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut keepalive_response = Ok(());
|
let mut keepalive_response = Ok(());
|
||||||
@@ -343,19 +342,25 @@ fn check_user_presence(cid: ChannelID) -> Result<(), Ctap2StatusCode> {
|
|||||||
let mut keepalive_callback = timer::with_callback(|_, _| {
|
let mut keepalive_callback = timer::with_callback(|_, _| {
|
||||||
keepalive_expired.set(true);
|
keepalive_expired.set(true);
|
||||||
});
|
});
|
||||||
let mut keepalive = keepalive_callback.init().unwrap();
|
let mut keepalive = keepalive_callback.init().flex_unwrap();
|
||||||
let keepalive_alarm = keepalive.set_alarm(KEEPALIVE_DELAY).unwrap();
|
let keepalive_alarm = keepalive.set_alarm(KEEPALIVE_DELAY).flex_unwrap();
|
||||||
|
|
||||||
// Wait for a button touch or an alarm.
|
// 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.
|
// Cleanup alarm callback.
|
||||||
match keepalive.stop_alarm(keepalive_alarm) {
|
match keepalive.stop_alarm(keepalive_alarm) {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
Err(TockValue::Expected(StopAlarmError::AlreadyDisabled)) => {
|
Err(TockError::Command(CommandError {
|
||||||
assert!(keepalive_expired.get())
|
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,
|
// 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.
|
// Cleanup button callbacks.
|
||||||
for mut button in &mut buttons {
|
for mut button in &mut buttons {
|
||||||
button.disable().unwrap();
|
button.disable().flex_unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns whether the user was present.
|
// 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
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// 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;
|
use core::cell::Cell;
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
#[cfg(feature = "debug_ctap")]
|
use libtock_core::result::{CommandError, EALREADY, EBUSY, SUCCESS};
|
||||||
use libtock::console::Console;
|
use libtock_core::{callback, syscalls};
|
||||||
use libtock::result::TockValue;
|
|
||||||
use libtock::result::{EALREADY, EBUSY, SUCCESS};
|
|
||||||
use libtock::syscalls;
|
|
||||||
use libtock::timer;
|
|
||||||
use libtock::timer::{Duration, StopAlarmError};
|
|
||||||
|
|
||||||
const DRIVER_NUMBER: usize = 0x20009;
|
const DRIVER_NUMBER: usize = 0x20009;
|
||||||
|
|
||||||
@@ -51,13 +52,13 @@ mod allow_nr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup() -> bool {
|
pub fn setup() -> bool {
|
||||||
let result = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::CHECK, 0, 0) };
|
let result = syscalls::command(DRIVER_NUMBER, command_nr::CHECK, 0, 0);
|
||||||
if result != 0 {
|
if result.is_err() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::CONNECT, 0, 0) };
|
let result = syscalls::command(DRIVER_NUMBER, command_nr::CONNECT, 0, 0);
|
||||||
if result != 0 {
|
if result.is_err() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,18 +73,22 @@ pub fn recv(buf: &mut [u8; 64]) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let done = Cell::new(false);
|
let done = Cell::new(false);
|
||||||
let mut alarm = |_, _, _| done.set(true);
|
let mut alarm = || done.set(true);
|
||||||
let subscription = syscalls::subscribe(DRIVER_NUMBER, subscribe_nr::RECEIVE, &mut alarm);
|
let subscription = syscalls::subscribe::<callback::Identity0Consumer, _>(
|
||||||
|
DRIVER_NUMBER,
|
||||||
|
subscribe_nr::RECEIVE,
|
||||||
|
&mut alarm,
|
||||||
|
);
|
||||||
if subscription.is_err() {
|
if subscription.is_err() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let result_code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::RECEIVE, 0, 0) };
|
let result_code = syscalls::command(DRIVER_NUMBER, command_nr::RECEIVE, 0, 0);
|
||||||
if result_code != 0 {
|
if result_code.is_err() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
syscalls::yieldk_for(|| done.get());
|
util::yieldk_for(|| done.get());
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,18 +100,22 @@ pub fn send(buf: &mut [u8; 64]) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let done = Cell::new(false);
|
let done = Cell::new(false);
|
||||||
let mut alarm = |_, _, _| done.set(true);
|
let mut alarm = || done.set(true);
|
||||||
let subscription = syscalls::subscribe(DRIVER_NUMBER, subscribe_nr::TRANSMIT, &mut alarm);
|
let subscription = syscalls::subscribe::<callback::Identity0Consumer, _>(
|
||||||
|
DRIVER_NUMBER,
|
||||||
|
subscribe_nr::TRANSMIT,
|
||||||
|
&mut alarm,
|
||||||
|
);
|
||||||
if subscription.is_err() {
|
if subscription.is_err() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let result_code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT, 0, 0) };
|
let result_code = syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT, 0, 0);
|
||||||
if result_code != 0 {
|
if result_code.is_err() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
syscalls::yieldk_for(|| done.get());
|
util::yieldk_for(|| done.get());
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +144,7 @@ pub fn send_or_recv(buf: &mut [u8; 64]) -> SendOrRecvStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let status = Cell::new(None);
|
let status = Cell::new(None);
|
||||||
let mut alarm = |direction, _, _| {
|
let mut alarm = |direction| {
|
||||||
status.set(Some(match direction {
|
status.set(Some(match direction {
|
||||||
subscribe_nr::callback_status::TRANSMITTED => SendOrRecvStatus::Sent,
|
subscribe_nr::callback_status::TRANSMITTED => SendOrRecvStatus::Sent,
|
||||||
subscribe_nr::callback_status::RECEIVED => SendOrRecvStatus::Received,
|
subscribe_nr::callback_status::RECEIVED => SendOrRecvStatus::Received,
|
||||||
@@ -144,19 +153,21 @@ pub fn send_or_recv(buf: &mut [u8; 64]) -> SendOrRecvStatus {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
let subscription =
|
let subscription = syscalls::subscribe::<callback::Identity1Consumer, _>(
|
||||||
syscalls::subscribe(DRIVER_NUMBER, subscribe_nr::TRANSMIT_OR_RECEIVE, &mut alarm);
|
DRIVER_NUMBER,
|
||||||
|
subscribe_nr::TRANSMIT_OR_RECEIVE,
|
||||||
|
&mut alarm,
|
||||||
|
);
|
||||||
if subscription.is_err() {
|
if subscription.is_err() {
|
||||||
return SendOrRecvStatus::Error;
|
return SendOrRecvStatus::Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
let result_code =
|
let result_code = syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT_OR_RECEIVE, 0, 0);
|
||||||
unsafe { syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT_OR_RECEIVE, 0, 0) };
|
if result_code.is_err() {
|
||||||
if result_code != 0 {
|
|
||||||
return SendOrRecvStatus::Error;
|
return SendOrRecvStatus::Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
syscalls::yieldk_for(|| status.get().is_some());
|
util::yieldk_for(|| status.get().is_some());
|
||||||
status.get().unwrap()
|
status.get().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +177,7 @@ pub fn recv_with_timeout(
|
|||||||
buf: &mut [u8; 64],
|
buf: &mut [u8; 64],
|
||||||
timeout_delay: Duration<isize>,
|
timeout_delay: Duration<isize>,
|
||||||
) -> Option<SendOrRecvStatus> {
|
) -> Option<SendOrRecvStatus> {
|
||||||
#[cfg(feature = "verbose")]
|
#[cfg(feature = "verbose_usb")]
|
||||||
writeln!(
|
writeln!(
|
||||||
Console::new(),
|
Console::new(),
|
||||||
"Receiving packet with timeout of {}ms",
|
"Receiving packet with timeout of {}ms",
|
||||||
@@ -176,7 +187,7 @@ pub fn recv_with_timeout(
|
|||||||
|
|
||||||
let result = recv_with_timeout_detail(buf, timeout_delay);
|
let result = recv_with_timeout_detail(buf, timeout_delay);
|
||||||
|
|
||||||
#[cfg(feature = "verbose")]
|
#[cfg(feature = "verbose_usb")]
|
||||||
{
|
{
|
||||||
if let Some(SendOrRecvStatus::Received) = result {
|
if let Some(SendOrRecvStatus::Received) = result {
|
||||||
writeln!(Console::new(), "Received packet = {:02x?}", buf as &[u8]).unwrap();
|
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],
|
buf: &mut [u8; 64],
|
||||||
timeout_delay: Duration<isize>,
|
timeout_delay: Duration<isize>,
|
||||||
) -> Option<SendOrRecvStatus> {
|
) -> Option<SendOrRecvStatus> {
|
||||||
#[cfg(feature = "verbose")]
|
#[cfg(feature = "verbose_usb")]
|
||||||
writeln!(
|
writeln!(
|
||||||
Console::new(),
|
Console::new(),
|
||||||
"Sending packet with timeout of {}ms = {:02x?}",
|
"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);
|
let result = send_or_recv_with_timeout_detail(buf, timeout_delay);
|
||||||
|
|
||||||
#[cfg(feature = "verbose")]
|
#[cfg(feature = "verbose_usb")]
|
||||||
{
|
{
|
||||||
if let Some(SendOrRecvStatus::Received) = result {
|
if let Some(SendOrRecvStatus::Received) = result {
|
||||||
writeln!(Console::new(), "Received packet = {:02x?}", buf as &[u8]).unwrap();
|
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 status = Cell::new(None);
|
||||||
let mut alarm = |direction, _, _| {
|
let mut alarm = |direction| {
|
||||||
status.set(Some(match direction {
|
status.set(Some(match direction {
|
||||||
subscribe_nr::callback_status::RECEIVED => SendOrRecvStatus::Received,
|
subscribe_nr::callback_status::RECEIVED => SendOrRecvStatus::Received,
|
||||||
// Unknown direction or "transmitted" sent by the kernel.
|
// 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() {
|
if subscription.is_err() {
|
||||||
return Some(SendOrRecvStatus::Error);
|
return Some(SendOrRecvStatus::Error);
|
||||||
}
|
}
|
||||||
@@ -251,17 +266,20 @@ fn recv_with_timeout_detail(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Trigger USB reception.
|
// Trigger USB reception.
|
||||||
let result_code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::RECEIVE, 0, 0) };
|
let result_code = syscalls::command(DRIVER_NUMBER, command_nr::RECEIVE, 0, 0);
|
||||||
if result_code != 0 {
|
if result_code.is_err() {
|
||||||
return Some(SendOrRecvStatus::Error);
|
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.
|
// Cleanup alarm callback.
|
||||||
match timeout.stop_alarm(timeout_alarm) {
|
match timeout.stop_alarm(timeout_alarm) {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
Err(TockValue::Expected(StopAlarmError::AlreadyDisabled)) => {
|
Err(TockError::Command(CommandError {
|
||||||
|
return_code: EALREADY,
|
||||||
|
..
|
||||||
|
})) => {
|
||||||
if !timeout_expired.get() {
|
if !timeout_expired.get() {
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
writeln!(
|
writeln!(
|
||||||
@@ -271,14 +289,20 @@ fn recv_with_timeout_detail(
|
|||||||
.unwrap();
|
.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.
|
// Cancel USB transaction if necessary.
|
||||||
if status.get().is_none() {
|
if status.get().is_none() {
|
||||||
#[cfg(feature = "verbose")]
|
#[cfg(feature = "verbose_usb")]
|
||||||
writeln!(Console::new(), "Cancelling USB receive due to timeout").unwrap();
|
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 {
|
match result_code {
|
||||||
// - SUCCESS means that we successfully cancelled the transaction.
|
// - SUCCESS means that we successfully cancelled the transaction.
|
||||||
// - EALREADY means that the transaction was already completed.
|
// - 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 status = Cell::new(None);
|
||||||
let mut alarm = |direction, _, _| {
|
let mut alarm = |direction| {
|
||||||
status.set(Some(match direction {
|
status.set(Some(match direction {
|
||||||
subscribe_nr::callback_status::TRANSMITTED => SendOrRecvStatus::Sent,
|
subscribe_nr::callback_status::TRANSMITTED => SendOrRecvStatus::Sent,
|
||||||
subscribe_nr::callback_status::RECEIVED => SendOrRecvStatus::Received,
|
subscribe_nr::callback_status::RECEIVED => SendOrRecvStatus::Received,
|
||||||
@@ -319,8 +343,11 @@ fn send_or_recv_with_timeout_detail(
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
let subscription =
|
let subscription = syscalls::subscribe::<callback::Identity1Consumer, _>(
|
||||||
syscalls::subscribe(DRIVER_NUMBER, subscribe_nr::TRANSMIT_OR_RECEIVE, &mut alarm);
|
DRIVER_NUMBER,
|
||||||
|
subscribe_nr::TRANSMIT_OR_RECEIVE,
|
||||||
|
&mut alarm,
|
||||||
|
);
|
||||||
if subscription.is_err() {
|
if subscription.is_err() {
|
||||||
return Some(SendOrRecvStatus::Error);
|
return Some(SendOrRecvStatus::Error);
|
||||||
}
|
}
|
||||||
@@ -340,18 +367,20 @@ fn send_or_recv_with_timeout_detail(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Trigger USB transmission.
|
// Trigger USB transmission.
|
||||||
let result_code =
|
let result_code = syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT_OR_RECEIVE, 0, 0);
|
||||||
unsafe { syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT_OR_RECEIVE, 0, 0) };
|
if result_code.is_err() {
|
||||||
if result_code != 0 {
|
|
||||||
return Some(SendOrRecvStatus::Error);
|
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.
|
// Cleanup alarm callback.
|
||||||
match timeout.stop_alarm(timeout_alarm) {
|
match timeout.stop_alarm(timeout_alarm) {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
Err(TockValue::Expected(StopAlarmError::AlreadyDisabled)) => {
|
Err(TockError::Command(CommandError {
|
||||||
|
return_code: EALREADY,
|
||||||
|
..
|
||||||
|
})) => {
|
||||||
if !timeout_expired.get() {
|
if !timeout_expired.get() {
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
writeln!(
|
writeln!(
|
||||||
@@ -361,14 +390,20 @@ fn send_or_recv_with_timeout_detail(
|
|||||||
.unwrap();
|
.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.
|
// Cancel USB transaction if necessary.
|
||||||
if status.get().is_none() {
|
if status.get().is_none() {
|
||||||
#[cfg(feature = "verbose")]
|
#[cfg(feature = "verbose_usb")]
|
||||||
writeln!(Console::new(), "Cancelling USB transaction due to timeout").unwrap();
|
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 {
|
match result_code {
|
||||||
// - SUCCESS means that we successfully cancelled the transaction.
|
// - SUCCESS means that we successfully cancelled the transaction.
|
||||||
// - EALREADY means that the transaction was already completed.
|
// - 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