Various minor improvements

pull/171/head
Andre Richter 2 years ago
parent b22b0b1792
commit 2345214367
No known key found for this signature in database
GPG Key ID: 2116C1AB102F615E

@ -302,6 +302,15 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/time.rs 07_timestamps/src/_arch/
+// Private Code +// Private Code
+//-------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------
+ +
+fn arch_timer_counter_frequency() -> NonZeroU32 {
+ // Read volatile is needed here to prevent the compiler from optimizing
+ // ARCH_TIMER_COUNTER_FREQUENCY away.
+ //
+ // This is safe, because all the safety requirements as stated in read_volatile()'s
+ // documentation are fulfilled.
+ unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }
+}
+
+impl GenericTimerCounterValue { +impl GenericTimerCounterValue {
+ pub const MAX: Self = GenericTimerCounterValue(u64::MAX); + pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
+} +}
@ -320,13 +329,7 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/time.rs 07_timestamps/src/_arch/
+ return Duration::ZERO; + return Duration::ZERO;
+ } + }
+ +
+ // Read volatile is needed here to prevent the compiler from optimizing + let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
+ // ARCH_TIMER_COUNTER_FREQUENCY away.
+ //
+ // This is safe, because all the safety requirements as stated in read_volatile()'s
+ // documentation are fulfilled.
+ let frequency: NonZeroU64 =
+ unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
+ +
+ // Div<NonZeroU64> implementation for u64 cannot panic. + // Div<NonZeroU64> implementation for u64 cannot panic.
+ let secs = counter_value.0.div(frequency); + let secs = counter_value.0.div(frequency);
@ -361,10 +364,7 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/time.rs 07_timestamps/src/_arch/
+ return Err("Conversion error. Duration too big"); + return Err("Conversion error. Duration too big");
+ } + }
+ +
+ // This is safe, because all the safety requirements as stated in read_volatile()'s + let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
+ // documentation are fulfilled.
+ let frequency: u128 =
+ unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
+ let duration: u128 = duration.as_nanos(); + let duration: u128 = duration.as_nanos();
+ +
+ // This is safe, because frequency can never be greater than u32::MAX, and + // This is safe, because frequency can never be greater than u32::MAX, and

@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN;
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn arch_timer_counter_frequency() -> NonZeroU32 {
// Read volatile is needed here to prevent the compiler from optimizing
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }
}
impl GenericTimerCounterValue { impl GenericTimerCounterValue {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX); pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
} }
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO; return Duration::ZERO;
} }
// Read volatile is needed here to prevent the compiler from optimizing let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
// Div<NonZeroU64> implementation for u64 cannot panic. // Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency); let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big"); return Err("Conversion error. Duration too big");
} }
// This is safe, because all the safety requirements as stated in read_volatile()'s let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let duration: u128 = duration.as_nanos(); let duration: u128 = duration.as_nanos();
// This is safe, because frequency can never be greater than u32::MAX, and // This is safe, because frequency can never be greater than u32::MAX, and

@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN;
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn arch_timer_counter_frequency() -> NonZeroU32 {
// Read volatile is needed here to prevent the compiler from optimizing
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }
}
impl GenericTimerCounterValue { impl GenericTimerCounterValue {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX); pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
} }
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO; return Duration::ZERO;
} }
// Read volatile is needed here to prevent the compiler from optimizing let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
// Div<NonZeroU64> implementation for u64 cannot panic. // Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency); let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big"); return Err("Conversion error. Duration too big");
} }
// This is safe, because all the safety requirements as stated in read_volatile()'s let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let duration: u128 = duration.as_nanos(); let duration: u128 = duration.as_nanos();
// This is safe, because frequency can never be greater than u32::MAX, and // This is safe, because frequency can never be greater than u32::MAX, and

@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN;
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn arch_timer_counter_frequency() -> NonZeroU32 {
// Read volatile is needed here to prevent the compiler from optimizing
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }
}
impl GenericTimerCounterValue { impl GenericTimerCounterValue {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX); pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
} }
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO; return Duration::ZERO;
} }
// Read volatile is needed here to prevent the compiler from optimizing let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
// Div<NonZeroU64> implementation for u64 cannot panic. // Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency); let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big"); return Err("Conversion error. Duration too big");
} }
// This is safe, because all the safety requirements as stated in read_volatile()'s let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let duration: u128 = duration.as_nanos(); let duration: u128 = duration.as_nanos();
// This is safe, because frequency can never be greater than u32::MAX, and // This is safe, because frequency can never be greater than u32::MAX, and

@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN;
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn arch_timer_counter_frequency() -> NonZeroU32 {
// Read volatile is needed here to prevent the compiler from optimizing
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }
}
impl GenericTimerCounterValue { impl GenericTimerCounterValue {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX); pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
} }
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO; return Duration::ZERO;
} }
// Read volatile is needed here to prevent the compiler from optimizing let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
// Div<NonZeroU64> implementation for u64 cannot panic. // Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency); let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big"); return Err("Conversion error. Duration too big");
} }
// This is safe, because all the safety requirements as stated in read_volatile()'s let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let duration: u128 = duration.as_nanos(); let duration: u128 = duration.as_nanos();
// This is safe, because frequency can never be greater than u32::MAX, and // This is safe, because frequency can never be greater than u32::MAX, and

@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN;
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn arch_timer_counter_frequency() -> NonZeroU32 {
// Read volatile is needed here to prevent the compiler from optimizing
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }
}
impl GenericTimerCounterValue { impl GenericTimerCounterValue {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX); pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
} }
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO; return Duration::ZERO;
} }
// Read volatile is needed here to prevent the compiler from optimizing let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
// Div<NonZeroU64> implementation for u64 cannot panic. // Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency); let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big"); return Err("Conversion error. Duration too big");
} }
// This is safe, because all the safety requirements as stated in read_volatile()'s let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let duration: u128 = duration.as_nanos(); let duration: u128 = duration.as_nanos();
// This is safe, because frequency can never be greater than u32::MAX, and // This is safe, because frequency can never be greater than u32::MAX, and

@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN;
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn arch_timer_counter_frequency() -> NonZeroU32 {
// Read volatile is needed here to prevent the compiler from optimizing
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }
}
impl GenericTimerCounterValue { impl GenericTimerCounterValue {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX); pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
} }
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO; return Duration::ZERO;
} }
// Read volatile is needed here to prevent the compiler from optimizing let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
// Div<NonZeroU64> implementation for u64 cannot panic. // Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency); let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big"); return Err("Conversion error. Duration too big");
} }
// This is safe, because all the safety requirements as stated in read_volatile()'s let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let duration: u128 = duration.as_nanos(); let duration: u128 = duration.as_nanos();
// This is safe, because frequency can never be greater than u32::MAX, and // This is safe, because frequency can never be greater than u32::MAX, and

@ -1249,7 +1249,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2/gicd.rs 1
diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs
--- 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs --- 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs
+++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/gicv2.rs
@@ -0,0 +1,221 @@ @@ -0,0 +1,220 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-License-Identifier: MIT OR Apache-2.0
+// +//
+// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com> +// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
@ -1337,7 +1337,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc
+// Private Definitions +// Private Definitions
+//-------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------
+ +
+type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; GICv2::NUM_IRQS]; +type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; IRQNumber::NUM_TOTAL];
+ +
+//-------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------
+// Public Definitions +// Public Definitions
@ -1364,7 +1364,6 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc
+ +
+impl GICv2 { +impl GICv2 {
+ const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. + const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space.
+ const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1;
+ +
+ pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; + pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)";
+ +
@ -1377,7 +1376,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc
+ Self { + Self {
+ gicd: gicd::GICD::new(gicd_mmio_start_addr), + gicd: gicd::GICD::new(gicd_mmio_start_addr),
+ gicc: gicc::GICC::new(gicc_mmio_start_addr), + gicc: gicc::GICC::new(gicc_mmio_start_addr),
+ handler_table: InitStateLock::new([None; Self::NUM_IRQS]), + handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]),
+ } + }
+ } + }
+} +}
@ -1520,14 +1519,18 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs
diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs
--- 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs --- 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs
+++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs
@@ -0,0 +1,167 @@ @@ -0,0 +1,170 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-License-Identifier: MIT OR Apache-2.0
+// +//
+// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com> +// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
+ +
+//! Peripheral Interrupt Controller Driver. +//! Peripheral Interrupt Controller Driver.
+//!
+//! # Resources
+//!
+//! - <https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf>
+ +
+use super::{InterruptController, PendingIRQs, PeripheralIRQ}; +use super::{PendingIRQs, PeripheralIRQ};
+use crate::{ +use crate::{
+ bsp::device_driver::common::MMIODerefWrapper, + bsp::device_driver::common::MMIODerefWrapper,
+ exception, synchronization, + exception, synchronization,
@ -1569,8 +1572,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru
+/// Abstraction for the ReadOnly parts of the associated MMIO registers. +/// Abstraction for the ReadOnly parts of the associated MMIO registers.
+type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>; +type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
+ +
+type HandlerTable = +type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; PeripheralIRQ::NUM_TOTAL];
+ [Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
+ +
+//-------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------
+// Public Definitions +// Public Definitions
@ -1602,7 +1604,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru
+ Self { + Self {
+ wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), + wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)),
+ ro_registers: ReadOnlyRegisters::new(mmio_start_addr), + ro_registers: ReadOnlyRegisters::new(mmio_start_addr),
+ handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), + handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]),
+ } + }
+ } + }
+ +
@ -1692,7 +1694,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru
diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs
--- 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs --- 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs
+++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs
@@ -0,0 +1,134 @@ @@ -0,0 +1,131 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-License-Identifier: MIT OR Apache-2.0
+// +//
+// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com> +// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
@ -1748,16 +1750,13 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru
+ type Item = usize; + type Item = usize;
+ +
+ fn next(&mut self) -> Option<Self::Item> { + fn next(&mut self) -> Option<Self::Item> {
+ use core::intrinsics::cttz; + if self.bitmask == 0 {
+
+ let next = cttz(self.bitmask);
+ if next == 64 {
+ return None; + return None;
+ } + }
+ +
+ self.bitmask &= !(1 << next); + let next = self.bitmask.trailing_zeros() as usize;
+ + self.bitmask &= self.bitmask.wrapping_sub(1);
+ Some(next as usize) + Some(next)
+ } + }
+} +}
+ +
@ -1766,9 +1765,9 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru
+//-------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------
+ +
+impl InterruptController { +impl InterruptController {
+ const MAX_LOCAL_IRQ_NUMBER: usize = 11; + // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward.
+ const MAX_LOCAL_IRQ_NUMBER: usize = 3;
+ const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; + const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63;
+ const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1;
+ +
+ pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; + pub const COMPATIBLE: &'static str = "BCM Interrupt Controller";
+ +
@ -2230,7 +2229,7 @@ diff -uNr 12_integrated_testing/kernel/src/driver.rs 13_exceptions_part2_periphe
diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs
--- 12_integrated_testing/kernel/src/exception/asynchronous.rs --- 12_integrated_testing/kernel/src/exception/asynchronous.rs
+++ 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs +++ 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.rs
@@ -8,7 +8,149 @@ @@ -8,7 +8,152 @@
#[path = "../_arch/aarch64/exception/asynchronous.rs"] #[path = "../_arch/aarch64/exception/asynchronous.rs"]
mod arch_asynchronous; mod arch_asynchronous;
@ -2343,6 +2342,9 @@ diff -uNr 12_integrated_testing/kernel/src/exception/asynchronous.rs 13_exceptio
+} +}
+ +
+impl<const MAX_INCLUSIVE: usize> IRQNumber<{ MAX_INCLUSIVE }> { +impl<const MAX_INCLUSIVE: usize> IRQNumber<{ MAX_INCLUSIVE }> {
+ /// The total number of IRQs this type supports.
+ pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1;
+
+ /// Creates a new instance if number <= MAX_INCLUSIVE. + /// Creates a new instance if number <= MAX_INCLUSIVE.
+ pub const fn new(number: usize) -> Self { + pub const fn new(number: usize) -> Self {
+ assert!(number <= MAX_INCLUSIVE); + assert!(number <= MAX_INCLUSIVE);

@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN;
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn arch_timer_counter_frequency() -> NonZeroU32 {
// Read volatile is needed here to prevent the compiler from optimizing
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }
}
impl GenericTimerCounterValue { impl GenericTimerCounterValue {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX); pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
} }
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO; return Duration::ZERO;
} }
// Read volatile is needed here to prevent the compiler from optimizing let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
// Div<NonZeroU64> implementation for u64 cannot panic. // Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency); let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big"); return Err("Conversion error. Duration too big");
} }
// This is safe, because all the safety requirements as stated in read_volatile()'s let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let duration: u128 = duration.as_nanos(); let duration: u128 = duration.as_nanos();
// This is safe, because frequency can never be greater than u32::MAX, and // This is safe, because frequency can never be greater than u32::MAX, and

@ -85,7 +85,7 @@ use crate::{bsp, cpu, driver, exception, synchronization, synchronization::InitS
// Private Definitions // Private Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; GICv2::NUM_IRQS]; type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; IRQNumber::NUM_TOTAL];
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
@ -112,7 +112,6 @@ pub struct GICv2 {
impl GICv2 { impl GICv2 {
const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space.
const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)";
@ -125,7 +124,7 @@ impl GICv2 {
Self { Self {
gicd: gicd::GICD::new(gicd_mmio_start_addr), gicd: gicd::GICD::new(gicd_mmio_start_addr),
gicc: gicc::GICC::new(gicc_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr),
handler_table: InitStateLock::new([None; Self::NUM_IRQS]), handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]),
} }
} }
} }

@ -53,16 +53,13 @@ impl Iterator for PendingIRQs {
type Item = usize; type Item = usize;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
use core::intrinsics::cttz; if self.bitmask == 0 {
let next = cttz(self.bitmask);
if next == 64 {
return None; return None;
} }
self.bitmask &= !(1 << next); let next = self.bitmask.trailing_zeros() as usize;
self.bitmask &= self.bitmask.wrapping_sub(1);
Some(next as usize) Some(next)
} }
} }
@ -71,9 +68,9 @@ impl Iterator for PendingIRQs {
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
impl InterruptController { impl InterruptController {
const MAX_LOCAL_IRQ_NUMBER: usize = 11; // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward.
const MAX_LOCAL_IRQ_NUMBER: usize = 3;
const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63;
const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; pub const COMPATIBLE: &'static str = "BCM Interrupt Controller";

@ -3,8 +3,12 @@
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com> // Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
//! Peripheral Interrupt Controller Driver. //! Peripheral Interrupt Controller Driver.
//!
//! # Resources
//!
//! - <https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf>
use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use super::{PendingIRQs, PeripheralIRQ};
use crate::{ use crate::{
bsp::device_driver::common::MMIODerefWrapper, bsp::device_driver::common::MMIODerefWrapper,
exception, synchronization, exception, synchronization,
@ -46,8 +50,7 @@ type WriteOnlyRegisters = MMIODerefWrapper<WORegisterBlock>;
/// Abstraction for the ReadOnly parts of the associated MMIO registers. /// Abstraction for the ReadOnly parts of the associated MMIO registers.
type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>; type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
type HandlerTable = type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; PeripheralIRQ::NUM_TOTAL];
[Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
@ -79,7 +82,7 @@ impl PeripheralIC {
Self { Self {
wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)),
ro_registers: ReadOnlyRegisters::new(mmio_start_addr), ro_registers: ReadOnlyRegisters::new(mmio_start_addr),
handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]),
} }
} }

@ -116,6 +116,9 @@ impl<'irq_context> IRQContext<'irq_context> {
} }
impl<const MAX_INCLUSIVE: usize> IRQNumber<{ MAX_INCLUSIVE }> { impl<const MAX_INCLUSIVE: usize> IRQNumber<{ MAX_INCLUSIVE }> {
/// The total number of IRQs this type supports.
pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1;
/// Creates a new instance if number <= MAX_INCLUSIVE. /// Creates a new instance if number <= MAX_INCLUSIVE.
pub const fn new(number: usize) -> Self { pub const fn new(number: usize) -> Self {
assert!(number <= MAX_INCLUSIVE); assert!(number <= MAX_INCLUSIVE);

@ -948,7 +948,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/g
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -121,11 +129,16 @@ @@ -120,11 +128,16 @@
/// # Safety /// # Safety
/// ///
/// - The user must ensure to provide a correct MMIO start address. /// - The user must ensure to provide a correct MMIO start address.
@ -961,12 +961,12 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/arm/g
Self { Self {
gicd: gicd::GICD::new(gicd_mmio_start_addr), gicd: gicd::GICD::new(gicd_mmio_start_addr),
gicc: gicc::GICC::new(gicc_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr),
handler_table: InitStateLock::new([None; Self::NUM_IRQS]), handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]),
+ post_init_callback, + post_init_callback,
} }
} }
} }
@@ -148,6 +161,8 @@ @@ -147,6 +160,8 @@
self.gicc.priority_accept_all(); self.gicc.priority_accept_all();
self.gicc.enable(); self.gicc.enable();
@ -1035,8 +1035,8 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/b
diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs
--- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs --- 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs
+++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ 14_virtual_mem_part2_mmio_remap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs
@@ -7,7 +7,9 @@ @@ -11,7 +11,9 @@
use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use super::{PendingIRQs, PeripheralIRQ};
use crate::{ use crate::{
bsp::device_driver::common::MMIODerefWrapper, bsp::device_driver::common::MMIODerefWrapper,
- exception, synchronization, - exception, synchronization,
@ -1046,7 +1046,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/b
synchronization::{IRQSafeNullLock, InitStateLock}, synchronization::{IRQSafeNullLock, InitStateLock},
}; };
use tock_registers::{ use tock_registers::{
@@ -75,7 +77,7 @@ @@ -78,7 +80,7 @@
/// # Safety /// # Safety
/// ///
/// - The user must ensure to provide a correct MMIO start address. /// - The user must ensure to provide a correct MMIO start address.
@ -1079,7 +1079,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/b
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -82,9 +86,13 @@ @@ -79,9 +83,13 @@
/// # Safety /// # Safety
/// ///
/// - The user must ensure to provide a correct MMIO start address. /// - The user must ensure to provide a correct MMIO start address.
@ -1094,7 +1094,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/b
} }
} }
} }
@@ -97,6 +105,12 @@ @@ -94,6 +102,12 @@
fn compatible(&self) -> &'static str { fn compatible(&self) -> &'static str {
Self::COMPATIBLE Self::COMPATIBLE
} }
@ -2302,7 +2302,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.
impl<'irq_context> IRQContext<'irq_context> { impl<'irq_context> IRQContext<'irq_context> {
/// Creates an IRQContext token. /// Creates an IRQContext token.
@@ -148,9 +158,17 @@ @@ -151,9 +161,17 @@
ret ret
} }

@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN;
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn arch_timer_counter_frequency() -> NonZeroU32 {
// Read volatile is needed here to prevent the compiler from optimizing
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }
}
impl GenericTimerCounterValue { impl GenericTimerCounterValue {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX); pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
} }
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO; return Duration::ZERO;
} }
// Read volatile is needed here to prevent the compiler from optimizing let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
// Div<NonZeroU64> implementation for u64 cannot panic. // Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency); let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big"); return Err("Conversion error. Duration too big");
} }
// This is safe, because all the safety requirements as stated in read_volatile()'s let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let duration: u128 = duration.as_nanos(); let duration: u128 = duration.as_nanos();
// This is safe, because frequency can never be greater than u32::MAX, and // This is safe, because frequency can never be greater than u32::MAX, and

@ -90,7 +90,7 @@ use crate::{
// Private Definitions // Private Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; GICv2::NUM_IRQS]; type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; IRQNumber::NUM_TOTAL];
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
@ -120,7 +120,6 @@ pub struct GICv2 {
impl GICv2 { impl GICv2 {
const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space.
const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)";
@ -137,7 +136,7 @@ impl GICv2 {
Self { Self {
gicd: gicd::GICD::new(gicd_mmio_start_addr), gicd: gicd::GICD::new(gicd_mmio_start_addr),
gicc: gicc::GICC::new(gicc_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr),
handler_table: InitStateLock::new([None; Self::NUM_IRQS]), handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]),
post_init_callback, post_init_callback,
} }
} }

@ -57,16 +57,13 @@ impl Iterator for PendingIRQs {
type Item = usize; type Item = usize;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
use core::intrinsics::cttz; if self.bitmask == 0 {
let next = cttz(self.bitmask);
if next == 64 {
return None; return None;
} }
self.bitmask &= !(1 << next); let next = self.bitmask.trailing_zeros() as usize;
self.bitmask &= self.bitmask.wrapping_sub(1);
Some(next as usize) Some(next)
} }
} }
@ -75,9 +72,9 @@ impl Iterator for PendingIRQs {
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
impl InterruptController { impl InterruptController {
const MAX_LOCAL_IRQ_NUMBER: usize = 11; // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward.
const MAX_LOCAL_IRQ_NUMBER: usize = 3;
const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63;
const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; pub const COMPATIBLE: &'static str = "BCM Interrupt Controller";

@ -3,8 +3,12 @@
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com> // Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
//! Peripheral Interrupt Controller Driver. //! Peripheral Interrupt Controller Driver.
//!
//! # Resources
//!
//! - <https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf>
use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use super::{PendingIRQs, PeripheralIRQ};
use crate::{ use crate::{
bsp::device_driver::common::MMIODerefWrapper, bsp::device_driver::common::MMIODerefWrapper,
exception, exception,
@ -48,8 +52,7 @@ type WriteOnlyRegisters = MMIODerefWrapper<WORegisterBlock>;
/// Abstraction for the ReadOnly parts of the associated MMIO registers. /// Abstraction for the ReadOnly parts of the associated MMIO registers.
type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>; type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
type HandlerTable = type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; PeripheralIRQ::NUM_TOTAL];
[Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
@ -81,7 +84,7 @@ impl PeripheralIC {
Self { Self {
wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)),
ro_registers: ReadOnlyRegisters::new(mmio_start_addr), ro_registers: ReadOnlyRegisters::new(mmio_start_addr),
handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]),
} }
} }

@ -126,6 +126,9 @@ impl<'irq_context> IRQContext<'irq_context> {
} }
impl<const MAX_INCLUSIVE: usize> IRQNumber<{ MAX_INCLUSIVE }> { impl<const MAX_INCLUSIVE: usize> IRQNumber<{ MAX_INCLUSIVE }> {
/// The total number of IRQs this type supports.
pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1;
/// Creates a new instance if number <= MAX_INCLUSIVE. /// Creates a new instance if number <= MAX_INCLUSIVE.
pub const fn new(number: usize) -> Self { pub const fn new(number: usize) -> Self {
assert!(number <= MAX_INCLUSIVE); assert!(number <= MAX_INCLUSIVE);

@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN;
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn arch_timer_counter_frequency() -> NonZeroU32 {
// Read volatile is needed here to prevent the compiler from optimizing
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }
}
impl GenericTimerCounterValue { impl GenericTimerCounterValue {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX); pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
} }
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO; return Duration::ZERO;
} }
// Read volatile is needed here to prevent the compiler from optimizing let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
// Div<NonZeroU64> implementation for u64 cannot panic. // Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency); let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big"); return Err("Conversion error. Duration too big");
} }
// This is safe, because all the safety requirements as stated in read_volatile()'s let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let duration: u128 = duration.as_nanos(); let duration: u128 = duration.as_nanos();
// This is safe, because frequency can never be greater than u32::MAX, and // This is safe, because frequency can never be greater than u32::MAX, and

@ -90,7 +90,7 @@ use crate::{
// Private Definitions // Private Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; GICv2::NUM_IRQS]; type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; IRQNumber::NUM_TOTAL];
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
@ -120,7 +120,6 @@ pub struct GICv2 {
impl GICv2 { impl GICv2 {
const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space.
const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)";
@ -137,7 +136,7 @@ impl GICv2 {
Self { Self {
gicd: gicd::GICD::new(gicd_mmio_start_addr), gicd: gicd::GICD::new(gicd_mmio_start_addr),
gicc: gicc::GICC::new(gicc_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr),
handler_table: InitStateLock::new([None; Self::NUM_IRQS]), handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]),
post_init_callback, post_init_callback,
} }
} }

@ -57,16 +57,13 @@ impl Iterator for PendingIRQs {
type Item = usize; type Item = usize;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
use core::intrinsics::cttz; if self.bitmask == 0 {
let next = cttz(self.bitmask);
if next == 64 {
return None; return None;
} }
self.bitmask &= !(1 << next); let next = self.bitmask.trailing_zeros() as usize;
self.bitmask &= self.bitmask.wrapping_sub(1);
Some(next as usize) Some(next)
} }
} }
@ -75,9 +72,9 @@ impl Iterator for PendingIRQs {
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
impl InterruptController { impl InterruptController {
const MAX_LOCAL_IRQ_NUMBER: usize = 11; // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward.
const MAX_LOCAL_IRQ_NUMBER: usize = 3;
const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63;
const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; pub const COMPATIBLE: &'static str = "BCM Interrupt Controller";

@ -3,8 +3,12 @@
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com> // Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
//! Peripheral Interrupt Controller Driver. //! Peripheral Interrupt Controller Driver.
//!
//! # Resources
//!
//! - <https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf>
use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use super::{PendingIRQs, PeripheralIRQ};
use crate::{ use crate::{
bsp::device_driver::common::MMIODerefWrapper, bsp::device_driver::common::MMIODerefWrapper,
exception, exception,
@ -48,8 +52,7 @@ type WriteOnlyRegisters = MMIODerefWrapper<WORegisterBlock>;
/// Abstraction for the ReadOnly parts of the associated MMIO registers. /// Abstraction for the ReadOnly parts of the associated MMIO registers.
type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>; type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
type HandlerTable = type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; PeripheralIRQ::NUM_TOTAL];
[Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
@ -81,7 +84,7 @@ impl PeripheralIC {
Self { Self {
wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)),
ro_registers: ReadOnlyRegisters::new(mmio_start_addr), ro_registers: ReadOnlyRegisters::new(mmio_start_addr),
handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]),
} }
} }

@ -126,6 +126,9 @@ impl<'irq_context> IRQContext<'irq_context> {
} }
impl<const MAX_INCLUSIVE: usize> IRQNumber<{ MAX_INCLUSIVE }> { impl<const MAX_INCLUSIVE: usize> IRQNumber<{ MAX_INCLUSIVE }> {
/// The total number of IRQs this type supports.
pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1;
/// Creates a new instance if number <= MAX_INCLUSIVE. /// Creates a new instance if number <= MAX_INCLUSIVE.
pub const fn new(number: usize) -> Self { pub const fn new(number: usize) -> Self {
assert!(number <= MAX_INCLUSIVE); assert!(number <= MAX_INCLUSIVE);

@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN;
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn arch_timer_counter_frequency() -> NonZeroU32 {
// Read volatile is needed here to prevent the compiler from optimizing
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }
}
impl GenericTimerCounterValue { impl GenericTimerCounterValue {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX); pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
} }
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO; return Duration::ZERO;
} }
// Read volatile is needed here to prevent the compiler from optimizing let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
// Div<NonZeroU64> implementation for u64 cannot panic. // Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency); let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big"); return Err("Conversion error. Duration too big");
} }
// This is safe, because all the safety requirements as stated in read_volatile()'s let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let duration: u128 = duration.as_nanos(); let duration: u128 = duration.as_nanos();
// This is safe, because frequency can never be greater than u32::MAX, and // This is safe, because frequency can never be greater than u32::MAX, and

@ -90,7 +90,7 @@ use crate::{
// Private Definitions // Private Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; GICv2::NUM_IRQS]; type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; IRQNumber::NUM_TOTAL];
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
@ -120,7 +120,6 @@ pub struct GICv2 {
impl GICv2 { impl GICv2 {
const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space.
const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)";
@ -137,7 +136,7 @@ impl GICv2 {
Self { Self {
gicd: gicd::GICD::new(gicd_mmio_start_addr), gicd: gicd::GICD::new(gicd_mmio_start_addr),
gicc: gicc::GICC::new(gicc_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr),
handler_table: InitStateLock::new([None; Self::NUM_IRQS]), handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]),
post_init_callback, post_init_callback,
} }
} }

@ -57,16 +57,13 @@ impl Iterator for PendingIRQs {
type Item = usize; type Item = usize;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
use core::intrinsics::cttz; if self.bitmask == 0 {
let next = cttz(self.bitmask);
if next == 64 {
return None; return None;
} }
self.bitmask &= !(1 << next); let next = self.bitmask.trailing_zeros() as usize;
self.bitmask &= self.bitmask.wrapping_sub(1);
Some(next as usize) Some(next)
} }
} }
@ -75,9 +72,9 @@ impl Iterator for PendingIRQs {
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
impl InterruptController { impl InterruptController {
const MAX_LOCAL_IRQ_NUMBER: usize = 11; // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward.
const MAX_LOCAL_IRQ_NUMBER: usize = 3;
const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63;
const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; pub const COMPATIBLE: &'static str = "BCM Interrupt Controller";

@ -3,8 +3,12 @@
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com> // Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
//! Peripheral Interrupt Controller Driver. //! Peripheral Interrupt Controller Driver.
//!
//! # Resources
//!
//! - <https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf>
use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use super::{PendingIRQs, PeripheralIRQ};
use crate::{ use crate::{
bsp::device_driver::common::MMIODerefWrapper, bsp::device_driver::common::MMIODerefWrapper,
exception, exception,
@ -48,8 +52,7 @@ type WriteOnlyRegisters = MMIODerefWrapper<WORegisterBlock>;
/// Abstraction for the ReadOnly parts of the associated MMIO registers. /// Abstraction for the ReadOnly parts of the associated MMIO registers.
type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>; type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
type HandlerTable = type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; PeripheralIRQ::NUM_TOTAL];
[Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
@ -81,7 +84,7 @@ impl PeripheralIC {
Self { Self {
wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)),
ro_registers: ReadOnlyRegisters::new(mmio_start_addr), ro_registers: ReadOnlyRegisters::new(mmio_start_addr),
handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]),
} }
} }

@ -126,6 +126,9 @@ impl<'irq_context> IRQContext<'irq_context> {
} }
impl<const MAX_INCLUSIVE: usize> IRQNumber<{ MAX_INCLUSIVE }> { impl<const MAX_INCLUSIVE: usize> IRQNumber<{ MAX_INCLUSIVE }> {
/// The total number of IRQs this type supports.
pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1;
/// Creates a new instance if number <= MAX_INCLUSIVE. /// Creates a new instance if number <= MAX_INCLUSIVE.
pub const fn new(number: usize) -> Self { pub const fn new(number: usize) -> Self {
assert!(number <= MAX_INCLUSIVE); assert!(number <= MAX_INCLUSIVE);

@ -168,13 +168,18 @@ fn kernel_symbol_section_virt_start_addr() -> Address<Virtual> {
Address::new(unsafe { __kernel_symbols_start.get() as usize }) Address::new(unsafe { __kernel_symbols_start.get() as usize })
} }
fn num_kernel_symbols() -> usize {
unsafe {
// Read volatile is needed here to prevent the compiler from optimizing NUM_KERNEL_SYMBOLS
// away.
core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize
}
}
fn kernel_symbols_slice() -> &'static [Symbol] { fn kernel_symbols_slice() -> &'static [Symbol] {
let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol; let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol;
unsafe { unsafe { slice::from_raw_parts(ptr, num_kernel_symbols()) }
let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize;
slice::from_raw_parts(ptr, num)
}
} }
``` ```
@ -338,7 +343,7 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/lib.rs 17_kernel_sy
diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs 17_kernel_symbols/kernel/src/symbols.rs diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs 17_kernel_symbols/kernel/src/symbols.rs
--- 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs --- 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs
+++ 17_kernel_symbols/kernel/src/symbols.rs +++ 17_kernel_symbols/kernel/src/symbols.rs
@@ -0,0 +1,83 @@ @@ -0,0 +1,88 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-License-Identifier: MIT OR Apache-2.0
+// +//
+// Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com> +// Copyright (c) 2022 Andre Richter <andre.o.richter@gmail.com>
@ -375,13 +380,18 @@ diff -uNr 16_virtual_mem_part4_higher_half_kernel/kernel/src/symbols.rs 17_kerne
+ Address::new(unsafe { __kernel_symbols_start.get() as usize }) + Address::new(unsafe { __kernel_symbols_start.get() as usize })
+} +}
+ +
+fn num_kernel_symbols() -> usize {
+ unsafe {
+ // Read volatile is needed here to prevent the compiler from optimizing NUM_KERNEL_SYMBOLS
+ // away.
+ core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize
+ }
+}
+
+fn kernel_symbols_slice() -> &'static [Symbol] { +fn kernel_symbols_slice() -> &'static [Symbol] {
+ let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol; + let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol;
+ +
+ unsafe { + unsafe { slice::from_raw_parts(ptr, num_kernel_symbols()) }
+ let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize;
+ slice::from_raw_parts(ptr, num)
+ }
+} +}
+ +
+//-------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------

@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN;
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn arch_timer_counter_frequency() -> NonZeroU32 {
// Read volatile is needed here to prevent the compiler from optimizing
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }
}
impl GenericTimerCounterValue { impl GenericTimerCounterValue {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX); pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
} }
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO; return Duration::ZERO;
} }
// Read volatile is needed here to prevent the compiler from optimizing let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
// Div<NonZeroU64> implementation for u64 cannot panic. // Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency); let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big"); return Err("Conversion error. Duration too big");
} }
// This is safe, because all the safety requirements as stated in read_volatile()'s let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let duration: u128 = duration.as_nanos(); let duration: u128 = duration.as_nanos();
// This is safe, because frequency can never be greater than u32::MAX, and // This is safe, because frequency can never be greater than u32::MAX, and

@ -90,7 +90,7 @@ use crate::{
// Private Definitions // Private Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; GICv2::NUM_IRQS]; type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; IRQNumber::NUM_TOTAL];
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
@ -120,7 +120,6 @@ pub struct GICv2 {
impl GICv2 { impl GICv2 {
const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space.
const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)";
@ -137,7 +136,7 @@ impl GICv2 {
Self { Self {
gicd: gicd::GICD::new(gicd_mmio_start_addr), gicd: gicd::GICD::new(gicd_mmio_start_addr),
gicc: gicc::GICC::new(gicc_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr),
handler_table: InitStateLock::new([None; Self::NUM_IRQS]), handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]),
post_init_callback, post_init_callback,
} }
} }

@ -57,16 +57,13 @@ impl Iterator for PendingIRQs {
type Item = usize; type Item = usize;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
use core::intrinsics::cttz; if self.bitmask == 0 {
let next = cttz(self.bitmask);
if next == 64 {
return None; return None;
} }
self.bitmask &= !(1 << next); let next = self.bitmask.trailing_zeros() as usize;
self.bitmask &= self.bitmask.wrapping_sub(1);
Some(next as usize) Some(next)
} }
} }
@ -75,9 +72,9 @@ impl Iterator for PendingIRQs {
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
impl InterruptController { impl InterruptController {
const MAX_LOCAL_IRQ_NUMBER: usize = 11; // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward.
const MAX_LOCAL_IRQ_NUMBER: usize = 3;
const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63;
const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; pub const COMPATIBLE: &'static str = "BCM Interrupt Controller";

@ -3,8 +3,12 @@
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com> // Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
//! Peripheral Interrupt Controller Driver. //! Peripheral Interrupt Controller Driver.
//!
//! # Resources
//!
//! - <https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf>
use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use super::{PendingIRQs, PeripheralIRQ};
use crate::{ use crate::{
bsp::device_driver::common::MMIODerefWrapper, bsp::device_driver::common::MMIODerefWrapper,
exception, exception,
@ -48,8 +52,7 @@ type WriteOnlyRegisters = MMIODerefWrapper<WORegisterBlock>;
/// Abstraction for the ReadOnly parts of the associated MMIO registers. /// Abstraction for the ReadOnly parts of the associated MMIO registers.
type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>; type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
type HandlerTable = type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; PeripheralIRQ::NUM_TOTAL];
[Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
@ -81,7 +84,7 @@ impl PeripheralIC {
Self { Self {
wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)),
ro_registers: ReadOnlyRegisters::new(mmio_start_addr), ro_registers: ReadOnlyRegisters::new(mmio_start_addr),
handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]),
} }
} }

@ -126,6 +126,9 @@ impl<'irq_context> IRQContext<'irq_context> {
} }
impl<const MAX_INCLUSIVE: usize> IRQNumber<{ MAX_INCLUSIVE }> { impl<const MAX_INCLUSIVE: usize> IRQNumber<{ MAX_INCLUSIVE }> {
/// The total number of IRQs this type supports.
pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1;
/// Creates a new instance if number <= MAX_INCLUSIVE. /// Creates a new instance if number <= MAX_INCLUSIVE.
pub const fn new(number: usize) -> Self { pub const fn new(number: usize) -> Self {
assert!(number <= MAX_INCLUSIVE); assert!(number <= MAX_INCLUSIVE);

@ -34,13 +34,18 @@ fn kernel_symbol_section_virt_start_addr() -> Address<Virtual> {
Address::new(unsafe { __kernel_symbols_start.get() as usize }) Address::new(unsafe { __kernel_symbols_start.get() as usize })
} }
fn num_kernel_symbols() -> usize {
unsafe {
// Read volatile is needed here to prevent the compiler from optimizing NUM_KERNEL_SYMBOLS
// away.
core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize
}
}
fn kernel_symbols_slice() -> &'static [Symbol] { fn kernel_symbols_slice() -> &'static [Symbol] {
let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol; let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol;
unsafe { unsafe { slice::from_raw_parts(ptr, num_kernel_symbols()) }
let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize;
slice::from_raw_parts(ptr, num)
}
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------

@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN;
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn arch_timer_counter_frequency() -> NonZeroU32 {
// Read volatile is needed here to prevent the compiler from optimizing
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }
}
impl GenericTimerCounterValue { impl GenericTimerCounterValue {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX); pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
} }
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO; return Duration::ZERO;
} }
// Read volatile is needed here to prevent the compiler from optimizing let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
// Div<NonZeroU64> implementation for u64 cannot panic. // Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency); let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big"); return Err("Conversion error. Duration too big");
} }
// This is safe, because all the safety requirements as stated in read_volatile()'s let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let duration: u128 = duration.as_nanos(); let duration: u128 = duration.as_nanos();
// This is safe, because frequency can never be greater than u32::MAX, and // This is safe, because frequency can never be greater than u32::MAX, and

@ -90,7 +90,7 @@ use crate::{
// Private Definitions // Private Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; GICv2::NUM_IRQS]; type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; IRQNumber::NUM_TOTAL];
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
@ -120,7 +120,6 @@ pub struct GICv2 {
impl GICv2 { impl GICv2 {
const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space.
const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)";
@ -137,7 +136,7 @@ impl GICv2 {
Self { Self {
gicd: gicd::GICD::new(gicd_mmio_start_addr), gicd: gicd::GICD::new(gicd_mmio_start_addr),
gicc: gicc::GICC::new(gicc_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr),
handler_table: InitStateLock::new([None; Self::NUM_IRQS]), handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]),
post_init_callback, post_init_callback,
} }
} }

@ -57,16 +57,13 @@ impl Iterator for PendingIRQs {
type Item = usize; type Item = usize;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
use core::intrinsics::cttz; if self.bitmask == 0 {
let next = cttz(self.bitmask);
if next == 64 {
return None; return None;
} }
self.bitmask &= !(1 << next); let next = self.bitmask.trailing_zeros() as usize;
self.bitmask &= self.bitmask.wrapping_sub(1);
Some(next as usize) Some(next)
} }
} }
@ -75,9 +72,9 @@ impl Iterator for PendingIRQs {
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
impl InterruptController { impl InterruptController {
const MAX_LOCAL_IRQ_NUMBER: usize = 11; // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward.
const MAX_LOCAL_IRQ_NUMBER: usize = 3;
const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63;
const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; pub const COMPATIBLE: &'static str = "BCM Interrupt Controller";

@ -3,8 +3,12 @@
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com> // Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
//! Peripheral Interrupt Controller Driver. //! Peripheral Interrupt Controller Driver.
//!
//! # Resources
//!
//! - <https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf>
use super::{InterruptController, PendingIRQs, PeripheralIRQ}; use super::{PendingIRQs, PeripheralIRQ};
use crate::{ use crate::{
bsp::device_driver::common::MMIODerefWrapper, bsp::device_driver::common::MMIODerefWrapper,
exception, exception,
@ -48,8 +52,7 @@ type WriteOnlyRegisters = MMIODerefWrapper<WORegisterBlock>;
/// Abstraction for the ReadOnly parts of the associated MMIO registers. /// Abstraction for the ReadOnly parts of the associated MMIO registers.
type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>; type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
type HandlerTable = type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; PeripheralIRQ::NUM_TOTAL];
[Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
@ -81,7 +84,7 @@ impl PeripheralIC {
Self { Self {
wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)),
ro_registers: ReadOnlyRegisters::new(mmio_start_addr), ro_registers: ReadOnlyRegisters::new(mmio_start_addr),
handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]),
} }
} }

@ -126,6 +126,9 @@ impl<'irq_context> IRQContext<'irq_context> {
} }
impl<const MAX_INCLUSIVE: usize> IRQNumber<{ MAX_INCLUSIVE }> { impl<const MAX_INCLUSIVE: usize> IRQNumber<{ MAX_INCLUSIVE }> {
/// The total number of IRQs this type supports.
pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1;
/// Creates a new instance if number <= MAX_INCLUSIVE. /// Creates a new instance if number <= MAX_INCLUSIVE.
pub const fn new(number: usize) -> Self { pub const fn new(number: usize) -> Self {
assert!(number <= MAX_INCLUSIVE); assert!(number <= MAX_INCLUSIVE);

@ -34,13 +34,18 @@ fn kernel_symbol_section_virt_start_addr() -> Address<Virtual> {
Address::new(unsafe { __kernel_symbols_start.get() as usize }) Address::new(unsafe { __kernel_symbols_start.get() as usize })
} }
fn num_kernel_symbols() -> usize {
unsafe {
// Read volatile is needed here to prevent the compiler from optimizing NUM_KERNEL_SYMBOLS
// away.
core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize
}
}
fn kernel_symbols_slice() -> &'static [Symbol] { fn kernel_symbols_slice() -> &'static [Symbol] {
let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol; let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol;
unsafe { unsafe { slice::from_raw_parts(ptr, num_kernel_symbols()) }
let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize;
slice::from_raw_parts(ptr, num)
}
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------

@ -298,57 +298,44 @@ diff -uNr 18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs 19_kernel_heap/
// Private Definitions // Private Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
-type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; GICv2::NUM_IRQS]; -type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; IRQNumber::NUM_TOTAL];
+type HandlerTable = Vec<Option<exception::asynchronous::IRQDescriptor>>; +type HandlerTable = Vec<Option<exception::asynchronous::IRQDescriptor>>;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
@@ -119,8 +120,7 @@ @@ -119,7 +120,7 @@
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
impl GICv2 { impl GICv2 {
- const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space. - const MAX_IRQ_NUMBER: usize = 300; // Normally 1019, but keep it lower to save some space.
- const NUM_IRQS: usize = Self::MAX_IRQ_NUMBER + 1;
+ const MAX_IRQ_NUMBER: usize = 1019; + const MAX_IRQ_NUMBER: usize = 1019;
pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)"; pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)";
@@ -137,7 +137,7 @@ @@ -136,7 +137,7 @@
Self { Self {
gicd: gicd::GICD::new(gicd_mmio_start_addr), gicd: gicd::GICD::new(gicd_mmio_start_addr),
gicc: gicc::GICC::new(gicc_mmio_start_addr), gicc: gicc::GICC::new(gicc_mmio_start_addr),
- handler_table: InitStateLock::new([None; Self::NUM_IRQS]), - handler_table: InitStateLock::new([None; IRQNumber::NUM_TOTAL]),
+ handler_table: InitStateLock::new(Vec::new()), + handler_table: InitStateLock::new(Vec::new()),
post_init_callback, post_init_callback,
} }
} }
@@ -178,6 +178,12 @@ @@ -153,6 +154,9 @@
self.handler_table.write(|table| { }
let irq_number = irq_number.get();
unsafe fn init(&self) -> Result<(), &'static str> {
+ if table.len() < irq_number { + self.handler_table
+ // IRQDescriptor has an integrated range sanity check on construction, so this + .write(|table| table.resize(IRQNumber::NUM_TOTAL, None));
+ // vector can't grow arbitrarily big.
+ table.resize(irq_number + 1, None);
+ }
+ +
if table[irq_number].is_some() { if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() {
return Err("IRQ handler already registered"); self.gicd.boot_core_init();
} }
diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs
--- 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs --- 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs
+++ 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs +++ 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs
@@ -4,7 +4,7 @@ @@ -16,6 +16,7 @@
//! Peripheral Interrupt Controller Driver.
-use super::{InterruptController, PendingIRQs, PeripheralIRQ};
+use super::{PendingIRQs, PeripheralIRQ};
use crate::{
bsp::device_driver::common::MMIODerefWrapper,
exception,
@@ -12,6 +12,7 @@
synchronization, synchronization,
synchronization::{IRQSafeNullLock, InitStateLock}, synchronization::{IRQSafeNullLock, InitStateLock},
}; };
@ -356,50 +343,46 @@ diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_contro
use tock_registers::{ use tock_registers::{
interfaces::{Readable, Writeable}, interfaces::{Readable, Writeable},
register_structs, register_structs,
@@ -48,8 +49,7 @@ @@ -52,7 +53,7 @@
/// Abstraction for the ReadOnly parts of the associated MMIO registers. /// Abstraction for the ReadOnly parts of the associated MMIO registers.
type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>; type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
-type HandlerTable = -type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; PeripheralIRQ::NUM_TOTAL];
- [Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
+type HandlerTable = Vec<Option<exception::asynchronous::IRQDescriptor>>; +type HandlerTable = Vec<Option<exception::asynchronous::IRQDescriptor>>;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Definitions // Public Definitions
@@ -81,7 +81,7 @@ @@ -84,10 +85,16 @@
Self { Self {
wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)), wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::new(mmio_start_addr)),
ro_registers: ReadOnlyRegisters::new(mmio_start_addr), ro_registers: ReadOnlyRegisters::new(mmio_start_addr),
- handler_table: InitStateLock::new([None; InterruptController::NUM_PERIPHERAL_IRQS]), - handler_table: InitStateLock::new([None; PeripheralIRQ::NUM_TOTAL]),
+ handler_table: InitStateLock::new(Vec::new()), + handler_table: InitStateLock::new(Vec::new()),
} }
} }
@@ -110,6 +110,12 @@ + /// Called by the kernel to bring up the device.
self.handler_table.write(|table| { + pub fn init(&self) {
let irq_number = irq.get(); + self.handler_table
+ .write(|table| table.resize(PeripheralIRQ::NUM_TOTAL, None));
+ if table.len() < irq_number { + }
+ // IRQDescriptor has an integrated range sanity check on construction, so this
+ // vector can't grow arbitrarily big.
+ table.resize(irq_number + 1, None);
+ }
+ +
if table[irq_number].is_some() { /// Query the list of pending IRQs.
return Err("IRQ handler already registered"); fn pending_irqs(&self) -> PendingIRQs {
} let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32)
diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs
--- 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs --- 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs
+++ 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs +++ 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller.rs
@@ -77,7 +77,6 @@ @@ -104,6 +104,8 @@
impl InterruptController { }
const MAX_LOCAL_IRQ_NUMBER: usize = 11;
const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63;
- const NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; unsafe fn init(&self) -> Result<(), &'static str> {
+ self.periph.init();
+
(self.post_init_callback)();
Ok(())
diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 19_kernel_heap/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
--- 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs --- 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs

@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN;
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn arch_timer_counter_frequency() -> NonZeroU32 {
// Read volatile is needed here to prevent the compiler from optimizing
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }
}
impl GenericTimerCounterValue { impl GenericTimerCounterValue {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX); pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
} }
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO; return Duration::ZERO;
} }
// Read volatile is needed here to prevent the compiler from optimizing let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
// Div<NonZeroU64> implementation for u64 cannot panic. // Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency); let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big"); return Err("Conversion error. Duration too big");
} }
// This is safe, because all the safety requirements as stated in read_volatile()'s let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let duration: u128 = duration.as_nanos(); let duration: u128 = duration.as_nanos();
// This is safe, because frequency can never be greater than u32::MAX, and // This is safe, because frequency can never be greater than u32::MAX, and

@ -154,6 +154,9 @@ impl driver::interface::DeviceDriver for GICv2 {
} }
unsafe fn init(&self) -> Result<(), &'static str> { unsafe fn init(&self) -> Result<(), &'static str> {
self.handler_table
.write(|table| table.resize(IRQNumber::NUM_TOTAL, None));
if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() { if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() {
self.gicd.boot_core_init(); self.gicd.boot_core_init();
} }
@ -178,12 +181,6 @@ impl exception::asynchronous::interface::IRQManager for GICv2 {
self.handler_table.write(|table| { self.handler_table.write(|table| {
let irq_number = irq_number.get(); let irq_number = irq_number.get();
if table.len() < irq_number {
// IRQDescriptor has an integrated range sanity check on construction, so this
// vector can't grow arbitrarily big.
table.resize(irq_number + 1, None);
}
if table[irq_number].is_some() { if table[irq_number].is_some() {
return Err("IRQ handler already registered"); return Err("IRQ handler already registered");
} }

@ -57,16 +57,13 @@ impl Iterator for PendingIRQs {
type Item = usize; type Item = usize;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
use core::intrinsics::cttz; if self.bitmask == 0 {
let next = cttz(self.bitmask);
if next == 64 {
return None; return None;
} }
self.bitmask &= !(1 << next); let next = self.bitmask.trailing_zeros() as usize;
self.bitmask &= self.bitmask.wrapping_sub(1);
Some(next as usize) Some(next)
} }
} }
@ -75,7 +72,8 @@ impl Iterator for PendingIRQs {
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
impl InterruptController { impl InterruptController {
const MAX_LOCAL_IRQ_NUMBER: usize = 11; // Restrict to 3 for now. This makes future code for local_ic.rs more straight forward.
const MAX_LOCAL_IRQ_NUMBER: usize = 3;
const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63; const MAX_PERIPHERAL_IRQ_NUMBER: usize = 63;
pub const COMPATIBLE: &'static str = "BCM Interrupt Controller"; pub const COMPATIBLE: &'static str = "BCM Interrupt Controller";
@ -106,6 +104,8 @@ impl driver::interface::DeviceDriver for InterruptController {
} }
unsafe fn init(&self) -> Result<(), &'static str> { unsafe fn init(&self) -> Result<(), &'static str> {
self.periph.init();
(self.post_init_callback)(); (self.post_init_callback)();
Ok(()) Ok(())

@ -3,6 +3,10 @@
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com> // Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
//! Peripheral Interrupt Controller Driver. //! Peripheral Interrupt Controller Driver.
//!
//! # Resources
//!
//! - <https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf>
use super::{PendingIRQs, PeripheralIRQ}; use super::{PendingIRQs, PeripheralIRQ};
use crate::{ use crate::{
@ -85,6 +89,12 @@ impl PeripheralIC {
} }
} }
/// Called by the kernel to bring up the device.
pub fn init(&self) {
self.handler_table
.write(|table| table.resize(PeripheralIRQ::NUM_TOTAL, None));
}
/// Query the list of pending IRQs. /// Query the list of pending IRQs.
fn pending_irqs(&self) -> PendingIRQs { fn pending_irqs(&self) -> PendingIRQs {
let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32) let pending_mask: u64 = (u64::from(self.ro_registers.PENDING_2.get()) << 32)
@ -110,12 +120,6 @@ impl exception::asynchronous::interface::IRQManager for PeripheralIC {
self.handler_table.write(|table| { self.handler_table.write(|table| {
let irq_number = irq.get(); let irq_number = irq.get();
if table.len() < irq_number {
// IRQDescriptor has an integrated range sanity check on construction, so this
// vector can't grow arbitrarily big.
table.resize(irq_number + 1, None);
}
if table[irq_number].is_some() { if table[irq_number].is_some() {
return Err("IRQ handler already registered"); return Err("IRQ handler already registered");
} }

@ -126,6 +126,9 @@ impl<'irq_context> IRQContext<'irq_context> {
} }
impl<const MAX_INCLUSIVE: usize> IRQNumber<{ MAX_INCLUSIVE }> { impl<const MAX_INCLUSIVE: usize> IRQNumber<{ MAX_INCLUSIVE }> {
/// The total number of IRQs this type supports.
pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1;
/// Creates a new instance if number <= MAX_INCLUSIVE. /// Creates a new instance if number <= MAX_INCLUSIVE.
pub const fn new(number: usize) -> Self { pub const fn new(number: usize) -> Self {
assert!(number <= MAX_INCLUSIVE); assert!(number <= MAX_INCLUSIVE);

@ -34,13 +34,18 @@ fn kernel_symbol_section_virt_start_addr() -> Address<Virtual> {
Address::new(unsafe { __kernel_symbols_start.get() as usize }) Address::new(unsafe { __kernel_symbols_start.get() as usize })
} }
fn num_kernel_symbols() -> usize {
unsafe {
// Read volatile is needed here to prevent the compiler from optimizing NUM_KERNEL_SYMBOLS
// away.
core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize
}
}
fn kernel_symbols_slice() -> &'static [Symbol] { fn kernel_symbols_slice() -> &'static [Symbol] {
let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol; let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol;
unsafe { unsafe { slice::from_raw_parts(ptr, num_kernel_symbols()) }
let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize;
slice::from_raw_parts(ptr, num)
}
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------

@ -43,6 +43,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN;
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
fn arch_timer_counter_frequency() -> NonZeroU32 {
// Read volatile is needed here to prevent the compiler from optimizing
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }
}
impl GenericTimerCounterValue { impl GenericTimerCounterValue {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX); pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
} }
@ -61,13 +70,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO; return Duration::ZERO;
} }
// Read volatile is needed here to prevent the compiler from optimizing let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// ARCH_TIMER_COUNTER_FREQUENCY away.
//
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
// Div<NonZeroU64> implementation for u64 cannot panic. // Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency); let secs = counter_value.0.div(frequency);
@ -102,10 +105,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big"); return Err("Conversion error. Duration too big");
} }
// This is safe, because all the safety requirements as stated in read_volatile()'s let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let duration: u128 = duration.as_nanos(); let duration: u128 = duration.as_nanos();
// This is safe, because frequency can never be greater than u32::MAX, and // This is safe, because frequency can never be greater than u32::MAX, and

Loading…
Cancel
Save