diff --git a/aarch32-cpu/src/lib.rs b/aarch32-cpu/src/lib.rs index 5303b432..4e411d39 100644 --- a/aarch32-cpu/src/lib.rs +++ b/aarch32-cpu/src/lib.rs @@ -235,3 +235,193 @@ macro_rules! svc6 { retval } } } + +/// Generate an HVC call with the given argument. +#[macro_export] +macro_rules! hvc { + ($r0:expr) => { + unsafe { + core::arch::asm!("hvc {arg}", arg = const $r0); + } + } +} + +/// Generate an HVC call with 1 parameters +/// +/// Puts the first argument in the instruction, and the parameter in r0. Gives you back +/// the value left in `r0` by the handler. +/// +/// ```rust,ignore +/// const HYPERCALL_FOO: u32 = 0x100; +/// let result = hvc1!(0x00, HYPERCALL_FOO); +/// ``` +#[macro_export] +macro_rules! hvc1 { + ($num:expr, $arg0:expr) => { { + let retval: u32; + let arg0: u32 = $arg0; + unsafe { + core::arch::asm!( + // Do the Hyper-call + "hvc {arg}", + arg = const $num, + inout("r0") arg0 => retval); + } + retval + } } +} + +/// Generate an HVC call with 2 parameters +/// +/// Puts the first argument in the instruction, and the parameters in r0-r1. Gives you back +/// the value left in `r0` by the handler. +/// +/// ```rust,ignore +/// const HYPERCALL_FOO: u32 = 0x100; +/// let result = hvc2!(0x00, HYPERCALL_FOO, 1); +/// ``` +#[macro_export] +macro_rules! hvc2 { + ($num:expr, $arg0:expr, $arg1:expr) => { { + let retval: u32; + let arg0: u32 = $arg0; + let arg1: u32 = $arg1; + unsafe { + core::arch::asm!( + // Do the Hyper-call + "hvc {arg}", + arg = const $num, + inout("r0") arg0 => retval, + in("r1") arg1); + } + retval + } } +} + +/// Generate an HVC call with 3 parameters +/// +/// Puts the first argument in the instruction, and the parameters in r0-r2. Gives you back +/// the value left in `r0` by the handler. +/// +/// ```rust,ignore +/// const HYPERCALL_FOO: u32 = 0x100; +/// let result = hvc3!(0x00, HYPERCALL_FOO, 1, 2); +/// ``` +#[macro_export] +macro_rules! hvc3 { + ($num:expr, $arg0:expr, $arg1:expr, $arg2:expr) => { { + let retval: u32; + let arg0: u32 = $arg0; + let arg1: u32 = $arg1; + let arg2: u32 = $arg2; + unsafe { + core::arch::asm!( + // Do the Hyper-call + "hvc {arg}", + arg = const $num, + inout("r0") arg0 => retval, + in("r1") arg1, + in("r2") arg2); + } + retval + } } +} + +/// Generate an HVC call with 4 parameters +/// +/// Puts the first argument in the instruction, and the parameters in r0-r3. Gives you back +/// the value left in `r0` by the handler. +/// +/// ```rust,ignore +/// const HYPERCALL_FOO: u32 = 0x100; +/// let result = hvc4!(0x00, HYPERCALL_FOO, 1, 2, 3); +/// ``` +#[macro_export] +macro_rules! hvc4 { + ($num:expr, $arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr) => { { + let retval: u32; + let arg0: u32 = $arg0; + let arg1: u32 = $arg1; + let arg2: u32 = $arg2; + let arg3: u32 = $arg3; + unsafe { + core::arch::asm!( + // Do the Hyper-call + "hvc {arg}", + arg = const $num, + inout("r0") arg0 => retval, + in("r1") arg1, + in("r2") arg2, + in("r3") arg3); + } + retval + } } +} + +/// Generate an HVC call with 5 parameters +/// +/// Puts the first argument in the instruction, and the parameters in r0-r4. Gives you back +/// the value left in `r0` by the handler. +/// +/// ```rust,ignore +/// const HYPERCALL_FOO: u32 = 0x100; +/// let result = hvc5!(0x00, HYPERCALL_FOO, 1, 2, 3, 4); +/// ``` +#[macro_export] +macro_rules! hvc5 { + ($num:expr, $arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr) => { { + let retval: u32; + let arg0: u32 = $arg0; + let arg1: u32 = $arg1; + let arg2: u32 = $arg2; + let arg3: u32 = $arg3; + let arg4: u32 = $arg4; + unsafe { + core::arch::asm!( + // Do the Hyper-call + "hvc {arg}", + arg = const $num, + inout("r0") arg0 => retval, + in("r1") arg1, + in("r2") arg2, + in("r3") arg3, + in("r4") arg4); + } + retval + } } +} + +/// Generate an HVC call with 6 parameters +/// +/// Puts the first argument in the instruction, and the parameters in r0-r5. Gives you back +/// the value left in `r0` by the handler. +/// +/// ```rust,ignore +/// const HYPERCALL_FOO: u32 = 0x100; +/// let result = hvc6!(0x00, HYPERCALL_FOO, 1, 2, 3, 4, 5); +/// ``` +#[macro_export] +macro_rules! hvc6 { + ($num:expr, $arg0:expr, $arg1:expr, $arg2:expr, $arg3:expr, $arg4:expr, $arg5:expr) => { { + let retval: u32; + let arg0: u32 = $arg0; + let arg1: u32 = $arg1; + let arg2: u32 = $arg2; + let arg3: u32 = $arg3; + let arg4: u32 = $arg4; + let arg5: u32 = $arg5; + unsafe { + core::arch::asm!( + // Do the Hyper-call + "hvc {arg}", + arg = const $num, + inout("r0") arg0 => retval, + in("r1") arg1, + in("r2") arg2, + in("r3") arg3, + in("r4") arg4, + in("r5") arg5); + } + retval + } } +} diff --git a/aarch32-cpu/src/register/armv8r/hsr.rs b/aarch32-cpu/src/register/armv8r/hsr.rs index 0075256e..40c2fe8f 100644 --- a/aarch32-cpu/src/register/armv8r/hsr.rs +++ b/aarch32-cpu/src/register/armv8r/hsr.rs @@ -2,11 +2,64 @@ use crate::register::{SysReg, SysRegRead, SysRegWrite}; +use arbitrary_int::u25; + /// HSR (*Hyp Syndrome Register*) -#[derive(Debug, Copy, Clone)] +#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))] +pub struct Hsr { + /// Exception Class. + /// + /// Indicates the reason for the exception that this register holds + /// information about. + #[bits(26..=31, rw)] + ec: Option, + /// Instruction length bit. + /// + /// Indicates the size of the instruction that has been trapped to Hyp mode. + #[bit(25, rw)] + il: InstructionLength, + /// Instruction Specific Syndrome. + /// + /// Architecturally, this field can be defined independently for each + /// defined Exception class. However, in practice, some ISS encodings are + /// used for more than one Exception class. + #[bits(0..=24, rw)] + iss: u25, +} + +#[bitbybit::bitenum(u6, exhaustive = false)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Hsr(pub u32); +#[derive(Debug, PartialEq, Eq)] +pub enum ExceptionClass { + Unknown = 0b00_0000, + TrappedWfiWfe = 0b00_0001, + TrappedCp15McrMrc = 0b00_0011, + TrappedCp15McrrMrrc = 0b00_0100, + TrappedCp14McrMrc = 0b00_0101, + TrappedLdcStc = 0b00_0110, + TrappedFpu = 0b00_0111, + TrappedVmrs = 0b00_1000, + TrappedCp14McrrMrrc = 0b00_1100, + IllegalAArch32Eret = 0b00_1110, + Svc = 0b01_0001, + Hvc = 0b01_0010, + Smc = 0b01_0011, + PrefetchAbortFromLower = 0b10_0000, + PrefetchAbortFromCurrent = 0b10_0001, + PcAlignment = 0b10_0010, + DataAbortFromLower = 0b10_0100, + DataAbortFromCurrent = 0b10_0101, +} + +#[bitbybit::bitenum(u1, exhaustive = true)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, PartialEq, Eq)] +pub enum InstructionLength { + SixteenBit = 0b0, + ThirtyTwoBit = 0b1, +} impl SysReg for Hsr { const CP: u32 = 15; @@ -22,7 +75,7 @@ impl Hsr { #[inline] /// Reads HSR (*Hyp Syndrome Register*) pub fn read() -> Hsr { - unsafe { Self(::read_raw()) } + unsafe { Self::new_with_raw_value(::read_raw()) } } } @@ -37,7 +90,7 @@ impl Hsr { /// Ensure that this value is appropriate for this register pub unsafe fn write(value: Self) { unsafe { - ::write_raw(value.0); + ::write_raw(value.raw_value()); } } } diff --git a/aarch32-rt-macros/src/lib.rs b/aarch32-rt-macros/src/lib.rs index 869946e2..e290dc04 100644 --- a/aarch32-rt-macros/src/lib.rs +++ b/aarch32-rt-macros/src/lib.rs @@ -114,6 +114,7 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { enum Exception { Undefined, SupervisorCall, + HypervisorCall, PrefetchAbort, DataAbort, Irq, @@ -124,6 +125,7 @@ impl std::fmt::Display for Exception { match self { Exception::Undefined => write!(f, "Undefined"), Exception::SupervisorCall => write!(f, "SupervisorCall"), + Exception::HypervisorCall => write!(f, "HypervisorCall"), Exception::PrefetchAbort => write!(f, "PrefetchAbort"), Exception::DataAbort => write!(f, "DataAbort"), Exception::Irq => write!(f, "Irq"), @@ -163,6 +165,7 @@ impl std::fmt::Display for Exception { /// /// * Undefined (creates `_undefined_handler`) /// * SupervisorCall (creates `_svc_handler`) +/// * HypervisorCall (creates `_hvc_handler`) /// * PrefetchAbort (creates `_prefetch_abort_handler`) /// * DataAbort (creates `_data_abort_handler`) /// * Irq (creates `_irq_handler`) - although people should prefer `#[irq]`. @@ -265,6 +268,7 @@ fn handle_vector(args: TokenStream, input: TokenStream, kind: VectorKind) -> Tok Exception::Undefined } "SupervisorCall" => Exception::SupervisorCall, + "HypervisorCall" => Exception::HypervisorCall, "PrefetchAbort" => { if !returns_never && f.sig.unsafety.is_none() { return parse::Error::new( @@ -403,6 +407,21 @@ fn handle_vector(args: TokenStream, input: TokenStream, kind: VectorKind) -> Tok } ) } + // extern "C" fn _hvc_handler(arg: u32, args: &Frame) -> u32; + Exception::HypervisorCall => { + let tramp_ident = Ident::new("__aarch32_rt_hvc_handler", Span::call_site()); + quote!( + #(#cfgs)* + #(#attrs)* + #[doc(hidden)] + #[export_name = "_hvc_handler"] + pub unsafe extern "C" fn #tramp_ident(hsr: u32, frame: &aarch32_rt::Frame) -> u32 { + #f + + #func_name(hsr, frame) + } + ) + } // extern "C" fn _irq_handler(addr: usize); Exception::Irq => { let tramp_ident = Ident::new("__aarch32_rt_irq_handler", Span::call_site()); diff --git a/aarch32-rt/link.x b/aarch32-rt/link.x index 29dc2597..bff28f54 100644 --- a/aarch32-rt/link.x +++ b/aarch32-rt/link.x @@ -140,6 +140,7 @@ PROVIDE(_pack_stacks = 0); /* set this to 1 to remove the filler section pushing PROVIDE(_start = _default_start); PROVIDE(_asm_undefined_handler = _asm_default_undefined_handler); PROVIDE(_asm_svc_handler = _asm_default_svc_handler); +PROVIDE(_asm_hvc_handler = _asm_default_hvc_handler); PROVIDE(_asm_prefetch_abort_handler = _asm_default_prefetch_abort_handler); PROVIDE(_asm_data_abort_handler = _asm_default_data_abort_handler); PROVIDE(_asm_irq_handler = _asm_default_irq_handler); @@ -148,6 +149,7 @@ PROVIDE(_asm_fiq_handler = _asm_default_fiq_handler); /* Weak aliases for C default handlers */ PROVIDE(_undefined_handler = _default_handler); PROVIDE(_svc_handler = _default_handler); +PROVIDE(_hvc_handler = _default_handler); PROVIDE(_prefetch_abort_handler = _default_handler); PROVIDE(_data_abort_handler = _default_handler); PROVIDE(_irq_handler = _default_handler); diff --git a/aarch32-rt/src/arch_v4/hvc.rs b/aarch32-rt/src/arch_v4/hvc.rs new file mode 100644 index 00000000..58f2b106 --- /dev/null +++ b/aarch32-rt/src/arch_v4/hvc.rs @@ -0,0 +1,18 @@ +//! Dummy hypervisor handler for architectures without HYP mode + +#[cfg(target_arch = "arm")] +core::arch::global_asm!( + r#" + // Work around https://github.com/rust-lang/rust/issues/127269 + .fpu vfp2 + + // Never called but makes the linker happy + .section .text._asm_default_hvc_handler + .arm + .global _asm_default_hvc_handler + .type _asm_default_hvc_handler, %function + _asm_default_hvc_handler: + b . + .size _asm_default_hvc_handler, . - _asm_default_hvc_handler + "#, +); diff --git a/aarch32-rt/src/arch_v4/mod.rs b/aarch32-rt/src/arch_v4/mod.rs index 31d1bdee..adca5cbe 100644 --- a/aarch32-rt/src/arch_v4/mod.rs +++ b/aarch32-rt/src/arch_v4/mod.rs @@ -1,6 +1,7 @@ //! ASM routines for Armv4 to Armv6 mod abort; +mod hvc; mod interrupt; mod svc; mod undefined; diff --git a/aarch32-rt/src/arch_v7/hvc.rs b/aarch32-rt/src/arch_v7/hvc.rs new file mode 100644 index 00000000..35474984 --- /dev/null +++ b/aarch32-rt/src/arch_v7/hvc.rs @@ -0,0 +1,56 @@ +//! HVC handler for Armv7 and higher + +#[cfg(target_arch = "arm")] +#[cfg(arm_architecture = "v8-r")] +core::arch::global_asm!( + r#" + // Work around https://github.com/rust-lang/rust/issues/127269 + .fpu vfp3 + + .section .text._asm_default_hvc_handler + + // Called from the vector table when we have an hypervisor call. + // Saves state and calls a C-compatible handler like + // `extern "C" fn _hvc_handler(hsr: u32, frame: &Frame) -> u32;` + .global _asm_default_hvc_handler + .type _asm_default_hvc_handler, %function + _asm_default_hvc_handler: + push {{ r12, lr }} // push state to stack + push {{ r0-r5 }} // push frame to stack + mov r12, sp // r12 = pointer to Frame + "#, + crate::save_fpu_context!(), + r#" + mrc p15, 4, r0, c5, c2, 0 // r0 = HSR value + mov r1, r12 // r1 = frame pointer + bl _hvc_handler + mov r12, r0 + "#, + crate::restore_fpu_context!(), + r#" + pop {{ r0-r5 }} // restore frame + mov r0, r12 // replace return value + pop {{ r12, lr }} // pop state from stack + eret // Return from the asm handler + .size _asm_default_hvc_handler, . - _asm_default_hvc_handler + "#, +); + +#[cfg(target_arch = "arm")] +#[cfg(not(arm_architecture = "v8-r"))] +core::arch::global_asm!( + r#" + // Work around https://github.com/rust-lang/rust/issues/127269 + .fpu vfp2 + + + // Never called but makes the linker happy + .section .text._asm_default_hvc_handler + .arm + .global _asm_default_hvc_handler + .type _asm_default_hvc_handler, %function + _asm_default_hvc_handler: + b . + .size _asm_default_hvc_handler, . - _asm_default_hvc_handler + "#, +); diff --git a/aarch32-rt/src/arch_v7/mod.rs b/aarch32-rt/src/arch_v7/mod.rs index 4305d27c..df4fcf19 100644 --- a/aarch32-rt/src/arch_v7/mod.rs +++ b/aarch32-rt/src/arch_v7/mod.rs @@ -1,6 +1,7 @@ //! ASM routines for for Armv7 and higher mod abort; +mod hvc; mod interrupt; mod svc; mod undefined; diff --git a/aarch32-rt/src/lib.rs b/aarch32-rt/src/lib.rs index 1393eb1f..0ca26461 100644 --- a/aarch32-rt/src/lib.rs +++ b/aarch32-rt/src/lib.rs @@ -201,8 +201,7 @@ //! cannot control where execution resumes. The function is passed the literal //! integer argument to the `svc` instruction, which is extracted from the //! machine code for you by the default assembly trampoline, along with -//! registers r0 through r7, in the form of a reference to a `Frame` -//! structure. +//! registers r0 through r5, in the form of a reference to a `Frame` structure. //! //! Our linker script PROVIDEs a default `_svc_handler` symbol which is an alias //! for the `_default_handler` function. You can override it by defining your @@ -229,6 +228,52 @@ //! } //! ``` //! +//! ### Hypervisor Call Handler +//! +//! The symbol `_hvc_handler` should be an `extern "C"` function. It is called +//! in HYP mode when an [Hypervisor Call Exception] occurs. +//! +//! [Hypervisor Call Exception]: +//! https://developer.arm.com/documentation/ddi0406/c/System-Level-Architecture/The-System-Level-Programmers--Model/Exception-descriptions/Hypervisor-Call--HVC--exception?lang=en +//! +//! Returning from this function will cause execution to resume at the function +//! the triggered the exception, immediately after the HVC instruction. You +//! cannot control where execution resumes. The function is passed contents of +//! the Hypervisor Syndrome Register (HSR) register, which is fetched by the +//! default assembly trampoline, along with registers r0 through r5, in the form +//! of a reference to a `Frame` structure. +//! +//! Our linker script PROVIDEs a default `_hvc_handler` symbol which is an alias +//! for the `_default_handler` function. You can override it by defining your +//! own `_hvc_handler` function, like: +//! +//! ```rust +//! #[unsafe(no_mangle)] +//! extern "C" fn _hvc_handler(hsr: u32, frame: &aarch32_rt::Frame) -> u32 { +//! // do stuff here +//! todo!() +//! } +//! ``` +//! +//! You can also create a `_hvc_handler` function by using the +//! `#[exception(HypervisorCall)]` attribute on a normal Rust function. +//! +//! ```rust +//! use aarch32_rt::exception; +//! +//! #[exception(HypervisorCall)] +//! fn my_hvc_handler(hsr: u32, frame: &aarch32_rt::Frame) -> u32 { +//! // do stuff here +//! todo!() +//! } +//! ``` +//! +//! If you wish to inspect the HSR value, you can use the `aarch32-cpu` crate: +//! +//! ```rust,ignore +//! let hsr = aarch32_cpu::register::Hsr::new_with_raw_value(hsr); +//! ``` +//! //! ### Prefetch Abort Handler //! //! The symbol `_prefetch_abort_handler` should be an `extern "C"` function. It @@ -543,7 +588,7 @@ core::arch::global_asm!( ldr pc, =_asm_svc_handler ldr pc, =_asm_prefetch_abort_handler ldr pc, =_asm_data_abort_handler - nop + ldr pc, =_asm_hvc_handler ldr pc, =_asm_irq_handler ldr pc, =_asm_fiq_handler .size _vector_table, . - _vector_table diff --git a/examples/mps3-an536/reference/hvc-a32-armv8r-none-eabihf.out b/examples/mps3-an536/reference/hvc-a32-armv8r-none-eabihf.out new file mode 100644 index 00000000..2e302569 --- /dev/null +++ b/examples/mps3-an536/reference/hvc-a32-armv8r-none-eabihf.out @@ -0,0 +1,4 @@ +x = 1, y = 2, z = 3.000 +In hvc_handler, with Hsr { ec: Ok(Hvc), il: ThirtyTwoBit, iss: 0000abcd }, Frame { r0: 10000000, r1: 10000001, r2: 10000002, r3: 10000003, r4: 10000004, r5: 10000005 } +Got 12345678 +x = 1, y = 2, z = 3.000 diff --git a/examples/mps3-an536/reference/hvc-a32-thumbv8r-none-eabihf.out b/examples/mps3-an536/reference/hvc-a32-thumbv8r-none-eabihf.out new file mode 100644 index 00000000..2e302569 --- /dev/null +++ b/examples/mps3-an536/reference/hvc-a32-thumbv8r-none-eabihf.out @@ -0,0 +1,4 @@ +x = 1, y = 2, z = 3.000 +In hvc_handler, with Hsr { ec: Ok(Hvc), il: ThirtyTwoBit, iss: 0000abcd }, Frame { r0: 10000000, r1: 10000001, r2: 10000002, r3: 10000003, r4: 10000004, r5: 10000005 } +Got 12345678 +x = 1, y = 2, z = 3.000 diff --git a/examples/mps3-an536/reference/hvc-t32-armv8r-none-eabihf.out b/examples/mps3-an536/reference/hvc-t32-armv8r-none-eabihf.out new file mode 100644 index 00000000..2e302569 --- /dev/null +++ b/examples/mps3-an536/reference/hvc-t32-armv8r-none-eabihf.out @@ -0,0 +1,4 @@ +x = 1, y = 2, z = 3.000 +In hvc_handler, with Hsr { ec: Ok(Hvc), il: ThirtyTwoBit, iss: 0000abcd }, Frame { r0: 10000000, r1: 10000001, r2: 10000002, r3: 10000003, r4: 10000004, r5: 10000005 } +Got 12345678 +x = 1, y = 2, z = 3.000 diff --git a/examples/mps3-an536/reference/hvc-t32-thumbv8r-none-eabihf.out b/examples/mps3-an536/reference/hvc-t32-thumbv8r-none-eabihf.out new file mode 100644 index 00000000..2e302569 --- /dev/null +++ b/examples/mps3-an536/reference/hvc-t32-thumbv8r-none-eabihf.out @@ -0,0 +1,4 @@ +x = 1, y = 2, z = 3.000 +In hvc_handler, with Hsr { ec: Ok(Hvc), il: ThirtyTwoBit, iss: 0000abcd }, Frame { r0: 10000000, r1: 10000001, r2: 10000002, r3: 10000003, r4: 10000004, r5: 10000005 } +Got 12345678 +x = 1, y = 2, z = 3.000 diff --git a/examples/mps3-an536/src/bin/hvc-a32.rs b/examples/mps3-an536/src/bin/hvc-a32.rs new file mode 100644 index 00000000..2e48231b --- /dev/null +++ b/examples/mps3-an536/src/bin/hvc-a32.rs @@ -0,0 +1,44 @@ +//! HVC (hypervisor call) example + +#![no_std] +#![no_main] + +use aarch32_rt::{entry, exception}; +use mps3_an536 as _; +use semihosting::println; + +/// The entry-point to the Rust application. +/// +/// It is called by the start-up. +#[entry] +fn main() -> ! { + let x = 1; + let y = x + 1; + let z = (y as f64) * 1.5; + println!("x = {}, y = {}, z = {:0.3}", x, y, z); + let value = do_hvc1(); + println!("Got {:08x}", value); + println!("x = {}, y = {}, z = {:0.3}", x, y, z); + mps3_an536::exit(0); +} + +/// This is our HVC exception handler +#[exception(HypervisorCall)] +fn hvc_handler(hsr: u32, frame: &aarch32_rt::Frame) -> u32 { + let hsr = aarch32_cpu::register::Hsr::new_with_raw_value(hsr); + println!("In hvc_handler, with {:08x?}, {:08x?}", hsr, frame); + return 0x12345678; +} + +#[instruction_set(arm::a32)] +fn do_hvc1() -> u32 { + aarch32_cpu::hvc6!( + 0xABCD, + 0x1000_0000, + 0x1000_0001, + 0x1000_0002, + 0x1000_0003, + 0x1000_0004, + 0x1000_0005 + ) +} diff --git a/examples/mps3-an536/src/bin/hvc-t32.rs b/examples/mps3-an536/src/bin/hvc-t32.rs new file mode 100644 index 00000000..4d0ce587 --- /dev/null +++ b/examples/mps3-an536/src/bin/hvc-t32.rs @@ -0,0 +1,44 @@ +//! HVC (hypervisor call) example + +#![no_std] +#![no_main] + +use aarch32_rt::{entry, exception}; +use mps3_an536 as _; +use semihosting::println; + +/// The entry-point to the Rust application. +/// +/// It is called by the start-up. +#[entry] +fn main() -> ! { + let x = 1; + let y = x + 1; + let z = (y as f64) * 1.5; + println!("x = {}, y = {}, z = {:0.3}", x, y, z); + let value = do_hvc1(); + println!("Got {:08x}", value); + println!("x = {}, y = {}, z = {:0.3}", x, y, z); + mps3_an536::exit(0); +} + +/// This is our HVC exception handler +#[exception(HypervisorCall)] +fn hvc_handler(hsr: u32, frame: &aarch32_rt::Frame) -> u32 { + let hsr = aarch32_cpu::register::Hsr::new_with_raw_value(hsr); + println!("In hvc_handler, with {:08x?}, {:08x?}", hsr, frame); + return 0x12345678; +} + +#[instruction_set(arm::t32)] +fn do_hvc1() -> u32 { + aarch32_cpu::hvc6!( + 0xABCD, + 0x1000_0000, + 0x1000_0001, + 0x1000_0002, + 0x1000_0003, + 0x1000_0004, + 0x1000_0005 + ) +}