From 0d83cf25a0620460c3e0ab917bbd8a3d0017b0fc Mon Sep 17 00:00:00 2001
From: Alex Martens <alex@thinglab.org>
Date: Fri, 20 Oct 2023 05:48:28 -0700
Subject: [PATCH 01/12] Add CODEOWNERS

---
 .github/CODEOWNERS | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 .github/CODEOWNERS

diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..bb51ea1
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @rust-embedded/libs

From e381ef76e8f84d0684f9f82fc00b32dc4ae25b76 Mon Sep 17 00:00:00 2001
From: Alex Martens <alex@thinglab.org>
Date: Sat, 21 Oct 2023 09:32:28 +0900
Subject: [PATCH 02/12] README: add team ownership

---
 README.md | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/README.md b/README.md
index 31076ef..1c9f2f4 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,8 @@ Exit QEMU with user-defined code.
 Quit a running QEMU session with user-defined exit code. Useful for unit or integration tests using
 QEMU.
 
+This project is developed and maintained by the [libs team].
+
 ## TL;DR
 
 ```rust
@@ -94,3 +96,5 @@ party projects and their respective licenses.
 Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the
 work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
 additional terms or conditions.
+
+[libs team]: https://github.com/rust-embedded/wg#the-libs-team

From cf6954a20f68617d754b59cf4d532f3ef1d548d1 Mon Sep 17 00:00:00 2001
From: Alex Martens <alex@thinglab.org>
Date: Sat, 21 Oct 2023 09:47:25 +0900
Subject: [PATCH 03/12] CI: update

---
 .github/workflows/build.yml | 74 +++++++++++++++++++++++++------------
 .github/workflows/test.yml  | 47 -----------------------
 2 files changed, 51 insertions(+), 70 deletions(-)
 delete mode 100644 .github/workflows/test.yml

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 9297b84..d1d49bb 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -2,8 +2,6 @@ name: Build
 
 on:
   pull_request:
-    branches:
-      - master
   push:
     branches:
       - master
@@ -11,40 +9,70 @@ on:
     - cron: "0 5 * * *"
 
 jobs:
+
   build:
     name: Build Library
-    runs-on: ubuntu-20.04
-
+    runs-on: ubuntu-latest
+    env: {"RUSTFLAGS": "-D warnings"}
     strategy:
       matrix:
         target:
-          [aarch64-unknown-none-softfloat, riscv64gc-unknown-none-elf, x86_64-unknown-linux-gnu]
+          - "aarch64-unknown-none-softfloat"
+          - "riscv64gc-unknown-none-elf"
+          - "x86_64-unknown-linux-gnu"
     steps:
-      - name: Rust setup
-        uses: actions-rs/toolchain@v1
+      - uses: dtolnay/rust-toolchain@master
         with:
           toolchain: nightly
-          override: true
           target: ${{ matrix.target }}
           components: rustfmt
 
-      - name: Check out repository
-        uses: actions/checkout@v2
+      - uses: actions/checkout@v4
 
-      - name: Cargo fmt
-        uses: actions-rs/cargo@v1
-        with:
-          command: fmt
-          args: -- --check
+      - name: cargo build
+        run: cargo build --target ${{ matrix.target }}
 
-      - name: Cargo check
-        uses: actions-rs/cargo@v1
+  format:
+    name: Format
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - uses: dtolnay/rust-toolchain@stable
         with:
-          command: check
-          args: --target ${{ matrix.target }}
+          components: rustfmt
+      - run: cargo fmt --all -- --check
+
+  test:
+    name: Test QEMU Exit
+    runs-on: ubuntu-latest
 
-      - name: Cargo build
-        uses: actions-rs/cargo@v1
+    strategy:
+      matrix:
+        target:
+          - "aarch64-unknown-none-softfloat"
+          - "riscv64gc-unknown-none-elf"
+
+    steps:
+      - uses: dtolnay/rust-toolchain@master
         with:
-          command: build
-          args: --target ${{ matrix.target }}
+          toolchain: nightly
+          target: ${{ matrix.target }}
+          components: llvm-tools-preview
+
+      - name: Check out repository
+        uses: actions/checkout@v4
+
+      - name: Install QEMU
+        run: |
+          sudo apt update
+          sudo apt install qemu-system
+
+      - name: Run tests AARCH64
+        if: matrix.target == 'aarch64-unknown-none-softfloat'
+        run: |
+          RUSTFLAGS="-D warnings -C link-arg=-Ttests/aarch64_raspi3/link.ld" cargo test --target ${{ matrix.target }} --release
+
+      - name: Run tests RISCV64
+        if: matrix.target == 'riscv64gc-unknown-none-elf'
+        run: |
+          RUSTFLAGS="-D warnings -C link-arg=-Ttests/riscv64_virt/link.ld" cargo test --target ${{ matrix.target }} --release
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
deleted file mode 100644
index ea06c6f..0000000
--- a/.github/workflows/test.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-name: Test
-
-on:
-  pull_request:
-    branches:
-      - master
-  push:
-    branches:
-      - master
-  schedule:
-    - cron: "0 5 * * *"
-
-jobs:
-  build:
-    name: Test QEMU Exit
-    runs-on: ubuntu-20.04
-
-    strategy:
-      matrix:
-        target: [aarch64-unknown-none-softfloat, riscv64gc-unknown-none-elf]
-
-    steps:
-      - name: Rust setup
-        uses: actions-rs/toolchain@v1
-        with:
-          toolchain: nightly
-          override: true
-          target: ${{ matrix.target }}
-          components: llvm-tools-preview
-
-      - name: Check out repository
-        uses: actions/checkout@v2
-
-      - name: Install QEMU
-        run: |
-          sudo apt update
-          sudo apt install qemu-system
-
-      - name: Run tests AARCH64
-        if: matrix.target == 'aarch64-unknown-none-softfloat'
-        run: |
-          RUSTFLAGS="-C link-arg=-Ttests/aarch64_raspi3/link.ld" cargo test --target ${{ matrix.target }} --release
-
-      - name: Run tests RISCV64
-        if: matrix.target == 'riscv64gc-unknown-none-elf'
-        run: |
-          RUSTFLAGS="-C link-arg=-Ttests/riscv64_virt/link.ld" cargo test --target ${{ matrix.target }} --release

From 2504c948d347a934c4791a0ec7ca22f8b77e3716 Mon Sep 17 00:00:00 2001
From: Alex Martens <alex@thinglab.org>
Date: Sat, 21 Oct 2023 09:50:02 +0900
Subject: [PATCH 04/12] README: fix dead link

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 1c9f2f4..1d0e8fd 100644
--- a/README.md
+++ b/README.md
@@ -70,7 +70,7 @@ let qemu_exit_handle = qemu_exit::X86::new(io_base, custom_exit_success);
 
 ## Literature
 
-- [Semihosting for AArch32 and AArch64](https://static.docs.arm.com/dui0003/b/semihosting.pdf)
+- [Semihosting for AArch32 and AArch64](https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst)
 - [QEMU isa-debug-exit source](https://git.qemu.org/?p=qemu.git;a=blob;f=hw/misc/debugexit.c)
 - [QEMU sifive_test source](https://git.qemu.org/?p=qemu.git;a=blob;f=hw/misc/sifive_test.c)
 

From 05c60dc10b1b7dd56911c77421eec2c84fcdb38c Mon Sep 17 00:00:00 2001
From: Alex Martens <alex@thinglab.org>
Date: Sat, 21 Oct 2023 09:57:02 +0900
Subject: [PATCH 05/12] Fix CI

---
 .github/workflows/build.yml  | 5 +++--
 tests/test_runner_wrapper.sh | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index d1d49bb..b8b1d0a 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,6 +1,7 @@
 name: Build
 
 on:
+  workflow_dispatch:
   pull_request:
   push:
     branches:
@@ -25,7 +26,6 @@ jobs:
         with:
           toolchain: nightly
           target: ${{ matrix.target }}
-          components: rustfmt
 
       - uses: actions/checkout@v4
 
@@ -37,8 +37,9 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - uses: dtolnay/rust-toolchain@stable
+      - uses: dtolnay/rust-toolchain@master
         with:
+          toolchain: nightly
           components: rustfmt
       - run: cargo fmt --all -- --check
 
diff --git a/tests/test_runner_wrapper.sh b/tests/test_runner_wrapper.sh
index ec9f6cd..f80bb6c 100755
--- a/tests/test_runner_wrapper.sh
+++ b/tests/test_runner_wrapper.sh
@@ -3,7 +3,7 @@
 TIMEOUT="timeout 10"
 
 if [[ $1 == *"aarch64"* ]]; then
-    $TIMEOUT qemu-system-aarch64 -M raspi3 -display none -semihosting -kernel $1
+    $TIMEOUT qemu-system-aarch64 -M raspi3b -display none -semihosting -kernel $1
 elif [[ $1 == *"riscv64"* ]]; then
     $TIMEOUT qemu-system-riscv64 -M virt -bios tests/riscv64_virt/fw_jump.elf -display none -kernel $1
 fi

From 9b2730156fb348b14e8249a1eaeb5380ac959e58 Mon Sep 17 00:00:00 2001
From: Alex Martens <alex@thinglab.org>
Date: Sat, 21 Oct 2023 10:03:14 +0900
Subject: [PATCH 06/12] Add GHMQ

---
 .github/workflows/build.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b8b1d0a..391eae4 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,6 +1,7 @@
 name: Build
 
 on:
+  merge_group:
   workflow_dispatch:
   pull_request:
   push:

From c515e56095aaf6eb6139e149cbb3f892a34b0928 Mon Sep 17 00:00:00 2001
From: Alex Martens <alex@thinglab.org>
Date: Sat, 21 Oct 2023 10:07:49 +0900
Subject: [PATCH 07/12] README: remove test badge

---
 README.md | 1 -
 1 file changed, 1 deletion(-)

diff --git a/README.md b/README.md
index 1d0e8fd..50d3394 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,6 @@
 [![crates.io](https://img.shields.io/crates/d/qemu-exit.svg)](https://crates.io/crates/qemu-exit)
 [![crates.io](https://img.shields.io/crates/v/qemu-exit.svg)](https://crates.io/crates/qemu-exit)
 ![Build](https://github.com/andre-richter/qemu-exit/workflows/Build/badge.svg)
-![Test](https://github.com/andre-richter/qemu-exit/workflows/Test/badge.svg)
 
 # qemu-exit
 

From ce1d0c18f013413a52d42723df36db15692685b1 Mon Sep 17 00:00:00 2001
From: Alex Martens <alex@thinglab.org>
Date: Sat, 21 Oct 2023 10:10:51 +0900
Subject: [PATCH 08/12] Update repository URLs

---
 Cargo.toml | 4 ++--
 README.md  | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 84e37f4..9ef515e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,8 +3,8 @@ name = "qemu-exit"
 version = "3.0.2"
 authors = ["Andre Richter <andre.o.richter@gmail.com>"]
 description = "Exit QEMU with user-defined code"
-homepage = "https://github.com/andre-richter/qemu-exit"
-repository = "https://github.com/andre-richter/qemu-exit"
+homepage = "https://github.com/rust-embedded/qemu-exit"
+repository = "https://github.com/rust-embedded/qemu-exit"
 readme = "README.md"
 keywords = ["aarch64", "x86_64", "risc-v", "qemu", "exit"]
 categories = ["embedded", "hardware-support", "no-std"]
diff --git a/README.md b/README.md
index 50d3394..55077c2 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 [![crates.io](https://img.shields.io/crates/d/qemu-exit.svg)](https://crates.io/crates/qemu-exit)
 [![crates.io](https://img.shields.io/crates/v/qemu-exit.svg)](https://crates.io/crates/qemu-exit)
-![Build](https://github.com/andre-richter/qemu-exit/workflows/Build/badge.svg)
+![Build](https://github.com/rust-embedded/qemu-exit/workflows/Build/badge.svg)
 
 # qemu-exit
 

From f5e2a1d0587dbb2e8ae53a62acf74c980b25f204 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Kr=C3=B6ning?=
 <martin.kroening@eonerc.rwth-aachen.de>
Date: Thu, 4 Apr 2024 16:05:10 +0200
Subject: [PATCH 09/12] docs: fix dead links
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Martin Kröning <martin.kroening@eonerc.rwth-aachen.de>
---
 README.md  | 4 ++--
 src/lib.rs | 6 +++---
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/README.md b/README.md
index 55077c2..d061bc7 100644
--- a/README.md
+++ b/README.md
@@ -70,8 +70,8 @@ let qemu_exit_handle = qemu_exit::X86::new(io_base, custom_exit_success);
 ## Literature
 
 - [Semihosting for AArch32 and AArch64](https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst)
-- [QEMU isa-debug-exit source](https://git.qemu.org/?p=qemu.git;a=blob;f=hw/misc/debugexit.c)
-- [QEMU sifive_test source](https://git.qemu.org/?p=qemu.git;a=blob;f=hw/misc/sifive_test.c)
+- [QEMU isa-debug-exit source](https://gitlab.com/qemu-project/qemu/-/blob/master/hw/misc/debugexit.c)
+- [QEMU sifive_test source](https://gitlab.com/qemu-project/qemu/-/blob/master/hw/misc/sifive_test.c)
 
 ## Authors
 
diff --git a/src/lib.rs b/src/lib.rs
index 97b7515..2731de1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -65,9 +65,9 @@
 //!
 //! ## Literature
 //!
-//! - [Semihosting for AArch32 and AArch64](https://static.docs.arm.com/dui0003/b/semihosting.pdf)
-//! - [QEMU isa-debug-exit source](https://git.qemu.org/?p=qemu.git;a=blob;f=hw/misc/debugexit.c)
-//! - [QEMU sifive_test source](https://git.qemu.org/?p=qemu.git;a=blob;f=hw/misc/sifive_test.c)
+//! - [Semihosting for AArch32 and AArch64](https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst)
+//! - [QEMU isa-debug-exit source](https://gitlab.com/qemu-project/qemu/-/blob/master/hw/misc/debugexit.c)
+//! - [QEMU sifive_test source](https://gitlab.com/qemu-project/qemu/-/blob/master/hw/misc/sifive_test.c)
 
 #![deny(missing_docs)]
 #![no_std]

From 3bb36900eca847045fc5c752eff574c2899c117f Mon Sep 17 00:00:00 2001
From: phil <schulz.phil@gmx.de>
Date: Sun, 29 Sep 2024 20:54:41 +0200
Subject: [PATCH 10/12] Add support for the 32 Bit Arm architectures.

---
 Makefile                         |  8 ++++
 README.md                        |  4 +-
 src/aarch32.rs                   | 75 ++++++++++++++++++++++++++++++++
 src/lib.rs                       | 18 ++++++++
 tests/armv7m_mps2an500/link.ld   | 22 ++++++++++
 tests/armv7m_mps2an500/mod.rs    | 16 +++++++
 tests/armv7m_mps2an500/startup.S | 12 +++++
 tests/exit_13.rs                 | 10 +++++
 tests/test_runner_wrapper.sh     |  4 +-
 9 files changed, 167 insertions(+), 2 deletions(-)
 create mode 100644 src/aarch32.rs
 create mode 100644 tests/armv7m_mps2an500/link.ld
 create mode 100644 tests/armv7m_mps2an500/mod.rs
 create mode 100644 tests/armv7m_mps2an500/startup.S

diff --git a/Makefile b/Makefile
index 24e92b6..733855a 100644
--- a/Makefile
+++ b/Makefile
@@ -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
 
@@ -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) \
diff --git a/README.md b/README.md
index d061bc7..b63bae7 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/src/aarch32.rs b/src/aarch32.rs
new file mode 100644
index 0000000..2f86d51
--- /dev/null
+++ b/src/aarch32.rs
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2024 Philipp Schulz <schulz.phil@gmx.de>
+
+//! 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)
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 2731de1..31a12de 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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);
@@ -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
@@ -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;
 
diff --git a/tests/armv7m_mps2an500/link.ld b/tests/armv7m_mps2an500/link.ld
new file mode 100644
index 0000000..e46b951
--- /dev/null
+++ b/tests/armv7m_mps2an500/link.ld
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: MIT OR Apache-2.0
+ *
+ * Copyright (c) 2024 Philipp Schulz <schulz.phil@gmx.de>
+ */
+ENTRY(_vectors)
+
+SECTIONS
+{
+    . = 0x0;
+    .boot :
+    {
+        KEEP(*(.text.boot))
+        KEEP(*(.data.boot))
+    }
+
+    .text :
+    {
+        *(.vectors)
+        *(.text._start)
+        *(.text)
+    }
+}
diff --git a/tests/armv7m_mps2an500/mod.rs b/tests/armv7m_mps2an500/mod.rs
new file mode 100644
index 0000000..b6f7047
--- /dev/null
+++ b/tests/armv7m_mps2an500/mod.rs
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2024 Philipp Schulz <schulz.phil@gmx.de>
+
+//! AArch32 specific setup code.
+
+use core::arch::global_asm;
+
+global_asm!(
+    include_str!("./startup.S")
+);
+
+#[no_mangle]
+extern "C" fn entry() {
+    super::test_main()
+}
diff --git a/tests/armv7m_mps2an500/startup.S b/tests/armv7m_mps2an500/startup.S
new file mode 100644
index 0000000..00507f7
--- /dev/null
+++ b/tests/armv7m_mps2an500/startup.S
@@ -0,0 +1,12 @@
+.section ".text.boot","ax"
+
+.thumb
+.thumb_func
+.globl _vectors
+_vectors:
+.word 0x2000
+.word reset
+
+.thumb_func
+reset:
+    bl entry
diff --git a/tests/exit_13.rs b/tests/exit_13.rs
index 0883764..cec0490 100644
--- a/tests/exit_13.rs
+++ b/tests/exit_13.rs
@@ -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
 //--------------------------------------------------------------------------------------------------
diff --git a/tests/test_runner_wrapper.sh b/tests/test_runner_wrapper.sh
index f80bb6c..3b2a18e 100755
--- a/tests/test_runner_wrapper.sh
+++ b/tests/test_runner_wrapper.sh
@@ -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

From cf82b4a10208aca30d50100eefdf4dc725def719 Mon Sep 17 00:00:00 2001
From: Markus Reiter <me@reitermark.us>
Date: Fri, 18 Apr 2025 16:46:08 +0200
Subject: [PATCH 11/12] Fix formatting.

---
 src/lib.rs                    | 10 ++++++----
 tests/armv7m_mps2an500/mod.rs |  4 +---
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 31a12de..5cf1347 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -36,23 +36,24 @@
 //!
 //! ### AArch64
 //!
-//! Pass the `-semihosting` argument to the QEMU invocation, e.g.:
+//! 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.:
+//! 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
 //!
 //! You need to chose a machine with the `sifive_test` device, for exemple `-M virt`:
+//!
 //! ```
 //! qemu-system-riscv64 -M virt -nographic -monitor none -serial stdio -kernel kernel.elf
 //! ```
@@ -60,6 +61,7 @@
 //! ### x86_64
 //!
 //! Add the special ISA debug exit device by passing the flags:
+//!
 //! ```
 //! -device isa-debug-exit,iobase=0xf4,iosize=0x04
 //! ```
diff --git a/tests/armv7m_mps2an500/mod.rs b/tests/armv7m_mps2an500/mod.rs
index b6f7047..c221c10 100644
--- a/tests/armv7m_mps2an500/mod.rs
+++ b/tests/armv7m_mps2an500/mod.rs
@@ -6,9 +6,7 @@
 
 use core::arch::global_asm;
 
-global_asm!(
-    include_str!("./startup.S")
-);
+global_asm!(include_str!("./startup.S"));
 
 #[no_mangle]
 extern "C" fn entry() {

From 84407e70cf819a49a2ee7a25a4b20db19a31f650 Mon Sep 17 00:00:00 2001
From: Chris Pick <chris@chrispick.com>
Date: Fri, 25 Apr 2025 18:39:28 -0400
Subject: [PATCH 12/12] Add notes on using crate from Linux userspace

It took me a little research to figure out how to use this crate from
x86/x86_64 Linux userspace.  Add some notes to help people in the future.
---
 README.md | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index b63bae7..9339d1a 100644
--- a/README.md
+++ b/README.md
@@ -58,7 +58,8 @@ Add the special ISA debug exit device by passing the flags:
 -device isa-debug-exit,iobase=0xf4,iosize=0x04
 ```
 
-When instantiating the handle, `iobase` must be given as the first parameter.
+When instantiating the handle with `qemu_exit::X86::new()`, `iobase` must be given as the first
+parameter.
 
 The second parameter must be an `EXIT_SUCCESS` code of your choice that is an odd number, aka
 bit number zero must be `1`. This is needed because in QEMU, the provided code is internally
@@ -69,6 +70,18 @@ possible to let QEMU invoke `exit(0)`.
 let qemu_exit_handle = qemu_exit::X86::new(io_base, custom_exit_success);
 ```
 
+#### x86/x86_64 Linux
+
+To use this mechanism from Linux userspace, the kernel must be compiled with
+`CONFIG_X86_IOPL_IOPERM=y` (which is the default) and the process must start with root privileges
+(or `CAP_SYS_RAWIO`) and call: [`ioperm(2)`](https://man7.org/linux/man-pages/man2/ioperm.2.html):
+```rust
+nix::errno::Errno::result(unsafe { libc::ioperm( 0xf4, 4, 1 )}).expect("ioperm failed");
+```
+
+Privileges/capabilities can then be dropped. Normal users can subsequently call
+`qemu_exit_handle.exit*()`.
+
 ## Literature
 
 - [Semihosting for AArch32 and AArch64](https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst)
