├── vm-superio ├── README.md ├── LICENSE-APACHE ├── LICENSE-BSD-3-Clause ├── Cargo.toml ├── src │ ├── lib.rs │ ├── i8042.rs │ ├── rtc_pl031.rs │ └── serial.rs └── CHANGELOG.md ├── vm-superio-ser ├── README.md ├── LICENSE-APACHE ├── LICENSE-BSD-3-Clause ├── src │ ├── lib.rs │ ├── rtc_pl031.rs │ └── serial.rs ├── Cargo.toml └── CHANGELOG.md ├── .gitignore ├── .gitmodules ├── coverage_config_aarch64.json ├── coverage_config_x86_64.json ├── CODEOWNERS ├── .github ├── dependabot.yml └── workflows │ ├── publish-vm-superio.yaml │ └── publish-vm-superio-ser.yaml ├── Cargo.toml ├── .cargo └── config ├── LICENSE-BSD-3-Clause ├── README.md └── LICENSE-APACHE /vm-superio/README.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /vm-superio-ser/README.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /vm-superio/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | ../LICENSE-APACHE -------------------------------------------------------------------------------- /vm-superio-ser/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | ../LICENSE-APACHE -------------------------------------------------------------------------------- /vm-superio-ser/LICENSE-BSD-3-Clause: -------------------------------------------------------------------------------- 1 | ../LICENSE-BSD-3-Clause -------------------------------------------------------------------------------- /vm-superio/LICENSE-BSD-3-Clause: -------------------------------------------------------------------------------- 1 | ../LICENSE-BSD-3-Clause -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | .idea 5 | kcov_output 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "rust-vmm-ci"] 2 | path = rust-vmm-ci 3 | url = https://github.com/rust-vmm/rust-vmm-ci.git 4 | -------------------------------------------------------------------------------- /coverage_config_aarch64.json: -------------------------------------------------------------------------------- 1 | { 2 | "coverage_score": 95.3, 3 | "exclude_path": "", 4 | "crate_features": "" 5 | } 6 | -------------------------------------------------------------------------------- /coverage_config_x86_64.json: -------------------------------------------------------------------------------- 1 | { 2 | "coverage_score": 96.06, 3 | "exclude_path": "", 4 | "crate_features": "" 5 | } 6 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Add the list of code owners here (using their GitHub username) 2 | * @andreeaflorescu @lauralt @gsserge @roypat @ShadowCurse 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gitsubmodule 4 | directory: "/" 5 | schedule: 6 | interval: monthly 7 | open-pull-requests-limit: 10 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "vm-superio", 4 | "vm-superio-ser", 5 | ] 6 | 7 | [workspace.dependencies] 8 | # rust-vmm crates 9 | vmm-sys-util = ">=0.12.1,<=0.14.0" 10 | -------------------------------------------------------------------------------- /.cargo/config: -------------------------------------------------------------------------------- 1 | # This workaround is needed because the linker is unable to find __addtf3, 2 | # __multf3 and __subtf3. 3 | # Related issue: https://github.com/rust-lang/compiler-builtins/issues/201 4 | [target.aarch64-unknown-linux-musl] 5 | rustflags = [ "-C", "target-feature=+crt-static", "-C", "link-arg=-lgcc"] 6 | -------------------------------------------------------------------------------- /vm-superio/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vm-superio" 3 | version = "0.8.1" 4 | description = "Emulation for legacy devices" 5 | keywords = ["superio", "emulation"] 6 | repository = "https://github.com/rust-vmm/vm-superio" 7 | readme = "README.md" 8 | authors = ["rust-vmm AWS maintainers "] 9 | license = "Apache-2.0 OR BSD-3-Clause" 10 | edition = "2018" 11 | 12 | [dev-dependencies] 13 | libc = "0.2.39" 14 | vmm-sys-util = { workspace = true } 15 | -------------------------------------------------------------------------------- /vm-superio-ser/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 4 | 5 | //! Adds to the state objects from `vm-superio` serialization capabilities. 6 | //! 7 | //! Provides wrappers over the state objects from `vm-superio` crate which 8 | //! implement the `Serialize`, `Deserialize` and `Versionize` traits as well. 9 | 10 | #![deny(missing_docs)] 11 | 12 | pub mod rtc_pl031; 13 | pub mod serial; 14 | 15 | pub use rtc_pl031::RtcStateSer; 16 | pub use serial::SerialStateSer; 17 | -------------------------------------------------------------------------------- /.github/workflows/publish-vm-superio.yaml: -------------------------------------------------------------------------------- 1 | name: Publish vm-superio to crates.io 2 | 3 | on: 4 | push: 5 | tags: ['vm-superio-v*'] # Triggers when pushing tags starting with 'vm-superio-v' 6 | 7 | jobs: 8 | publish: 9 | runs-on: ubuntu-latest 10 | # environment: release # Optional: for enhanced security 11 | permissions: 12 | id-token: write # Required for OIDC token exchange 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: rust-lang/crates-io-auth-action@v1 16 | id: auth 17 | - run: | 18 | cd vm-superio 19 | cargo publish 20 | env: 21 | CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} 22 | -------------------------------------------------------------------------------- /.github/workflows/publish-vm-superio-ser.yaml: -------------------------------------------------------------------------------- 1 | name: Publish vm-superio-ser to crates.io 2 | 3 | on: 4 | push: 5 | tags: ['vm-superio-ser-v*'] # Triggers when pushing tags starting with 'vm-superio-ser-v' 6 | 7 | jobs: 8 | publish: 9 | runs-on: ubuntu-latest 10 | # environment: release # Optional: for enhanced security 11 | permissions: 12 | id-token: write # Required for OIDC token exchange 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: rust-lang/crates-io-auth-action@v1 16 | id: auth 17 | - run: | 18 | cd vm-superio-ser 19 | cargo publish 20 | env: 21 | CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} 22 | -------------------------------------------------------------------------------- /vm-superio-ser/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vm-superio-ser" 3 | version = "0.4.1" 4 | description = "Serialization for legacy device states" 5 | keywords = ["superio", "serialization", "versioning"] 6 | repository = "https://github.com/rust-vmm/vm-superio" 7 | readme = "README.md" 8 | authors = ["rust-vmm AWS maintainers "] 9 | license = "Apache-2.0 OR BSD-3-Clause" 10 | edition = "2018" 11 | 12 | [dependencies] 13 | serde = { version = "1.0.27", features = ["derive"] } 14 | versionize = "0.2.0" 15 | versionize_derive = "0.1.3" 16 | # Combining both `version` and `path` so that it is possible to publish 17 | # the crate on crates.io. More details here: 18 | # https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#multiple-locations. 19 | # We are using a fixed version of `vm-superio` so that the current version 20 | # of `vm-superio-ser` won't take a newer version of vm-superio, with which 21 | # it may not be compatible. 22 | vm-superio = { version = "=0.8.1", path = "../vm-superio" } 23 | 24 | [dev-dependencies] 25 | libc = "0.2.39" 26 | vmm-sys-util = { workspace = true } 27 | bincode = "1.3" 28 | -------------------------------------------------------------------------------- /vm-superio-ser/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Upcoming Release 4 | 5 | ## v0.4.1 6 | 7 | ### Changed 8 | 9 | - Widen vmm-sys-util dependency to 0.12.0-0.14.0 10 | 11 | ## v0.4.0 12 | 13 | ### Changed 14 | 15 | - Updated vmm-sys-util dependency to 0.12.1 16 | - Updated versionize dependency to 0.2.0 17 | 18 | ## v0.3.0 19 | 20 | ### Changed 21 | 22 | - Updated vmm-sys-util dependency to 0.11.0 23 | - Switched to specifying dependencies using caret requirements 24 | instead of comparision requirements 25 | 26 | ## v0.2.0 27 | 28 | ### Added 29 | 30 | - Added support for a `(De)Serialize` and `Versionize` serial state object, 31 | `SerialStateSer`([#73](https://github.com/rust-vmm/vm-superio/pull/73)). 32 | 33 | ## v0.1.0 34 | 35 | This is the first `vm-superio-ser` release. 36 | The `vm-superio-ser` crate provides support for persisting the states from 37 | `vm-superio`. For now, it provides this support only for the `Rtc` device. 38 | `RtcStateSer` can be used by customers who need an `RtcState` that is also 39 | `(De)Serialize` and/or `Versionize`. 40 | This version of `RtcStateSer` is compatible with v0.5.0 version of `RtcState`. 41 | -------------------------------------------------------------------------------- /LICENSE-BSD-3-Clause: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Chromium OS Authors. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above 10 | // copyright notice, this list of conditions and the following disclaimer 11 | // in the documentation and/or other materials provided with the 12 | // distribution. 13 | // * Neither the name of Google Inc. nor the names of its 14 | // contributors may be used to endorse or promote products derived from 15 | // this software without specific prior written permission. 16 | // 17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vm-superio/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Portions Copyright 2017 The Chromium OS Authors. All rights reserved. 4 | // Use of this source code is governed by a BSD-style license that can be 5 | // found in the THIRD-PARTY file. 6 | // 7 | // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 8 | 9 | //! Emulation for legacy devices. 10 | //! 11 | //! For now, it offers emulation support only for the Linux serial console, 12 | //! an Arm PL031 Real Time Clock (RTC), and an i8042 PS/2 controller that only 13 | //! handles the CPU reset. 14 | //! 15 | //! It also provides a [Trigger](trait.Trigger.html) interface for an object 16 | //! that can generate an event. 17 | 18 | #![deny(missing_docs)] 19 | #![deny(missing_copy_implementations)] 20 | 21 | pub mod i8042; 22 | pub mod rtc_pl031; 23 | pub mod serial; 24 | 25 | pub use i8042::I8042Device; 26 | pub use rtc_pl031::{Rtc, RtcState}; 27 | pub use serial::{Serial, SerialState}; 28 | 29 | use std::result::Result; 30 | 31 | /// Abstraction for a simple, push-button like interrupt mechanism. 32 | /// This helps in abstracting away how events/interrupts are generated when 33 | /// working with the emulated devices. 34 | /// 35 | /// The user has to provide a `Trigger` object to the device's constructor when 36 | /// initializing that device. The generic type `T: Trigger` is used in the 37 | /// device's structure definition to mark the fact that the events notification 38 | /// mechanism is done via the Trigger interface. 39 | /// An example of how to implement the `Trigger` interface for 40 | /// [an eventfd wrapper](https://docs.rs/vmm-sys-util/latest/vmm_sys_util/eventfd/index.html) 41 | /// can be found in the 42 | /// [`Example` section from `Serial`](../vm_superio/serial/struct.Serial.html#example). 43 | /// The `EventFd` is wrapped in the `EventFdTrigger` newtype because Rust 44 | /// doesn't allow implementing an external trait on external types. To get 45 | /// around this restriction, the newtype pattern can be used. More details 46 | /// about this, 47 | /// [here](https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits-on-external-types). 48 | pub trait Trigger { 49 | /// Underlying type for the potential error conditions returned by `Self::trigger`. 50 | type E: std::fmt::Debug; 51 | 52 | /// Trigger an event. 53 | fn trigger(&self) -> Result<(), Self::E>; 54 | } 55 | -------------------------------------------------------------------------------- /vm-superio-ser/src/rtc_pl031.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 4 | 5 | //! Provides a wrapper over an `RtcState` that has serialization capabilities. 6 | //! 7 | //! This module defines the `RtcStateSer` abstraction which mirrors the 8 | //! `RtcState` from the base crate, and adds on top of it derives for 9 | //! the `Serialize`, `Deserialize` and `Versionize` traits. 10 | 11 | use serde::{Deserialize, Serialize}; 12 | use versionize::{VersionMap, Versionize, VersionizeResult}; 13 | use versionize_derive::Versionize; 14 | use vm_superio::RtcState; 15 | 16 | /// Wrapper over an `RtcState` that has serialization capabilities. 17 | #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize, Versionize)] 18 | pub struct RtcStateSer { 19 | /// The load register. 20 | pub lr: u32, 21 | /// The offset applied to the counter to get the RTC value. 22 | pub offset: i64, 23 | /// The MR register. 24 | pub mr: u32, 25 | /// The interrupt mask. 26 | pub imsc: u32, 27 | /// The raw interrupt value. 28 | pub ris: u32, 29 | } 30 | 31 | // The following `From` implementations can be used to convert from an `RtcStateSer` to the 32 | // `RtcState` from the base crate and vice versa. 33 | impl From<&RtcStateSer> for RtcState { 34 | fn from(state: &RtcStateSer) -> Self { 35 | RtcState { 36 | lr: state.lr, 37 | offset: state.offset, 38 | mr: state.mr, 39 | imsc: state.imsc, 40 | ris: state.ris, 41 | } 42 | } 43 | } 44 | 45 | impl From<&RtcState> for RtcStateSer { 46 | fn from(state: &RtcState) -> Self { 47 | RtcStateSer { 48 | lr: state.lr, 49 | offset: state.offset, 50 | mr: state.mr, 51 | imsc: state.imsc, 52 | ris: state.ris, 53 | } 54 | } 55 | } 56 | 57 | impl Default for RtcStateSer { 58 | fn default() -> Self { 59 | RtcStateSer::from(&RtcState::default()) 60 | } 61 | } 62 | 63 | #[cfg(test)] 64 | mod tests { 65 | use super::*; 66 | use vm_superio::rtc_pl031::NoEvents; 67 | use vm_superio::Rtc; 68 | 69 | #[test] 70 | fn test_state_ser() { 71 | let mut rtc = Rtc::new(); 72 | let mut data = [0; 4]; 73 | 74 | // Do some operations with the RTC. 75 | // Get the RTC value with a load register of 0 (the initial value). 76 | rtc.read(0x000, &mut data); 77 | 78 | let data2 = [1; 4]; 79 | // Write to LR register. 80 | rtc.write(0x008, &data2); 81 | 82 | let state = rtc.state(); 83 | let ser_state = RtcStateSer::from(&state); 84 | 85 | let state_after_restore = RtcState::from(&ser_state); 86 | let mut rtc_after_restore = Rtc::from_state(&state_after_restore, NoEvents); 87 | 88 | // Reading from the LR register should return the same value as before saving the state. 89 | rtc_after_restore.read(0x008, &mut data); 90 | assert_eq!(data, data2); 91 | 92 | // Check that the old and the new state are identical when using the intermediate 93 | // `RtcStateSer` object as well. 94 | assert_eq!(state, state_after_restore); 95 | 96 | // Test the `Default` implementation of RtcStateSer. 97 | let default_rtc_state_ser = RtcStateSer::default(); 98 | assert_eq!(RtcState::from(&default_rtc_state_ser), RtcState::default()); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /vm-superio/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Upcoming Release 4 | 5 | ## v0.8.1 6 | 7 | ### Changed 8 | 9 | - Widen vmm-sys-util dependency to 0.12.0-0.14.0 10 | 11 | ## v0.8.0 12 | 13 | ### Changed 14 | 15 | - Added a `reset_evt` to the `I8042Device` type to retrieve the underlying 16 | reset event object. 17 | - Added three methods to `Serial` to retrieve the `Write` output object. 18 | - Derived the `Copy` trait for `RtcState` and other auxiliary types. 19 | - Updated vmm-sys-util dependency to 0.12.1 20 | 21 | ## v0.7.0 22 | 23 | ### Changed 24 | 25 | - Update vmm-sys-util dependency to 0.11.0. 26 | - Switched to specifying dependencies using caret requirements 27 | instead of comparision requirements. 28 | 29 | ## v0.6.0 30 | 31 | ### Added 32 | 33 | - Added `SerialState`, and support for saving and restoring the state of the 34 | `Serial` device ([#73](https://github.com/rust-vmm/vm-superio/pull/73)). 35 | - Added the `Debug` derive to the exported structures 36 | ([#75](https://github.com/rust-vmm/vm-superio/pull/75)). 37 | 38 | ### Fixed 39 | 40 | - Fixed `enqueue_raw_bytes` for the corner case when 0 bytes were sent, and the 41 | fifo was full ([#77](https://github.com/rust-vmm/vm-superio/pull/77)). 42 | 43 | ## v0.5.0 44 | 45 | ### Added 46 | 47 | - Added `RtcState`, and support for saving and restoring the state of the `Rtc` 48 | device. This support is useful for snapshot use cases, such as live 49 | migration ([#65](https://github.com/rust-vmm/vm-superio/pull/65)). 50 | 51 | ### Fixed 52 | 53 | - Fixed potential overflow in the `Rtc` implementation caused by an invalid 54 | offset ([#65](https://github.com/rust-vmm/vm-superio/pull/65)). 55 | 56 | ## v0.4.0 57 | 58 | ### Added 59 | 60 | - Added `in_buffer_empty` to SerialEvents trait. This helps with handling 61 | the registration of I/O events related to the serial input 62 | ([#63](https://github.com/rust-vmm/vm-superio/pull/63)). 63 | 64 | ### Changed 65 | 66 | - Changed `RTC` to `Rtc` and `RTCEvents` to `RtcEvents` as part of the Rust 67 | version update to 1.52.1 68 | ([#57](https://github.com/rust-vmm/vm-superio/pull/57)). 69 | 70 | ## v0.3.0 71 | 72 | ### Fixed 73 | 74 | - Fixed implementation of Data Register (DR) which caused the guest time to be 75 | in the year 1970 ([#47](https://github.com/rust-vmm/vm-superio/issues/47)). 76 | 77 | ## v0.2.0 78 | 79 | ### Added 80 | 81 | - Added emulation support for an i8042 controller that only handles the CPU 82 | reset ([#11](https://github.com/rust-vmm/vm-superio/pull/11)). 83 | - Added `SerialEvents` trait, which can be implemented by a backend that wants 84 | to keep track of serial events using metrics, logs etc 85 | ([#5](https://github.com/rust-vmm/vm-superio/issues/5)). 86 | - Added a threat model to the serial console documentation 87 | ([#16](https://github.com/rust-vmm/vm-superio/issues/16)). 88 | - Added emulation support for an ARM PL031 Real Time Clock 89 | ([#22](https://github.com/rust-vmm/vm-superio/issues/22)), and the `RTCEvents` 90 | trait, used for keeping track of RTC events 91 | ([#34](https://github.com/rust-vmm/vm-superio/issues/34)). 92 | - Added an implementation for `Arc` for both serial console and RTC device 93 | ([#40](https://github.com/rust-vmm/vm-superio/pull/40)). 94 | - Added methods for retrieving a reference to the events object for both serial 95 | console and RTC device 96 | ([#40](https://github.com/rust-vmm/vm-superio/pull/40)). 97 | 98 | ### Changed 99 | 100 | - Changed the notification mechanism from EventFd to the Trigger abstraction 101 | for both serial console and i8042 102 | ([#7](https://github.com/rust-vmm/vm-superio/issues/7)). 103 | 104 | ### Fixed 105 | 106 | - Limited the maximum number of bytes allowed at a time, when enqueuing input 107 | for serial, to 64 (FIFO_SIZE) to avoid memory pressure 108 | ([#17](https://github.com/rust-vmm/vm-superio/issues/17)). 109 | - Fixed possible indefinite blocking of the serial driver by always sending the 110 | THR Empty interrupt to it when trying to write to the device 111 | ([#23](https://github.com/rust-vmm/vm-superio/issues/23)). 112 | 113 | ## v0.1.0 114 | 115 | This is the first `vm-superio` release. 116 | The `vm-superio` crate provides emulation for legacy devices. For now, it offers 117 | this support only for the Linux serial console. 118 | -------------------------------------------------------------------------------- /vm-superio/src/i8042.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 3 | // 4 | // Portions Copyright 2017 The Chromium OS Authors. All rights reserved. 5 | // Use of this source code is governed by a BSD-style license that can be 6 | // found in the THIRD-PARTY file. 7 | 8 | //! Provides emulation for a super minimal i8042 controller. 9 | //! 10 | //! This emulates just the CPU reset command. 11 | 12 | use std::result::Result; 13 | 14 | use crate::Trigger; 15 | 16 | // Offset of the command register, for write accesses (port 0x64). The same 17 | // offset can be used, in case of read operations, to access the status 18 | // register (in which we are not interested for an i8042 that only knows 19 | // about reset). 20 | const COMMAND_OFFSET: u8 = 4; 21 | 22 | // Reset CPU command. 23 | const CMD_RESET_CPU: u8 = 0xFE; 24 | 25 | /// An i8042 PS/2 controller that emulates just enough to shutdown the machine. 26 | /// 27 | /// A [`Trigger`](../trait.Trigger.html) object is used for notifying the VMM 28 | /// about the CPU reset event. 29 | /// 30 | /// # Example 31 | /// 32 | /// ```rust 33 | /// # use std::io::{Error, Result}; 34 | /// # use std::ops::Deref; 35 | /// # use vm_superio::Trigger; 36 | /// # use vm_superio::I8042Device; 37 | /// # use vmm_sys_util::eventfd::EventFd; 38 | /// 39 | /// struct EventFdTrigger(EventFd); 40 | /// impl Trigger for EventFdTrigger { 41 | /// type E = Error; 42 | /// 43 | /// fn trigger(&self) -> Result<()> { 44 | /// self.write(1) 45 | /// } 46 | /// } 47 | /// impl Deref for EventFdTrigger { 48 | /// type Target = EventFd; 49 | /// fn deref(&self) -> &Self::Target { 50 | /// &self.0 51 | /// } 52 | /// } 53 | /// impl EventFdTrigger { 54 | /// pub fn new(flag: i32) -> Self { 55 | /// EventFdTrigger(EventFd::new(flag).unwrap()) 56 | /// } 57 | /// } 58 | /// 59 | /// let reset_evt = EventFdTrigger::new(libc::EFD_NONBLOCK); 60 | /// let mut i8042 = I8042Device::new(reset_evt); 61 | /// 62 | /// // Check read/write operations. 63 | /// assert_eq!(i8042.read(0), 0); 64 | /// i8042.write(4, 0xFE).unwrap(); 65 | /// ``` 66 | #[derive(Debug)] 67 | pub struct I8042Device { 68 | /// CPU reset event object. We will trigger this event when the guest issues 69 | /// the reset CPU command. 70 | reset_evt: T, 71 | } 72 | 73 | impl I8042Device { 74 | /// Constructs an i8042 device that will signal the given event when the 75 | /// guest requests it. 76 | /// 77 | /// # Arguments 78 | /// * `reset_evt` - A Trigger object that will be used to notify the driver 79 | /// about the reset event. 80 | /// 81 | /// # Example 82 | /// 83 | /// You can see an example of how to use this function in the 84 | /// [`Example` section from `I8042Device`](struct.I8042Device.html#example). 85 | pub fn new(reset_evt: T) -> I8042Device { 86 | I8042Device { reset_evt } 87 | } 88 | 89 | /// Provides a reference to the reset event object. 90 | pub fn reset_evt(&self) -> &T { 91 | &self.reset_evt 92 | } 93 | 94 | /// Handles a read request from the driver at `_offset` offset from the 95 | /// base I/O address. 96 | /// 97 | /// Returns the read value, which at this moment is 0x00, since we're not 98 | /// interested in an i8042 operation other than CPU reset. 99 | /// 100 | /// # Arguments 101 | /// * `_offset` - The offset that will be added to the base address 102 | /// for writing to a specific register. 103 | /// 104 | /// # Example 105 | /// 106 | /// You can see an example of how to use this function in the 107 | /// [`Example` section from `I8042Device`](struct.I8042Device.html#example). 108 | pub fn read(&mut self, _offset: u8) -> u8 { 109 | 0x00 110 | } 111 | 112 | /// Handles a write request from the driver at `offset` offset from the 113 | /// base I/O address. 114 | /// 115 | /// # Arguments 116 | /// * `offset` - The offset that will be added to the base address 117 | /// for writing to a specific register. 118 | /// * `value` - The byte that should be written. 119 | /// 120 | /// # Example 121 | /// 122 | /// You can see an example of how to use this function in the 123 | /// [`Example` section from `I8042Device`](struct.I8042Device.html#example). 124 | pub fn write(&mut self, offset: u8, value: u8) -> Result<(), T::E> { 125 | match offset { 126 | COMMAND_OFFSET if value == CMD_RESET_CPU => { 127 | // Trigger the exit event. 128 | self.reset_evt.trigger() 129 | } 130 | _ => Ok(()), 131 | } 132 | } 133 | } 134 | 135 | #[cfg(test)] 136 | mod tests { 137 | use super::*; 138 | use vmm_sys_util::eventfd::EventFd; 139 | 140 | #[test] 141 | fn test_i8042_valid_ops() { 142 | let reset_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 143 | let mut i8042 = I8042Device::new(reset_evt.try_clone().unwrap()); 144 | 145 | assert_eq!(i8042.read(0), 0); 146 | 147 | // Check if reset works. 148 | i8042.write(COMMAND_OFFSET, CMD_RESET_CPU).unwrap(); 149 | assert_eq!(reset_evt.read().unwrap(), 1); 150 | } 151 | 152 | #[test] 153 | fn test_i8042_invalid_reset() { 154 | let reset_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 155 | let mut i8042 = I8042Device::new(reset_evt.try_clone().unwrap()); 156 | 157 | // Write something different than CPU reset and check that the reset event 158 | // was not triggered. For this we have to write 1 to the reset event fd, so 159 | // that read doesn't block. 160 | assert!(reset_evt.write(1).is_ok()); 161 | i8042.write(COMMAND_OFFSET, CMD_RESET_CPU + 1).unwrap(); 162 | assert_eq!(reset_evt.read().unwrap(), 1); 163 | 164 | // Write the CPU reset to a different offset than COMMAND_OFFSET and check that 165 | // the reset event was not triggered. 166 | // For such accesses we should increment some metric (COMMAND_OFFSET + 1 is not 167 | // even a valid i8042 offset), see 168 | // [tracking issue](https://github.com/rust-vmm/vm-superio/issues/13). 169 | assert!(reset_evt.write(1).is_ok()); 170 | i8042.write(COMMAND_OFFSET + 1, CMD_RESET_CPU).unwrap(); 171 | assert_eq!(reset_evt.read().unwrap(), 1); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /vm-superio-ser/src/serial.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 4 | 5 | //! Provides a wrapper over an `SerialState` that has serialization capabilities. 6 | //! 7 | //! This module defines the `SerialStateSer` abstraction which mirrors the 8 | //! `SerialState` from the base crate, and adds on top of it derives for 9 | //! the `Serialize`, `Deserialize` and `Versionize` traits. 10 | 11 | use serde::{Deserialize, Serialize}; 12 | use versionize::{VersionMap, Versionize, VersionizeResult}; 13 | use versionize_derive::Versionize; 14 | use vm_superio::SerialState; 15 | 16 | /// Wrapper over an `SerialState` that has serialization capabilities. 17 | #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize, Versionize)] 18 | pub struct SerialStateSer { 19 | /// Divisor Latch Low Byte 20 | pub baud_divisor_low: u8, 21 | /// Divisor Latch High Byte 22 | pub baud_divisor_high: u8, 23 | /// Interrupt Enable Register 24 | pub interrupt_enable: u8, 25 | /// Interrupt Identification Register 26 | pub interrupt_identification: u8, 27 | /// Line Control Register 28 | pub line_control: u8, 29 | /// Line Status Register 30 | pub line_status: u8, 31 | /// Modem Control Register 32 | pub modem_control: u8, 33 | /// Modem Status Register 34 | pub modem_status: u8, 35 | /// Scratch Register 36 | pub scratch: u8, 37 | /// Transmitter Holding Buffer/Receiver Buffer 38 | pub in_buffer: Vec, 39 | } 40 | 41 | // The following `From` implementations can be used to convert from an `SerialStateSer` to the 42 | // `SerialState` from the base crate and vice versa. 43 | impl From<&SerialStateSer> for SerialState { 44 | fn from(state: &SerialStateSer) -> Self { 45 | SerialState { 46 | baud_divisor_low: state.baud_divisor_low, 47 | baud_divisor_high: state.baud_divisor_high, 48 | interrupt_enable: state.interrupt_enable, 49 | interrupt_identification: state.interrupt_identification, 50 | line_control: state.line_control, 51 | line_status: state.line_status, 52 | modem_control: state.modem_control, 53 | modem_status: state.modem_status, 54 | scratch: state.scratch, 55 | in_buffer: state.in_buffer.clone(), 56 | } 57 | } 58 | } 59 | 60 | impl From<&SerialState> for SerialStateSer { 61 | fn from(state: &SerialState) -> Self { 62 | SerialStateSer { 63 | baud_divisor_low: state.baud_divisor_low, 64 | baud_divisor_high: state.baud_divisor_high, 65 | interrupt_enable: state.interrupt_enable, 66 | interrupt_identification: state.interrupt_identification, 67 | line_control: state.line_control, 68 | line_status: state.line_status, 69 | modem_control: state.modem_control, 70 | modem_status: state.modem_status, 71 | scratch: state.scratch, 72 | in_buffer: state.in_buffer.clone(), 73 | } 74 | } 75 | } 76 | 77 | impl Default for SerialStateSer { 78 | fn default() -> Self { 79 | SerialStateSer::from(&SerialState::default()) 80 | } 81 | } 82 | 83 | #[cfg(test)] 84 | mod tests { 85 | use super::*; 86 | use std::io::sink; 87 | use std::ops::Deref; 88 | use vm_superio::serial::NoEvents; 89 | use vm_superio::{Serial, Trigger}; 90 | use vmm_sys_util::eventfd::EventFd; 91 | 92 | const RAW_INPUT_BUF: [u8; 3] = [b'a', b'b', b'c']; 93 | 94 | struct EventFdTrigger(EventFd); 95 | 96 | impl Trigger for EventFdTrigger { 97 | type E = std::io::Error; 98 | 99 | fn trigger(&self) -> std::io::Result<()> { 100 | self.write(1) 101 | } 102 | } 103 | 104 | impl Deref for EventFdTrigger { 105 | type Target = EventFd; 106 | fn deref(&self) -> &Self::Target { 107 | &self.0 108 | } 109 | } 110 | 111 | impl EventFdTrigger { 112 | pub fn new(flag: i32) -> Self { 113 | EventFdTrigger(EventFd::new(flag).unwrap()) 114 | } 115 | 116 | pub fn try_clone(&self) -> Self { 117 | EventFdTrigger((**self).try_clone().unwrap()) 118 | } 119 | } 120 | 121 | #[test] 122 | fn test_state_ser_default() { 123 | let default_serial_state_ser = SerialStateSer::default(); 124 | assert_eq!( 125 | SerialState::from(&default_serial_state_ser), 126 | SerialState::default() 127 | ); 128 | } 129 | 130 | #[test] 131 | fn test_state_ser_idempotency() { 132 | let state = SerialState::default(); 133 | let state_ser = SerialStateSer::from(&state); 134 | let state_from_ser = SerialState::from(&state_ser); 135 | 136 | assert_eq!(state, state_from_ser); 137 | } 138 | 139 | #[test] 140 | fn test_state_ser() { 141 | let intr_evt = EventFdTrigger::new(libc::EFD_NONBLOCK); 142 | let mut serial = Serial::new(intr_evt.try_clone(), sink()); 143 | 144 | serial.enqueue_raw_bytes(&RAW_INPUT_BUF).unwrap(); 145 | 146 | let state = serial.state(); 147 | let ser_state = SerialStateSer::from(&state); 148 | 149 | let state_after_restore = SerialState::from(&ser_state); 150 | let mut serial_after_restore = 151 | Serial::from_state(&state_after_restore, intr_evt.try_clone(), NoEvents, sink()) 152 | .unwrap(); 153 | 154 | RAW_INPUT_BUF.iter().for_each(|&c| { 155 | assert_eq!(serial_after_restore.read(0), c); 156 | }); 157 | assert_eq!(state, state_after_restore); 158 | } 159 | 160 | #[test] 161 | fn test_ser_der_binary() { 162 | let state = SerialStateSer::default(); 163 | let state_ser = bincode::serialize(&state).unwrap(); 164 | let state_der = bincode::deserialize(&state_ser).unwrap(); 165 | 166 | assert_eq!(state, state_der); 167 | } 168 | 169 | #[test] 170 | fn test_versionize() { 171 | let map = VersionMap::new(); 172 | let state = SerialStateSer::default(); 173 | let mut v1_state = Vec::new(); 174 | 175 | Versionize::serialize(&state, &mut v1_state, &map, 1).unwrap(); 176 | 177 | let from_v1: SerialStateSer = 178 | Versionize::deserialize(&mut v1_state.as_slice(), &map, 1).unwrap(); 179 | 180 | assert_eq!(from_v1, state); 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vm-superio 2 | 3 | 4 | `vm-superio` provides emulation for legacy devices. For now, it offers this 5 | support only for the 6 | [Linux serial console](https://en.wikipedia.org/wiki/Linux_console), a minimal 7 | [i8042 PS/2 Controller](https://wiki.osdev.org/%228042%22_PS/2_Controller) and 8 | an 9 | [ARM PL031 Real Time Clock](https://developer.arm.com/documentation/ddi0224/c/Programmers-model). 10 | To enable snapshot use cases, such as live migration, it also provides support 11 | for saving and restoring the state, and for persisting it. 12 | In order to achieve this, and to keep a clear separation of concerns, 13 | `vm-superio` is a 14 | [workspace](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html), 15 | containing the following crates: 16 | - `vm-superio` - which keeps the state of the component; 17 | - `vm-superio-ser` - which mirrors the state structure from `vm-superio` and 18 | adds the required version constraints on it, and derives/implements the 19 | required (de)serialization traits (i.e. `serde`'s `Serialize` and 20 | `Deserialize`; `Versionize`). 21 | 22 | ## Serial Console 23 | 24 | ### Design 25 | 26 | The console emulation is done by emulating a simple 27 | [UART 16550A serial port](https://en.wikipedia.org/wiki/16550_UART) with a 28 | 64-byte FIFO. 29 | This UART is an improvement of the original 30 | [UART 8250 serial port](https://en.wikibooks.org/w/index.php?title=Serial_Programming/8250_UART_Programming§ion=15#Serial_COM_Port_Memory_and_I/O_Allocation), 31 | mostly because of the FIFO buffers that allow storing more than one byte at a 32 | time, which, in virtualized environments, is essential. 33 | 34 | For a VMM to be able to use this device, besides the emulation part which is 35 | covered in this crate, the VMM needs to do the following operations: 36 | - add the serial port to the Bus (either PIO or MMIO) 37 | - define the serial backend 38 | - event handling (optional) 39 | 40 | The following UART registers are emulated via the 41 | [`Serial` structure](./vm-superio/src/serial.rs): DLL, IER, DLH, IIR, LCR, 42 | LSR, MCR, MSR and SR (a brief, but nice presentation about these, 43 | [here](https://www.lammertbies.nl/comm/info/serial-uart#regs)). 44 | The Fifo Control Register (FCR) is not emulated; there is no support yet for 45 | directly controlling the FIFOs (which, in this implementation, are always 46 | enabled). The serial console implements only the RX FIFO (and its 47 | corresponding RBR register). The RX buffer helps in testing the UART when 48 | running in loopback mode and for sending more bytes to the guest in one shot. 49 | The TX FIFO is trivially implemented by immediately writing a byte coming from 50 | the driver to an `io::Write` object (`out`), which can be, for example, 51 | `io::Stdout` or `io::Sink`. This object has to be provided when 52 | [initializing the serial console](https://docs.rs/vm-superio/0.1.1/vm_superio/serial/struct.Serial.html#method.new). 53 | A `Trigger` object is the currently used mechanism for notifying the driver 54 | about in/out events that need to be handled. 55 | 56 | ## Threat model 57 | 58 | Trusted actors: 59 | * host kernel 60 | 61 | Untrusted actors: 62 | * guest kernel 63 | * guest drivers 64 | 65 | The untrusted actors can change the state of the device through reads and 66 | writes on the Bus at the address where the device resides. 67 | 68 | |#NR |Threat |Mitigation | 69 | |--- |--- |--- | 70 | |1 | A malicious guest generates large memory allocations by flooding the serial console input. [CVE-2020-27173](https://nvd.nist.gov/vuln/detail/CVE-2020-27173) |The serial console limits the number of elements in the FIFO corresponding to the serial console input to `FIFO_SIZE` (=64), returning a FIFO Full error when the limit is reached. This error MUST be handled by the crate customer. When the serial console input is connected to an event loop, the customer MUST ensure that the loop is not flooded with events coming from untrusted sources when no space is available in the FIFO. | 71 | |2 |A malicious guest can fill up the host disk by generating a high amount of data to be written to the serial output. |Mitigation is not possible at the emulation layer because we are not controlling the output (`Writer`). This needs to be mitigated at the VMM level by adding a rate limiting mechanism. We recommend using as output a resource that has a fixed size (e.g. ring buffer or a named pipe). | 72 | 73 | ### Usage 74 | 75 | The interaction between the serial console and its driver, at the emulation 76 | level, is done by the two `read` and `write` specific methods, which handle 77 | one byte accesses. For sending more input, `enqueue_raw_bytes` can be used. 78 | 79 | ## i8042 PS/2 Controller 80 | 81 | The i8042 PS/2 controller emulates, at this point, only the 82 | [CPU reset command](https://wiki.osdev.org/%228042%22_PS/2_Controller#CPU_Reset) 83 | which is needed for announcing the VMM about the guest's shutdown. 84 | 85 | ## ARM PL031 Real Time Clock 86 | 87 | This module emulates the ARM PrimeCell Real Time Clock (RTC) 88 | [PL031](https://developer.arm.com/documentation/ddi0224/c/Functional-overview/RTC-operation/RTC-operation). 89 | The PL031 provides a long time base counter with a 1HZ counter signal and 90 | a configurable offset. 91 | 92 | This implementation emulates all control, peripheral ID, and PrimeCell ID 93 | registers; however, the interrupt based on the value of the Match Register 94 | (RTCMR) is not currently implemented (i.e., setting the Match Register has 95 | no effect). 96 | 97 | For a VMM to be able to use this device, the VMM needs to do the following: 98 | - add the RTC to the Bus (either PIO or MMIO) 99 | - provide a structure that implements RTCEvents to track the occurrence of significant events (optional) 100 | 101 | Note that because the Match Register is the only possible source of an event, 102 | and the Match Register is not currently implemented, no event handling 103 | is required. 104 | 105 | ### Threat model 106 | 107 | Trusted actors: 108 | * host kernel 109 | 110 | Untrusted actors: 111 | * guest kernel 112 | * guest drivers 113 | 114 | The untrusted actors can change the state of the device through reads and 115 | writes on the Bus at the address where the device resides. 116 | 117 | |#NR |Threat |Mitigation | 118 | |--- |--- |--- | 119 | |1 |A malicious guest writes invalid values in the Load Register to cause overflows on subsequent reads of the Data Register. |The arithmetic operations in the RTC are checked for overflows. When such a situation occurs, the state of the device is reset. | 120 | |2 |A malicious guest performs reads and writes from invalid offsets (that do not correspond to the RTC registers) to cause crashes or to get access to data. |Reads and writes of invalid offsets are denied by the emulation, and an `invalid_read/write` event is called. These events can be implemented by VMMs, and extend them to generate alarms (and for example stop the execution of the malicious guest). | 121 | 122 | ## Save/restore state support 123 | 124 | This support is offered for the `Rtc` and the `Serial` devices by the following 125 | abstractions: 126 | - `State` -> which keeps the hardware state of the ``; 127 | - `StateSer` -> which can be used by customers who need a 128 | `State` that is also `(De)Serialize` and/or `Versionize`. If the 129 | customers want a different state than the upstream one, then they can 130 | implement `From` (or similar mechanisms) in their products to convert the 131 | upstream state to the desired product state. 132 | 133 | A detailed design document for the save/restore state support in rust-vmm can 134 | be found [here](https://github.com/rust-vmm/community/pull/118/files). 135 | 136 | ### Compatibility between `vm-superio` and `vm-superio-ser` versions 137 | 138 | Each time there's a change in a state from `vm-superio`, that change needs to 139 | be propagated in the corresponding state from `vm-superio-ser`. To keep the 140 | compatibility between the release versions of these two crates, once we have a 141 | new release of `vm-superio` that implied a change in `vm-superio-ser`, we need 142 | to have a new release of `vm-superio-ser` as well. 143 | Therefore, the `vm-superio-ser` crate has an exact version of `vm-superio` as 144 | dependency. 145 | 146 | ## License 147 | 148 | This project is licensed under either of 149 | 150 | - [Apache License](http://www.apache.org/licenses/LICENSE-2.0), Version 2.0 151 | - [BSD-3-Clause License](https://opensource.org/licenses/BSD-3-Clause) 152 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /vm-superio/src/rtc_pl031.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 3 | 4 | //! Provides emulation for a minimal ARM PL031 Real Time Clock. 5 | //! 6 | //! This module implements a PL031 Real Time Clock (RTC) that provides a long 7 | //! time base counter. This is achieved by generating an interrupt signal after 8 | //! counting for a programmed number of cycles of a real-time clock input. 9 | 10 | use std::convert::TryFrom; 11 | use std::sync::Arc; 12 | use std::time::{SystemTime, UNIX_EPOCH}; 13 | 14 | // The following defines are mapping to the specification: 15 | // https://developer.arm.com/documentation/ddi0224/c/Programmers-model/Summary-of-RTC-registers 16 | // 17 | // From 0x0 to 0x1C we have following registers: 18 | const RTCDR: u16 = 0x000; // Data Register (RO). 19 | const RTCMR: u16 = 0x004; // Match Register. 20 | const RTCLR: u16 = 0x008; // Load Register. 21 | const RTCCR: u16 = 0x00C; // Control Register. 22 | const RTCIMSC: u16 = 0x010; // Interrupt Mask Set or Clear Register. 23 | const RTCRIS: u16 = 0x014; // Raw Interrupt Status (RO). 24 | const RTCMIS: u16 = 0x018; // Masked Interrupt Status (RO). 25 | const RTCICR: u16 = 0x01C; // Interrupt Clear Register (WO). 26 | 27 | // From 0x020 to 0xFDC => reserved space. 28 | 29 | // From 0xFE0 to 0xFFF => Peripheral and PrimeCell Identification Registers 30 | // These are read-only registers, so we store their values in a constant array. 31 | // The values are found in the 'Reset value' column of Table 3.1 (Summary of 32 | // RTC registers) in the the reference manual linked above. 33 | const AMBA_IDS: [u8; 8] = [0x31, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1]; 34 | 35 | // Since we are specifying the AMBA IDs in an array, instead of in individual 36 | // registers, these constants bound the register addresses where these IDs 37 | // would normally be located. 38 | const AMBA_ID_LOW: u16 = 0xFE0; 39 | const AMBA_ID_HIGH: u16 = 0xFFF; 40 | 41 | /// Defines a series of callbacks that are invoked in response to the occurrence of specific 42 | /// failure or missed events as part of the RTC operation (e.g., write to an invalid offset). The 43 | /// methods below can be implemented by a backend that keeps track of such events by incrementing 44 | /// metrics, logging messages, or any other action. 45 | /// 46 | /// We're using a trait to avoid constraining the concrete characteristics of the backend in 47 | /// any way, enabling zero-cost abstractions and use case-specific implementations. 48 | pub trait RtcEvents { 49 | /// The driver attempts to read from an invalid offset. 50 | fn invalid_read(&self); 51 | 52 | /// The driver attempts to write to an invalid offset. 53 | fn invalid_write(&self); 54 | } 55 | 56 | /// Provides a no-op implementation of `RtcEvents` which can be used in situations that 57 | /// do not require logging or otherwise doing anything in response to the events defined 58 | /// as part of `RtcEvents`. 59 | #[derive(Debug, Clone, Copy)] 60 | pub struct NoEvents; 61 | 62 | impl RtcEvents for NoEvents { 63 | fn invalid_read(&self) {} 64 | fn invalid_write(&self) {} 65 | } 66 | 67 | impl RtcEvents for Arc { 68 | fn invalid_read(&self) { 69 | self.as_ref().invalid_read(); 70 | } 71 | 72 | fn invalid_write(&self) { 73 | self.as_ref().invalid_write(); 74 | } 75 | } 76 | 77 | /// A PL031 Real Time Clock (RTC) that emulates a long time base counter. 78 | /// 79 | /// This structure emulates the registers for the RTC. 80 | /// 81 | /// # Example 82 | /// 83 | /// ```rust 84 | /// # use std::thread; 85 | /// # use std::io::Error; 86 | /// # use std::ops::Deref; 87 | /// # use std::time::{Instant, Duration, SystemTime, UNIX_EPOCH}; 88 | /// # use vm_superio::Rtc; 89 | /// 90 | /// let mut data = [0; 4]; 91 | /// let mut rtc = Rtc::new(); 92 | /// const RTCDR: u16 = 0x0; // Data Register. 93 | /// const RTCLR: u16 = 0x8; // Load Register. 94 | /// 95 | /// // Write system time since UNIX_EPOCH in seconds to the load register. 96 | /// let v = SystemTime::now() 97 | /// .duration_since(UNIX_EPOCH) 98 | /// .unwrap() 99 | /// .as_secs() as u32; 100 | /// data = v.to_le_bytes(); 101 | /// rtc.write(RTCLR, &data); 102 | /// 103 | /// // Read the value back out of the load register. 104 | /// rtc.read(RTCLR, &mut data); 105 | /// assert_eq!(v, u32::from_le_bytes(data)); 106 | /// 107 | /// // Sleep for 1.5 seconds to let the counter tick. 108 | /// let delay = Duration::from_millis(1500); 109 | /// thread::sleep(delay); 110 | /// 111 | /// // Read the current RTC value from the Data Register. 112 | /// rtc.read(RTCDR, &mut data); 113 | /// assert!(u32::from_le_bytes(data) > v); 114 | /// ``` 115 | #[derive(Debug)] 116 | pub struct Rtc { 117 | // The load register. 118 | lr: u32, 119 | 120 | // The offset applied to the counter to get the RTC value. 121 | offset: i64, 122 | 123 | // The MR register is used for implementing the RTC alarm. A 124 | // real time clock alarm is a feature that can be used to allow 125 | // a computer to 'wake up' after shut down to execute tasks 126 | // every day or on a certain day. It can sometimes be found in 127 | // the 'Power Management' section of a motherboard's BIOS setup. 128 | // This is not currently implemented, so we raise an error. 129 | // TODO: Implement the match register functionality. 130 | mr: u32, 131 | 132 | // The interrupt mask. 133 | imsc: u32, 134 | 135 | // The raw interrupt value. 136 | ris: u32, 137 | 138 | // Used for tracking the occurrence of significant events. 139 | events: EV, 140 | } 141 | 142 | /// The state of the Rtc device. 143 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] 144 | pub struct RtcState { 145 | /// The load register. 146 | pub lr: u32, 147 | /// The offset applied to the counter to get the RTC value. 148 | pub offset: i64, 149 | /// The MR register. 150 | pub mr: u32, 151 | /// The interrupt mask. 152 | pub imsc: u32, 153 | /// The raw interrupt value. 154 | pub ris: u32, 155 | } 156 | 157 | fn get_current_time() -> u32 { 158 | let epoch_time = SystemTime::now() 159 | .duration_since(UNIX_EPOCH) 160 | // This expect should never fail because UNIX_EPOCH is in 1970, 161 | // and the only possible failure is if `now` time is before UNIX EPOCH. 162 | .expect("SystemTime::duration_since failed"); 163 | // The following conversion is safe because u32::MAX would correspond to 164 | // year 2106. By then we would not be able to use the RTC in its 165 | // current form because RTC only works with 32-bits registers, and a bigger 166 | // time value would not fit. 167 | epoch_time.as_secs() as u32 168 | } 169 | 170 | impl Default for Rtc { 171 | fn default() -> Self { 172 | Self::new() 173 | } 174 | } 175 | 176 | // This is the state from which a fresh Rtc can be created. 177 | #[allow(clippy::derivable_impls)] 178 | impl Default for RtcState { 179 | fn default() -> Self { 180 | RtcState { 181 | // The load register is initialized to 0. 182 | lr: 0, 183 | offset: 0, 184 | // The match register is initialised to zero (not currently used). 185 | // TODO: Implement the match register functionality. 186 | mr: 0, 187 | // The interrupt mask is initialised as not set. 188 | imsc: 0, 189 | // The raw interrupt is initialised as not asserted. 190 | ris: 0, 191 | } 192 | } 193 | } 194 | 195 | impl Rtc { 196 | /// Creates a new `AMBA PL031 RTC` instance without any metric capabilities. The instance is 197 | /// created from the default state. 198 | pub fn new() -> Self { 199 | Self::from_state(&RtcState::default(), NoEvents) 200 | } 201 | } 202 | 203 | impl Rtc { 204 | /// Creates a new `AMBA PL031 RTC` instance from a given `state` and that is able to track 205 | /// events during operation using the passed `rtc_events` object. 206 | /// For creating the instance from a fresh state, [`with_events`](#method.with_events) or 207 | /// [`new`](#method.new) methods can be used. 208 | /// 209 | /// # Arguments 210 | /// * `state` - A reference to the state from which the `Rtc` is constructed. 211 | /// * `rtc_events` - The `RtcEvents` implementation used to track the occurrence 212 | /// of failure or missed events in the RTC operation. 213 | pub fn from_state(state: &RtcState, rtc_events: EV) -> Self { 214 | Rtc { 215 | lr: state.lr, 216 | offset: state.offset, 217 | mr: state.mr, 218 | imsc: state.imsc, 219 | ris: state.ris, 220 | // A struct implementing `RtcEvents` for tracking the occurrence of 221 | // significant events. 222 | events: rtc_events, 223 | } 224 | } 225 | 226 | /// Creates a new `AMBA PL031 RTC` instance that is able to track events during operation using 227 | /// the passed `rtc_events` object. The instance is created from the default state. 228 | /// 229 | /// # Arguments 230 | /// * `rtc_events` - The `RtcEvents` implementation used to track the occurrence 231 | /// of failure or missed events in the RTC operation. 232 | pub fn with_events(rtc_events: EV) -> Self { 233 | Self::from_state(&RtcState::default(), rtc_events) 234 | } 235 | 236 | /// Returns the state of the RTC. 237 | pub fn state(&self) -> RtcState { 238 | RtcState { 239 | lr: self.lr, 240 | offset: self.offset, 241 | mr: self.mr, 242 | imsc: self.imsc, 243 | ris: self.ris, 244 | } 245 | } 246 | 247 | /// Provides a reference to the RTC events object. 248 | pub fn events(&self) -> &EV { 249 | &self.events 250 | } 251 | 252 | fn get_rtc_value(&self) -> u32 { 253 | // The RTC value is the time + offset as per: 254 | // https://developer.arm.com/documentation/ddi0224/c/Functional-overview/RTC-functional-description/Update-block 255 | // 256 | // In the unlikely case of the value not fitting in an u32, we just set the time to 257 | // the current time on the host. 258 | let current_host_time = get_current_time(); 259 | u32::try_from( 260 | (current_host_time as i64) 261 | .checked_add(self.offset) 262 | .unwrap_or(current_host_time as i64), 263 | ) 264 | .unwrap_or(current_host_time) 265 | } 266 | 267 | /// Handles a write request from the driver at `offset` offset from the 268 | /// base register address. 269 | /// 270 | /// # Arguments 271 | /// * `offset` - The offset from the base register specifying 272 | /// the register to be written. 273 | /// * `data` - The little endian, 4 byte array to write to the register 274 | /// 275 | /// # Example 276 | /// 277 | /// You can see an example of how to use this function in the 278 | /// [`Example` section from `Rtc`](struct.Rtc.html#example). 279 | pub fn write(&mut self, offset: u16, data: &[u8; 4]) { 280 | let val = u32::from_le_bytes(*data); 281 | 282 | match offset { 283 | RTCMR => { 284 | // Set the match register. 285 | // TODO: Implement the match register functionality. 286 | self.mr = val; 287 | } 288 | RTCLR => { 289 | // The guest can make adjustments to its time by writing to 290 | // this register. When these adjustments happen, we calculate the 291 | // offset as the difference between the LR value and the host time. 292 | // This offset is later used to calculate the RTC value (see 293 | // `get_rtc_value`). 294 | self.lr = val; 295 | // Both lr & offset are u32, hence the following 296 | // conversions are safe, and the result fits in an i64. 297 | self.offset = self.lr as i64 - get_current_time() as i64; 298 | } 299 | RTCCR => { 300 | // Writing 1 to the control register resets the RTC value, 301 | // which means both the load register and the offset are reset. 302 | if val == 1 { 303 | self.lr = 0; 304 | self.offset = 0; 305 | } 306 | } 307 | RTCIMSC => { 308 | // Set or clear the interrupt mask. 309 | self.imsc = val & 1; 310 | } 311 | RTCICR => { 312 | // Writing 1 clears the interrupt; however, since the match 313 | // register is unimplemented, this should never be necessary. 314 | self.ris &= !val; 315 | } 316 | _ => { 317 | // RTCDR, RTCRIS, and RTCMIS are read-only, so writes to these 318 | // registers or to an invalid offset are ignored; however, 319 | // We increment the invalid_write() method of the events struct. 320 | self.events.invalid_write(); 321 | } 322 | }; 323 | } 324 | 325 | /// Handles a read request from the driver at `offset` offset from the 326 | /// base register address. 327 | /// 328 | /// # Arguments 329 | /// * `offset` - The offset from the base register specifying 330 | /// the register to be read. 331 | /// * `data` - The little-endian, 4 byte array storing the read value. 332 | /// 333 | /// # Example 334 | /// 335 | /// You can see an example of how to use this function in the 336 | /// [`Example` section from `Rtc`](struct.Rtc.html#example). 337 | pub fn read(&mut self, offset: u16, data: &mut [u8; 4]) { 338 | let v = if (AMBA_ID_LOW..=AMBA_ID_HIGH).contains(&offset) { 339 | let index = ((offset - AMBA_ID_LOW) >> 2) as usize; 340 | u32::from(AMBA_IDS[index]) 341 | } else { 342 | match offset { 343 | RTCDR => self.get_rtc_value(), 344 | RTCMR => { 345 | // Read the match register. 346 | // TODO: Implement the match register functionality. 347 | self.mr 348 | } 349 | RTCLR => self.lr, 350 | RTCCR => 1, // RTC is always enabled. 351 | RTCIMSC => self.imsc, 352 | RTCRIS => self.ris, 353 | RTCMIS => self.ris & self.imsc, 354 | _ => { 355 | // RTCICR is write only. For reads of this register or 356 | // an invalid offset, call the invalid_read method of the 357 | // events struct and return. 358 | self.events.invalid_read(); 359 | return; 360 | } 361 | } 362 | }; 363 | 364 | *data = v.to_le_bytes(); 365 | } 366 | } 367 | 368 | #[cfg(test)] 369 | mod tests { 370 | use super::*; 371 | 372 | use std::sync::atomic::AtomicU64; 373 | use std::sync::Arc; 374 | use std::thread; 375 | use std::time::Duration; 376 | 377 | use vmm_sys_util::metric::Metric; 378 | 379 | #[derive(Default)] 380 | struct ExampleRtcMetrics { 381 | invalid_read_count: AtomicU64, 382 | invalid_write_count: AtomicU64, 383 | } 384 | 385 | impl RtcEvents for ExampleRtcMetrics { 386 | fn invalid_read(&self) { 387 | self.invalid_read_count.inc(); 388 | // We can also log a message here, or as part of any of the other methods. 389 | } 390 | 391 | fn invalid_write(&self) { 392 | self.invalid_write_count.inc(); 393 | } 394 | } 395 | 396 | #[test] 397 | fn test_regression_year_1970() { 398 | // This is a regression test for: https://github.com/rust-vmm/vm-superio/issues/47. 399 | // The problem is that the time in the guest would show up as in the 1970s. 400 | let mut rtc = Rtc::new(); 401 | let expected_time = get_current_time(); 402 | 403 | let mut actual_time = [0u8; 4]; 404 | rtc.read(RTCDR, &mut actual_time); 405 | // Check that the difference between the current time, and the time read from the 406 | // RTC device is never bigger than one second. This should hold true irrespective of 407 | // scheduling. 408 | assert!(u32::from_le_bytes(actual_time) - expected_time <= 1); 409 | } 410 | 411 | #[test] 412 | fn test_data_register() { 413 | // Verify we can read the Data Register, but not write to it, 414 | // and that the Data Register RTC count increments over time. 415 | // This also tests that the invalid write metric is incremented for 416 | // writes to RTCDR. 417 | let metrics = Arc::new(ExampleRtcMetrics::default()); 418 | let mut rtc = Rtc::with_events(metrics); 419 | let mut data = [0; 4]; 420 | 421 | // Check metrics are equal to 0 at the beginning. 422 | assert_eq!(rtc.events.invalid_read_count.count(), 0); 423 | assert_eq!(rtc.events.invalid_write_count.count(), 0); 424 | 425 | // Read the data register. 426 | rtc.read(RTCDR, &mut data); 427 | let first_read = u32::from_le_bytes(data); 428 | 429 | // Sleep for 1.5 seconds to let the counter tick. 430 | let delay = Duration::from_millis(1500); 431 | thread::sleep(delay); 432 | 433 | // Read the data register again. 434 | rtc.read(RTCDR, &mut data); 435 | let second_read = u32::from_le_bytes(data); 436 | 437 | // The second time should be greater than the first 438 | assert!(second_read > first_read); 439 | 440 | // Sleep for 1.5 seconds to let the counter tick. 441 | let delay = Duration::from_millis(1500); 442 | thread::sleep(delay); 443 | 444 | // Writing the data register should have no effect. 445 | data = 0u32.to_le_bytes(); 446 | rtc.write(RTCDR, &data); 447 | 448 | // Invalid write should increment. All others should not change. 449 | assert_eq!(rtc.events.invalid_read_count.count(), 0); 450 | assert_eq!(rtc.events.invalid_write_count.count(), 1); 451 | 452 | // Read the data register again. 453 | rtc.read(RTCDR, &mut data); 454 | let third_read = u32::from_le_bytes(data); 455 | 456 | // The third time should be greater than the second. 457 | assert!(third_read > second_read); 458 | 459 | // Confirm metrics are unchanged. 460 | assert_eq!(rtc.events.invalid_read_count.count(), 0); 461 | assert_eq!(rtc.events.invalid_write_count.count(), 1); 462 | } 463 | 464 | #[test] 465 | fn test_match_register() { 466 | // Test reading and writing to the match register. 467 | // TODO: Implement the alarm functionality and confirm an interrupt 468 | // is raised when the match register is set. 469 | let mut rtc = Rtc::new(); 470 | let mut data: [u8; 4]; 471 | 472 | // Write to the match register. 473 | data = 123u32.to_le_bytes(); 474 | rtc.write(RTCMR, &data); 475 | 476 | // Read the value back out of the match register and confirm it was 477 | // correctly written. 478 | rtc.read(RTCMR, &mut data); 479 | assert_eq!(123, u32::from_le_bytes(data)); 480 | } 481 | 482 | #[test] 483 | fn test_load_register() { 484 | // Read and write to the load register to confirm we can both 485 | // set the RTC value forward and backward. 486 | // This also tests the default Rtc constructor. 487 | let mut rtc: Rtc = Default::default(); 488 | let mut data = [0; 4]; 489 | 490 | // Get the RTC value with a load register of 0 (the initial value). 491 | rtc.read(RTCDR, &mut data); 492 | let old_val = u32::from_le_bytes(data); 493 | 494 | // Increment LR and verify that the value was updated. 495 | let lr = get_current_time() + 100; 496 | data = lr.to_le_bytes(); 497 | rtc.write(RTCLR, &data); 498 | 499 | // Read the load register and verify it matches the value just loaded. 500 | rtc.read(RTCLR, &mut data); 501 | assert_eq!(lr, u32::from_le_bytes(data)); 502 | 503 | // Read the data register and verify it matches the value just loaded. 504 | // Note that this assumes less than 1 second has elapsed between 505 | // setting RTCLR and this read (based on the RTC counter 506 | // tick rate being 1Hz). 507 | rtc.read(RTCDR, &mut data); 508 | assert_eq!(lr, u32::from_le_bytes(data)); 509 | 510 | // Confirm that the new RTC value is greater than the old 511 | let new_val = u32::from_le_bytes(data); 512 | assert!(new_val > old_val); 513 | 514 | // Set the LR in the past, and check that the RTC value is updated. 515 | let lr = get_current_time() - 100; 516 | data = lr.to_le_bytes(); 517 | rtc.write(RTCLR, &data); 518 | 519 | rtc.read(RTCDR, &mut data); 520 | let rtc_value = u32::from_le_bytes(data); 521 | assert!(rtc_value < get_current_time()); 522 | 523 | // Checking that setting the maximum possible value for the LR does 524 | // not cause overflows. 525 | let lr = u32::MAX; 526 | data = lr.to_le_bytes(); 527 | rtc.write(RTCLR, &data); 528 | rtc.read(RTCDR, &mut data); 529 | assert!(rtc.offset > -(u32::MAX as i64) && rtc.offset < u32::MAX as i64); 530 | // We're checking that this is not 0 because that's the value we're 531 | // setting in case the DR value does not fit in an u32. 532 | assert_ne!(u32::from_le_bytes(data), 0); 533 | 534 | // Reset the RTC value to 0 and confirm it was reset. 535 | let lr = 0u32; 536 | data = lr.to_le_bytes(); 537 | rtc.write(RTCLR, &data); 538 | 539 | // Read the data register and verify it has been reset. 540 | rtc.read(RTCDR, &mut data); 541 | assert_eq!(lr, u32::from_le_bytes(data)); 542 | } 543 | 544 | #[test] 545 | fn test_rtc_value_overflow() { 546 | // Verify that the RTC value will wrap on overflow instead of panic. 547 | let mut rtc = Rtc::new(); 548 | let mut data: [u8; 4]; 549 | 550 | // Write u32::MAX to the load register 551 | let lr_max = u32::MAX; 552 | data = lr_max.to_le_bytes(); 553 | rtc.write(RTCLR, &data); 554 | 555 | // Read the load register and verify it matches the value just loaded. 556 | rtc.read(RTCLR, &mut data); 557 | assert_eq!(lr_max, u32::from_le_bytes(data)); 558 | 559 | // Read the data register and verify it matches the value just loaded. 560 | // Note that this assumes less than 1 second has elapsed between 561 | // setting RTCLR and this read (based on the RTC counter 562 | // tick rate being 1Hz). 563 | rtc.read(RTCDR, &mut data); 564 | assert_eq!(lr_max, u32::from_le_bytes(data)); 565 | 566 | // Sleep for 1.5 seconds to let the counter tick. This should 567 | // cause the RTC value to overflow and wrap. 568 | let delay = Duration::from_millis(1500); 569 | thread::sleep(delay); 570 | 571 | // Read the data register and verify it has wrapped around. 572 | rtc.read(RTCDR, &mut data); 573 | assert!(lr_max > u32::from_le_bytes(data)); 574 | } 575 | 576 | #[test] 577 | fn test_interrupt_mask_set_clear_register() { 578 | // Test setting and clearing the interrupt mask bit. 579 | let mut rtc = Rtc::new(); 580 | let mut data: [u8; 4]; 581 | 582 | // Manually set the raw interrupt. 583 | rtc.ris = 1; 584 | 585 | // Set the mask bit. 586 | data = 1u32.to_le_bytes(); 587 | rtc.write(RTCIMSC, &data); 588 | 589 | // Confirm the mask bit is set. 590 | rtc.read(RTCIMSC, &mut data); 591 | assert_eq!(1, u32::from_le_bytes(data)); 592 | 593 | // Confirm the raw and masked interrupts are set. 594 | rtc.read(RTCRIS, &mut data); 595 | assert_eq!(1, u32::from_le_bytes(data)); 596 | rtc.read(RTCMIS, &mut data); 597 | assert_eq!(1, u32::from_le_bytes(data)); 598 | 599 | // Clear the mask bit. 600 | data = 0u32.to_le_bytes(); 601 | rtc.write(RTCIMSC, &data); 602 | 603 | // Confirm the mask bit is cleared. 604 | rtc.read(RTCIMSC, &mut data); 605 | assert_eq!(0, u32::from_le_bytes(data)); 606 | 607 | // Confirm the raw interrupt is set and the masked 608 | // interrupt is not. 609 | rtc.read(RTCRIS, &mut data); 610 | assert_eq!(1, u32::from_le_bytes(data)); 611 | rtc.read(RTCMIS, &mut data); 612 | assert_eq!(0, u32::from_le_bytes(data)); 613 | } 614 | 615 | #[test] 616 | fn test_interrupt_clear_register() { 617 | // Test clearing the interrupt. This also tests 618 | // that the invalid read and write metrics are incremented. 619 | let metrics = Arc::new(ExampleRtcMetrics::default()); 620 | let mut rtc = Rtc::with_events(metrics); 621 | let mut data = [0; 4]; 622 | 623 | // Check metrics are equal to 0 at the beginning. 624 | assert_eq!(rtc.events.invalid_read_count.count(), 0); 625 | assert_eq!(rtc.events.invalid_write_count.count(), 0); 626 | 627 | // Manually set the raw interrupt and interrupt mask. 628 | rtc.ris = 1; 629 | rtc.imsc = 1; 630 | 631 | // Confirm the raw and masked interrupts are set. 632 | rtc.read(RTCRIS, &mut data); 633 | assert_eq!(1, u32::from_le_bytes(data)); 634 | rtc.read(RTCMIS, &mut data); 635 | assert_eq!(1, u32::from_le_bytes(data)); 636 | 637 | // Write to the interrupt clear register. 638 | data = 1u32.to_le_bytes(); 639 | rtc.write(RTCICR, &data); 640 | 641 | // Metrics should not change. 642 | assert_eq!(rtc.events.invalid_read_count.count(), 0); 643 | assert_eq!(rtc.events.invalid_write_count.count(), 0); 644 | 645 | // Confirm the raw and masked interrupts are cleared. 646 | rtc.read(RTCRIS, &mut data); 647 | assert_eq!(0, u32::from_le_bytes(data)); 648 | rtc.read(RTCMIS, &mut data); 649 | assert_eq!(0, u32::from_le_bytes(data)); 650 | 651 | // Confirm reading from RTCICR has no effect. 652 | data = 123u32.to_le_bytes(); 653 | rtc.read(RTCICR, &mut data); 654 | let v = u32::from_le_bytes(data); 655 | assert_eq!(v, 123); 656 | 657 | // Invalid read should increment. All others should not change. 658 | assert_eq!(rtc.events.invalid_read_count.count(), 1); 659 | assert_eq!(rtc.events.invalid_write_count.count(), 0); 660 | } 661 | 662 | #[test] 663 | fn test_control_register() { 664 | // Writing 1 to the Control Register should reset the RTC value. 665 | // Writing 0 should have no effect. 666 | let mut rtc = Rtc::new(); 667 | let mut data: [u8; 4]; 668 | 669 | // Let's move the guest time in the future. 670 | let lr = get_current_time() + 100; 671 | data = lr.to_le_bytes(); 672 | rtc.write(RTCLR, &data); 673 | 674 | // Get the RTC value. 675 | rtc.read(RTCDR, &mut data); 676 | let old_val = u32::from_le_bytes(data); 677 | 678 | // Reset the RTC value by writing 1 to RTCCR. 679 | data = 1u32.to_le_bytes(); 680 | rtc.write(RTCCR, &data); 681 | 682 | // Get the RTC value. 683 | rtc.read(RTCDR, &mut data); 684 | let new_val = u32::from_le_bytes(data); 685 | 686 | // The new value should be less than the old value. 687 | assert!(new_val < old_val); 688 | 689 | // Attempt to clear the control register should have no effect on 690 | // either the RTCCR value or the RTC value. 691 | data = 0u32.to_le_bytes(); 692 | rtc.write(RTCCR, &data); 693 | 694 | // Read the RTCCR value and confirm it's still 1. 695 | rtc.read(RTCCR, &mut data); 696 | let v = u32::from_le_bytes(data); 697 | assert_eq!(v, 1); 698 | 699 | // Sleep for 1.5 seconds to let the counter tick. 700 | let delay = Duration::from_millis(1500); 701 | thread::sleep(delay); 702 | 703 | // Read the RTC value and confirm it has incremented. 704 | let old_val = new_val; 705 | rtc.read(RTCDR, &mut data); 706 | let new_val = u32::from_le_bytes(data); 707 | assert!(new_val > old_val); 708 | } 709 | 710 | #[test] 711 | fn test_raw_interrupt_status_register() { 712 | // Writing to the Raw Interrupt Status Register should have no effect, 713 | // and reading should return the value of RTCRIS. 714 | let mut rtc = Rtc::new(); 715 | let mut data = [0; 4]; 716 | 717 | // Set the raw interrupt for testing. 718 | rtc.ris = 1u32; 719 | 720 | // Read the current value of RTCRIS. 721 | rtc.read(RTCRIS, &mut data); 722 | assert_eq!(u32::from_le_bytes(data), 1); 723 | 724 | // Attempt to write to RTCRIS. 725 | data = 0u32.to_le_bytes(); 726 | rtc.write(RTCRIS, &data); 727 | 728 | // Read the current value of RTCRIS and confirm it's unchanged. 729 | rtc.read(RTCRIS, &mut data); 730 | assert_eq!(u32::from_le_bytes(data), 1); 731 | } 732 | 733 | #[test] 734 | fn test_mask_interrupt_status_register() { 735 | // Writing to the Masked Interrupt Status Register should have no effect, 736 | // and reading should return the value of RTCRIS & RTCIMSC. 737 | let mut rtc = Rtc::new(); 738 | let mut data = [0; 4]; 739 | 740 | // Set the raw interrupt for testing. 741 | rtc.ris = 1u32; 742 | 743 | // Confirm the mask bit is not set. 744 | rtc.read(RTCIMSC, &mut data); 745 | assert_eq!(0, u32::from_le_bytes(data)); 746 | 747 | // Read the current value of RTCMIS. Since the interrupt mask is 748 | // initially 0, the interrupt should not be masked and reading RTCMIS 749 | // should return 0. 750 | rtc.read(RTCMIS, &mut data); 751 | assert_eq!(u32::from_le_bytes(data), 0); 752 | 753 | // Set the mask bit. 754 | data = 1u32.to_le_bytes(); 755 | rtc.write(RTCIMSC, &data); 756 | 757 | // Read the current value of RTCMIS. Since the interrupt mask is 758 | // now set, the masked interrupt should be set. 759 | rtc.read(RTCMIS, &mut data); 760 | assert_eq!(u32::from_le_bytes(data), 1); 761 | 762 | // Attempt to write to RTCMIS should have no effect. 763 | data = 0u32.to_le_bytes(); 764 | rtc.write(RTCMIS, &data); 765 | 766 | // Read the current value of RTCMIS and confirm it's unchanged. 767 | rtc.read(RTCMIS, &mut data); 768 | assert_eq!(u32::from_le_bytes(data), 1); 769 | } 770 | 771 | #[test] 772 | fn test_read_only_register_addresses() { 773 | let mut rtc = Rtc::new(); 774 | let mut data = [0; 4]; 775 | 776 | // Read the current value of AMBA_ID_LOW. 777 | rtc.read(AMBA_ID_LOW, &mut data); 778 | assert_eq!(data[0], AMBA_IDS[0]); 779 | 780 | // Attempts to write to read-only registers (AMBA_ID_LOW in this case) 781 | // should have no effect. 782 | data = 123u32.to_le_bytes(); 783 | rtc.write(AMBA_ID_LOW, &data); 784 | 785 | // Reread the current value of AMBA_ID_LOW and confirm it's unchanged. 786 | rtc.read(AMBA_ID_LOW, &mut data); 787 | assert_eq!(data[0], AMBA_IDS[0]); 788 | 789 | // Reading from the AMBA_ID registers should succeed. 790 | // Becuase we compute the index of the AMBA_IDS array by a logical bit 791 | // shift of (offset - AMBA_ID_LOW) >> 2, we want to make sure that 792 | // we correctly align down to a 4-byte register boundary, and that we 793 | // don't overflow (we shouldn't, since offset provided to read() 794 | // is unsigned). 795 | 796 | // Verify that we can read from AMBA_ID_LOW and that the logical shift 797 | // doesn't overflow. 798 | data = [0; 4]; 799 | rtc.read(AMBA_ID_LOW, &mut data); 800 | assert_eq!(data[0], AMBA_IDS[0]); 801 | 802 | // Verify that attempts to read from AMBA_ID_LOW + 5 align down to 803 | // AMBA_ID_LOW + 4, corresponding to AMBA_IDS[1]. 804 | data = [0; 4]; 805 | rtc.read(AMBA_ID_LOW + 5, &mut data); 806 | assert_eq!(data[0], AMBA_IDS[1]); 807 | } 808 | 809 | #[test] 810 | fn test_invalid_write_offset() { 811 | // Test that writing to an invalid register offset has no effect 812 | // on the RTC value (as read from the data register), and confirm 813 | // the invalid write metric increments. 814 | let metrics = Arc::new(ExampleRtcMetrics::default()); 815 | let mut rtc = Rtc::with_events(metrics); 816 | let mut data = [0; 4]; 817 | 818 | // Check metrics are equal to 0 at the beginning. 819 | assert_eq!(rtc.events.invalid_read_count.count(), 0); 820 | assert_eq!(rtc.events.invalid_write_count.count(), 0); 821 | 822 | // First test: Write to an address outside the expected range of 823 | // register memory. 824 | 825 | // Read the data register. 826 | rtc.read(RTCDR, &mut data); 827 | let first_read = u32::from_le_bytes(data); 828 | 829 | // Attempt to write to an address outside the expected range of 830 | // register memory. 831 | data = 123u32.to_le_bytes(); 832 | rtc.write(AMBA_ID_HIGH + 4, &data); 833 | 834 | // Invalid write should increment. All others should not change. 835 | assert_eq!(rtc.events.invalid_read_count.count(), 0); 836 | assert_eq!(rtc.events.invalid_write_count.count(), 1); 837 | 838 | // Read the data register again. 839 | rtc.read(RTCDR, &mut data); 840 | let second_read = u32::from_le_bytes(data); 841 | 842 | // RTCDR should be unchanged. 843 | // Note that this assumes less than 1 second has elapsed between 844 | // the first and second read of RTCDR (based on the RTC counter 845 | // tick rate being 1Hz). 846 | assert_eq!(second_read, first_read); 847 | 848 | // Second test: Attempt to write to a register address similar to the 849 | // load register, but not actually valid. 850 | 851 | // Read the data register. 852 | rtc.read(RTCDR, &mut data); 853 | let first_read = u32::from_le_bytes(data); 854 | 855 | // Attempt to write to an invalid register address close to the load 856 | // register's address. 857 | data = 123u32.to_le_bytes(); 858 | rtc.write(RTCLR + 1, &data); 859 | 860 | // Invalid write should increment again. All others should not change. 861 | assert_eq!(rtc.events.invalid_read_count.count(), 0); 862 | assert_eq!(rtc.events.invalid_write_count.count(), 2); 863 | 864 | // Read the data register again. 865 | rtc.read(RTCDR, &mut data); 866 | let second_read = u32::from_le_bytes(data); 867 | 868 | // RTCDR should be unchanged 869 | // Note that this assumes less than 1 second has elapsed between 870 | // the first and second read of RTCDR (based on the RTC counter 871 | // tick rate being 1Hz). 872 | assert_eq!(second_read, first_read); 873 | 874 | // Confirm neither metric has changed. 875 | assert_eq!(rtc.events.invalid_read_count.count(), 0); 876 | assert_eq!(rtc.events.invalid_write_count.count(), 2); 877 | } 878 | 879 | #[test] 880 | fn test_invalid_read_offset() { 881 | // Test that reading from an invalid register offset has no effect, 882 | // and confirm the invalid read metric increments. 883 | let metrics = Arc::new(ExampleRtcMetrics::default()); 884 | let mut rtc = Rtc::with_events(metrics); 885 | let mut data: [u8; 4]; 886 | 887 | // Check metrics are equal to 0 at the beginning. 888 | assert_eq!(rtc.events.invalid_read_count.count(), 0); 889 | assert_eq!(rtc.events.invalid_write_count.count(), 0); 890 | 891 | // Reading from a non-existent register should have no effect. 892 | data = 123u32.to_le_bytes(); 893 | rtc.read(AMBA_ID_HIGH + 4, &mut data); 894 | assert_eq!(123, u32::from_le_bytes(data)); 895 | 896 | // Invalid read should increment. All others should not change. 897 | assert_eq!(rtc.events.invalid_read_count.count(), 1); 898 | assert_eq!(rtc.events.invalid_write_count.count(), 0); 899 | 900 | // Just to prove that AMBA_ID_HIGH + 4 doesn't contain 123... 901 | data = 321u32.to_le_bytes(); 902 | rtc.read(AMBA_ID_HIGH + 4, &mut data); 903 | assert_eq!(321, u32::from_le_bytes(data)); 904 | 905 | // Invalid read should increment again. All others should not change. 906 | assert_eq!(rtc.events.invalid_read_count.count(), 2); 907 | assert_eq!(rtc.events.invalid_write_count.count(), 0); 908 | } 909 | 910 | #[test] 911 | fn test_state() { 912 | let metrics = Arc::new(ExampleRtcMetrics::default()); 913 | let mut rtc = Rtc::with_events(metrics); 914 | let mut data = [0; 4]; 915 | 916 | // Get the RTC value with a load register of 0 (the initial value). 917 | rtc.read(RTCDR, &mut data); 918 | let first_read = u32::from_le_bytes(data); 919 | 920 | // Increment LR and verify that the value was updated. 921 | let lr = get_current_time() + 100; 922 | data = lr.to_le_bytes(); 923 | rtc.write(RTCLR, &data); 924 | 925 | let state = rtc.state(); 926 | rtc.read(RTCLR, &mut data); 927 | assert_eq!(state.lr.to_le_bytes(), data); 928 | 929 | // Do an invalid `write` in order to increment a metric. 930 | let mut data2 = 123u32.to_le_bytes(); 931 | rtc.write(AMBA_ID_HIGH + 4, &data2); 932 | assert_eq!(rtc.events.invalid_write_count.count(), 1); 933 | 934 | let metrics = Arc::new(ExampleRtcMetrics::default()); 935 | let mut rtc_from_state = Rtc::from_state(&state, metrics.clone()); 936 | let state_after_restore = rtc_from_state.state(); 937 | 938 | // Check that the old and the new state are identical. 939 | assert_eq!(state, state_after_restore); 940 | 941 | // Read the data register again. 942 | rtc.read(RTCDR, &mut data); 943 | let second_read = u32::from_le_bytes(data); 944 | // The RTC values should be different. 945 | assert!(second_read > first_read); 946 | 947 | // Reading from the LR register should return the same value as before saving the state. 948 | rtc_from_state.read(RTCLR, &mut data2); 949 | assert_eq!(data, data2); 950 | 951 | // Check that the restored `Rtc` doesn't keep the state of the old `metrics` object. 952 | assert_eq!(rtc_from_state.events.invalid_write_count.count(), 0); 953 | 954 | // Let's increment again a metric, and this time save the state of events as well (separate 955 | // from the base state). 956 | // Do an invalid `write` in order to increment a metric. 957 | let data3 = 123u32.to_le_bytes(); 958 | rtc_from_state.write(AMBA_ID_HIGH + 4, &data3); 959 | assert_eq!(rtc_from_state.events.invalid_write_count.count(), 1); 960 | 961 | let state2 = rtc_from_state.state(); 962 | // Mimic saving the metrics for the sake of the example. 963 | let saved_metrics = metrics; 964 | let rtc = Rtc::from_state(&state2, saved_metrics); 965 | 966 | // Check that the restored `Rtc` keeps the state of the old `metrics` object. 967 | assert_eq!(rtc.events.invalid_write_count.count(), 1); 968 | } 969 | 970 | #[test] 971 | fn test_overflow_offset() { 972 | // Test that an invalid offset (too big) does not cause an overflow. 973 | let rtc_state = RtcState { 974 | lr: 65535, 975 | offset: 9223372036854710636, 976 | mr: 0, 977 | imsc: 0, 978 | ris: 0, 979 | }; 980 | let mut rtc = Rtc::from_state(&rtc_state, NoEvents); 981 | let mut data = [0u8; 4]; 982 | rtc.read(RTCDR, &mut data); 983 | } 984 | } 985 | -------------------------------------------------------------------------------- /vm-superio/src/serial.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // 3 | // Portions Copyright 2017 The Chromium OS Authors. All rights reserved. 4 | // Use of this source code is governed by a BSD-style license that can be 5 | // found in the THIRD-PARTY file. 6 | // 7 | // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 8 | 9 | //! Provides emulation for Linux serial console. 10 | //! 11 | //! This is done by emulating an UART serial port. 12 | 13 | use std::collections::VecDeque; 14 | use std::error::Error as StdError; 15 | use std::fmt; 16 | use std::io::{self, Write}; 17 | use std::result::Result; 18 | use std::sync::Arc; 19 | 20 | use crate::Trigger; 21 | 22 | // Register offsets. 23 | // Receiver and Transmitter registers offset, depending on the I/O 24 | // access type: write -> THR, read -> RBR. 25 | const DATA_OFFSET: u8 = 0; 26 | const IER_OFFSET: u8 = 1; 27 | const IIR_OFFSET: u8 = 2; 28 | const LCR_OFFSET: u8 = 3; 29 | const MCR_OFFSET: u8 = 4; 30 | const LSR_OFFSET: u8 = 5; 31 | const MSR_OFFSET: u8 = 6; 32 | const SCR_OFFSET: u8 = 7; 33 | const DLAB_LOW_OFFSET: u8 = 0; 34 | const DLAB_HIGH_OFFSET: u8 = 1; 35 | 36 | const FIFO_SIZE: usize = 0x40; 37 | 38 | // Received Data Available interrupt - for letting the driver know that 39 | // there is some pending data to be processed. 40 | const IER_RDA_BIT: u8 = 0b0000_0001; 41 | // Transmitter Holding Register Empty interrupt - for letting the driver 42 | // know that the entire content of the output buffer was sent. 43 | const IER_THR_EMPTY_BIT: u8 = 0b0000_0010; 44 | // The interrupts that are available on 16550 and older models. 45 | const IER_UART_VALID_BITS: u8 = 0b0000_1111; 46 | 47 | //FIFO enabled. 48 | const IIR_FIFO_BITS: u8 = 0b1100_0000; 49 | const IIR_NONE_BIT: u8 = 0b0000_0001; 50 | const IIR_THR_EMPTY_BIT: u8 = 0b0000_0010; 51 | const IIR_RDA_BIT: u8 = 0b0000_0100; 52 | 53 | const LCR_DLAB_BIT: u8 = 0b1000_0000; 54 | 55 | const LSR_DATA_READY_BIT: u8 = 0b0000_0001; 56 | // These two bits help the driver know if the device is ready to accept 57 | // another character. 58 | // THR is empty. 59 | const LSR_EMPTY_THR_BIT: u8 = 0b0010_0000; 60 | // The shift register, which takes a byte from THR and breaks it in bits 61 | // for sending them on the line, is empty. 62 | const LSR_IDLE_BIT: u8 = 0b0100_0000; 63 | 64 | // The following five MCR bits allow direct manipulation of the device and 65 | // are available on 16550 and older models. 66 | // Data Terminal Ready. 67 | const MCR_DTR_BIT: u8 = 0b0000_0001; 68 | // Request To Send. 69 | const MCR_RTS_BIT: u8 = 0b0000_0010; 70 | // Auxiliary Output 1. 71 | const MCR_OUT1_BIT: u8 = 0b0000_0100; 72 | // Auxiliary Output 2. 73 | const MCR_OUT2_BIT: u8 = 0b0000_1000; 74 | // Loopback Mode. 75 | const MCR_LOOP_BIT: u8 = 0b0001_0000; 76 | 77 | // Clear To Send. 78 | const MSR_CTS_BIT: u8 = 0b0001_0000; 79 | // Data Set Ready. 80 | const MSR_DSR_BIT: u8 = 0b0010_0000; 81 | // Ring Indicator. 82 | const MSR_RI_BIT: u8 = 0b0100_0000; 83 | // Data Carrier Detect. 84 | const MSR_DCD_BIT: u8 = 0b1000_0000; 85 | 86 | // The following values can be used to set the baud rate to 9600 bps. 87 | const DEFAULT_BAUD_DIVISOR_HIGH: u8 = 0x00; 88 | const DEFAULT_BAUD_DIVISOR_LOW: u8 = 0x0C; 89 | 90 | // No interrupts enabled. 91 | const DEFAULT_INTERRUPT_ENABLE: u8 = 0x00; 92 | // No pending interrupt. 93 | const DEFAULT_INTERRUPT_IDENTIFICATION: u8 = IIR_NONE_BIT; 94 | // We're setting the default to include LSR_EMPTY_THR_BIT and LSR_IDLE_BIT 95 | // and never update those bits because we're working with a virtual device, 96 | // hence we should always be ready to receive more data. 97 | const DEFAULT_LINE_STATUS: u8 = LSR_EMPTY_THR_BIT | LSR_IDLE_BIT; 98 | // 8 bits word length. 99 | const DEFAULT_LINE_CONTROL: u8 = 0b0000_0011; 100 | // Most UARTs need Auxiliary Output 2 set to '1' to enable interrupts. 101 | const DEFAULT_MODEM_CONTROL: u8 = MCR_OUT2_BIT; 102 | const DEFAULT_MODEM_STATUS: u8 = MSR_DSR_BIT | MSR_CTS_BIT | MSR_DCD_BIT; 103 | const DEFAULT_SCRATCH: u8 = 0x00; 104 | 105 | /// Defines a series of callbacks that are invoked in response to the occurrence of specific 106 | /// events as part of the serial emulation logic (for example, when the driver reads data). The 107 | /// methods below can be implemented by a backend that keeps track of such events by incrementing 108 | /// metrics, logging messages, or any other action. 109 | /// 110 | /// We're using a trait to avoid constraining the concrete characteristics of the backend in 111 | /// any way, enabling zero-cost abstractions and use case-specific implementations. 112 | // TODO: The events defined below are just some examples for now to validate the approach. If 113 | // things look good, we can move on to establishing the initial list. It's also worth mentioning 114 | // the methods can have extra parameters that provide additional information about the event. 115 | pub trait SerialEvents { 116 | /// The driver reads data from the input buffer. 117 | fn buffer_read(&self); 118 | /// The driver successfully wrote one byte to serial output. 119 | fn out_byte(&self); 120 | /// An error occurred while writing a byte to serial output resulting in a lost byte. 121 | fn tx_lost_byte(&self); 122 | /// This event can be used by the consumer to re-enable events coming from 123 | /// the serial input. 124 | fn in_buffer_empty(&self); 125 | } 126 | 127 | /// Provides a no-op implementation of `SerialEvents` which can be used in situations that 128 | /// do not require logging or otherwise doing anything in response to the events defined 129 | /// as part of `SerialEvents`. 130 | #[derive(Debug, Clone, Copy)] 131 | pub struct NoEvents; 132 | 133 | impl SerialEvents for NoEvents { 134 | fn buffer_read(&self) {} 135 | fn out_byte(&self) {} 136 | fn tx_lost_byte(&self) {} 137 | fn in_buffer_empty(&self) {} 138 | } 139 | 140 | impl SerialEvents for Arc { 141 | fn buffer_read(&self) { 142 | self.as_ref().buffer_read(); 143 | } 144 | 145 | fn out_byte(&self) { 146 | self.as_ref().out_byte(); 147 | } 148 | 149 | fn tx_lost_byte(&self) { 150 | self.as_ref().tx_lost_byte(); 151 | } 152 | 153 | fn in_buffer_empty(&self) { 154 | self.as_ref().in_buffer_empty(); 155 | } 156 | } 157 | 158 | /// The state of the Serial device. 159 | #[derive(Clone, Debug, Eq, PartialEq)] 160 | pub struct SerialState { 161 | /// Divisor Latch Low Byte 162 | pub baud_divisor_low: u8, 163 | /// Divisor Latch High Byte 164 | pub baud_divisor_high: u8, 165 | /// Interrupt Enable Register 166 | pub interrupt_enable: u8, 167 | /// Interrupt Identification Register 168 | pub interrupt_identification: u8, 169 | /// Line Control Register 170 | pub line_control: u8, 171 | /// Line Status Register 172 | pub line_status: u8, 173 | /// Modem Control Register 174 | pub modem_control: u8, 175 | /// Modem Status Register 176 | pub modem_status: u8, 177 | /// Scratch Register 178 | pub scratch: u8, 179 | /// Transmitter Holding Buffer/Receiver Buffer 180 | pub in_buffer: Vec, 181 | } 182 | 183 | impl Default for SerialState { 184 | fn default() -> Self { 185 | SerialState { 186 | baud_divisor_low: DEFAULT_BAUD_DIVISOR_LOW, 187 | baud_divisor_high: DEFAULT_BAUD_DIVISOR_HIGH, 188 | interrupt_enable: DEFAULT_INTERRUPT_ENABLE, 189 | interrupt_identification: DEFAULT_INTERRUPT_IDENTIFICATION, 190 | line_control: DEFAULT_LINE_CONTROL, 191 | line_status: DEFAULT_LINE_STATUS, 192 | modem_control: DEFAULT_MODEM_CONTROL, 193 | modem_status: DEFAULT_MODEM_STATUS, 194 | scratch: DEFAULT_SCRATCH, 195 | in_buffer: Vec::new(), 196 | } 197 | } 198 | } 199 | 200 | /// The serial console emulation is done by emulating a serial COM port. 201 | /// 202 | /// Each serial COM port (COM1-4) has an associated Port I/O address base and 203 | /// 12 registers mapped into 8 consecutive Port I/O locations (with the first 204 | /// one being the base). 205 | /// This structure emulates the registers that make sense for UART 16550 (and below) 206 | /// and helps in the interaction between the driver and device by using a 207 | /// [`Trigger`](../trait.Trigger.html) object for notifications. It also writes the 208 | /// guest's output to an `out` Write object. 209 | /// 210 | /// # Example 211 | /// 212 | /// ```rust 213 | /// # use std::io::{sink, Error, Result}; 214 | /// # use std::ops::Deref; 215 | /// # use vm_superio::Trigger; 216 | /// # use vm_superio::Serial; 217 | /// # use vmm_sys_util::eventfd::EventFd; 218 | /// 219 | /// struct EventFdTrigger(EventFd); 220 | /// impl Trigger for EventFdTrigger { 221 | /// type E = Error; 222 | /// 223 | /// fn trigger(&self) -> Result<()> { 224 | /// self.write(1) 225 | /// } 226 | /// } 227 | /// impl Deref for EventFdTrigger { 228 | /// type Target = EventFd; 229 | /// fn deref(&self) -> &Self::Target { 230 | /// &self.0 231 | /// } 232 | /// } 233 | /// impl EventFdTrigger { 234 | /// pub fn new(flag: i32) -> Self { 235 | /// EventFdTrigger(EventFd::new(flag).unwrap()) 236 | /// } 237 | /// pub fn try_clone(&self) -> Self { 238 | /// EventFdTrigger((**self).try_clone().unwrap()) 239 | /// } 240 | /// } 241 | /// 242 | /// let intr_evt = EventFdTrigger::new(libc::EFD_NONBLOCK); 243 | /// let mut serial = Serial::new(intr_evt.try_clone(), Vec::new()); 244 | /// // std::io::Sink can be used if user is not interested in guest's output. 245 | /// let serial_with_sink = Serial::new(intr_evt, sink()); 246 | /// 247 | /// // Write 0x01 to THR register. 248 | /// serial.write(0, 0x01).unwrap(); 249 | /// // Read from RBR register. 250 | /// let value = serial.read(0); 251 | /// 252 | /// // Send more bytes to the guest in one shot. 253 | /// let input = &[b'a', b'b', b'c']; 254 | /// // Before enqueuing bytes we first check if there is enough free space 255 | /// // in the FIFO. 256 | /// if serial.fifo_capacity() >= input.len() { 257 | /// serial.enqueue_raw_bytes(input).unwrap(); 258 | /// } 259 | /// ``` 260 | #[derive(Debug)] 261 | pub struct Serial { 262 | // Some UART registers. 263 | baud_divisor_low: u8, 264 | baud_divisor_high: u8, 265 | interrupt_enable: u8, 266 | interrupt_identification: u8, 267 | line_control: u8, 268 | line_status: u8, 269 | modem_control: u8, 270 | modem_status: u8, 271 | scratch: u8, 272 | // This is the buffer that is used for achieving the Receiver register 273 | // functionality in FIFO mode. Reading from RBR will return the oldest 274 | // unread byte from the RX FIFO. 275 | in_buffer: VecDeque, 276 | 277 | // Used for notifying the driver about some in/out events. 278 | interrupt_evt: T, 279 | events: EV, 280 | out: W, 281 | } 282 | 283 | /// Errors encountered while handling serial console operations. 284 | #[derive(Debug)] 285 | pub enum Error { 286 | /// Failed to trigger interrupt. 287 | Trigger(E), 288 | /// Couldn't write/flush to the given destination. 289 | IOError(io::Error), 290 | /// No space left in FIFO. 291 | FullFifo, 292 | } 293 | 294 | impl fmt::Display for Error { 295 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 296 | match self { 297 | Error::Trigger(e) => write!(f, "Failed to trigger interrupt: {e}"), 298 | Error::IOError(e) => write!(f, "Couldn't write/flush to the given destination: {e}"), 299 | Error::FullFifo => write!(f, "No space left in FIFO"), 300 | } 301 | } 302 | } 303 | 304 | impl StdError for Error {} 305 | 306 | impl Serial { 307 | /// Creates a new `Serial` instance which writes the guest's output to 308 | /// `out` and uses `trigger` object to notify the driver about new 309 | /// events. 310 | /// 311 | /// # Arguments 312 | /// * `trigger` - The Trigger object that will be used to notify the driver 313 | /// about events. 314 | /// * `out` - An object for writing guest's output to. In case the output 315 | /// is not of interest, 316 | /// [std::io::Sink](https://doc.rust-lang.org/std/io/struct.Sink.html) 317 | /// can be used here. 318 | /// 319 | /// # Example 320 | /// 321 | /// You can see an example of how to use this function in the 322 | /// [`Example` section from `Serial`](struct.Serial.html#example). 323 | pub fn new(trigger: T, out: W) -> Serial { 324 | Self::with_events(trigger, NoEvents, out) 325 | } 326 | } 327 | 328 | impl Serial { 329 | /// Creates a new `Serial` instance from a given `state`, which writes the guest's output to 330 | /// `out`, uses `trigger` object to notify the driver about new 331 | /// events, and invokes the `serial_evts` implementation of `SerialEvents` 332 | /// during operation. 333 | /// For creating the instance from a default state, [`with_events`](#method.with_events) method 334 | /// can be used. 335 | /// 336 | /// # Arguments 337 | /// * `state` - A reference to the state from which the `Serial` is constructed. 338 | /// * `trigger` - The `Trigger` object that will be used to notify the driver 339 | /// about events. 340 | /// * `serial_evts` - The `SerialEvents` implementation used to track the occurrence 341 | /// of significant events in the serial operation logic. 342 | /// * `out` - An object for writing guest's output to. In case the output 343 | /// is not of interest, 344 | /// [std::io::Sink](https://doc.rust-lang.org/std/io/struct.Sink.html) 345 | /// can be used here. 346 | pub fn from_state( 347 | state: &SerialState, 348 | trigger: T, 349 | serial_evts: EV, 350 | out: W, 351 | ) -> Result> { 352 | if state.in_buffer.len() > FIFO_SIZE { 353 | return Err(Error::FullFifo); 354 | } 355 | 356 | let mut serial = Serial { 357 | baud_divisor_low: state.baud_divisor_low, 358 | baud_divisor_high: state.baud_divisor_high, 359 | interrupt_enable: state.interrupt_enable, 360 | interrupt_identification: state.interrupt_identification, 361 | line_control: state.line_control, 362 | line_status: state.line_status, 363 | modem_control: state.modem_control, 364 | modem_status: state.modem_status, 365 | scratch: state.scratch, 366 | in_buffer: VecDeque::from(state.in_buffer.clone()), 367 | interrupt_evt: trigger, 368 | events: serial_evts, 369 | out, 370 | }; 371 | 372 | if serial.is_thr_interrupt_enabled() && serial.is_thr_interrupt_set() { 373 | serial.trigger_interrupt().map_err(Error::Trigger)?; 374 | } 375 | if serial.is_rda_interrupt_enabled() && serial.is_rda_interrupt_set() { 376 | serial.trigger_interrupt().map_err(Error::Trigger)?; 377 | } 378 | 379 | Ok(serial) 380 | } 381 | 382 | /// Creates a new `Serial` instance from the default state, which writes the guest's output to 383 | /// `out`, uses `trigger` object to notify the driver about new 384 | /// events, and invokes the `serial_evts` implementation of `SerialEvents` 385 | /// during operation. 386 | /// 387 | /// # Arguments 388 | /// * `trigger` - The `Trigger` object that will be used to notify the driver 389 | /// about events. 390 | /// * `serial_evts` - The `SerialEvents` implementation used to track the occurrence 391 | /// of significant events in the serial operation logic. 392 | /// * `out` - An object for writing guest's output to. In case the output 393 | /// is not of interest, 394 | /// [std::io::Sink](https://doc.rust-lang.org/std/io/struct.Sink.html) 395 | /// can be used here. 396 | pub fn with_events(trigger: T, serial_evts: EV, out: W) -> Self { 397 | // Safe because we are using the default state that has an appropriately size input buffer 398 | // and there are no pending interrupts to be triggered. 399 | Self::from_state(&SerialState::default(), trigger, serial_evts, out).unwrap() 400 | } 401 | 402 | /// Returns the state of the Serial. 403 | pub fn state(&self) -> SerialState { 404 | SerialState { 405 | baud_divisor_low: self.baud_divisor_low, 406 | baud_divisor_high: self.baud_divisor_high, 407 | interrupt_enable: self.interrupt_enable, 408 | interrupt_identification: self.interrupt_identification, 409 | line_control: self.line_control, 410 | line_status: self.line_status, 411 | modem_control: self.modem_control, 412 | modem_status: self.modem_status, 413 | scratch: self.scratch, 414 | in_buffer: Vec::from(self.in_buffer.clone()), 415 | } 416 | } 417 | 418 | /// Gets a reference to the output Write object 419 | /// 420 | /// ```rust 421 | /// # use vm_superio::Trigger; 422 | /// # use vm_superio::serial::Serial; 423 | /// # struct DummyTrigger; 424 | /// # impl Trigger for DummyTrigger { 425 | /// # type E = (); 426 | /// # fn trigger(&self) -> Result<(), ()> { Ok(()) } 427 | /// # } 428 | /// const DATA_OFFSET: u8 = 0; 429 | /// 430 | /// let output = Vec::new(); 431 | /// let mut serial = Serial::new(DummyTrigger, output); 432 | /// serial.write(DATA_OFFSET, 0x66).unwrap(); 433 | /// assert_eq!(serial.writer().first().copied(), Some(0x66)); 434 | /// ``` 435 | pub fn writer(&self) -> &W { 436 | &self.out 437 | } 438 | 439 | /// Gets a mutable reference to the output Write object 440 | /// 441 | /// ```rust 442 | /// # use vm_superio::Trigger; 443 | /// # use vm_superio::serial::Serial; 444 | /// # struct DummyTrigger; 445 | /// # impl Trigger for DummyTrigger { 446 | /// # type E = (); 447 | /// # fn trigger(&self) -> Result<(), ()> { Ok(()) } 448 | /// # } 449 | /// const DATA_OFFSET: u8 = 0; 450 | /// 451 | /// let output = Vec::new(); 452 | /// let mut serial = Serial::new(DummyTrigger, output); 453 | /// serial.write(DATA_OFFSET, 0x66).unwrap(); 454 | /// serial.writer_mut().clear(); 455 | /// assert_eq!(serial.writer().first(), None); 456 | /// ``` 457 | pub fn writer_mut(&mut self) -> &mut W { 458 | &mut self.out 459 | } 460 | 461 | /// Consumes the device and retrieves the inner writer. This 462 | /// can be useful when restoring a copy of the device. 463 | /// 464 | /// ```rust 465 | /// # use vm_superio::Trigger; 466 | /// # use vm_superio::serial::{NoEvents, Serial}; 467 | /// # struct DummyTrigger; 468 | /// # impl Trigger for DummyTrigger { 469 | /// # type E = (); 470 | /// # fn trigger(&self) -> Result<(), ()> { Ok(()) } 471 | /// # } 472 | /// const DATA_OFFSET: u8 = 0; 473 | /// 474 | /// // Create a device with some state 475 | /// let output = Vec::new(); 476 | /// let mut serial = Serial::new(DummyTrigger, output); 477 | /// serial.write(DATA_OFFSET, 0x66).unwrap(); 478 | /// 479 | /// // Save the state 480 | /// let state = serial.state(); 481 | /// let output = serial.into_writer(); 482 | /// 483 | /// // Restore the device 484 | /// let restored_serial = Serial::from_state(&state, DummyTrigger, NoEvents, output).unwrap(); 485 | /// assert_eq!(restored_serial.writer().first().copied(), Some(0x66)); 486 | /// ``` 487 | pub fn into_writer(self) -> W { 488 | self.out 489 | } 490 | 491 | /// Provides a reference to the interrupt event object. 492 | pub fn interrupt_evt(&self) -> &T { 493 | &self.interrupt_evt 494 | } 495 | 496 | /// Provides a reference to the serial events object. 497 | pub fn events(&self) -> &EV { 498 | &self.events 499 | } 500 | 501 | fn is_dlab_set(&self) -> bool { 502 | (self.line_control & LCR_DLAB_BIT) != 0 503 | } 504 | 505 | fn is_rda_interrupt_enabled(&self) -> bool { 506 | (self.interrupt_enable & IER_RDA_BIT) != 0 507 | } 508 | 509 | fn is_thr_interrupt_enabled(&self) -> bool { 510 | (self.interrupt_enable & IER_THR_EMPTY_BIT) != 0 511 | } 512 | 513 | fn is_rda_interrupt_set(&self) -> bool { 514 | (self.interrupt_identification & IIR_RDA_BIT) != 0 515 | } 516 | 517 | fn is_thr_interrupt_set(&self) -> bool { 518 | (self.interrupt_identification & IIR_THR_EMPTY_BIT) != 0 519 | } 520 | 521 | fn is_in_loop_mode(&self) -> bool { 522 | (self.modem_control & MCR_LOOP_BIT) != 0 523 | } 524 | 525 | fn trigger_interrupt(&mut self) -> Result<(), T::E> { 526 | self.interrupt_evt.trigger() 527 | } 528 | 529 | fn set_lsr_rda_bit(&mut self) { 530 | self.line_status |= LSR_DATA_READY_BIT 531 | } 532 | 533 | fn clear_lsr_rda_bit(&mut self) { 534 | self.line_status &= !LSR_DATA_READY_BIT 535 | } 536 | 537 | fn add_interrupt(&mut self, interrupt_bits: u8) { 538 | self.interrupt_identification &= !IIR_NONE_BIT; 539 | self.interrupt_identification |= interrupt_bits; 540 | } 541 | 542 | fn del_interrupt(&mut self, interrupt_bits: u8) { 543 | self.interrupt_identification &= !interrupt_bits; 544 | if self.interrupt_identification == 0x00 { 545 | self.interrupt_identification = IIR_NONE_BIT; 546 | } 547 | } 548 | 549 | fn thr_empty_interrupt(&mut self) -> Result<(), T::E> { 550 | if self.is_thr_interrupt_enabled() { 551 | // Trigger the interrupt only if the identification bit wasn't 552 | // set or acknowledged. 553 | if self.interrupt_identification & IIR_THR_EMPTY_BIT == 0 { 554 | self.add_interrupt(IIR_THR_EMPTY_BIT); 555 | self.trigger_interrupt()? 556 | } 557 | } 558 | Ok(()) 559 | } 560 | 561 | fn received_data_interrupt(&mut self) -> Result<(), T::E> { 562 | if self.is_rda_interrupt_enabled() { 563 | // Trigger the interrupt only if the identification bit wasn't 564 | // set or acknowledged. 565 | if self.interrupt_identification & IIR_RDA_BIT == 0 { 566 | self.add_interrupt(IIR_RDA_BIT); 567 | self.trigger_interrupt()? 568 | } 569 | } 570 | Ok(()) 571 | } 572 | 573 | fn reset_iir(&mut self) { 574 | self.interrupt_identification = DEFAULT_INTERRUPT_IDENTIFICATION 575 | } 576 | 577 | /// Handles a write request from the driver at `offset` offset from the 578 | /// base Port I/O address. 579 | /// 580 | /// # Arguments 581 | /// * `offset` - The offset that will be added to the base PIO address 582 | /// for writing to a specific register. 583 | /// * `value` - The byte that should be written. 584 | /// 585 | /// # Example 586 | /// 587 | /// You can see an example of how to use this function in the 588 | /// [`Example` section from `Serial`](struct.Serial.html#example). 589 | pub fn write(&mut self, offset: u8, value: u8) -> Result<(), Error> { 590 | match offset { 591 | DLAB_LOW_OFFSET if self.is_dlab_set() => self.baud_divisor_low = value, 592 | DLAB_HIGH_OFFSET if self.is_dlab_set() => self.baud_divisor_high = value, 593 | DATA_OFFSET => { 594 | if self.is_in_loop_mode() { 595 | // In loopback mode, what is written in the transmit register 596 | // will be immediately found in the receive register, so we 597 | // simulate this behavior by adding in `in_buffer` the 598 | // transmitted bytes and letting the driver know there is some 599 | // pending data to be read, by setting RDA bit and its 600 | // corresponding interrupt. 601 | if self.in_buffer.len() < FIFO_SIZE { 602 | self.in_buffer.push_back(value); 603 | self.set_lsr_rda_bit(); 604 | self.received_data_interrupt().map_err(Error::Trigger)?; 605 | } 606 | } else { 607 | let res = self 608 | .out 609 | .write_all(&[value]) 610 | .map_err(Error::IOError) 611 | .and_then(|_| self.out.flush().map_err(Error::IOError)) 612 | .map(|_| self.events.out_byte()) 613 | .inspect_err(|_| { 614 | self.events.tx_lost_byte(); 615 | }); 616 | // Because we cannot block the driver, the THRE interrupt is sent 617 | // irrespective of whether we are able to write the byte or not 618 | self.thr_empty_interrupt().map_err(Error::Trigger)?; 619 | return res; 620 | } 621 | } 622 | // We want to enable only the interrupts that are available for 16550A (and below). 623 | IER_OFFSET => self.interrupt_enable = value & IER_UART_VALID_BITS, 624 | LCR_OFFSET => self.line_control = value, 625 | MCR_OFFSET => self.modem_control = value, 626 | SCR_OFFSET => self.scratch = value, 627 | // We are not interested in writing to other offsets (such as FCR offset). 628 | _ => {} 629 | } 630 | Ok(()) 631 | } 632 | 633 | /// Handles a read request from the driver at `offset` offset from the 634 | /// base Port I/O address. 635 | /// 636 | /// Returns the read value. 637 | /// 638 | /// # Arguments 639 | /// * `offset` - The offset that will be added to the base PIO address 640 | /// for reading from a specific register. 641 | /// 642 | /// # Example 643 | /// 644 | /// You can see an example of how to use this function in the 645 | /// [`Example` section from `Serial`](struct.Serial.html#example). 646 | pub fn read(&mut self, offset: u8) -> u8 { 647 | match offset { 648 | DLAB_LOW_OFFSET if self.is_dlab_set() => self.baud_divisor_low, 649 | DLAB_HIGH_OFFSET if self.is_dlab_set() => self.baud_divisor_high, 650 | DATA_OFFSET => { 651 | // Here we emulate the reset method for when RDA interrupt 652 | // was raised (i.e. read the receive buffer and clear the 653 | // interrupt identification register and RDA bit when no 654 | // more data is available). 655 | self.del_interrupt(IIR_RDA_BIT); 656 | let byte = self.in_buffer.pop_front().unwrap_or_default(); 657 | if self.in_buffer.is_empty() { 658 | self.clear_lsr_rda_bit(); 659 | self.events.in_buffer_empty(); 660 | } 661 | self.events.buffer_read(); 662 | byte 663 | } 664 | IER_OFFSET => self.interrupt_enable, 665 | IIR_OFFSET => { 666 | // We're enabling FIFO capability by setting the serial port to 16550A: 667 | // https://elixir.bootlin.com/linux/latest/source/drivers/tty/serial/8250/8250_port.c#L1299. 668 | let iir = self.interrupt_identification | IIR_FIFO_BITS; 669 | self.reset_iir(); 670 | iir 671 | } 672 | LCR_OFFSET => self.line_control, 673 | MCR_OFFSET => self.modem_control, 674 | LSR_OFFSET => self.line_status, 675 | MSR_OFFSET => { 676 | if self.is_in_loop_mode() { 677 | // In loopback mode, the four modem control inputs (CTS, DSR, RI, DCD) are 678 | // internally connected to the four modem control outputs (RTS, DTR, OUT1, OUT2). 679 | // This way CTS is controlled by RTS, DSR by DTR, RI by OUT1 and DCD by OUT2. 680 | // (so they will basically contain the same value). 681 | let mut msr = 682 | self.modem_status & !(MSR_DSR_BIT | MSR_CTS_BIT | MSR_RI_BIT | MSR_DCD_BIT); 683 | if (self.modem_control & MCR_DTR_BIT) != 0 { 684 | msr |= MSR_DSR_BIT; 685 | } 686 | if (self.modem_control & MCR_RTS_BIT) != 0 { 687 | msr |= MSR_CTS_BIT; 688 | } 689 | if (self.modem_control & MCR_OUT1_BIT) != 0 { 690 | msr |= MSR_RI_BIT; 691 | } 692 | if (self.modem_control & MCR_OUT2_BIT) != 0 { 693 | msr |= MSR_DCD_BIT; 694 | } 695 | msr 696 | } else { 697 | self.modem_status 698 | } 699 | } 700 | SCR_OFFSET => self.scratch, 701 | _ => 0, 702 | } 703 | } 704 | 705 | /// Returns how much space is still available in the FIFO. 706 | /// 707 | /// # Example 708 | /// 709 | /// You can see an example of how to use this function in the 710 | /// [`Example` section from `Serial`](struct.Serial.html#example). 711 | #[inline] 712 | pub fn fifo_capacity(&self) -> usize { 713 | FIFO_SIZE - self.in_buffer.len() 714 | } 715 | 716 | /// Helps in sending more bytes to the guest in one shot, by storing 717 | /// `input` bytes in UART buffer and letting the driver know there is 718 | /// some pending data to be read by setting RDA bit and its corresponding 719 | /// interrupt when not already triggered. 720 | /// 721 | /// # Arguments 722 | /// * `input` - The data to be sent to the guest. 723 | /// 724 | /// # Returns 725 | /// 726 | /// The function returns the number of bytes it was able to write to the fifo, 727 | /// or `FullFifo` error when the fifo is full. Users can use 728 | /// [`fifo_capacity`](#method.fifo_capacity) before calling this function 729 | /// to check the available space. 730 | /// 731 | /// # Example 732 | /// 733 | /// You can see an example of how to use this function in the 734 | /// [`Example` section from `Serial`](struct.Serial.html#example). 735 | pub fn enqueue_raw_bytes(&mut self, input: &[u8]) -> Result> { 736 | let mut write_count = 0; 737 | if !self.is_in_loop_mode() { 738 | // First check if the input slice and the fifo are non-empty so we can return early in 739 | // those cases. Any subsequent `write` to the `in_buffer` will write at least one byte. 740 | if input.is_empty() { 741 | return Ok(0); 742 | } 743 | if self.fifo_capacity() == 0 { 744 | return Err(Error::FullFifo); 745 | } 746 | 747 | write_count = std::cmp::min(self.fifo_capacity(), input.len()); 748 | self.in_buffer.extend(&input[0..write_count]); 749 | self.set_lsr_rda_bit(); 750 | self.received_data_interrupt().map_err(Error::Trigger)?; 751 | } 752 | Ok(write_count) 753 | } 754 | } 755 | 756 | #[cfg(test)] 757 | mod tests { 758 | use super::*; 759 | 760 | use std::io::{sink, Result}; 761 | use std::sync::atomic::AtomicU64; 762 | use std::sync::Arc; 763 | 764 | use vmm_sys_util::eventfd::EventFd; 765 | use vmm_sys_util::metric::Metric; 766 | 767 | const RAW_INPUT_BUF: [u8; 3] = [b'a', b'b', b'c']; 768 | 769 | impl Trigger for EventFd { 770 | type E = io::Error; 771 | 772 | fn trigger(&self) -> Result<()> { 773 | self.write(1) 774 | } 775 | } 776 | 777 | struct ExampleSerialEvents { 778 | read_count: AtomicU64, 779 | out_byte_count: AtomicU64, 780 | tx_lost_byte_count: AtomicU64, 781 | buffer_ready_event: EventFd, 782 | } 783 | 784 | impl ExampleSerialEvents { 785 | fn new() -> Self { 786 | ExampleSerialEvents { 787 | read_count: AtomicU64::new(0), 788 | out_byte_count: AtomicU64::new(0), 789 | tx_lost_byte_count: AtomicU64::new(0), 790 | buffer_ready_event: EventFd::new(libc::EFD_NONBLOCK).unwrap(), 791 | } 792 | } 793 | } 794 | 795 | impl SerialEvents for ExampleSerialEvents { 796 | fn buffer_read(&self) { 797 | self.read_count.inc(); 798 | // We can also log a message here, or as part of any of the other methods. 799 | } 800 | 801 | fn out_byte(&self) { 802 | self.out_byte_count.inc(); 803 | } 804 | 805 | fn tx_lost_byte(&self) { 806 | self.tx_lost_byte_count.inc(); 807 | } 808 | 809 | fn in_buffer_empty(&self) { 810 | self.buffer_ready_event.write(1).unwrap(); 811 | } 812 | } 813 | 814 | #[test] 815 | fn test_serial_output() { 816 | let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 817 | let mut serial = Serial::new(intr_evt, Vec::new()); 818 | 819 | // Valid one char at a time writes. 820 | RAW_INPUT_BUF 821 | .iter() 822 | .for_each(|&c| serial.write(DATA_OFFSET, c).unwrap()); 823 | assert_eq!(serial.writer().as_slice(), &RAW_INPUT_BUF); 824 | } 825 | 826 | #[test] 827 | fn test_serial_raw_input() { 828 | let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 829 | let mut serial = Serial::new(intr_evt.try_clone().unwrap(), sink()); 830 | 831 | serial.write(IER_OFFSET, IER_RDA_BIT).unwrap(); 832 | 833 | serial.enqueue_raw_bytes(&[]).unwrap(); 834 | // When enqueuing 0 bytes, the serial should neither raise an interrupt, 835 | // nor set the `DATA_READY` bit. 836 | assert_eq!( 837 | intr_evt.read().unwrap_err().kind(), 838 | io::ErrorKind::WouldBlock 839 | ); 840 | let mut lsr = serial.read(LSR_OFFSET); 841 | assert_eq!(lsr & LSR_DATA_READY_BIT, 0); 842 | 843 | // Enqueue a non-empty slice. 844 | serial.enqueue_raw_bytes(&RAW_INPUT_BUF).unwrap(); 845 | 846 | // Verify the serial raised an interrupt. 847 | assert_eq!(intr_evt.read().unwrap(), 1); 848 | 849 | // `DATA_READY` bit should've been set by `enqueue_raw_bytes()`. 850 | lsr = serial.read(LSR_OFFSET); 851 | assert_ne!(lsr & LSR_DATA_READY_BIT, 0); 852 | 853 | // Verify reading the previously pushed buffer. 854 | RAW_INPUT_BUF.iter().for_each(|&c| { 855 | lsr = serial.read(LSR_OFFSET); 856 | // `DATA_READY` bit won't be cleared until there is 857 | // just one byte left in the receive buffer. 858 | assert_ne!(lsr & LSR_DATA_READY_BIT, 0); 859 | assert_eq!(serial.read(DATA_OFFSET), c); 860 | // The Received Data Available interrupt bit should be 861 | // cleared after reading the first pending byte. 862 | assert_eq!( 863 | serial.interrupt_identification, 864 | DEFAULT_INTERRUPT_IDENTIFICATION 865 | ); 866 | }); 867 | 868 | lsr = serial.read(LSR_OFFSET); 869 | assert_eq!(lsr & LSR_DATA_READY_BIT, 0); 870 | } 871 | 872 | #[test] 873 | fn test_serial_thr() { 874 | let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 875 | let mut serial = Serial::new(intr_evt.try_clone().unwrap(), sink()); 876 | 877 | serial.write(IER_OFFSET, IER_THR_EMPTY_BIT).unwrap(); 878 | assert_eq!( 879 | serial.interrupt_enable, 880 | IER_THR_EMPTY_BIT & IER_UART_VALID_BITS 881 | ); 882 | serial.write(DATA_OFFSET, b'a').unwrap(); 883 | 884 | // Verify the serial raised an interrupt. 885 | assert_eq!(intr_evt.read().unwrap(), 1); 886 | 887 | let ier = serial.read(IER_OFFSET); 888 | assert_eq!(ier & IER_UART_VALID_BITS, IER_THR_EMPTY_BIT); 889 | let iir = serial.read(IIR_OFFSET); 890 | // Verify the raised interrupt is indeed the empty THR one. 891 | assert_ne!(iir & IIR_THR_EMPTY_BIT, 0); 892 | 893 | // When reading from IIR offset, the returned value will tell us that 894 | // FIFO feature is enabled. 895 | assert_eq!(iir, IIR_THR_EMPTY_BIT | IIR_FIFO_BITS); 896 | assert_eq!( 897 | serial.interrupt_identification, 898 | DEFAULT_INTERRUPT_IDENTIFICATION 899 | ); 900 | } 901 | 902 | #[test] 903 | fn test_serial_loop_mode() { 904 | let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 905 | let mut serial = Serial::new(intr_evt.try_clone().unwrap(), sink()); 906 | 907 | serial.write(MCR_OFFSET, MCR_LOOP_BIT).unwrap(); 908 | serial.write(IER_OFFSET, IER_RDA_BIT).unwrap(); 909 | 910 | for value in 0..FIFO_SIZE as u8 { 911 | serial.write(DATA_OFFSET, value).unwrap(); 912 | assert_eq!(intr_evt.read().unwrap(), 1); 913 | assert_eq!(serial.in_buffer.len(), 1); 914 | // Immediately read a pushed value. 915 | assert_eq!(serial.read(DATA_OFFSET), value); 916 | } 917 | 918 | assert_eq!(serial.line_status & LSR_DATA_READY_BIT, 0); 919 | 920 | for value in 0..FIFO_SIZE as u8 { 921 | serial.write(DATA_OFFSET, value).unwrap(); 922 | } 923 | 924 | assert_eq!(intr_evt.read().unwrap(), 1); 925 | assert_eq!(serial.in_buffer.len(), FIFO_SIZE); 926 | 927 | // Read the pushed values at the end. 928 | for value in 0..FIFO_SIZE as u8 { 929 | assert_ne!(serial.line_status & LSR_DATA_READY_BIT, 0); 930 | assert_eq!(serial.read(DATA_OFFSET), value); 931 | } 932 | assert_eq!(serial.line_status & LSR_DATA_READY_BIT, 0); 933 | } 934 | 935 | #[test] 936 | fn test_serial_dlab() { 937 | let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 938 | let mut serial = Serial::new(intr_evt, sink()); 939 | 940 | // For writing to DLAB registers, `DLAB` bit from LCR should be set. 941 | serial.write(LCR_OFFSET, LCR_DLAB_BIT).unwrap(); 942 | serial.write(DLAB_HIGH_OFFSET, 0x12).unwrap(); 943 | assert_eq!(serial.read(DLAB_LOW_OFFSET), DEFAULT_BAUD_DIVISOR_LOW); 944 | assert_eq!(serial.read(DLAB_HIGH_OFFSET), 0x12); 945 | 946 | serial.write(DLAB_LOW_OFFSET, 0x34).unwrap(); 947 | 948 | assert_eq!(serial.read(DLAB_LOW_OFFSET), 0x34); 949 | assert_eq!(serial.read(DLAB_HIGH_OFFSET), 0x12); 950 | 951 | // If LCR_DLAB_BIT is not set, the values from `DLAB_LOW_OFFSET` and 952 | // `DLAB_HIGH_OFFSET` won't be the expected ones. 953 | serial.write(LCR_OFFSET, 0x00).unwrap(); 954 | assert_ne!(serial.read(DLAB_LOW_OFFSET), 0x12); 955 | assert_ne!(serial.read(DLAB_HIGH_OFFSET), 0x34); 956 | } 957 | 958 | #[test] 959 | fn test_basic_register_accesses() { 960 | let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 961 | let mut serial = Serial::new(intr_evt, sink()); 962 | 963 | // Writing to these registers does not alter the initial values to be written 964 | // and reading from these registers just returns those values, without 965 | // modifying them. 966 | let basic_register_accesses = [LCR_OFFSET, MCR_OFFSET, SCR_OFFSET]; 967 | for offset in basic_register_accesses.iter() { 968 | serial.write(*offset, 0x12).unwrap(); 969 | assert_eq!(serial.read(*offset), 0x12); 970 | } 971 | } 972 | 973 | #[test] 974 | fn test_invalid_access() { 975 | let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 976 | let mut serial = Serial::new(intr_evt, sink()); 977 | 978 | // Check if reading from an offset outside 0-7 returns for sure 0. 979 | serial.write(SCR_OFFSET + 1, 5).unwrap(); 980 | assert_eq!(serial.read(SCR_OFFSET + 1), 0); 981 | } 982 | 983 | #[test] 984 | fn test_serial_msr() { 985 | let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 986 | let mut serial = Serial::new(intr_evt, sink()); 987 | 988 | assert_eq!(serial.read(MSR_OFFSET), DEFAULT_MODEM_STATUS); 989 | 990 | // Activate loopback mode. 991 | serial.write(MCR_OFFSET, MCR_LOOP_BIT).unwrap(); 992 | 993 | // In loopback mode, MSR won't contain the default value anymore. 994 | assert_ne!(serial.read(MSR_OFFSET), DEFAULT_MODEM_STATUS); 995 | assert_eq!(serial.read(MSR_OFFSET), 0x00); 996 | 997 | // Depending on which bytes we enable for MCR, MSR will be modified accordingly. 998 | serial 999 | .write(MCR_OFFSET, DEFAULT_MODEM_CONTROL | MCR_LOOP_BIT) 1000 | .unwrap(); 1001 | // DEFAULT_MODEM_CONTROL sets OUT2 from MCR to 1. In loopback mode, OUT2 is equivalent 1002 | // to DCD bit from MSR. 1003 | assert_eq!(serial.read(MSR_OFFSET), MSR_DCD_BIT); 1004 | 1005 | // The same should happen with OUT1 and RI. 1006 | serial 1007 | .write(MCR_OFFSET, MCR_OUT1_BIT | MCR_LOOP_BIT) 1008 | .unwrap(); 1009 | assert_eq!(serial.read(MSR_OFFSET), MSR_RI_BIT); 1010 | 1011 | serial 1012 | .write(MCR_OFFSET, MCR_LOOP_BIT | MCR_DTR_BIT | MCR_RTS_BIT) 1013 | .unwrap(); 1014 | // DSR and CTS from MSR are "matching wires" to DTR and RTS from MCR (so they will 1015 | // have the same value). 1016 | assert_eq!(serial.read(MSR_OFFSET), MSR_DSR_BIT | MSR_CTS_BIT); 1017 | } 1018 | 1019 | #[test] 1020 | fn test_fifo_max_size() { 1021 | let event_fd = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 1022 | let mut serial = Serial::new(event_fd, sink()); 1023 | 1024 | // Test case: trying to write too many bytes in an empty fifo will just write 1025 | // `FIFO_SIZE`. Any other subsequent writes, will return a `FullFifo` error. 1026 | let too_many_bytes = vec![1u8; FIFO_SIZE + 1]; 1027 | let written_bytes = serial.enqueue_raw_bytes(&too_many_bytes).unwrap(); 1028 | assert_eq!(written_bytes, FIFO_SIZE); 1029 | assert_eq!(serial.in_buffer.len(), FIFO_SIZE); 1030 | 1031 | // A subsequent call to `enqueue_raw_bytes` with an empty slice should not fail, 1032 | // even though the fifo is now full. 1033 | let written_bytes = serial.enqueue_raw_bytes(&[]).unwrap(); 1034 | assert_eq!(written_bytes, 0); 1035 | assert_eq!(serial.in_buffer.len(), FIFO_SIZE); 1036 | 1037 | // A subsequent call to `enqueue_raw_bytes` with a non-empty slice fails because 1038 | // the fifo is now full. 1039 | let one_byte_input = [1u8]; 1040 | match serial.enqueue_raw_bytes(&one_byte_input) { 1041 | Err(Error::FullFifo) => (), 1042 | _ => unreachable!(), 1043 | } 1044 | 1045 | // Test case: consuming one byte from a full fifo does not allow writes 1046 | // bigger than one byte. 1047 | let _ = serial.read(DATA_OFFSET); 1048 | let written_bytes = serial.enqueue_raw_bytes(&too_many_bytes[..2]).unwrap(); 1049 | assert_eq!(written_bytes, 1); 1050 | assert_eq!(serial.in_buffer.len(), FIFO_SIZE); 1051 | } 1052 | 1053 | #[test] 1054 | fn test_serial_events() { 1055 | let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 1056 | 1057 | let events_ = Arc::new(ExampleSerialEvents::new()); 1058 | let mut oneslot_buf = [0u8; 1]; 1059 | let mut serial = Serial::with_events(intr_evt, events_, oneslot_buf.as_mut()); 1060 | 1061 | // This should be an error because buffer_ready_event has not been 1062 | // triggered yet so no one should have written to that fd yet. 1063 | assert_eq!( 1064 | serial.events.buffer_ready_event.read().unwrap_err().kind(), 1065 | io::ErrorKind::WouldBlock 1066 | ); 1067 | 1068 | // Check everything is equal to 0 at the beginning. 1069 | assert_eq!(serial.events.read_count.count(), 0); 1070 | assert_eq!(serial.events.out_byte_count.count(), 0); 1071 | assert_eq!(serial.events.tx_lost_byte_count.count(), 0); 1072 | 1073 | // This DATA read should cause the `SerialEvents::buffer_read` method to be invoked. 1074 | // And since the in_buffer is empty the buffer_ready_event should have 1075 | // been triggered, hence we can read from that fd. 1076 | serial.read(DATA_OFFSET); 1077 | assert_eq!(serial.events.read_count.count(), 1); 1078 | assert_eq!(serial.events.buffer_ready_event.read().unwrap(), 1); 1079 | 1080 | // This DATA write should cause `SerialEvents::out_byte` to be called. 1081 | serial.write(DATA_OFFSET, 1).unwrap(); 1082 | assert_eq!(serial.events.out_byte_count.count(), 1); 1083 | // `SerialEvents::tx_lost_byte` should not have been called. 1084 | assert_eq!(serial.events.tx_lost_byte_count.count(), 0); 1085 | 1086 | // This DATA write should cause `SerialEvents::tx_lost_byte` to be called. 1087 | serial.write(DATA_OFFSET, 1).unwrap_err(); 1088 | assert_eq!(serial.events.tx_lost_byte_count.count(), 1); 1089 | 1090 | // Check that every metric has the expected value at the end, to ensure we didn't 1091 | // unexpectedly invoked any extra callbacks. 1092 | assert_eq!(serial.events.read_count.count(), 1); 1093 | assert_eq!(serial.events.out_byte_count.count(), 1); 1094 | assert_eq!(serial.events.tx_lost_byte_count.count(), 1); 1095 | 1096 | // This DATA read should cause the `SerialEvents::buffer_read` method to be invoked. 1097 | // And since it was the last byte from in buffer the `SerialEvents::in_buffer_empty` 1098 | // was also invoked. 1099 | serial.read(DATA_OFFSET); 1100 | assert_eq!(serial.events.read_count.count(), 2); 1101 | assert_eq!(serial.events.buffer_ready_event.read().unwrap(), 1); 1102 | let _res = serial.enqueue_raw_bytes(&[1, 2]); 1103 | serial.read(DATA_OFFSET); 1104 | // Since there is still one byte in the in_buffer, buffer_ready_events 1105 | // should have not been triggered so we shouldn't have anything to read 1106 | // from that fd. 1107 | assert_eq!( 1108 | serial.events.buffer_ready_event.read().unwrap_err().kind(), 1109 | io::ErrorKind::WouldBlock 1110 | ); 1111 | } 1112 | 1113 | #[test] 1114 | fn test_out_descrp_full_thre_sent() { 1115 | let mut nospace_buf = [0u8; 0]; 1116 | let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 1117 | let mut serial = Serial::new(intr_evt, nospace_buf.as_mut()); 1118 | 1119 | // Enable THR interrupt. 1120 | serial.write(IER_OFFSET, IER_THR_EMPTY_BIT).unwrap(); 1121 | 1122 | // Write some data. 1123 | let res = serial.write(DATA_OFFSET, 5); 1124 | let iir = serial.read(IIR_OFFSET); 1125 | 1126 | // The write failed. 1127 | assert!( 1128 | matches!(res.unwrap_err(), Error::IOError(io_err) if io_err.kind() == io::ErrorKind::WriteZero 1129 | ) 1130 | ); 1131 | // THR empty interrupt was raised nevertheless. 1132 | assert_eq!(iir & IIR_THR_EMPTY_BIT, IIR_THR_EMPTY_BIT); 1133 | } 1134 | 1135 | #[test] 1136 | fn test_serial_state_default() { 1137 | let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 1138 | let serial = Serial::new(intr_evt, Vec::new()); 1139 | 1140 | assert_eq!(serial.state(), SerialState::default()); 1141 | } 1142 | 1143 | #[test] 1144 | fn test_from_state_with_too_many_bytes() { 1145 | let mut state = SerialState::default(); 1146 | let too_many_bytes = vec![1u8; 128]; 1147 | 1148 | state.in_buffer.extend(too_many_bytes); 1149 | 1150 | let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 1151 | let serial = Serial::from_state(&state, intr_evt, NoEvents, sink()); 1152 | 1153 | assert!(matches!(serial, Err(Error::FullFifo))); 1154 | } 1155 | 1156 | #[test] 1157 | fn test_from_state_with_pending_thre_interrupt() { 1158 | let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 1159 | let mut serial = Serial::new(intr_evt.try_clone().unwrap(), sink()); 1160 | 1161 | serial.write(IER_OFFSET, IER_THR_EMPTY_BIT).unwrap(); 1162 | serial.write(DATA_OFFSET, b'a').unwrap(); 1163 | assert_eq!(intr_evt.read().unwrap(), 1); 1164 | 1165 | let state = serial.state(); 1166 | let mut serial_after_restore = 1167 | Serial::from_state(&state, intr_evt.try_clone().unwrap(), NoEvents, sink()).unwrap(); 1168 | 1169 | let ier = serial_after_restore.read(IER_OFFSET); 1170 | assert_eq!(ier & IER_UART_VALID_BITS, IER_THR_EMPTY_BIT); 1171 | let iir = serial_after_restore.read(IIR_OFFSET); 1172 | assert_ne!(iir & IIR_THR_EMPTY_BIT, 0); 1173 | 1174 | // Verify the serial raised an interrupt again. 1175 | assert_eq!(intr_evt.read().unwrap(), 1); 1176 | } 1177 | 1178 | #[test] 1179 | fn test_from_state_with_pending_rda_interrupt() { 1180 | let intr_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); 1181 | let mut serial = Serial::new(intr_evt.try_clone().unwrap(), sink()); 1182 | 1183 | serial.write(IER_OFFSET, IER_RDA_BIT).unwrap(); 1184 | serial.enqueue_raw_bytes(&RAW_INPUT_BUF).unwrap(); 1185 | assert_eq!(intr_evt.read().unwrap(), 1); 1186 | 1187 | let state = serial.state(); 1188 | let mut serial_after_restore = 1189 | Serial::from_state(&state, intr_evt.try_clone().unwrap(), NoEvents, sink()).unwrap(); 1190 | 1191 | let ier = serial_after_restore.read(IER_OFFSET); 1192 | assert_eq!(ier & IER_UART_VALID_BITS, IER_RDA_BIT); 1193 | let iir = serial_after_restore.read(IIR_OFFSET); 1194 | assert_ne!(iir & IIR_RDA_BIT, 0); 1195 | 1196 | // Verify the serial raised an interrupt again. 1197 | assert_eq!(intr_evt.read().unwrap(), 1); 1198 | } 1199 | } 1200 | --------------------------------------------------------------------------------