Peripheral Interrupt Procedure in RISC-V

Last updated on April 2, 2023 pm

Peripheral Interrupt Procedure in RISC-V

The procedure of peripheral interrupt in RISC-V is quite complicated and multi-layered.

Basically, all peripheral interrupts are reported to platform-level interrupt controller or PLIC, which is similar to PIC (programmable interrupt controller) in x86 architecture.

The memory mapped from PLIC varied by platforms. Chapter 3 of official PLIC Specification gives a sample. In QEMU, it could be found under qemu/include/hw/riscv folder.

Registers

There are (five types of) registers for PLIC:

  • priority
  • pending
  • enable
  • threshold
  • claim/complete

Priorities

The priorities of external interrupts are defined in priority registers, whose ranges from 1 to 1023 (1023 sources in total, also known as interrupt identifiers, ID). Note that 0 is reserved for no interrupt occurring.

1 interrupt source maps to 1 register. For example,

Address Mapping
base + 0x0000 Reserved
base + 0x0004 priority value of Interrupt source 1
base + 0x0008 priority value of Interrupt source 2
base + 0x0FFC priority value of Interrupt source 1023

The value in the priority is the priority level of mapped resource. 0 is representing never interrupt, and the larger the higher priority.

If two interrupt resources have the same priority level, PLIC will get the smallest ID first and give the interrupt to Hart to handle.

QEMU Specific

QEMU’s RISC-V virtual machine virt supports 7 levels of priority.

In its create_pcie_irq_map function, it set that

1
2
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
0x1800, 0, 0, 0x7);

qemu_fdt_setprop_cells is a function-like macro defined in qemu/include/sysemu/device_tree.h, helping set up. fdt stands for flattened device tree and represents the device tree blob pointer. And prop means properties. It treats interrupt-map-mask as a property whit smallest value 0 and biggest value 7.

Pending

Each bit of pending corresponds to one interrupt source, 1 for interrupt happening.

Interrupt Flow

When external interrupts come in:

  1. PLIC checks their priority
    • if same, get the one with the smallest interrupt source ID
  2. PLIC checks enable
  3. PLIC checks is the priority bigger than threshold
  4. PLIC sets corresponding pending
    • HART’s running is interrupted and starts to handle the interrupt
  5. HART reads value from claim to know interrupt source ID
  6. HART calls corresponding functions
  7. HART writes back to complete
  8. HART returns to normal running
  9. PLIC cleans the pending

Initialization

  1. Define interrupt source ID
  2. Set priority
  3. Set enable
  4. Set threshold
  5. Set MIE bit in mstatus, M-mode global interrupt-enable bit (for M-mode)
  6. Set MEIE bit in mie, machine-level external interrupts enable bit in machine interrupt enable register.

References

  1. riscv/riscv-plic-spec: PLIC Specification
  2. [完结] 循序渐进,学习开发一个RISC-V上的操作系统 - 汪辰 - 2021春:第11章-外部设备中断_哔哩哔哩_bilibili
  3. Interrupts - Beginner’s Guide to PIC Programming - picguides.com
  4. mini-riscv-os/07-ExterInterrupt.md at master · cccriscv/mini-riscv-os
  5. PLIC - OSDev Wiki
  6. 8259 PIC - OSDev Wiki
  7. 2 4 RISC V::中斷與異常處理 中斷篇 · ianchen0119/AwesomeCS Wiki
  8. 2 5 RISC V::中斷與異常處理 PLIC 介紹 · ianchen0119/AwesomeCS Wiki

Peripheral Interrupt Procedure in RISC-V
https://lingkang.dev/2023/04/02/peripheral-interrupt/
Author
Lingkang
Posted on
April 2, 2023
Licensed under