diff --git a/.travis.yml b/.travis.yml index dfefbd0..70f2c72 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,20 +6,31 @@ branches: language: rust +rust: +# build nightly only for the time beeing + - nightly + matrix: fast_finish: true - include: - - rust: nightly + - name: "build 64Bit" + install: + - sudo apt-get install gcc-aarch64-linux-gnu gcc-aarch64-linux-gnu + - cargo install cargo-xbuild + - rustup target add aarch64-unknown-linux-gnu + - rustup component add rust-src + - sudo chmod ugo+x build.sh + script: sed -i 's/path.*=.*"\.\{2\}.*", version/version/g' Cargo.toml && ./build.sh 64 travis -script: ./travis-build.sh + - name: "build 32Bit" + install: + - sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf + - cargo install cargo-xbuild + - rustup target add armv7-unknown-linux-gnueabihf + - rustup component add rust-src + - sudo chmod ugo+x build.sh + # remove the path in the dependencies of the cargo file to ensure we use the version from crates.io + script: sed -i 's/path.*=.*"\.\{2\}.*", version/version/g' Cargo.toml && ./build.sh 32 travis -install: -# install cross compiler toolchain - - sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf -# install cargo xbuild to proper cross compile - - cargo install cargo-xbuild -# add the build target used for Raspbarry Pi targeting builds - - rustup target add armv7-unknown-linux-gnueabihf - - rustup component add rust-src - - sudo chmod ugo+x ./travis-build.sh \ No newline at end of file + - name: "unit tests" + script: sed -i 's/path.*=.*"\.\{2\}.*", version/version/g' Cargo.toml && cargo test --tests diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 0823472..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,150 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "paste" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "paste-impl" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro2" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quote" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ruspiro-interrupt" -version = "0.2.1" -dependencies = [ - "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ruspiro-interrupt-core 0.2.0", - "ruspiro-interrupt-macros 0.2.0", - "ruspiro-register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ruspiro-singleton 0.2.0", -] - -[[package]] -name = "ruspiro-interrupt-core" -version = "0.2.0" - -[[package]] -name = "ruspiro-interrupt-macros" -version = "0.2.0" -dependencies = [ - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ruspiro-lock" -version = "0.2.0" -dependencies = [ - "ruspiro-interrupt-core 0.2.0", -] - -[[package]] -name = "ruspiro-register" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ruspiro-singleton" -version = "0.2.0" -dependencies = [ - "ruspiro-interrupt-core 0.2.0", - "ruspiro-lock 0.2.0", -] - -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syn" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-xid" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "423a519e1c6e828f1e73b720f9d9ed2fa643dce8a7737fb43235ce0b41eeaa49" -"checksum paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4214c9e912ef61bf42b81ba9a47e8aad1b2ffaf739ab162bf96d1e011f54e6c5" -"checksum proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e688f31d92ffd7c1ddc57a1b4e6d773c0f2a14ee437a4b0a4f5a69c80eb221c8" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5c2380ae88876faae57698be9e9775e3544decad214599c3a6266cca6ac802" -"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum ruspiro-register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b980f28994eba9f2f2a7e539acdc2daf7903cd38dd173c24153d4a2a69f23414" -"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" diff --git a/Cargo.toml b/Cargo.toml index 39634df..54a11f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,13 @@ [package] name = "ruspiro-interrupt" authors = ["Andre Borrmann "] -version = "0.2.1" # remember to update html_root_url -description = "Providing a simple and convinient way to implement interrupt handler for Raspberry Pi interrupts." +version = "0.3.0" # remember to update html_root_url +description = """ +Providing a simple and convinient way to implement interrupt handler for Raspberry Pi interrupts. +""" license = "Apache-2.0" -repository = "https://github.com/RusPiRo/ruspiro-interrupt/tree/v0.2.1" -documentation = "https://docs.rs/ruspiro-interrupt/0.2.1" +repository = "https://github.com/RusPiRo/ruspiro-interrupt/tree/v0.3.0" +documentation = "https://docs.rs/ruspiro-interrupt/0.3.0" readme = "README.md" keywords = ["RusPiRo", "baremetal", "raspberrypi", "interrupt"] categories = ["no-std", "embedded"] @@ -19,10 +21,10 @@ maintenance = { status = "actively-developed" } [dependencies] paste = "0.1.5" -ruspiro-register = "0.1" -ruspiro-interrupt-core = { path = "./core", version = "0.2" } +ruspiro-register = { path = "../register", version = "0.3" } +ruspiro-interrupt-core = { path = "./core", version = "0.3" } ruspiro-interrupt-macros = { path = "./macros", version = "0.2" } -ruspiro-singleton = "0.2" +ruspiro-singleton = { path = "../singleton", version = "0.3" } [features] default = ["ruspiro_pi3"] diff --git a/README.md b/README.md index e3e2e75..2199334 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,12 @@ script providing all the necessary linker symbols and entrypoints calling into t To use the crate just add the following dependency to your ``Cargo.toml`` file: ``` [dependencies] -ruspiro-interrupt = "0.2" +ruspiro-interrupt = "0.3" ``` Once done the access to the features/attribute of the interrupt crate is available in your rust files like so: ``` +extern crate ruspiro_interrupt; // needed for proper linking of weak defined functions use ruspiro-interrupt::*; #[IrqHandler()] diff --git a/Xargo.toml b/Xargo.toml deleted file mode 100644 index 58e3d0f..0000000 --- a/Xargo.toml +++ /dev/null @@ -1,4 +0,0 @@ -# define specific additional dependencies in addition to the rust core crate when running xargo to create documentation -# the release build done with cargo xbuild does not need this to properly compile and link all used additional crates -[target.armv7-unknown-linux-gnueabihf.dependencies] -alloc = {} diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..3f18e2c --- /dev/null +++ b/build.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +set +ev + +if [ $# -eq 0 ] + then + echo "not enough parameter given" + exit 1 +fi + +# check which aarch version to build +if [ $1 = "64" ] + then + # aarch64 + export CFLAGS='-march=armv8-a -Wall -O3 -nostdlib -nostartfiles -ffreestanding -mtune=cortex-a53' + export RUSTFLAGS='-C linker=aarch64-elf-gcc -C target-cpu=cortex-a53 -C target-feature=+strict-align,+a53,+fp-armv8,+neon -C link-arg=-nostartfiles -C opt-level=3 -C debuginfo=0' + if [ "$2" = "" ] + then + export CC='aarch64-elf-gcc' + export AR='aarch64-elf-ar' + fi + cargo xbuild --target aarch64-unknown-linux-gnu --release +elif [ $1 = "32" ] + then + # aarch32 + export CFLAGS='-mfpu=neon-fp-armv8 -mfloat-abi=hard -march=armv8-a -Wall -O3 -nostdlib -nostartfiles -ffreestanding -mtune=cortex-a53' + export RUSTFLAGS='-C linker=arm-eabi-gcc.exe -C target-cpu=cortex-a53 -C target-feature=+strict-align,+a53,+fp-armv8,+v8,+vfp3,+d16,+thumb2,+neon -C link-arg=-nostartfiles -C opt-level=3 -C debuginfo=0' + if [ -z "$2" ] + then + export CC='arm-eabi-gcc.exe' + export AR='arm-eabi-ar.exe' + fi + cargo xbuild --target armv7-unknown-linux-gnueabihf --release +else + echo 'provide the archtitecture to be build. Use either "build.sh 32" or "build.sh 64"' +fi diff --git a/core/Cargo.toml b/core/Cargo.toml index ce0075d..b3494f1 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,11 +1,13 @@ [package] name = "ruspiro-interrupt-core" authors = ["Andre Borrmann "] -version = "0.2.0" # remember to update html_root_url -description = "Interrupt core functions to globally enable/disable interrupts on Raspberry Pi" +version = "0.3.0" # remember to update html_root_url +description = """ +Interrupt core functions to globally enable/disable interrupts on Raspberry Pi +""" license = "Apache-2.0" -repository = "https://github.com/RusPiRo/ruspiro-interrupt/tree/v0.2.1/core" -documentation = "https://docs.rs/ruspiro-interrupt-core/0.2.0" +repository = "https://github.com/RusPiRo/ruspiro-interrupt/tree/v0.3.0/core" +documentation = "https://docs.rs/ruspiro-interrupt-core/0.3.0" readme = "README.md" keywords = ["RusPiRo", "baremetal", "raspberrypi", "interrupt"] categories = ["no-std", "embedded"] diff --git a/core/README.md b/core/README.md index 2657ecf..a472e59 100644 --- a/core/README.md +++ b/core/README.md @@ -13,7 +13,7 @@ Core interrupt functions to globally enable/disable interrupts to be triggered o To use the crate just add the following dependency to your ``Cargo.toml`` file: ``` [dependencies] -ruspiro-interrupt-core = "0.2" +ruspiro-interrupt-core = "0.3" ``` Once done the access to the functions to enable/disable interrupts is available in your rust files like so: diff --git a/core/src/lib.rs b/core/src/lib.rs index 701eed1..48265f0 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,26 +1,42 @@ -/*********************************************************************************************************************** +/*********************************************************************************************************************** * Copyright (c) 2019 by the authors - * - * Author: André Borrmann + * + * Author: André Borrmann * License: Apache License 2.0 **********************************************************************************************************************/ -#![doc(html_root_url = "https://docs.rs/ruspiro-interrupt-core/0.2.0")] +#![doc(html_root_url = "https://docs.rs/ruspiro-interrupt-core/0.3.0")] #![no_std] #![feature(asm)] //! # Interrupt Core functions -//! -//! Core functions to enable/disable interupts globally. This is splitted from the +//! +//! Core functions to enable/disable interrupts globally. This is splitted from the //! [``ruspiro-interrupt``](https://crates.io/crates/ruspiro-interrupt) crate to remove circular dependencies between -//! the interrupt crate others (e.g. ``ruspiro-singleton``) crate. +//! the interrupt crate and others (e.g. ``ruspiro-singleton``). use core::sync::atomic::{AtomicBool, Ordering}; +// simple state to track whether we are currently running inside an IRQ +// this is usually set and cleared by the interrupt handler [interrupt_handler] +static IRQ_HANDLER_ACTIVE: AtomicBool = AtomicBool::new(false); + // last IRQ state before globally disabling interrupts static IRQ_STATE: AtomicBool = AtomicBool::new(false); // last FAULT/FIQ state before globally disabling fast interrupts static FAULT_STATE: AtomicBool = AtomicBool::new(false); +/// Function used to store a cross core global flag that an interrupt is currently +/// handled +pub fn entering_interrupt_handler() { + IRQ_HANDLER_ACTIVE.store(true, Ordering::SeqCst); +} + +/// Function used to clear a cross core global flag that no interrupt is currently +/// handled +pub fn leaving_interrupt_handler() { + IRQ_HANDLER_ACTIVE.store(false, Ordering::SeqCst); +} + /// globally enabling interrupts (IRQ/FIQ) to be triggered pub fn enable_interrupts() { enable_irq(); @@ -29,6 +45,14 @@ pub fn enable_interrupts() { /// globally disabling interrupts (IRQ/FIQ) from beeing triggered pub fn disable_interrupts() { + // in aarch64 mode the interrupts are disabled by default on entering + // no need to disable + #[cfg(target_arch = "aarch64")] + { + if IRQ_HANDLER_ACTIVE.load(Ordering::SeqCst) { + return; + } + } disable_irq(); disable_fiq(); } @@ -36,56 +60,99 @@ pub fn disable_interrupts() { /// globally re-enabling interrupts (IRQ/FIQ) to be triggered. This is done based on the global state /// that was set before the interrupts were disable using the [``disable_interrupts``] function. pub fn re_enable_interrupts() { + // in aarch64 mode the interrupts are disabled by default on entering + // no need to re-enable when running inside interrupt handler + #[cfg(target_arch = "aarch64")] + { + if IRQ_HANDLER_ACTIVE.load(Ordering::SeqCst) { + return; + } + } re_enable_irq(); re_enable_fiq(); } - /// globally enable ``IRQ`` interrupts to be triggered pub fn enable_irq() { - #[cfg(target_arch="arm")] - unsafe { - asm!("cpsie i - isb") // as per ARM spec the ISB ensures triggering pending interrupts + #[cfg(target_arch = "arm")] + unsafe { + asm!( + "cpsie i + isb" + ) // as per ARM spec the ISB ensures triggering pending interrupts + }; + #[cfg(target_arch = "aarch64")] + unsafe { + asm!( + "msr daifclr, #2 + isb" + ) // as per ARM spec the ISB ensures triggering pending interrupts }; } -/// globally re-enabe ``IRQ`` interrupts to be triggered based on the global state that was set before disabling IRQ +/// globally re-enable ``IRQ`` interrupts to be triggered based on the global state that was set before disabling IRQ /// interrupts wihin the [``disable_irq``] function. -pub fn re_enable_irq() { +fn re_enable_irq() { // re-enable interrupts if they have been enabled prior to disabling let state = IRQ_STATE.load(Ordering::SeqCst); if state { - #[cfg(target_arch="arm")] - unsafe { - asm!("cpsie i - isb") // as per ARM spec the ISB ensures triggering pending interrupts - }; + #[cfg(target_arch = "arm")] + unsafe { + asm!( + "cpsie i + isb" + ) // as per ARM spec the ISB ensures triggering pending interrupts + }; + #[cfg(target_arch = "aarch64")] + unsafe { + asm!( + "msr daifclr, #2 + isb" + ) // as per ARM spec the ISB ensures triggering pending interrupts + }; } } /// globally enable ``FIQ`` interrupts to be triggered pub fn enable_fiq() { - #[cfg(target_arch="arm")] - unsafe { - asm!("cpsie f - isb") // as per ARM spec the ISB ensures triggering pending interrupts + #[cfg(target_arch = "arm")] + unsafe { + asm!( + "cpsie f + isb" + ) // as per ARM spec the ISB ensures triggering pending interrupts + }; + #[cfg(target_arch = "aarch64")] + unsafe { + asm!( + "msr daifclr, #1 + isb" + ) // as per ARM spec the ISB ensures triggering pending interrupts }; } -/// globally re-enabe ``FIQ`` interrupts to be triggered based on the global state that was set before disabling FIQ +/// globally re-enable ``FIQ`` interrupts to be triggered based on the global state that was set before disabling FIQ /// interrupts wihin the [``disable_fiq``] function. -pub fn re_enable_fiq() { +fn re_enable_fiq() { // re-enable interrupts if they have been enabled prior to disabling let state = FAULT_STATE.load(Ordering::SeqCst); if state { - #[cfg(target_arch="arm")] - unsafe { - asm!("cpsie f - isb") // as per ARM spec the ISB ensures triggering pending interrupts - }; + #[cfg(target_arch = "arm")] + unsafe { + asm!( + "cpsie f + isb" + ) // as per ARM spec the ISB ensures triggering pending interrupts + }; + #[cfg(target_arch = "aarch64")] + unsafe { + asm!( + "msr daifclr, #1 + isb" + ) // as per ARM spec the ISB ensures triggering pending interrupts + }; } } @@ -96,8 +163,14 @@ pub fn disable_irq() { // remember the last IRQ state let state = get_interrupt_state(); - #[cfg(target_arch="arm")] - unsafe { asm!("cpsid i") }; + #[cfg(target_arch = "arm")] + unsafe { + asm!("cpsid i") + }; + #[cfg(target_arch = "aarch64")] + unsafe { + asm!("msr daifset, #2") + }; // store the last interrupt state after interrupts have been // disabled to ensure interrupt free atomic operation @@ -111,8 +184,14 @@ pub fn disable_fiq() { // remember the last FIQ state let state = get_fault_state(); - #[cfg(target_arch="arm")] - unsafe { asm!("cpsid f") }; + #[cfg(target_arch = "arm")] + unsafe { + asm!("cpsid f") + }; + #[cfg(target_arch = "aarch64")] + unsafe { + asm!("msr daifset, #1") + }; // store the last interrupt state after interrupts have been // disabled to ensure interrupt free atomic operation @@ -121,24 +200,38 @@ pub fn disable_fiq() { #[allow(unreachable_code)] fn get_interrupt_state() -> u32 { - #[cfg(target_arch="arm")] + #[cfg(target_arch = "arm")] unsafe { let state: u32; asm!("MRS $0, CPSR":"=r"(state):::"volatile"); return state & 0x80; } + #[cfg(target_arch = "aarch64")] + unsafe { + let state: u32; + asm!("MRS $0, DAIF":"=r"(state):::"volatile"); + // irq enabled if mask bit was not set + return !((state >> 6) & 0x2); + } // for non ARM targets there is nothing implemented to get current IRQ state, so return 0 0 } #[allow(unreachable_code)] -fn get_fault_state() -> u32 { - #[cfg(target_arch="arm")] +fn get_fault_state() -> u32 { + #[cfg(target_arch = "arm")] unsafe { let state: u32; asm!("MRS $0, CPSR":"=r"(state):::"volatile"); return state & 0x40; } + #[cfg(target_arch = "aarch64")] + unsafe { + let state: u32; + asm!("MRS $0, DAIF":"=r"(state):::"volatile"); + // fiq enabled if mask bit was not set + return !((state >> 6) & 0x1); + } // for non ARM targets there is nothing implemented to get current IRQ state, so return 0 0 -} \ No newline at end of file +} diff --git a/macros/Cargo.toml b/macros/Cargo.toml index 5a7aa28..38f91c3 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "ruspiro-interrupt-macros" authors = ["Andre Borrmann "] -version = "0.2.0" # remember to update html_root_url +version = "0.2.1" # remember to update html_root_url description = """ Macros used to implement interrupt handler. !!This crate is only useful in conjunction with the `ruspiro-interrupt` crate and shall never be used standalone!! """ license = "Apache-2.0" -repository = "https://github.com/RusPiRo/ruspiro-interrupt/tree/v0.2.0" -documentation = "https://docs.rs/ruspiro-interrupt/0.2.0" +repository = "https://github.com/RusPiRo/ruspiro-interrupt/tree/v0.3.0" +documentation = "https://docs.rs/ruspiro-interrupt/0.3.0" readme = "README.md" keywords = ["RusPiRo", "baremetal", "raspberrypi", "interrupt"] categories = ["no-std", "embedded"] diff --git a/macros/src/lib.rs b/macros/src/lib.rs index b67fa7b..2b49850 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -1,67 +1,73 @@ -/*********************************************************************************************************************** +/*********************************************************************************************************************** * Copyright (c) 2019 by the authors - * - * Author: André Borrmann + * + * Author: André Borrmann * License: Apache License 2.0 **********************************************************************************************************************/ -#![doc(html_root_url = "https://docs.rs/ruspiro-interrupt-macros/0.2.0")] +#![doc(html_root_url = "https://docs.rs/ruspiro-interrupt-macros/0.2.1")] //! # Interrupt Macros -//! -//! This crate provides the custom attribute ``#[IrqHandler([, ])]`` to be used when implementing an +//! +//! This crate provides the custom attribute ``#[IrqHandler([, ])]`` to be used when implementing an //! interrupt handler. -//! +//! //! # Usage +//! +//! ```no_run +//! use ruspiro_interrupt_macros::*; //! -//! ``` //! #[IrqHandler(ArmTimer)] //! unsafe fn my_timer_handler() { //! // implement the interrupt handling here and do not forget //! // to acknowledge the interrupt in the interrupt specific registers -//! // in case of the timer interrupt it would be done like so -//! -//! TIMERIRQ::Register.set(1); //! } //! -//! define_registers! ( TIMERIRQ: WriteOnly @ 0x3F00_B40C => [] ); +//! # fn main() { } //! ``` -//! +//! //! In some rare cases the interrupt line is shared between specific interrupt sources. In this case the source of //! the interrupt need to be passed as well as an identifier. -//! ``` +//! ```no_run +//! use ruspiro_interrupt_macros::*; +//! //! #[IrqHandler(Aux, Uart1)] //! unsafe fn my_aux_uart1_handler() { //! // handle Uart1 interrupt here - this usually has no "acknowledge" register... //! } -//! ``` -//! //! +//! # fn main() { } +//! ``` +//! +//! extern crate proc_macro; -extern crate syn; extern crate quote; +extern crate syn; use proc_macro::*; -use syn::*; use quote::quote; +use syn::*; #[proc_macro_attribute] #[allow(non_snake_case)] pub fn IrqHandler(attr: TokenStream, item: TokenStream) -> TokenStream { // indicate usage of this macro in the compiler output println!("implement handler for IRQ: \"{}\"", attr.to_string()); - + let func = parse_macro_input!(item as ItemFn); - let args:AttributeArgs = parse_macro_input!(attr as AttributeArgs); + let args: AttributeArgs = parse_macro_input!(attr as AttributeArgs); let irq_name = match args.get(0) { Some(NestedMeta::Meta(Meta::Word(meta))) => meta, - _ => return syn::Error::new(syn::export::Span::call_site(), "interrupt identifier missing in `#[IrqHandler(identifier)`") - .to_compile_error() - .into(), + _ => { + return syn::Error::new( + syn::export::Span::call_site(), + "interrupt identifier missing in `#[IrqHandler(identifier)`", + ) + .to_compile_error() + .into() + } }; - - // verify the signature of the function given to the handler // the required signature may differ depending on the interrupt that shall be handled // first check the basic ones @@ -88,36 +94,38 @@ pub fn IrqHandler(attr: TokenStream, item: TokenStream) -> TokenStream { }; let aux_source_s = aux_source.to_string(); // check for valid Aux types - if &*aux_source_s != "Uart1" && - &*aux_source_s != "Spi1" && - &*aux_source_s != "Spi2" { + if &*aux_source_s != "Uart1" && &*aux_source_s != "Spi1" && &*aux_source_s != "Spi2" { return syn::Error::new(syn::export::Span::call_site(), "Wrong source for `Aux` interrupt in `#[IrqHandler(Aux, )`. could be one of: `Uart1` | `Spi1` | `Spi2`.") .to_compile_error() - .into() + .into(); } - let valid_signature = valid_common_signature - && func.decl.inputs.is_empty(); + let valid_signature = valid_common_signature && func.decl.inputs.is_empty(); if !valid_signature { - return syn::Error::new(syn::export::Span::call_site(), "interrupt handler must have signature `[unsafe] fn()`") - .to_compile_error() - .into() + return syn::Error::new( + syn::export::Span::call_site(), + "interrupt handler must have signature `[unsafe] fn()`", + ) + .to_compile_error() + .into(); } format!("{}_{}", irq_name.to_string(), aux_source.to_string()) - }, + } _ => { - let valid_signature = valid_common_signature - && func.decl.inputs.is_empty(); + let valid_signature = valid_common_signature && func.decl.inputs.is_empty(); if !valid_signature { - return syn::Error::new(syn::export::Span::call_site(), "interrupt handler must have signature `[unsafe] fn()`") + return syn::Error::new( + syn::export::Span::call_site(), + "interrupt handler must have signature `[unsafe] fn()`", + ) .to_compile_error() - .into() + .into(); } irq_name.to_string() - }, + } }; let ident = func.ident; // original function identifier @@ -139,5 +147,6 @@ pub fn IrqHandler(attr: TokenStream, item: TokenStream) -> TokenStream { #(#stmts)* } - ).into() -} \ No newline at end of file + ) + .into() +} diff --git a/makefile b/makefile index 528cc24..203b090 100644 --- a/makefile +++ b/makefile @@ -7,38 +7,29 @@ # Author: André Borrmann # License: Apache License 2.0 #****************************************************************** -CARGO_BIN = "$(USER_ROOT)\\.cargo\\bin" -ARM_GCC_BIN = "$(USER_ROOT)\\arm-gcc\\gcc-arm-eabi\\bin" -ARM_GCC_LIB = "$(USER_ROOT)\\arm-gcc\\gcc-arm-eabi\\lib\\gcc\\arm-eabi\\8.3.0" -TARGET = armv7-unknown-linux-gnueabihf -TARGETDIR = target\\armv7-unknown-linux-gnueabihf\\release -# environment variables needed by cargo xbuild to use the custom build target -export CC = arm-eabi-gcc.exe -export AR = arm-eabi-ar.exe -export CFLAGS = -std=c11 -mfpu=neon-fp-armv8 -mfloat-abi=hard -march=armv8-a -Wall -O3 -nostartfiles -ffreestanding -mtune=cortex-a53 -export PATH += "$(PROJECT_ROOT);$(ARM_GCC_BIN);$(ARM_GCC_LIB);$(CARGO_BIN)" -# build the current crate -all: -# update dependend crates to their latest version if any - cargo update -# cross compile the crate - cargo xbuild --target $(TARGET) --release +all32: export CFLAGS = -mfpu=neon-fp-armv8 -mfloat-abi=hard -march=armv8-a -Wall -O3 -nostdlib -nostartfiles -ffreestanding -mtune=cortex-a53 +all32: export RUSTFLAGS = -C linker=arm-eabi-gcc.exe -C target-cpu=cortex-a53 -C target-feature=+strict-align,+a53,+fp-armv8,+v8,+vfp3,+d16,+thumb2,+neon -C link-arg=-nostartfiles -C opt-level=3 -C debuginfo=0 +all32: export CC = arm-eabi-gcc.exe +all32: export AR = arm-eabi-ar.exe +all32: + cargo xbuild --target armv7-unknown-linux-gnueabihf --release + +all64: export CFLAGS = -march=armv8-a -Wall -O3 -nostdlib -nostartfiles -ffreestanding -mtune=cortex-a53 +all64: export RUSTFLAGS = -C linker=aarch64-elf-gcc.exe -C target-cpu=cortex-a53 -C target-feature=+strict-align,+a53,+fp-armv8,+neon -C link-arg=-nostartfiles -C opt-level=3 -C debuginfo=0 +all64: export CC = aarch64-elf-gcc.exe +all64: export AR = aarch64-elf-ar.exe +all64: + cargo xbuild --target aarch64-unknown-linux-gnu --release + +doc: export CFLAGS = -march=armv8-a -Wall -O3 -nostdlib -nostartfiles -ffreestanding -mtune=cortex-a53 +doc: export RUSTFLAGS = -C linker=aarch64-elf-gcc.exe -C target-cpu=cortex-a53 -C target-feature=+strict-align,+a53,+fp-armv8,+neon -C link-arg=-nostartfiles -C opt-level=3 -C debuginfo=0 +doc: export CC = aarch64-elf-gcc.exe +doc: export AR = aarch64-elf-ar.exe doc: - # update dependend crates to their latest version if any - cargo update # build docu for this crate using custom target - xargo doc --all --no-deps --target $(TARGET) --release --open + cargo doc --no-deps --target aarch64-unknown-linux-gnu --release --open -test: - xargo test --doc --target $(TARGET) - -publish-dry-run: - xargo publish --dry-run --target $(TARGET) - -publish: - xargo publish --target $(TARGET) - clean: cargo clean \ No newline at end of file diff --git a/src/auxhandler.rs b/src/auxhandler.rs index 6d9ad33..2342b4e 100644 --- a/src/auxhandler.rs +++ b/src/auxhandler.rs @@ -1,18 +1,18 @@ -/*********************************************************************************************************************** +/*********************************************************************************************************************** * Copyright (c) 2019 by the authors - * - * Author: André Borrmann + * + * Author: André Borrmann * License: Apache License 2.0 **********************************************************************************************************************/ //! # Aux interrupt line handler -//! +//! //! The Aux interrupt line is shared between Uart1, Spi1 and Spi2. This handler branches to the specific handler //! implementation based on the interrupt source. -//! +//! -use ruspiro_register::define_registers; +use ruspiro_register::define_mmio_register; -#[cfg(feature="ruspiro_pi3")] +#[cfg(feature = "ruspiro_pi3")] const PERIPHERAL_BASE: u32 = 0x3F00_0000; pub(crate) fn aux_handler() { @@ -30,10 +30,10 @@ pub(crate) fn aux_handler() { } } -define_registers! [ - AUX_IRQ: ReadWrite @ PERIPHERAL_BASE + 0x0021_5000 => [ +define_mmio_register! [ + AUX_IRQ@(PERIPHERAL_BASE + 0x0021_5000)> { SPI2 OFFSET(2), SPI1 OFFSET(1), UART1 OFFSET(0) - ] -]; \ No newline at end of file + } +]; diff --git a/src/interface.rs b/src/interface.rs index f427ebf..635c7af 100644 --- a/src/interface.rs +++ b/src/interface.rs @@ -1,18 +1,18 @@ -/*********************************************************************************************************************** +/*********************************************************************************************************************** * Copyright (c) 2019 by the authors - * - * Author: André Borrmann + * + * Author: André Borrmann * License: Apache License 2.0 **********************************************************************************************************************/ //! # Internal interrupt interface implementation -//! -use ruspiro_register::define_registers; +//! +use ruspiro_register::define_mmio_register; -#[cfg(feature="ruspiro_pi3")] +#[cfg(feature = "ruspiro_pi3")] const PERIPHERAL_BASE: u32 = 0x3F00_0000; -#[cfg(feature="ruspiro_pi3")] +#[cfg(feature = "ruspiro_pi3")] const ARM_CORE_BASE: u32 = 0x4000_0000; const ARM_IRQ_BASE: u32 = PERIPHERAL_BASE + 0x0000_B000; @@ -22,7 +22,11 @@ pub(crate) fn initialize() { IRQ_DISABLE_1::Register.set(0xFFFF_FFFF); IRQ_DISABLE_2::Register.set(0xFFFF_FFFF); IRQ_DISABLE_B::Register.set(0xFFFF_FFFF); - unsafe{ asm!("dmb") }; + + #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] + unsafe { + asm!("dmb sy") + }; // set the routing of GPU interrupts to core 0 GPU_INT_ROUTING::Register.set(0); @@ -57,38 +61,38 @@ pub(crate) fn deactivate(bank: u32, irq_num: u32) { pub(crate) fn get_pending_irqs() -> [u32; 3] { let pendings: [u32; 3] = [ - IRQ_PENDING_1::Register.get(), - IRQ_PENDING_2::Register.get(), - IRQ_PENDING_B::Register.get(), - ]; + IRQ_PENDING_1::Register.get(), + IRQ_PENDING_2::Register.get(), + IRQ_PENDING_B::Register.get(), + ]; pendings } -define_registers! [ - GPU_INT_ROUTING: ReadWrite @ ARM_CORE_BASE + 0x20C, +define_mmio_register! [ + GPU_INT_ROUTING@(ARM_CORE_BASE + 0x00C)>, - CORE_MB_INT_CONTROL0: ReadWrite @ ARM_CORE_BASE + 0x250, - CORE_MB_INT_CONTROL1: ReadWrite @ ARM_CORE_BASE + 0x254, - CORE_MB_INT_CONTROL2: ReadWrite @ ARM_CORE_BASE + 0x258, - CORE_MB_INT_CONTROL3: ReadWrite @ ARM_CORE_BASE + 0x25C, + CORE_MB_INT_CONTROL0@(ARM_CORE_BASE + 0x050)>, + CORE_MB_INT_CONTROL1@(ARM_CORE_BASE + 0x054)>, + CORE_MB_INT_CONTROL2@(ARM_CORE_BASE + 0x058)>, + CORE_MB_INT_CONTROL3@(ARM_CORE_BASE + 0x05C)>, - CORE_IRQ_PENDING0: ReadWrite @ ARM_CORE_BASE + 0x260, - CORE_IRQ_PENDING1: ReadWrite @ ARM_CORE_BASE + 0x264, - CORE_IRQ_PENDING2: ReadWrite @ ARM_CORE_BASE + 0x268, - CORE_IRQ_PENDING3: ReadWrite @ ARM_CORE_BASE + 0x26C, + CORE_IRQ_PENDING0@(ARM_CORE_BASE + 0x060)>, + CORE_IRQ_PENDING1@(ARM_CORE_BASE + 0x064)>, + CORE_IRQ_PENDING2@(ARM_CORE_BASE + 0x068)>, + CORE_IRQ_PENDING3@(ARM_CORE_BASE + 0x06C)>, - IRQ_PENDING_B: ReadWrite @ ARM_IRQ_BASE + 0x200, - IRQ_PENDING_1: ReadWrite @ ARM_IRQ_BASE + 0x204, - IRQ_PENDING_2: ReadWrite @ ARM_IRQ_BASE + 0x208, + IRQ_PENDING_B@(ARM_IRQ_BASE + 0x200)>, + IRQ_PENDING_1@(ARM_IRQ_BASE + 0x204)>, + IRQ_PENDING_2@(ARM_IRQ_BASE + 0x208)>, - FIQ_CONTROL: ReadWrite @ ARM_IRQ_BASE + 0x20C, + FIQ_CONTROL@(ARM_IRQ_BASE + 0x20C)>, - IRQ_ENABLE_1: ReadWrite @ ARM_IRQ_BASE + 0x210, - IRQ_ENABLE_2: ReadWrite @ ARM_IRQ_BASE + 0x214, - IRQ_ENABLE_B: ReadWrite @ ARM_IRQ_BASE + 0x218, + IRQ_ENABLE_1@(ARM_IRQ_BASE + 0x210)>, + IRQ_ENABLE_2@(ARM_IRQ_BASE + 0x214)>, + IRQ_ENABLE_B@(ARM_IRQ_BASE + 0x218)>, - IRQ_DISABLE_1: ReadWrite @ ARM_IRQ_BASE + 0x21C, - IRQ_DISABLE_2: ReadWrite @ ARM_IRQ_BASE + 0x220, - IRQ_DISABLE_B: ReadWrite @ ARM_IRQ_BASE + 0x224 -]; \ No newline at end of file + IRQ_DISABLE_1@(ARM_IRQ_BASE + 0x21C)>, + IRQ_DISABLE_2@(ARM_IRQ_BASE + 0x220)>, + IRQ_DISABLE_B@(ARM_IRQ_BASE + 0x224)> +]; diff --git a/src/irqtypes.rs b/src/irqtypes.rs index 88e2f64..449c7ab 100644 --- a/src/irqtypes.rs +++ b/src/irqtypes.rs @@ -1,14 +1,14 @@ -/*********************************************************************************************************************** +/*********************************************************************************************************************** * Copyright (c) 2019 by the authors - * - * Author: André Borrmann + * + * Author: André Borrmann * License: Apache License 2.0 **********************************************************************************************************************/ //! # Interrupt Types -//! +//! //! Defining the different possible interrupts of the Raspberry Pi a handler could be registered for. -//! +//! /// The list of available interrupts on Raspberry Pi 3. /// Note: Even if it is possible to register an interrupt handler for them the behaviour might be untested/undefined. @@ -17,54 +17,23 @@ /// #[repr(u8)] #[derive(Copy, Clone)] -pub enum Interrupt { +pub enum Interrupt { // IRQ's appearing in the GPU pending register 1 and 2 // IRQ 0 - 31 / Bank 1 (only the IRQ's that could be registered) - SystemTimer1 = 1, - SystemTimer3 = 3, - /*// Codec IRQ's - Codec0 = 4, - Codec1 = 5, - Codec2 = 6, - // JPEG - Jpeg = 7, // also avilable as IRQ 74 in basic pending - */ - // ISP - Isp = 8, + SystemTimer1 = 1, + SystemTimer3 = 3, + Isp = 8, // USB - Usb = 9, // Synopsys DesignWare Hi-Speed USB 2.0 OTG controller IRQ. Also available as IRQ 75 in basic pending - /*// 3D - ThreeD = 10, // also available as IRQ 75 in basic pending - // transponder - Transponder = 11, - */ - // multi core sync - CoreSync0 = 12, - CoreSync1 = 13, - CoreSync2 = 14, - CoreSync3 = 15, - /* - // DMA - Dma0 = 16, - Dma1 = 17, - Dma2 = 18, - Dma3 = 19, - Dma4 = 20, - Dma5 = 21, - Dma6 = 22, - Dma7 = 23, - Dma8 = 24, - Dma9 = 25, - Dma10 = 26, - Dma11 = 27, - Dma12 = 28, - */ - // UART1, SPI1, SPI2 - Aux = 29, + Usb = 9, // Synopsys DesignWare Hi-Speed USB 2.0 OTG controller IRQ. Also available as IRQ 75 in basic pending + CoreSync0 = 12, + CoreSync1 = 13, + CoreSync2 = 14, + CoreSync3 = 15, + Aux = 29, // ARM - Arm = 30, + Arm = 30, // GPU-DMA - GpuDma = 31, + GpuDma = 31, // IRQ 32 - 63 / Bank 2 /*HostPort = 32, @@ -85,31 +54,23 @@ pub enum Interrupt { Cpr = 47, Smi = 48, */ - GpioBank0 = 49, // GPIO Bank 0 - GpioBank1 = 50, - GpioBank2 = 51, // Not existend at BCM2837??? - GpioBank3 = 52, - I2c = 53, // also available as IRQ 79 in basic pending - Spi = 54, // also available as IRQ 80 in basic pending - I2sPcm = 55, // also available as IRQ 81 in basic pending - Sdio = 56, // also available as IRQ 82 in basic pending - Pl011 = 57, // also avialable as IRQ 83 in basic pending - /*SlimBus = 58, - Vec = 59, - Cpg = 60, - Rng = 61, - Sdhci = 62, // also available as IRQ 84 in basic pending - AvsPmon = 63, -*/ - // IRQ 64 - 84 / bank basic pending - ArmTimer = 64, - ArmMailbox = 65, - ArmDoorbell0 = 66, - ArmDoorbell1 = 67, - ArmGpu0Halted = 68, - ArmGpu1halted = 69, + GpioBank0 = 49, // GPIO Bank 0 + GpioBank1 = 50, + GpioBank2 = 51, // Not existend at BCM2837??? + GpioBank3 = 52, + I2c = 53, // also available as IRQ 79 in basic pending + Spi = 54, // also available as IRQ 80 in basic pending + I2sPcm = 55, // also available as IRQ 81 in basic pending + Sdio = 56, // also available as IRQ 82 in basic pending + Pl011 = 57, // also avialable as IRQ 83 in basic pending + ArmTimer = 64, + ArmMailbox = 65, + ArmDoorbell0 = 66, + ArmDoorbell1 = 67, + ArmGpu0Halted = 68, + ArmGpu1halted = 69, ArmIllegalType1 = 70, ArmIllegalType0 = 71, - ArmPending1 = 72, - ArmPending2 = 73, + ArmPending1 = 72, + ArmPending2 = 73, } diff --git a/src/lib.rs b/src/lib.rs index 175dec5..bcee5ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,56 +1,68 @@ -/*********************************************************************************************************************** +/*********************************************************************************************************************** * Copyright (c) 2019 by the authors - * - * Author: André Borrmann + * + * Author: André Borrmann * License: Apache License 2.0 **********************************************************************************************************************/ -#![doc(html_root_url = "https://docs.rs/ruspiro-interrupt/0.2.1")] +#![doc(html_root_url = "https://docs.rs/ruspiro-interrupt/0.3.0")] #![no_std] #![feature(asm)] #![feature(linkage)] //! # Interrupt handler for Raspberry Pi -//! -//! This crates provides functions and macros (custom attribute) to conviniently implement interrupt handler for +//! +//! This crates provides functions and macros (custom attribute) to conviniently implement interrupt handler for //! Raspberry Pi 3. The possible interrupts a handler can be implemented for are available as enum [irqtypes::Interrupt] -//! +//! //! # Usage -//! -//! ``` +//! +//! ```no_run //! extern crate ruspiro_interrupt; // <- this kind of usage is VERY IMPORTANT to ensure linking works as expected! //! use ruspiro_interrupt::*; -//! +//! //! #[IrqHandler(ArmTimer)] //! fn timer_handler() { -//! // TODO: acknowledge the irq -//! +//! // IMPORTANT: acknowledge the irq ! +//! //! // implement stuff that shall be executed if the interrupt is raised... -//! // be careful when this code uses spinlocks as this might lead to dead-locks if the +//! // be careful when this code uses spinlocks as this might lead to dead-locks if the //! // executing code interrupted currently helds a lock the code inside this handler tries to aquire the same one -//! println!("timer interrupt raised"); //! } -//! -//! fn doc() { +//! +//! fn main() { //! // as we have an interrupt handler defined we need to enable interrupt handling globally as well //! // as the specific interrupt we have a handler implemented for //! IRQ_MANAGER.take_for(|irq_mgr| { -//! irq_mgr.enable(); -//! irq_mgr.activate(Interrupt.ArmTimer); +//! irq_mgr.initialize(); +//! irq_mgr.activate(Interrupt::ArmTimer); +//! irq_mgr.activate(Interrupt::Aux); //! }); +//! +//! enable_interrupts(); //! } //! ``` -//! +//! //! In some cases the interrupt type/line is shared between different sources. In those cases a handler need to be //! implemented for the specific interrupt source. The source is given in the custom attribute like this: -//! ``` +//! +//! ```no_run +//! extern crate ruspiro_interrupt; // <- this kind of usage is VERY IMPORTANT to ensure linking works as expected! +//! use ruspiro_interrupt::*; +//! //! #[IrqHandler(Aux, Uart1)] //! fn aux_uart1_handler() { //! // implement Uart1 interrupt handler here //! } +//! +//! # fn main() { +//! # } //! ``` +//! +//! # Limitations +//! //! However, only a limited ammount of shared interrupts is available with the current version - which is only the **Aux** //! interrupt at the moment. -//! +//! extern crate alloc; extern crate paste; @@ -62,8 +74,8 @@ pub use irqtypes::*; use ruspiro_singleton::Singleton; -mod interface; mod auxhandler; +mod interface; use alloc::vec::*; @@ -76,10 +88,8 @@ pub struct InterruptManager { } impl InterruptManager { - pub(crate) const fn new () -> Self { - InterruptManager { - enabled: [0; 3], - } + pub(crate) const fn new() -> Self { + InterruptManager { enabled: [0; 3] } } /// One time interrupt manager initialization. This performs the initial configuration and deactivates all IRQs @@ -95,13 +105,15 @@ impl InterruptManager { pub fn activate(&mut self, irq: Interrupt) { let irq_num = irq as u32; let irq_bank = irq_num >> 5; - - interface::activate(irq_bank, irq_num); - + self.enabled[irq_bank as usize] |= 1 << (irq_num & 0x1F); + + interface::activate(irq_bank, irq_num); //println!("enabled Irq's: {:X}, {:X}, {:X}", self.enabled[0], self.enabled[1], self.enabled[2]); - #[cfg(target_arch="arm")] - unsafe{ asm!("dmb") }; + #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] + unsafe { + asm!("dmb sy") + }; } /// deactivate a specific interrupt from beeing raised. This ensures the handler will also not getting called any @@ -111,10 +123,12 @@ impl InterruptManager { let irq_bank = irq_num >> 5; interface::deactivate(irq_bank, irq_num); - + self.enabled[irq_bank as usize] &= !(1 << (irq_num & 0x1F)); - #[cfg(target_arch="arm")] - unsafe{ asm!("dmb") }; + #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] + unsafe { + asm!("dmb sy") + }; } } @@ -122,6 +136,203 @@ impl InterruptManager { * Functions that need to be exported, this seem not to work if they are part of of a child * module, so define them here ********************************************************************************************/ +#[allow(dead_code)] +#[repr(u32)] +enum ExceptionType { + CurrentElSp0Sync = 0x01, + CurrentElSp0Irq = 0x02, + CurrentElSp0Fiq = 0x03, + CurrentElSp0SErr = 0x04, + + CurrentElSpxSync = 0x11, + CurrentElSpxIrq = 0x12, + CurrentElSpxFiq = 0x13, + CurrentElSpxSErr = 0x14, + + LowerEl64SpxSync = 0x21, + LowerEl64SpxIrq = 0x22, + LowerEl64SpxFiq = 0x23, + LowerEl64SpxSErr = 0x24, + + LowerEl32SpxSync = 0x31, + LowerEl32SpxIrq = 0x32, + LowerEl32SpxFiq = 0x33, + LowerEl32SpxSErr = 0x34, + + A32UndefInstruction = 0x50, + A32SoftwareInterrupt = 0x51, + A32PrefetchAbort = 0x52, + A32DataAbort = 0x53, + A32Irq = 0x54, + A32Fiq = 0x55, +} + +/// The default exception handler. +/// This is the entry point for any exception taken at any core. The type gives the hint on what +/// the exyception is about, sync, irq, etc. This entry point is called from the ``ruspiro-boot`` +/// crate when this is used for bootstrapping. Otherwise the custom bootstrapping need to properly +/// setup the exception table and call this entry point with the required input +/// +#[cfg(target_arch = "aarch64")] +#[no_mangle] +unsafe fn __exception_handler_default( + exception: ExceptionType, + _esr: u64, + _spsr: u64, + _far: u64, + _elr: u64, +) { + match exception { + ExceptionType::CurrentElSp0Irq => interrupt_handler(), + ExceptionType::CurrentElSp0Fiq => interrupt_handler(), + ExceptionType::CurrentElSpxIrq => interrupt_handler(), + ExceptionType::CurrentElSpxFiq => interrupt_handler(), + _ => (), + } +} + +#[cfg(target_arch = "arm")] +#[no_mangle] +unsafe fn __exception_handler_default( + exception: ExceptionType, + _spsr: u32, + _sp_irq: u32, + _lr_irq: u32, +) { + match exception { + ExceptionType::A32Irq => interrupt_handler(), + ExceptionType::A32Fiq => interrupt_handler(), + _ => (), + } +} + +/// Entry point for interrupt handling. This function dispatches the detected interrupt to the +/// elsewhere implemented dedicated handlers. Those handlers should be tagged with the ``IrqHandler`` +/// attribute +#[allow(dead_code)] +fn interrupt_handler() { + // first globally store that we are inside an interrupt handler + entering_interrupt_handler(); + + // now retrieve the pending interrupts + let pendings = interface::get_pending_irqs(); + + // from the pending interrupts filter the active ones + let active = IRQ_MANAGER.use_for(|mgr| { + [ + mgr.enabled[0] & pendings[0], + mgr.enabled[1] & pendings[1], + mgr.enabled[2] & pendings[2], + ] + }); + + // now that we have the active interrupts we can dispatch to the dedicated handlers + if active[0] != 0 { + // IRQ Bank 1 + if active[0] & (1 << 1) != 0 { + __irq_handler__SystemTimer1() + } + if active[0] & (1 << 3) != 0 { + __irq_handler__SystemTimer3() + } + if active[0] & (1 << 8) != 0 { + __irq_handler__Isp() + } + if active[0] & (1 << 9) != 0 { + __irq_handler__Usb() + } + if active[0] & (1 << 12) != 0 { + __irq_handler__CoreSync0() + } + if active[0] & (1 << 13) != 0 { + __irq_handler__CoreSync1() + } + if active[0] & (1 << 14) != 0 { + __irq_handler__CoreSync2() + } + if active[0] & (1 << 15) != 0 { + __irq_handler__CoreSync3() + } + if active[0] & (1 << 29) != 0 { + auxhandler::aux_handler() + } + if active[0] & (1 << 30) != 0 { + __irq_handler__Arm() + } + if active[0] & (1 << 31) != 0 { + __irq_handler__GpuDma() + } + } + + if active[1] != 0 { + // IRQ Bank 2 + if active[1] & (1 << 49 - 32) != 0 { + __irq_handler__GpioBank0() + } + if active[1] & (1 << 50 - 32) != 0 { + __irq_handler__GpioBank1() + } + if active[1] & (1 << 51 - 32) != 0 { + __irq_handler__GpioBank2() + } + if active[1] & (1 << 52 - 32) != 0 { + __irq_handler__GpioBank3() + } + if active[1] & (1 << 53 - 32) != 0 { + __irq_handler__I2c() + } + if active[1] & (1 << 54 - 32) != 0 { + __irq_handler__Spi() + } + if active[1] & (1 << 55 - 32) != 0 { + __irq_handler__I2sPcm() + } + if active[1] & (1 << 56 - 32) != 0 { + __irq_handler__Sdio() + } + if active[1] & (1 << 57 - 32) != 0 { + __irq_handler__Pl011() + } + } + + if active[2] != 0 { + // IRQ Bank Basic + if active[2] & (1 << (64 - 64)) != 0 { + __irq_handler__ArmTimer() + } + if active[2] & (1 << (65 - 64)) != 0 { + __irq_handler__ArmMailbox() + } + if active[2] & (1 << (66 - 64)) != 0 { + __irq_handler__ArmDoorbell0() + } + if active[2] & (1 << (67 - 64)) != 0 { + __irq_handler__ArmDoorbell1() + } + if active[2] & (1 << (68 - 64)) != 0 { + __irq_handler__ArmGpu0Halted() + } + if active[2] & (1 << (69 - 64)) != 0 { + __irq_handler__ArmGpu1Halted() + } + if active[2] & (1 << (70 - 64)) != 0 { + __irq_handler__ArmIllegalType1() + } + if active[2] & (1 << (71 - 64)) != 0 { + __irq_handler__ArmIllegalType0() + } + if active[2] & (1 << (72 - 64)) != 0 { + __irq_handler__ArmPending1() + } + if active[2] & (1 << (73 - 64)) != 0 { + __irq_handler__ArmPending2() + } + } + + // when we are done store that we are leaving an interrupt handler + leaving_interrupt_handler(); +} + /// The IRQ handling entry point. This entrypoint is maintained by the ``rusprio-boot`` crate and points to /// an empty implementation using a linker script "magic". Once interrupts are globally enabled and specific /// interrupts has been activated this entry point will be called wheneever an interrupt occurs. The @@ -129,6 +340,7 @@ impl InterruptManager { /// done somewhere else #[no_mangle] unsafe fn __interrupt_h(_core: u32) { + entering_interrupt_handler(); IRQ_MANAGER.use_for(|mgr| { // check wheter the interrupt in a pending register really has been activiated let pendings: [u32; 3] = interface::get_pending_irqs(); @@ -136,60 +348,64 @@ unsafe fn __interrupt_h(_core: u32) { // build a list of interrupt id's based on the bit's set in the 3 irq enable banks let active_irqs: Vec = (0..).zip(&pendings).fold(Vec::new(), |acc, p| { - acc - .into_iter() - .chain( - set_bits_to_vec( - (*p.1) & mgr.enabled[p.0 as usize], p.0*32) - ) + acc.into_iter() + .chain(set_bits_to_vec( + (*p.1) & mgr.enabled[p.0 as usize], + p.0 * 32, + )) .collect() }); for id in active_irqs { match id { - 1 => __irq_handler__SystemTimer1(), - 3 => __irq_handler__SystemTimer3(), - 8 => __irq_handler__Isp(), - 9 => __irq_handler__Usb(), - 12 => __irq_handler__CoreSync0(), - 13 => __irq_handler__CoreSync1(), - 14 => __irq_handler__CoreSync2(), - 15 => __irq_handler__CoreSync3(), - 29 => auxhandler::aux_handler(), - 30 => __irq_handler__Arm(), - 31 => __irq_handler__GpuDma(), - 49 => __irq_handler__GpioBank0(), - 50 => __irq_handler__GpioBank1(), - 51 => __irq_handler__GpioBank2(), - 52 => __irq_handler__GpioBank3(), - 53 => __irq_handler__I2c(), - 54 => __irq_handler__Spi(), - 55 => __irq_handler__I2sPcm(), - 56 => __irq_handler__Sdio(), - 57 => __irq_handler__Pl011(), - 64 => __irq_handler__ArmTimer(), - 65 => __irq_handler__ArmMailbox(), - 66 => __irq_handler__ArmDoorbell0(), - 67 => __irq_handler__ArmDoorbell1(), - 68 => __irq_handler__ArmGpu0Halted(), - 69 => __irq_handler__ArmGpu1Halted(), - 70 => __irq_handler__ArmIllegalType1(), - 71 => __irq_handler__ArmIllegalType0(), - 72 => __irq_handler__ArmPending1(), - 73 => __irq_handler__ArmPending2(), - - _ => __irq_handler_Default() + 1 => __irq_handler__SystemTimer1(), + 3 => __irq_handler__SystemTimer3(), + 8 => __irq_handler__Isp(), + 9 => __irq_handler__Usb(), + 12 => __irq_handler__CoreSync0(), + 13 => __irq_handler__CoreSync1(), + 14 => __irq_handler__CoreSync2(), + 15 => __irq_handler__CoreSync3(), + 29 => auxhandler::aux_handler(), + 30 => __irq_handler__Arm(), + 31 => __irq_handler__GpuDma(), + 49 => __irq_handler__GpioBank0(), + 50 => __irq_handler__GpioBank1(), + 51 => __irq_handler__GpioBank2(), + 52 => __irq_handler__GpioBank3(), + 53 => __irq_handler__I2c(), + 54 => __irq_handler__Spi(), + 55 => __irq_handler__I2sPcm(), + 56 => __irq_handler__Sdio(), + 57 => __irq_handler__Pl011(), + 64 => __irq_handler__ArmTimer(), + 65 => __irq_handler__ArmMailbox(), + 66 => __irq_handler__ArmDoorbell0(), + 67 => __irq_handler__ArmDoorbell1(), + 68 => __irq_handler__ArmGpu0Halted(), + 69 => __irq_handler__ArmGpu1Halted(), + 70 => __irq_handler__ArmIllegalType1(), + 71 => __irq_handler__ArmIllegalType0(), + 72 => __irq_handler__ArmPending1(), + 73 => __irq_handler__ArmPending2(), + + _ => __irq_handler_Default(), } } }); + leaving_interrupt_handler(); } fn set_bits_to_vec(value: u32, base: u8) -> Vec { let mut v: Vec = Vec::with_capacity(32); let mut check = value; for idx in 0..32 { - if check == 0 { break; } - if (check & 0x1) != 0 { v.push(idx + base); } + if check == 0 { + break; + } + if (check & 0x1) != 0 { + v.push(idx + base); + } check >>= 1; } @@ -203,7 +419,7 @@ macro_rules! default_handler_impl { #[linkage="weak"] #[no_mangle] extern "C" fn [<__irq_handler__ $name>](){ - __irq_handler_Default(); + //__irq_handler_Default(); } } )*}; @@ -246,6 +462,4 @@ default_handler_impl![ #[allow(non_snake_case)] #[no_mangle] -fn __irq_handler_Default() { - -} +fn __irq_handler_Default() {} diff --git a/travis-build.sh b/travis-build.sh deleted file mode 100644 index 80771e4..0000000 --- a/travis-build.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -set -ev - -export CFLAGS='-mfpu=neon-fp-armv8 -mfloat-abi=hard -march=armv8-a -Wall -O3 -nostdlib -nostartfiles -ffreestanding -mtune=cortex-a53' -export RUSTFLAGS='-C linker=arm-linux-gnueabihf-gcc -C target-cpu=cortex-a53 -C target-feature=+a53,+fp-armv8,+v8,+vfp3,+d16,+thumb2,+neon -C link-arg=-nostartfiles -C opt-level=3 -C debuginfo=0' - -cargo xbuild --target armv7-unknown-linux-gnueabihf --verbose --release --all \ No newline at end of file