Skip to content

Commit

Permalink
Add support for the 32 Bit Arm architectures.
Browse files Browse the repository at this point in the history
  • Loading branch information
dinkelhacker committed Sep 29, 2024
1 parent 5644679 commit 3bb3690
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 2 deletions.
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
TARGET_AARCH64 := aarch64-unknown-none-softfloat
TARGET_AARCH32 := thumbv7em-none-eabi
LINKER_SCRIPT_AARCH64 := tests/aarch64_raspi3/link.ld
LINKER_SCRIPT_AARCH32 := tests/armv7m_mps2an500/link.ld

TARGET_RISCV64 := riscv64gc-unknown-none-elf
LINKER_SCRIPT_RISCV64 := tests/riscv64_virt/link.ld

default:
cargo build --target $(TARGET_AARCH64) --release
cargo build --target $(TARGET_AARCH32) --release
cargo build --target $(TARGET_RISCV64) --release
cargo build --release

clippy:
cargo clippy --target $(TARGET_AARCH64)
cargo clippy --target $(TARGET_AARCH32)
cargo clippy --target $(TARGET_RISCV64)
cargo clippy

Expand All @@ -19,6 +23,10 @@ test:
cargo test \
--target $(TARGET_AARCH64) \
--release
RUSTFLAGS="-C link-arg=-T$(LINKER_SCRIPT_AARCH32) -Clink-args=-Map=/tmp/qemuexit-mapfile.map" \
cargo test \
--target $(TARGET_AARCH32) \
--release
RUSTFLAGS="-C link-arg=-T$(LINKER_SCRIPT_RISCV64)" \
cargo test \
--target $(TARGET_RISCV64) \
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@ qemu_exit_handle.exit_failure();

## Architecture Specific Configuration

### AArch64
### AArch64/AArch32

Pass the `-semihosting` argument to the QEMU invocation, e.g.:
```
qemu-system-aarch64 -M raspi3 -serial stdio -semihosting -kernel kernel8.img
qemu-system-arm -nographic -M mps2-an500 -cpu cortex-m7 -serial mon:stdio -semihosting -kernel
kernel.img
```

### RISCV64
Expand Down
75 changes: 75 additions & 0 deletions src/aarch32.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2024 Philipp Schulz <[email protected]>

//! AArch32.
use crate::QEMUExit;
use core::arch::asm;

const EXIT_SUCCESS: u32 = 0;
const EXIT_FAILURE: u32 = 1;

#[allow(non_upper_case_globals)]
const ADP_Stopped_ApplicationExit: u32 = 0x20026;

/// The parameter block layout that is expected by QEMU.
///
/// If QEMU finds `ADP_Stopped_ApplicationExit` in the first parameter, it uses the second parameter
/// as exit code.
///
/// If first paraemter != `ADP_Stopped_ApplicationExit`, exit code `1` is used.
#[repr(C)]
struct QEMUParameterBlock {
arg0: u32,
arg1: u32,
}

/// AArch32 configuration.
pub struct AArch32 {}

/// A Semihosting call using `0x20` - `SYS_EXIT_EXTENDED`.
fn semihosting_sys_exit_call(block: &QEMUParameterBlock) -> ! {
unsafe {
asm!(
"bkpt #0xab",
in("r0") 0x20,
in("r1") block as *const _ as u32,
options(nostack)
);

// For the case that the QEMU exit attempt did not work, transition into an infinite loop.
// Calling `panic!()` here is unfeasible, since there is a good chance this function here is
// the last expression in the `panic!()` handler itself. This prevents a possible
// infinite loop.
loop {
asm!("wfe", options(nomem, nostack));
}
}
}

impl AArch32 {
/// Create an instance.
pub const fn new() -> Self {
AArch32 {}
}
}

impl QEMUExit for AArch32 {
fn exit(&self, code: u32) -> ! {
let block = QEMUParameterBlock {
arg0: ADP_Stopped_ApplicationExit,
arg1: code as u32,
};

semihosting_sys_exit_call(&block)
}

fn exit_success(&self) -> ! {
self.exit(EXIT_SUCCESS)
}

fn exit_failure(&self) -> ! {
self.exit(EXIT_FAILURE)
}
}
18 changes: 18 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
//! #[cfg(target_arch = "aarch64")]
//! let qemu_exit_handle = qemu_exit::AArch64::new();
//!
//! #[cfg(target_arch = "arm")]
//! let qemu_exit_handle = qemu_exit::Aarch32::new();
//!
//! // addr: The address of sifive_test.
//! #[cfg(target_arch = "riscv64")]
//! let qemu_exit_handle = qemu_exit::RISCV64::new(addr);
Expand All @@ -36,6 +39,15 @@
//! Pass the `-semihosting` argument to the QEMU invocation, e.g.:
//! ```
//! qemu-system-aarch64 -M raspi3 -serial stdio -semihosting -kernel kernel8.img
//!
//! ```
//!
//! ### AArch32
//!
//! Pass the `-semihosting` argument to the QEMU invocation, e.g.:
//! ```
//! qemu-system-arm -m 16M -nographic -M mps2-an500 -cpu cortex-m7 -serial mon:stdio -semihosting -kernel kernel.img
//!
//! ```
//!
//! ### RISCV64
Expand Down Expand Up @@ -78,6 +90,12 @@ pub mod aarch64;
#[cfg(target_arch = "aarch64")]
pub use aarch64::*;

#[cfg(target_arch = "arm")]
pub mod aarch32;

#[cfg(target_arch = "arm")]
pub use aarch32::*;

#[cfg(target_arch = "riscv64")]
pub mod riscv64;

Expand Down
22 changes: 22 additions & 0 deletions tests/armv7m_mps2an500/link.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: MIT OR Apache-2.0
*
* Copyright (c) 2024 Philipp Schulz <[email protected]>
*/
ENTRY(_vectors)

SECTIONS
{
. = 0x0;
.boot :
{
KEEP(*(.text.boot))
KEEP(*(.data.boot))
}

.text :
{
*(.vectors)
*(.text._start)
*(.text)
}
}
16 changes: 16 additions & 0 deletions tests/armv7m_mps2an500/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2024 Philipp Schulz <[email protected]>

//! AArch32 specific setup code.
use core::arch::global_asm;

global_asm!(
include_str!("./startup.S")
);

#[no_mangle]
extern "C" fn entry() {
super::test_main()
}
12 changes: 12 additions & 0 deletions tests/armv7m_mps2an500/startup.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.section ".text.boot","ax"

.thumb
.thumb_func
.globl _vectors
_vectors:
.word 0x2000
.word reset

.thumb_func
reset:
bl entry
10 changes: 10 additions & 0 deletions tests/exit_13.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ const QEMU_EXIT_HANDLE: qemu_exit::AArch64 = qemu_exit::AArch64::new();
#[cfg(target_arch = "aarch64")]
mod aarch64_raspi3;

//--------------------------------------------------------------------------------------------------
// Aarch32
//--------------------------------------------------------------------------------------------------

#[cfg(target_arch = "arm")]
const QEMU_EXIT_HANDLE: qemu_exit::AArch32 = qemu_exit::AArch32::new();

#[cfg(target_arch = "arm")]
mod armv7m_mps2an500;

//--------------------------------------------------------------------------------------------------
// RISCV64
//--------------------------------------------------------------------------------------------------
Expand Down
4 changes: 3 additions & 1 deletion tests/test_runner_wrapper.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#!/usr/bin/env bash

TIMEOUT="timeout 10"

if [[ $1 == *"aarch64"* ]]; then
$TIMEOUT qemu-system-aarch64 -M raspi3b -display none -semihosting -kernel $1
elif [[ $1 == *"thumbv7em"* ]]; then
arm-none-eabi-objcopy -O binary $1 /tmp/qemu_exit_armv7em.bin
qemu-system-arm -m 16M -nographic -M mps2-an500 -cpu cortex-m7 -serial mon:stdio -semihosting -kernel /tmp/qemu_exit_armv7em.bin
elif [[ $1 == *"riscv64"* ]]; then
$TIMEOUT qemu-system-riscv64 -M virt -bios tests/riscv64_virt/fw_jump.elf -display none -kernel $1
fi
Expand Down

0 comments on commit 3bb3690

Please sign in to comment.