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
+//--------------------------------------------------------------------------------------------------
+
+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 {
+ 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;
+ }
+
+ // 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.
+ let frequency: NonZeroU64 =
+ unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
+ let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
+
+ // Div<NonZeroU64> implementation for u64 cannot panic.
+ 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");
+ }
+
+ // This is safe, because all the safety requirements as stated in read_volatile()'s
+ // documentation are fulfilled.
+ let frequency: u128 =
+ unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
+ let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
+ let duration: u128 = duration.as_nanos();
+
+ // 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
//--------------------------------------------------------------------------------------------------
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 {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
}
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO;
}
// 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.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big");
}
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
let duration: u128 = duration.as_nanos();
// 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
//--------------------------------------------------------------------------------------------------
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 {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
}
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO;
}
// 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.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big");
}
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
let duration: u128 = duration.as_nanos();
// 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
//--------------------------------------------------------------------------------------------------
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 {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
}
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO;
}
// 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.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big");
}
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
let duration: u128 = duration.as_nanos();
// 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
//--------------------------------------------------------------------------------------------------
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 {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
}
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO;
}
// 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.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big");
}
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
let duration: u128 = duration.as_nanos();
// 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
//--------------------------------------------------------------------------------------------------
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 {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
}
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO;
}
// 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.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big");
}
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
let duration: u128 = duration.as_nanos();
// 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
//--------------------------------------------------------------------------------------------------
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 {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
}
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO;
}
// 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.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big");
}
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
let duration: u128 = duration.as_nanos();
// 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
--- 12_integrated_testing/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
+//
+// 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
+//--------------------------------------------------------------------------------------------------
+
+type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; GICv2::NUM_IRQS];
+type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; IRQNumber::NUM_TOTAL];
+
+//--------------------------------------------------------------------------------------------------
+// Public Definitions
@ -1364,7 +1364,6 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc
+
+impl GICv2 {
+ 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)";
+
@ -1377,7 +1376,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/arm/gicv2.rs 13_exc
+ Self {
+ gicd: gicd::GICD::new(gicd_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
--- 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
@@ -0,0 +1,167 @@
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
+
+//! 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::{
+ bsp::device_driver::common::MMIODerefWrapper,
+ 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.
+type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
+
+type HandlerTable =
+ [Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
+type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; PeripheralIRQ::NUM_TOTAL];
+
+//--------------------------------------------------------------------------------------------------
+// Public Definitions
@ -1602,7 +1604,7 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru
+ Self {
+ wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::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
--- 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
@@ -0,0 +1,134 @@
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0
+//
+// 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;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ use core::intrinsics::cttz;
+
+ let next = cttz(self.bitmask);
+ if next == 64 {
+ if self.bitmask == 0 {
+ return None;
+ }
+
+ self.bitmask &= !(1 << next);
+
+ Some(next as usize)
+ let next = self.bitmask.trailing_zeros() as usize;
+ self.bitmask &= self.bitmask.wrapping_sub(1);
+ Some(next)
+ }
+}
+
@ -1766,9 +1765,9 @@ diff -uNr 12_integrated_testing/kernel/src/bsp/device_driver/bcm/bcm2xxx_interru
+//--------------------------------------------------------------------------------------------------
+
+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 NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1;
+
+ 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
--- 12_integrated_testing/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"]
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 }> {
+ /// The total number of IRQs this type supports.
+ pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1;
+
+ /// Creates a new instance if number <= MAX_INCLUSIVE.
+ pub const fn new(number: usize) -> Self {
+ assert!(number <= MAX_INCLUSIVE);

@ -42,6 +42,15 @@ static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN;
// 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 {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
}
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO;
}
// 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.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big");
}
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
let duration: u128 = duration.as_nanos();
// 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
//--------------------------------------------------------------------------------------------------
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; GICv2::NUM_IRQS];
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; IRQNumber::NUM_TOTAL];
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -112,7 +112,6 @@ pub struct GICv2 {
impl GICv2 {
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)";
@ -125,7 +124,7 @@ impl GICv2 {
Self {
gicd: gicd::GICD::new(gicd_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;
fn next(&mut self) -> Option<Self::Item> {
use core::intrinsics::cttz;
let next = cttz(self.bitmask);
if next == 64 {
if self.bitmask == 0 {
return None;
}
self.bitmask &= !(1 << next);
Some(next as usize)
let next = self.bitmask.trailing_zeros() as usize;
self.bitmask &= self.bitmask.wrapping_sub(1);
Some(next)
}
}
@ -71,9 +68,9 @@ impl Iterator for PendingIRQs {
//--------------------------------------------------------------------------------------------------
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 NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "BCM Interrupt Controller";

@ -3,8 +3,12 @@
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
//! 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::{
bsp::device_driver::common::MMIODerefWrapper,
exception, synchronization,
@ -46,8 +50,7 @@ type WriteOnlyRegisters = MMIODerefWrapper<WORegisterBlock>;
/// Abstraction for the ReadOnly parts of the associated MMIO registers.
type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
type HandlerTable =
[Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; PeripheralIRQ::NUM_TOTAL];
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -79,7 +82,7 @@ impl PeripheralIC {
Self {
wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::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 }> {
/// The total number of IRQs this type supports.
pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1;
/// Creates a new instance if number <= MAX_INCLUSIVE.
pub const fn new(number: usize) -> Self {
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
///
/// - 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 {
gicd: gicd::GICD::new(gicd_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,
}
}
}
@@ -148,6 +161,8 @@
@@ -147,6 +160,8 @@
self.gicc.priority_accept_all();
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
--- 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
@@ -7,7 +7,9 @@
use super::{InterruptController, PendingIRQs, PeripheralIRQ};
@@ -11,7 +11,9 @@
use super::{PendingIRQs, PeripheralIRQ};
use crate::{
bsp::device_driver::common::MMIODerefWrapper,
- exception, synchronization,
@ -1046,7 +1046,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/bsp/device_driver/bcm/b
synchronization::{IRQSafeNullLock, InitStateLock},
};
use tock_registers::{
@@ -75,7 +77,7 @@
@@ -78,7 +80,7 @@
/// # Safety
///
/// - 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
///
/// - 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 {
Self::COMPATIBLE
}
@ -2302,7 +2302,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/kernel/src/exception/asynchronous.
impl<'irq_context> IRQContext<'irq_context> {
/// Creates an IRQContext token.
@@ -148,9 +158,17 @@
@@ -151,9 +161,17 @@
ret
}

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

@ -90,7 +90,7 @@ use crate::{
// Private Definitions
//--------------------------------------------------------------------------------------------------
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; GICv2::NUM_IRQS];
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; IRQNumber::NUM_TOTAL];
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -120,7 +120,6 @@ pub struct GICv2 {
impl GICv2 {
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)";
@ -137,7 +136,7 @@ impl GICv2 {
Self {
gicd: gicd::GICD::new(gicd_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,
}
}

@ -57,16 +57,13 @@ impl Iterator for PendingIRQs {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
use core::intrinsics::cttz;
let next = cttz(self.bitmask);
if next == 64 {
if self.bitmask == 0 {
return None;
}
self.bitmask &= !(1 << next);
Some(next as usize)
let next = self.bitmask.trailing_zeros() as usize;
self.bitmask &= self.bitmask.wrapping_sub(1);
Some(next)
}
}
@ -75,9 +72,9 @@ impl Iterator for PendingIRQs {
//--------------------------------------------------------------------------------------------------
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 NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "BCM Interrupt Controller";

@ -3,8 +3,12 @@
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
//! 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::{
bsp::device_driver::common::MMIODerefWrapper,
exception,
@ -48,8 +52,7 @@ type WriteOnlyRegisters = MMIODerefWrapper<WORegisterBlock>;
/// Abstraction for the ReadOnly parts of the associated MMIO registers.
type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
type HandlerTable =
[Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; PeripheralIRQ::NUM_TOTAL];
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -81,7 +84,7 @@ impl PeripheralIC {
Self {
wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::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 }> {
/// The total number of IRQs this type supports.
pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1;
/// Creates a new instance if number <= MAX_INCLUSIVE.
pub const fn new(number: usize) -> Self {
assert!(number <= MAX_INCLUSIVE);

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

@ -90,7 +90,7 @@ use crate::{
// Private Definitions
//--------------------------------------------------------------------------------------------------
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; GICv2::NUM_IRQS];
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; IRQNumber::NUM_TOTAL];
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -120,7 +120,6 @@ pub struct GICv2 {
impl GICv2 {
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)";
@ -137,7 +136,7 @@ impl GICv2 {
Self {
gicd: gicd::GICD::new(gicd_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,
}
}

@ -57,16 +57,13 @@ impl Iterator for PendingIRQs {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
use core::intrinsics::cttz;
let next = cttz(self.bitmask);
if next == 64 {
if self.bitmask == 0 {
return None;
}
self.bitmask &= !(1 << next);
Some(next as usize)
let next = self.bitmask.trailing_zeros() as usize;
self.bitmask &= self.bitmask.wrapping_sub(1);
Some(next)
}
}
@ -75,9 +72,9 @@ impl Iterator for PendingIRQs {
//--------------------------------------------------------------------------------------------------
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 NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "BCM Interrupt Controller";

@ -3,8 +3,12 @@
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
//! 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::{
bsp::device_driver::common::MMIODerefWrapper,
exception,
@ -48,8 +52,7 @@ type WriteOnlyRegisters = MMIODerefWrapper<WORegisterBlock>;
/// Abstraction for the ReadOnly parts of the associated MMIO registers.
type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
type HandlerTable =
[Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; PeripheralIRQ::NUM_TOTAL];
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -81,7 +84,7 @@ impl PeripheralIC {
Self {
wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::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 }> {
/// The total number of IRQs this type supports.
pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1;
/// Creates a new instance if number <= MAX_INCLUSIVE.
pub const fn new(number: usize) -> Self {
assert!(number <= MAX_INCLUSIVE);

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

@ -90,7 +90,7 @@ use crate::{
// Private Definitions
//--------------------------------------------------------------------------------------------------
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; GICv2::NUM_IRQS];
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; IRQNumber::NUM_TOTAL];
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -120,7 +120,6 @@ pub struct GICv2 {
impl GICv2 {
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)";
@ -137,7 +136,7 @@ impl GICv2 {
Self {
gicd: gicd::GICD::new(gicd_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,
}
}

@ -57,16 +57,13 @@ impl Iterator for PendingIRQs {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
use core::intrinsics::cttz;
let next = cttz(self.bitmask);
if next == 64 {
if self.bitmask == 0 {
return None;
}
self.bitmask &= !(1 << next);
Some(next as usize)
let next = self.bitmask.trailing_zeros() as usize;
self.bitmask &= self.bitmask.wrapping_sub(1);
Some(next)
}
}
@ -75,9 +72,9 @@ impl Iterator for PendingIRQs {
//--------------------------------------------------------------------------------------------------
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 NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "BCM Interrupt Controller";

@ -3,8 +3,12 @@
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
//! 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::{
bsp::device_driver::common::MMIODerefWrapper,
exception,
@ -48,8 +52,7 @@ type WriteOnlyRegisters = MMIODerefWrapper<WORegisterBlock>;
/// Abstraction for the ReadOnly parts of the associated MMIO registers.
type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
type HandlerTable =
[Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; PeripheralIRQ::NUM_TOTAL];
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -81,7 +84,7 @@ impl PeripheralIC {
Self {
wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::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 }> {
/// The total number of IRQs this type supports.
pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1;
/// Creates a new instance if number <= MAX_INCLUSIVE.
pub const fn new(number: usize) -> Self {
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 })
}
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] {
let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol;
unsafe {
let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize;
slice::from_raw_parts(ptr, num)
}
unsafe { slice::from_raw_parts(ptr, num_kernel_symbols()) }
}
```
@ -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
--- 16_virtual_mem_part4_higher_half_kernel/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
+//
+// 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 })
+}
+
+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] {
+ let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol;
+
+ unsafe {
+ let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize;
+ slice::from_raw_parts(ptr, num)
+ }
+ unsafe { slice::from_raw_parts(ptr, num_kernel_symbols()) }
+}
+
+//--------------------------------------------------------------------------------------------------

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

@ -90,7 +90,7 @@ use crate::{
// Private Definitions
//--------------------------------------------------------------------------------------------------
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; GICv2::NUM_IRQS];
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; IRQNumber::NUM_TOTAL];
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -120,7 +120,6 @@ pub struct GICv2 {
impl GICv2 {
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)";
@ -137,7 +136,7 @@ impl GICv2 {
Self {
gicd: gicd::GICD::new(gicd_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,
}
}

@ -57,16 +57,13 @@ impl Iterator for PendingIRQs {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
use core::intrinsics::cttz;
let next = cttz(self.bitmask);
if next == 64 {
if self.bitmask == 0 {
return None;
}
self.bitmask &= !(1 << next);
Some(next as usize)
let next = self.bitmask.trailing_zeros() as usize;
self.bitmask &= self.bitmask.wrapping_sub(1);
Some(next)
}
}
@ -75,9 +72,9 @@ impl Iterator for PendingIRQs {
//--------------------------------------------------------------------------------------------------
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 NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "BCM Interrupt Controller";

@ -3,8 +3,12 @@
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
//! 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::{
bsp::device_driver::common::MMIODerefWrapper,
exception,
@ -48,8 +52,7 @@ type WriteOnlyRegisters = MMIODerefWrapper<WORegisterBlock>;
/// Abstraction for the ReadOnly parts of the associated MMIO registers.
type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
type HandlerTable =
[Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; PeripheralIRQ::NUM_TOTAL];
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -81,7 +84,7 @@ impl PeripheralIC {
Self {
wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::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 }> {
/// The total number of IRQs this type supports.
pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1;
/// Creates a new instance if number <= MAX_INCLUSIVE.
pub const fn new(number: usize) -> Self {
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 })
}
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] {
let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol;
unsafe {
let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize;
slice::from_raw_parts(ptr, num)
}
unsafe { slice::from_raw_parts(ptr, num_kernel_symbols()) }
}
//--------------------------------------------------------------------------------------------------

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

@ -90,7 +90,7 @@ use crate::{
// Private Definitions
//--------------------------------------------------------------------------------------------------
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; GICv2::NUM_IRQS];
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; IRQNumber::NUM_TOTAL];
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -120,7 +120,6 @@ pub struct GICv2 {
impl GICv2 {
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)";
@ -137,7 +136,7 @@ impl GICv2 {
Self {
gicd: gicd::GICD::new(gicd_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,
}
}

@ -57,16 +57,13 @@ impl Iterator for PendingIRQs {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
use core::intrinsics::cttz;
let next = cttz(self.bitmask);
if next == 64 {
if self.bitmask == 0 {
return None;
}
self.bitmask &= !(1 << next);
Some(next as usize)
let next = self.bitmask.trailing_zeros() as usize;
self.bitmask &= self.bitmask.wrapping_sub(1);
Some(next)
}
}
@ -75,9 +72,9 @@ impl Iterator for PendingIRQs {
//--------------------------------------------------------------------------------------------------
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 NUM_PERIPHERAL_IRQS: usize = Self::MAX_PERIPHERAL_IRQ_NUMBER + 1;
pub const COMPATIBLE: &'static str = "BCM Interrupt Controller";

@ -3,8 +3,12 @@
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
//! 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::{
bsp::device_driver::common::MMIODerefWrapper,
exception,
@ -48,8 +52,7 @@ type WriteOnlyRegisters = MMIODerefWrapper<WORegisterBlock>;
/// Abstraction for the ReadOnly parts of the associated MMIO registers.
type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
type HandlerTable =
[Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; PeripheralIRQ::NUM_TOTAL];
//--------------------------------------------------------------------------------------------------
// Public Definitions
@ -81,7 +84,7 @@ impl PeripheralIC {
Self {
wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::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 }> {
/// The total number of IRQs this type supports.
pub const NUM_TOTAL: usize = MAX_INCLUSIVE + 1;
/// Creates a new instance if number <= MAX_INCLUSIVE.
pub const fn new(number: usize) -> Self {
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 })
}
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] {
let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol;
unsafe {
let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize;
slice::from_raw_parts(ptr, num)
}
unsafe { slice::from_raw_parts(ptr, num_kernel_symbols()) }
}
//--------------------------------------------------------------------------------------------------

@ -298,57 +298,44 @@ diff -uNr 18_backtrace/kernel/src/bsp/device_driver/arm/gicv2.rs 19_kernel_heap/
// 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>>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
@@ -119,8 +120,7 @@
@@ -119,7 +120,7 @@
//--------------------------------------------------------------------------------------------------
impl GICv2 {
- 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;
pub const COMPATIBLE: &'static str = "GICv2 (ARM Generic Interrupt Controller v2)";
@@ -137,7 +137,7 @@
@@ -136,7 +137,7 @@
Self {
gicd: gicd::GICD::new(gicd_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()),
post_init_callback,
}
}
@@ -178,6 +178,12 @@
self.handler_table.write(|table| {
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);
+ }
@@ -153,6 +154,9 @@
}
unsafe fn init(&self) -> Result<(), &'static str> {
+ self.handler_table
+ .write(|table| table.resize(IRQNumber::NUM_TOTAL, None));
+
if table[irq_number].is_some() {
return Err("IRQ handler already registered");
}
if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() {
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
--- 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
@@ -4,7 +4,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 @@
@@ -16,6 +16,7 @@
synchronization,
synchronization::{IRQSafeNullLock, InitStateLock},
};
@ -356,50 +343,46 @@ diff -uNr 18_backtrace/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_contro
use tock_registers::{
interfaces::{Readable, Writeable},
register_structs,
@@ -48,8 +49,7 @@
@@ -52,7 +53,7 @@
/// Abstraction for the ReadOnly parts of the associated MMIO registers.
type ReadOnlyRegisters = MMIODerefWrapper<RORegisterBlock>;
-type HandlerTable =
- [Option<exception::asynchronous::IRQDescriptor>; InterruptController::NUM_PERIPHERAL_IRQS];
-type HandlerTable = [Option<exception::asynchronous::IRQDescriptor>; PeripheralIRQ::NUM_TOTAL];
+type HandlerTable = Vec<Option<exception::asynchronous::IRQDescriptor>>;
//--------------------------------------------------------------------------------------------------
// Public Definitions
@@ -81,7 +81,7 @@
@@ -84,10 +85,16 @@
Self {
wo_registers: IRQSafeNullLock::new(WriteOnlyRegisters::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()),
}
}
@@ -110,6 +110,12 @@
self.handler_table.write(|table| {
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);
+ }
+ /// Called by the kernel to bring up the device.
+ pub fn init(&self) {
+ self.handler_table
+ .write(|table| table.resize(PeripheralIRQ::NUM_TOTAL, None));
+ }
+
if table[irq_number].is_some() {
return Err("IRQ handler already registered");
}
/// Query the list of pending IRQs.
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
--- 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
@@ -77,7 +77,6 @@
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;
@@ -104,6 +104,8 @@
}
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
--- 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
//--------------------------------------------------------------------------------------------------
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 {
pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
}
@ -60,13 +69,7 @@ impl From<GenericTimerCounterValue> for Duration {
return Duration::ZERO;
}
// 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.
let frequency: NonZeroU64 =
unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
let frequency: NonZeroU64 = arch_timer_counter_frequency().into();
// Div<NonZeroU64> implementation for u64 cannot panic.
let secs = counter_value.0.div(frequency);
@ -101,10 +104,7 @@ impl TryFrom<Duration> for GenericTimerCounterValue {
return Err("Conversion error. Duration too big");
}
// This is safe, because all the safety requirements as stated in read_volatile()'s
// documentation are fulfilled.
let frequency: u128 =
unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
let frequency: u128 = u32::from(arch_timer_counter_frequency()) as u128;
let duration: u128 = duration.as_nanos();
// 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> {
self.handler_table
.write(|table| table.resize(IRQNumber::NUM_TOTAL, None));
if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() {
self.gicd.boot_core_init();
}
@ -178,12 +181,6 @@ impl exception::asynchronous::interface::IRQManager for GICv2 {
self.handler_table.write(|table| {
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() {
return Err("IRQ handler already registered");
}

@ -57,16 +57,13 @@ impl Iterator for PendingIRQs {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
use core::intrinsics::cttz;
let next = cttz(self.bitmask);
if next == 64 {
if self.bitmask == 0 {
return None;
}
self.bitmask &= !(1 << next);
Some(next as usize)
let next = self.bitmask.trailing_zeros() as usize;
self.bitmask &= self.bitmask.wrapping_sub(1);
Some(next)
}
}
@ -75,7 +72,8 @@ impl Iterator for PendingIRQs {
//--------------------------------------------------------------------------------------------------
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;
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> {
self.periph.init();
(self.post_init_callback)();
Ok(())

@ -3,6 +3,10 @@
// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
//! Peripheral Interrupt Controller Driver.
//!
//! # Resources
//!
//! - <https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf>
use super::{PendingIRQs, PeripheralIRQ};
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.
fn pending_irqs(&self) -> PendingIRQs {
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| {
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() {
return Err("IRQ handler already registered");
}

@ -126,6 +126,9 @@ impl<'irq_context> IRQContext<'irq_context> {
}
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.
pub const fn new(number: usize) -> Self {
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 })
}
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] {
let ptr = kernel_symbol_section_virt_start_addr().as_usize() as *const Symbol;
unsafe {
let num = core::ptr::read_volatile(&NUM_KERNEL_SYMBOLS as *const u64) as usize;
slice::from_raw_parts(ptr, num)
}
unsafe { slice::from_raw_parts(ptr, num_kernel_symbols()) }
}
//--------------------------------------------------------------------------------------------------

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

Loading…
Cancel
Save