Use safe-mmio

Refactor driver to use safe-mmio for accessing register and handling
the ownership and lifetime of the peripheral.

Change-Id: I031c3ceb1e34978218188160a3e0ec345c2f4630
Signed-off-by: Imre Kis <imre.kis@arm.com>
diff --git a/Cargo.lock b/Cargo.lock
index eac2616..7758337 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -7,10 +7,76 @@
 version = "0.1.0"
 dependencies = [
  "bitflags",
+ "safe-mmio",
+ "zerocopy",
 ]
 
 [[package]]
 name = "bitflags"
-version = "2.6.0"
+version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.94"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "safe-mmio"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3bc59a975d8faa0b4475145266e9f9eac01f0b3f393d0e5eecc8b88646ca2d29"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "zerocopy"
+version = "0.8.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/Cargo.toml b/Cargo.toml
index af86174..bec41bd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,4 +18,6 @@
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-bitflags = "2.6"
+bitflags = "2.9"
+safe-mmio = "0.2"
+zerocopy = "0.8"
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index cb0610b..b7567c5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -9,13 +9,22 @@
 #![no_std]
 
 use bitflags::bitflags;
-use core::ops::{DerefMut, Range};
+use core::ops::Range;
+use safe_mmio::{
+    field,
+    fields::{ReadOnly, ReadPure, ReadPureWrite, ReadWrite, WriteOnly},
+    UniqueMmioPointer,
+};
+use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
+
+#[repr(transparent)]
+#[derive(Copy, Clone, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
+
+struct DistributorControlRegister(u32);
 
 bitflags! {
     // Distributor Control Register
-    #[repr(transparent)]
-    #[derive(Copy, Clone)]
-    struct DistributorControlRegister : u32 {
+    impl DistributorControlRegister : u32 {
         /// Register Write Pending
         const RWP = 1 << 31;
         /// Enable 1 of N Wakeup Functionality
@@ -36,71 +45,135 @@
 }
 
 /// GIC Distributor register map
+#[derive(Clone, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)]
 #[repr(C, align(4))]
 pub struct GICDRegisters {
-    ctlr: u32,                  // 0x0000
-    typer: u32,                 // 0x0004
-    iidr: u32,                  // 0x0008
-    typer2: u32,                // 0x000c
-    statusr: u32,               // 0x0010
-    reserved_0014: [u32; 3],    // 0x0014-0x001c
-    imdef0: [u32; 8],           // 0x0020-0x003c
-    setspi_nsr: u32,            // 0x0040
-    reserved_0044: u32,         // 0x0044
-    clrspi_nsr: u32,            // 0x0048
-    reserved_004c: u32,         // 0x004c
-    setspi_sr: u32,             // 0x0050
-    reserved_0054: u32,         // 0x0054
-    clrspi_sr: u32,             // 0x0058
-    reserved_005c: [u32; 9],    // 0x005c-0x007c
-    igroupr: [u32; 32],         // 0x0080-0x00fc
-    isenabler: [u32; 32],       // 0x0100-0x017c
-    icenabler: [u32; 32],       // 0x0180-0x01fc
-    ispendr: [u32; 32],         // 0x0200-0x027c
-    icpendr: [u32; 32],         // 0x0280-0x02fc
-    isactiver: [u32; 32],       // 0x0300-0x037c
-    icactiver: [u32; 32],       // 0x0380-0x03fc
-    ipriorityr: [u32; 256],     // 0x0400-0x07f8
-    itargetsr: [u32; 256],      // 0x0800-0x0bfc
-    icfgr: [u32; 64],           // 0x0c00-0x0cfc
-    igrpmodr: [u32; 32],        // 0x0d00-0x0d7c
-    reserved_0d80: [u32; 32],   // 0x0d80-0x0dfc
-    nsacr: [u32; 64],           // 0x0e00-0x0efc
-    sgir: u32,                  // 0x0f00
-    reserved_0f04: [u32; 3],    // 0x0f04-0x0f0c
-    cpendsgir: [u32; 4],        // 0x0f10-0x0f1c
-    spendsgir: [u32; 4],        // 0x0f20-0x0f2c
-    reserved_0f30: [u32; 20],   // 0x0f30-0x0f7c
-    inmir: [u32; 32],           // 0x0f80-0x0ffc
-    igroupr_e: [u32; 32],       // 0x1000-0x107c
-    reserved_1080: [u32; 96],   // 0x1080-0x1fc
-    isenabler_e: [u32; 32],     // 0x1200-0x127c
-    reserved_1280: [u32; 96],   // 0x1280-0x13fc
-    icenabler_e: [u32; 32],     // 0x1400-0x147c
-    reserved_1480: [u32; 96],   // 0x1480-0x15fc
-    ispendr_e: [u32; 32],       // 0x1600-0x167c
-    reserved_1680: [u32; 96],   // 0x1680-0x17fc
-    icpendr_e: [u32; 32],       // 0x1800-0x187c
-    reserved_1880: [u32; 96],   // 0x1880-0x19fc
-    isactive_e: [u32; 32],      // 0x1a00-0x1a7c
-    reserved_1a80: [u32; 96],   // 0x1a80-0x1bfc
-    icactive_e: [u32; 32],      // 0x1c00-0x1c7c
-    reserved_1c80: [u32; 224],  // 0x1c80-0x1ffc
-    ipriorityr_e: [u32; 256],   // 0x2000-0x23fc
-    reserved_2400: [u32; 768],  // 0x2400-0x2ffc
-    icfgr_e: [u32; 64],         // 0x3000-0x30fc
-    reserved_3100: [u32; 192],  // 0x3100-0x33fc
-    igrpmodr_e: [u32; 32],      // 0x3400-0x347c
-    reserved_3480: [u32; 96],   // 0x3480-0x35fc
-    nsacr_e: [u32; 32],         // 0x3600-0x367c
-    reserved_3680: [u32; 256],  // 0x3680-0x3afc
-    inmir_e: [u32; 64],         // 0x3b00-0x3bfc
-    reserved_3b80: [u32; 2400], // 0x3b80-0x60fc
-    irouter: [u32; 1975],       // 0x6100-0x7fd8
-    reserved_7fdc: [u32; 9],    // 0x7fdc-0x7ffc
-    irouter_e: [u32; 2048],     // 0x8000-0x9ffc
-    reserved_a000: [u32; 6132], // 0xa000-0xffcc
-    id_registers: [u32; 12],    // 0xffd0-0xfffc
+    /// 0x0000
+    ctlr: ReadPureWrite<DistributorControlRegister>,
+    /// 0x0004
+    typer: ReadPure<u32>,
+    /// 0x0008
+    iidr: ReadPure<u32>,
+    /// 0x000c
+    typer2: ReadPure<u32>,
+    /// 0x0010
+    statusr: ReadPureWrite<u32>,
+    /// 0x0014-0x001c
+    reserved_0014: [u32; 3],
+    /// 0x0020-0x003c
+    imdef0: [ReadWrite<u32>; 8],
+    /// 0x0040
+    setspi_nsr: WriteOnly<u32>,
+    /// 0x0044
+    reserved_0044: u32,
+    /// 0x0048
+    clrspi_nsr: WriteOnly<u32>,
+    /// 0x004c
+    reserved_004c: u32,
+    /// 0x0050
+    setspi_sr: WriteOnly<u32>,
+    /// 0x0054
+    reserved_0054: u32,
+    /// 0x0058
+    clrspi_sr: WriteOnly<u32>,
+    /// 0x005c-0x007c
+    reserved_005c: [u32; 9],
+    /// 0x0080-0x00fc
+    igroupr: [ReadPureWrite<u32>; 32],
+    /// 0x0100-0x017c
+    isenabler: [ReadPureWrite<u32>; 32],
+    /// 0x0180-0x01fc
+    icenabler: [ReadPureWrite<u32>; 32],
+    // 0x0200-0x027c
+    ispendr: [ReadPureWrite<u32>; 32],
+    /// 0x0280-0x02fc
+    icpendr: [ReadPureWrite<u32>; 32],
+    /// 0x0300-0x037c
+    isactiver: [ReadPureWrite<u32>; 32],
+    /// 0x0380-0x03fc
+    icactiver: [ReadPureWrite<u32>; 32],
+    /// 0x0400-0x07f8
+    ipriorityr: [ReadPureWrite<u32>; 256],
+    /// 0x0800-0x0bfc
+    itargetsr: [ReadOnly<u32>; 256],
+    /// 0x0c00-0x0cfc
+    icfgr: [ReadPureWrite<u32>; 64],
+    /// 0x0d00-0x0d7c
+    igrpmodr: [ReadPureWrite<u32>; 32],
+    /// 0x0d80-0x0dfc
+    reserved_0d80: [u32; 32],
+    /// 0x0e00-0x0efc
+    nsacr: [ReadPureWrite<u32>; 64],
+    /// 0x0f00
+    sgir: WriteOnly<u32>,
+    /// 0x0f04-0x0f0c
+    reserved_0f04: [u32; 3],
+    /// 0x0f10-0x0f1c
+    cpendsgir: [ReadPureWrite<u32>; 4],
+    /// 0x0f20-0x0f2c
+    spendsgir: [ReadPureWrite<u32>; 4],
+    /// 0x0f30-0x0f7c
+    reserved_0f30: [u32; 20],
+    /// 0x0f80-0x0ffc
+    inmir: [ReadPureWrite<u32>; 32],
+    /// 0x1000-0x107c
+    igroupr_e: [ReadPureWrite<u32>; 32],
+    /// 0x1080-0x1fc
+    reserved_1080: [u32; 96],
+    /// 0x1200-0x127c
+    isenabler_e: [ReadPureWrite<u32>; 32],
+    /// 0x1280-0x13fc
+    reserved_1280: [u32; 96],
+    /// 0x1400-0x147c
+    icenabler_e: [ReadPureWrite<u32>; 32],
+    /// 0x1480-0x15fc
+    reserved_1480: [u32; 96],
+    /// 0x1600-0x167c
+    ispendr_e: [ReadPureWrite<u32>; 32],
+    /// 0x1680-0x17fc
+    reserved_1680: [u32; 96],
+    /// 0x1800-0x187c
+    icpendr_e: [ReadPureWrite<u32>; 32],
+    /// 0x1880-0x19fc
+    reserved_1880: [u32; 96],
+    /// 0x1a00-0x1a7c
+    isactive_e: [ReadPureWrite<u32>; 32],
+    /// 0x1a80-0x1bfc
+    reserved_1a80: [u32; 96],
+    /// 0x1c00-0x1c7c
+    icactive_e: [ReadPureWrite<u32>; 32],
+    /// 0x1c80-0x1ffc
+    reserved_1c80: [u32; 224],
+    /// 0x2000-0x23fc
+    ipriorityr_e: [ReadPureWrite<u32>; 256],
+    /// 0x2400-0x2ffc
+    reserved_2400: [u32; 768],
+    /// 0x3000-0x30fc
+    icfgr_e: [ReadPureWrite<u32>; 64],
+    /// 0x3100-0x33fc
+    reserved_3100: [u32; 192],
+    /// 0x3400-0x347c
+    igrpmodr_e: [ReadPureWrite<u32>; 32],
+    /// 0x3480-0x35fc
+    reserved_3480: [u32; 96],
+    /// 0x3600-0x367c
+    nsacr_e: [ReadPureWrite<u32>; 32],
+    /// 0x3680-0x3afc
+    reserved_3680: [u32; 256],
+    /// 0x3b00-0x3bfc
+    inmir_e: [ReadPureWrite<u32>; 64],
+    /// 0x3b80-0x60fc
+    reserved_3b80: [u32; 2400],
+    /// 0x6100-0x7fd8
+    irouter: [ReadPureWrite<u32>; 1975],
+    /// 0x7fdc-0x7ffc
+    reserved_7fdc: [u32; 9],
+    /// 0x8000-0x9ffc
+    irouter_e: [ReadPureWrite<u32>; 2048],
+    /// 0xa000-0xffcc
+    reserved_a000: [u32; 6132],
+    /// 0xffd0-0xfffc
+    id_registers: [ReadOnly<u32>; 12],
 }
 
 /// # GIC Distributor error type
@@ -113,28 +186,19 @@
 ///
 /// The Distributor performs interrupt prioritization and distribution of SPIs and SGIs to the
 /// Redistributors and CPU interfaces that are connected to the PEs in the system.
-pub struct GicDistributor<R>
-where
-    R: DerefMut<Target = GICDRegisters>,
-{
-    gicd: R,
+pub struct GicDistributor<'a> {
+    gicd: UniqueMmioPointer<'a, GICDRegisters>,
 }
 
-impl<R> GicDistributor<R>
-where
-    R: DerefMut<Target = GICDRegisters>,
-{
+impl<'a> GicDistributor<'a> {
     const MAX_IT: usize = 32;
 
     /// Create GIC Distributor instance
-    pub fn new(mut gicd: R) -> Self {
-        // SAFETY: gicd can be dereferenced as a valid GIC Distributor register block
-        unsafe {
-            for n in 0..Self::MAX_IT {
-                (&raw mut gicd.icenabler[n]).write_volatile(0xffffffff);
-                (&raw mut gicd.icpendr[n]).write_volatile(0xffffffff);
-                (&raw mut gicd.igroupr[n]).write_volatile(0xffffffff);
-            }
+    pub fn new(mut gicd: UniqueMmioPointer<'a, GICDRegisters>) -> Self {
+        for n in 0..Self::MAX_IT {
+            field!(gicd, icenabler).split()[n].write(0xffff_ffff);
+            field!(gicd, icpendr).split()[n].write(0xffff_ffff);
+            field!(gicd, igroupr).split()[n].write(0xffff_ffff);
         }
 
         Self { gicd }
@@ -142,32 +206,20 @@
 
     /// Enable Group 0 interrupts
     pub fn enable_group0(&mut self) {
-        // SAFETY: self.gicd can be dereferenced as a valid GIC Distributor register block
-        unsafe {
-            let value = (&raw const self.gicd.ctlr).read_volatile();
-            (&raw mut self.gicd.ctlr)
-                .write_volatile(value | DistributorControlRegister::EnableGrp0.bits());
-        }
+        let value = field!(self.gicd, ctlr).read();
+        field!(self.gicd, ctlr).write(value | DistributorControlRegister::EnableGrp0);
     }
 
     /// Enable Secure Group 1 interrupts
     pub fn enable_secure_group1(&mut self) {
-        // SAFETY: self.gicd can be dereferenced as a valid GIC Distributor register block
-        unsafe {
-            let value = (&raw const self.gicd.ctlr).read_volatile();
-            (&raw mut self.gicd.ctlr)
-                .write_volatile(value | DistributorControlRegister::EnableGrp1S.bits());
-        }
+        let value = field!(self.gicd, ctlr).read();
+        field!(self.gicd, ctlr).write(value | DistributorControlRegister::EnableGrp1S);
     }
 
     /// Enable Non-secure Group 1 interrupts
     pub fn enable_non_secure_group1(&mut self) {
-        // SAFETY: self.gicd can be dereferenced as a valid GIC Distributor register block
-        unsafe {
-            let value = (&raw const self.gicd.ctlr).read_volatile();
-            (&raw mut self.gicd.ctlr)
-                .write_volatile(value | DistributorControlRegister::EnableGrp1NS.bits());
-        }
+        let value = field!(self.gicd, ctlr).read();
+        field!(self.gicd, ctlr).write(value | DistributorControlRegister::EnableGrp1NS);
     }
 
     /// Select a range of interrupts for group 0
@@ -188,7 +240,7 @@
     where
         F: Fn(u32, u32) -> u32,
     {
-        let max_it_index: usize = self.gicd.igroupr.len() * 32;
+        let max_it_index: usize = field!(self.gicd, igroupr).split().len() * 32;
 
         if range.start > max_it_index || range.end > max_it_index {
             return Err(GicDistributorError::InvalidParameter);
@@ -197,10 +249,9 @@
         let (start_reg, start_bit) = Self::index_to_reg_and_bit(range.start);
         let (end_reg, end_bit) = Self::index_to_reg_and_bit(range.end);
 
-        // SAFETY: self.gicd can be dereferenced as a valid GIC Distributor register block
-        let mut modify_igroupr = |index, mask| unsafe {
-            let ptr: *mut u32 = (&raw mut self.gicd.igroupr[index]);
-            ptr.write_volatile(f(ptr.read_volatile(), mask));
+        let mut modify_igroupr = |index: usize, mask| {
+            let value = field!(self.gicd, igroupr).split()[index].read();
+            field!(self.gicd, igroupr).split()[index].write(f(value, mask));
         };
 
         if start_reg == end_reg {
@@ -274,94 +325,84 @@
 }
 
 // SAFETY: It is safe to access GicDistributor from any core/thread.
-unsafe impl<R> Sync for GicDistributor<R> where R: DerefMut<Target = GICDRegisters> {}
+unsafe impl Sync for GicDistributor<'_> {}
 
-#[test]
-fn test_gicd_size() {
-    assert_eq!(core::mem::size_of::<GICDRegisters>(), 0x1_0000);
-}
+#[cfg(test)]
+mod tests {
+    use super::*;
 
-#[test]
-fn test_bitmask() {
-    assert_eq!(
-        0x0000_0000,
-        GicDistributor::<&mut GICDRegisters>::create_mask(0..0)
-    );
-    assert_eq!(
-        0x0000_0001,
-        GicDistributor::<&mut GICDRegisters>::create_mask(0..1)
-    );
-    assert_eq!(
-        0x8000_0000,
-        GicDistributor::<&mut GICDRegisters>::create_mask(31..32)
-    );
-    assert_eq!(
-        0x0000_00ff,
-        GicDistributor::<&mut GICDRegisters>::create_mask(0..8)
-    );
-    assert_eq!(
-        0xffff_ffff,
-        GicDistributor::<&mut GICDRegisters>::create_mask(0..32)
-    );
-}
+    #[test]
+    fn test_gicd_size() {
+        assert_eq!(core::mem::size_of::<GICDRegisters>(), 0x1_0000);
+    }
 
-#[test]
-fn test_gicd() {
-    extern crate alloc;
-    use alloc::vec::Vec;
+    #[test]
+    fn test_bitmask() {
+        assert_eq!(0x0000_0000, GicDistributor::create_mask(0..0));
+        assert_eq!(0x0000_0001, GicDistributor::create_mask(0..1));
+        assert_eq!(0x8000_0000, GicDistributor::create_mask(31..32));
+        assert_eq!(0x0000_00ff, GicDistributor::create_mask(0..8));
+        assert_eq!(0xffff_ffff, GicDistributor::create_mask(0..32));
+    }
 
-    let area: [u32; 0x4000] = [0; 0x4000];
-    let mut registers: GICDRegisters = unsafe { core::mem::transmute(area) };
+    fn check_igroup(expected: &[u32], mut registers: UniqueMmioPointer<GICDRegisters>) {
+        for (index, expected) in expected.iter().enumerate() {
+            let actual = field!(registers, igroupr).split()[index].read();
+            assert_eq!(*expected, actual);
+        }
+    }
 
-    let mut gic_distributor = GicDistributor::new(&mut registers);
-    gic_distributor.select_group0_range(8..16).unwrap();
-    let result: Vec<u32> = registers.igroupr.to_vec();
-    let mut expected = [0xffff_ffffu32; 32];
-    expected[0] = 0xffff_00ff;
-    assert_eq!(result.as_slice(), &expected);
+    #[test]
+    fn test_gicd() {
+        let area: [u32; 0x4000] = [0; 0x4000];
+        let mut registers: GICDRegisters = unsafe { core::mem::transmute(area) };
 
-    let mut gic_distributor = GicDistributor::new(&mut registers);
-    gic_distributor.select_group0_range(8..40).unwrap();
-    let result: Vec<u32> = registers.igroupr.to_vec();
-    let mut expected = [0xffff_ffffu32; 32];
-    expected[0] = 0x0000_00ff;
-    expected[1] = 0xffff_ff00;
-    assert_eq!(result.as_slice(), &expected);
+        {
+            let mut gic_distributor = GicDistributor::new((&mut registers).into());
+            gic_distributor.select_group0_range(8..16).unwrap();
+        }
 
-    let mut gic_distributor = GicDistributor::new(&mut registers);
-    gic_distributor.select_group0_range(8..72).unwrap();
-    let result: Vec<u32> = registers.igroupr.to_vec();
-    let mut expected = [0xffff_ffffu32; 32];
-    expected[0] = 0x0000_00ff;
-    expected[1] = 0x0000_0000;
-    expected[2] = 0xffff_ff00;
-    assert_eq!(result.as_slice(), &expected);
+        let mut expected = [0xffff_ffffu32; 32];
+        expected[0] = 0xffff_00ff;
+        check_igroup(&expected, (&mut registers).into());
 
-    let mut gic_distributor = GicDistributor::new(&mut registers);
-    gic_distributor.select_group0_range(8..64).unwrap();
-    let result: Vec<u32> = registers.igroupr.to_vec();
-    let mut expected = [0xffff_ffffu32; 32];
-    expected[0] = 0x0000_00ff;
-    expected[1] = 0x0000_0000;
-    assert_eq!(result.as_slice(), &expected);
+        let mut gic_distributor = GicDistributor::new((&mut registers).into());
+        gic_distributor.select_group0_range(8..40).unwrap();
+        let mut expected = [0xffff_ffffu32; 32];
+        expected[0] = 0x0000_00ff;
+        expected[1] = 0xffff_ff00;
+        check_igroup(&expected, (&mut registers).into());
 
-    let mut gic_distributor = GicDistributor::new(&mut registers);
-    gic_distributor.select_group0_range(1..1023).unwrap();
-    let result: Vec<u32> = registers.igroupr.to_vec();
-    let mut expected = [0x0000_0000u32; 32];
-    expected[0] = 0x0000_0001;
-    expected[31] = 0x8000_0000;
-    assert_eq!(result.as_slice(), &expected);
+        let mut gic_distributor = GicDistributor::new((&mut registers).into());
+        gic_distributor.select_group0_range(8..72).unwrap();
+        let mut expected = [0xffff_ffffu32; 32];
+        expected[0] = 0x0000_00ff;
+        expected[1] = 0x0000_0000;
+        expected[2] = 0xffff_ff00;
+        check_igroup(&expected, (&mut registers).into());
 
-    let mut gic_distributor = GicDistributor::new(&mut registers);
-    gic_distributor.select_group0_range(0..1024).unwrap();
-    let result: Vec<u32> = registers.igroupr.to_vec();
-    let expected = [0x0000_0000u32; 32];
-    assert_eq!(result.as_slice(), &expected);
+        let mut gic_distributor = GicDistributor::new((&mut registers).into());
+        gic_distributor.select_group0_range(8..64).unwrap();
+        let mut expected = [0xffff_ffffu32; 32];
+        expected[0] = 0x0000_00ff;
+        expected[1] = 0x0000_0000;
+        check_igroup(&expected, (&mut registers).into());
 
-    let mut gic_distributor = GicDistributor::new(&mut registers);
-    assert!(gic_distributor.select_group0_range(0..2048).is_err());
-    let result: Vec<u32> = registers.igroupr.to_vec();
-    let expected = [0xffff_ffffu32; 32];
-    assert_eq!(result.as_slice(), &expected);
+        let mut gic_distributor = GicDistributor::new((&mut registers).into());
+        gic_distributor.select_group0_range(1..1023).unwrap();
+        let mut expected = [0x0000_0000u32; 32];
+        expected[0] = 0x0000_0001;
+        expected[31] = 0x8000_0000;
+        check_igroup(&expected, (&mut registers).into());
+
+        let mut gic_distributor = GicDistributor::new((&mut registers).into());
+        gic_distributor.select_group0_range(0..1024).unwrap();
+        let expected = [0x0000_0000u32; 32];
+        check_igroup(&expected, (&mut registers).into());
+
+        let mut gic_distributor = GicDistributor::new((&mut registers).into());
+        assert!(gic_distributor.select_group0_range(0..2048).is_err());
+        let expected = [0xffff_ffffu32; 32];
+        check_igroup(&expected, (&mut registers).into());
+    }
 }