PLIC: Difference between revisions
(Initial writeup -- incomplete but need to restart) |
No edit summary |
||
Line 42: | Line 42: | ||
... | ... | ||
base + 0x3FFFFFC: Reserved | base + 0x3FFFFFC: Reserved | ||
Or, more usefully: | Or, more usefully: | ||
<syntaxhighlight lang="rust" line> | |||
#[repr(C)] | |||
struct Plic { | |||
source_priorities: [u32; 1024], | |||
interrupt_pending: [u32; 32], | |||
_padding1: [u8; 3968], | |||
interrupt_enable: [[u32; 32]; 15872], | |||
_padding2: [u8; 57344], | |||
threshold_and_claim: [[u32; 1024]; 15872], | |||
} | |||
</syntaxhighlight> | |||
Each <pre>u32</pre> inside of the <pre>source_priorities</pre> is a priority level from <pre>0..=7</pre> (on most platforms, see your platform specification for more complete information) of increasing priority level where priority <pre>0</pre> is considered "never interrupt" and will cause the interrupt to effectively be disabled, with the exception of interrupt #0, which does not exist and is reserved. <pre>interrupt_pending</pre> is a read-only bitmap of the pending status for priorities <pre>1..=1024</pre> (with the interrupt #0 bit hardwired to zero). Both <pre>interrupt_enable</pre> and <pre>threshold_and_claim</pre> work on the aforementioned contexts, and need to be indexed at a platform-specific index for a given hart and privilege mode combination. The <pre>interrupt_enable</pre> consists of another bitmap of interrupt sources (again with interrupt #0 for each context being hardwired to zero) which allow enabling and disabling specific interrupt sources at the context level, but also means that if you wish for a given interrupt to trigger across any hart, it will need to be enabled for each context for the privilege mode you are executing in. <pre>threshold_and_claim</pre> is made up of a threshold <pre>u32</pre> value and a claim <pre>u32</pre> value, with the rest of the <pre>u32</pre>s being reserved and should not be written to. |
Revision as of 02:44, 2 February 2023
The Platform Interrupt Controller (PLIC) is the standardized device for receiving, routing, and completing external interrupts with configuration per-hart and per-privilege mode. Originally, the PLIC design is based on early SiFive designs which were then slightly refined and standardized and only supports basic interrupt enabling/disabling, prioritization and routing. As part of the RISC-V Advanced Interrupt Architecture (AIA), the original PLIC design is extended to support more types of interrupts, namely Message Signaled Interrupts (MSIs), which are important for technologies like PCI. The PLIC specification can be found at https://github.com/riscv/riscv-plic-spec while the APLIC specification is available at https://github.com/riscv/riscv-aia.
Original PLIC Design
The original PLIC design consist of a set of: interrupt source priorities, interrupt pending bits, per-context interrupt enable bits, and then per-context priority threshold & claim/complete regions. A context is the combination of a hart ID and a privilege mode, though the specific ordering of contexts is platform-specific and cannot be generalized between them. A small table below has been added for quick reference, but likely will not contain a formula for calculating the context for every platform. The memory layout for the PLIC is as follows (taken from the PLIC spec):
base + 0x000000: Reserved (interrupt source 0 does not exist) base + 0x000004: Interrupt source 1 priority base + 0x000008: Interrupt source 2 priority ... base + 0x000FFC: Interrupt source 1023 priority base + 0x001000: Interrupt Pending bit 0-31 base + 0x00107C: Interrupt Pending bit 992-1023 ... base + 0x002000: Enable bits for sources 0-31 on context 0 base + 0x002004: Enable bits for sources 32-63 on context 0 ... base + 0x00207C: Enable bits for sources 992-1023 on context 0 base + 0x002080: Enable bits for sources 0-31 on context 1 base + 0x002084: Enable bits for sources 32-63 on context 1 ... base + 0x0020FC: Enable bits for sources 992-1023 on context 1 base + 0x002100: Enable bits for sources 0-31 on context 2 base + 0x002104: Enable bits for sources 32-63 on context 2 ... base + 0x00217C: Enable bits for sources 992-1023 on context 2 ... base + 0x1F1F80: Enable bits for sources 0-31 on context 15871 base + 0x1F1F84: Enable bits for sources 32-63 on context 15871 base + 0x1F1FFC: Enable bits for sources 992-1023 on context 15871 ... base + 0x1FFFFC: Reserved base + 0x200000: Priority threshold for context 0 base + 0x200004: Claim/complete for context 0 base + 0x200008: Reserved ... base + 0x200FFC: Reserved base + 0x201000: Priority threshold for context 1 base + 0x201004: Claim/complete for context 1 ... base + 0x3FFF000: Priority threshold for context 15871 base + 0x3FFF004: Claim/complete for context 15871 base + 0x3FFF008: Reserved ... base + 0x3FFFFFC: Reserved
Or, more usefully:
#[repr(C)]
struct Plic {
source_priorities: [u32; 1024],
interrupt_pending: [u32; 32],
_padding1: [u8; 3968],
interrupt_enable: [[u32; 32]; 15872],
_padding2: [u8; 57344],
threshold_and_claim: [[u32; 1024]; 15872],
}
Each
u32
inside of the
source_priorities
is a priority level from
0..=7
(on most platforms, see your platform specification for more complete information) of increasing priority level where priority
0
is considered "never interrupt" and will cause the interrupt to effectively be disabled, with the exception of interrupt #0, which does not exist and is reserved.
interrupt_pending
is a read-only bitmap of the pending status for priorities
1..=1024
(with the interrupt #0 bit hardwired to zero). Both
interrupt_enable
and
threshold_and_claim
work on the aforementioned contexts, and need to be indexed at a platform-specific index for a given hart and privilege mode combination. The
interrupt_enable
consists of another bitmap of interrupt sources (again with interrupt #0 for each context being hardwired to zero) which allow enabling and disabling specific interrupt sources at the context level, but also means that if you wish for a given interrupt to trigger across any hart, it will need to be enabled for each context for the privilege mode you are executing in.
threshold_and_claim
is made up of a threshold
u32
value and a claim
u32
value, with the rest of the
u32
s being reserved and should not be written to.