diff --git a/.github/actions/ci-checks/action.yml b/.github/actions/ci-checks/action.yml index 08a3024ce..6a437ad96 100644 --- a/.github/actions/ci-checks/action.yml +++ b/.github/actions/ci-checks/action.yml @@ -12,7 +12,7 @@ runs: - if: >- ${{ contains(fromJSON(inputs.checks), 'changelog') || contains(fromJSON(inputs.checks), 'sync') }} - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: fetch-depth: 0 - if: inputs.use-cache == 'true' @@ -69,7 +69,7 @@ runs: run: ./scripts/ci-tests.sh 3 4 shell: bash - if: ${{ contains(fromJSON(inputs.checks), 'hw-host') }} - run: ./scripts/hwci.sh host --no-default-features --features=unix + run: ./scripts/hwci.sh host shell: bash - if: ${{ contains(fromJSON(inputs.checks), 'book') }} run: ./scripts/ci-book.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a5d78e7f8..889a470cf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: checks: runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Compute the checks for ${{ github.event_name }} id: checks run: | @@ -59,7 +59,7 @@ jobs: runs-on: ubuntu-latest needs: checks steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - if: github.event_name != 'schedule' id: cache name: Restore and save the cache @@ -84,7 +84,7 @@ jobs: check: ${{ fromJSON(needs.checks.outputs.checks) }} name: ${{ matrix.check }} steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Run the ${{ matrix.check }} check uses: ./.github/actions/ci-checks with: @@ -104,9 +104,9 @@ jobs: contents: write id-token: write steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - run: ./scripts/artifacts.sh - - uses: actions/attest-build-provenance@6149ea5740be74af77f260b9db67e633f6b0a9a1 # v1.4.2 + - uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3 id: attest with: subject-path: 'artifacts/*' diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 2d0e31d5c..816d3e9ed 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -15,7 +15,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: fetch-depth: 0 - run: sudo apt-get update diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 1482194a7..f4ca73b1e 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -18,7 +18,7 @@ jobs: # Needed to publish results and get a badge (see publish_results below). id-token: write steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: persist-credentials: false - uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 @@ -31,6 +31,6 @@ jobs: name: SARIF file path: results.sarif retention-days: 5 - - uses: github/codeql-action/upload-sarif@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3.26.6 + - uses: github/codeql-action/upload-sarif@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 with: sarif_file: results.sarif diff --git a/crates/api-desc/CHANGELOG.md b/crates/api-desc/CHANGELOG.md index a4eda0548..246f42c82 100644 --- a/crates/api-desc/CHANGELOG.md +++ b/crates/api-desc/CHANGELOG.md @@ -2,6 +2,10 @@ ## 0.2.1-git +### Minor + +- Remove `debug::exit()` and add `scheduling::exit()` instead + ### Patch - Update dependencies diff --git a/crates/api-desc/src/debug.rs b/crates/api-desc/src/debug.rs index 15df5ff8a..6b2874792 100644 --- a/crates/api-desc/src/debug.rs +++ b/crates/api-desc/src/debug.rs @@ -72,16 +72,6 @@ pub(crate) fn new() -> Item { ptr: *mut u8, } -> () }, - item! { - /// Exits the platform with an error code. - /// - /// This is used by test applets to terminate the platform and propagate the test - /// result. - fn exit "de" { - /// 0 for success, 1 for failure. - code: usize, - } -> ! - }, ]; Item::Mod(Mod { docs, name, items }) } diff --git a/crates/api-desc/src/scheduling.rs b/crates/api-desc/src/scheduling.rs index 0d5ab8566..a54f18278 100644 --- a/crates/api-desc/src/scheduling.rs +++ b/crates/api-desc/src/scheduling.rs @@ -32,6 +32,10 @@ pub(crate) fn new() -> Item { /// Aborts the applet. fn abort "sa" {} -> ! }, + item! { + /// Exits the applet. + fn exit "se" {} -> ! + }, ]; Item::Mod(Mod { docs, name, items }) } diff --git a/crates/api-macro/CHANGELOG.md b/crates/api-macro/CHANGELOG.md index 344d584f0..abdb7fd05 100644 --- a/crates/api-macro/CHANGELOG.md +++ b/crates/api-macro/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog -## 0.6.2-git +## 0.7.0-git + +### Major + +- Update `wasefire-applet-api-desc` version ### Patch diff --git a/crates/api-macro/Cargo.lock b/crates/api-macro/Cargo.lock index 823de13ae..fcb2e331c 100644 --- a/crates/api-macro/Cargo.lock +++ b/crates/api-macro/Cargo.lock @@ -87,7 +87,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] diff --git a/crates/api-macro/Cargo.toml b/crates/api-macro/Cargo.toml index 4cdf606b5..baaf0572f 100644 --- a/crates/api-macro/Cargo.toml +++ b/crates/api-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" authors = ["Julien Cretin "] license = "Apache-2.0" publish = true diff --git a/crates/api/CHANGELOG.md b/crates/api/CHANGELOG.md index f5287e5b8..b4f0ab966 100644 --- a/crates/api/CHANGELOG.md +++ b/crates/api/CHANGELOG.md @@ -1,9 +1,14 @@ # Changelog -## 0.6.2-git +## 0.7.0-git + +### Major + +- Update `wasefire-applet-api-macro` version ### Patch +- Make sure at compile-time that exactly one `host` or `wasm` feature is enabled - Update dependencies ## 0.6.1 @@ -93,4 +98,4 @@ ## 0.1.0 - + diff --git a/crates/api/Cargo.lock b/crates/api/Cargo.lock index 0f1e7a3b5..1655ad98d 100644 --- a/crates/api/Cargo.lock +++ b/crates/api/Cargo.lock @@ -134,13 +134,14 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "sealed", "wasefire-applet-api-macro", "wasefire-error", "wasefire-logger", + "wasefire-one-of", ] [[package]] @@ -156,7 +157,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -170,4 +171,8 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" + +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" diff --git a/crates/api/Cargo.toml b/crates/api/Cargo.toml index 94f41651d..931c154e2 100644 --- a/crates/api/Cargo.toml +++ b/crates/api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" authors = ["Julien Cretin "] license = "Apache-2.0" publish = true @@ -18,9 +18,10 @@ features = ["full-api", "wasm"] [dependencies] bytemuck = { version = "1.16.0", default-features = false, features = ["derive"] } sealed = { version = "0.5.0", default-features = false, optional = true } -wasefire-applet-api-macro = { version = "0.6.2-git", path = "../api-macro" } +wasefire-applet-api-macro = { version = "0.7.0-git", path = "../api-macro" } wasefire-error = { version = "0.1.2-git", path = "../error" } -wasefire-logger = { version = "0.1.5", path = "../logger", optional = true } +wasefire-logger = { version = "0.1.6-git", path = "../logger", optional = true } +wasefire-one-of = { version = "0.1.0-git", path = "../one-of" } [features] # Compiles for host or wasm (choose exactly one). diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs index 9fc640aec..0444a1fd4 100644 --- a/crates/api/src/lib.rs +++ b/crates/api/src/lib.rs @@ -24,12 +24,15 @@ extern crate alloc; #[cfg(feature = "host")] pub use host::*; use wasefire_error as _; +use wasefire_one_of::exactly_one_of; #[cfg(feature = "host")] mod host; #[cfg(feature = "wasm")] pub(crate) mod wasm; +exactly_one_of!["host", "wasm"]; + #[cfg(feature = "wasm")] wasefire_applet_api_macro::wasm!(); diff --git a/crates/board/CHANGELOG.md b/crates/board/CHANGELOG.md index bba8b17a7..713360b5a 100644 --- a/crates/board/CHANGELOG.md +++ b/crates/board/CHANGELOG.md @@ -4,6 +4,10 @@ ### Major +- Remove `platform::protocol::Api::disable()` in favor of locking +- Add `Api::Applet` as a required API for simple applet management +- Remove `debug::Api::exit()` +- Remove `api-platform{,-protocol,-update}` features making those APIs required - (Only when `api-platform-protocol` is used) Change `platform::protocol::Api::{enable,disable}()` to also control whether requests are accepted - (Only when `api-storage` is used) The reexported `wasefire-store::Storage` now uses @@ -11,10 +15,12 @@ ### Minor +- Add `usb::serial::Serial::{read,write,flush,enable,disable}()` to bypass `HasSerial` - Implement `defmt::Format` for `Event` when `defmt` is enabled ### Patch +- Fix documentation of `crypto::aead::Api` - Use `derive-where` instead of `derivative` - Update dependencies - Remove workaround lint false positive @@ -155,4 +161,4 @@ ## 0.1.0 - + diff --git a/crates/board/Cargo.lock b/crates/board/Cargo.lock index a78864952..fc0ec2555 100644 --- a/crates/board/Cargo.lock +++ b/crates/board/Cargo.lock @@ -701,12 +701,13 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "sealed", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -722,7 +723,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -766,12 +767,16 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" dependencies = [ "defmt", "log", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-store" version = "0.3.0-git" diff --git a/crates/board/Cargo.toml b/crates/board/Cargo.toml index e8d064123..ee1048084 100644 --- a/crates/board/Cargo.toml +++ b/crates/board/Cargo.toml @@ -35,11 +35,11 @@ typenum = { version = "1.17.0", default-features = false, optional = true } usb-device = { version = "0.3.2", default-features = false, optional = true } usbd-serial = { version = "0.2.2", default-features = false, optional = true } wasefire-error = { version = "0.1.2-git", path = "../error" } -wasefire-logger = { version = "0.1.5", path = "../logger" } +wasefire-logger = { version = "0.1.6-git", path = "../logger" } wasefire-store = { version = "0.3.0-git", path = "../store", optional = true } [dependencies.wasefire-applet-api] -version = "0.6.2-git" +version = "0.7.0-git" path = "../api" features = ["host"] optional = true @@ -62,9 +62,6 @@ api-crypto-sha256 = ["internal-api-crypto-hash"] api-crypto-sha384 = ["internal-api-crypto-hash"] api-gpio = ["bytemuck/derive"] api-led = [] -api-platform = ["internal-api-platform"] -api-platform-protocol = ["internal-api-platform"] -api-platform-update = ["internal-api-platform"] api-radio-ble = ["internal-api-radio", "wasefire-applet-api/api-radio-ble"] api-rng = [] api-storage = ["dep:wasefire-store"] @@ -84,9 +81,6 @@ full-api = [ "api-crypto-sha384", "api-gpio", "api-led", - "api-platform", - "api-platform-protocol", - "api-platform-update", "api-radio-ble", "api-rng", "api-storage", @@ -132,7 +126,6 @@ internal-api-crypto-aead = ["dep:crypto-common", "dep:typenum", "internal-api-cr internal-api-crypto-ecc = ["dep:crypto-common", "dep:typenum", "internal-api-crypto"] internal-api-crypto-hash = ["dep:crypto-common", "dep:digest", "dep:typenum", "internal-api-crypto"] internal-api-crypto-hmac = ["dep:crypto-common", "dep:typenum", "digest/mac", "internal-api-crypto"] -internal-api-platform = [] internal-api-radio = [] internal-api-usb = [] internal-software-crypto = [ diff --git a/crates/board/src/applet.rs b/crates/board/src/applet.rs new file mode 100644 index 000000000..3015e2647 --- /dev/null +++ b/crates/board/src/applet.rs @@ -0,0 +1,48 @@ +// Copyright 2024 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. + +//! Applet interface. + +use crate::Error; + +/// Applet interface. +pub trait Api: Send { + /// Returns the persisted applet. + /// + /// # Safety + /// + /// This function must not be called after `start(true)` until `finish()` is called. Besides, + /// whenever `start(true)` is called, it invalidates the result of a previous call to this + /// function. + unsafe fn get() -> Result<&'static [u8], Error>; + + /// Starts the process of writing an applet to flash. + /// + /// Also erases the previous applet (if any). In particular, writing an empty applet can be used + /// to erase an existing applet (because valid applets are not empty). + /// + /// In case an applet is already being written, this function will start a new process. + /// + /// During a dry-run, any mutable operation is skipped and only checks are performed. + fn start(dry_run: bool) -> Result<(), Error>; + + /// Writes the next chunk of an applet being written to flash. + fn write(chunk: &[u8]) -> Result<(), Error>; + + /// Finishes the process of writing an applet to flash. + /// + /// Implementations should make sure that if the platform reboots before this call, the + /// persisted applet is empty. + fn finish() -> Result<(), Error>; +} diff --git a/crates/board/src/crypto/aead.rs b/crates/board/src/crypto/aead.rs index 2adcafea3..9870aaa8b 100644 --- a/crates/board/src/crypto/aead.rs +++ b/crates/board/src/crypto/aead.rs @@ -34,7 +34,7 @@ impl From for bool { } } -/// Elliptic-curve cryptography interface. +/// AEAD interface. pub trait Api: Support + Send where Key: ArrayLength, diff --git a/crates/board/src/debug.rs b/crates/board/src/debug.rs index 43fadb01b..c719e6643 100644 --- a/crates/board/src/debug.rs +++ b/crates/board/src/debug.rs @@ -32,9 +32,6 @@ pub trait Api: Send { /// This wraps once [`Self::MAX_TIME`] is reached. In particular, a maximum value of zero /// equivalent to not supporting this API. fn time() -> u64; - - /// Exits the platform with a success/failure result. - fn exit(success: bool) -> !; } /// Default implementation. @@ -46,8 +43,4 @@ impl Api for Impl { fn time() -> u64 { 0 } - - fn exit(success: bool) -> ! { - log::panic!("exit({}) called", success) - } } diff --git a/crates/board/src/lib.rs b/crates/board/src/lib.rs index fb1beca73..0fc845cba 100644 --- a/crates/board/src/lib.rs +++ b/crates/board/src/lib.rs @@ -30,6 +30,7 @@ use derive_where::derive_where; use wasefire_error::Code; pub use wasefire_error::Error; +pub mod applet; #[cfg(feature = "api-button")] pub mod button; #[cfg(feature = "internal-api-crypto")] @@ -39,7 +40,6 @@ pub mod debug; pub mod gpio; #[cfg(feature = "api-led")] pub mod led; -#[cfg(feature = "internal-api-platform")] pub mod platform; #[cfg(feature = "internal-api-radio")] pub mod radio; @@ -78,6 +78,9 @@ pub trait Api: Send + 'static { None } + /// Applet interface. + type Applet: applet::Api; + /// Button interface. #[cfg(feature = "api-button")] type Button: button::Api; @@ -98,7 +101,6 @@ pub trait Api: Send + 'static { type Led: led::Api; /// Platform interface. - #[cfg(feature = "internal-api-platform")] type Platform: platform::Api; /// Radio interface. @@ -158,7 +160,6 @@ pub enum Event { Button(button::Event), /// Platform event. - #[cfg(feature = "internal-api-platform")] Platform(platform::Event), /// Radio event. @@ -202,6 +203,9 @@ impl Impossible { } } +/// Applet interface. +pub type Applet = ::Applet; + /// Button interface. #[cfg(feature = "api-button")] pub type Button = ::Button; @@ -222,7 +226,6 @@ pub type Gpio = ::Gpio; pub type Led = ::Led; /// Platform interface. -#[cfg(feature = "internal-api-platform")] pub type Platform = ::Platform; /// Radio interface. diff --git a/crates/board/src/platform.rs b/crates/board/src/platform.rs index b29281397..673daaa23 100644 --- a/crates/board/src/platform.rs +++ b/crates/board/src/platform.rs @@ -14,12 +14,9 @@ //! Platform interface. -#[cfg(feature = "api-platform")] use crate::Error; -#[cfg(feature = "api-platform-protocol")] pub mod protocol; -#[cfg(feature = "api-platform-update")] pub mod update; /// Platform event. @@ -27,7 +24,6 @@ pub mod update; #[derive(Debug, PartialEq, Eq)] pub enum Event { /// Protocol event. - #[cfg(feature = "api-platform-protocol")] Protocol(protocol::Event), } @@ -40,32 +36,25 @@ impl From for crate::Event { /// Platform interface. pub trait Api: Send { /// Platform protocol interface. - #[cfg(feature = "api-platform-protocol")] type Protocol: protocol::Api; /// Platform update interface. - #[cfg(feature = "api-platform-update")] type Update: update::Api; /// Returns the platform serial. - #[cfg(feature = "api-platform")] fn serial() -> alloc::borrow::Cow<'static, [u8]>; /// Returns the platform version. /// /// Versions are comparable with lexicographical order. - #[cfg(feature = "api-platform")] fn version() -> alloc::borrow::Cow<'static, [u8]>; /// Reboots the device (thus platform and applets). - #[cfg(feature = "api-platform")] fn reboot() -> Result; } /// Platform protocol interface. -#[cfg(feature = "api-platform-protocol")] pub type Protocol = as Api>::Protocol; /// Platform update interface. -#[cfg(feature = "api-platform-update")] pub type Update = as Api>::Update; diff --git a/crates/board/src/platform/protocol.rs b/crates/board/src/platform/protocol.rs index 310284d8c..5c0c1d6c4 100644 --- a/crates/board/src/platform/protocol.rs +++ b/crates/board/src/platform/protocol.rs @@ -42,9 +42,6 @@ pub trait Api { /// Also triggers an event each time a request is received. fn enable() -> Result<(), Error>; - /// Stops accepting requests. - fn disable() -> Result<(), Error>; - /// Handles vendor-specific requests. fn vendor(request: &[u8]) -> Result, Error>; } diff --git a/crates/board/src/usb/serial.rs b/crates/board/src/usb/serial.rs index 1185a6eab..36ee4e460 100644 --- a/crates/board/src/usb/serial.rs +++ b/crates/board/src/usb/serial.rs @@ -92,32 +92,9 @@ impl<'a, T: UsbBus> Serial<'a, T> { Self { port, read_enabled: false, write_enabled: false } } - /// Accesses the port of a serial. - pub fn port(&mut self) -> &mut SerialPort<'a, T> { - &mut self.port - } - - /// Pushes events based on whether the USB serial was polled. - pub fn tick(&mut self, polled: bool, mut push: impl FnMut(Event)) { - if self.read_enabled && polled { - push(Event::Read); - } - if self.write_enabled && self.port.dtr() { - push(Event::Write); - } - } - - fn set(&mut self, event: &Event, enabled: bool) { - match event { - Event::Read => self.read_enabled = enabled, - Event::Write => self.write_enabled = enabled, - } - } -} - -impl Api for WithSerial { - fn read(output: &mut [u8]) -> Result { - match T::with_serial(|serial| serial.port.read(output)) { + /// Reads from the USB serial into a buffer. + pub fn read(&mut self, output: &mut [u8]) -> Result { + match self.port.read(output) { Ok(len) => { log::trace!("{}{:?} = read({})", len, &output[.. len], output.len()); Ok(len) @@ -130,12 +107,13 @@ impl Api for WithSerial { } } - fn write(input: &[u8]) -> Result { - if !T::with_serial(|serial| serial.port.dtr()) { + /// Writes from a buffer to the USB serial. + pub fn write(&mut self, input: &[u8]) -> Result { + if !self.port.dtr() { // Data terminal is not ready. return Ok(0); } - match T::with_serial(|serial| serial.port.write(input)) { + match self.port.write(input) { Ok(len) => { log::trace!("{} = write({}{:?})", len, input.len(), input); Ok(len) @@ -148,9 +126,10 @@ impl Api for WithSerial { } } - fn flush() -> Result<(), Error> { + /// Flushes the USB serial. + pub fn flush(&mut self) -> Result<(), Error> { loop { - match T::with_serial(|serial| serial.port.flush()) { + match self.port.flush() { Ok(()) => { log::trace!("flush()"); break Ok(()); @@ -167,13 +146,58 @@ impl Api for WithSerial { } } - fn enable(event: &Event) -> Result<(), Error> { - T::with_serial(|serial| serial.set(event, true)); + /// Enables a given event to be triggered. + pub fn enable(&mut self, event: &Event) -> Result<(), Error> { + self.set(event, true) + } + + /// Disables a given event from being triggered. + pub fn disable(&mut self, event: &Event) -> Result<(), Error> { + self.set(event, false) + } + + /// Accesses the port of a serial. + pub fn port(&mut self) -> &mut SerialPort<'a, T> { + &mut self.port + } + + /// Pushes events based on whether the USB serial was polled. + pub fn tick(&mut self, polled: bool, mut push: impl FnMut(Event)) { + if self.read_enabled && polled { + push(Event::Read); + } + if self.write_enabled && self.port.dtr() { + push(Event::Write); + } + } + + fn set(&mut self, event: &Event, enabled: bool) -> Result<(), Error> { + match event { + Event::Read => self.read_enabled = enabled, + Event::Write => self.write_enabled = enabled, + } Ok(()) } +} + +impl Api for WithSerial { + fn read(output: &mut [u8]) -> Result { + T::with_serial(|x| x.read(output)) + } + + fn write(input: &[u8]) -> Result { + T::with_serial(|x| x.write(input)) + } + + fn flush() -> Result<(), Error> { + T::with_serial(|x| x.flush()) + } + + fn enable(event: &Event) -> Result<(), Error> { + T::with_serial(|x| x.enable(event)) + } fn disable(event: &Event) -> Result<(), Error> { - T::with_serial(|serial| serial.set(event, false)); - Ok(()) + T::with_serial(|x| x.disable(event)) } } diff --git a/crates/cli-tools/CHANGELOG.md b/crates/cli-tools/CHANGELOG.md index 4e06dd9d5..fa18e15d7 100644 --- a/crates/cli-tools/CHANGELOG.md +++ b/crates/cli-tools/CHANGELOG.md @@ -4,18 +4,33 @@ ### Major +- Remove `Default` for `action::RustAppletBuild` (implement `clap::Parser` instead) +- Add `action` feature to gate the `action` module - Change API to be async using tokio ### Minor +- Extend `fs::write()` first parameter to set the `OpenOptions` too +- Add `error::root_cause_is()` to check the `anyhow::Error` root cause +- Add `action::PlatformLock` for locking a platform protocol +- Expose `action::Transfer` for transfers from host to device +- Add `action::AppletExitStatus` to get the applet exit status +- Add `action::Applet{Install,Uninstall}` for simple applet management +- Add `action::PlatformApiVersion` to get a platform API version +- Change the flags of `action::AppletRpc` to use `action::Wait` +- Add `action::Wait` for commands returning an optional response +- Change the default connection timeout from 1 second to infinite (0 seconds) +- Add `action::PlatformUpdate` for platform update - Add `action::PlatformList` to list connected platforms - Add `action::ConnectionOptions` for commands that need a platform connection - Change the behavior of `fs::copy_if_changed()` to keep an original source ### Patch +- Fix incorrect error with UNIX and TCP platform protocols +- Only print commands and file system operations when warnings are logged - Update dependencies ## 0.1.0 - + diff --git a/crates/cli-tools/Cargo.lock b/crates/cli-tools/Cargo.lock index 02d3baf3f..f27a40d1b 100644 --- a/crates/cli-tools/Cargo.lock +++ b/crates/cli-tools/Cargo.lock @@ -132,6 +132,18 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "windows-sys", +] + [[package]] name = "data-encoding" version = "2.6.0" @@ -149,6 +161,12 @@ dependencies = [ "syn", ] +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "equivalent" version = "1.0.1" @@ -195,12 +213,39 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.155" @@ -272,6 +317,12 @@ dependencies = [ "syn", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "object" version = "0.36.4" @@ -293,6 +344,12 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "portable-atomic" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" + [[package]] name = "proc-macro2" version = "1.0.83" @@ -525,6 +582,8 @@ dependencies = [ "clap", "data-encoding", "humantime", + "indicatif", + "log", "rusb", "serde", "tokio", @@ -544,14 +603,18 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" dependencies = [ "log", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-protocol" -version = "0.1.1-git" +version = "0.2.0-git" dependencies = [ "anyhow", "wasefire-error", @@ -566,6 +629,7 @@ dependencies = [ "tokio", "wasefire-board-api", "wasefire-logger", + "wasefire-one-of", "wasefire-protocol", ] @@ -577,6 +641,7 @@ dependencies = [ "rusb", "wasefire-board-api", "wasefire-logger", + "wasefire-one-of", "wasefire-protocol", ] diff --git a/crates/cli-tools/Cargo.toml b/crates/cli-tools/Cargo.toml index abfd27c51..7848bc49e 100644 --- a/crates/cli-tools/Cargo.toml +++ b/crates/cli-tools/Cargo.toml @@ -11,32 +11,64 @@ include = ["/LICENSE", "/src/"] keywords = ["cli", "embedded", "framework", "wasm"] categories = ["command-line-utilities", "embedded", "wasm"] +[package.metadata.docs.rs] +all-features = true + [dependencies] anyhow = { version = "1.0.86", default-features = false, features = ["std"] } -cargo_metadata = { version = "0.18.1", default-features = false } -clap = { version = "4.5.4", default-features = false, features = ["derive", "env", "std"] } -data-encoding = { version = "2.6.0", default-features = false, features = ["std"] } -humantime = { version = "2.1.0", default-features = false } -rusb = { version = "0.9.4", default-features = false } +cargo_metadata = { version = "0.18.1", default-features = false, optional = true } +data-encoding = { version = "2.6.0", default-features = false, features = ["std"], optional = true } +humantime = { version = "2.1.0", default-features = false, optional = true } +indicatif = { version = "0.17.8", default-features = false, optional = true } +log = { version = "0.4.21", default-features = false } +rusb = { version = "0.9.4", default-features = false, optional = true } serde = { version = "1.0.202", default-features = false, features = ["derive"] } toml = { version = "0.8.13", default-features = false, features = ["display", "parse"] } -wasefire-protocol = { version = "0.1.1-git", path = "../protocol", features = ["host"] } -wasefire-wire = { version = "0.1.1-git", path = "../wire" } +wasefire-wire = { version = "0.1.1-git", path = "../wire", optional = true } + +[dependencies.clap] +version = "4.5.4" +default-features = false +features = ["derive", "env", "std"] +optional = true [dependencies.tokio] version = "1.40.0" default-features = false -features = ["fs", "io-std", "process", "rt"] +features = ["fs", "io-std", "io-util", "macros", "process", "rt"] + +[dependencies.wasefire-protocol] +version = "0.2.0-git" +path = "../protocol" +features = ["host"] +optional = true [dependencies.wasefire-protocol-tokio] version = "0.1.0-git" path = "../protocol-tokio" features = ["host", "log"] +optional = true [dependencies.wasefire-protocol-usb] version = "0.2.0-git" path = "../protocol-usb" features = ["host", "log"] +optional = true + +[features] +action = [ + "dep:cargo_metadata", + "dep:clap", + "dep:data-encoding", + "dep:humantime", + "dep:indicatif", + "dep:rusb", + "dep:wasefire-protocol", + "dep:wasefire-protocol-tokio", + "dep:wasefire-protocol-usb", + "dep:wasefire-wire", + "tokio/time", +] [lints] clippy.unit-arg = "allow" diff --git a/crates/cli-tools/src/action.rs b/crates/cli-tools/src/action.rs index 39e2a3d95..7d4a5a50c 100644 --- a/crates/cli-tools/src/action.rs +++ b/crates/cli-tools/src/action.rs @@ -14,14 +14,17 @@ use std::fmt::Display; use std::path::{Path, PathBuf}; +use std::time::Duration; use anyhow::{bail, ensure, Result}; use cargo_metadata::{Metadata, MetadataCommand}; use clap::{ValueEnum, ValueHint}; use rusb::GlobalContext; use tokio::process::Command; -use wasefire_protocol::{self as service, applet, Api, Connection, ConnectionExt}; +use wasefire_protocol::{self as service, applet, Connection, ConnectionExt}; +use wasefire_wire::{self as wire, Yoke}; +use crate::error::root_cause_is; use crate::{cmd, fs}; mod protocol; @@ -41,7 +44,7 @@ pub struct ConnectionOptions { protocol: protocol::Protocol, /// Timeout to send or receive with the USB protocol. - #[arg(long, default_value = "1s")] + #[arg(long, default_value = "0s")] timeout: humantime::Duration, } @@ -52,6 +55,99 @@ impl ConnectionOptions { } } +/// Returns the API version of a platform. +#[derive(clap::Args)] +pub struct PlatformApiVersion {} + +impl PlatformApiVersion { + pub async fn run(self, connection: &mut dyn Connection) -> Result { + let PlatformApiVersion {} = self; + connection.call::(()).await.map(|x| *x.get()) + } +} + +/// Installs an applet on a platform. +#[derive(clap::Args)] +pub struct AppletInstall { + /// Path to the applet to install. + #[arg(value_hint = ValueHint::FilePath)] + pub applet: PathBuf, + + #[clap(flatten)] + pub transfer: Transfer, +} + +impl AppletInstall { + pub async fn run(self, connection: &mut dyn Connection) -> Result<()> { + let AppletInstall { applet, transfer } = self; + transfer + .run::(connection, applet, "Installed", None:: _>) + .await + } +} + +/// Uninstalls an applet from a platform. +#[derive(clap::Args)] +pub struct AppletUninstall {} + +impl AppletUninstall { + pub async fn run(self, connection: &mut dyn Connection) -> Result<()> { + let AppletUninstall {} = self; + connection.call::(()).await.map(|x| *x.get()) + } +} + +/// Prints the exit status of an applet from a platform. +#[derive(clap::Parser)] +#[non_exhaustive] +pub struct AppletExitStatus { + #[clap(flatten)] + pub wait: Wait, + + /// Also exits with the applet exit code. + #[arg(long)] + exit_code: bool, +} + +impl AppletExitStatus { + fn print(status: Option) { + match status { + Some(applet::ExitStatus::Exit) => println!("The applet exited."), + Some(applet::ExitStatus::Abort) => println!("The applet aborted."), + Some(applet::ExitStatus::Trap) => println!("The applet trapped."), + Some(applet::ExitStatus::Kill) => println!("The applet was killed."), + None => println!("The applet is still running."), + } + } + + fn code(status: Option) -> i32 { + match status { + Some(applet::ExitStatus::Exit) => 0, + Some(applet::ExitStatus::Abort) => 1, + Some(applet::ExitStatus::Trap) => 2, + Some(applet::ExitStatus::Kill) => 62, + None => 63, + } + } + + pub fn ensure_exit(&mut self) { + self.exit_code = true; + } + + pub async fn run(self, connection: &mut dyn Connection) -> Result<()> { + let AppletExitStatus { wait, exit_code } = self; + let status = wait + .run::(connection, applet::AppletId) + .await? + .map(|x| *x.get()); + Self::print(status); + if exit_code { + std::process::exit(Self::code(status)) + } + Ok(()) + } +} + /// Parameters for an applet or platform RPC. #[derive(clap::Args)] pub struct Rpc { @@ -89,27 +185,77 @@ pub struct AppletRpc { #[clap(flatten)] rpc: Rpc, - /// Number of retries to receive a response. - #[arg(long, default_value = "3")] - retries: usize, + #[clap(flatten)] + wait: Wait, } impl AppletRpc { pub async fn run(self, connection: &mut dyn Connection) -> Result<()> { - let AppletRpc { applet, rpc, retries } = self; + let AppletRpc { applet, rpc, mut wait } = self; let applet_id = match applet { Some(_) => bail!("applet identifiers are not supported yet"), None => applet::AppletId, }; let request = applet::Request { applet_id, request: &rpc.read().await? }; connection.call::(request).await?.get(); - for _ in 0 .. retries { - let response = connection.call::(applet_id).await?; - if let Some(response) = response.get().response { - return rpc.write(response).await; + wait.ensure_wait(); + match wait.run::(connection, applet_id).await? { + None => bail!("did not receive a response"), + Some(response) => rpc.write(response.get()).await, + } + } +} + +/// Options to repeatedly call a command with an optional response. +#[derive(clap::Parser)] +pub struct Wait { + /// Waits until there is a response. + /// + /// This is equivalent to --period=100ms. + #[arg(long)] + wait: bool, + + /// Retries every so often until there is a response. + /// + /// The command doesn't return `None` in that case. + #[arg(long, conflicts_with = "wait")] + period: Option, +} + +impl Wait { + pub fn ensure_wait(&mut self) { + if self.wait || self.period.is_some() { + return; + } + self.wait = true; + } + + pub fn set_period(&mut self, period: Duration) { + self.wait = false; + self.period = Some(period.into()); + } + + pub async fn run>( + self, connection: &mut dyn Connection, request: S::Request<'_>, + ) -> Result>>> + where S: for<'a> service::Service = Option>> { + let Wait { wait, period } = self; + let period = match (wait, period) { + (true, None) => Some(Duration::from_millis(100)), + (true, Some(_)) => unreachable!(), + (false, None) => None, + (false, Some(x)) => Some(*x), + }; + let request = S::request(request); + loop { + match connection.call_ref::(&request).await?.try_map(|x| x.ok_or(())) { + Ok(x) => break Ok(Some(x)), + Err(()) => match period { + Some(period) => tokio::time::sleep(period).await, + None => break Ok(None), + }, } } - bail!("did not receive a response after {retries} retries"); } } @@ -140,6 +286,109 @@ impl PlatformList { } } +/// Updates a platform. +#[derive(clap::Args)] +pub struct PlatformUpdate { + /// Path to the new platform. + #[arg(value_hint = ValueHint::FilePath)] + platform: PathBuf, + + #[clap(flatten)] + transfer: Transfer, +} + +impl PlatformUpdate { + pub async fn metadata(connection: &mut dyn Connection) -> Result> { + connection.call::(()).await + } + + pub async fn run(self, connection: &mut dyn Connection) -> Result<()> { + let PlatformUpdate { platform, transfer } = self; + transfer + .run::( + connection, + platform, + "Updated", + Some(|_| bail!("device responded to a transfer finish")), + ) + .await + } +} + +/// Parameters for a transfer from the host to the device. +#[derive(clap::Args)] +pub struct Transfer { + /// Whether the transfer is a dry-run. + #[arg(long)] + dry_run: bool, + + /// How to chunk the payload. + #[arg(long, default_value_t = 1024)] + chunk_size: usize, +} + +impl Transfer { + async fn run( + &self, connection: &mut dyn Connection, payload: impl AsRef, message: &'static str, + finish: Option>) -> Result>, + ) -> Result<()> + where + S: for<'a> service::Service< + Request<'a> = service::transfer::Request<'a>, + Response<'a> = (), + >, + { + use wasefire_protocol::transfer::Request; + let Transfer { dry_run, chunk_size } = self; + let payload = fs::read(payload).await?; + let progress = indicatif::ProgressBar::new(payload.len() as u64) + .with_style( + indicatif::ProgressStyle::with_template( + "{msg:9} {elapsed:>3} {spinner} [{wide_bar}] {bytes:>10} / {total_bytes:<10}", + )? + .tick_chars("-\\|/ ") + .progress_chars("##-"), + ) + .with_message("Starting"); + progress.enable_steady_tick(Duration::from_millis(200)); + connection.call::(Request::Start { dry_run: *dry_run }).await?.get(); + progress.set_message("Writing"); + for chunk in payload.chunks(*chunk_size) { + progress.inc(chunk.len() as u64); + connection.call::(Request::Write { chunk }).await?.get(); + } + progress.set_message("Finishing"); + match (*dry_run, finish) { + (false, Some(finish)) => final_call::(connection, Request::Finish, finish).await?, + _ => *connection.call::(Request::Finish).await?.get(), + } + progress.finish_with_message(message); + Ok(()) + } +} + +async fn final_call( + connection: &mut dyn Connection, request: S::Request<'_>, + proof: impl FnOnce(Yoke>) -> Result, +) -> Result<()> { + connection.send(&S::request(request)).await?; + match connection.receive::().await { + Ok(x) => proof(x)?, + Err(e) => { + if root_cause_is::(&e, |x| matches!(x, rusb::Error::NoDevice)) { + return Ok(()); + } + if root_cause_is::(&e, |x| { + use std::io::ErrorKind::*; + matches!(x.kind(), NotConnected | BrokenPipe | UnexpectedEof) + }) { + return Ok(()); + } + Err(e) + } + } +} + /// Reboots a platform. #[derive(clap::Args)] pub struct PlatformReboot {} @@ -147,14 +396,18 @@ pub struct PlatformReboot {} impl PlatformReboot { pub async fn run(self, connection: &mut dyn Connection) -> Result<()> { let PlatformReboot {} = self; - connection.send(&Api::PlatformReboot(())).await?; - match connection.receive::().await { - Ok(x) => *x.get(), - Err(e) => match e.downcast_ref::() { - Some(rusb::Error::Timeout | rusb::Error::NoDevice) => Ok(()), - _ => Err(e), - }, - } + final_call::(connection, (), |x| match *x.get() {}).await + } +} + +/// Locks a platform. +#[derive(clap::Args)] +pub struct PlatformLock {} + +impl PlatformLock { + pub async fn run(self, connection: &mut dyn Connection) -> Result<()> { + let PlatformLock {} = self; + connection.call::(()).await.map(|x| *x.get()) } } @@ -211,7 +464,7 @@ impl RustAppletNew { } /// Builds a Rust applet from its project. -#[derive(Default, clap::Args)] +#[derive(clap::Parser)] pub struct RustAppletBuild { /// Builds for production, disabling debugging facilities. #[arg(long)] diff --git a/crates/cli-tools/src/error.rs b/crates/cli-tools/src/error.rs new file mode 100644 index 000000000..55a49b87d --- /dev/null +++ b/crates/cli-tools/src/error.rs @@ -0,0 +1,24 @@ +// Copyright 2024 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. + +use std::error::Error; + +/// Checks the root cause of an error. +/// +/// Returns whether the root cause of the error is of the provided type and satisfies the predicate. +pub fn root_cause_is( + error: &anyhow::Error, predicate: impl FnOnce(&E) -> bool, +) -> bool { + error.root_cause().downcast_ref::().map_or(false, predicate) +} diff --git a/crates/cli-tools/src/fs.rs b/crates/cli-tools/src/fs.rs index 9f1f205f1..0b67c1633 100644 --- a/crates/cli-tools/src/fs.rs +++ b/crates/cli-tools/src/fs.rs @@ -15,12 +15,14 @@ //! Wrappers around `tokio::fs` with descriptive errors. use std::fs::Metadata; +use std::future::Future; use std::io::ErrorKind; use std::path::{Component, Path, PathBuf}; use anyhow::{Context, Result}; use serde::de::DeserializeOwned; use serde::Serialize; +use tokio::fs::{File, OpenOptions}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; pub async fn canonicalize(path: impl AsRef) -> Result { @@ -144,12 +146,62 @@ pub async fn touch(path: impl AsRef) -> Result<()> { write(path, "").await } -pub async fn write(path: impl AsRef, contents: impl AsRef<[u8]>) -> Result<()> { - let name = path.as_ref().display(); +pub struct WriteParams> { + path: P, + options: OpenOptions, +} + +impl> WriteParams

{ + pub fn new(path: P) -> Self { + WriteParams { path, options: OpenOptions::new() } + } + pub fn options(&mut self) -> &mut OpenOptions { + &mut self.options + } +} + +pub trait WriteFile { + fn path(&self) -> &Path; + fn open(self) -> impl Future>; +} + +impl> WriteFile for WriteParams

{ + fn path(&self) -> &Path { + self.path.as_ref() + } + async fn open(self) -> Result { + (&self).open().await + } +} + +impl> WriteFile for &WriteParams

{ + fn path(&self) -> &Path { + (*self).path() + } + async fn open(self) -> Result { + Ok(self.options.open(&self.path).await?) + } +} + +impl> WriteFile for P { + fn path(&self) -> &Path { + self.as_ref() + } + async fn open(self) -> Result { + let mut params = WriteParams::new(self); + params.options().write(true).create(true).truncate(true); + params.open().await + } +} + +pub async fn write(file: impl WriteFile, contents: impl AsRef<[u8]>) -> Result<()> { + let name = format!("{}", file.path().display()); let contents = contents.as_ref(); - create_parent(path.as_ref()).await?; + create_parent(file.path()).await?; debug!("write > {name:?}"); - tokio::fs::write(path.as_ref(), contents).await.with_context(|| format!("writing {name}"))?; + let mut file = file.open().await.with_context(|| format!("creating {name}"))?; + file.write_all(contents).await.with_context(|| format!("writing {name}"))?; + file.flush().await.with_context(|| format!("flushing {name}"))?; Ok(()) } diff --git a/crates/cli-tools/src/lib.rs b/crates/cli-tools/src/lib.rs index 382ef9e74..957676ff5 100644 --- a/crates/cli-tools/src/lib.rs +++ b/crates/cli-tools/src/lib.rs @@ -17,17 +17,23 @@ //! This library is also used for the internal maintenance CLI of Wasefire called xtask. #![feature(async_fn_track_caller)] +#![feature(doc_auto_cfg)] +#![feature(never_type)] #![feature(path_add_extension)] #![feature(try_find)] macro_rules! debug { ($($x:tt)*) => { - print!("\x1b[1;36m"); - print!($($x)*); - println!("\x1b[m"); + if log::log_enabled!(log::Level::Warn) { + print!("\x1b[1;36m"); + print!($($x)*); + println!("\x1b[m"); + } }; } +#[cfg(feature = "action")] pub mod action; pub mod cmd; +pub mod error; pub mod fs; diff --git a/crates/cli-tools/test.sh b/crates/cli-tools/test.sh index 2de77fa48..85089814e 100755 --- a/crates/cli-tools/test.sh +++ b/crates/cli-tools/test.sh @@ -19,4 +19,5 @@ set -e test_helper +cargo test --lib --features=action cargo test --lib diff --git a/crates/cli/CHANGELOG.md b/crates/cli/CHANGELOG.md index fc9bed14e..7318de10b 100644 --- a/crates/cli/CHANGELOG.md +++ b/crates/cli/CHANGELOG.md @@ -7,8 +7,17 @@ - Rename `--serial` to `--protocol` with more support - Move `--serial` and `--timeout` to commands that need them +### Minor + +- Support `RUST_LOG` to control logging +- Add `platform-lock` to lock a platform protocol +- Add `applet-exit-status` to get an applet exit status +- Implement `applet-{install,uninstall}` for applet management +- Add `platform-update-{metadata,transfer}` for platform update + ### Patch +- Print `wasefire` instead of `wasefire-cli` with `--version` - Check for bad command-line configuration - Update dependencies - Restore release builds to the default @@ -36,4 +45,4 @@ ## 0.1.0 - + diff --git a/crates/cli/Cargo.lock b/crates/cli/Cargo.lock index ffa0c1f18..14431d6a2 100644 --- a/crates/cli/Cargo.lock +++ b/crates/cli/Cargo.lock @@ -17,6 +17,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "anstream" version = "0.6.14" @@ -107,9 +116,9 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "camino" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] @@ -204,6 +213,18 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "windows-sys", +] + [[package]] name = "data-encoding" version = "2.6.0" @@ -221,6 +242,35 @@ dependencies = [ "syn", ] +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -267,6 +317,27 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.0" @@ -279,6 +350,12 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.155" @@ -309,9 +386,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" @@ -342,24 +419,30 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "object" version = "0.36.4" @@ -400,9 +483,15 @@ checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "portable-atomic" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "d30538d42559de6b034bc76fd6dd4c38961b1ee5c6c56e3808c50128fdbc22ce" [[package]] name = "proc-macro2" @@ -431,6 +520,35 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "rusb" version = "0.9.4" @@ -490,11 +608,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -552,18 +671,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", @@ -668,6 +787,7 @@ dependencies = [ "anyhow", "clap", "clap_complete", + "env_logger", "tokio", "wasefire-cli-tools", ] @@ -681,6 +801,8 @@ dependencies = [ "clap", "data-encoding", "humantime", + "indicatif", + "log", "rusb", "serde", "tokio", @@ -700,14 +822,18 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" dependencies = [ "log", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-protocol" -version = "0.1.1-git" +version = "0.2.0-git" dependencies = [ "anyhow", "wasefire-error", @@ -722,6 +848,7 @@ dependencies = [ "tokio", "wasefire-board-api", "wasefire-logger", + "wasefire-one-of", "wasefire-protocol", ] @@ -733,6 +860,7 @@ dependencies = [ "rusb", "wasefire-board-api", "wasefire-logger", + "wasefire-one-of", "wasefire-protocol", ] diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index cd914814d..b75181461 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -19,7 +19,8 @@ path = "src/main.rs" anyhow = { version = "1.0.86", default-features = false } clap = { version = "4.5.4", default-features = false, features = ["default", "derive", "env"] } clap_complete = { version = "4.5.2", default-features = false } -wasefire-cli-tools = { version = "0.2.0-git", path = "../cli-tools" } +env_logger = { version = "0.11.3", default-features = false, features = ["default"] } +wasefire-cli-tools = { version = "0.2.0-git", path = "../cli-tools", features = ["action"] } [dependencies.tokio] version = "1.40.0" diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 9aec185d5..a4d44d0b4 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -22,7 +22,7 @@ use clap_complete::Shell; use wasefire_cli_tools::{action, fs}; #[derive(Parser)] -#[command(version, about)] +#[command(name = "wasefire", version, about)] struct Flags { #[command(flatten)] options: Options, @@ -44,14 +44,34 @@ enum Action { /// Lists the applets installed on a platform. AppletList, - /// Installs an applet on a platform. - AppletInstall, + #[group(id = "Action::AppletInstall")] + AppletInstall { + #[command(flatten)] + options: action::ConnectionOptions, + #[command(flatten)] + action: action::AppletInstall, + #[command(subcommand)] + command: Option, + }, /// Updates an applet on a platform. AppletUpdate, - /// Uninstalls an applet from a platform. - AppletUninstall, + #[group(id = "Action::AppletUninstall")] + AppletUninstall { + #[command(flatten)] + options: action::ConnectionOptions, + #[command(flatten)] + action: action::AppletUninstall, + }, + + #[group(id = "Action::AppletExitStatus")] + AppletExitStatus { + #[command(flatten)] + options: action::ConnectionOptions, + #[command(flatten)] + action: action::AppletExitStatus, + }, // TODO(https://github.com/clap-rs/clap/issues/2621): We should be able to remove the explicit // group name. @@ -62,10 +82,21 @@ enum Action { #[command(flatten)] action: action::AppletRpc, }, + PlatformList(action::PlatformList), - /// Updates a connected platform. - PlatformUpdate, + /// Prints the platform update metadata (possibly binary output). + PlatformUpdateMetadata { + #[command(flatten)] + options: action::ConnectionOptions, + }, + + PlatformUpdateTransfer { + #[command(flatten)] + options: action::ConnectionOptions, + #[command(flatten)] + action: action::PlatformUpdate, + }, #[group(id = "Action::PlatformReboot")] PlatformReboot { @@ -74,6 +105,15 @@ enum Action { #[command(flatten)] action: action::PlatformReboot, }, + + #[group(id = "Action::PlatformLock")] + PlatformLock { + #[command(flatten)] + options: action::ConnectionOptions, + #[command(flatten)] + action: action::PlatformLock, + }, + #[group(id = "Action::PlatformRpc")] PlatformRpc { #[command(flatten)] @@ -81,6 +121,7 @@ enum Action { #[command(flatten)] action: action::PlatformRpc, }, + RustAppletNew(action::RustAppletNew), RustAppletBuild(action::RustAppletBuild), RustAppletTest(action::RustAppletTest), @@ -89,6 +130,16 @@ enum Action { Completion(Completion), } +#[derive(clap::Subcommand)] +enum AppletInstallCommand { + /// Waits until the applet exits. + #[group(id = "AppletInstallCommand::Wait")] + Wait { + #[command(flatten)] + action: action::AppletExitStatus, + }, +} + #[derive(clap::Args)] struct Completion { /// Generates a completion file for this shell (tries to guess by default). @@ -120,19 +171,42 @@ impl Completion { #[tokio::main] async fn main() -> Result<()> { + env_logger::init(); let flags = Flags::parse(); let dir = std::env::current_dir()?; match flags.action { Action::AppletList => bail!("not implemented yet"), - Action::AppletInstall => bail!("not implemented yet"), + Action::AppletInstall { options, action, command } => { + let mut connection = options.connect().await?; + action.run(&mut connection).await?; + match command { + None => Ok(()), + Some(AppletInstallCommand::Wait { mut action }) => { + action.wait.ensure_wait(); + action.run(&mut connection).await + } + } + } Action::AppletUpdate => bail!("not implemented yet"), - Action::AppletUninstall => bail!("not implemented yet"), + Action::AppletUninstall { options, action } => { + action.run(&mut options.connect().await?).await + } + Action::AppletExitStatus { options, action } => { + action.run(&mut options.connect().await?).await + } Action::AppletRpc { options, action } => action.run(&mut options.connect().await?).await, Action::PlatformList(x) => x.run().await, - Action::PlatformUpdate => bail!("not implemented yet"), + Action::PlatformUpdateMetadata { options } => { + let metadata = action::PlatformUpdate::metadata(&mut options.connect().await?).await?; + fs::write_stdout(metadata.get()).await + } + Action::PlatformUpdateTransfer { options, action } => { + action.run(&mut options.connect().await?).await + } Action::PlatformReboot { options, action } => { action.run(&mut options.connect().await?).await } + Action::PlatformLock { options, action } => action.run(&mut options.connect().await?).await, Action::PlatformRpc { options, action } => action.run(&mut options.connect().await?).await, Action::RustAppletNew(x) => x.run().await, Action::RustAppletBuild(x) => x.run(dir).await, diff --git a/crates/interpreter/CHANGELOG.md b/crates/interpreter/CHANGELOG.md index b4fd64f70..f0eb13f85 100644 --- a/crates/interpreter/CHANGELOG.md +++ b/crates/interpreter/CHANGELOG.md @@ -8,6 +8,8 @@ ### Patch +- Return an error instead of unsupported when too many locals +- Only take the initial frame in `Thread::new()` - Fix and test the `cache` feature in continuous integration ## 0.3.0 diff --git a/crates/interpreter/src/exec.rs b/crates/interpreter/src/exec.rs index b948b6ddb..761eed5a5 100644 --- a/crates/interpreter/src/exec.rs +++ b/crates/interpreter/src/exec.rs @@ -195,7 +195,7 @@ impl<'m> Store<'m> { let mut parser = self.insts[inst_id].module.func(ptr.index()); let mut locals = Vec::new(); append_locals(&mut parser, &mut locals); - let thread = Thread::new(parser, vec![Frame::new(inst_id, 0, &[], locals)]); + let thread = Thread::new(parser, Frame::new(inst_id, 0, &[], locals)); let result = thread.run(self)?; assert!(matches!(result, RunResult::Done(x) if x.is_empty())); } @@ -225,7 +225,7 @@ impl<'m> Store<'m> { let mut locals = args; append_locals(&mut parser, &mut locals); let frame = Frame::new(inst_id, t.results.len(), &[], locals); - Thread::new(parser, vec![frame]).run(self) + Thread::new(parser, frame).run(self) } /// Returns the value of a global of an instance. @@ -730,14 +730,13 @@ enum ThreadResult<'m> { } impl<'m> Thread<'m> { - fn new(parser: Parser<'m>, frames: Vec>) -> Thread<'m> { - Thread { parser, frames, values: vec![] } + fn new(parser: Parser<'m>, frame: Frame<'m>) -> Thread<'m> { + Thread { parser, frames: vec![frame], values: vec![] } } fn const_expr(store: &mut Store<'m>, inst_id: usize, mut_parser: &mut Parser<'m>) -> Val { - let frames = vec![Frame::new(inst_id, 1, &[], Vec::new())]; let parser = mut_parser.clone(); - let mut thread = Thread::new(parser, frames); + let mut thread = Thread::new(parser, Frame::new(inst_id, 1, &[], Vec::new())); let (parser, results) = loop { let p = thread.parser.save(); match thread.step(store).unwrap() { diff --git a/crates/interpreter/src/parser.rs b/crates/interpreter/src/parser.rs index 8755e1dec..6bbb072c0 100644 --- a/crates/interpreter/src/parser.rs +++ b/crates/interpreter/src/parser.rs @@ -469,15 +469,20 @@ impl<'m, M: Mode> Parser<'m, M> { } pub fn parse_locals(&mut self, locals: &mut Vec) -> MResult<(), M> { + let mut total = locals.len() as u32; for _ in 0 .. self.parse_vec()? { - let len = self.parse_u32()? as usize; - if locals.len().checked_add(len).map_or(true, |x| x > MAX_LOCALS) { - return M::unsupported(if_debug!(Unsupported::MaxLocals)); - } + let len = self.parse_u32()?; + total = M::open(|| total.checked_add(len))?; let val = self.parse_valtype()?; - locals.extend(core::iter::repeat(val).take(len)); + if total <= MAX_LOCALS { + locals.extend(core::iter::repeat(val).take(len as usize)); + } + } + if total <= MAX_LOCALS { + Ok(()) + } else { + M::unsupported(if_debug!(Unsupported::MaxLocals)) } - Ok(()) } pub fn parse_elem(&mut self, user: &mut impl ParseElem<'m, M>) -> MResult<(), M> { @@ -650,7 +655,7 @@ impl<'m, M: Mode> Parser<'m, M> { /// Maximum number of locals (must be less than 2^32). // NOTE: This should be configurable. -const MAX_LOCALS: usize = 100; +const MAX_LOCALS: u32 = 100; fn check_eq(x: T, y: T) -> MResult<(), M> { M::check(|| x == y) diff --git a/crates/interpreter/test.sh b/crates/interpreter/test.sh index 7c04aeb1b..b474c8795 100755 --- a/crates/interpreter/test.sh +++ b/crates/interpreter/test.sh @@ -28,5 +28,6 @@ cargo check --lib --target=riscv32imc-unknown-none-elf \ --features=portable-atomic/critical-section RUSTFLAGS=--cfg=portable_atomic_unsafe_assume_single_core \ cargo check --lib --target=riscv32imc-unknown-none-elf -cargo test --test=spec --features=debug,toctou,float-types,vector-types cargo check --example=hello +# Run with `-- --test-threads=1 --nocapture` to see unsupported tests. +cargo test --test=spec --features=debug,toctou,float-types,vector-types diff --git a/crates/interpreter/tests/spec.rs b/crates/interpreter/tests/spec.rs index 9c05c94ce..aa5667dc9 100644 --- a/crates/interpreter/tests/spec.rs +++ b/crates/interpreter/tests/spec.rs @@ -36,15 +36,13 @@ fn test(repo: &str, name: &str) { let mut env = Env::new(pool); env.instantiate("spectest", &SPECTEST); env.register_name("spectest", None); - assert!(env.inst.is_ok()); + assert!(matches!(env.inst, Sup::Yes(_))); for directive in wast.directives { eprintln!("{name}:{}", directive.span().offset()); match directive { WastDirective::Wat(QuoteWat::Wat(Wat::Module(mut m))) => { env.instantiate(name, &m.encode().unwrap()); - if !matches!(env.inst, Err(Error::Unsupported(_))) { - env.register_id(m.id, env.inst.unwrap()); - } + env.register_id(m.id, env.inst); } WastDirective::Wat(mut wat) => env.instantiate(name, &wat.encode().unwrap()), WastDirective::AssertMalformed { module, .. } => assert_malformed(module), @@ -97,16 +95,58 @@ fn mem_size(name: &str) -> usize { } } +/// Whether something is supported. +#[derive(Copy, Clone)] +enum Sup { + Uninit, + No(Unsupported), + Yes(T), +} + +impl Sup { + fn conv(x: Result) -> Result, Error> { + match x { + Ok(x) => Ok(Sup::Yes(x)), + Err(Error::Unsupported(x)) => { + eprintln!("unsupported {x:?}"); + Ok(Sup::No(x)) + } + Err(x) => Err(x), + } + } + + fn res(self) -> Result { + match self { + Sup::Uninit => unreachable!(), + Sup::No(x) => Err(Error::Unsupported(x)), + Sup::Yes(x) => Ok(x), + } + } +} + +macro_rules! only_sup { + ($x:expr) => { + match $x { + Ok(x) => Ok(x), + Err(Error::Unsupported(x)) => { + eprintln!("skip unsupported {x:?}"); + return; + } + Err(x) => Err(x), + } + }; +} + struct Env<'m> { pool: &'m mut [u8], store: Store<'m>, - inst: Result, - map: HashMap, InstId>, + inst: Sup, + map: HashMap, Sup>, } impl<'m> Env<'m> { fn new(pool: &'m mut [u8]) -> Self { - Env { pool, store: Store::default(), inst: Err(Error::Invalid), map: HashMap::new() } + Env { pool, store: Store::default(), inst: Sup::Uninit, map: HashMap::new() } } fn alloc(&mut self, size: usize) -> &'m mut [u8] { @@ -120,14 +160,6 @@ impl<'m> Env<'m> { &mut result[.. size] } - fn set_inst(&mut self, inst: Result) { - match inst { - Ok(_) | Err(Error::Unsupported(_)) => (), - Err(e) => panic!("{e:?}"), - } - self.inst = inst; - } - fn maybe_instantiate(&mut self, name: &str, wasm: &[u8]) -> Result { let module = self.alloc(wasm.len()); module.copy_from_slice(wasm); @@ -141,7 +173,7 @@ impl<'m> Env<'m> { fn instantiate(&mut self, name: &str, wasm: &[u8]) { let inst = self.maybe_instantiate(name, wasm); - self.set_inst(inst); + self.inst = Sup::conv(inst).unwrap(); } fn invoke(&mut self, inst_id: InstId, name: &str, args: Vec) -> Result, Error> { @@ -152,20 +184,21 @@ impl<'m> Env<'m> { } fn register_name(&mut self, name: &'m str, module: Option>) { - let inst_id = self.inst.unwrap(); - self.register_id(module, inst_id); - self.store.set_name(inst_id, name).unwrap(); + self.register_id(module, self.inst); + if let Sup::Yes(inst_id) = self.inst { + self.store.set_name(inst_id, name).unwrap(); + } } - fn register_id(&mut self, id: Option>, inst_id: InstId) { + fn register_id(&mut self, id: Option>, inst_id: Sup) { if let Some(id) = id { self.map.insert(id, inst_id); } } - fn inst_id(&self, id: Option) -> Result { + fn inst_id(&self, id: Option) -> Sup { match id { - Some(x) => Ok(self.map[&x]), + Some(x) => self.map[&x], None => self.inst, } } @@ -257,7 +290,7 @@ fn spectest() -> Vec { } fn assert_return(env: &mut Env, exec: WastExecute, expected: Vec) { - let actual = wast_execute(env, exec).unwrap(); + let actual = only_sup!(wast_execute(env, exec)).unwrap(); assert_eq!(actual.len(), expected.len()); for (actual, expected) in actual.into_iter().zip(expected.into_iter()) { use wast::core::HeapType; @@ -295,42 +328,31 @@ fn assert_return(env: &mut Env, exec: WastExecute, expected: Vec) { } fn assert_trap(env: &mut Env, exec: WastExecute) { - assert_eq!(wast_execute(env, exec), Err(Error::Trap)); + assert_eq!(only_sup!(wast_execute(env, exec)), Err(Error::Trap)); } fn assert_invoke(env: &mut Env, invoke: WastInvoke) { - assert_eq!(wast_invoke(env, invoke), Ok(Vec::new())); + assert_eq!(only_sup!(wast_invoke(env, invoke)), Ok(Vec::new())); } fn assert_malformed(mut wat: QuoteWat) { if let Ok(wasm) = wat.encode() { - let module = Module::new(&wasm); - if !matches!(module, Err(Error::Unsupported(_))) { - assert_eq!(module.err(), Some(Error::Invalid)); - } + assert_eq!(only_sup!(Module::new(&wasm)).err(), Some(Error::Invalid)); } } fn assert_invalid(mut wat: QuoteWat) { let wasm = wat.encode().unwrap(); - let module = Module::new(&wasm); - if !matches!(module, Err(Error::Unsupported(_))) { - assert_eq!(module.err(), Some(Error::Invalid)); - } + assert_eq!(only_sup!(Module::new(&wasm)).err(), Some(Error::Invalid)); } fn assert_exhaustion(env: &mut Env, call: WastInvoke) { - let result = wast_invoke(env, call); - if !matches!(result, Err(Error::Unsupported(_))) { - assert_eq!(result, Err(Error::Trap)); - } + assert_eq!(only_sup!(wast_invoke(env, call)), Err(Error::Trap)); } fn assert_unlinkable(env: &mut Env, mut wat: Wat) { - let inst = env.maybe_instantiate("", &wat.encode().unwrap()); - if !matches!(inst, Err(Error::Unsupported(_))) { - assert_eq!(inst.err(), Some(Error::NotFound)); - } + let inst = only_sup!(env.maybe_instantiate("", &wat.encode().unwrap())); + assert_eq!(inst.err(), Some(Error::NotFound)); } fn wast_execute(env: &mut Env, exec: WastExecute) -> Result, Error> { @@ -340,14 +362,14 @@ fn wast_execute(env: &mut Env, exec: WastExecute) -> Result, Error> { env.maybe_instantiate("", &wat.encode().unwrap()).map(|_| Vec::new()) } WastExecute::Get { module, global, .. } => { - let inst_id = env.inst_id(module)?; + let inst_id = env.inst_id(module).res()?; env.store.get_global(inst_id, global).map(|x| vec![x]) } } } fn wast_invoke(env: &mut Env, invoke: WastInvoke) -> Result, Error> { - let inst_id = env.inst_id(invoke.module)?; + let inst_id = env.inst_id(invoke.module).res()?; let args = wast_args(invoke.args); env.invoke(inst_id, invoke.name, args) } @@ -411,11 +433,7 @@ test!(br_table); test!(bulk); test!(call); test!(call_indirect); -test!( - // This test seems specific to text format. - #[ignore] - comments -); +test!(comments); test!(const_, "const"); test!(conversions); test!(custom); @@ -463,6 +481,7 @@ test!(memory_size); test!(memory_trap); test!(names); test!(nop); +test!(obsolete_keywords, "obsolete-keywords"); test!(ref_func); test!(ref_is_null); test!(ref_null); @@ -483,11 +502,6 @@ test!(table_init); test!(table_set); test!(table_size); test!(token); -test!( - // This test seems specific to text format. - #[ignore] - tokens -); test!(traps); test!(type_, "type"); test!(unreachable); diff --git a/crates/logger/CHANGELOG.md b/crates/logger/CHANGELOG.md index c186acaad..58d314de4 100644 --- a/crates/logger/CHANGELOG.md +++ b/crates/logger/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.1.6-git + +### Minor + +- Add `flush()` to flush possible buffered logs + ## 0.1.5 ### Patch diff --git a/crates/logger/Cargo.lock b/crates/logger/Cargo.lock index a56075184..798337226 100644 --- a/crates/logger/Cargo.lock +++ b/crates/logger/Cargo.lock @@ -143,7 +143,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" dependencies = [ "defmt", "log", diff --git a/crates/logger/Cargo.toml b/crates/logger/Cargo.toml index e20851bd8..5bf6cfdd2 100644 --- a/crates/logger/Cargo.toml +++ b/crates/logger/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" authors = ["Julien Cretin "] license = "Apache-2.0" publish = true diff --git a/crates/logger/src/lib.rs b/crates/logger/src/lib.rs index a238c7811..6e594566a 100644 --- a/crates/logger/src/lib.rs +++ b/crates/logger/src/lib.rs @@ -74,12 +74,21 @@ mod custom { pub use std::println; #[cfg(feature = "defmt")] -pub use defmt::{debug, error, info, panic, println, trace, warn, Debug2Format, Display2Format}; +pub use defmt::{ + debug, error, flush, info, panic, println, trace, warn, Debug2Format, Display2Format, +}; #[cfg(feature = "log")] pub use log::{debug, error, info, trace, warn}; #[cfg(not(feature = "defmt"))] pub use no_defmt::*; +#[cfg(feature = "log")] +pub fn flush() { + log::logger().flush(); +} +#[cfg(not(any(feature = "log", feature = "defmt")))] +pub fn flush() {} + #[macro_export] macro_rules! every { ($n:expr, $t:ident, $($args: expr),*$(,)?) => {{ diff --git a/crates/one-of/CHANGELOG.md b/crates/one-of/CHANGELOG.md new file mode 100644 index 000000000..9e0843dbf --- /dev/null +++ b/crates/one-of/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog + +## 0.1.0-git + + diff --git a/crates/one-of/Cargo.lock b/crates/one-of/Cargo.lock new file mode 100644 index 000000000..d47c51cda --- /dev/null +++ b/crates/one-of/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" diff --git a/crates/one-of/Cargo.toml b/crates/one-of/Cargo.toml new file mode 100644 index 000000000..12c98ad7d --- /dev/null +++ b/crates/one-of/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "wasefire-one-of" +version = "0.1.0-git" +authors = ["Julien Cretin "] +license = "Apache-2.0" +publish = true +edition = "2021" +description = "Macros for mutually exclusive features" +repository = "https://github.com/google/wasefire" +include = ["/LICENSE", "/src/"] +keywords = ["macro", "no-std"] +categories = ["no-std"] + +[lints] +clippy.unit-arg = "allow" +rust.missing-docs = "warn" +rust.unreachable-pub = "warn" +rust.unsafe-op-in-unsafe-fn = "warn" +rust.unused-crate-dependencies = "warn" diff --git a/crates/one-of/LICENSE b/crates/one-of/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/crates/one-of/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/crates/one-of/src/lib.rs b/crates/one-of/src/lib.rs new file mode 100644 index 000000000..c3c49c2a0 --- /dev/null +++ b/crates/one-of/src/lib.rs @@ -0,0 +1,91 @@ +// Copyright 2024 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. + +//! Provides macros to check mutually exclusive features. + +#![no_std] + +// TODO(https://github.com/rust-lang/rust/issues/122105): Remove when fixed. +extern crate alloc; + +/// Makes sure exactly one of the provided feature is enabled. +/// +/// For example, `exactly_one_of!["a", "b", "c"]` will expand to: +/// +/// ```ignore +/// #[cfg(any( +/// not(any(feature = "a", feature = "b", feature = "c")), +/// all(feature = "a", feature = "b"), +/// all(feature = "a", feature = "c"), +/// all(feature = "b", feature = "c"), +/// ))] +/// compile_error!("Exactly one of feature \"a\", \"b\", or \"c\" can be enabled."); +/// ``` +#[macro_export] +macro_rules! exactly_one_of { + ($f:literal, $($fs:literal),+$(,)?) => { + $crate::internal_one_of!(0 [$f $($fs)*] "Exactly"); + }; +} + +/// Makes sure at most one of the provided feature is enabled. +/// +/// For example, `at_most_one_of!["a", "b", "c"]` will expand to: +/// +/// ```ignore +/// #[cfg(any( +/// all(feature = "a", feature = "b"), +/// all(feature = "a", feature = "c"), +/// all(feature = "b", feature = "c"), +/// ))] +/// compile_error!("At most one of feature \"a\", \"b\", or \"c\" can be enabled."); +/// ``` +#[macro_export] +macro_rules! at_most_one_of { + ($f:literal, $($fs:literal),+$(,)?) => { + $crate::internal_one_of!(1 [$f $($fs)*] () ["At most";]); + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! internal_one_of { + (0 [$($f:literal)*] $p:literal) => { + $crate::internal_one_of!(1 [$($f)*] (not(any($(feature = $f),*)),) [$p;]); + }; + + (1 [$f:literal $($fs:literal)*] $r:tt [$($ds:literal)*; $($d:literal)?]) => { + $crate::internal_one_of!(2 [$($fs)*] $f [$($fs)*] $r [$($ds)* $($d)?; $f]); + }; + (1 [] $r:tt $ds:tt) => { + #[cfg(any $r)] + $crate::internal_one_of!(3 $ds); + }; + + (2 $s:tt $g:literal [$f:literal $($fs:literal)*] ($($r:tt)*) $d:tt) => { + $crate::internal_one_of!(2 $s $g [$($fs)*] ($($r)* all(feature = $g, feature = $f),) $d); + }; + (2 $s:tt $g:literal [] $r:tt $d:tt) => { + $crate::internal_one_of!(1 $s $r $d); + }; + + (3 [$p:literal $a:literal; $b:literal]) => { + compile_error!(concat!($p, " one of feature ", stringify!($a), " or ", stringify!($b), + " can be enabled.")); + }; + (3 [$p:literal $($as:literal)*; $b:literal]) => { + compile_error!(concat!($p, " one of feature ",$(stringify!($as), ", ",)* "or ", + stringify!($b), " can be enabled.")); + }; +} diff --git a/crates/one-of/test.sh b/crates/one-of/test.sh new file mode 100755 index 000000000..3e0b9afc3 --- /dev/null +++ b/crates/one-of/test.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# Copyright 2024 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. + +set -e + +. "$(git rev-parse --show-toplevel)"/scripts/test-helper.sh + +test_helper + +cargo test --lib +cargo check --lib --target=thumbv7em-none-eabi diff --git a/crates/prelude/CHANGELOG.md b/crates/prelude/CHANGELOG.md index d9d43f94e..4e198c481 100644 --- a/crates/prelude/CHANGELOG.md +++ b/crates/prelude/CHANGELOG.md @@ -1,9 +1,19 @@ # Changelog -## 0.6.1-git +## 0.7.0-git + +### Major + +- Remove `debug::{assert,assert_eq}()` in favor of `core::{assert,assert_eq}!` +- Remove `debug::exit()` in favor of `scheduling::{abort,exit}()` + +### Minor + +- Add `scheduling::exit()` for successful applet exit ### Patch +- Make sure at compile-time that at most one `native`, `test`, or `wasm` feature is enabled - Update dependencies ## 0.6.0 @@ -162,4 +172,4 @@ ## 0.1.0 - + diff --git a/crates/prelude/Cargo.lock b/crates/prelude/Cargo.lock index 72e873485..369446531 100644 --- a/crates/prelude/Cargo.lock +++ b/crates/prelude/Cargo.lock @@ -262,7 +262,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "aead", "bytemuck", @@ -274,18 +274,20 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", "zeroize", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", "wasefire-logger", + "wasefire-one-of", ] [[package]] @@ -301,7 +303,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -315,7 +317,11 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" + +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" [[package]] name = "wasefire-sync" diff --git a/crates/prelude/Cargo.toml b/crates/prelude/Cargo.toml index 6e3a87548..28ae94159 100644 --- a/crates/prelude/Cargo.toml +++ b/crates/prelude/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" authors = ["Julien Cretin "] license = "Apache-2.0" publish = true @@ -24,8 +24,9 @@ digest = { version = "0.10.7", default-features = false, features = ["mac"], opt rlsf = { version = "0.2.1", default-features = false, optional = true } sealed = { version = "0.5.0", default-features = false, optional = true } typenum = { version = "1.17.0", default-features = false, optional = true } -wasefire-applet-api = { version = "0.6.2-git", path = "../api", features = ["wasm"] } +wasefire-applet-api = { version = "0.7.0-git", path = "../api", features = ["wasm"] } wasefire-error = { version = "0.1.2-git", path = "../error" } +wasefire-one-of = { version = "0.1.0-git", path = "../one-of" } wasefire-sync = { version = "0.1.1", path = "../sync" } zeroize = { version = "1.7.0", default-features = false, features = ["derive"], optional = true } diff --git a/crates/prelude/src/debug.rs b/crates/prelude/src/debug.rs index a1b07db9c..0c6422eec 100644 --- a/crates/prelude/src/debug.rs +++ b/crates/prelude/src/debug.rs @@ -23,7 +23,7 @@ use wasefire_applet_api::debug as api; pub use wasefire_applet_api::debug::Perf; use wasefire_error::Error; -use crate::{convert, convert_never, convert_unit}; +use crate::{convert, convert_unit}; /// Prints a line to the debug output. pub fn println(msg: &str) { @@ -65,27 +65,3 @@ macro_rules! debug { } }; } - -/// Exits the platform indicating success of failure. -pub fn exit(success: bool) -> ! { - let params = api::exit::Params { code: if success { 0 } else { 1 } }; - convert_never(unsafe { api::exit(params) }).unwrap(); -} - -/// Asserts that a condition holds and exits with an error otherwise. -#[track_caller] -pub fn assert(condition: bool) { - if !condition { - debug!("Assertion failed at {}", core::panic::Location::caller()); - exit(false); - } -} - -/// Asserts that an equality holds and exits with an error otherwise. -#[track_caller] -pub fn assert_eq(x: &T, y: &T) { - if x != y { - debug!("{x:?} != {y:?} at {}", core::panic::Location::caller()); - exit(false); - } -} diff --git a/crates/prelude/src/lib.rs b/crates/prelude/src/lib.rs index 1e95112d7..1c000387c 100644 --- a/crates/prelude/src/lib.rs +++ b/crates/prelude/src/lib.rs @@ -38,6 +38,7 @@ extern crate alloc; use wasefire_applet_api as api; pub use wasefire_error::Error; +use wasefire_one_of::at_most_one_of; #[cfg(feature = "rust-crypto")] use {aead as _, crypto_common as _, digest as _, typenum as _, zeroize as _}; @@ -77,6 +78,8 @@ pub mod uart; #[cfg(feature = "internal-api-usb")] pub mod usb; +at_most_one_of!["native", "test", "wasm"]; + /// Board-specific syscalls. /// /// Those calls are directly forwarded to the board by the scheduler. @@ -151,7 +154,7 @@ macro_rules! applet { #[cfg(not(feature = "test"))] #[panic_handler] fn handle_panic(info: &core::panic::PanicInfo) -> ! { - debug!("{}", info); + debug!("{info}"); scheduling::abort(); } diff --git a/crates/prelude/src/scheduling.rs b/crates/prelude/src/scheduling.rs index dabfe252e..8f6b1ba23 100644 --- a/crates/prelude/src/scheduling.rs +++ b/crates/prelude/src/scheduling.rs @@ -54,3 +54,8 @@ pub fn wait_indefinitely() -> ! { pub fn abort() -> ! { convert_never(unsafe { api::abort() }).unwrap(); } + +/// Exits the applet. +pub fn exit() -> ! { + convert_never(unsafe { api::exit() }).unwrap(); +} diff --git a/crates/protocol-tokio/CHANGELOG.md b/crates/protocol-tokio/CHANGELOG.md index 6faacf764..db2bed9c0 100644 --- a/crates/protocol-tokio/CHANGELOG.md +++ b/crates/protocol-tokio/CHANGELOG.md @@ -2,4 +2,4 @@ ## 0.1.0-git - + diff --git a/crates/protocol-tokio/Cargo.lock b/crates/protocol-tokio/Cargo.lock index 52d33d49a..9921aff5a 100644 --- a/crates/protocol-tokio/Cargo.lock +++ b/crates/protocol-tokio/Cargo.lock @@ -259,14 +259,18 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" dependencies = [ "log", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-protocol" -version = "0.1.1-git" +version = "0.2.0-git" dependencies = [ "anyhow", "wasefire-error", @@ -282,6 +286,7 @@ dependencies = [ "wasefire-board-api", "wasefire-error", "wasefire-logger", + "wasefire-one-of", "wasefire-protocol", ] diff --git a/crates/protocol-tokio/Cargo.toml b/crates/protocol-tokio/Cargo.toml index 3f53e64bd..c5482aacc 100644 --- a/crates/protocol-tokio/Cargo.toml +++ b/crates/protocol-tokio/Cargo.toml @@ -17,7 +17,8 @@ features = ["device"] [dependencies] anyhow = { version = "1.0.86", default-features = false, features = ["std"] } wasefire-error = { version = "0.1.2-git", path = "../error", optional = true } -wasefire-logger = { version = "0.1.5", path = "../logger" } +wasefire-logger = { version = "0.1.6-git", path = "../logger", optional = true } +wasefire-one-of = { version = "0.1.0-git", path = "../one-of" } [dependencies.tokio] version = "1.40.0" @@ -27,19 +28,19 @@ features = ["io-util", "macros", "net", "rt", "sync"] [dependencies.wasefire-board-api] version = "0.8.0-git" path = "../board" -features = ["api-platform-protocol", "std"] +features = ["std"] optional = true [dependencies.wasefire-protocol] -version = "0.1.1-git" +version = "0.2.0-git" path = "../protocol" features = ["host"] optional = true [features] -log = ["wasefire-board-api?/log", "wasefire-logger/log"] +log = ["wasefire-board-api?/log", "wasefire-logger?/log"] # Exactly one of host or device must be selected. -device = ["dep:wasefire-board-api", "dep:wasefire-error"] +device = ["dep:wasefire-board-api", "dep:wasefire-error", "dep:wasefire-logger"] host = ["dep:wasefire-protocol"] [lints] diff --git a/crates/protocol-tokio/src/common.rs b/crates/protocol-tokio/src/common.rs index e7904bf64..74680fc31 100644 --- a/crates/protocol-tokio/src/common.rs +++ b/crates/protocol-tokio/src/common.rs @@ -14,49 +14,22 @@ //! Message format between device and host. -use std::io::ErrorKind; +use std::io::Result; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; -use wasefire_logger as log; -pub(crate) async fn read(stream: &mut S) -> Result, ()> { +pub(crate) async fn read(stream: &mut S) -> Result> { let mut length = [0; 4]; - read_exact(stream, &mut length).await?; + stream.read_exact(&mut length).await?; let length = u32::from_be_bytes(length); let mut message = vec![0; length as usize]; - read_exact(stream, &mut message).await?; + stream.read_exact(&mut message).await?; Ok(message.into_boxed_slice()) } -pub(crate) async fn write(stream: &mut S, message: &[u8]) -> Result<(), ()> { +pub(crate) async fn write(stream: &mut S, message: &[u8]) -> Result<()> { let length = message.len() as u32; - write_all(stream, &length.to_be_bytes()).await?; - write_all(stream, message).await?; + stream.write_all(&length.to_be_bytes()).await?; + stream.write_all(message).await?; Ok(()) } - -async fn read_exact(stream: &mut S, buffer: &mut [u8]) -> Result<(), ()> { - match stream.read_exact(buffer).await { - Ok(_) => Ok(()), - Err(x) => match x.kind() { - ErrorKind::NotConnected | ErrorKind::BrokenPipe | ErrorKind::UnexpectedEof => { - log::debug!("read_exact {:?}", x.kind()); - Err(()) - } - _ => panic!("{x}"), - }, - } -} - -async fn write_all(stream: &mut S, buffer: &[u8]) -> Result<(), ()> { - match stream.write_all(buffer).await { - Ok(_) => Ok(()), - Err(x) => match x.kind() { - ErrorKind::NotConnected | ErrorKind::BrokenPipe => { - log::debug!("write_all {:?}", x.kind()); - Err(()) - } - _ => panic!("{x}"), - }, - } -} diff --git a/crates/protocol-tokio/src/device.rs b/crates/protocol-tokio/src/device.rs index 566f75054..e36f15890 100644 --- a/crates/protocol-tokio/src/device.rs +++ b/crates/protocol-tokio/src/device.rs @@ -69,6 +69,45 @@ impl Pipe { Self::new::(addr, push).await } + pub fn read(&mut self) -> Result>, Error> { + let mut state = self.shared.state.lock().unwrap(); + match &mut *state { + State::Disabled | State::Process => Err(Error::user(Code::InvalidState)), + State::Accept | State::Ready | State::Response { .. } => Ok(None), + State::Request { request } => { + let request = std::mem::take(request); + *state = State::Process; + self.shared.notify.notify_one(); + Ok(Some(request)) + } + } + } + + pub fn write(&mut self, response: &[u8]) -> Result<(), Error> { + let mut state = self.shared.state.lock().unwrap(); + match &mut *state { + State::Process => { + let response = response.to_vec().into_boxed_slice(); + *state = State::Response { response }; + self.shared.notify.notify_one(); + Ok(()) + } + _ => Err(Error::user(Code::InvalidState)), + } + } + + pub fn enable(&mut self) -> Result<(), Error> { + let mut state = self.shared.state.lock().unwrap(); + match &mut *state { + State::Disabled => { + *state = State::Accept; + self.shared.notify.notify_one(); + Ok(()) + } + _ => Err(Error::user(Code::InvalidState)), + } + } + async fn new(bind: L::Name<'_>, push: P) -> Result { let shared = Shared { notify: Arc::new(Notify::new()), @@ -101,7 +140,7 @@ impl Pipe { } match Self::manage_stream::(&mut stream, &shared, &push).await { Ok(()) => (), - Err(()) => match &mut *shared.state.lock().unwrap() { + Err(_) => match &mut *shared.state.lock().unwrap() { State::Disabled => (), x => *x = State::Accept, }, @@ -116,7 +155,7 @@ impl Pipe { async fn manage_stream( stream: &mut L::Stream, shared: &Shared, push: &P, - ) -> Result<(), ()> { + ) -> std::io::Result<()> { loop { enum Action { Receive, @@ -157,62 +196,15 @@ impl Pipe { impl Api for Impl { fn read() -> Result>, Error> { - T::with_pipe(|x| { - let mut state = x.shared.state.lock().unwrap(); - match &mut *state { - State::Disabled | State::Process => Err(Error::user(Code::InvalidState)), - State::Accept | State::Ready | State::Response { .. } => Ok(None), - State::Request { request } => { - let request = std::mem::take(request); - *state = State::Process; - x.shared.notify.notify_one(); - Ok(Some(request)) - } - } - }) + T::with_pipe(Pipe::read) } fn write(response: &[u8]) -> Result<(), Error> { - T::with_pipe(|x| { - let mut state = x.shared.state.lock().unwrap(); - match &mut *state { - State::Process => { - let response = response.to_vec().into_boxed_slice(); - *state = State::Response { response }; - x.shared.notify.notify_one(); - Ok(()) - } - _ => Err(Error::user(Code::InvalidState)), - } - }) + T::with_pipe(|x| x.write(response)) } fn enable() -> Result<(), Error> { - T::with_pipe(|x| { - let mut state = x.shared.state.lock().unwrap(); - match &mut *state { - State::Disabled => { - *state = State::Accept; - x.shared.notify.notify_one(); - Ok(()) - } - _ => Err(Error::user(Code::InvalidState)), - } - }) - } - - fn disable() -> Result<(), Error> { - T::with_pipe(|x| { - let mut state = x.shared.state.lock().unwrap(); - match &mut *state { - State::Disabled => Err(Error::user(Code::InvalidState)), - _ => { - *state = State::Disabled; - x.shared.notify.notify_one(); - Ok(()) - } - } - }) + T::with_pipe(Pipe::enable) } fn vendor(request: &[u8]) -> Result, Error> { diff --git a/crates/protocol-tokio/src/host.rs b/crates/protocol-tokio/src/host.rs index ede4f3c4b..0744578fa 100644 --- a/crates/protocol-tokio/src/host.rs +++ b/crates/protocol-tokio/src/host.rs @@ -15,7 +15,7 @@ use std::net::SocketAddr; use std::path::Path; -use anyhow::{bail, Result}; +use anyhow::Result; use tokio::io::{AsyncRead, AsyncWrite}; use tokio::net::{TcpStream, UnixStream}; use wasefire_protocol::DynFuture; @@ -43,20 +43,10 @@ impl Connection { impl wasefire_protocol::Connection for Connection { fn read(&mut self) -> DynFuture> { - Box::pin(async move { - match read(&mut self.stream).await { - Ok(x) => Ok(x), - Err(()) => bail!("Error reading from the device."), - } - }) + Box::pin(async move { Ok(read(&mut self.stream).await?) }) } fn write<'a>(&'a mut self, request: &'a [u8]) -> DynFuture<'a, ()> { - Box::pin(async move { - match write(&mut self.stream, request).await { - Ok(()) => Ok(()), - Err(()) => bail!("Error writing to the device."), - } - }) + Box::pin(async move { Ok(write(&mut self.stream, request).await?) }) } } diff --git a/crates/protocol-tokio/src/lib.rs b/crates/protocol-tokio/src/lib.rs index 87ef91b2a..da5e6665f 100644 --- a/crates/protocol-tokio/src/lib.rs +++ b/crates/protocol-tokio/src/lib.rs @@ -21,9 +21,12 @@ pub use device::*; #[cfg(feature = "host")] pub use host::*; +use wasefire_one_of::exactly_one_of; mod common; #[cfg(feature = "device")] mod device; #[cfg(feature = "host")] mod host; + +exactly_one_of!["device", "host"]; diff --git a/crates/protocol-usb/CHANGELOG.md b/crates/protocol-usb/CHANGELOG.md index 76bcdbf76..fd96786c1 100644 --- a/crates/protocol-usb/CHANGELOG.md +++ b/crates/protocol-usb/CHANGELOG.md @@ -8,13 +8,18 @@ ### Minor +- Add `Rpc::enable()` with feature `device` to bypass `HasRpc` +- Migrate to removal of `platform::protocol::Api::disable()` +- Add error message when missing udev rule +- Implement `Debug` for `Candidate` and `Connection` - Implement `Display` for `Connection` ### Patch +- Fail to compile if `device` and `host` features are used together - Update dependencies - Remove workaround lint false positive ## 0.1.0 - + diff --git a/crates/protocol-usb/Cargo.lock b/crates/protocol-usb/Cargo.lock index 2c77dc117..5ef2cafdb 100644 --- a/crates/protocol-usb/Cargo.lock +++ b/crates/protocol-usb/Cargo.lock @@ -292,15 +292,19 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" dependencies = [ "defmt", "log", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-protocol" -version = "0.1.1-git" +version = "0.2.0-git" dependencies = [ "anyhow", "wasefire-error", @@ -318,6 +322,7 @@ dependencies = [ "wasefire-board-api", "wasefire-error", "wasefire-logger", + "wasefire-one-of", "wasefire-protocol", ] diff --git a/crates/protocol-usb/Cargo.toml b/crates/protocol-usb/Cargo.toml index 204c13fec..058a270e1 100644 --- a/crates/protocol-usb/Cargo.toml +++ b/crates/protocol-usb/Cargo.toml @@ -11,22 +11,25 @@ include = ["/LICENSE", "/src/"] keywords = ["embedded", "framework", "no-std"] categories = ["embedded", "no-std"] +[package.metadata.docs.rs] +features = ["device"] + [dependencies] anyhow = { version = "1.0.86", default-features = false, features = ["std"], optional = true } defmt = { version = "0.3.8", default-features = false, optional = true } rusb = { version = "0.9.4", default-features = false, optional = true } usb-device = { version = "0.3.2", default-features = false, optional = true } wasefire-error = { version = "0.1.2-git", path = "../error", optional = true } -wasefire-logger = { version = "0.1.5", path = "../logger" } +wasefire-logger = { version = "0.1.6-git", path = "../logger" } +wasefire-one-of = { version = "0.1.0-git", path = "../one-of" } [dependencies.wasefire-board-api] version = "0.8.0-git" path = "../board" -features = ["api-platform-protocol"] optional = true [dependencies.wasefire-protocol] -version = "0.1.1-git" +version = "0.2.0-git" path = "../protocol" features = ["host"] optional = true diff --git a/crates/protocol-usb/src/device.rs b/crates/protocol-usb/src/device.rs index 490692542..a412d9530 100644 --- a/crates/protocol-usb/src/device.rs +++ b/crates/protocol-usb/src/device.rs @@ -42,31 +42,15 @@ pub trait HasRpc<'a, B: UsbBus> { impl<'a, B: UsbBus, T: HasRpc<'a, B>> Api for Impl<'a, B, T> { fn read() -> Result>, Error> { - T::with_rpc(|rpc| rpc.read()) + T::with_rpc(|x| x.read()) } fn write(response: &[u8]) -> Result<(), Error> { - T::with_rpc(|rpc| rpc.write(response)) + T::with_rpc(|x| x.write(response)) } fn enable() -> Result<(), Error> { - T::with_rpc(|rpc| match rpc.state { - State::Disabled => { - rpc.state = WaitRequest; - Ok(()) - } - _ => Err(Error::user(Code::InvalidState)), - }) - } - - fn disable() -> Result<(), Error> { - T::with_rpc(|rpc| match rpc.state { - State::Disabled => Err(Error::user(Code::InvalidState)), - _ => { - rpc.state = Disabled; - Ok(()) - } - }) + T::with_rpc(|x| x.enable()) } fn vendor(request: &[u8]) -> Result, Error> { @@ -109,6 +93,16 @@ impl<'a, B: UsbBus> Rpc<'a, B> { self.state.write(response, &self.write_ep) } + pub fn enable(&mut self) -> Result<(), Error> { + match self.state { + State::Disabled => { + self.state = WaitRequest; + Ok(()) + } + _ => Err(Error::user(Code::InvalidState)), + } + } + pub fn tick(&mut self, push: impl FnOnce(Event)) { if self.state.notify() { push(Event); diff --git a/crates/protocol-usb/src/host.rs b/crates/protocol-usb/src/host.rs index 7a7f548dc..969760bbd 100644 --- a/crates/protocol-usb/src/host.rs +++ b/crates/protocol-usb/src/host.rs @@ -125,6 +125,12 @@ pub struct Candidate { interface: u8, } +impl Debug for Candidate { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{self}") + } +} + impl Display for Candidate { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let Candidate { device, configuration, interface } = self; @@ -138,7 +144,26 @@ impl Candidate { /// The timeout is used for all send and receive operations using this connection. pub fn connect(self, timeout: Duration) -> rusb::Result> { let Candidate { device, configuration, interface } = self; - let handle = device.open()?; + let handle = device.open().inspect_err(|&e| { + if e == Error::Access { + std::eprintln!( + r#" +You don't have permission to access a USB device that looks like a Wasefire platform: +{device:?} + +If you are running Linux and are in the plugdev group, you can copy/paste the following 4 lines to +add a udev rule for USB devices that look like Wasefire platforms: + +sudo tee /etc/udev/rules.d/99-wasefire.rules << EOF +SUBSYSTEM=="usb", ATTR{{product}}=="Wasefire", ENV{{ID_USB_INTERFACES}}=="*:ff5801:*", MODE="0664", GROUP="plugdev" +EOF +sudo udevadm control --reload + +Then replug your device for the udev rule to take effect. +"# + ); + } + })?; let current_configuration = handle.active_configuration()?; if current_configuration != configuration { log::info!("Configuring the device from {current_configuration} to {configuration}."); @@ -156,6 +181,12 @@ pub struct Connection { timeout: Duration, } +impl Debug for Connection { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{self}") + } +} + impl Display for Connection { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { self.device.fmt(f) diff --git a/crates/protocol-usb/src/lib.rs b/crates/protocol-usb/src/lib.rs index 24254943f..f8bd80ea9 100644 --- a/crates/protocol-usb/src/lib.rs +++ b/crates/protocol-usb/src/lib.rs @@ -19,6 +19,10 @@ #![no_std] #![feature(never_type)] +use wasefire_one_of::exactly_one_of; + +exactly_one_of!["device", "host"]; + extern crate alloc; #[cfg(feature = "std")] extern crate std; diff --git a/crates/protocol/CHANGELOG.md b/crates/protocol/CHANGELOG.md index ed8a1274c..33230580c 100644 --- a/crates/protocol/CHANGELOG.md +++ b/crates/protocol/CHANGELOG.md @@ -1,9 +1,19 @@ # Changelog -## 0.1.1-git +## 0.2.0-git + +### Major + +- Remove `applet::Response` and inline its definition in `AppletResponse::Response` ### Minor +- Add `PlatformLock` to lock a platform protocol +- Add `AppletExitStatus` and `applet::ExitStatus` to get an applet exit status +- Add `Applet{Install,Uninstall}` for applet management +- Add `ConnectionExt::call_ref()` to share a request between calls +- Add a `Service::NAME` constant with `host` feature +- Add `PlatformUpdate{Metadata,Transfer}` calls and `transfer` module for platform updates - Add a `Connection` abstraction with `host` feature ### Patch @@ -12,4 +22,4 @@ ## 0.1.0 - + diff --git a/crates/protocol/Cargo.lock b/crates/protocol/Cargo.lock index 0eedf3978..13b50f5be 100644 --- a/crates/protocol/Cargo.lock +++ b/crates/protocol/Cargo.lock @@ -72,7 +72,7 @@ dependencies = [ [[package]] name = "wasefire-protocol" -version = "0.1.1-git" +version = "0.2.0-git" dependencies = [ "anyhow", "wasefire-error", diff --git a/crates/protocol/Cargo.toml b/crates/protocol/Cargo.toml index 60334eb5b..6fbc6baf3 100644 --- a/crates/protocol/Cargo.toml +++ b/crates/protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasefire-protocol" -version = "0.1.1-git" +version = "0.2.0-git" authors = ["Julien Cretin "] license = "Apache-2.0" publish = true diff --git a/crates/protocol/crates/schema/Cargo.lock b/crates/protocol/crates/schema/Cargo.lock index c375be4a9..3e2ec8fab 100644 --- a/crates/protocol/crates/schema/Cargo.lock +++ b/crates/protocol/crates/schema/Cargo.lock @@ -17,12 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "anstyle" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" - [[package]] name = "anyhow" version = "1.0.86" @@ -62,38 +56,6 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" -[[package]] -name = "camino" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", -] - [[package]] name = "cc" version = "1.0.101" @@ -106,61 +68,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "clap" -version = "4.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" -dependencies = [ - "anstyle", - "clap_lex", -] - -[[package]] -name = "clap_derive" -version = "4.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" - -[[package]] -name = "data-encoding" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" - -[[package]] -name = "derive-where" -version = "1.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -179,24 +86,12 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "indexmap" version = "2.2.6" @@ -207,30 +102,12 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - [[package]] name = "libc" version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" -[[package]] -name = "libusb1-sys" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da050ade7ac4ff1ba5379af847a10a10a8e284181e060105bf8d86960ce9ce0f" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "lock_api" version = "0.4.12" @@ -243,9 +120,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" @@ -332,12 +209,6 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - [[package]] name = "proc-macro2" version = "1.0.84" @@ -365,28 +236,12 @@ dependencies = [ "bitflags", ] -[[package]] -name = "rusb" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab9f9ff05b63a786553a4c02943b74b34a988448671001e9a27e2f0565cc05a4" -dependencies = [ - "libc", - "libusb1-sys", -] - [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - [[package]] name = "schema" version = "0.1.0" @@ -405,15 +260,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" -dependencies = [ - "serde", -] - [[package]] name = "serde" version = "1.0.203" @@ -434,17 +280,6 @@ dependencies = [ "syn", ] -[[package]] -name = "serde_json" -version = "1.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" -dependencies = [ - "itoa", - "ryu", - "serde", -] - [[package]] name = "serde_spanned" version = "0.6.6" @@ -490,26 +325,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "thiserror" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tokio" version = "1.40.0" @@ -579,39 +394,15 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "wasefire-board-api" -version = "0.8.0-git" -dependencies = [ - "derive-where", - "wasefire-error", - "wasefire-logger", - "wasefire-store", -] - [[package]] name = "wasefire-cli-tools" version = "0.2.0-git" dependencies = [ "anyhow", - "cargo_metadata", - "clap", - "data-encoding", - "humantime", - "rusb", + "log", "serde", "tokio", "toml", - "wasefire-protocol", - "wasefire-protocol-tokio", - "wasefire-protocol-usb", - "wasefire-wire", ] [[package]] @@ -621,49 +412,13 @@ dependencies = [ "num_enum", ] -[[package]] -name = "wasefire-logger" -version = "0.1.5" -dependencies = [ - "log", -] - [[package]] name = "wasefire-protocol" -version = "0.1.1-git" -dependencies = [ - "anyhow", - "wasefire-error", - "wasefire-wire", -] - -[[package]] -name = "wasefire-protocol-tokio" -version = "0.1.0-git" -dependencies = [ - "anyhow", - "tokio", - "wasefire-board-api", - "wasefire-logger", - "wasefire-protocol", -] - -[[package]] -name = "wasefire-protocol-usb" version = "0.2.0-git" dependencies = [ "anyhow", - "rusb", - "wasefire-board-api", - "wasefire-logger", - "wasefire-protocol", -] - -[[package]] -name = "wasefire-store" -version = "0.3.0-git" -dependencies = [ "wasefire-error", + "wasefire-wire", ] [[package]] diff --git a/crates/protocol/crates/schema/device.bin b/crates/protocol/crates/schema/device.bin index e8a7bfbb2..ffa4b0622 100644 Binary files a/crates/protocol/crates/schema/device.bin and b/crates/protocol/crates/schema/device.bin differ diff --git a/crates/protocol/crates/schema/device.txt b/crates/protocol/crates/schema/device.txt index a6dccfa07..c75057ce7 100644 --- a/crates/protocol/crates/schema/device.txt +++ b/crates/protocol/crates/schema/device.txt @@ -1,9 +1,15 @@ result: {Ok=0:() Err=1:(space:u8 code:u16)} -version: 2 +version: 4 0 [0 -] ApiVersion: () -> u32 1 [0 -] AppletRequest: (applet_id:() request:[u8]) -> () -2 [0 -] AppletResponse: () -> (response:{None=0:() Some=1:[u8]}) +2 [0 -] AppletResponse: () -> {None=0:() Some=1:[u8]} 3 [0 -] PlatformReboot: () -> {} 4 [0 -] AppletTunnel: (applet_id:() delimiter:[u8]) -> () 5 [1 -] PlatformInfo: () -> (serial:[u8] version:[u8]) 6 [2 -] PlatformVendor: [u8] -> [u8] +7 [3 -] PlatformUpdateMetadata: () -> [u8] +8 [3 -] PlatformUpdateTransfer: {Start=0:(dry_run:bool) Write=1:(chunk:[u8]) Finish=2:()} -> () +9 [4 -] AppletInstall: {Start=0:(dry_run:bool) Write=1:(chunk:[u8]) Finish=2:()} -> () +10 [4 -] AppletUninstall: () -> () +11 [4 -] AppletExitStatus: () -> {None=0:() Some=1:{Exit=0:() Abort=1:() Trap=2:() Kill=3:()}} +12 [4 -] PlatformLock: () -> () diff --git a/crates/protocol/crates/schema/host.bin b/crates/protocol/crates/schema/host.bin index e8a7bfbb2..ffa4b0622 100644 Binary files a/crates/protocol/crates/schema/host.bin and b/crates/protocol/crates/schema/host.bin differ diff --git a/crates/protocol/crates/schema/host.txt b/crates/protocol/crates/schema/host.txt index a6dccfa07..c75057ce7 100644 --- a/crates/protocol/crates/schema/host.txt +++ b/crates/protocol/crates/schema/host.txt @@ -1,9 +1,15 @@ result: {Ok=0:() Err=1:(space:u8 code:u16)} -version: 2 +version: 4 0 [0 -] ApiVersion: () -> u32 1 [0 -] AppletRequest: (applet_id:() request:[u8]) -> () -2 [0 -] AppletResponse: () -> (response:{None=0:() Some=1:[u8]}) +2 [0 -] AppletResponse: () -> {None=0:() Some=1:[u8]} 3 [0 -] PlatformReboot: () -> {} 4 [0 -] AppletTunnel: (applet_id:() delimiter:[u8]) -> () 5 [1 -] PlatformInfo: () -> (serial:[u8] version:[u8]) 6 [2 -] PlatformVendor: [u8] -> [u8] +7 [3 -] PlatformUpdateMetadata: () -> [u8] +8 [3 -] PlatformUpdateTransfer: {Start=0:(dry_run:bool) Write=1:(chunk:[u8]) Finish=2:()} -> () +9 [4 -] AppletInstall: {Start=0:(dry_run:bool) Write=1:(chunk:[u8]) Finish=2:()} -> () +10 [4 -] AppletUninstall: () -> () +11 [4 -] AppletExitStatus: () -> {None=0:() Some=1:{Exit=0:() Abort=1:() Trap=2:() Kill=3:()}} +12 [4 -] PlatformLock: () -> () diff --git a/crates/protocol/crates/schema/sync.sh b/crates/protocol/crates/schema/sync.sh new file mode 100755 index 000000000..46fb3ff0c --- /dev/null +++ b/crates/protocol/crates/schema/sync.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# Copyright 2024 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. + +set -e + +cargo run --features=host +cargo run --features=device diff --git a/crates/protocol/src/applet.rs b/crates/protocol/src/applet.rs index b2f1ebe2a..c47f2003b 100644 --- a/crates/protocol/src/applet.rs +++ b/crates/protocol/src/applet.rs @@ -20,11 +20,6 @@ pub struct Request<'a> { pub request: &'a [u8], } -#[derive(Debug, Wire)] -pub struct Response<'a> { - pub response: Option<&'a [u8]>, -} - #[derive(Debug, Copy, Clone, Wire)] pub struct AppletId; @@ -33,3 +28,18 @@ pub struct Tunnel<'a> { pub applet_id: AppletId, pub delimiter: &'a [u8], } + +#[derive(Debug, Copy, Clone, Wire)] +pub enum ExitStatus { + /// The applet exited successfully. + Exit, + + /// The applet aborted (e.g. it panicked). + Abort, + + /// The applet trapped (e.g. bad memory access). + Trap, + + /// The applet was killed (e.g. it was uninstalled). + Kill, +} diff --git a/crates/protocol/src/connection.rs b/crates/protocol/src/connection.rs index 869c85964..7fb5e7129 100644 --- a/crates/protocol/src/connection.rs +++ b/crates/protocol/src/connection.rs @@ -13,6 +13,7 @@ // limitations under the License. use alloc::boxed::Box; +use alloc::format; use core::future::Future; use core::pin::Pin; @@ -45,10 +46,16 @@ pub trait ConnectionExt: Connection { /// Calls a service on the device. fn call( &mut self, request: S::Request<'_>, + ) -> impl Future>>> { + async { self.call_ref::(&S::request(request)).await } + } + + fn call_ref( + &mut self, request: &Api, ) -> impl Future>>> { async { - self.send(&S::request(request)).await.context("sending request")?; - self.receive::().await.context("receiving response") + self.send(request).await.with_context(|| format!("sending {}", S::NAME))?; + self.receive::().await.with_context(|| format!("receiving {}", S::NAME)) } } @@ -69,7 +76,7 @@ pub trait ConnectionExt: Connection { let response = ApiResult::::decode_yoke(response).context("decoding response")?; response.try_map(|x| match x { ApiResult::Ok(x) => Ok(x), - ApiResult::Err(error) => anyhow::bail!("error response: {error}"), + ApiResult::Err(error) => Err(anyhow::Error::new(error)), }) } } diff --git a/crates/protocol/src/lib.rs b/crates/protocol/src/lib.rs index 900e7c103..139387023 100644 --- a/crates/protocol/src/lib.rs +++ b/crates/protocol/src/lib.rs @@ -46,9 +46,12 @@ pub mod applet; #[cfg(feature = "host")] mod connection; pub mod platform; +pub mod transfer; /// Service description. pub trait Service: 'static { + #[cfg(feature = "host")] + const NAME: &str; /// Range of versions implementing this service. #[cfg(feature = "host")] const VERSIONS: Versions; @@ -159,10 +162,10 @@ impl core::fmt::Display for Descriptor { } macro_rules! api { - ($(#![$api:meta])* version = $version:literal; next = $next:literal; $( + ($(#![$api:meta])* $( $(#[doc = $doc:literal])* - $tag:literal [$min:literal - $($max:literal)?] $Name:ident: $request:ty => $response:ty - ),*$(,)?) => { + $tag:literal [$min:literal - $($max:literal)?] $Name:ident: $request:ty => $response:ty, + )* next $next:literal [$version:literal - ]) => { $(#[$api])* #[derive(Debug, Wire)] #[wire(static = T)] #[cfg_attr(feature = "host", wire(range = $next))] @@ -178,6 +181,8 @@ macro_rules! api { pub enum $Name {} $(#[cfg(feature = "host")] ${ignore($max)})? impl Service for $Name { + #[cfg(feature = "host")] + const NAME: &str = stringify!($Name); #[cfg(feature = "host")] const VERSIONS: Versions = api!(versions $min $($max)?); type Request<'a> = $request; @@ -187,7 +192,7 @@ macro_rules! api { } )* /// Device API version (or maximum supported device API version for host). - pub const VERSION: u32 = $version; + pub const VERSION: u32 = $version - 1; #[cfg(feature = "_descriptor")] pub const DESCRIPTORS: &'static [Descriptor] = &[ $( @@ -206,10 +211,7 @@ macro_rules! api { api! { //! Protocol API parametric over the message direction. //! - //! Variants gated by the `full` feature are deprecated. They won't be used by new devices. - //! However, to support older devices, the host must be able to use them. - version = 2; - next = 7; + //! Deprecated variants are only available to the host (to support older devices). /// Returns the device API version. 0 [0 -] ApiVersion: () => u32, @@ -218,7 +220,7 @@ api! { 1 [0 -] AppletRequest: applet::Request<'a> => (), /// Reads a response from an applet. - 2 [0 -] AppletResponse: applet::AppletId => applet::Response<'a>, + 2 [0 -] AppletResponse: applet::AppletId => Option<&'a [u8]>, /// Reboots the platform. 3 [0 -] PlatformReboot: () => !, @@ -231,4 +233,26 @@ api! { /// Calls a vendor-specific platform command. 6 [2 -] PlatformVendor: &'a [u8] => &'a [u8], + + /// Returns the metadata for platform update. + 7 [3 -] PlatformUpdateMetadata: () => &'a [u8], + + /// Updates the platform. + 8 [3 -] PlatformUpdateTransfer: transfer::Request<'a> => (), + + /// Installs an applet. + 9 [4 -] AppletInstall: transfer::Request<'a> => (), + + /// Uninstalls an applet. + 10 [4 -] AppletUninstall: () => (), + + /// Returns the exit status of an applet, if not running. + 11 [4 -] AppletExitStatus: applet::AppletId => Option, + + /// Locks a platform until reboot. + /// + /// This is useful for testing purposes by locking a platform before flashing a new one. + 12 [4 -] PlatformLock: () => (), + + next 13 [5 -] } diff --git a/crates/protocol/src/transfer.rs b/crates/protocol/src/transfer.rs new file mode 100644 index 000000000..20fb94806 --- /dev/null +++ b/crates/protocol/src/transfer.rs @@ -0,0 +1,42 @@ +// Copyright 2024 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. + +//! Protocol to transfer data from the host to the device. + +use wasefire_wire::Wire; + +/// Requests to transfer data. +/// +/// The responses contain no information and just use the unit type. +#[derive(Debug, Wire)] +pub enum Request<'a> { + /// Starts a transfer. + Start { + /// Whether the transfer is a dry-run. + /// + /// In dry-run mode, all mutable operations are skipped. + dry_run: bool, + }, + + /// Writes a chunk of data. + /// + /// Should only be used between a `Start` and a `Finish`. + Write { + /// The next chunk of data to transfer. + chunk: &'a [u8], + }, + + /// Finishes a transfer. + Finish, +} diff --git a/crates/runner-host/Cargo.lock b/crates/runner-host/Cargo.lock index 70d7d5268..bb4720923 100644 --- a/crates/runner-host/Cargo.lock +++ b/crates/runner-host/Cargo.lock @@ -213,38 +213,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" -[[package]] -name = "camino" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", -] - [[package]] name = "cc" version = "1.0.98" @@ -551,21 +519,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" version = "0.3.30" @@ -582,23 +535,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" -[[package]] -name = "futures-executor" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - [[package]] name = "futures-macro" version = "0.3.30" @@ -628,13 +564,10 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ - "futures-channel", "futures-core", - "futures-io", "futures-macro", "futures-sink", "futures-task", - "memchr", "pin-project-lite", "pin-utils", "slab", @@ -916,18 +849,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "libusb1-sys" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da050ade7ac4ff1ba5379af847a10a10a8e284181e060105bf8d86960ce9ce0f" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "lock_api" version = "0.4.12" @@ -1316,10 +1237,7 @@ dependencies = [ "clap", "data-encoding", "env_logger", - "futures", "rand", - "signal-hook", - "signal-hook-tokio", "tokio", "usb-device", "usbd-serial", @@ -1329,6 +1247,7 @@ dependencies = [ "wasefire-error", "wasefire-interpreter", "wasefire-logger", + "wasefire-one-of", "wasefire-protocol-tokio", "wasefire-protocol-usb", "wasefire-scheduler", @@ -1336,16 +1255,6 @@ dependencies = [ "web-server", ] -[[package]] -name = "rusb" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab9f9ff05b63a786553a4c02943b74b34a988448671001e9a27e2f0565cc05a4" -dependencies = [ - "libc", - "libusb1-sys", -] - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -1395,15 +1304,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" -dependencies = [ - "serde", -] - [[package]] name = "serde" version = "1.0.202" @@ -1478,16 +1378,6 @@ dependencies = [ "digest", ] -[[package]] -name = "signal-hook" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" -dependencies = [ - "libc", - "signal-hook-registry", -] - [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -1497,18 +1387,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signal-hook-tokio" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213241f76fb1e37e27de3b6aa1b068a2c333233b59cca6634f634b80a27ecf1e" -dependencies = [ - "futures-core", - "libc", - "signal-hook", - "tokio", -] - [[package]] name = "signature" version = "2.2.0" @@ -1869,12 +1747,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.4" @@ -1927,12 +1799,13 @@ dependencies = [ [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "sealed", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -1948,7 +1821,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -1984,18 +1857,10 @@ name = "wasefire-cli-tools" version = "0.2.0-git" dependencies = [ "anyhow", - "cargo_metadata", - "clap", - "data-encoding", - "humantime", - "rusb", + "log", "serde", "tokio", "toml", - "wasefire-protocol", - "wasefire-protocol-tokio", - "wasefire-protocol-usb", - "wasefire-wire", ] [[package]] @@ -2017,16 +1882,19 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" dependencies = [ "log", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-protocol" -version = "0.1.1-git" +version = "0.2.0-git" dependencies = [ - "anyhow", "wasefire-error", "wasefire-wire", ] @@ -2040,25 +1908,23 @@ dependencies = [ "wasefire-board-api", "wasefire-error", "wasefire-logger", - "wasefire-protocol", + "wasefire-one-of", ] [[package]] name = "wasefire-protocol-usb" version = "0.2.0-git" dependencies = [ - "anyhow", - "rusb", "usb-device", "wasefire-board-api", "wasefire-error", "wasefire-logger", - "wasefire-protocol", + "wasefire-one-of", ] [[package]] name = "wasefire-scheduler" -version = "0.3.2-git" +version = "0.4.0-git" dependencies = [ "bytemuck", "derive-where", @@ -2070,6 +1936,7 @@ dependencies = [ "wasefire-error", "wasefire-interpreter", "wasefire-logger", + "wasefire-one-of", "wasefire-protocol", "wasefire-store", "wasefire-sync", diff --git a/crates/runner-host/Cargo.toml b/crates/runner-host/Cargo.toml index a6b3a2ca2..7da539977 100644 --- a/crates/runner-host/Cargo.toml +++ b/crates/runner-host/Cargo.toml @@ -11,35 +11,34 @@ anyhow = "1.0.86" clap = { version = "4.5.4", features = ["derive"] } data-encoding = "2.6.0" env_logger = "0.11.3" -futures = "0.3.30" rand = "0.8.5" -signal-hook = "0.3.17" -signal-hook-tokio = { version = "0.3.1", features = ["futures-v0_3"] } tokio = { version = "1.40.0", features = ["full"] } -usb-device = { version = "0.3.2", optional = true } -usbd-serial = { version = "0.2.2", optional = true } -usbip-device = { version = "0.2.0", optional = true } +usb-device = "0.3.2" +usbd-serial = "0.2.2" +usbip-device = "0.2.0" wasefire-board-api = { path = "../board", features = ["std"] } -wasefire-cli-tools = { path = "../cli-tools", optional = true } +wasefire-cli-tools = { path = "../cli-tools" } wasefire-error = { path = "../error" } wasefire-interpreter = { path = "../interpreter", optional = true } wasefire-logger = { path = "../logger" } -wasefire-protocol-tokio = { path = "../protocol-tokio", features = ["device"], optional = true } -wasefire-protocol-usb = { path = "../protocol-usb", features = ["device", "std"], optional = true } +wasefire-one-of = { path = "../one-of" } +wasefire-protocol-tokio = { path = "../protocol-tokio", features = ["device"] } +wasefire-protocol-usb = { path = "../protocol-usb", features = ["device", "std"] } wasefire-store = { path = "../store", features = ["std"] } -web-server = { path = "crates/web-server", optional = true } +web-server = { path = "crates/web-server" } [dependencies.wasefire-scheduler] path = "../scheduler" features = [ + "applet-api-platform", + "applet-api-platform-protocol", "board-api-button", "board-api-led", - "board-api-platform", - "board-api-platform-protocol", "board-api-rng", "board-api-storage", "board-api-timer", "board-api-uart", + "board-api-usb-serial", "software-crypto-aes128-ccm", "software-crypto-aes256-gcm", "software-crypto-hmac-sha256", @@ -52,23 +51,11 @@ features = [ ] [features] -default = ["usb"] -web = ["dep:wasefire-cli-tools", "dep:web-server"] -# Exactly one platform protocol must be selected. -tcp = ["dep:wasefire-protocol-tokio"] -unix = ["dep:wasefire-protocol-tokio"] -usb = [ - "dep:usb-device", - "dep:usbd-serial", - "dep:usbip-device", - "dep:wasefire-protocol-usb", - "wasefire-scheduler/board-api-usb-serial", -] # Exactly one is enabled by xtask. debug = [ "wasefire-logger/log", - "wasefire-protocol-tokio?/log", - "wasefire-protocol-usb?/log", + "wasefire-protocol-tokio/log", + "wasefire-protocol-usb/log", "wasefire-scheduler/log", ] release = [] diff --git a/crates/runner-host/crates/web-server/Cargo.lock b/crates/runner-host/crates/web-server/Cargo.lock index b80ca4e08..ff30f0e35 100644 --- a/crates/runner-host/crates/web-server/Cargo.lock +++ b/crates/runner-host/crates/web-server/Cargo.lock @@ -1040,7 +1040,7 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" [[package]] name = "wasi" diff --git a/crates/runner-host/crates/web-server/src/lib.rs b/crates/runner-host/crates/web-server/src/lib.rs index 774ed89f3..9341961ac 100644 --- a/crates/runner-host/crates/web-server/src/lib.rs +++ b/crates/runner-host/crates/web-server/src/lib.rs @@ -12,11 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::net::IpAddr; +use std::net::SocketAddr; use std::sync::{Arc, Mutex}; use std::time::Duration; -use anyhow::{Context, Result}; +use anyhow::Result; use futures_util::{SinkExt, StreamExt}; use tokio::sync::{mpsc, oneshot}; use warp::ws::{Message, WebSocket}; @@ -26,6 +26,7 @@ use web_common::{ButtonState, Command, Component}; #[derive(Debug, Copy, Clone)] pub enum Event { + Exit, Button { pressed: bool }, } @@ -34,11 +35,7 @@ pub struct Client { } impl Client { - pub async fn new(url: &str, events: mpsc::Sender) -> Result { - let (addr, port) = url.split_once(':').context("URL is not :")?; - let addr: IpAddr = addr.parse().context("parsing in URL")?; - let port: u16 = port.parse().context("parsing in URL")?; - + pub async fn new(addr: SocketAddr, events: mpsc::Sender) -> Result { let (sender, mut receiver) = oneshot::channel(); let client = Arc::new(Mutex::new(Some((sender, events)))); @@ -49,8 +46,8 @@ impl Client { .map(|ws: warp::ws::Ws, client| ws.on_upgrade(|socket| handle(socket, client))); let routes = warp::get().and(static_files.or(ws)); - tokio::spawn(async move { warp::serve(routes).run((addr, port)).await }); - let url = format!("http://{addr}:{port}/"); + tokio::spawn(async move { warp::serve(routes).run(addr).await }); + let url = format!("http://{addr}/"); // Wait 2 seconds for a client to connect, otherwise open a browser. The client is supposed // to connect every second. This should ensure that at most one client is open. @@ -165,7 +162,7 @@ async fn handle(mut ws: WebSocket, client: ClientInput) { } } log::info!("The client disconnected. Exiting the runner."); - std::process::exit(0); + event_sender.send(Event::Exit).await.unwrap(); } fn to_message(command: &Command) -> Message { diff --git a/crates/runner-host/src/board.rs b/crates/runner-host/src/board.rs index edcb1a8f8..70f47932f 100644 --- a/crates/runner-host/src/board.rs +++ b/crates/runner-host/src/board.rs @@ -12,16 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. +pub mod applet; pub mod button; mod crypto; mod debug; mod led; -mod platform; +pub mod platform; mod rng; mod storage; pub mod timer; pub mod uart; -#[cfg(feature = "usb")] pub mod usb; use tokio::sync::mpsc::Sender; @@ -37,13 +37,10 @@ pub struct State { pub led: bool, pub timers: timer::Timers, pub uarts: uart::Uarts, - #[cfg(any(feature = "tcp", feature = "unix"))] - pub pipe: wasefire_protocol_tokio::Pipe, - #[cfg(feature = "usb")] - pub usb: usb::Usb, + pub protocol: platform::protocol::State, + pub usb: usb::State, pub storage: Option, - #[cfg(feature = "web")] - pub web: web_server::Client, + pub web: Option, } pub enum Board {} @@ -65,6 +62,7 @@ impl Api for Board { } } + type Applet = applet::Impl; type Button = button::Impl; type Crypto = crypto::Impl; type Debug = debug::Impl; @@ -74,6 +72,5 @@ impl Api for Board { type Storage = storage::Impl; type Timer = timer::Impl; type Uart = uart::Impl; - #[cfg(feature = "usb")] type Usb = usb::Impl; } diff --git a/crates/runner-host/src/board/applet.rs b/crates/runner-host/src/board/applet.rs new file mode 100644 index 000000000..a44723729 --- /dev/null +++ b/crates/runner-host/src/board/applet.rs @@ -0,0 +1,112 @@ +// Copyright 2024 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. + +use std::path::{Path, PathBuf}; +use std::sync::Mutex; + +use tokio::runtime::Handle; +use wasefire_board_api::applet::Api; +use wasefire_board_api::Error; +use wasefire_cli_tools::fs; +use wasefire_error::Code; + +pub enum Impl {} + +impl Api for Impl { + unsafe fn get() -> Result<&'static [u8], Error> { + with_state(|x| x.get()) + } + + fn start(dry_run: bool) -> Result<(), Error> { + with_state(|x| Handle::current().block_on(x.start(dry_run))) + } + + fn write(chunk: &[u8]) -> Result<(), Error> { + with_state(|x| x.write(chunk)) + } + + fn finish() -> Result<(), Error> { + with_state(|x| Handle::current().block_on(x.finish())) + } +} + +pub async fn init(path: PathBuf) { + let applet = read(&path).await; + *STATE.lock().unwrap() = Some(State { path, applet, update: None }); +} + +async fn read(path: &Path) -> Option<&'static [u8]> { + let content = fs::read(path).await.ok()?; + Some(Box::leak(content.into_boxed_slice())) +} + +fn with_state(f: impl FnOnce(&mut State) -> Result) -> Result { + let mut state = STATE.lock().map_err(|_| Error::world(Code::InvalidState))?; + let state = state.as_mut().ok_or_else(|| Error::internal(Code::InvalidState))?; + f(state) +} + +static STATE: Mutex> = Mutex::new(None); + +struct State { + path: PathBuf, + applet: Option<&'static [u8]>, // shared Box<[u8]> + update: Option, +} + +struct Update { + dry_run: bool, + buffer: Vec, +} + +impl State { + fn get(&mut self) -> Result<&'static [u8], Error> { + if self.update.is_some() { + return Err(Error::user(Code::InvalidState)); + } + Ok(self.applet.unwrap_or_default()) + } + + async fn start(&mut self, dry_run: bool) -> Result<(), Error> { + self.update = Some(Update { dry_run, buffer: Vec::new() }); + if dry_run { + return Ok(()); + } + if let Some(applet) = std::mem::take(&mut self.applet) { + drop(unsafe { Box::from_raw(applet as *const [u8] as *mut [u8]) }); + fs::remove_file(&self.path).await.map_err(|_| Error::world(0))?; + } + Ok(()) + } + + fn write(&mut self, chunk: &[u8]) -> Result<(), Error> { + match &mut self.update { + Some(x) => Ok(x.buffer.extend_from_slice(chunk)), + None => Err(Error::user(Code::InvalidState)), + } + } + + async fn finish(&mut self) -> Result<(), Error> { + let update = match std::mem::take(&mut self.update) { + Some(x) => x, + None => return Err(Error::user(Code::InvalidState)), + }; + if update.dry_run || update.buffer.is_empty() { + return Ok(()); + } + fs::write(&self.path, &update.buffer).await.map_err(|_| Error::world(0))?; + self.applet = Some(Box::leak(update.buffer.into_boxed_slice())); + Ok(()) + } +} diff --git a/crates/runner-host/src/board/debug.rs b/crates/runner-host/src/board/debug.rs index 3f03274da..87716840a 100644 --- a/crates/runner-host/src/board/debug.rs +++ b/crates/runner-host/src/board/debug.rs @@ -15,18 +15,20 @@ use std::sync::OnceLock; use std::time::Instant; -use wasefire_board_api as board; +use {wasefire_board_api as board, wasefire_logger as log}; pub enum Impl {} impl board::debug::Api for Impl { const MAX_TIME: u64 = u64::MAX; - #[cfg(feature = "web")] fn println(line: &str) { let time = Self::time(); let message = format!("{}.{:06}: {}", time / 1000000, time % 1000000, line); - crate::with_state(|state| state.web.println(message)) + crate::with_state(|state| match &state.web { + Some(x) => x.println(message), + None => log::println!("{message}"), + }) } fn time() -> u64 { @@ -35,9 +37,4 @@ impl board::debug::Api for Impl { let origin = ORIGIN.get_or_init(|| now); now.duration_since(*origin).as_micros() as u64 } - - fn exit(success: bool) -> ! { - crate::cleanup::flush(); - std::process::exit(if success { 0 } else { 1 }) - } } diff --git a/crates/runner-host/src/board/led.rs b/crates/runner-host/src/board/led.rs index 432b9b93e..d9297c37d 100644 --- a/crates/runner-host/src/board/led.rs +++ b/crates/runner-host/src/board/led.rs @@ -31,12 +31,12 @@ impl Api for Impl { fn set(id: Id, on: bool) -> Result<(), Error> { assert_eq!(*id, 0); - #[cfg(not(feature = "web"))] - println!("Led is {}", if on { "on" } else { "off" }); with_state(|state| { - #[cfg(feature = "web")] - state.web.set_led(on); - state.led = on + match &state.web { + Some(x) => x.set_led(on), + None => println!("Led is {}", if on { "on" } else { "off" }), + } + state.led = on; }); Ok(()) } diff --git a/crates/runner-host/src/board/platform.rs b/crates/runner-host/src/board/platform.rs index a20eee9bb..0faa18a8b 100644 --- a/crates/runner-host/src/board/platform.rs +++ b/crates/runner-host/src/board/platform.rs @@ -19,14 +19,14 @@ use wasefire_board_api::platform::Api; use wasefire_board_api::Error; use wasefire_error::Code; +pub mod protocol; + pub enum Impl {} impl Api for Impl { - #[cfg(any(feature = "tcp", feature = "unix"))] - type Protocol = wasefire_protocol_tokio::Impl; + type Protocol = protocol::Impl; - #[cfg(feature = "usb")] - type Protocol = crate::board::usb::ProtocolImpl; + type Update = UpdateImpl; fn serial() -> Cow<'static, [u8]> { from_hex(option_env!("WASEFIRE_HOST_SERIAL")) @@ -41,43 +41,25 @@ impl Api for Impl { } } -fn from_hex(x: Option<&str>) -> Cow<'static, [u8]> { - HEXLOWER_PERMISSIVE.decode(x.unwrap_or_default().as_bytes()).unwrap().into() +pub enum UpdateImpl {} +impl wasefire_board_api::Support for UpdateImpl { + const SUPPORT: bool = false; } - -pub(crate) fn vendor(request: &[u8]) -> Result, Error> { - if let Some(request) = request.strip_prefix(b"echo ") { - let mut response = request.to_vec().into_boxed_slice(); - for x in &mut response { - if x.is_ascii_alphabetic() { - *x ^= 0x20; - } - if matches!(*x, b'I' | b'O' | b'i' | b'o') { - *x ^= 0x6; - } - } - Ok(response) - } else { - Err(Error::user(Code::InvalidArgument)) +impl wasefire_board_api::platform::update::Api for UpdateImpl { + fn metadata() -> Result, Error> { + Err(Error::world(Code::NotImplemented)) + } + fn initialize(_dry_run: bool) -> Result<(), Error> { + Err(Error::world(Code::NotImplemented)) + } + fn process(_chunk: &[u8]) -> Result<(), Error> { + Err(Error::world(Code::NotImplemented)) + } + fn finalize() -> Result<(), Error> { + Err(Error::world(Code::NotImplemented)) } } -#[cfg(any(feature = "tcp", feature = "unix"))] -mod pipe { - use wasefire_error::Error; - use wasefire_protocol_tokio::{HasPipe, Pipe}; - - use crate::with_state; - - pub enum Impl {} - - impl HasPipe for Impl { - fn with_pipe(f: impl FnOnce(&mut Pipe) -> R) -> R { - with_state(|state| f(&mut state.pipe)) - } - - fn vendor(request: &[u8]) -> Result, Error> { - super::vendor(request) - } - } +fn from_hex(x: Option<&str>) -> Cow<'static, [u8]> { + HEXLOWER_PERMISSIVE.decode(x.unwrap_or_default().as_bytes()).unwrap().into() } diff --git a/crates/runner-host/src/board/platform/protocol.rs b/crates/runner-host/src/board/platform/protocol.rs new file mode 100644 index 000000000..824ef7972 --- /dev/null +++ b/crates/runner-host/src/board/platform/protocol.rs @@ -0,0 +1,66 @@ +// Copyright 2024 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. + +use wasefire_board_api::platform::protocol::Api; +use wasefire_error::{Code, Error}; +use wasefire_protocol_tokio::Pipe; + +use crate::with_state; + +pub enum Impl {} + +impl Api for Impl { + fn read() -> Result>, Error> { + with_state(|state| match &mut state.protocol { + State::Pipe(x) => x.read(), + State::Usb => state.usb.protocol().read(), + }) + } + + fn write(response: &[u8]) -> Result<(), Error> { + with_state(|state| match &mut state.protocol { + State::Pipe(x) => x.write(response), + State::Usb => state.usb.protocol().write(response), + }) + } + + fn enable() -> Result<(), Error> { + with_state(|state| match &mut state.protocol { + State::Pipe(x) => x.enable(), + State::Usb => state.usb.protocol().enable(), + }) + } + + fn vendor(request: &[u8]) -> Result, Error> { + if let Some(request) = request.strip_prefix(b"echo ") { + let mut response = request.to_vec().into_boxed_slice(); + for x in &mut response { + if x.is_ascii_alphabetic() { + *x ^= 0x20; + } + if matches!(*x, b'I' | b'O' | b'i' | b'o') { + *x ^= 0x6; + } + } + Ok(response) + } else { + Err(Error::user(Code::InvalidArgument)) + } + } +} + +pub enum State { + Pipe(Pipe), + Usb, +} diff --git a/crates/runner-host/src/board/usb.rs b/crates/runner-host/src/board/usb.rs index 6202a453e..bf5a6543e 100644 --- a/crates/runner-host/src/board/usb.rs +++ b/crates/runner-host/src/board/usb.rs @@ -12,113 +12,119 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::process::{Child, Command}; +use std::process::{Child, Command, Stdio}; use std::time::Duration; use anyhow::{ensure, Result}; +use usb_device::class::UsbClass; use usb_device::class_prelude::UsbBusAllocator; use usb_device::device::StringDescriptors; use usb_device::prelude::{UsbDevice, UsbDeviceBuilder, UsbVidPid}; use usb_device::UsbError; use usbd_serial::SerialPort; use usbip_device::UsbIpBus; -use wasefire_board_api::usb::serial::{HasSerial, Serial, WithSerial}; +use wasefire_board_api::usb::serial::Serial; use wasefire_board_api::usb::Api; -use wasefire_error::Error; -use wasefire_protocol_usb::{HasRpc, Rpc}; +use wasefire_error::{Code, Error}; +use wasefire_protocol_usb::Rpc; -use crate::board::State; use crate::with_state; -pub enum Impl {} +mod serial; -pub type ProtocolImpl = wasefire_protocol_usb::Impl<'static, UsbIpBus, crate::board::usb::Impl>; +pub enum Impl {} impl Api for Impl { - type Serial = WithSerial; + type Serial = serial::Impl; } -impl HasRpc<'static, UsbIpBus> for Impl { - fn with_rpc(f: impl FnOnce(&mut Rpc<'static, UsbIpBus>) -> R) -> R { - with_state(|state| f(&mut state.usb.protocol)) - } - - fn vendor(request: &[u8]) -> Result, Error> { - crate::board::platform::vendor(request) - } +pub struct State { + protocol: Option>, + serial: Option>, + // Some iff at least one class is Some. + usb_dev: Option>, } -impl HasSerial for Impl { - type UsbBus = UsbIpBus; - - fn with_serial(f: impl FnOnce(&mut Serial) -> R) -> R { - with_state(|state| f(&mut state.usb.serial)) +pub fn init() -> Result<()> { + if with_state(|x| x.usb.usb_dev.is_none()) { + return Ok(()); } + ensure!( + spawn(&["sudo", "modprobe", "vhci-hcd"]).wait().unwrap().code() == Some(0), + "failed to load kernel module for USB/IP" + ); + let mut usbip = spawn(&["sudo", "usbip", "attach", "-r", "localhost", "-b", "1-1"]); + loop { + with_state(|state| state.usb.poll()); + match usbip.try_wait().unwrap() { + None => continue, + Some(e) => ensure!(e.code() == Some(0), "failed to attach remote USB/IP device"), + } + break; + } + tokio::spawn(async move { + loop { + tokio::time::sleep(Duration::from_millis(1)).await; + with_state(|state| { + let polled = state.usb.poll(); + let crate::board::State { sender, usb: State { protocol, serial, .. }, .. } = state; + if let Some(protocol) = protocol { + protocol.tick(|event| drop(sender.try_send(event.into()))); + } + if let Some(serial) = serial { + let has_serial = + !matches!(serial.port().read(&mut []), Err(UsbError::WouldBlock)); + serial.tick(polled && has_serial, |event| drop(sender.try_send(event.into()))); + } + }); + } + }); + Ok(()) } -pub struct Usb { - pub protocol: Rpc<'static, UsbIpBus>, - pub serial: Serial<'static, UsbIpBus>, - pub usb_dev: UsbDevice<'static, UsbIpBus>, -} - -impl Default for Usb { - fn default() -> Self { +impl State { + pub fn new(vid_pid: &str, protocol: bool, serial: bool) -> Self { + let mut state = State { protocol: None, serial: None, usb_dev: None }; + if !protocol && !serial { + return state; + } let usb_bus = Box::leak(Box::new(UsbBusAllocator::new(UsbIpBus::new()))); - let protocol = Rpc::new(usb_bus); - let serial = Serial::new(SerialPort::new(usb_bus)); - // TODO: VID and PID should be configurable. - let usb_dev = UsbDeviceBuilder::new(usb_bus, UsbVidPid(0x16c0, 0x27dd)) - .strings(&[StringDescriptors::new(usb_device::LangID::EN).product("Wasefire")]) - .unwrap() - .build(); - Self { protocol, serial, usb_dev } + if protocol { + state.protocol = Some(Rpc::new(usb_bus)); + } + if serial { + state.serial = Some(Serial::new(SerialPort::new(usb_bus))); + } + let (vid, pid) = vid_pid.split_once(':').expect("--usb-vid-pid must be VID:PID"); + let vid = u16::from_str_radix(vid, 16).expect("invalid VID"); + let pid = u16::from_str_radix(pid, 16).expect("invalid PID"); + state.usb_dev = Some( + UsbDeviceBuilder::new(usb_bus, UsbVidPid(vid, pid)) + .strings(&[StringDescriptors::new(usb_device::LangID::EN).product("Wasefire")]) + .unwrap() + .build(), + ); + state } -} -impl Usb { - pub fn init() -> Result<()> { - ensure!( - spawn(&["sudo", "modprobe", "vhci-hcd"]).wait().unwrap().code() == Some(0), - "failed to load kernel module for USB/IP" - ); - let mut usbip = spawn(&["sudo", "usbip", "attach", "-r", "localhost", "-b", "1-1"]); - loop { - with_state(|state| state.usb.poll()); - match usbip.try_wait().unwrap() { - None => continue, - Some(e) => ensure!(e.code() == Some(0), "failed to attach remote USB/IP device"), - } - break; - } - tokio::spawn({ - async move { - loop { - tokio::time::sleep(Duration::from_millis(1)).await; - with_state(|state| { - let polled = state.usb.poll(); - let has_serial = !matches!( - state.usb.serial.port().read(&mut []), - Err(UsbError::WouldBlock) - ); - let State { sender, usb: Usb { protocol, serial, .. }, .. } = state; - protocol.tick(|event| drop(sender.try_send(event.into()))); - serial.tick(polled && has_serial, |event| { - drop(sender.try_send(event.into())) - }); - }); - } - } - }); - Ok(()) + pub fn protocol(&mut self) -> &mut Rpc<'static, UsbIpBus> { + self.protocol.as_mut().unwrap() + } + + pub fn serial(&mut self) -> Result<&mut Serial<'static, UsbIpBus>, Error> { + self.serial.as_mut().ok_or(Error::world(Code::NotImplemented)) } - pub fn poll(&mut self) -> bool { - self.usb_dev.poll(&mut [&mut self.protocol, self.serial.port()]) + fn poll(&mut self) -> bool { + let usb_dev = self.usb_dev.as_mut().unwrap(); + let mut classes = Vec::<&mut dyn UsbClass<_>>::with_capacity(2); + classes.extend(self.protocol.as_mut().map(|x| x as &mut dyn UsbClass<_>)); + classes.extend(self.serial.as_mut().map(|x| x.port() as &mut dyn UsbClass<_>)); + usb_dev.poll(&mut classes) } } fn spawn(cmd: &[&str]) -> Child { println!("Executing: {}", cmd.join(" ")); - Command::new(cmd[0]).args(&cmd[1 ..]).spawn().unwrap() + Command::new(cmd[0]).args(&cmd[1 ..]).stdin(Stdio::null()).spawn().unwrap() } diff --git a/crates/runner-host/src/board/usb/serial.rs b/crates/runner-host/src/board/usb/serial.rs new file mode 100644 index 000000000..4b357f974 --- /dev/null +++ b/crates/runner-host/src/board/usb/serial.rs @@ -0,0 +1,42 @@ +// Copyright 2024 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. + +use wasefire_board_api::usb::serial::{Api, Event}; +use wasefire_error::Error; + +use crate::with_state; + +pub enum Impl {} + +impl Api for Impl { + fn read(output: &mut [u8]) -> Result { + with_state(|x| x.usb.serial()?.read(output)) + } + + fn write(input: &[u8]) -> Result { + with_state(|x| x.usb.serial()?.write(input)) + } + + fn flush() -> Result<(), Error> { + with_state(|x| x.usb.serial()?.flush()) + } + + fn enable(event: &Event) -> Result<(), Error> { + with_state(|x| x.usb.serial()?.enable(event)) + } + + fn disable(event: &Event) -> Result<(), Error> { + with_state(|x| x.usb.serial()?.disable(event)) + } +} diff --git a/crates/runner-host/src/cleanup.rs b/crates/runner-host/src/cleanup.rs index 3dc3775e1..e6e7f5f59 100644 --- a/crates/runner-host/src/cleanup.rs +++ b/crates/runner-host/src/cleanup.rs @@ -12,20 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::io::Write; use std::sync::Mutex; pub type Cleanup = Box; -#[cfg(feature = "unix")] pub fn push(cleanup: Cleanup) { CLEANUP.lock().unwrap().push(cleanup); } -pub fn flush() { +pub fn shutdown(status: i32) -> ! { let cleanups = std::mem::take(&mut *CLEANUP.lock().unwrap()); for cleanup in cleanups { cleanup(); } + wasefire_logger::flush(); + _ = std::io::stdout().flush(); + _ = std::io::stderr().flush(); + std::process::exit(status) } static CLEANUP: Mutex> = Mutex::new(Vec::new()); diff --git a/crates/runner-host/src/main.rs b/crates/runner-host/src/main.rs index 79c954be9..357d936e7 100644 --- a/crates/runner-host/src/main.rs +++ b/crates/runner-host/src/main.rs @@ -15,23 +15,31 @@ #![feature(never_type)] #![feature(try_blocks)] -use std::path::Path; +use std::net::SocketAddr; +use std::path::PathBuf; use std::sync::Mutex; use anyhow::Result; -use board::Board; use clap::Parser; -use tokio::runtime::Handle; +use tokio::select; use tokio::sync::mpsc::{channel, Receiver}; use wasefire_board_api::Event; #[cfg(feature = "wasm")] use wasefire_interpreter as _; +use wasefire_one_of::exactly_one_of; +use wasefire_protocol_tokio::Pipe; use wasefire_scheduler::Scheduler; use wasefire_store::{FileOptions, FileStorage}; +use crate::board::platform::protocol::State as ProtocolState; +use crate::board::Board; + mod board; mod cleanup; +exactly_one_of!["debug", "release"]; +exactly_one_of!["native", "wasm"]; + static STATE: Mutex> = Mutex::new(None); static RECEIVER: Mutex>>> = Mutex::new(None); @@ -41,17 +49,40 @@ fn with_state(f: impl FnOnce(&mut board::State) -> R) -> R { #[derive(Parser)] struct Flags { - #[cfg(feature = "tcp")] - #[clap(long, default_value = "127.0.0.1:3457")] - tcp_addr: std::net::SocketAddr, + /// Directory containing files representing the flash. + #[arg(long, default_value = "../../target/wasefire")] + flash_dir: PathBuf, + + /// Transport to listen to for the platform protocol. + #[arg(long, default_value = "usb")] + protocol: Protocol, + + /// Socket address to bind to when --protocol=tcp (ignored otherwise). + #[arg(long, default_value = "127.0.0.1:3457")] + tcp_addr: SocketAddr, + + /// Socket path to bind to when --protocol=unix (ignored otherwise). + #[arg(long, default_value = "/tmp/wasefire")] + unix_path: PathBuf, - #[cfg(feature = "unix")] - #[clap(long, default_value = "/tmp/wasefire")] - unix_path: std::path::PathBuf, + /// The VID:PID to use for the USB device. + /// + /// A USB device is used when --protocol=usb or --usb-serial (ignored otherwise). Note that USB + /// requires sudo. + #[arg(long, default_value = "16c0:27dd")] + usb_vid_pid: String, - #[cfg(feature = "web")] - #[clap(flatten)] - web_options: WebOptions, + /// Whether to enable USB serial. + #[arg(long)] + usb_serial: bool, + + /// User interface to interact with the board. + #[arg(long, default_value = "stdio")] + interface: Interface, + + /// Socket address to bind to when --interface=web (ignored otherwise). + #[arg(long, default_value = "127.0.0.1:5000")] + web_addr: SocketAddr, } #[test] @@ -59,113 +90,118 @@ fn flags() { ::command().debug_assert(); } -#[derive(clap::Args)] -struct WebOptions { - /// Host to start the webserver. - #[clap(long, default_value = "127.0.0.1")] - web_host: String, +#[derive(Clone, clap::ValueEnum)] +enum Protocol { + Tcp, + Unix, + Usb, +} - /// Port to start the webserver. - #[clap(long, default_value = "5000")] - web_port: u16, +#[derive(Clone, clap::ValueEnum)] +enum Interface { + Stdio, + Web, } #[tokio::main] async fn main() -> Result<()> { env_logger::init(); - #[cfg_attr(feature = "usb", allow(unused_variables))] let flags = Flags::parse(); std::panic::set_hook(Box::new(|info| { eprintln!("{info}"); - use wasefire_board_api::debug::Api; - wasefire_board_api::Debug::::exit(false); + cleanup::shutdown(1) })); tokio::spawn(async { - use futures::stream::StreamExt; - use signal_hook::consts::{SIGINT, SIGTERM}; - let mut signals = signal_hook_tokio::Signals::new([SIGINT, SIGTERM]).unwrap(); - assert!(signals.next().await.is_none()); + use tokio::signal::unix::{signal, SignalKind}; + let mut sigint = signal(SignalKind::interrupt()).unwrap(); + let mut sigterm = signal(SignalKind::terminate()).unwrap(); + let signal = select! { + _ = sigint.recv() => SignalKind::interrupt(), + _ = sigterm.recv() => SignalKind::terminate(), + }; + cleanup::shutdown(128 + signal.as_raw_value()); }); - // TODO: Should be a flag controlled by xtask (value is duplicated there). - const STORAGE: &str = "../../target/wasefire/storage.bin"; + wasefire_cli_tools::fs::create_dir_all(&flags.flash_dir).await?; + let storage = flags.flash_dir.join("storage.bin"); let options = FileOptions { word_size: 4, page_size: 4096, num_pages: 16 }; - let storage = Some(FileStorage::new(Path::new(STORAGE), options).unwrap()); + let storage = Some(FileStorage::new(&storage, options)?); + board::applet::init(flags.flash_dir.join("applet.bin")).await; let (sender, receiver) = channel(10); *RECEIVER.lock().unwrap() = Some(receiver); - #[cfg(feature = "web")] - let web = { - let (sender, mut receiver) = channel(10); - tokio::spawn(async move { - while let Some(event) = receiver.recv().await { - match event { - web_server::Event::Button { pressed } => { - with_state(|state| board::button::event(state, Some(pressed))); + let web = match flags.interface { + Interface::Stdio => None, + Interface::Web => { + let (sender, mut receiver) = channel(10); + tokio::spawn(async move { + while let Some(event) = receiver.recv().await { + match event { + web_server::Event::Exit => cleanup::shutdown(0), + web_server::Event::Button { pressed } => { + with_state(|state| board::button::event(state, Some(pressed))); + } } } - } - }); - let mut trunk = tokio::process::Command::new("../../scripts/wrapper.sh"); - trunk.args(["trunk", "build", "--release", "crates/web-client/index.html"]); - wasefire_cli_tools::cmd::execute(&mut trunk).await?; - let url = format!("{}:{}", flags.web_options.web_host, flags.web_options.web_port); - web_server::Client::new(&url, sender).await? + }); + let mut trunk = tokio::process::Command::new("../../scripts/wrapper.sh"); + trunk.args(["trunk", "build", "--release", "crates/web-client/index.html"]); + wasefire_cli_tools::cmd::execute(&mut trunk).await?; + Some(web_server::Client::new(flags.web_addr, sender).await?) + } }; - #[cfg(any(feature = "tcp", feature = "unix"))] let push = { use wasefire_board_api::platform::protocol::Event; let sender = sender.clone(); move |event: Event| drop(sender.try_send(event.into())) }; - #[cfg(feature = "tcp")] - let pipe = wasefire_protocol_tokio::Pipe::new_tcp(flags.tcp_addr, push).await.unwrap(); - #[cfg(feature = "unix")] - let pipe = { - let pipe = wasefire_protocol_tokio::Pipe::new_unix(&flags.unix_path, push).await.unwrap(); - let unix_path = flags.unix_path.clone(); - crate::cleanup::push(Box::new(move || drop(std::fs::remove_file(unix_path)))); - pipe + let protocol = match flags.protocol { + Protocol::Tcp => ProtocolState::Pipe(Pipe::new_tcp(flags.tcp_addr, push).await.unwrap()), + Protocol::Unix => { + let pipe = Pipe::new_unix(&flags.unix_path, push).await.unwrap(); + let unix_path = flags.unix_path.clone(); + cleanup::push(Box::new(move || drop(std::fs::remove_file(unix_path)))); + ProtocolState::Pipe(pipe) + } + Protocol::Usb => ProtocolState::Usb, }; + let usb = board::usb::State::new( + &flags.usb_vid_pid, + matches!(protocol, ProtocolState::Usb), + flags.usb_serial, + ); *STATE.lock().unwrap() = Some(board::State { sender, button: false, led: false, timers: board::timer::Timers::default(), uarts: board::uart::Uarts::new(), - #[cfg(any(feature = "tcp", feature = "unix"))] - pipe, - #[cfg(feature = "usb")] - usb: board::usb::Usb::default(), + protocol, + usb, storage, - #[cfg(feature = "web")] web, }); board::uart::Uarts::init(); - #[cfg(feature = "usb")] - board::usb::Usb::init()?; - #[cfg(not(feature = "web"))] - tokio::task::spawn_blocking(|| { - use std::io::BufRead; - // The tokio::io::Stdin documentation recommends to use blocking IO in a dedicated thread. - // Note that because of this, the runtime may not exit until the user press enter. - for line in std::io::stdin().lock().lines() { - let pressed = match line.unwrap().as_str() { - "button" => None, - "press" => Some(true), - "release" => Some(false), - x => { - println!("Unrecognized command: {x}"); - continue; - } - }; - with_state(|state| board::button::event(state, pressed)); - } - }); + board::usb::init()?; + if matches!(flags.interface, Interface::Stdio) { + tokio::task::spawn_blocking(|| { + use std::io::BufRead; + // The tokio::io::Stdin documentation recommends to use blocking IO in a dedicated + // thread. Note that because of this, the runtime may not exit until the + // user press enter. + for line in std::io::stdin().lock().lines() { + let pressed = match line.unwrap().as_str() { + "button" => None, + "press" => Some(true), + "release" => Some(false), + x => { + println!("Unrecognized command: {x}"); + continue; + } + }; + with_state(|state| board::button::event(state, pressed)); + } + }); + } println!("Board initialized. Starting scheduler."); - #[cfg(feature = "wasm")] - const WASM: &[u8] = include_bytes!("../../../target/wasefire/applet.wasm"); - #[cfg(feature = "wasm")] - Handle::current().spawn_blocking(|| Scheduler::::run(WASM)).await?; - #[cfg(feature = "native")] - Handle::current().spawn_blocking(|| Scheduler::::run()).await?; - Ok(()) + // Not sure why Rust doesn't figure out this can't return (maybe async). + let _: ! = tokio::task::spawn_blocking(|| Scheduler::::run()).await?; } diff --git a/crates/runner-host/test.sh b/crates/runner-host/test.sh index 30e57b774..f7624706c 100755 --- a/crates/runner-host/test.sh +++ b/crates/runner-host/test.sh @@ -22,8 +22,5 @@ ensure_applet test_helper cargo test --bin=runner-host --features=wasm,debug -cargo check --bin=runner-host --features=wasm,debug,web cargo check --bin=runner-host --features=wasm,release cargo check --bin=runner-host --target=i686-unknown-linux-gnu --features=native,release -cargo check --bin=runner-host --no-default-features --features=wasm,debug,tcp -cargo check --bin=runner-host --no-default-features --features=wasm,debug,unix diff --git a/crates/runner-nordic/Cargo.lock b/crates/runner-nordic/Cargo.lock index 1fbbbda54..fa0d208ee 100644 --- a/crates/runner-nordic/Cargo.lock +++ b/crates/runner-nordic/Cargo.lock @@ -187,15 +187,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "cortex-m-semihosting" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c23234600452033cc77e4b761e740e02d2c4168e11dbf36ab14a0f58973592b0" -dependencies = [ - "cortex-m", -] - [[package]] name = "cpufeatures" version = "0.2.12" @@ -842,7 +833,6 @@ version = "0.1.0" dependencies = [ "cortex-m", "cortex-m-rt", - "cortex-m-semihosting", "critical-section", "defmt", "defmt-rtt", @@ -864,6 +854,7 @@ dependencies = [ "wasefire-error", "wasefire-interpreter", "wasefire-logger", + "wasefire-one-of", "wasefire-protocol-usb", "wasefire-scheduler", "wasefire-store", @@ -1098,12 +1089,13 @@ dependencies = [ [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "sealed", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -1119,7 +1111,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -1169,14 +1161,18 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" dependencies = [ "defmt", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-protocol" -version = "0.1.1-git" +version = "0.2.0-git" dependencies = [ "wasefire-error", "wasefire-wire", @@ -1191,11 +1187,12 @@ dependencies = [ "wasefire-board-api", "wasefire-error", "wasefire-logger", + "wasefire-one-of", ] [[package]] name = "wasefire-scheduler" -version = "0.3.2-git" +version = "0.4.0-git" dependencies = [ "bytemuck", "defmt", @@ -1208,6 +1205,7 @@ dependencies = [ "wasefire-error", "wasefire-interpreter", "wasefire-logger", + "wasefire-one-of", "wasefire-protocol", "wasefire-store", "wasefire-sync", diff --git a/crates/runner-nordic/Cargo.toml b/crates/runner-nordic/Cargo.toml index 804898aac..35901b16c 100644 --- a/crates/runner-nordic/Cargo.toml +++ b/crates/runner-nordic/Cargo.toml @@ -9,7 +9,6 @@ edition = "2021" [dependencies] cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } cortex-m-rt = { version = "0.7.3", features = ["set-vtor"] } -cortex-m-semihosting = "0.5.0" critical-section = "1.1.2" defmt = { version = "0.3.8", features = ["avoid-default-panic"], optional = true } defmt-rtt = { version = "0.4.1", optional = true } @@ -29,6 +28,7 @@ wasefire-board-api = { path = "../board" } wasefire-error = { path = "../error" } wasefire-interpreter = { path = "../interpreter", optional = true } wasefire-logger = { path = "../logger" } +wasefire-one-of = { version = "0.1.0-git", path = "../one-of" } wasefire-protocol-usb = { path = "../protocol-usb", features = ["device"] } wasefire-store = { path = "../store" } wasefire-sync = { path = "../sync" } @@ -45,13 +45,13 @@ features = ["52840"] [dependencies.wasefire-scheduler] path = "../scheduler" features = [ + "applet-api-platform", + "applet-api-platform-protocol", + "applet-api-platform-update", "board-api-button", "board-api-crypto-aes128-ccm", "board-api-gpio", "board-api-led", - "board-api-platform", - "board-api-platform-protocol", - "board-api-platform-update", "board-api-radio-ble", "board-api-rng", "board-api-storage", @@ -61,10 +61,9 @@ features = [ ] [features] -# Software crypto features. The software-crypto feature enables all of them. -software-crypto = ["software-crypto-aes256-gcm", "software-crypto-p256", "software-crypto-sha256"] +# Software crypto features. software-crypto-aes256-gcm = ["wasefire-scheduler/software-crypto-aes256-gcm"] -software-crypto-p256 = ["wasefire-scheduler/software-crypto-p256"] +software-crypto-p256 = ["software-crypto-sha256", "wasefire-scheduler/software-crypto-p256"] software-crypto-sha256 = ["wasefire-scheduler/software-crypto-sha256"] # Exactly one is enabled by xtask. debug = [ @@ -81,6 +80,8 @@ release = ["dep:panic-abort"] # Exactly one is enabled by xtask. native = ["wasefire-scheduler/native"] wasm = ["dep:wasefire-interpreter", "wasefire-scheduler/wasm"] +# Internal features. +_software-crypto = ["software-crypto-aes256-gcm", "software-crypto-p256", "software-crypto-sha256"] [lints] clippy.unit-arg = "allow" diff --git a/crates/runner-nordic/crates/header/src/lib.rs b/crates/runner-nordic/crates/header/src/lib.rs index 3c92ae23d..1c24aaa3d 100644 --- a/crates/runner-nordic/crates/header/src/lib.rs +++ b/crates/runner-nordic/crates/header/src/lib.rs @@ -111,4 +111,4 @@ unsafe fn read(addr: u32) -> u32 { // Keep those values in sync with the memory.x linker script. const HEADER_LEN: u32 = 0x00000100; const FIRMWARE_A: u32 = 0x00010000; -const FIRMWARE_B: u32 = 0x00080000; +const FIRMWARE_B: u32 = 0x00060000; diff --git a/crates/runner-nordic/memory.x b/crates/runner-nordic/memory.x index 62621167d..2bc57865f 100644 --- a/crates/runner-nordic/memory.x +++ b/crates/runner-nordic/memory.x @@ -7,22 +7,30 @@ RAM: Flash: - 0x00000000 bootloader (64KiB) -- 0x00010000 platform A (448KiB) -- 0x00080000 platform B (448KiB) +- 0x00010000 platform A (320KiB) +- 0x00060000 platform B (320KiB) +- 0x000b0000 applet (256KiB) - 0x000f0000 persistent storage (64KiB) - 0x00100000 */ -/* Keep those values in sync with the bootloader. */ -__header_origin = 0x00010000 + RUNNER_SIDE * 0x00070000; +/* Keep those values in sync with the header crate used by the bootloader. */ +__bootloader_size = 0x00010000; +__platform_size = 0x00050000; +__applet_size = 0x00040000; +ASSERT(__bootloader_size + __platform_size == 0x00060000, "bad layout"); +ASSERT(__bootloader_size + 2 * __platform_size + __applet_size == 0x000f0000, "bad layout"); +__header_origin = __bootloader_size + RUNNER_SIDE * __platform_size; __header_length = 0x00000100; __flash_origin = __header_origin + __header_length; -__flash_length = 0x00070000 - __header_length; -__sother = 0x00010000 + (1 - RUNNER_SIDE) * 0x00070000; -__eother = __sother + 0x00070000; -/* Keep those values in sync with --reset-storage in xtask */ -__sstore = 0x000f0000; +__flash_length = __platform_size - __header_length; +__sother = __bootloader_size + (1 - RUNNER_SIDE) * __platform_size; +__eother = __sother + __platform_size; +/* Keep those values in sync with --reset-flash in xtask */ +__sapplet = __bootloader_size + 2 * __platform_size; +__eapplet = __sapplet + __applet_size; +__sstore = __eapplet; __estore = 0x00100000; __stack_origin = 0x20000000; diff --git a/crates/runner-nordic/src/board.rs b/crates/runner-nordic/src/board.rs index 86c091145..85bcb541f 100644 --- a/crates/runner-nordic/src/board.rs +++ b/crates/runner-nordic/src/board.rs @@ -18,6 +18,7 @@ use wasefire_scheduler as scheduler; use crate::{with_state, Board}; +pub mod applet; pub mod button; mod crypto; mod debug; @@ -53,6 +54,7 @@ impl board::Api for Board { } } + type Applet = applet::Impl; type Button = button::Impl; type Crypto = crypto::Impl; type Debug = debug::Impl; diff --git a/crates/runner-nordic/src/board/applet.rs b/crates/runner-nordic/src/board/applet.rs new file mode 100644 index 000000000..d8779c875 --- /dev/null +++ b/crates/runner-nordic/src/board/applet.rs @@ -0,0 +1,90 @@ +// Copyright 2024 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. + +use wasefire_board_api::applet::Api; +use wasefire_board_api::Error; +use wasefire_store::{Storage as _, StorageIndex}; +use wasefire_sync::TakeCell; + +use crate::storage::{Storage, StorageWriter}; + +pub enum Impl {} + +impl Api for Impl { + unsafe fn get() -> Result<&'static [u8], Error> { + STATE.with(|state| { + let storage = unsafe { state.writer.get() }?; + Ok(&storage[.. state.size]) + }) + } + + fn start(dry_run: bool) -> Result<(), Error> { + STATE.with(|state| { + state.size = 0; + state.writer.start(dry_run) + }) + } + + fn write(chunk: &[u8]) -> Result<(), Error> { + STATE.with(|state| { + state.writer.write(chunk)?; + state.size += chunk.len(); + Ok(()) + }) + } + + fn finish() -> Result<(), Error> { + STATE.with(|state| { + let dry_run = state.writer.dry_run()?; + state.writer.finish()?; + if dry_run { + Ok(state.size = read_size(state.writer.storage())?) + } else { + write_size(state.writer.storage_mut(), state.size) + } + }) + } +} + +pub fn init(storage: Storage) { + let size = read_size(&storage).unwrap_or(0); + let state = State { writer: StorageWriter::new(storage), size }; + STATE.put(state); +} + +static STATE: TakeCell = TakeCell::new(None); + +struct State { + writer: StorageWriter, + // In sync with the complement of the last 4 bytes of the storage (native-endian) outside a + // write process. + size: usize, +} + +fn last_word(storage: &Storage) -> StorageIndex { + let num_pages = storage.num_pages(); + let word_size = storage.word_size(); + let page_size = storage.page_size(); + StorageIndex { page: num_pages - 1, byte: page_size - word_size } +} + +fn read_size(storage: &Storage) -> Result { + let word_size = storage.word_size(); + let slice = storage.read_slice(last_word(storage), word_size)?; + Ok(!usize::from_ne_bytes(*<&[u8; 4]>::try_from(&slice[..]).unwrap())) +} + +fn write_size(storage: &mut Storage, size: usize) -> Result<(), Error> { + storage.write_slice(last_word(storage), &(!size).to_ne_bytes()) +} diff --git a/crates/runner-nordic/src/board/debug.rs b/crates/runner-nordic/src/board/debug.rs index d4199e76e..1d207b831 100644 --- a/crates/runner-nordic/src/board/debug.rs +++ b/crates/runner-nordic/src/board/debug.rs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use cortex_m_semihosting::debug; use wasefire_board_api as board; pub enum Impl {} @@ -30,12 +29,4 @@ impl board::debug::Api for Impl { let time = 0; time } - - fn exit(success: bool) -> ! { - #[cfg(feature = "debug")] - defmt::flush(); - let status = if success { debug::EXIT_SUCCESS } else { debug::EXIT_FAILURE }; - debug::exit(status); - unreachable!(); - } } diff --git a/crates/runner-nordic/src/board/platform.rs b/crates/runner-nordic/src/board/platform.rs index e7b0f5a06..707565250 100644 --- a/crates/runner-nordic/src/board/platform.rs +++ b/crates/runner-nordic/src/board/platform.rs @@ -53,7 +53,6 @@ impl Api for Impl { } pub fn reboot() -> ! { - #[cfg(feature = "debug")] - defmt::flush(); + wasefire_logger::flush(); nrf52840_hal::pac::SCB::sys_reset() } diff --git a/crates/runner-nordic/src/board/platform/update.rs b/crates/runner-nordic/src/board/platform/update.rs index 9fcd0d9d3..f27f0a843 100644 --- a/crates/runner-nordic/src/board/platform/update.rs +++ b/crates/runner-nordic/src/board/platform/update.rs @@ -47,7 +47,7 @@ impl Api for Impl { fn finalize() -> Result<(), Error> { STATE.with(|state| { let dry_run = state.dry_run()?; - state.flush()?; + state.finish()?; match dry_run { true => Ok(()), false => super::reboot(), diff --git a/crates/runner-nordic/src/main.rs b/crates/runner-nordic/src/main.rs index 159e1dac6..da3990b77 100644 --- a/crates/runner-nordic/src/main.rs +++ b/crates/runner-nordic/src/main.rs @@ -57,6 +57,7 @@ use wasefire_board_api::{Id, Support}; #[cfg(feature = "wasm")] use wasefire_interpreter as _; use wasefire_logger as log; +use wasefire_one_of::exactly_one_of; use wasefire_scheduler::Scheduler; use crate::board::button::{channel, Button}; @@ -68,6 +69,9 @@ use crate::board::usb::Usb; use crate::board::{button, led, Events}; use crate::storage::Storage; +exactly_one_of!["debug", "release"]; +exactly_one_of!["native", "wasm"]; + #[cfg(feature = "debug")] #[defmt::panic_handler] fn panic() -> ! { @@ -169,6 +173,7 @@ fn main() -> ! { storage::init(p.NVMC); let storage = Some(Storage::new_store()); crate::board::platform::update::init(Storage::new_other()); + crate::board::applet::init(Storage::new_applet()); let uart_rx = port0.p0_28.into_floating_input().degrade(); let uart_tx = port0.p0_29.into_push_pull_output(gpio::Level::High).degrade(); let uarts = Uarts::new(p.UARTE0, uart_rx, uart_tx, p.UARTE1); @@ -197,11 +202,6 @@ fn main() -> ! { unsafe { NVIC::unmask(interrupt) }; } log::debug!("Runner is initialized."); - #[cfg(feature = "wasm")] - const WASM: &[u8] = include_bytes!("../../../target/wasefire/applet.wasm"); - #[cfg(feature = "wasm")] - Scheduler::::run(WASM); - #[cfg(feature = "native")] Scheduler::::run(); } diff --git a/crates/runner-nordic/src/storage.rs b/crates/runner-nordic/src/storage.rs index ba36f5c1f..c19109339 100644 --- a/crates/runner-nordic/src/storage.rs +++ b/crates/runner-nordic/src/storage.rs @@ -70,16 +70,20 @@ impl Storage { Storage::new(take_storage!(__sother .. __eother)) } + pub fn new_applet() -> Self { + Storage::new(take_storage!(__sapplet .. __eapplet)) + } + /// Returns an exclusive reference to the storage. /// /// This object is locked until the reference is released with `put()`. - pub fn take(&self) -> &'static mut [u8] { + fn take(&self) -> &'static mut [u8] { assert!(!self.used.swap(true, Ordering::Acquire)); unsafe { &mut *self.ptr } } - pub fn put(&self, data: &'static mut [u8]) { - assert_eq!(data as *mut [u8], self.ptr); + fn put(&self, data: &'static mut [u8]) { + assert_eq!(core::ptr::from_mut(data), self.ptr); assert!(self.used.swap(false, Ordering::Release)); } @@ -88,16 +92,12 @@ impl Storage { /// # Safety /// /// The returned reference is invalidated when `take()` is called. - pub unsafe fn get(&self) -> &'static [u8] { + unsafe fn get(&self) -> &'static [u8] { assert!(!self.used.load(Ordering::Acquire)); unsafe { &*self.ptr } } - pub fn ptr(&self) -> *const u8 { - self.ptr as *const u8 - } - - pub fn len(&self) -> usize { + fn len(&self) -> usize { self.ptr.len() } } @@ -117,6 +117,26 @@ impl StorageWriter { StorageWriter { storage, dry_run: None, offset: 0, buffer: Vec::with_capacity(WORD_SIZE) } } + pub fn storage(&self) -> &Storage { + &self.storage + } + + pub fn storage_mut(&mut self) -> &mut Storage { + &mut self.storage + } + + /// Returns a shared reference to the storage. + /// + /// # Safety + /// + /// The returned reference is invalidated when `start()` is called. + pub unsafe fn get(&self) -> Result<&'static [u8], Error> { + if self.dry_run.is_some() { + return Err(Error::user(Code::InvalidState)); + } + Ok(unsafe { self.storage.get() }) + } + pub fn dry_run(&self) -> Result { self.dry_run.ok_or(Error::user(Code::InvalidState)) } @@ -181,7 +201,7 @@ impl StorageWriter { Ok(()) } - pub fn flush(&mut self) -> Result<(), Error> { + pub fn finish(&mut self) -> Result<(), Error> { if !self.buffer.is_empty() { assert!(self.buffer.len() < WORD_SIZE); self.buffer.resize(WORD_SIZE, 0xff); diff --git a/crates/runner-nordic/test.sh b/crates/runner-nordic/test.sh index 9e87e1b04..2ecc13c75 100755 --- a/crates/runner-nordic/test.sh +++ b/crates/runner-nordic/test.sh @@ -22,7 +22,7 @@ ensure_applet test_helper cargo check --bin=runner-nordic --target=thumbv7em-none-eabi --features=wasm,debug -cargo check --bin=runner-nordic --target=thumbv7em-none-eabi --features=wasm,debug,software-crypto +cargo check --bin=runner-nordic --target=thumbv7em-none-eabi --features=wasm,debug,_software-crypto DEFMT_LOG=trace cargo check --bin=runner-nordic --target=thumbv7em-none-eabi --features=wasm,debug cargo check --bin=runner-nordic --target=thumbv7em-none-eabi --features=wasm,release cargo check --bin=runner-nordic --target=thumbv7em-none-eabi --features=native,release diff --git a/crates/scheduler/CHANGELOG.md b/crates/scheduler/CHANGELOG.md index e182dd6bc..f9c034ee9 100644 --- a/crates/scheduler/CHANGELOG.md +++ b/crates/scheduler/CHANGELOG.md @@ -1,9 +1,24 @@ # Changelog -## 0.3.2-git +## 0.4.0-git + +### Major + +- Remove `board-api-platform{,-protocol,-update}` features + +### Minor + +- Trap applets calling into host during init (except for debug printing) +- Support `PlatformLock` protocol call +- Support `AppletExitStatus` protocol call (the platform keeps running when the applet exits) +- Support `Applet{Install,Uninstall}` protocol calls +- Migrate from `debug::exit()` to `scheduling::exit()` +- Support `PlatformUpdate{Metadata,Transfer}` protocol calls ### Patch +- Reduce logging level of applet trapping (those are not errors) +- Make sure at compile-time that exactly one `native` or `wasm` feature is enabled - Use `derive-where` instead of `derivative` - Implement `defmt::Format` for `Key` when `defmt` is enabled - Stop using `log::Debug2Format()` when logging events @@ -152,4 +167,4 @@ ## 0.1.0 - + diff --git a/crates/scheduler/Cargo.lock b/crates/scheduler/Cargo.lock index 94776ae89..99c4fc342 100644 --- a/crates/scheduler/Cargo.lock +++ b/crates/scheduler/Cargo.lock @@ -716,12 +716,13 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "sealed", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -737,7 +738,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -791,15 +792,19 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" dependencies = [ "defmt", "log", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-protocol" -version = "0.1.1-git" +version = "0.2.0-git" dependencies = [ "wasefire-error", "wasefire-wire", @@ -807,7 +812,7 @@ dependencies = [ [[package]] name = "wasefire-scheduler" -version = "0.3.2-git" +version = "0.4.0-git" dependencies = [ "bytemuck", "defmt", @@ -820,6 +825,7 @@ dependencies = [ "wasefire-error", "wasefire-interpreter", "wasefire-logger", + "wasefire-one-of", "wasefire-protocol", "wasefire-store", "wasefire-sync", diff --git a/crates/scheduler/Cargo.toml b/crates/scheduler/Cargo.toml index 7059c6920..2e2670128 100644 --- a/crates/scheduler/Cargo.toml +++ b/crates/scheduler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasefire-scheduler" -version = "0.3.2-git" +version = "0.4.0-git" authors = ["Julien Cretin "] license = "Apache-2.0" publish = true @@ -22,10 +22,12 @@ derive-where = { version = "1.2.7", default-features = false, features = ["night digest = { version = "0.10.7", default-features = false, features = ["mac"], optional = true } generic-array = { version = "=0.14.7", default-features = false, optional = true } typenum = { version = "1.17.0", default-features = false, optional = true } -wasefire-applet-api = { version = "0.6.2-git", path = "../api", features = ["host"] } +wasefire-applet-api = { version = "0.7.0-git", path = "../api", features = ["host"] } wasefire-board-api = { version = "0.8.0-git", path = "../board" } wasefire-error = { version = "0.1.2-git", path = "../error" } -wasefire-logger = { version = "0.1.5", path = "../logger" } +wasefire-logger = { version = "0.1.6-git", path = "../logger" } +wasefire-one-of = { version = "0.1.0-git", path = "../one-of" } +wasefire-protocol = { version = "0.2.0-git", path = "../protocol", features = ["device"] } wasefire-store = { version = "0.3.0-git", path = "../store", optional = true } wasefire-sync = { version = "0.1.1", path = "../sync", optional = true } @@ -35,12 +37,6 @@ path = "../interpreter" features = ["toctou"] optional = true -[dependencies.wasefire-protocol] -version = "0.1.1-git" -path = "../protocol" -features = ["device"] -optional = true - [features] std = ["wasefire-board-api/std", "wasefire-store?/std"] # Logging features (enable at most one). @@ -124,22 +120,6 @@ board-api-crypto-sha256 = ["applet-api-crypto-hash", "wasefire-board-api/api-cry board-api-crypto-sha384 = ["applet-api-crypto-hash", "wasefire-board-api/api-crypto-sha384"] board-api-gpio = ["applet-api-gpio", "wasefire-board-api/api-gpio"] board-api-led = ["applet-api-led", "wasefire-board-api/api-led"] -board-api-platform = [ - "applet-api-platform", - "internal-board-api-platform", - "wasefire-board-api/api-platform", -] -board-api-platform-protocol = [ - "applet-api-platform-protocol", - "dep:wasefire-protocol", - "internal-board-api-platform", - "wasefire-board-api/api-platform-protocol", -] -board-api-platform-update = [ - "applet-api-platform-update", - "internal-board-api-platform", - "wasefire-board-api/api-platform-update", -] board-api-radio-ble = [ "applet-api-radio-ble", "internal-board-api-radio", @@ -196,9 +176,6 @@ full-board-api = [ "board-api-crypto-sha384", "board-api-gpio", "board-api-led", - "board-api-platform", - "board-api-platform-protocol", - "board-api-platform-update", "board-api-radio-ble", "board-api-rng", "board-api-storage", @@ -235,7 +212,7 @@ wasm = ["dep:wasefire-interpreter"] # safety invariant. unsafe-skip-validation = [] # Internal features. -_test = ["wasefire-protocol?/_exhaustive"] +_test = ["wasefire-protocol/_exhaustive"] internal-applet-api-crypto = [] internal-applet-api-crypto-hash = ["dep:digest", "dep:generic-array", "internal-applet-api-crypto"] internal-applet-api-platform = [] @@ -243,7 +220,6 @@ internal-applet-api-radio = [] internal-applet-api-store = [] internal-applet-api-usb = [] internal-board-api-crypto-ecc = [] -internal-board-api-platform = [] internal-board-api-radio = [] internal-board-api-usb = [] internal-debug = [] diff --git a/crates/scheduler/src/applet.rs b/crates/scheduler/src/applet.rs index a16da835a..d5cd51342 100644 --- a/crates/scheduler/src/applet.rs +++ b/crates/scheduler/src/applet.rs @@ -12,14 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[cfg(feature = "board-api-platform-protocol")] use alloc::boxed::Box; use alloc::collections::{BTreeSet, VecDeque}; #[cfg(feature = "internal-hash-context")] use wasefire_board_api as board; use wasefire_board_api::{Api as Board, Event}; -#[cfg(feature = "board-api-platform-protocol")] use wasefire_error::{Code, Error}; use wasefire_logger as log; @@ -29,6 +27,22 @@ use crate::Trap; pub mod store; +pub enum Slot { + #[cfg(feature = "wasm")] + Empty, + Running(Applet), + Exited(wasefire_protocol::applet::ExitStatus), +} + +impl Slot { + pub fn get(&mut self) -> Option<&mut Applet> { + match self { + Slot::Running(x) => Some(x), + _ => None, + } + } +} + pub struct Applet { pub store: self::store::Store, @@ -36,7 +50,6 @@ pub struct Applet { events: VecDeque>, /// Protocol request or response, if any. - #[cfg(feature = "board-api-platform-protocol")] protocol: Protocol, /// Whether we returned from a callback. @@ -55,7 +68,6 @@ impl Default for Applet { Self { store: Default::default(), events: Default::default(), - #[cfg(feature = "board-api-platform-protocol")] protocol: Default::default(), #[cfg(feature = "wasm")] done: Default::default(), @@ -66,7 +78,6 @@ impl Default for Applet { } } -#[cfg(feature = "board-api-platform-protocol")] #[derive(Debug, Default)] enum Protocol { #[default] @@ -184,6 +195,15 @@ impl Applet { } } + pub fn free(&mut self) { + self.events.clear(); + for &Handler { key, .. } in &self.handlers { + if let Err(error) = key.disable() { + log::warn!("Failed disabling {:?}: {}", key, error); + } + } + } + pub fn get(&self, key: Key) -> Option<&Handler> { self.handlers.get(&key) } @@ -192,7 +212,6 @@ impl Applet { self.events.len() } - #[cfg(feature = "board-api-platform-protocol")] pub fn put_request(&mut self, event: Event, request: &[u8]) -> Result<(), Error> { self.get(Key::from(&event)).ok_or(Error::world(Code::InvalidState))?; // If the applet is processing a request, we'll send the event when they respond. @@ -204,7 +223,6 @@ impl Applet { Ok(()) } - #[cfg(feature = "board-api-platform-protocol")] pub fn get_request(&mut self) -> Result>, Error> { let (update, result) = match core::mem::take(&mut self.protocol) { x @ (Protocol::Empty | Protocol::Response(_)) => (x, Ok(None)), @@ -215,7 +233,6 @@ impl Applet { result } - #[cfg(feature = "board-api-platform-protocol")] pub fn put_response(&mut self, response: Box<[u8]>) -> Result<(), Error> { match &self.protocol { Protocol::Processing => self.protocol = Protocol::Response(response), @@ -226,7 +243,6 @@ impl Applet { Ok(()) } - #[cfg(feature = "board-api-platform-protocol")] pub fn get_response(&mut self) -> Result>, Error> { let (update, result) = match core::mem::take(&mut self.protocol) { x @ (Protocol::Processing | Protocol::Request(_)) => (x, Ok(None)), diff --git a/crates/scheduler/src/call/debug.rs b/crates/scheduler/src/call/debug.rs index 192e82806..fac7ea092 100644 --- a/crates/scheduler/src/call/debug.rs +++ b/crates/scheduler/src/call/debug.rs @@ -24,7 +24,6 @@ pub fn process(call: Api>) { Api::Println(call) => println(call), Api::Time(call) => time(call), Api::Perf(call) => perf(call), - Api::Exit(call) => exit(call), } } @@ -63,8 +62,3 @@ fn perf(mut call: SchedulerCall) { }; call.reply(result) } - -fn exit(call: SchedulerCall) { - let api::exit::Params { code } = call.read(); - board::Debug::::exit(*code == 0); -} diff --git a/crates/scheduler/src/call/platform.rs b/crates/scheduler/src/call/platform.rs index de367f175..1d217dc4d 100644 --- a/crates/scheduler/src/call/platform.rs +++ b/crates/scheduler/src/call/platform.rs @@ -12,19 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[cfg(feature = "board-api-platform")] +#[cfg(feature = "applet-api-platform")] use wasefire_applet_api::platform as api; use wasefire_applet_api::platform::Api; -#[cfg(feature = "board-api-platform")] +#[cfg(feature = "applet-api-platform")] use wasefire_board_api as board; -#[cfg(feature = "board-api-platform")] +#[cfg(feature = "applet-api-platform")] use wasefire_board_api::platform::Api as _; use wasefire_board_api::Api as Board; -#[cfg(feature = "board-api-platform")] +#[cfg(feature = "applet-api-platform")] use crate::applet::store::MemoryApi; use crate::DispatchSchedulerCall; -#[cfg(feature = "board-api-platform")] +#[cfg(feature = "applet-api-platform")] use crate::{Applet, Failure, SchedulerCall}; #[cfg(feature = "applet-api-platform-protocol")] @@ -39,35 +39,35 @@ pub fn process(call: Api>) { #[cfg(feature = "applet-api-platform-update")] Api::Update(call) => update::process(call), #[cfg(feature = "applet-api-platform")] - Api::Serial(call) => or_fail!("board-api-platform", serial(call)), + Api::Serial(call) => serial(call), #[cfg(feature = "applet-api-platform")] - Api::Version(call) => or_fail!("board-api-platform", version(call)), + Api::Version(call) => version(call), #[cfg(feature = "applet-api-platform")] - Api::Reboot(call) => or_fail!("board-api-platform", reboot(call)), + Api::Reboot(call) => reboot(call), } } -#[cfg(feature = "board-api-platform")] +#[cfg(feature = "applet-api-platform")] fn serial(mut call: SchedulerCall) { let api::serial::Params { ptr } = call.read(); let result = alloc_bytes(call.applet(), *ptr, &board::Platform::::serial()); call.reply(result); } -#[cfg(feature = "board-api-platform")] +#[cfg(feature = "applet-api-platform")] fn version(mut call: SchedulerCall) { let api::version::Params { ptr } = call.read(); let result = alloc_bytes(call.applet(), *ptr, &board::Platform::::version()); call.reply(result); } -#[cfg(feature = "board-api-platform")] +#[cfg(feature = "applet-api-platform")] fn reboot(call: SchedulerCall) { let api::reboot::Params {} = call.read(); call.reply(board::Platform::::reboot().map_err(|x| x.into())); } -#[cfg(feature = "board-api-platform")] +#[cfg(feature = "applet-api-platform")] fn alloc_bytes( applet: &mut Applet, ptr_ptr: u32, data: &[u8], ) -> Result { diff --git a/crates/scheduler/src/call/platform/protocol.rs b/crates/scheduler/src/call/platform/protocol.rs index d513a3e41..71dd84180 100644 --- a/crates/scheduler/src/call/platform/protocol.rs +++ b/crates/scheduler/src/call/platform/protocol.rs @@ -12,29 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[cfg(feature = "board-api-platform-protocol")] use wasefire_applet_api::platform::protocol as api; use wasefire_applet_api::platform::protocol::Api; use wasefire_board_api::Api as Board; -#[cfg(feature = "board-api-platform-protocol")] use crate::applet::store::MemoryApi; -#[cfg(feature = "board-api-platform-protocol")] -use crate::event::{platform::protocol::Key, Handler}; -use crate::DispatchSchedulerCall; -#[cfg(feature = "board-api-platform-protocol")] -use crate::SchedulerCall; +use crate::event::platform::protocol::Key; +use crate::event::Handler; +use crate::{DispatchSchedulerCall, SchedulerCall}; pub fn process(call: Api>) { match call { - Api::Read(call) => or_fail!("board-api-platform-protocol", read(call)), - Api::Write(call) => or_fail!("board-api-platform-protocol", write(call)), - Api::Register(call) => or_fail!("board-api-platform-protocol", register(call)), - Api::Unregister(call) => or_fail!("board-api-platform-protocol", unregister(call)), + Api::Read(call) => read(call), + Api::Write(call) => write(call), + Api::Register(call) => register(call), + Api::Unregister(call) => unregister(call), } } -#[cfg(feature = "board-api-platform-protocol")] fn read(mut call: SchedulerCall) { let api::read::Params { ptr: ptr_ptr, len: len_ptr } = call.read(); let applet = call.applet(); @@ -51,7 +46,6 @@ fn read(mut call: SchedulerCall) { call.reply(result); } -#[cfg(feature = "board-api-platform-protocol")] fn write(mut call: SchedulerCall) { let api::write::Params { ptr, len } = call.read(); let result = try { @@ -61,7 +55,6 @@ fn write(mut call: SchedulerCall) { call.reply(result); } -#[cfg(feature = "board-api-platform-protocol")] fn register(mut call: SchedulerCall) { let api::register::Params { handler_func, handler_data } = call.read(); let inst = call.inst(); @@ -78,7 +71,6 @@ fn register(mut call: SchedulerCall) { call.reply(result); } -#[cfg(feature = "board-api-platform-protocol")] fn unregister(mut call: SchedulerCall) { let api::unregister::Params {} = call.read(); let result = try { diff --git a/crates/scheduler/src/call/platform/update.rs b/crates/scheduler/src/call/platform/update.rs index 71da271d9..83d5bdedb 100644 --- a/crates/scheduler/src/call/platform/update.rs +++ b/crates/scheduler/src/call/platform/update.rs @@ -13,38 +13,28 @@ // limitations under the License. use wasefire_applet_api::platform::update::{self as api, Api}; -#[cfg(feature = "board-api-platform-update")] use wasefire_board_api::platform::update::Api as _; -use wasefire_board_api::Api as Board; -#[cfg(feature = "board-api-platform-update")] -use wasefire_board_api::{self as board, Support}; +use wasefire_board_api::{self as board, Api as Board, Support}; -#[cfg(feature = "board-api-platform-update")] use crate::applet::store::MemoryApi; -#[cfg(feature = "board-api-platform-update")] -use crate::Trap; -use crate::{DispatchSchedulerCall, SchedulerCall}; +use crate::{DispatchSchedulerCall, SchedulerCall, Trap}; pub fn process(call: Api>) { match call { Api::IsSupported(call) => is_supported(call), - Api::Metadata(call) => or_fail!("board-api-platform-update", metadata(call)), - Api::Initialize(call) => or_fail!("board-api-platform-update", initialize(call)), - Api::Process(call) => or_fail!("board-api-platform-update", process_(call)), - Api::Finalize(call) => or_fail!("board-api-platform-update", finalize(call)), + Api::Metadata(call) => metadata(call), + Api::Initialize(call) => initialize(call), + Api::Process(call) => process_(call), + Api::Finalize(call) => finalize(call), } } fn is_supported(call: SchedulerCall) { let api::is_supported::Params {} = call.read(); - #[cfg(feature = "board-api-platform-update")] let supported = board::platform::Update::::SUPPORT as u32; - #[cfg(not(feature = "board-api-platform-update"))] - let supported = 0; call.reply(Ok(supported)) } -#[cfg(feature = "board-api-platform-update")] fn metadata(mut call: SchedulerCall) { let api::metadata::Params { ptr: ptr_ptr, len: len_ptr } = call.read(); let applet = call.applet(); @@ -56,7 +46,6 @@ fn metadata(mut call: SchedulerCall) { call.reply(result); } -#[cfg(feature = "board-api-platform-update")] fn initialize(call: SchedulerCall) { let api::initialize::Params { dry_run } = call.read(); let result = try { @@ -70,7 +59,6 @@ fn initialize(call: SchedulerCall) { call.reply(result); } -#[cfg(feature = "board-api-platform-update")] fn process_(mut call: SchedulerCall) { let api::process::Params { ptr, len } = call.read(); let applet = call.applet(); @@ -82,7 +70,6 @@ fn process_(mut call: SchedulerCall) { call.reply(result); } -#[cfg(feature = "board-api-platform-update")] fn finalize(call: SchedulerCall) { let api::finalize::Params {} = call.read(); call.reply(try { board::platform::Update::::finalize()? }); diff --git a/crates/scheduler/src/call/scheduling.rs b/crates/scheduler/src/call/scheduling.rs index 3faf8eca4..333799e39 100644 --- a/crates/scheduler/src/call/scheduling.rs +++ b/crates/scheduler/src/call/scheduling.rs @@ -22,6 +22,7 @@ pub fn process(call: Api>) { Api::WaitForCallback(call) => wait_for_callback(call), Api::NumPendingCallbacks(call) => num_pending_callbacks(call), Api::Abort(call) => abort(call), + Api::Exit(call) => exit(call), } } @@ -42,3 +43,8 @@ fn abort(call: SchedulerCall) { let api::abort::Params {} = call.read(); call.reply_(Err(crate::Trap.into())); } + +fn exit(call: SchedulerCall) { + let api::exit::Params {} = call.read(); + call.reply_(Err(crate::Trap.into())); +} diff --git a/crates/scheduler/src/call/store.rs b/crates/scheduler/src/call/store.rs index dc2643645..e9be6ff6d 100644 --- a/crates/scheduler/src/call/store.rs +++ b/crates/scheduler/src/call/store.rs @@ -50,7 +50,7 @@ pub fn process(call: Api>) { fn insert(mut call: SchedulerCall) { let api::insert::Params { key, ptr, len } = call.read(); let scheduler = call.scheduler(); - let memory = scheduler.applet.as_mut().unwrap().memory(); + let memory = scheduler.applet.get().unwrap().memory(); let result = try { let value = memory.get(*ptr, *len)?; scheduler.store.insert(*key as usize, value)? @@ -69,7 +69,7 @@ fn remove(mut call: SchedulerCall) { fn find(mut call: SchedulerCall) { let api::find::Params { key, ptr: ptr_ptr, len: len_ptr } = call.read(); let scheduler = call.scheduler(); - let mut memory = scheduler.applet.as_mut().unwrap().memory(); + let mut memory = scheduler.applet.get().unwrap().memory(); let result = try { match scheduler.store.find(*key as usize)? { None => false, @@ -86,7 +86,7 @@ fn find(mut call: SchedulerCall) { fn keys(mut call: SchedulerCall) { let api::keys::Params { ptr: ptr_ptr } = call.read(); let scheduler = call.scheduler(); - let mut memory = scheduler.applet.as_mut().unwrap().memory(); + let mut memory = scheduler.applet.get().unwrap().memory(); let result = try { let mut keys = Vec::new(); for handle in scheduler.store.iter()? { diff --git a/crates/scheduler/src/call/store/fragment.rs b/crates/scheduler/src/call/store/fragment.rs index 41be984c9..6c084bf60 100644 --- a/crates/scheduler/src/call/store/fragment.rs +++ b/crates/scheduler/src/call/store/fragment.rs @@ -37,7 +37,7 @@ pub fn process(call: Api>) { fn insert(mut call: SchedulerCall) { let api::insert::Params { keys, ptr, len } = call.read(); let scheduler = call.scheduler(); - let memory = scheduler.applet.as_mut().unwrap().memory(); + let memory = scheduler.applet.get().unwrap().memory(); let result = try { let keys = decode_keys(keys)?; let value = memory.get(*ptr, *len)?; @@ -57,7 +57,7 @@ fn remove(mut call: SchedulerCall) { fn find(mut call: SchedulerCall) { let api::find::Params { keys, ptr: ptr_ptr, len: len_ptr } = call.read(); let scheduler = call.scheduler(); - let mut memory = scheduler.applet.as_mut().unwrap().memory(); + let mut memory = scheduler.applet.get().unwrap().memory(); let result = try { match fragment::read(&scheduler.store, &decode_keys(keys)?)? { None => false, diff --git a/crates/scheduler/src/event.rs b/crates/scheduler/src/event.rs index 6ecb5a1fd..2070cb4e7 100644 --- a/crates/scheduler/src/event.rs +++ b/crates/scheduler/src/event.rs @@ -17,6 +17,7 @@ use core::borrow::Borrow; use derive_where::derive_where; use wasefire_board_api::{Api as Board, Event, Impossible}; +use wasefire_error::Error; #[cfg(feature = "wasm")] pub use wasefire_interpreter::InstId; use wasefire_logger as log; @@ -25,7 +26,6 @@ use crate::Scheduler; #[cfg(feature = "board-api-button")] pub mod button; -#[cfg(feature = "internal-board-api-platform")] pub mod platform; #[cfg(feature = "internal-board-api-radio")] pub mod radio; @@ -46,7 +46,6 @@ pub struct InstId; pub enum Key { #[cfg(feature = "board-api-button")] Button(button::Key), - #[cfg(feature = "internal-board-api-platform")] Platform(platform::Key), #[cfg(feature = "internal-board-api-radio")] Radio(radio::Key), @@ -77,7 +76,6 @@ impl<'a, B: Board> From<&'a Event> for Key { Event::Button(event) => { or_unreachable!("applet-api-button", [event], Key::Button(event.into())) } - #[cfg(feature = "internal-board-api-platform")] Event::Platform(event) => { or_unreachable!( "internal-applet-api-platform", @@ -106,6 +104,25 @@ impl<'a, B: Board> From<&'a Event> for Key { } } +impl Key { + pub fn disable(self) -> Result<(), Error> { + match self { + #[cfg(feature = "board-api-button")] + Key::Button(x) => x.disable(), + Key::Platform(x) => x.disable(), + #[cfg(feature = "internal-board-api-radio")] + Key::Radio(x) => x.disable::(), + #[cfg(feature = "board-api-timer")] + Key::Timer(x) => x.disable(), + #[cfg(feature = "board-api-uart")] + Key::Uart(x) => x.disable(), + #[cfg(feature = "internal-board-api-usb")] + Key::Usb(x) => x.disable::(), + Key::_Impossible(x) => x.unreachable(), + } + } +} + #[derive_where(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Handler { pub key: Key, @@ -122,7 +139,7 @@ impl Borrow> for Handler { #[cfg_attr(feature = "native", allow(clippy::needless_pass_by_ref_mut))] pub fn process(scheduler: &mut Scheduler, event: Event) { - let applet = scheduler.applet.as_mut().unwrap(); + let applet = scheduler.applet.get().unwrap(); let (inst, func, data) = match applet.get(Key::from(&event)) { Some(x) => (x.inst, x.func, x.data), None => { @@ -138,10 +155,7 @@ pub fn process(scheduler: &mut Scheduler, event: Event) { Event::Button(event) => { or_unreachable!("applet-api-button", [event], button::process(event, &mut params)) } - #[cfg(feature = "internal-board-api-platform")] - Event::Platform(event) => { - or_unreachable!("internal-applet-api-platform", [event], platform::process(event)) - } + Event::Platform(event) => platform::process(event), #[cfg(feature = "internal-board-api-radio")] Event::Radio(event) => { or_unreachable!("internal-applet-api-radio", [event], radio::process(event)) diff --git a/crates/scheduler/src/event/button.rs b/crates/scheduler/src/event/button.rs index 3c13417a2..a2e9dbe9d 100644 --- a/crates/scheduler/src/event/button.rs +++ b/crates/scheduler/src/event/button.rs @@ -17,6 +17,7 @@ use alloc::vec::Vec; use derive_where::derive_where; use wasefire_board_api::button::Event; use wasefire_board_api::{self as board, Api as Board, Id}; +use wasefire_error::Error; #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive_where(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -36,6 +37,13 @@ impl<'a, B: Board> From<&'a Event> for Key { } } +impl Key { + pub fn disable(self) -> Result<(), Error> { + use wasefire_board_api::button::Api as _; + board::Button::::disable(self.button) + } +} + pub fn process(event: Event, params: &mut Vec) { params.push(event.pressed as u32); } diff --git a/crates/scheduler/src/event/platform.rs b/crates/scheduler/src/event/platform.rs index be47d70ff..8fcd5e89a 100644 --- a/crates/scheduler/src/event/platform.rs +++ b/crates/scheduler/src/event/platform.rs @@ -14,14 +14,13 @@ use wasefire_board_api::platform::Event; use wasefire_board_api::Api as Board; +use wasefire_error::Error; -#[cfg(feature = "board-api-platform-protocol")] pub mod protocol; #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum Key { - #[cfg(feature = "board-api-platform-protocol")] Protocol(protocol::Key), } @@ -34,15 +33,21 @@ impl From for crate::event::Key { impl<'a> From<&'a Event> for Key { fn from(event: &'a Event) -> Self { match *event { - #[cfg(feature = "board-api-platform-protocol")] Event::Protocol(ref event) => Key::Protocol(event.into()), } } } +impl Key { + pub fn disable(self) -> Result<(), Error> { + match self { + Key::Protocol(x) => x.disable(), + } + } +} + pub fn process(event: Event) { match event { - #[cfg(feature = "board-api-platform-protocol")] Event::Protocol(_) => protocol::process(), } } diff --git a/crates/scheduler/src/event/platform/protocol.rs b/crates/scheduler/src/event/platform/protocol.rs index 2266d5996..81c89954c 100644 --- a/crates/scheduler/src/event/platform/protocol.rs +++ b/crates/scheduler/src/event/platform/protocol.rs @@ -14,6 +14,7 @@ use wasefire_board_api::platform::protocol::Event; use wasefire_board_api::Api as Board; +use wasefire_error::Error; #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -35,4 +36,11 @@ impl<'a> From<&'a Event> for Key { } } +impl Key { + pub fn disable(self) -> Result<(), Error> { + // We need to process non-applet requests. + Ok(()) + } +} + pub fn process() {} diff --git a/crates/scheduler/src/event/radio.rs b/crates/scheduler/src/event/radio.rs index 72ab60a4a..f5d8f28e8 100644 --- a/crates/scheduler/src/event/radio.rs +++ b/crates/scheduler/src/event/radio.rs @@ -14,6 +14,7 @@ use wasefire_board_api::radio::Event; use wasefire_board_api::Api as Board; +use wasefire_error::Error; #[cfg(feature = "board-api-radio-ble")] pub mod ble; @@ -40,6 +41,14 @@ impl<'a> From<&'a Event> for Key { } } +impl Key { + pub fn disable(self) -> Result<(), Error> { + match self { + Key::Ble(x) => x.disable::(), + } + } +} + pub fn process(event: Event) { match event { #[cfg(feature = "board-api-radio-ble")] diff --git a/crates/scheduler/src/event/radio/ble.rs b/crates/scheduler/src/event/radio/ble.rs index 3d05a6ee5..cec8e6f3e 100644 --- a/crates/scheduler/src/event/radio/ble.rs +++ b/crates/scheduler/src/event/radio/ble.rs @@ -13,7 +13,8 @@ // limitations under the License. use wasefire_board_api::radio::ble::Event; -use wasefire_board_api::Api as Board; +use wasefire_board_api::{self as board, Api as Board}; +use wasefire_error::Error; #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -35,4 +36,11 @@ impl<'a> From<&'a Event> for Key { } } +impl Key { + pub fn disable(self) -> Result<(), Error> { + use wasefire_board_api::radio::ble::Api as _; + board::radio::Ble::::disable(&Event::Advertisement) + } +} + pub fn process() {} diff --git a/crates/scheduler/src/event/timer.rs b/crates/scheduler/src/event/timer.rs index 83dd5792d..e9fe1af01 100644 --- a/crates/scheduler/src/event/timer.rs +++ b/crates/scheduler/src/event/timer.rs @@ -15,6 +15,7 @@ use derive_where::derive_where; use wasefire_board_api::timer::Event; use wasefire_board_api::{self as board, Api as Board, Id}; +use wasefire_error::Error; #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive_where(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -34,4 +35,11 @@ impl<'a, B: Board> From<&'a Event> for Key { } } +impl Key { + pub fn disable(self) -> Result<(), Error> { + use wasefire_board_api::timer::Api as _; + board::Timer::::disarm(self.timer) + } +} + pub fn process() {} diff --git a/crates/scheduler/src/event/uart.rs b/crates/scheduler/src/event/uart.rs index 1002ddebf..99167ce3f 100644 --- a/crates/scheduler/src/event/uart.rs +++ b/crates/scheduler/src/event/uart.rs @@ -15,6 +15,7 @@ use derive_where::derive_where; use wasefire_board_api::uart::{Direction, Event}; use wasefire_board_api::{self as board, Api as Board, Id}; +use wasefire_error::Error; #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive_where(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -35,4 +36,11 @@ impl<'a, B: Board> From<&'a Event> for Key { } } +impl Key { + pub fn disable(self) -> Result<(), Error> { + use wasefire_board_api::uart::Api as _; + board::Uart::::disable(self.uart, self.direction) + } +} + pub fn process() {} diff --git a/crates/scheduler/src/event/usb.rs b/crates/scheduler/src/event/usb.rs index c13626dd5..795ca489a 100644 --- a/crates/scheduler/src/event/usb.rs +++ b/crates/scheduler/src/event/usb.rs @@ -14,6 +14,7 @@ use wasefire_board_api::usb::Event; use wasefire_board_api::Api as Board; +use wasefire_error::Error; #[cfg(feature = "board-api-usb-serial")] pub mod serial; @@ -40,6 +41,15 @@ impl<'a> From<&'a Event> for Key { } } +impl Key { + pub fn disable(self) -> Result<(), Error> { + match self { + #[cfg(feature = "board-api-usb-serial")] + Key::Serial(x) => x.disable::(), + } + } +} + pub fn process(event: Event) { match event { #[cfg(feature = "board-api-usb-serial")] diff --git a/crates/scheduler/src/event/usb/serial.rs b/crates/scheduler/src/event/usb/serial.rs index b94d9c518..8c5266d26 100644 --- a/crates/scheduler/src/event/usb/serial.rs +++ b/crates/scheduler/src/event/usb/serial.rs @@ -13,7 +13,8 @@ // limitations under the License. use wasefire_board_api::usb::serial::Event; -use wasefire_board_api::Api as Board; +use wasefire_board_api::{self as board, Api as Board}; +use wasefire_error::Error; #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -37,4 +38,15 @@ impl<'a> From<&'a Event> for Key { } } +impl Key { + pub fn disable(self) -> Result<(), Error> { + use wasefire_board_api::usb::serial::Api as _; + let event = match self { + Key::Read => Event::Read, + Key::Write => Event::Write, + }; + board::usb::Serial::::disable(&event) + } +} + pub fn process() {} diff --git a/crates/scheduler/src/lib.rs b/crates/scheduler/src/lib.rs index 2c195b193..5d25cd3b1 100644 --- a/crates/scheduler/src/lib.rs +++ b/crates/scheduler/src/lib.rs @@ -38,6 +38,8 @@ use wasefire_error::Error; #[cfg(feature = "wasm")] use wasefire_interpreter::{self as interpreter, Call, Module, RunAnswer, Val}; use wasefire_logger as log; +use wasefire_one_of::exactly_one_of; +use wasefire_protocol::applet::ExitStatus; #[cfg(feature = "board-api-storage")] use wasefire_store as store; @@ -52,12 +54,13 @@ mod event; mod native; #[cfg(feature = "internal-debug")] mod perf; -#[cfg(feature = "board-api-platform-protocol")] mod protocol; #[cfg(all(feature = "native", not(target_pointer_width = "32")))] compile_error!("Only 32-bits architectures support native applets."); +exactly_one_of!["native", "wasm"]; + #[derive_where(Default)] pub struct Events(VecDeque>); @@ -91,12 +94,11 @@ pub struct Scheduler { #[cfg(feature = "board-api-storage")] store: store::Store, host_funcs: Vec>, - applet: Option>, + applet: applet::Slot, #[cfg(feature = "board-api-timer")] timers: Vec>, #[cfg(feature = "internal-debug")] perf: perf::Perf, - #[cfg(feature = "board-api-platform-protocol")] protocol: protocol::State, } @@ -186,22 +188,23 @@ impl<'a, B: Board, T: Signature> SchedulerCall<'a, B, T> { self.reply_(result.map(|x| x.into())) } - fn reply_(self, result: Result, Failure>) { + fn reply_(mut self, result: Result, Failure>) { let result = Error::encode(match result { Ok(x) => Ok(*x), Err(Failure::Error(e)) => Err(e), - Err(Failure::Trap(Trap)) => applet_trapped::(Some(T::NAME)), + Err(Failure::Trap(Trap)) => { + return applet_trapped::(self.scheduler(), Some(T::NAME)); + } }); #[cfg(feature = "wasm")] { - let mut this = self; let results = [Val::I32(result as u32)]; #[cfg(feature = "internal-debug")] - this.scheduler().perf.record(perf::Slot::Platform); - let answer = this.call().resume(&results).map(|x| x.forget()); + self.scheduler().perf.record(perf::Slot::Platform); + let answer = self.call().resume(&results).map(|x| x.forget()); #[cfg(feature = "internal-debug")] - this.scheduler().perf.record(perf::Slot::Applets); - this.erased.scheduler.process_answer(answer); + self.scheduler().perf.record(perf::Slot::Applets); + self.erased.scheduler.process_answer(answer); } #[cfg(feature = "native")] { @@ -210,7 +213,7 @@ impl<'a, B: Board, T: Signature> SchedulerCall<'a, B, T> { } fn applet(&mut self) -> &mut Applet { - self.erased.scheduler.applet.as_mut().unwrap() + self.erased.scheduler.applet.get().unwrap() } fn store(&mut self) -> &mut Store { @@ -225,10 +228,11 @@ impl<'a, B: Board, T: Signature> SchedulerCall<'a, B, T> { impl Scheduler { #[cfg(feature = "wasm")] - pub fn run(wasm: &'static [u8]) -> ! { + pub fn run() -> ! { let mut scheduler = Self::new(); - log::debug!("Loading applet."); - scheduler.load(wasm); + if let Err(error) = scheduler.start_applet() { + log::warn!("Failed to start applet: {}", error); + } loop { scheduler.flush_events(); scheduler.process_applet(); @@ -238,7 +242,6 @@ impl Scheduler { #[cfg(feature = "native")] pub fn run() -> ! { native::set_scheduler(Self::new()); - native::with_scheduler(|x| x.new_applet()); extern "C" { fn applet_init(); fn applet_main(); @@ -287,63 +290,90 @@ impl Scheduler { Api::::iter(&mut host_funcs, |x| x); host_funcs.sort_by_key(|x| x.descriptor().name); assert!(host_funcs.windows(2).all(|x| x[0].descriptor().name != x[1].descriptor().name)); - #[cfg(feature = "board-api-platform-protocol")] protocol::enable::(); Self { #[cfg(feature = "board-api-storage")] store: store::Store::new(board::Storage::::take().unwrap()).ok().unwrap(), host_funcs, - applet: None, + #[cfg(feature = "native")] + applet: applet::Slot::Running(Applet::default()), + #[cfg(feature = "wasm")] + applet: applet::Slot::Empty, #[cfg(feature = "board-api-timer")] timers: alloc::vec![None; board::Timer::::SUPPORT], #[cfg(feature = "internal-debug")] perf: perf::Perf::default(), - #[cfg(feature = "board-api-platform-protocol")] protocol: protocol::State::default(), } } - fn new_applet(&mut self) { - assert!(self.applet.is_none()); - self.applet = Some(Applet::default()); + fn stop_applet(&mut self, status: ExitStatus) { + let applet = match self.applet.get() { + Some(x) => x, + None => return, + }; + log::info!("Stopping applet."); + applet.free(); + self.applet = applet::Slot::Exited(status); + #[cfg(feature = "native")] + { + log::debug!("Applet stopped, executing protocol events only."); + loop { + let event = B::wait_event(); + if protocol::should_process_event(&event) { + protocol::process_event(self, event); + } + } + } } #[cfg(feature = "wasm")] - fn load(&mut self, wasm: &'static [u8]) { + fn start_applet(&mut self) -> Result<(), Error> { const MEMORY_SIZE: usize = memory_size(); #[repr(align(16))] struct Memory([u8; MEMORY_SIZE]); static mut MEMORY: Memory = Memory([0; MEMORY_SIZE]); + // SAFETY: We stop the applet before installing a new one. + let wasm = unsafe { as board::applet::Api>::get()? }; + if wasm.is_empty() { + log::info!("No applet to start."); + return Ok(()); + } + log::info!("Starting applet."); + self.applet = applet::Slot::Running(Applet::default()); #[cfg(not(feature = "unsafe-skip-validation"))] - let module = Module::new(wasm).unwrap(); + let module = Module::new(wasm)?; // SAFETY: The module is valid by the feature invariant. #[cfg(feature = "unsafe-skip-validation")] let module = unsafe { Module::new_unchecked(wasm) }; - self.new_applet(); - let applet = self.applet.as_mut().unwrap(); + let applet = self.applet.get().unwrap(); let store = applet.store_mut(); for f in &self.host_funcs { let d = f.descriptor(); - store.link_func("env", d.name, d.params, 1).unwrap(); + store.link_func("env", d.name, d.params, 1)?; } - store.link_func_default("env").unwrap(); + store.link_func_default("env")?; // SAFETY: This function is called once in `run()`. - let inst = store.instantiate(module, unsafe { &mut MEMORY.0 }).unwrap(); + let inst = store.instantiate(module, unsafe { &mut MEMORY.0 })?; #[cfg(feature = "internal-debug")] self.perf.record(perf::Slot::Platform); self.call(inst, "init", &[]); - while let Some(call) = self.applet.as_mut().unwrap().store_mut().last_call() { + while let Some(call) = self.applet.get().unwrap().store_mut().last_call() { match self.host_funcs[call.index()].descriptor().name { "dp" => (), - x => log::panic!("init called {} into host", log::Debug2Format(&x)), + x => { + log::warn!("init called {} into host", log::Debug2Format(&x)); + return Ok(applet_trapped(self, Some(x))); + } } self.process_applet(); } - assert!(matches!(self.applet.as_mut().unwrap().pop(), EventAction::Reply)); + assert!(matches!(self.applet.get().unwrap().pop(), EventAction::Reply)); #[cfg(feature = "internal-debug")] self.perf.record(perf::Slot::Applets); self.call(inst, "main", &[]); + Ok(()) } fn flush_events(&mut self) { @@ -353,11 +383,10 @@ impl Scheduler { } fn triage_event(&mut self, event: board::Event) { - #[cfg(feature = "board-api-platform-protocol")] if protocol::should_process_event(&event) { return protocol::process_event(self, event); } - match &mut self.applet { + match self.applet.get() { None => log::warn!("{:?} matches no applet", event), Some(applet) => applet.push(event), } @@ -366,16 +395,13 @@ impl Scheduler { /// Returns whether execution should resume. fn process_event(&mut self) -> bool { let event = loop { - match self.applet.as_mut().map_or(EventAction::Wait, |x| x.pop()) { + let applet = match self.applet.get() { + Some(x) => x, + None => return false, + }; + match applet.pop() { EventAction::Handle(event) => break event, - EventAction::Wait => { - #[cfg(feature = "internal-debug")] - self.perf.record(perf::Slot::Platform); - let event = B::wait_event(); - #[cfg(feature = "internal-debug")] - self.perf.record(perf::Slot::Waiting); - self.triage_event(event); - } + EventAction::Wait => self.wait_event(), #[cfg(feature = "wasm")] EventAction::Reply => return true, } @@ -384,16 +410,32 @@ impl Scheduler { false } + fn wait_event(&mut self) { + #[cfg(feature = "internal-debug")] + self.perf.record(perf::Slot::Platform); + let event = B::wait_event(); + #[cfg(feature = "internal-debug")] + self.perf.record(perf::Slot::Waiting); + self.triage_event(event); + } + #[cfg(feature = "wasm")] fn process_applet(&mut self) { - let applet = match &mut self.applet { + let applet = match self.applet.get() { Some(x) => x, - None => return, + None => { + log::info!("There are no applets. Let's process events."); + while self.applet.get().is_none() { + self.wait_event(); + } + return; + } }; let call = match applet.store_mut().last_call() { Some(x) => x, None => { - self.process_event(); + // When main exits, we continue processing events. + let _ = self.process_event(); return; } }; @@ -415,9 +457,9 @@ impl Scheduler { call::process(call); } - #[allow(dead_code)] // in case there are no events + #[allow(dead_code)] // in case there are no applet-controlled events fn disable_event(&mut self, key: Key) -> Result<(), Trap> { - if let Some(applet) = &mut self.applet { + if let Some(applet) = self.applet.get() { applet.disable(key)?; } self.flush_events(); @@ -430,7 +472,7 @@ impl Scheduler { let args = args.iter().map(|&x| Val::I32(x)).collect(); #[cfg(feature = "internal-debug")] self.perf.record(perf::Slot::Platform); - let applet = self.applet.as_mut().unwrap(); + let applet = self.applet.get().unwrap(); let answer = applet.store_mut().invoke(inst, name, args).map(|x| x.forget()); #[cfg(feature = "internal-debug")] self.perf.record(perf::Slot::Applets); @@ -443,23 +485,27 @@ impl Scheduler { Ok(RunAnswer::Done(x)) => { log::debug!("Thread is done."); debug_assert!(x.is_empty()); - self.applet.as_mut().unwrap().done(); + self.applet.get().unwrap().done(); } Ok(RunAnswer::Host) => (), - Err(interpreter::Error::Trap) => applet_trapped::(None), + Err(interpreter::Error::Trap) => applet_trapped::(self, None), Err(e) => log::panic!("{}", log::Debug2Format(&e)), } } } -fn applet_trapped(reason: Option<&'static str>) -> ! { - // Until we support multiple applets, we just exit the platform when the applet traps. +fn applet_trapped(scheduler: &mut Scheduler, reason: Option<&'static str>) { match reason { - None => log::error!("Applet trapped in wasm (think segfault)."), - Some("sa") => log::error!("Applet aborted (probably a panic)."), - Some(name) => log::error!("Applet trapped calling host {:?}.", name), - } - as board::debug::Api>::exit(false); + None => log::warn!("Applet trapped in wasm (think segfault)."), + Some("sa") => log::warn!("Applet aborted (probably a panic)."), + Some("se") => log::info!("Applet exited."), + Some(name) => log::warn!("Applet trapped calling host {:?}.", name), + } + scheduler.stop_applet(match reason { + Some("se") => ExitStatus::Exit, + Some("sa") => ExitStatus::Abort, + _ => ExitStatus::Trap, + }); } struct Trap; diff --git a/crates/scheduler/src/native.rs b/crates/scheduler/src/native.rs index 3d1e4e13b..f2c13626b 100644 --- a/crates/scheduler/src/native.rs +++ b/crates/scheduler/src/native.rs @@ -24,7 +24,6 @@ use crate::perf::Slot; use crate::Scheduler; pub(crate) trait ErasedScheduler: Send { - fn new_applet(&mut self); fn dispatch(&mut self, link: &CStr, params: *const u32) -> isize; fn flush_events(&mut self); fn process_event(&mut self); @@ -33,10 +32,6 @@ pub(crate) trait ErasedScheduler: Send { } impl ErasedScheduler for Scheduler { - fn new_applet(&mut self) { - self.new_applet(); - } - fn dispatch(&mut self, link: &CStr, params: *const u32) -> isize { self.dispatch(link, params) } diff --git a/crates/scheduler/src/protocol.rs b/crates/scheduler/src/protocol.rs index 06e73514c..5fd2b379a 100644 --- a/crates/scheduler/src/protocol.rs +++ b/crates/scheduler/src/protocol.rs @@ -14,25 +14,21 @@ use alloc::boxed::Box; +#[cfg(feature = "applet-api-platform-protocol")] use wasefire_applet_api::platform::protocol as applet_api; use wasefire_board_api::platform::protocol::Api as _; use wasefire_board_api::{self as board, Api as Board}; use wasefire_error::{Code, Error}; use wasefire_logger as log; use wasefire_protocol::applet::AppletId; +#[cfg(feature = "wasm")] +use wasefire_protocol::applet::ExitStatus; use wasefire_protocol::{self as service, Api, ApiResult, Request, Service, VERSION}; -use crate::{Applet, Scheduler, SchedulerCall}; +use crate::{Applet, Scheduler}; #[derive(Debug, Default)] -pub enum State { - #[default] - Normal, - Tunnel { - applet_id: service::applet::AppletId, - delimiter: Box<[u8]>, - }, -} +pub struct State(StateImpl); pub fn enable() { if let Err(error) = board::platform::Protocol::::enable() { @@ -59,11 +55,12 @@ pub fn process_event(scheduler: &mut Scheduler, event: board::Event fn process_event_( scheduler: &mut Scheduler, event: board::Event, request: Box<[u8]>, ) -> Result<(), Error> { - match &scheduler.protocol { - State::Normal => (), - State::Tunnel { applet_id, delimiter } => { + match &scheduler.protocol.0 { + Normal { .. } => (), + Locked => return Err(Error::user(Code::InvalidState)), + Tunnel { applet_id, delimiter } => { if request == *delimiter { - scheduler.protocol = State::Normal; + scheduler.protocol = State::default(); return Ok(reply::(())); } return applet::(scheduler, *applet_id)?.put_request(event, &request); @@ -78,25 +75,17 @@ fn process_event_( } Api::AppletResponse(applet_id) => { let response = applet::(scheduler, applet_id)?.get_response()?; - let response = response.as_deref(); - reply::(service::applet::Response { response }); + reply::(response.as_deref()); } - #[cfg(feature = "board-api-platform")] Api::PlatformReboot(()) => { use wasefire_board_api::platform::Api as _; board::Platform::::reboot()?; } Api::AppletTunnel(service::applet::Tunnel { applet_id, delimiter }) => { - match scheduler.protocol { - State::Normal => { - let delimiter = delimiter.to_vec().into_boxed_slice(); - scheduler.protocol = State::Tunnel { applet_id, delimiter }; - reply::(()) - } - State::Tunnel { .. } => unreachable!(), - } + let delimiter = delimiter.to_vec().into_boxed_slice(); + scheduler.protocol.0 = Tunnel { applet_id, delimiter }; + reply::(()) } - #[cfg(feature = "board-api-platform")] Api::PlatformInfo(()) => { use wasefire_board_api::platform::Api as _; reply::(service::platform::Info { @@ -109,14 +98,50 @@ fn process_event_( let response = board::platform::Protocol::::vendor(request)?; reply::(&response); } + Api::PlatformUpdateMetadata(()) => { + use wasefire_board_api::platform::update::Api as _; + let response = board::platform::Update::::metadata()?; + reply::(&response); + } + Api::PlatformUpdateTransfer(request) => process_update::(scheduler, request)?, + #[cfg(feature = "native")] + Api::AppletInstall(_) | Api::AppletUninstall(_) => { + return Err(Error::world(Code::NotImplemented)); + } + #[cfg(feature = "wasm")] + Api::AppletInstall(request) => process_install::(scheduler, request)?, + #[cfg(feature = "wasm")] + Api::AppletUninstall(()) => { + use wasefire_board_api::applet::Api as _; + board::Applet::::start(false)?; + board::Applet::::finish()?; + scheduler.stop_applet(ExitStatus::Kill); + reply::(()); + } + Api::AppletExitStatus(applet_id) => { + use crate::applet::Slot; + let service::applet::AppletId = applet_id; + let status = match scheduler.applet { + #[cfg(feature = "wasm")] + Slot::Empty => return Err(Error::user(Code::NotFound)), + Slot::Running(_) => None, + Slot::Exited(x) => Some(x), + }; + reply::(status); + } + Api::PlatformLock(()) => { + scheduler.protocol.0 = Locked; + reply::(()); + } #[cfg(not(feature = "_test"))] _ => return Err(Error::internal(Code::NotImplemented)), } Ok(()) } +#[cfg(feature = "applet-api-platform-protocol")] pub fn put_response( - call: &mut SchedulerCall, response: Box<[u8]>, + call: &mut crate::SchedulerCall, response: Box<[u8]>, ) -> Result<(), Error> { match call.applet().put_response(response) { Ok(()) => (), @@ -127,9 +152,10 @@ pub fn put_response( } Err(error) => return Err(error), } - match &call.scheduler().protocol { - State::Normal => Ok(()), - State::Tunnel { applet_id, .. } => { + match &call.scheduler().protocol.0 { + Normal { .. } => Ok(()), + Locked => Err(Error::world(Code::InvalidState)), + Tunnel { applet_id, .. } => { let service::applet::AppletId = applet_id; match call.applet().get_response()? { Some(response) => board::platform::Protocol::::write(&response), @@ -142,11 +168,121 @@ pub fn put_response( } } +fn process_update( + scheduler: &mut Scheduler, request: service::transfer::Request, +) -> Result<(), Error> { + use wasefire_board_api::platform::update::Api as _; + match request { + service::transfer::Request::Start { dry_run } => { + *scheduler.protocol.0.update() = TransferState::Running { dry_run }; + board::platform::Update::::initialize(dry_run)?; + } + service::transfer::Request::Write { chunk } => { + let _ = scheduler.protocol.0.update().dry_run()?; + board::platform::Update::::process(chunk)?; + } + service::transfer::Request::Finish => { + let _ = scheduler.protocol.0.update().dry_run()?; + board::platform::Update::::finalize()?; + *scheduler.protocol.0.update() = TransferState::Ready; + } + } + reply::(()); + Ok(()) +} + +#[cfg(feature = "wasm")] +fn process_install( + scheduler: &mut Scheduler, request: service::transfer::Request, +) -> Result<(), Error> { + use wasefire_board_api::applet::Api as _; + match request { + service::transfer::Request::Start { dry_run } => { + if !dry_run { + scheduler.stop_applet(ExitStatus::Kill); + } + *scheduler.protocol.0.install() = TransferState::Running { dry_run }; + board::Applet::::start(dry_run)?; + } + service::transfer::Request::Write { chunk } => { + let _ = scheduler.protocol.0.install().dry_run()?; + board::Applet::::write(chunk)?; + } + service::transfer::Request::Finish => { + let dry_run = scheduler.protocol.0.install().dry_run()?; + board::Applet::::finish()?; + *scheduler.protocol.0.install() = TransferState::Ready; + if !dry_run { + scheduler.start_applet()?; + } + } + } + reply::(()); + Ok(()) +} + +#[derive(Debug)] +enum TransferState { + Ready, + Running { dry_run: bool }, +} + +impl TransferState { + fn dry_run(&self) -> Result { + match self { + TransferState::Ready => Err(Error::user(Code::InvalidState)), + TransferState::Running { dry_run } => Ok(*dry_run), + } + } +} + +#[derive(Debug)] +enum StateImpl { + Normal { + update: TransferState, + #[cfg(feature = "wasm")] + install: TransferState, + }, + Locked, + Tunnel { + applet_id: service::applet::AppletId, + delimiter: Box<[u8]>, + }, +} +use StateImpl::*; + +impl Default for StateImpl { + fn default() -> Self { + Normal { + update: TransferState::Ready, + #[cfg(feature = "wasm")] + install: TransferState::Ready, + } + } +} + +impl StateImpl { + fn update(&mut self) -> &mut TransferState { + match self { + Normal { update, .. } => update, + _ => unreachable!(), + } + } + + #[cfg(feature = "wasm")] + fn install(&mut self) -> &mut TransferState { + match self { + Normal { install, .. } => install, + _ => unreachable!(), + } + } +} + fn applet( scheduler: &mut Scheduler, applet_id: AppletId, ) -> Result<&mut Applet, Error> { let AppletId = applet_id; - scheduler.applet.as_mut().ok_or_else(|| { + scheduler.applet.get().ok_or_else(|| { log::warn!("Failed to find applet"); Error::world(Code::NotFound) }) diff --git a/crates/stub/CHANGELOG.md b/crates/stub/CHANGELOG.md index 0d85ad957..76cebd292 100644 --- a/crates/stub/CHANGELOG.md +++ b/crates/stub/CHANGELOG.md @@ -2,6 +2,10 @@ ## 0.1.5-git +### Minor + +- Migrate from `debug::exit()` to `scheduling::{abort,exit}()` + ### Patch - Update dependencies @@ -40,4 +44,4 @@ ## 0.1.0 - + diff --git a/crates/stub/Cargo.lock b/crates/stub/Cargo.lock index cf1dfcf55..dc96573ca 100644 --- a/crates/stub/Cargo.lock +++ b/crates/stub/Cargo.lock @@ -425,12 +425,13 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", "wasefire-logger", + "wasefire-one-of", ] [[package]] @@ -446,7 +447,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -460,7 +461,11 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" + +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" [[package]] name = "wasefire-stub" diff --git a/crates/stub/Cargo.toml b/crates/stub/Cargo.toml index 3f3acf654..277628455 100644 --- a/crates/stub/Cargo.toml +++ b/crates/stub/Cargo.toml @@ -24,11 +24,11 @@ rand = { version = "0.8.5", default-features = false, features = ["std", "std_rn sha2 = { version = "0.10.8", default-features = false } signature = { version = "2.2.0", default-features = false } wasefire-error = { version = "0.1.2-git", path = "../error" } -wasefire-logger = { version = "0.1.5", path = "../logger" } +wasefire-logger = { version = "0.1.6-git", path = "../logger" } [dependencies.wasefire-applet-api] features = ["full-api", "native", "wasm"] -version = "0.6.2-git" +version = "0.7.0-git" path = "../api" [lints] diff --git a/crates/stub/src/debug.rs b/crates/stub/src/debug.rs index 23eb89cca..e40fc1463 100644 --- a/crates/stub/src/debug.rs +++ b/crates/stub/src/debug.rs @@ -21,9 +21,3 @@ unsafe extern "C" fn env_dp(params: api::println::Params) { let msg = std::str::from_utf8(msg).unwrap(); eprintln!("{msg}"); } - -#[no_mangle] -unsafe extern "C" fn env_de(params: api::exit::Params) { - let api::exit::Params { code } = params; - std::process::exit(code as i32) -} diff --git a/crates/stub/src/lib.rs b/crates/stub/src/lib.rs index f8c27e15e..1dffb41f7 100644 --- a/crates/stub/src/lib.rs +++ b/crates/stub/src/lib.rs @@ -32,6 +32,7 @@ use wasefire_error::Error; mod crypto; mod debug; mod rng; +mod scheduling; fn convert(x: Result) -> isize { Error::encode(x) as isize diff --git a/crates/stub/src/scheduling.rs b/crates/stub/src/scheduling.rs new file mode 100644 index 000000000..f7205a50d --- /dev/null +++ b/crates/stub/src/scheduling.rs @@ -0,0 +1,23 @@ +// Copyright 2024 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_mangle] +unsafe extern "C" fn env_sa() { + std::process::exit(1) +} + +#[no_mangle] +unsafe extern "C" fn env_se() { + std::process::exit(0) +} diff --git a/crates/wasm-bench/Cargo.lock b/crates/wasm-bench/Cargo.lock index cbe05f4f5..87532f68b 100644 --- a/crates/wasm-bench/Cargo.lock +++ b/crates/wasm-bench/Cargo.lock @@ -229,18 +229,18 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.109.0" +version = "0.109.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6b33d7e757a887989eb18b35712b2a67d96171ec3149d1bfb657b29b7b367c" +checksum = "fad7096c10a285583f2ed620c0c85d7baf745922e33415290f2900b73319f1e0" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.109.0" +version = "0.109.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9acf15cb22be42d07c3b57d7856329cb228b7315d385346149df2566ad5e4aa" +checksum = "bd0d5b0dcd4a4e18c6352304d76f1c63258b5b2c248fc261b89c3a02952d51ff" dependencies = [ "bumpalo", "cranelift-bforest", @@ -260,33 +260,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.109.0" +version = "0.109.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e934d301392b73b3f8b0540391fb82465a0f179a3cee7c726482ac4727efcc97" +checksum = "3d14aa8551924931235a4eec42d561a8415d5a758267a549575a3fe0e13ba84f" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.109.0" +version = "0.109.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb2a2566b3d54b854dfb288b3b187f6d3d17d6f762c92898207eba302931da" +checksum = "315a326e9f63b996f55e93b73a9a239b55f2de1211fcfbcc99d9423f44dc6ded" [[package]] name = "cranelift-control" -version = "0.109.0" +version = "0.109.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0100f33b704cdacd01ad66ff41f8c5030d57cbff078e2a4e49ab1822591299fa" +checksum = "806ca69ca5aa8422035543444e1dc936f8f3e7f6854d562ef31db9fe30355c5c" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.109.0" +version = "0.109.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8cfdc315e5d18997093e040a8d234bea1ac1e118a716d3e30f40d449e78207b" +checksum = "c9778487136bf37f9007920d9cb332a020e5d7259c1fbf35e625368eb88c7bfe" dependencies = [ "serde", "serde_derive", @@ -294,9 +294,9 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.109.0" +version = "0.109.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f74b84f16af2e982b0c0c72233503d9d55cbfe3865dbe807ca28dc6642a28b5" +checksum = "55326cb3b61ca368210899a35892bca66aea4d75e8ceb5464e0539906c2ffb61" dependencies = [ "cranelift-codegen", "log", @@ -306,15 +306,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.109.0" +version = "0.109.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adf306d3dde705fb94bd48082f01d38c4ededc74293a4c007805f610bf08bc6e" +checksum = "4807df8ebad0106f207bcdc1f38199200ed175066b4122689e7f18e33ec8548c" [[package]] name = "cranelift-native" -version = "0.109.0" +version = "0.109.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ea0ebdef7aff4a79bcbc8b6495f31315f16b3bf311152f472eaa8d679352581" +checksum = "91c24c076002cb6a926a3f7220040278c7178878cd9142a418ddef9ee5b84963" dependencies = [ "cranelift-codegen", "libc", @@ -323,9 +323,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.109.0" +version = "0.109.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d549108a1942065cdbac3bb96c2952afa0e1b9a3beff4b08c4308ac72257576d" +checksum = "66ba3e8a666222d2df5a79a1279282c04545c4ca9712b7d85f4f54937617a533" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -1405,9 +1405,9 @@ dependencies = [ [[package]] name = "wasmtime" -version = "22.0.0" +version = "22.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786d8b5e7a4d54917c5ebe555b9667337e5f93383f49bddaaeec2eba68093b45" +checksum = "9de397b45aa057cbadd8fbef22227779ef05121d9f47ac55c9a1ff77e0c29695" dependencies = [ "anyhow", "bumpalo", @@ -1445,18 +1445,18 @@ dependencies = [ [[package]] name = "wasmtime-asm-macros" -version = "22.0.0" +version = "22.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d697d99c341d4a9ffb72f3af7a02124d233eeb59aee010f36d88e97cca553d5e" +checksum = "379c81227d624024d8b950a9eb7fc48671f77fff368e021d9b6f16c83a650369" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-component-macro" -version = "22.0.0" +version = "22.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b29b462b068e73b5b27fae092a27f47e5937cabf6b26be2779c978698a52feca" +checksum = "2f579efa3807fc05078939d001e9295f3ab65613345fa7fe0c19875129aabae4" dependencies = [ "anyhow", "proc-macro2", @@ -1469,15 +1469,15 @@ dependencies = [ [[package]] name = "wasmtime-component-util" -version = "22.0.0" +version = "22.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d2912c53d9054984b380dfbd7579f9c3681b2a73b903a56bd71a1c4f175f1e" +checksum = "e935348dec39c79e895f80dd9ea7726b0c9059ef6210deae0c58e7e327422adc" [[package]] name = "wasmtime-cranelift" -version = "22.0.0" +version = "22.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3975deafea000457ba84355c7c0fce0372937204f77026510b7b454f28a3a65" +checksum = "8e8ec68af53f896a8c98ce7c540762686239b6b81f83d95ef2a074d8b0d67443" dependencies = [ "anyhow", "cfg-if", @@ -1499,9 +1499,9 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "22.0.0" +version = "22.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f444e900e848b884d8a8a2949b6f5b92af642a3e663ff8fbe78731143a55be61" +checksum = "e41bba8b753ccb9426986b106fa03820bc04e097f02e09f28ce85ca0191d7db0" dependencies = [ "anyhow", "cranelift-entity", @@ -1521,9 +1521,9 @@ dependencies = [ [[package]] name = "wasmtime-jit-icache-coherence" -version = "22.0.0" +version = "22.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5afe2f0499542f9a4bcfa1b55bfdda803b6ade4e7c93c6b99e0f39dba44b0a91" +checksum = "a0e7ccd55d5dfff4fb7abc889137c5af6531ad57bbd5890651f7e22533a61c7d" dependencies = [ "anyhow", "cfg-if", @@ -1533,15 +1533,15 @@ dependencies = [ [[package]] name = "wasmtime-slab" -version = "22.0.0" +version = "22.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a7de1f2bec5bbb35d532e61c85c049dc84ae671df60492f90b954ecf21169e7" +checksum = "7df4e5141e11e6f12330450d97f289ccc8f7de2d3c2db7c46252ccd95d78f093" [[package]] name = "wasmtime-types" -version = "22.0.0" +version = "22.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "412463e9000e14cf6856be48628d2213c20c153e29ffc22b036980c892ea6964" +checksum = "b2017ea47e7a91440f94cc29f5f41d303e80f979a5384bf560d4b0afdabe32d0" dependencies = [ "cranelift-entity", "serde", @@ -1552,9 +1552,9 @@ dependencies = [ [[package]] name = "wasmtime-versioned-export-macros" -version = "22.0.0" +version = "22.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de5a9bc4f44ceeb168e9e8e3be4e0b4beb9095b468479663a9e24c667e36826f" +checksum = "455fc30062a08ba6a9c2ccc6e8c76ea2759d01324d3548324f5d38257d0e8d96" dependencies = [ "proc-macro2", "quote", @@ -1563,9 +1563,9 @@ dependencies = [ [[package]] name = "wasmtime-wit-bindgen" -version = "22.0.0" +version = "22.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc077306b38288262e5ba01d4b21532a6987416cdc0aedf04bb06c22a68fdc" +checksum = "e6b893eec1dbf19e20beb6f2821ddd9672978db0e7c00ab8bb628afaad823783" dependencies = [ "anyhow", "heck", diff --git a/crates/wasm-bench/Cargo.toml b/crates/wasm-bench/Cargo.toml index ccc686fb8..8e8fcb5a5 100644 --- a/crates/wasm-bench/Cargo.toml +++ b/crates/wasm-bench/Cargo.toml @@ -31,7 +31,7 @@ features = ["build-bindgen", "use-32bit-slots"] optional = true [dependencies.wasmtime] -version = "22.0.0" +version = "22.0.1" default-features = false features = ["cranelift", "runtime"] optional = true diff --git a/crates/wasm-bench/osv-scanner.toml b/crates/wasm-bench/osv-scanner.toml index 5856a76e5..3e9d755e5 100644 --- a/crates/wasm-bench/osv-scanner.toml +++ b/crates/wasm-bench/osv-scanner.toml @@ -1,12 +1,4 @@ -# TODO(https://github.com/google/osv-scanner/issues/1155): Simplify this file. - -# This crate (wasm-bench) is used for benchmarks only. Those alerts can't be fixed because one of -# the comparison point (wasm3) is dead. We can't remove it because it is the best benchmark -# reference so far. -IgnoredVulns = [ - { id = "GHSA-crf8-h2wq-2h9x" }, - { id = "GHSA-g98v-hv3f-hcfr" }, - { id = "GHSA-gq4p-4hxv-5rg9" }, - { id = "GHSA-r7qv-8r2h-pg27" }, - { id = "RUSTSEC-2021-0139" }, -] +[[PackageOverrides]] +ecosystem = "crates.io" +ignore = true +reason = "benchmarks only" diff --git a/crates/wire/CHANGELOG.md b/crates/wire/CHANGELOG.md index 0bd20a256..69bb16f19 100644 --- a/crates/wire/CHANGELOG.md +++ b/crates/wire/CHANGELOG.md @@ -2,10 +2,14 @@ ## 0.1.1-git +### Minor + +- Implement `Debug` for `Yoke` + ### Patch - Update dependencies ## 0.1.0 - + diff --git a/crates/wire/src/lib.rs b/crates/wire/src/lib.rs index 1ed893b9e..8cc4b06d2 100644 --- a/crates/wire/src/lib.rs +++ b/crates/wire/src/lib.rs @@ -99,6 +99,14 @@ pub struct Yoke> { data: *mut [u8], } +impl> core::fmt::Debug for Yoke +where for<'a> T::Type<'a>: core::fmt::Debug +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + as core::fmt::Debug>::fmt(self.get(), f) + } +} + impl> Drop for Yoke { fn drop(&mut self) { // SAFETY: data comes from into_raw and has been used linearly since then. @@ -235,8 +243,6 @@ impl<'a, const N: usize> internal::Wire<'a> for &'a [u8; N] { } } fn encode(&self, writer: &mut Writer<'a>) -> Result<(), Error> { - // TODO(https://github.com/rust-lang/rust-clippy/issues/9841): Remove. - #[allow(clippy::explicit_auto_deref)] Ok(writer.put_share(*self)) } fn decode(reader: &mut Reader<'a>) -> Result { diff --git a/crates/wire/src/schema.rs b/crates/wire/src/schema.rs index 99771f06c..fcf58419e 100644 --- a/crates/wire/src/schema.rs +++ b/crates/wire/src/schema.rs @@ -386,7 +386,7 @@ impl ViewFrame { impl ViewFrameLock { fn new(rec: Option, view: &View) -> Self { // TODO(https://github.com/rust-lang/rust-clippy/issues/12860): Remove when fixed. - #[allow(clippy::unnecessary_cast)] + #[expect(clippy::unnecessary_cast)] // SAFETY: This function is only called when drop is called before the lifetime ends. let view = unsafe { &*(view as *const _ as *const View<'static>) }; let frame = ViewFrame { rec, view }; diff --git a/crates/xtask/Cargo.lock b/crates/xtask/Cargo.lock index 56d894c4f..015177b13 100644 --- a/crates/xtask/Cargo.lock +++ b/crates/xtask/Cargo.lock @@ -220,9 +220,9 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "camino" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] @@ -317,6 +317,18 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -505,6 +517,12 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "env_filter" version = "0.1.0" @@ -789,6 +807,27 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + [[package]] name = "io-kit-sys" version = "0.4.1" @@ -840,6 +879,12 @@ dependencies = [ "serde", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "leb128" version = "0.2.5" @@ -1011,6 +1056,12 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "nusb" version = "0.1.9" @@ -1129,6 +1180,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "portable-atomic" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d30538d42559de6b034bc76fd6dd4c38961b1ee5c6c56e3808c50128fdbc22ce" + [[package]] name = "probe-rs" version = "0.24.0" @@ -1362,11 +1419,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -1792,6 +1850,8 @@ dependencies = [ "clap", "data-encoding", "humantime", + "indicatif", + "log", "rusb", "serde", "tokio", @@ -1811,14 +1871,18 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" dependencies = [ "log", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-protocol" -version = "0.1.1-git" +version = "0.2.0-git" dependencies = [ "anyhow", "wasefire-error", @@ -1833,6 +1897,7 @@ dependencies = [ "tokio", "wasefire-board-api", "wasefire-logger", + "wasefire-one-of", "wasefire-protocol", ] @@ -1844,6 +1909,7 @@ dependencies = [ "rusb", "wasefire-board-api", "wasefire-logger", + "wasefire-one-of", "wasefire-protocol", ] @@ -2075,6 +2141,7 @@ dependencies = [ "stack-sizes", "tokio", "wasefire-cli-tools", + "wasefire-error", ] [[package]] diff --git a/crates/xtask/Cargo.toml b/crates/xtask/Cargo.toml index dd62a8e55..61a3368e9 100644 --- a/crates/xtask/Cargo.toml +++ b/crates/xtask/Cargo.toml @@ -16,7 +16,8 @@ rustc-demangle = "0.1.24" serde = { version = "1.0.202", features = ["derive"] } stack-sizes = "0.5.0" tokio = { version = "1.40.0", features = ["full"] } -wasefire-cli-tools = { path = "../cli-tools" } +wasefire-cli-tools = { path = "../cli-tools", features = ["action"] } +wasefire-error = { version = "0.1.2-git", path = "../error", features = ["std"] } [lints] clippy.unit-arg = "allow" diff --git a/crates/xtask/src/footprint.rs b/crates/xtask/src/footprint.rs index a8aed8b61..5da0a7744 100644 --- a/crates/xtask/src/footprint.rs +++ b/crates/xtask/src/footprint.rs @@ -78,7 +78,7 @@ pub async fn compare(output: &str) -> Result<()> { None => write!(output, " |"), }; for config in configs { - for key in ["total", "applet", "runner"] { + for key in ["applet", "runner"] { let base = base.get(config).map(|x| x[key]); let head = head.get(config).map(|x| x[key]); let diff = base.and_then(|base| head.map(|head| head - base)); @@ -136,8 +136,7 @@ impl Footprint { } let mut value = HashMap::new(); value.insert("applet", applet as i64); - value.insert("total", runner as i64); - value.insert("runner", runner as i64 - applet as i64); + value.insert("runner", runner as i64); value }; let value = match value { diff --git a/crates/xtask/src/main.rs b/crates/xtask/src/main.rs index 8a0c6cef0..f3e4ea6e1 100644 --- a/crates/xtask/src/main.rs +++ b/crates/xtask/src/main.rs @@ -16,7 +16,9 @@ use std::cmp::Reverse; use std::collections::BinaryHeap; +use std::ffi::OsString; use std::sync::{Arc, Mutex}; +use std::time::Duration; use anyhow::{bail, ensure, Context, Result}; use clap::Parser; @@ -25,6 +27,7 @@ use probe_rs::{flashing, Permissions, Session}; use rustc_demangle::demangle; use tokio::process::Command; use tokio::sync::OnceCell; +use wasefire_cli_tools::error::root_cause_is; use wasefire_cli_tools::{action, cmd, fs}; mod footprint; @@ -85,6 +88,12 @@ enum MainCommand { /// Compiles a runner. Runner(Runner), + /// Waits for an applet to exit. + WaitApplet(Wait), + + /// Waits for a platform to be ready. + WaitPlatform(Wait), + /// Appends a comparison between footprint-base.toml and footprint-pull_request.toml. /// /// If any file is missing, it is assumed to have no measurements. @@ -134,13 +143,36 @@ struct AppletOptions { #[derive(clap::Subcommand)] enum AppletCommand { /// Compiles a runner with the applet. - Runner(RunnerOptions), + Runner(Runner), + + /// Installs the applet on a platform. + Install { + #[command(flatten)] + options: action::ConnectionOptions, + #[command(flatten)] + action: action::Transfer, + #[command(subcommand)] + command: Option, + }, +} + +#[derive(clap::Subcommand)] +enum AppletInstallCommand { + /// Waits until the applet exits. + #[group(id = "AppletInstallCommand::Wait")] + Wait { + #[command(flatten)] + action: action::AppletExitStatus, + }, } #[derive(clap::Args)] struct Runner { #[clap(flatten)] options: RunnerOptions, + + #[clap(subcommand)] + command: Option, } #[derive(Default, clap::Args)] @@ -163,18 +195,14 @@ struct RunnerOptions { #[clap(long)] features: Vec, + /// Runner arguments. + #[clap(long)] + arg: Vec, + /// Optimization level (0, 1, 2, 3, s, z). #[clap(long, short = 'O')] opt_level: Option, - /// Produces target/wasefire/platform_{side}.bin files instead of flashing. - #[clap(long)] - bundle: bool, - - /// Resets the persistent storage before running. - #[clap(long)] - reset_storage: bool, - /// Prints the command lines to use GDB. #[clap(long)] gdb: bool, @@ -183,22 +211,6 @@ struct RunnerOptions { #[clap(long)] log: Option, - /// Additional flags for `probe-rs run`. - #[clap(long)] - probe_rs: Vec, - - /// Creates a web interface for the host runner. - #[clap(long)] - web: bool, - - /// Host to start the webserver. - #[clap(long)] - web_host: Option, - - /// Port to start the webserver. - #[clap(long)] - web_port: Option, - /// Measures bloat after building. // TODO: Make this a subcommand taking additional options for cargo bloat. #[clap(long)] @@ -216,11 +228,39 @@ struct RunnerOptions { memory_page_count: Option, } +#[derive(clap::Subcommand)] +enum RunnerCommand { + /// Flashes the runner. + Flash(Flash), + + /// Produces target/wasefire/platform_{side}.bin files instead of flashing. + Bundle, +} + +#[derive(clap::Args)] +struct Flash { + /// Resets the flash before running. + #[clap(long)] + reset_flash: bool, + + /// Additional flags for `probe-rs run`. + #[clap(long)] + probe_rs: Vec, +} + +#[derive(clap::Args)] +struct Wait { + #[command(flatten)] + options: action::ConnectionOptions, +} + impl Flags { async fn execute(self) -> Result<()> { match self.command { MainCommand::Applet(applet) => applet.execute(&self.options).await, MainCommand::Runner(runner) => runner.execute(&self.options).await, + MainCommand::WaitApplet(wait) => wait.execute(true).await, + MainCommand::WaitPlatform(wait) => wait.execute(false).await, MainCommand::Footprint { output } => footprint::compare(&output).await, MainCommand::Textreview => textreview::execute().await, } @@ -236,7 +276,7 @@ impl MainOptions { impl Applet { async fn execute(self, main: &MainOptions) -> Result<()> { self.options.execute(main, &self.command).await?; - if let Some(command) = &self.command { + if let Some(command) = self.command { command.execute(main).await?; } Ok(()) @@ -266,11 +306,14 @@ impl AppletOptions { let native = match (main.native, &main.native_target, command) { (_, Some(target), command) => { if let Some(AppletCommand::Runner(x)) = command { - ensure!(target == x.target().await, "--native-target must match runner"); + ensure!( + target == x.options.target().await, + "--native-target must match runner" + ); } Some(target.as_str()) } - (true, None, Some(AppletCommand::Runner(x))) => Some(x.target().await), + (true, None, Some(AppletCommand::Runner(x))) => Some(x.options.target().await), (true, None, _) => bail!("--native requires runner"), (false, _, _) => None, }; @@ -280,7 +323,7 @@ impl AppletOptions { profile: self.profile.clone(), opt_level: self.opt_level, stack_size: self.stack_size, - ..Default::default() + ..action::RustAppletBuild::parse_from::<_, OsString>([]) }; for features in &self.features { action.cargo.push(format!("--features={features}")); @@ -328,26 +371,47 @@ impl AppletOptions { } impl AppletCommand { - async fn execute(&self, main: &MainOptions) -> Result<()> { + async fn execute(self, main: &MainOptions) -> Result<()> { match self { - AppletCommand::Runner(runner) => runner.execute(main, 0, true).await, + AppletCommand::Runner(runner) => runner.execute(main).await, + AppletCommand::Install { options, action, command } => { + let applet = "target/wasefire/applet.wasm".into(); + let action = action::AppletInstall { applet, transfer: action }; + let mut connection = options.connect().await?; + action.run(&mut connection).await?; + match command { + None => Ok(()), + Some(AppletInstallCommand::Wait { mut action }) => { + action.wait.ensure_wait(); + action.ensure_exit(); + action.run(&mut connection).await + } + } + } } } } impl Runner { async fn execute(&self, main: &MainOptions) -> Result<()> { - self.options.execute(main, 0, false).await?; + self.options.execute(main, 0, &self.command).await?; Ok(()) } } impl RunnerOptions { - async fn execute(&self, main: &MainOptions, step: usize, run: bool) -> Result<()> { + async fn execute( + &self, main: &MainOptions, step: usize, cmd: &Option, + ) -> Result<()> { + let flash = match cmd { + Some(RunnerCommand::Flash(x)) => Some(x), + Some(RunnerCommand::Bundle) => None, + None => None, + }; let mut cargo = Command::new("cargo"); let mut rustflags = Vec::new(); let mut features = self.features.clone(); - if run && self.name == "host" { + if flash.is_some() && self.name == "host" { cargo.arg("run"); } else { cargo.arg("build"); @@ -403,17 +467,10 @@ impl RunnerOptions { } if self.no_default_features { cargo.arg("--no-default-features"); - } else if std::env::var_os("CODESPACES").is_some() { - log::warn!("Assuming runner --no-default-features when running in a codespace."); - cargo.arg("--no-default-features"); } if let Some(log) = &self.log { cargo.env(self.log_env(), log); } - let web = self.web || self.web_host.is_some() || self.web_port.is_some(); - if self.name == "host" && web { - features.push("web".to_string()); - } if self.stack_sizes.is_some() { rustflags.push("-Z emit-stack-sizes".to_string()); rustflags.push("-C link-arg=-Tstack-sizes.x".to_string()); @@ -434,21 +491,21 @@ impl RunnerOptions { cargo.env("RUSTFLAGS", rustflags.join(" ")); } cargo.current_dir(format!("crates/runner-{}", self.name)); - if !main.native { - fs::touch("target/wasefire/applet.wasm").await?; - } - if run && self.name == "host" { - let path = "target/wasefire/storage.bin"; - if self.reset_storage && fs::exists(path).await { - fs::remove_file(path).await?; + if flash.is_some() && self.name == "host" { + if flash.unwrap().reset_flash { + for file in ["applet.bin", "storage.bin"] { + let path = format!("target/wasefire/{file}"); + if fs::exists(&path).await { + fs::remove_file(&path).await?; + } + } } cargo.arg("--"); - if let Some(host) = &self.web_host { - cargo.arg(format!("--web-host={host}")); - } - if let Some(port) = &self.web_port { - cargo.arg(format!("--web-port={port}")); + if std::env::var_os("CODESPACES").is_some() { + log::warn!("Assuming runner --arg=--protocol=unix when running in a codespace."); + cargo.arg("--protocol=unix"); } + cargo.args(&self.arg); cmd::replace(cargo); } else { cmd::execute(&mut cargo).await?; @@ -509,19 +566,20 @@ impl RunnerOptions { println!("{:#010x}\t{}\t{}", address, stack, demangle(name)); } } - if self.bundle { + if matches!(cmd, Some(RunnerCommand::Bundle)) { let mut objcopy = wrap_command().await?; objcopy.args(["rust-objcopy", "-O", "binary", &elf]); objcopy.arg(format!("target/wasefire/platform{side}.bin")); cmd::execute(&mut objcopy).await?; if step < max_step { - return Box::pin(self.execute(main, step + 1, run)).await; + return Box::pin(self.execute(main, step + 1, cmd)).await; } return Ok(()); } - if !run { - return Ok(()); - } + let flash = match flash { + Some(x) => x, + None => return Ok(()), + }; let chip = match self.name.as_str() { "nordic" => "nRF52840_xxAA", "host" => unreachable!(), @@ -533,14 +591,14 @@ impl RunnerOptions { Permissions::default(), )?) }))); - if self.reset_storage { - println!("Erasing the persistent storage."); + if flash.reset_flash { + println!("Erasing the flash."); // Keep those values in sync with crates/runner-nordic/memory.x. tokio::task::spawn_blocking({ let session = session.clone(); move || { let mut session = session.lock().unwrap(); - anyhow::Ok(flashing::erase_sectors(session.get()?, None, 240, 16)?) + anyhow::Ok(flashing::erase_all(session.get()?, None)?) } }) .await??; @@ -568,7 +626,7 @@ impl RunnerOptions { let mut probe_rs = wrap_command().await?; probe_rs.args(["probe-rs", "run"]); probe_rs.arg(format!("--chip={chip}")); - probe_rs.args(&self.probe_rs); + probe_rs.args(&flash.probe_rs); probe_rs.arg(elf); println!("Replace `run` with `attach` in the following command to rerun:"); cmd::replace(probe_rs); @@ -608,6 +666,32 @@ impl RunnerOptions { } } +impl Wait { + async fn execute(&self, applet: bool) -> Result<()> { + let period = Duration::from_millis(300); + loop { + tokio::time::sleep(period).await; + let mut action = action::AppletExitStatus::parse_from::<_, OsString>([]); + action.wait.set_period(period); + if applet { + action.ensure_exit(); + } + let mut connection = match self.options.connect().await { + Ok(x) => x, + Err(_) => continue, + }; + let error = match action.run(&mut connection).await { + Err(x) => x, + Ok(_) => continue, + }; + use wasefire_error::{Code, Error}; + if root_cause_is::(&error, |&x| x == Error::user(Code::NotFound)) { + break Ok(()); + } + } + } +} + async fn ensure_command(cmd: &[&str]) -> Result<()> { let mut wrapper = Command::new("./scripts/wrapper.sh"); wrapper.args(cmd); diff --git a/examples/assemblyscript/api.ts b/examples/assemblyscript/api.ts index 873034525..ab319ebd2 100644 --- a/examples/assemblyscript/api.ts +++ b/examples/assemblyscript/api.ts @@ -534,16 +534,6 @@ // Pointer to the output [`super::Perf`] struct. ptr: usize, ): i32 - - // Exits the platform with an error code. - // - // This is used by test applets to terminate the platform and propagate the test - // result. - @external("env", "de") - export declare function debug_exit( - // 0 for success, 1 for failure. - code: usize, - ): i32 // END OF MODULE debug // START OF MODULE gpio @@ -898,6 +888,11 @@ @external("env", "sa") export declare function scheduling_abort( ): i32 + + // Exits the applet. + @external("env", "se") + export declare function scheduling_exit( + ): i32 // END OF MODULE scheduling // START OF MODULE store diff --git a/examples/rust/blink/Cargo.lock b/examples/rust/blink/Cargo.lock index 706724210..81eef3747 100644 --- a/examples/rust/blink/Cargo.lock +++ b/examples/rust/blink/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/blink_periodic/Cargo.lock b/examples/rust/blink_periodic/Cargo.lock index b4214cc35..78b913a65 100644 --- a/examples/rust/blink_periodic/Cargo.lock +++ b/examples/rust/blink_periodic/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/button/Cargo.lock b/examples/rust/button/Cargo.lock index f031d0d0e..b8f9fc68a 100644 --- a/examples/rust/button/Cargo.lock +++ b/examples/rust/button/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/button_abort/Cargo.lock b/examples/rust/button_abort/Cargo.lock index 98d79e190..2a38f923f 100644 --- a/examples/rust/button_abort/Cargo.lock +++ b/examples/rust/button_abort/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/ccm/Cargo.lock b/examples/rust/ccm/Cargo.lock index 463df4de1..fd3caca32 100644 --- a/examples/rust/ccm/Cargo.lock +++ b/examples/rust/ccm/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/ctap/Cargo.lock b/examples/rust/ctap/Cargo.lock index a79783645..621705972 100644 --- a/examples/rust/ctap/Cargo.lock +++ b/examples/rust/ctap/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/ec_test/Cargo.lock b/examples/rust/ec_test/Cargo.lock index 9b06552c3..ce52bd5d4 100644 --- a/examples/rust/ec_test/Cargo.lock +++ b/examples/rust/ec_test/Cargo.lock @@ -466,7 +466,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -474,17 +474,19 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", "wasefire-logger", + "wasefire-one-of", ] [[package]] @@ -500,7 +502,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -514,7 +516,11 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" + +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" [[package]] name = "wasefire-stub" diff --git a/examples/rust/ec_test/src/lib.rs b/examples/rust/ec_test/src/lib.rs index e73b787c7..893f12334 100644 --- a/examples/rust/ec_test/src/lib.rs +++ b/examples/rust/ec_test/src/lib.rs @@ -33,7 +33,7 @@ pub fn main() -> ! { test_ecdsa::("p384", P384_ECDSA_VECTORS); test_ecdsa_random::("p256"); test_ecdsa_random::("p384"); - debug::exit(true); + scheduling::exit(); } fn test_ecdh(name: &str, vectors: &[EcdhVector]) { @@ -52,7 +52,7 @@ fn test_ecdh(name: &str, vectors: &[EcdhVector]) { ) .unwrap(); let shared_ = private.diffie_hellman(&public); - debug::assert_eq(shared_.raw_bytes().as_slice(), shared); + assert_eq!(shared_.raw_bytes().as_slice(), shared); } } @@ -67,7 +67,7 @@ fn test_ecdh_random(name: &str) { let k2 = EcdhPrivate::::random().unwrap(); let s1 = k1.diffie_hellman(&k2.public_key()); let s2 = k2.diffie_hellman(&k1.public_key()); - debug::assert_eq(s1.raw_bytes().as_slice(), s2.raw_bytes()); + assert_eq!(s1.raw_bytes(), s2.raw_bytes()); debug!("- {:02x?}", &s1.raw_bytes()[.. 8]); } } @@ -90,7 +90,7 @@ fn test_ecdsa(name: &str, vectors: &[EcdsaVector]) { Int::::clone_from_slice(s), ); let v_ = public.verify(m, &signature).unwrap(); - debug::assert_eq(&v_, &v); + assert_eq!(v_, v); } } @@ -110,12 +110,12 @@ fn test_ecdsa_random(name: &str) { debug!("- {:02x?}{:02x?} ({} bytes message)", &s.r()[.. 4], &s.s()[.. 4], m.len()); rs.push(s.r().clone()); let p = d.public_key(); - debug::assert(p.verify(&m, &s).unwrap()); + assert!(p.verify(&m, &s).unwrap()); } // Make sure all r components are different. for i in 1 .. rs.len() { for j in 0 .. i { - debug::assert(rs[j] != rs[i]); + assert!(rs[j] != rs[i]); } } } diff --git a/examples/rust/echo/Cargo.lock b/examples/rust/echo/Cargo.lock index 226d4894c..4938f7b1f 100644 --- a/examples/rust/echo/Cargo.lock +++ b/examples/rust/echo/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/exercises/client/Cargo.lock b/examples/rust/exercises/client/Cargo.lock index 1a44ac07b..88f0ef7d5 100644 --- a/examples/rust/exercises/client/Cargo.lock +++ b/examples/rust/exercises/client/Cargo.lock @@ -831,7 +831,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -839,16 +839,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -864,7 +866,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -876,6 +878,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/exercises/interface/Cargo.lock b/examples/rust/exercises/interface/Cargo.lock index 181f8526f..eace444c2 100644 --- a/examples/rust/exercises/interface/Cargo.lock +++ b/examples/rust/exercises/interface/Cargo.lock @@ -233,7 +233,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -241,16 +241,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -266,7 +268,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -278,6 +280,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/exercises/part-1-sol/Cargo.lock b/examples/rust/exercises/part-1-sol/Cargo.lock index 65960e913..b118f7742 100644 --- a/examples/rust/exercises/part-1-sol/Cargo.lock +++ b/examples/rust/exercises/part-1-sol/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/exercises/part-1/Cargo.lock b/examples/rust/exercises/part-1/Cargo.lock index 341bd2184..e815baed0 100644 --- a/examples/rust/exercises/part-1/Cargo.lock +++ b/examples/rust/exercises/part-1/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/exercises/part-2-sol/Cargo.lock b/examples/rust/exercises/part-2-sol/Cargo.lock index cfc5eb1bb..ac92939c8 100644 --- a/examples/rust/exercises/part-2-sol/Cargo.lock +++ b/examples/rust/exercises/part-2-sol/Cargo.lock @@ -241,7 +241,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -249,16 +249,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -274,7 +276,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -286,6 +288,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/exercises/part-2/Cargo.lock b/examples/rust/exercises/part-2/Cargo.lock index cc5a1884a..337e6a0d7 100644 --- a/examples/rust/exercises/part-2/Cargo.lock +++ b/examples/rust/exercises/part-2/Cargo.lock @@ -241,7 +241,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -249,16 +249,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -274,7 +276,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -286,6 +288,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/exercises/part-3-sol/Cargo.lock b/examples/rust/exercises/part-3-sol/Cargo.lock index c4fd9bbec..2d2eb694e 100644 --- a/examples/rust/exercises/part-3-sol/Cargo.lock +++ b/examples/rust/exercises/part-3-sol/Cargo.lock @@ -241,7 +241,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -249,16 +249,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -274,7 +276,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -286,6 +288,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/exercises/part-3/Cargo.lock b/examples/rust/exercises/part-3/Cargo.lock index 951c836a0..6169aa2af 100644 --- a/examples/rust/exercises/part-3/Cargo.lock +++ b/examples/rust/exercises/part-3/Cargo.lock @@ -241,7 +241,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -249,16 +249,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -274,7 +276,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -286,6 +288,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/exercises/part-4-sol/Cargo.lock b/examples/rust/exercises/part-4-sol/Cargo.lock index ac56c0fdc..2786a6783 100644 --- a/examples/rust/exercises/part-4-sol/Cargo.lock +++ b/examples/rust/exercises/part-4-sol/Cargo.lock @@ -241,7 +241,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -249,16 +249,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -274,7 +276,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -286,6 +288,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/exercises/part-4/Cargo.lock b/examples/rust/exercises/part-4/Cargo.lock index 344a51362..edcfe2ba7 100644 --- a/examples/rust/exercises/part-4/Cargo.lock +++ b/examples/rust/exercises/part-4/Cargo.lock @@ -241,7 +241,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -249,16 +249,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -274,7 +276,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -286,6 +288,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/exercises/part-5-sol/Cargo.lock b/examples/rust/exercises/part-5-sol/Cargo.lock index 87bd024e1..03e2c8e57 100644 --- a/examples/rust/exercises/part-5-sol/Cargo.lock +++ b/examples/rust/exercises/part-5-sol/Cargo.lock @@ -241,7 +241,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -249,16 +249,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -274,7 +276,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -286,6 +288,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/exercises/part-5/Cargo.lock b/examples/rust/exercises/part-5/Cargo.lock index cfefbea78..1d3927ed5 100644 --- a/examples/rust/exercises/part-5/Cargo.lock +++ b/examples/rust/exercises/part-5/Cargo.lock @@ -241,7 +241,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -249,16 +249,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -274,7 +276,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -286,6 +288,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/exercises/part-6-sol/Cargo.lock b/examples/rust/exercises/part-6-sol/Cargo.lock index 05a0ea3e1..bb844d4ce 100644 --- a/examples/rust/exercises/part-6-sol/Cargo.lock +++ b/examples/rust/exercises/part-6-sol/Cargo.lock @@ -241,7 +241,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -249,16 +249,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -274,7 +276,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -286,6 +288,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/exercises/part-6/Cargo.lock b/examples/rust/exercises/part-6/Cargo.lock index f84f7f1fd..40f9396a9 100644 --- a/examples/rust/exercises/part-6/Cargo.lock +++ b/examples/rust/exercises/part-6/Cargo.lock @@ -241,7 +241,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -249,16 +249,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -274,7 +276,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -286,6 +288,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/exercises/part-7-sol/Cargo.lock b/examples/rust/exercises/part-7-sol/Cargo.lock index c4d27d1da..555cac92c 100644 --- a/examples/rust/exercises/part-7-sol/Cargo.lock +++ b/examples/rust/exercises/part-7-sol/Cargo.lock @@ -241,7 +241,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -249,16 +249,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -274,7 +276,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -286,6 +288,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/exercises/part-7/Cargo.lock b/examples/rust/exercises/part-7/Cargo.lock index 45966079c..cd7216163 100644 --- a/examples/rust/exercises/part-7/Cargo.lock +++ b/examples/rust/exercises/part-7/Cargo.lock @@ -241,7 +241,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -249,16 +249,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -274,7 +276,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -286,6 +288,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/gcm_test/Cargo.lock b/examples/rust/gcm_test/Cargo.lock index febc2a65e..da0f58274 100644 --- a/examples/rust/gcm_test/Cargo.lock +++ b/examples/rust/gcm_test/Cargo.lock @@ -215,7 +215,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "aead", "bytemuck", @@ -225,17 +225,19 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", "zeroize", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -251,7 +253,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -263,6 +265,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/gcm_test/src/lib.rs b/examples/rust/gcm_test/src/lib.rs index 00d14bac5..3ab43224d 100644 --- a/examples/rust/gcm_test/src/lib.rs +++ b/examples/rust/gcm_test/src/lib.rs @@ -35,7 +35,7 @@ fn main() { test_decrypt(); test_decrypt_in_place(); } - debug::exit(true); + scheduling::exit(); } fn test_encrypt() { @@ -53,8 +53,8 @@ fn test_encrypt() { }; #[cfg(not(feature = "rust-crypto"))] let Cipher { text: cipher_, tag: tag_ } = encrypt(key, iv, aad, clear).unwrap(); - debug::assert_eq(&cipher_[..], cipher); - debug::assert_eq(&tag_[..], &tag[.. tag_len]); + assert_eq!(cipher_[..], cipher[..]); + assert_eq!(tag_[..], tag[.. tag_len]); } } @@ -73,8 +73,8 @@ fn test_encrypt_in_place() { } #[cfg(not(feature = "rust-crypto"))] encrypt_in_place(key, iv, aad, &mut cipher_, &mut tag_).unwrap(); - debug::assert_eq(&cipher_[..], cipher); - debug::assert_eq(&tag_[..], &tag[.. tag_len]); + assert_eq!(cipher_[..], cipher[..]); + assert_eq!(tag_[..], tag[.. tag_len]); } } @@ -98,7 +98,7 @@ fn test_decrypt() { let cipher = Cipher { text: cipher.to_vec(), tag: tag_ }; decrypt(key, iv, aad, &cipher).unwrap() }; - debug::assert_eq(&clear_[..], clear); + assert_eq!(clear_[..], clear[..]); } } @@ -115,7 +115,7 @@ fn test_decrypt_in_place() { .unwrap(); #[cfg(not(feature = "rust-crypto"))] decrypt_in_place(key, iv, aad, &tag[.. tag_len], &mut clear_).unwrap(); - debug::assert_eq(&clear_[..], clear); + assert_eq!(clear_[..], clear[..]); } } diff --git a/examples/rust/gpio_test/Cargo.lock b/examples/rust/gpio_test/Cargo.lock index 31646a45b..c84aa9ce6 100644 --- a/examples/rust/gpio_test/Cargo.lock +++ b/examples/rust/gpio_test/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/gpio_test/src/lib.rs b/examples/rust/gpio_test/src/lib.rs index a167cffde..0a8fc6617 100644 --- a/examples/rust/gpio_test/src/lib.rs +++ b/examples/rust/gpio_test/src/lib.rs @@ -28,7 +28,7 @@ use wasefire::gpio::{Config, Gpio, InputConfig, OutputConfig}; fn main() -> Result<(), Error> { if gpio::count() < 3 { debug!("This test needs at least 3 GPIOs (connected together)."); - debug::exit(true); + scheduling::exit(); } let mut configs = Vec::new(); for input in [InputConfig::Disabled, Floating, PullUp, PullDown] { @@ -57,17 +57,17 @@ fn main() -> Result<(), Error> { let _src = Gpio::new(0, src)?; let dst = Gpio::new(1, dst)?; match expected { - Some(expected) => debug::assert_eq(&dst.read()?, &expected), + Some(expected) => assert_eq!(dst.read()?, expected), None => { let bus = Gpio::new(2, &Config::output(PushPull, false))?; - debug::assert_eq(&dst.read()?, &false); + assert!(!dst.read()?); bus.write(true)?; - debug::assert_eq(&dst.read()?, &true); + assert!(dst.read()?); } } } } - debug::exit(true); + scheduling::exit(); } fn simulate(src: &Config, dst: &Config) -> Option> { diff --git a/examples/rust/hash_test/Cargo.lock b/examples/rust/hash_test/Cargo.lock index 1134231bd..e7c822879 100644 --- a/examples/rust/hash_test/Cargo.lock +++ b/examples/rust/hash_test/Cargo.lock @@ -477,7 +477,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "aead", "bytemuck", @@ -487,18 +487,20 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", "zeroize", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", "wasefire-logger", + "wasefire-one-of", ] [[package]] @@ -514,7 +516,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -528,7 +530,11 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" + +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" [[package]] name = "wasefire-stub" diff --git a/examples/rust/hash_test/src/lib.rs b/examples/rust/hash_test/src/lib.rs index a69d7b08d..a401306ab 100644 --- a/examples/rust/hash_test/src/lib.rs +++ b/examples/rust/hash_test/src/lib.rs @@ -35,7 +35,7 @@ pub fn main() -> ! { test_hmac("sha384", Algorithm::Sha384, HMAC_SHA384_VECTORS); test_hkdf("sha256", Algorithm::Sha256, HKDF_SHA256_VECTORS); test_hkdf("sha384", Algorithm::Sha384, HKDF_SHA384_VECTORS); - debug::exit(true); + scheduling::exit(); } fn test(name: &str, algorithm: Algorithm, vectors: &[Vector]) { @@ -57,7 +57,7 @@ fn test(name: &str, algorithm: Algorithm, vectors: &[Vector]) { Digest::digest(algorithm, message, &mut digest).unwrap(); digest }; - debug::assert_eq(&digest_[..], digest); + assert_eq!(digest_[..], digest[..]); } } @@ -90,7 +90,7 @@ fn test_hmac(name: &str, algorithm: Algorithm, vectors: &[HmacVector]) { Hmac::hmac(algorithm, key, msg, &mut mac).unwrap(); mac }; - debug::assert_eq(&mac_[..], mac); + assert_eq!(mac_[..], mac[..]); } } @@ -108,10 +108,10 @@ fn test_hkdf(name: &str, algorithm: Algorithm, vectors: &[HkdfVector]) { debug!("- {test_case}"); let mut prk_ = vec![0; algorithm.digest_len()]; hkdf_extract(algorithm, salt, ikm, &mut prk_).unwrap(); - debug::assert_eq(&prk_[..], prk); + assert_eq!(prk_[..], prk[..]); let mut okm_ = vec![0; okm.len()]; hkdf_expand(algorithm, prk, info, &mut okm_).unwrap(); - debug::assert_eq(&okm_[..], okm); + assert_eq!(okm_[..], okm[..]); } } diff --git a/examples/rust/hello/Cargo.lock b/examples/rust/hello/Cargo.lock index 1e76e66c0..a4be769b6 100644 --- a/examples/rust/hello/Cargo.lock +++ b/examples/rust/hello/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/hsm/Cargo.lock b/examples/rust/hsm/Cargo.lock index 10aac3ab8..bda7e589c 100644 --- a/examples/rust/hsm/Cargo.lock +++ b/examples/rust/hsm/Cargo.lock @@ -196,7 +196,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -204,16 +204,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -229,7 +231,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -241,6 +243,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/hsm/common/Cargo.lock b/examples/rust/hsm/common/Cargo.lock index daee7d53a..c3d8f20eb 100644 --- a/examples/rust/hsm/common/Cargo.lock +++ b/examples/rust/hsm/common/Cargo.lock @@ -209,7 +209,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -217,16 +217,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -242,7 +244,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -254,6 +256,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/led/Cargo.lock b/examples/rust/led/Cargo.lock index 9ed83bf6a..3eb210338 100644 --- a/examples/rust/led/Cargo.lock +++ b/examples/rust/led/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/link_test/Cargo.lock b/examples/rust/link_test/Cargo.lock index d3ef0e558..c3912d09e 100644 --- a/examples/rust/link_test/Cargo.lock +++ b/examples/rust/link_test/Cargo.lock @@ -189,7 +189,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -197,17 +197,19 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", "wasefire-logger", + "wasefire-one-of", ] [[package]] @@ -223,7 +225,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -237,7 +239,11 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" + +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" [[package]] name = "wasefire-sync" diff --git a/examples/rust/link_test/src/lib.rs b/examples/rust/link_test/src/lib.rs index 86f993505..fc2baa67f 100644 --- a/examples/rust/link_test/src/lib.rs +++ b/examples/rust/link_test/src/lib.rs @@ -27,14 +27,14 @@ fn main() { test(|| unsafe { test_only_1(0) }); test(|| unsafe { test_only_1b(0) }); test(|| unsafe { test_only_10(0, 0, 0, 0, 0, 0, 0, 0, 0, 0) }); - debug::exit(true); + scheduling::exit(); } fn test(f: impl FnOnce() -> isize) { let actual = f(); debug!("- {:08x} {:?}", actual as usize, Error::decode(actual as i32)); let expected = Error::encode(Err(Error::world(Code::NotImplemented))) as isize; - debug::assert_eq(&actual, &expected); + assert_eq!(actual, expected); } #[cfg(not(feature = "native"))] diff --git a/examples/rust/memory_game/Cargo.lock b/examples/rust/memory_game/Cargo.lock index f4a447e56..a3f099c5e 100644 --- a/examples/rust/memory_game/Cargo.lock +++ b/examples/rust/memory_game/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/oom/Cargo.lock b/examples/rust/oom/Cargo.lock index a08ce96e4..2599dbe6a 100644 --- a/examples/rust/oom/Cargo.lock +++ b/examples/rust/oom/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/panic/Cargo.lock b/examples/rust/panic/Cargo.lock index 353f4d120..b2a05c921 100644 --- a/examples/rust/panic/Cargo.lock +++ b/examples/rust/panic/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/perf/Cargo.lock b/examples/rust/perf/Cargo.lock index b6aedce98..6a9e41a14 100644 --- a/examples/rust/perf/Cargo.lock +++ b/examples/rust/perf/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/protocol/Cargo.lock b/examples/rust/protocol/Cargo.lock index b0d682e9c..3e2fb2321 100644 --- a/examples/rust/protocol/Cargo.lock +++ b/examples/rust/protocol/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/protocol/host/Cargo.lock b/examples/rust/protocol/host/Cargo.lock index 778df6f45..e25798fbd 100644 --- a/examples/rust/protocol/host/Cargo.lock +++ b/examples/rust/protocol/host/Cargo.lock @@ -561,14 +561,18 @@ dependencies = [ [[package]] name = "wasefire-logger" -version = "0.1.5" +version = "0.1.6-git" dependencies = [ "log", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-protocol" -version = "0.1.1-git" +version = "0.2.0-git" dependencies = [ "anyhow", "wasefire-error", @@ -583,6 +587,7 @@ dependencies = [ "rusb", "wasefire-board-api", "wasefire-logger", + "wasefire-one-of", "wasefire-protocol", ] diff --git a/examples/rust/protocol/host/src/main.rs b/examples/rust/protocol/host/src/main.rs index 5e18345ca..f0bb09aa4 100644 --- a/examples/rust/protocol/host/src/main.rs +++ b/examples/rust/protocol/host/src/main.rs @@ -56,7 +56,7 @@ async fn main() -> Result<()> { connection.call::(request).await?.get(); loop { let response = connection.call::(AppletId).await?; - if let Some(response) = response.get().response { + if let Some(response) = response.get() { print!("{}", std::str::from_utf8(response).unwrap()); break Ok(()); } diff --git a/examples/rust/rand/Cargo.lock b/examples/rust/rand/Cargo.lock index 989be9880..7629e25c2 100644 --- a/examples/rust/rand/Cargo.lock +++ b/examples/rust/rand/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/reboot/Cargo.lock b/examples/rust/reboot/Cargo.lock index b21317af2..39e3ece6e 100644 --- a/examples/rust/reboot/Cargo.lock +++ b/examples/rust/reboot/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/rng_test/Cargo.lock b/examples/rust/rng_test/Cargo.lock index 799e4fae8..3408e1e01 100644 --- a/examples/rust/rng_test/Cargo.lock +++ b/examples/rust/rng_test/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/rng_test/src/lib.rs b/examples/rust/rng_test/src/lib.rs index e13dd1ada..030b0a418 100644 --- a/examples/rust/rng_test/src/lib.rs +++ b/examples/rust/rng_test/src/lib.rs @@ -19,7 +19,7 @@ wasefire::applet!(); fn main() { test_non_constant(); - debug::exit(true); + scheduling::exit(); } fn test_non_constant() { @@ -31,7 +31,7 @@ fn test_non_constant() { } for i in 1 .. buffers.len() { for j in 0 .. i { - debug::assert(buffers[j] != buffers[i]); + assert!(buffers[j] != buffers[i]); } } } diff --git a/examples/rust/store/Cargo.lock b/examples/rust/store/Cargo.lock index 6b48ca595..8c5a03134 100644 --- a/examples/rust/store/Cargo.lock +++ b/examples/rust/store/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/store_test/Cargo.lock b/examples/rust/store_test/Cargo.lock index c24643361..c91cbc220 100644 --- a/examples/rust/store_test/Cargo.lock +++ b/examples/rust/store_test/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/store_test/src/lib.rs b/examples/rust/store_test/src/lib.rs index 7e41fcf62..913e45d42 100644 --- a/examples/rust/store_test/src/lib.rs +++ b/examples/rust/store_test/src/lib.rs @@ -21,13 +21,13 @@ use alloc::vec::Vec; fn main() { store::clear().unwrap(); - debug::assert(store::keys().unwrap().is_empty()); + assert!(store::keys().unwrap().is_empty()); test_insert(); test_remove(); test_find(); test_keys(); test_fragment(); - debug::exit(true); + scheduling::exit(); } fn test_insert() { @@ -62,7 +62,7 @@ fn test_find() { let expected = (!removed).then(|| value(key)); debug!("- Check {key:4} is {}", if removed { "-removed" } else { "present" }); let actual = store::find(key).unwrap(); - debug::assert_eq(&actual.as_deref(), &expected.as_deref()); + assert_eq!(actual.as_deref(), expected.as_deref()); } for &key in INSERTED { let removed = REMOVED.contains(&key); @@ -86,17 +86,17 @@ fn test_keys() { let mut actual = store::keys().unwrap(); actual.sort(); debug!("- {actual:?}"); - debug::assert_eq(&actual, &expected); + assert_eq!(actual, expected); } fn test_fragment() { debug!("test_fragment(): Test fragmented entries."); debug!("- insert then find"); store::fragment::insert(0 .. 2, &[0xca; 1500]).unwrap(); - debug::assert_eq(&store::fragment::find(0 .. 2).unwrap().unwrap()[..], &[0xca; 1500][..]); + assert_eq!(store::fragment::find(0 .. 2).unwrap().unwrap()[..], [0xca; 1500]); debug!("- remove then find"); store::fragment::remove(0 .. 2).unwrap(); - debug::assert(store::fragment::find(0 .. 2).unwrap().is_none()); + assert!(store::fragment::find(0 .. 2).unwrap().is_none()); } const INSERTED: &[usize] = &[0, 1, 2, 3, 100, 500, 1000, 2000]; diff --git a/examples/rust/sync_test/Cargo.lock b/examples/rust/sync_test/Cargo.lock index 59816a2e5..05379998b 100644 --- a/examples/rust/sync_test/Cargo.lock +++ b/examples/rust/sync_test/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/sync_test/src/lib.rs b/examples/rust/sync_test/src/lib.rs index ec2bae308..da6ecd799 100644 --- a/examples/rust/sync_test/src/lib.rs +++ b/examples/rust/sync_test/src/lib.rs @@ -23,42 +23,42 @@ use core::cell::Cell; fn main() { test_mutex(); test_atomic(); - debug::exit(true); + scheduling::exit(); } fn test_mutex() { debug!("test_mutex(): Mutex operations should work."); static GLOBAL: sync::Mutex = sync::Mutex::new(0); debug!("- read initial value"); - debug::assert_eq(&*GLOBAL.lock(), &0); + assert_eq!(*GLOBAL.lock(), 0); debug!("- write new value"); *GLOBAL.lock() = 1; debug!("- read updated value"); - debug::assert_eq(&*GLOBAL.lock(), &1); + assert_eq!(*GLOBAL.lock(), 1); let _lock = GLOBAL.lock(); debug!("- try to double lock from the same thread"); - debug::assert(GLOBAL.try_lock().is_none()); + assert!(GLOBAL.try_lock().is_none()); debug!("- try to double lock from a callback"); let has_run = Rc::new(Cell::new(false)); let timer = timer::Timer::new({ let has_run = has_run.clone(); move || { has_run.set(true); - debug::assert(GLOBAL.try_lock().is_none()); + assert!(GLOBAL.try_lock().is_none()); } }); timer.start_ms(timer::Oneshot, 100); scheduling::wait_for_callback(); - debug::assert(has_run.get()); + assert!(has_run.get()); } fn test_atomic() { debug!("test_atomic(): Atomic operations should work."); static GLOBAL: sync::AtomicI32 = sync::AtomicI32::new(0); debug!("- read initial value"); - debug::assert_eq(&GLOBAL.load(sync::Ordering::SeqCst), &0); + assert_eq!(GLOBAL.load(sync::Ordering::SeqCst), 0); debug!("- write new value"); GLOBAL.store(1, sync::Ordering::SeqCst); debug!("- read updated value"); - debug::assert_eq(&GLOBAL.load(sync::Ordering::SeqCst), &1); + assert_eq!(GLOBAL.load(sync::Ordering::SeqCst), 1); } diff --git a/examples/rust/syscall_test/Cargo.lock b/examples/rust/syscall_test/Cargo.lock index f9c56bbea..2f2bb3ad5 100644 --- a/examples/rust/syscall_test/Cargo.lock +++ b/examples/rust/syscall_test/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/syscall_test/src/lib.rs b/examples/rust/syscall_test/src/lib.rs index cd5d6680e..e5d918aca 100644 --- a/examples/rust/syscall_test/src/lib.rs +++ b/examples/rust/syscall_test/src/lib.rs @@ -19,7 +19,7 @@ wasefire::applet!(); fn main() { test_error(); - debug::exit(true); + scheduling::exit(); } fn test_error() { @@ -32,6 +32,6 @@ fn test_error() { (0xffffffff, Err(Error::default())), ] { debug!("- {x:08x} -> {r:?}"); - debug::assert_eq(&syscall(0, 0, 0, x), &r); + assert_eq!(syscall(0, 0, 0, x), r); } } diff --git a/examples/rust/timer/Cargo.lock b/examples/rust/timer/Cargo.lock index 8fb78e3f0..26bdeab17 100644 --- a/examples/rust/timer/Cargo.lock +++ b/examples/rust/timer/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/timer_test/Cargo.lock b/examples/rust/timer_test/Cargo.lock index e1d473196..614b10c57 100644 --- a/examples/rust/timer_test/Cargo.lock +++ b/examples/rust/timer_test/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/timer_test/src/lib.rs b/examples/rust/timer_test/src/lib.rs index 78d828040..d444ce9f8 100644 --- a/examples/rust/timer_test/src/lib.rs +++ b/examples/rust/timer_test/src/lib.rs @@ -35,7 +35,7 @@ fn main() { test_periodic_cancel(); test_cancel_callback(); test_empty(); - debug::exit(true); + scheduling::exit(); } fn test_periodic(explicit_stop: bool) { @@ -58,7 +58,7 @@ fn test_periodic(explicit_stop: bool) { debug!("+ stop timer"); timer.stop(); } - debug::assert_eq(&i.get(), &5); + assert_eq!(i.get(), 5); } fn test_oneshot() { @@ -74,7 +74,7 @@ fn test_oneshot() { debug!("+ start timer"); timer.start_ms(timer::Oneshot, SECOND_MS); scheduling::wait_until(|| done.get()); - debug::assert(done.get()); + assert!(done.get()); } fn test_oneshot_cancel() { @@ -90,7 +90,7 @@ fn test_oneshot_cancel() { timer::sleep_ms(SECOND_MS); debug!("+ stop timer"); timer.stop(); - debug::assert(!done.get()); + assert!(!done.get()); } fn test_periodic_cancel() { @@ -109,7 +109,7 @@ fn test_periodic_cancel() { timer::sleep_ms(7 * SECOND_MS / 2); debug!("+ stop timer"); timer.stop(); - debug::assert_eq(&i.get(), &3); + assert_eq!(i.get(), 3); } fn test_cancel_callback() { @@ -123,8 +123,8 @@ fn test_cancel_callback() { while scheduling::num_pending_callbacks() == 0 {} debug!("- callback scheduled"); drop(first); - debug::assert_eq(&scheduling::num_pending_callbacks(), &0); - debug::assert(!has_run.get()); + assert_eq!(scheduling::num_pending_callbacks(), 0); + assert!(!has_run.get()); } fn test_empty() { @@ -138,5 +138,5 @@ fn test_empty() { timer.start_ms(timer::Oneshot, 0); scheduling::wait_until(|| done.get()); debug!("- done"); - debug::assert(done.get()); + assert!(done.get()); } diff --git a/examples/rust/uart-usb/Cargo.lock b/examples/rust/uart-usb/Cargo.lock index 27e45dc18..f5cc31249 100644 --- a/examples/rust/uart-usb/Cargo.lock +++ b/examples/rust/uart-usb/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/update/Cargo.lock b/examples/rust/update/Cargo.lock index a16f3a774..9c8dbbd24 100644 --- a/examples/rust/update/Cargo.lock +++ b/examples/rust/update/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/examples/rust/version/Cargo.lock b/examples/rust/version/Cargo.lock index df433ddab..ce099783c 100644 --- a/examples/rust/version/Cargo.lock +++ b/examples/rust/version/Cargo.lock @@ -188,7 +188,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasefire" -version = "0.6.1-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "crypto-common", @@ -196,16 +196,18 @@ dependencies = [ "typenum", "wasefire-applet-api", "wasefire-error", + "wasefire-one-of", "wasefire-sync", ] [[package]] name = "wasefire-applet-api" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "bytemuck", "wasefire-applet-api-macro", "wasefire-error", + "wasefire-one-of", ] [[package]] @@ -221,7 +223,7 @@ dependencies = [ [[package]] name = "wasefire-applet-api-macro" -version = "0.6.2-git" +version = "0.7.0-git" dependencies = [ "wasefire-applet-api-desc", ] @@ -233,6 +235,10 @@ dependencies = [ "num_enum", ] +[[package]] +name = "wasefire-one-of" +version = "0.1.0-git" + [[package]] name = "wasefire-sync" version = "0.1.1" diff --git a/scripts/ci.sh b/scripts/ci.sh index ae728902d..90329e138 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -34,7 +34,7 @@ x ./scripts/ci-taplo.sh x ./scripts/ci-applets.sh x ./scripts/ci-runners.sh x ./scripts/ci-tests.sh -x ./scripts/hwci.sh host --no-default-features --features=unix +x ./scripts/hwci.sh host x ./scripts/ci-book.sh x ./scripts/footprint.sh x rm footprint.toml diff --git a/scripts/hwci.sh b/scripts/hwci.sh index e2c7fe75d..4c222fd03 100755 --- a/scripts/hwci.sh +++ b/scripts/hwci.sh @@ -17,10 +17,12 @@ set -e . scripts/log.sh . scripts/package.sh -# This script runs the test applets and thus needs an appropriate board. It -# takes the name of the runner as argument and any runner flags, if any. - -[ $# -gt 0 ] || e "Usage: $0 [..]" +# This script runs the test applets and thus needs a connected platform. +# +# Usage: {host,nordic} +# Runs all supported hardware tests for an xtask runner. +# Usage: [ [--release]] +# Runs simple hardware tests for generic platforms. list() { find examples/rust -maxdepth 1 -name '*_test' -printf '%P\n' | sort @@ -30,17 +32,53 @@ features() { package_features | grep -v -e human -e test } -for name in $(list); do - x cargo xtask applet rust $name runner "$@" - for feature in $(cd examples/rust/$name && features); do - native= - if [ $feature = native ]; then - [ "$1" = host ] && continue - native=--native - fi - x cargo xtask $native applet rust $name --features=$feature runner "$@" +# {,--release} [] +run() { + local protocol=$1 release=$2 + local name feature runner + shift 2 + for name in $(list); do + [ $# -gt 0 ] || x cargo xtask $release applet rust $name install $protocol wait + for feature in $(cd examples/rust/$name && features); do + if [ $feature = native ]; then + [ $# -gt 0 ] || continue + y cargo xtask $release --native \ + applet rust $name --features=native \ + runner "$@" flash --reset-flash + runner=$! + x cargo xtask wait-applet $protocol + x cargo wasefire platform-lock $protocol + x kill $runner + else + [ $# -gt 0 ] && continue + x cargo xtask $release applet rust $name --features=$feature install $protocol wait + fi + done done -done -for name in $(list); do - x cargo xtask --release applet rust $name runner "$@" -done +} + +# +full() { + local protocol=--protocol=$1 + local release + shift + trap "trap 'exit 1' TERM && kill -- -$$" EXIT + cargo wasefire platform-lock $protocol 2>/dev/null || true + for release in '' --release; do + y cargo xtask $release runner "$@" flash --reset-flash + runner=$! + x cargo xtask wait-platform $protocol + run $protocol "$release" + x cargo wasefire platform-lock $protocol + x kill $runner + [ $1 = host ] || run $protocol "$release" "$@" + done + trap - EXIT +} + +case $1 in + host) full unix host --arg=--protocol=unix ;; + # P1.01, P1.02, and P1.03 must be connected together (gpio_test). + nordic) full usb nordic ;; + *) run --protocol=${1:-usb} "$2" ;; +esac diff --git a/scripts/log.sh b/scripts/log.sh index 087a0dad1..25c5f7ab4 100644 --- a/scripts/log.sh +++ b/scripts/log.sh @@ -12,7 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -x() { ( set -x; "$@"; ); } +x() { ( set -x; "$@" ) } +y() { ( set -x; exec "$@" ) & echo pid=$!; } i() { _log '1;36' Info "$*"; } w() { _log '1;33' Warn "$*"; } t() { _log '1;33' Todo "$*"; } diff --git a/scripts/publish.sh b/scripts/publish.sh index eb2021d91..3a535ea0c 100755 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -22,6 +22,7 @@ set -e [ -z "$(git status -s)" ] || e "Repository is not clean" TOPOLOGICAL_ORDER=( + one-of logger wire-derive error diff --git a/scripts/setup.sh b/scripts/setup.sh index 63e80607a..bbd85b4b1 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -57,6 +57,5 @@ fi ensure bin cc ensure lib libudev -# Transitive dependencies of runner-host. This should ideally be installed on -# demand by xtask. +# Transitive dependencies of runner-host. ensure bin usbip diff --git a/scripts/sync.sh b/scripts/sync.sh index 6b8a605de..7cf44f478 100755 --- a/scripts/sync.sh +++ b/scripts/sync.sh @@ -35,10 +35,9 @@ for dir in $(find crates -name Cargo.toml -printf '%h\n' | sort); do [ "$(tail -n1 $file)" = '[lints]' ] || printf '\n[lints]\n' >> $file add_lint $file allow clippy.unit-arg # add_lint $file warn rust.elided-lifetimes-in-paths - # add_lint $file warn rust.missing-debug-implementations # TODO: Use the same [ -e src/lib.rs -a "$(package_publish)" = true ] test as in test-helper. case $crate in - board|prelude) add_lint $file warn rust.missing-docs ;; + board|one-of|prelude) add_lint $file warn rust.missing-docs ;; esac # TODO: Enable for all crates. case $crate in @@ -53,10 +52,12 @@ for dir in $(find crates -name Cargo.toml -printf '%h\n' | sort); do # add_lint $file warn rust.unused-results done -( cd crates/protocol/crates/schema - cargo run --features=host - cargo run --features=device -) +for dir in $(git ls-files '*/sync.sh'); do + dir=$(dirname $dir) + [ $dir = scripts ] && continue + i "Sync $dir" + ( cd $dir && ./sync.sh ) +done book_example() { local src=book/src/applet/prelude/$1.rs diff --git a/scripts/test-helper.sh b/scripts/test-helper.sh index c164eb985..3c84eaaed 100644 --- a/scripts/test-helper.sh +++ b/scripts/test-helper.sh @@ -20,13 +20,12 @@ SELF="$0" ensure_applet() { ( cd "$GIT_ROOT" - if [ ! -e target/wasefire/applet.wasm ]; then - mkdir -p target/wasefire - x touch target/wasefire/applet.wasm - fi - if [ ! -e target/wasefire/libapplet.a ]; then - x cargo xtask --native-target=thumbv7em-none-eabi applet rust hello - fi + for file in applet.wasm libapplet.a; do + if [ ! -e target/wasefire/$file ]; then + mkdir -p target/wasefire + x touch target/wasefire/$file + fi + done ) } @@ -187,9 +186,6 @@ crypto-sha256 crypto-sha384 gpio led -platform -platform-protocol -platform-update radio-ble rng storage