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
/* Copyright (c) [2023] [Syswonder Community]
 *   [Rukos] is licensed under Mulan PSL v2.
 *   You can use this software according to the terms and conditions of the Mulan PSL v2.
 *   You may obtain a copy of Mulan PSL v2 at:
 *               http://license.coscl.org.cn/MulanPSL2
 *   THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *   See the Mulan PSL v2 for more details.
 */

//! ARM Generic Interrupt Controller (GIC) register definitions and basic
//! operations.

#![no_std]
#![feature(const_ptr_as_ref)]
#![feature(const_option)]
#![feature(const_nonnull_new)]

pub mod gic_v2;

use core::ops::Range;

/// 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
            }
        }
    }
}