SimpleKernel 1.17.0
Loading...
Searching...
No Matches
plic.cpp
Go to the documentation of this file.
1
5#include "plic.h"
6
7#include <cpu_io.h>
8
9#include "basic_info.hpp"
10#include "kernel_log.hpp"
11
12namespace {
13auto DefaultPlicHandler(uint64_t cause, cpu_io::TrapContext* context)
14 -> uint64_t {
15 klog::Info("Default PLIC handler, cause: {:#x}, context: {:#x}", cause,
16 reinterpret_cast<uintptr_t>(context));
17 return 0;
18}
19} // namespace
20
21alignas(4) std::array<Plic::InterruptDelegate,
23
24Plic::Plic(uint64_t dev_addr, size_t ndev, size_t context_count)
25 : base_addr_(dev_addr), ndev_(ndev), context_count_(context_count) {
26 // 设置所有中断源的优先级为 0 (禁用)
27 klog::Info("Setting all interrupt priorities to 0");
28 for (size_t source_id = 0; source_id <= ndev_; source_id++) {
29 SourcePriority(source_id) = 0;
30 }
31
32 klog::Info("Disabling all interrupts for all contexts");
33
34 for (size_t context_id = 0; context_id < context_count_; context_id++) {
35 // 设置优先级阈值为 0 (允许所有优先级的中断)
36 PriorityThreshold(context_id) = 0;
37 // 禁用所有中断
38 for (size_t source_id = 0; source_id <= ndev_; source_id++) {
39 SetEnableBit(context_id, source_id, false);
40 }
41 }
42
44 "PLIC initialization: all interrupts disabled, priorities set to 0");
45
46 for (auto& h : interrupt_handlers_) {
47 h = InterruptDelegate::create<DefaultPlicHandler>();
48 }
49}
50
51auto Plic::Which() const -> uint32_t {
52 auto context_id = GetContextId(cpu_io::GetCurrentCoreId());
53 return ClaimComplete(context_id);
54}
55
56auto Plic::Done(uint32_t source_id) const -> void {
57 auto context_id = GetContextId(cpu_io::GetCurrentCoreId());
58 ClaimComplete(context_id) = source_id;
59}
60
62 -> void {
63 interrupt_handlers_[cause] = func;
64}
65
66auto Plic::Do(uint64_t cause, cpu_io::TrapContext* context) -> void {
67 interrupt_handlers_[cause](cause, context);
68}
69
70auto Plic::Set(uint32_t hart_id, uint32_t source_id, uint32_t priority,
71 bool enable) const -> void {
72 // 设置中断优先级
73 SourcePriority(source_id) = priority;
74
75 // 设置中断使能状态
76 uint32_t context_id = GetContextId(hart_id);
77 SetEnableBit(context_id, source_id, enable);
78}
79
80auto Plic::Get(uint32_t hart_id, uint32_t source_id) const
81 -> std::tuple<uint32_t, bool, bool> {
82 // 获取中断优先级
83 auto priority = SourcePriority(source_id);
84
85 // 获取中断使能状态
86 uint32_t context_id = GetContextId(hart_id);
87 auto enabled = GetEnableBit(context_id, source_id);
88
89 // 获取中断挂起状态
90 auto pending = GetPendingBit(source_id);
91
92 return {priority, enabled, pending};
93}
94
95auto Plic::GetEnableBit(uint32_t context_id, uint32_t source_id) const -> bool {
96 uint32_t word_index = source_id / 32;
97 uint32_t bit_index = source_id % 32;
98 uint32_t* word_addr = reinterpret_cast<uint32_t*>(
99 base_addr_ + kEnableBitsOffset + (context_id * kEnableSize) +
100 (word_index * 4));
101 return (*word_addr >> bit_index) & 1;
102}
103
104auto Plic::SetEnableBit(uint32_t context_id, uint32_t source_id,
105 bool value) const -> void {
106 uint32_t word_index = source_id / 32;
107 uint32_t bit_index = source_id % 32;
108 uint32_t* word_addr = reinterpret_cast<uint32_t*>(
109 base_addr_ + kEnableBitsOffset + (context_id * kEnableSize) +
110 (word_index * 4));
111 if (value) {
112 *word_addr |= (1U << bit_index);
113 } else {
114 *word_addr &= ~(1U << bit_index);
115 }
116}
117
118auto Plic::SourcePriority(uint32_t source_id) const -> uint32_t& {
119 return *reinterpret_cast<uint32_t*>(base_addr_ + kSourcePriorityOffset +
120 (source_id * sizeof(uint32_t)));
121}
122
123auto Plic::GetPendingBit(uint32_t source_id) const -> bool {
124 uint32_t word_index = source_id / 32;
125 uint32_t bit_index = source_id % 32;
126 uint32_t* word_addr = reinterpret_cast<uint32_t*>(
127 base_addr_ + kPendingBitsOffset + (word_index * 4));
128 return (*word_addr >> bit_index) & 1;
129}
130
131auto Plic::SetPendingBit(uint32_t source_id, bool value) const -> void {
132 uint32_t word_index = source_id / 32;
133 uint32_t bit_index = source_id % 32;
134 uint32_t* word_addr = reinterpret_cast<uint32_t*>(
135 base_addr_ + kPendingBitsOffset + (word_index * 4));
136 if (value) {
137 *word_addr |= (1U << bit_index);
138 } else {
139 *word_addr &= ~(1U << bit_index);
140 }
141}
142
143auto Plic::PriorityThreshold(uint32_t context_id) const -> uint32_t& {
144 return *reinterpret_cast<uint32_t*>(base_addr_ + kContextOffset +
145 (context_id * kContextSize) +
146 kPriorityThresholdOffset);
147}
148
149auto Plic::ClaimComplete(uint32_t context_id) const -> uint32_t& {
150 return *reinterpret_cast<uint32_t*>(base_addr_ + kContextOffset +
151 (context_id * kContextSize) +
152 kClaimCompleteOffset);
153}
auto Set(uint32_t hart_id, uint32_t source_id, uint32_t priority, bool enable) const -> void
设置指定中断源的使能状态
Definition plic.cpp:70
size_t ndev_
Definition plic.h:109
auto GetEnableBit(uint32_t context_id, uint32_t source_id) const -> bool
获取使能位寄存器中指定中断源的状态
Definition plic.cpp:95
auto Done(uint32_t source_id) const -> void
告知 Plic 已经处理了当前 IRQ
Definition plic.cpp:56
size_t context_count_
Definition plic.h:110
auto PriorityThreshold(uint32_t context_id) const -> uint32_t &
获取优先级阈值寄存器
Definition plic.cpp:143
auto SourcePriority(uint32_t source_id) const -> uint32_t &
获取中断源优先级寄存器
Definition plic.cpp:118
auto Which() const -> uint32_t
向 Plic 询问中断
Definition plic.cpp:51
auto GetPendingBit(uint32_t source_id) const -> bool
获取挂起位寄存器中指定中断源的状态
Definition plic.cpp:123
auto SetEnableBit(uint32_t context_id, uint32_t source_id, bool value) const -> void
设置使能位寄存器中指定中断源的状态
Definition plic.cpp:104
auto ClaimComplete(uint32_t context_id) const -> uint32_t &
获取声明/完成寄存器
Definition plic.cpp:149
auto Get(uint32_t hart_id, uint32_t source_id) const -> std::tuple< uint32_t, bool, bool >
获取指定中断源的状态信息
Definition plic.cpp:80
auto Do(uint64_t cause, cpu_io::TrapContext *context) -> void
执行外部中断处理
Definition plic.cpp:66
__always_inline auto GetContextId(uint32_t hart_id, uint32_t mode=1) const -> uint32_t
计算 context ID
Definition plic.h:119
static constexpr size_t kInterruptMaxCount
最大外部中断数量
Definition plic.h:25
Plic()=default
InterruptBase::InterruptDelegate InterruptDelegate
Definition plic.h:22
auto SetPendingBit(uint32_t source_id, bool value) const -> void
设置挂起位寄存器中指定中断源的状态
Definition plic.cpp:131
auto RegisterInterruptFunc(uint8_t cause, InterruptDelegate func) -> void
注册外部中断处理函数
Definition plic.cpp:61
static std::array< InterruptDelegate, kInterruptMaxCount > interrupt_handlers_
外部中断处理函数数组
Definition plic.h:106
auto GetCurrentCoreId() -> size_t
Definition cpu_io.h:26
auto Info(etl::format_string< Args... > fmt, Args &&... args) -> void
以 INFO 级别记录日志