diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..531ddd1 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,55 @@ +name: CI + +on: [push, pull_request] + +jobs: + ci: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + rust-toolchain: [nightly] + targets: [x86_64-unknown-linux-gnu, x86_64-unknown-none, riscv64gc-unknown-none-elf, aarch64-unknown-none-softfloat] + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + with: + toolchain: ${{ matrix.rust-toolchain }} + components: rust-src, clippy, rustfmt + targets: ${{ matrix.targets }} + - name: Check rust version + run: rustc --version --verbose + - name: Check code format + run: cargo fmt --all -- --check + - name: Clippy + run: cargo clippy --target ${{ matrix.targets }} --all-features -- -A clippy::new_without_default + - name: Build + run: cargo build --target ${{ matrix.targets }} --all-features + - name: Unit test + if: ${{ matrix.targets == 'x86_64-unknown-linux-gnu' }} + run: cargo test --target ${{ matrix.targets }} -- --nocapture + + doc: + runs-on: ubuntu-latest + strategy: + fail-fast: false + permissions: + contents: write + env: + default-branch: ${{ format('refs/heads/{0}', github.event.repository.default_branch) }} + RUSTDOCFLAGS: -D rustdoc::broken_intra_doc_links -D missing-docs + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + - name: Build docs + continue-on-error: ${{ github.ref != env.default-branch && github.event_name != 'pull_request' }} + run: | + cargo doc --no-deps --all-features + printf '' $(cargo tree | head -1 | cut -d' ' -f1) > target/doc/index.html + - name: Deploy to Github Pages + if: ${{ github.ref == env.default-branch }} + uses: JamesIves/github-pages-deploy-action@v4 + with: + single-commit: true + branch: gh-pages + folder: target/doc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ff78c42 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target +/.vscode +.DS_Store +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..6235f4a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "arm_pl031" +version = "0.1.0" +edition = "2021" +authors = ["Keyang Hu "] +description = "System Real Time Clock (RTC) Drivers for aarch64 based on PL031." +license = "GPL-3.0-or-later OR Apache-2.0 OR MulanPSL-2.0" +homepage = "https://github.com/arceos-org/arceos" +repository = "https://github.com/arceos-org/arceos/tree/main/crates/arm_pl031" +documentation = "https://docs.rs/arm_pl031" +keywords = ["arceos", "aarch64", "rtc"] +categories = ["os", "hardware-support", "no-std"] + +[dependencies] diff --git a/README.md b/README.md new file mode 100644 index 0000000..e573f1e --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# arm_pl031 + +[![Crates.io](https://img.shields.io/crates/v/arm_pl031)](https://crates.io/crates/arm_pl031) + +System Real Time Clock (RTC) Drivers for aarch64 based on PL031. + +## Examples + +```rust +use arm_pl031::Rtc; + +let epoch_time = Rtc::new(0x901_0000).get_unix_timestamp(); +``` + +`base_addr` needs to be the device virtual address available for mmio, which can be obtained from the device tree, for example: + +``` +/ { + interrupt-parent = <0x8002>; + model = "linux,dummy-virt"; + #size-cells = <0x02>; + #address-cells = <0x02>; + compatible = "linux,dummy-virt"; + + pl031@9010000 { + clock-names = "apb_pclk"; + clocks = <0x8000>; + interrupts = <0x00 0x02 0x04>; + reg = <0x00 0x9010000 0x00 0x1000>; + compatible = "arm,pl031\0arm,primecell"; + }; + + ... +} +``` \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..7eed437 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,41 @@ +//! System Real Time Clock (RTC) Drivers for aarch64 based on PL031. + +#![cfg_attr(not(test), no_std)] + +const RTC_DR: usize = 0x00; //Data Register +const RTC_LR: usize = 0x08; //Load Register + +/// The System Real Time Clock structure for aarch64 based on PL031. +pub struct Rtc { + base_address: usize, +} + +impl Rtc { + unsafe fn read(&self, reg: usize) -> u32 { + core::ptr::read_volatile((self.base_address + reg) as *const u32) + } + + unsafe fn write(&self, reg: usize, value: u32) { + core::ptr::write_volatile((self.base_address + reg) as *mut u32, value); + } +} + +impl Rtc { + /// Construct a new PL031 RTC structure. + /// + /// `base_addr` represents the device address + /// (which can be obtained from the device tree). + pub fn new(base_address: usize) -> Self { + Rtc { base_address } + } + + /// Returns the current time in seconds since UNIX epoch. + pub fn get_unix_timestamp(&self) -> u64 { + unsafe { self.read(RTC_DR) as u64 } + } + + /// Sets the current time in seconds since UNIX epoch. + pub fn set_unix_timestamp(&self, unix_time: u64) { + unsafe { self.write(RTC_LR, unix_time as u32) } + } +}