diff --git a/.lock b/.lock new file mode 100644 index 0000000..e69de29 diff --git a/arm_gicv2/all.html b/arm_gicv2/all.html new file mode 100644 index 0000000..8d78890 --- /dev/null +++ b/arm_gicv2/all.html @@ -0,0 +1 @@ +
pub const GIC_MAX_IRQ: usize = 1024;
Maximum number of interrupts supported by the GIC.
+pub enum InterruptType {
+ SGI,
+ PPI,
+ SPI,
+}
Different types of interrupt that the GIC handles.
+Software-generated interrupt.
+SGIs are typically used for inter-processor communication and are +generated by a write to an SGI register in the GIC.
+Private Peripheral Interrupt.
+Peripheral interrupts that are private to one core.
+Shared Peripheral Interrupt.
+Peripheral interrupts that can delivered to any connected core.
+pub enum TriggerMode {
+ Edge = 0,
+ Level = 1,
+}
Interrupt trigger mode.
+Edge-triggered.
+This is an interrupt that is asserted on detection of a rising edge of +an interrupt signal and then, regardless of the state of the signal, +remains asserted until it is cleared by the conditions defined by this +specification.
+Level-sensitive.
+This is an interrupt that is asserted whenever the interrupt signal +level is active, and deasserted whenever the level is not active.
+pub const fn translate_irq(id: usize, int_type: InterruptType) -> Option<usize>
Translate an interrupt of a given type to a GIC INTID.
+Redirecting to ../../arm_gicv2/struct.GicCpuInterface.html...
+ + + \ No newline at end of file diff --git a/arm_gicv2/gic_v2/struct.GicDistributor.html b/arm_gicv2/gic_v2/struct.GicDistributor.html new file mode 100644 index 0000000..12d76d4 --- /dev/null +++ b/arm_gicv2/gic_v2/struct.GicDistributor.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../arm_gicv2/struct.GicDistributor.html...
+ + + \ No newline at end of file diff --git a/arm_gicv2/index.html b/arm_gicv2/index.html new file mode 100644 index 0000000..a7ed2d5 --- /dev/null +++ b/arm_gicv2/index.html @@ -0,0 +1,7 @@ +ARM Generic Interrupt Controller version 2 (GICv2) register definitions and basic operations.
+The official documentation: https://developer.arm.com/documentation/ihi0048/latest/
+pub struct GicCpuInterface { /* private fields */ }
The GIC CPU interface.
+Each CPU interface block performs priority masking and preemption +handling for a connected processor in the system.
+Each CPU interface provides a programming interface for:
+Construct a new GIC CPU interface instance from the base address.
+Returns the interrupt ID of the highest priority pending interrupt for +the CPU interface. (read GICC_IAR)
+The read returns a spurious interrupt ID of 1023
if the distributor
+or the CPU interface are disabled, or there is no pending interrupt on
+the CPU interface.
Informs the CPU interface that it has completed the processing of the +specified interrupt. (write GICC_EOIR)
+The value written must be the value returns from Self::iar
.
handles the signaled interrupt.
+It first reads GICC_IAR to obtain the pending interrupt ID and then +calls the given handler. After the handler returns, it writes GICC_EOIR +to acknowledge the interrupt.
+If read GICC_IAR returns a spurious interrupt ID of 1023
, it does
+nothing.
pub struct GicDistributor { /* private fields */ }
The GIC distributor.
+The Distributor block performs interrupt prioritization and distribution +to the CPU interface blocks that connect to the processors in the system.
+The Distributor provides a programming interface for:
+In addition, the Distributor provides:
+Construct a new GIC distributor instance from the base address.
+Configures the trigger mode for the given interrupt.
+Enables or disables the given interrupt.
+U::from(self)
.\nCalls U::from(self)
.\nCalls U::from(self)
.\nCalls U::from(self)
.\nThe maximum number of interrupts that the GIC supports\nConstruct a new GIC distributor instance from the base …\nConstruct a new GIC CPU interface instance from the base …\nEnables or disables the given interrupt.\nTranslate an interrupt of a given type to a GIC INTID.")
\ No newline at end of file
diff --git a/settings.html b/settings.html
new file mode 100644
index 0000000..70bd407
--- /dev/null
+++ b/settings.html
@@ -0,0 +1 @@
+1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +
//! Types and definitions for GICv2.
+//!
+//! The official documentation: <https://developer.arm.com/documentation/ihi0048/latest/>
+
+use core::ptr::NonNull;
+
+use crate::{TriggerMode, GIC_MAX_IRQ, SPI_RANGE};
+use tock_registers::interfaces::{Readable, Writeable};
+use tock_registers::register_structs;
+use tock_registers::registers::{ReadOnly, ReadWrite, WriteOnly};
+
+register_structs! {
+ /// GIC Distributor registers.
+ #[allow(non_snake_case)]
+ GicDistributorRegs {
+ /// Distributor Control Register.
+ (0x0000 => CTLR: ReadWrite<u32>),
+ /// Interrupt Controller Type Register.
+ (0x0004 => TYPER: ReadOnly<u32>),
+ /// Distributor Implementer Identification Register.
+ (0x0008 => IIDR: ReadOnly<u32>),
+ (0x000c => _reserved_0),
+ /// Interrupt Group Registers.
+ (0x0080 => IGROUPR: [ReadWrite<u32>; 0x20]),
+ /// Interrupt Set-Enable Registers.
+ (0x0100 => ISENABLER: [ReadWrite<u32>; 0x20]),
+ /// Interrupt Clear-Enable Registers.
+ (0x0180 => ICENABLER: [ReadWrite<u32>; 0x20]),
+ /// Interrupt Set-Pending Registers.
+ (0x0200 => ISPENDR: [ReadWrite<u32>; 0x20]),
+ /// Interrupt Clear-Pending Registers.
+ (0x0280 => ICPENDR: [ReadWrite<u32>; 0x20]),
+ /// Interrupt Set-Active Registers.
+ (0x0300 => ISACTIVER: [ReadWrite<u32>; 0x20]),
+ /// Interrupt Clear-Active Registers.
+ (0x0380 => ICACTIVER: [ReadWrite<u32>; 0x20]),
+ /// Interrupt Priority Registers.
+ (0x0400 => IPRIORITYR: [ReadWrite<u32>; 0x100]),
+ /// Interrupt Processor Targets Registers.
+ (0x0800 => ITARGETSR: [ReadWrite<u32>; 0x100]),
+ /// Interrupt Configuration Registers.
+ (0x0c00 => ICFGR: [ReadWrite<u32>; 0x40]),
+ (0x0d00 => _reserved_1),
+ /// Software Generated Interrupt Register.
+ (0x0f00 => SGIR: WriteOnly<u32>),
+ (0x0f04 => @END),
+ }
+}
+
+register_structs! {
+ /// GIC CPU Interface registers.
+ #[allow(non_snake_case)]
+ GicCpuInterfaceRegs {
+ /// CPU Interface Control Register.
+ (0x0000 => CTLR: ReadWrite<u32>),
+ /// Interrupt Priority Mask Register.
+ (0x0004 => PMR: ReadWrite<u32>),
+ /// Binary Point Register.
+ (0x0008 => BPR: ReadWrite<u32>),
+ /// Interrupt Acknowledge Register.
+ (0x000c => IAR: ReadOnly<u32>),
+ /// End of Interrupt Register.
+ (0x0010 => EOIR: WriteOnly<u32>),
+ /// Running Priority Register.
+ (0x0014 => RPR: ReadOnly<u32>),
+ /// Highest Priority Pending Interrupt Register.
+ (0x0018 => HPPIR: ReadOnly<u32>),
+ (0x001c => _reserved_1),
+ /// CPU Interface Identification Register.
+ (0x00fc => IIDR: ReadOnly<u32>),
+ (0x0100 => _reserved_2),
+ /// Deactivate Interrupt Register.
+ (0x1000 => DIR: WriteOnly<u32>),
+ (0x1004 => @END),
+ }
+}
+
+/// The GIC distributor.
+///
+/// The Distributor block performs interrupt prioritization and distribution
+/// to the CPU interface blocks that connect to the processors in the system.
+///
+/// The Distributor provides a programming interface for:
+/// - Globally enabling the forwarding of interrupts to the CPU interfaces.
+/// - Enabling or disabling each interrupt.
+/// - Setting the priority level of each interrupt.
+/// - Setting the target processor list of each interrupt.
+/// - Setting each peripheral interrupt to be level-sensitive or edge-triggered.
+/// - Setting each interrupt as either Group 0 or Group 1.
+/// - Forwarding an SGI to one or more target processors.
+///
+/// In addition, the Distributor provides:
+/// - visibility of the state of each interrupt
+/// - a mechanism for software to set or clear the pending state of a peripheral
+/// interrupt.
+pub struct GicDistributor {
+ base: NonNull<GicDistributorRegs>,
+ max_irqs: usize,
+}
+
+/// The GIC CPU interface.
+///
+/// Each CPU interface block performs priority masking and preemption
+/// handling for a connected processor in the system.
+///
+/// Each CPU interface provides a programming interface for:
+///
+/// - enabling the signaling of interrupt requests to the processor
+/// - acknowledging an interrupt
+/// - indicating completion of the processing of an interrupt
+/// - setting an interrupt priority mask for the processor
+/// - defining the preemption policy for the processor
+/// - determining the highest priority pending interrupt for the processor.
+pub struct GicCpuInterface {
+ base: NonNull<GicCpuInterfaceRegs>,
+}
+
+unsafe impl Send for GicDistributor {}
+unsafe impl Sync for GicDistributor {}
+
+unsafe impl Send for GicCpuInterface {}
+unsafe impl Sync for GicCpuInterface {}
+
+impl GicDistributor {
+ /// Construct a new GIC distributor instance from the base address.
+ pub const fn new(base: *mut u8) -> Self {
+ Self {
+ base: NonNull::new(base).unwrap().cast(),
+ max_irqs: GIC_MAX_IRQ,
+ }
+ }
+
+ const fn regs(&self) -> &GicDistributorRegs {
+ unsafe { self.base.as_ref() }
+ }
+
+ /// The number of implemented CPU interfaces.
+ pub fn cpu_num(&self) -> usize {
+ ((self.regs().TYPER.get() as usize >> 5) & 0b111) + 1
+ }
+
+ /// The maximum number of interrupts that the GIC supports
+ pub fn max_irqs(&self) -> usize {
+ ((self.regs().TYPER.get() as usize & 0b11111) + 1) * 32
+ }
+
+ /// Configures the trigger mode for the given interrupt.
+ pub fn configure_interrupt(&mut self, vector: usize, tm: TriggerMode) {
+ // Only configurable for SPI interrupts
+ if vector >= self.max_irqs || vector < SPI_RANGE.start {
+ return;
+ }
+
+ // type is encoded with two bits, MSB of the two determine type
+ // 16 irqs encoded per ICFGR register
+ let reg_idx = vector >> 4;
+ let bit_shift = ((vector & 0xf) << 1) + 1;
+ let mut reg_val = self.regs().ICFGR[reg_idx].get();
+ match tm {
+ TriggerMode::Edge => reg_val |= 1 << bit_shift,
+ TriggerMode::Level => reg_val &= !(1 << bit_shift),
+ }
+ self.regs().ICFGR[reg_idx].set(reg_val);
+ }
+
+ /// Enables or disables the given interrupt.
+ pub fn set_enable(&mut self, vector: usize, enable: bool) {
+ if vector >= self.max_irqs {
+ return;
+ }
+ let reg = vector / 32;
+ let mask = 1 << (vector % 32);
+ if enable {
+ self.regs().ISENABLER[reg].set(mask);
+ } else {
+ self.regs().ICENABLER[reg].set(mask);
+ }
+ }
+
+ /// Initializes the GIC distributor.
+ ///
+ /// It disables all interrupts, sets the target of all SPIs to CPU 0,
+ /// configures all SPIs to be edge-triggered, and finally enables the GICD.
+ ///
+ /// This function should be called only once.
+ pub fn init(&mut self) {
+ let max_irqs = self.max_irqs();
+ assert!(max_irqs <= GIC_MAX_IRQ);
+ self.max_irqs = max_irqs;
+
+ // Disable all interrupts
+ for i in (0..max_irqs).step_by(32) {
+ self.regs().ICENABLER[i / 32].set(u32::MAX);
+ self.regs().ICPENDR[i / 32].set(u32::MAX);
+ }
+ if self.cpu_num() > 1 {
+ for i in (SPI_RANGE.start..max_irqs).step_by(4) {
+ // Set external interrupts to target cpu 0
+ self.regs().ITARGETSR[i / 4].set(0x01_01_01_01);
+ }
+ }
+ // Initialize all the SPIs to edge triggered
+ for i in SPI_RANGE.start..max_irqs {
+ self.configure_interrupt(i, TriggerMode::Edge);
+ }
+
+ // enable GIC0
+ self.regs().CTLR.set(1);
+ }
+}
+
+impl GicCpuInterface {
+ /// Construct a new GIC CPU interface instance from the base address.
+ pub const fn new(base: *mut u8) -> Self {
+ Self {
+ base: NonNull::new(base).unwrap().cast(),
+ }
+ }
+
+ const fn regs(&self) -> &GicCpuInterfaceRegs {
+ unsafe { self.base.as_ref() }
+ }
+
+ /// Returns the interrupt ID of the highest priority pending interrupt for
+ /// the CPU interface. (read GICC_IAR)
+ ///
+ /// The read returns a spurious interrupt ID of `1023` if the distributor
+ /// or the CPU interface are disabled, or there is no pending interrupt on
+ /// the CPU interface.
+ pub fn iar(&self) -> u32 {
+ self.regs().IAR.get()
+ }
+
+ /// Informs the CPU interface that it has completed the processing of the
+ /// specified interrupt. (write GICC_EOIR)
+ ///
+ /// The value written must be the value returns from [`Self::iar`].
+ pub fn eoi(&self, iar: u32) {
+ self.regs().EOIR.set(iar);
+ }
+
+ /// handles the signaled interrupt.
+ ///
+ /// It first reads GICC_IAR to obtain the pending interrupt ID and then
+ /// calls the given handler. After the handler returns, it writes GICC_EOIR
+ /// to acknowledge the interrupt.
+ ///
+ /// If read GICC_IAR returns a spurious interrupt ID of `1023`, it does
+ /// nothing.
+ pub fn handle_irq<F>(&self, handler: F)
+ where
+ F: FnOnce(u32),
+ {
+ let iar = self.iar();
+ let vector = iar & 0x3ff;
+ if vector < 1020 {
+ handler(vector);
+ self.eoi(iar);
+ } else {
+ // spurious
+ }
+ }
+
+ /// Initializes the GIC CPU interface.
+ ///
+ /// It unmask interrupts at all priority levels and enables the GICC.
+ ///
+ /// This function should be called only once.
+ pub fn init(&self) {
+ // enable GIC0
+ self.regs().CTLR.set(1);
+ // unmask interrupts at all priority levels
+ self.regs().PMR.set(0xff);
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +
#![no_std]
+#![feature(const_option)]
+#![feature(const_nonnull_new)]
+#![doc = include_str!("../README.md")]
+
+use core::ops::Range;
+
+mod gic_v2;
+
+pub use gic_v2::{GicCpuInterface, GicDistributor};
+
+/// Interrupt ID 0-15 are used for SGIs (Software-generated interrupt).
+///
+/// SGI is an interrupt generated by software writing to a GICD_SGIR register in
+/// the GIC. The system uses SGIs for interprocessor communication.
+pub const SGI_RANGE: Range<usize> = 0..16;
+
+/// Interrupt ID 16-31 are used for PPIs (Private Peripheral Interrupt).
+///
+/// PPI is a peripheral interrupt that is specific to a single processor.
+pub const PPI_RANGE: Range<usize> = 16..32;
+
+/// Interrupt ID 32-1019 are used for SPIs (Shared Peripheral Interrupt).
+///
+/// SPI is a peripheral interrupt that the Distributor can route to any of a
+/// specified combination of processors.
+pub const SPI_RANGE: Range<usize> = 32..1020;
+
+/// Maximum number of interrupts supported by the GIC.
+pub const GIC_MAX_IRQ: usize = 1024;
+
+/// Interrupt trigger mode.
+pub enum TriggerMode {
+ /// Edge-triggered.
+ ///
+ /// This is an interrupt that is asserted on detection of a rising edge of
+ /// an interrupt signal and then, regardless of the state of the signal,
+ /// remains asserted until it is cleared by the conditions defined by this
+ /// specification.
+ Edge = 0,
+ /// Level-sensitive.
+ ///
+ /// This is an interrupt that is asserted whenever the interrupt signal
+ /// level is active, and deasserted whenever the level is not active.
+ Level = 1,
+}
+
+/// Different types of interrupt that the GIC handles.
+pub enum InterruptType {
+ /// Software-generated interrupt.
+ ///
+ /// SGIs are typically used for inter-processor communication and are
+ /// generated by a write to an SGI register in the GIC.
+ SGI,
+ /// Private Peripheral Interrupt.
+ ///
+ /// Peripheral interrupts that are private to one core.
+ PPI,
+ /// Shared Peripheral Interrupt.
+ ///
+ /// Peripheral interrupts that can delivered to any connected core.
+ SPI,
+}
+
+/// Translate an interrupt of a given type to a GIC INTID.
+pub const fn translate_irq(id: usize, int_type: InterruptType) -> Option<usize> {
+ match int_type {
+ InterruptType::SGI => {
+ if id < SGI_RANGE.end {
+ Some(id)
+ } else {
+ None
+ }
+ }
+ InterruptType::PPI => {
+ if id < PPI_RANGE.end - PPI_RANGE.start {
+ Some(id + PPI_RANGE.start)
+ } else {
+ None
+ }
+ }
+ InterruptType::SPI => {
+ if id < SPI_RANGE.end - SPI_RANGE.start {
+ Some(id + SPI_RANGE.start)
+ } else {
+ None
+ }
+ }
+ }
+}
+
fn:
) to \
+ restrict the search to a given item kind.","Accepted kinds are: fn
, mod
, struct
, \
+ enum
, trait
, type
, macro
, \
+ and const
.","Search functions by type signature (e.g., vec -> usize
or \
+ -> vec
or String, enum:Cow -> bool
)","You can look for items with an exact name by putting double quotes around \
+ your request: \"string\"
","Look for functions that accept or return \
+ slices and \
+ arrays by writing \
+ square brackets (e.g., -> [u8]
or [] -> Option
)","Look for items inside another one by searching for a path: vec::Vec
",].map(x=>""+x+"
").join("");const div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="${value.replaceAll(" ", " ")}
`}else{error[index]=value}});output+=`