PLIC

From FriendOS Wiki
Revision as of 01:54, 2 February 2023 by Repnop (talk | contribs) (Initial writeup -- incomplete but need to restart)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

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)]
pub 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; 4090]; 15872],
    _padding3: [u8; 8184],
}