SimpleKernel 1.17.0
Loading...
Searching...
No Matches
gic.cpp
Go to the documentation of this file.
1
5#include "gic.h"
6
7#include <cpu_io.h>
8
9#include <cassert>
10
11#include "kernel_log.hpp"
12
13Gic::Gic(uint64_t gicd_base_addr, uint64_t gicr_base_addr)
14 : gicd_(gicd_base_addr), gicr_(gicr_base_addr) {
15 cpu_io::ICC_IGRPEN1_EL1::Enable::Clear();
16 cpu_io::ICC_PMR_EL1::Priority::Set();
17
19
20 klog::Info("Gic init.");
21}
22
23auto Gic::SetUp() const -> void {
24 cpu_io::ICC_IGRPEN1_EL1::Enable::Clear();
25 cpu_io::ICC_PMR_EL1::Priority::Set();
27
28 gicr_.SetUp();
29}
30
31auto Gic::Spi(uint32_t intid, uint32_t cpuid) const -> void {
32 gicd_.SetupSpi(intid, cpuid);
33}
34
35auto Gic::Ppi(uint32_t intid, uint32_t cpuid) const -> void {
36 gicr_.SetupPpi(intid, cpuid);
37}
38
39auto Gic::Sgi(uint32_t intid, uint32_t cpuid) const -> void {
40 gicr_.SetupSgi(intid, cpuid);
41}
42
43Gic::Gicd::Gicd(uint64_t _base_addr) : base_addr_(_base_addr) {
44 assert(base_addr_ != 0 && "GICD base address is invalid");
45
46 // 将 GICD_CTLR 清零
47 Write(kCtlr, 0);
48
49 // 读取 ITLinesNumber 数量
50 auto it_lines_number = Read(kTyper) & kTyperItLinesNumberMask;
51
52 klog::Info("it_lines_number {}", it_lines_number);
53
54 // 设置中断为 Non-secure Group 1
55 for (uint32_t i = 0; i < it_lines_number; i++) {
56 Write(Igrouprn(i), UINT32_MAX);
57 }
58}
59
60auto Gic::Gicd::Enable(uint32_t intid) const -> void {
61 auto is = Read(Isenablern(intid / kIsEnablernSize));
62 is |= 1 << (intid % kIsEnablernSize);
63 Write(Isenablern(intid / kIsEnablernSize), is);
64}
65
66auto Gic::Gicd::EnableGrp1Ns() const -> void {
67 Write(kCtlr, kCtlrEnableGrp1Ns);
68 cpu_io::ICC_IGRPEN1_EL1::Enable::Set();
69}
70
71auto Gic::Gicd::Disable(uint32_t intid) const -> void {
72 auto ic = Read(Icenablern(intid / kIcEnablernSize));
73 ic |= 1 << (intid % kIcEnablernSize);
74 Write(Icenablern(intid / kIcEnablernSize), ic);
75}
76
77auto Gic::Gicd::Clear(uint32_t intid) const -> void {
78 auto ic = Read(Icpendrn(intid / kIcPendrnSize));
79 ic |= 1 << (intid % kIcPendrnSize);
80 Write(Icpendrn(intid / kIcPendrnSize), ic);
81}
82
83auto Gic::Gicd::IsEnable(uint32_t intid) const -> bool {
84 auto is = Read(Isenablern(intid / kIsEnablernSize));
85 return is & (1 << (intid % kIsEnablernSize));
86}
87
88auto Gic::Gicd::SetPrio(uint32_t intid, uint32_t prio) const -> void {
89 auto shift = (intid % kIpriorityrnSize) * kIpriorityrnBits;
90 auto ip = Read(Ipriorityrn(intid / kIpriorityrnSize));
91 ip &= ~(kIpriorityrnBitsMask << shift);
92 ip |= prio << shift;
93 Write(Ipriorityrn(intid / kIpriorityrnSize), ip);
94}
95
96auto Gic::Gicd::SetConfig(uint32_t intid, uint32_t config) const -> void {
97 auto shift = (intid % kIcfgrnSize) * kIcfgrnBits;
98 auto ic = Read(Icfgrn(intid / kIcfgrnSize));
99 ic &= ~(kIcfgrnBitsMask << shift);
100 ic |= config << shift;
101 Write(Icfgrn(intid / kIcfgrnSize), ic);
102}
103
104auto Gic::Gicd::SetTarget(uint32_t intid, uint32_t cpuid) const -> void {
105 auto target = Read(Itargetsrn(intid / kItargetsrnSize));
106 target &= ~(kIcfgrnBitsMask << ((intid % kItargetsrnSize) * kItargetsrnBits));
107 Write(
108 Itargetsrn(intid / kItargetsrnSize),
109 target | ((1 << cpuid) << ((intid % kItargetsrnSize) * kItargetsrnBits)));
110}
111
112auto Gic::Gicr::SetUp() const -> void {
113 auto cpuid = cpu_io::GetCurrentCoreId();
114
115 // 将 GICR_CTLR 清零
116 Write(cpuid, kCtlr, 0);
117
118 // The System register interface for the current Security state is enabled.
119 cpu_io::ICC_SRE_EL1::SRE::Set();
120
121 // 允许 Non-secure Group 1 中断
122 Write(cpuid, kIgroupr0, kIgroupr0Set);
123 Write(cpuid, kIgrpmodr0, kIgrpmodr0Clear);
124
125 // 唤醒 Redistributor
126 // @see
127 // https://developer.arm.com/documentation/ddi0601/2024-12/External-Registers/GICR-WAKER--Redistributor-Wake-Register?lang=en
128 auto waker = Read(cpuid, kWaker);
129 // Clear the ProcessorSleep bit
130 Write(cpuid, kWaker, waker & ~kWakerProcessorSleepMask);
131 // 等待唤醒完成
132 while (Read(cpuid, kWaker) & kWakerChildrenAsleepMask) {
134 }
135}
136
137auto Gic::Gicd::SetupSpi(uint32_t intid, uint32_t cpuid) const -> void {
138 // 电平触发
139 SetConfig(intid, kIcfgrnLevelSensitive);
140
141 // 优先级设定
142 SetPrio(intid, 0);
143
144 // 设置所有中断由 cpu0 处理
145 SetTarget(intid, cpuid);
146 // 清除中断请求
147 Clear(intid);
148 // 使能中断
149 Enable(intid);
150}
151
152Gic::Gicr::Gicr(uint64_t _base_addr) : base_addr_(_base_addr) {
153 assert(base_addr_ != 0 && "GICR base address is invalid");
154
155 auto cpuid = cpu_io::GetCurrentCoreId();
156
157 // 将 GICR_CTLR 清零
158 Write(cpuid, kCtlr, 0);
159
160 // The System register interface for the current Security state is enabled.
161 cpu_io::ICC_SRE_EL1::SRE::Set();
162
163 // 允许 Non-secure Group 1 中断
166
167 // 唤醒 Redistributor
168 // @see
169 // https://developer.arm.com/documentation/ddi0601/2024-12/External-Registers/GICR-WAKER--Redistributor-Wake-Register?lang=en
170 auto waker = Read(cpuid, kWaker);
171 // Clear the ProcessorSleep bit
172 Write(cpuid, kWaker, waker & ~kWakerProcessorSleepMask);
173 // 等待唤醒完成
174 while (Read(cpuid, kWaker) & kWakerChildrenAsleepMask) {
176 }
177}
178
179auto Gic::Gicr::Enable(uint32_t intid, uint32_t cpuid) const -> void {
180 auto is = Read(cpuid, kIsEnabler0);
181 is |= 1 << (intid % kIsEnabler0Size);
182 Write(cpuid, kIsEnabler0, is);
183}
184
185auto Gic::Gicr::Disable(uint32_t intid, uint32_t cpuid) const -> void {
186 auto ic = Read(cpuid, kIcEnabler0);
187 ic |= 1 << (intid % kIcEnabler0Size);
188 Write(cpuid, kIcEnabler0, ic);
189}
190
191auto Gic::Gicr::Clear(uint32_t intid, uint32_t cpuid) const -> void {
192 auto ic = Read(cpuid, kIcPendr0);
193 ic |= 1 << (intid % kIcPendr0Size);
194 Write(cpuid, kIcPendr0, ic);
195}
196
197auto Gic::Gicr::SetPrio(uint32_t intid, uint32_t cpuid, uint32_t prio) const
198 -> void {
199 auto shift = (intid % kIpriorityrnSize) * kIpriorityrnBits;
200 auto ip = Read(cpuid, Ipriorityrn(intid / kIpriorityrnSize));
201 ip &= ~(kIpriorityrnBitsMask << shift);
202 ip |= prio << shift;
203 Write(cpuid, Ipriorityrn(intid / kIpriorityrnSize), ip);
204}
205
206auto Gic::Gicr::SetupPpi(uint32_t intid, uint32_t cpuid) const -> void {
207 SetPrio(intid, cpuid, 0);
208 Clear(intid, cpuid);
209 Enable(intid, cpuid);
210}
211
212auto Gic::Gicr::SetupSgi(uint32_t intid, uint32_t cpuid) const -> void {
213 SetPrio(intid, cpuid, 0);
214 Clear(intid, cpuid);
215 Enable(intid, cpuid);
216}
static constexpr uint32_t kTyper
Configuration dependent Interrupt Controller Type Register, RO.
Definition gic.h:145
auto EnableGrp1Ns() const -> void
允许 no-sec group1 中断
Definition gic.cpp:66
auto SetTarget(uint32_t intid, uint32_t cpuid) const -> void
设置 intid 的由指定 cpu 处理
Definition gic.cpp:104
auto SetConfig(uint32_t intid, uint32_t config) const -> void
设置 intid 的属性
Definition gic.cpp:96
Gicd()=default
auto SetupSpi(uint32_t intid, uint32_t cpuid) const -> void
设置指定 SPI 中断 SPI: shared peripheral interrupt, 共享外设中断,该中断来源于外设,但是该中断可以对所有的 core 有效
Definition gic.cpp:137
auto Disable(uint32_t intid) const -> void
禁止从 Distributor 转发到 redistributor
Definition gic.cpp:71
uint64_t base_addr_
GICD 基地址
Definition gic.h:394
__always_inline auto Igrouprn(uint64_t n) const -> uint64_t
计算 IGROUPR 寄存器偏移
Definition gic.h:232
__always_inline auto Write(uint32_t off, uint32_t val) const -> void
Definition gic.h:401
auto SetPrio(uint32_t intid, uint32_t prio) const -> void
设置 intid 的优先级
Definition gic.cpp:88
auto Clear(uint32_t intid) const -> void
清除 intid 的中断
Definition gic.cpp:77
auto IsEnable(uint32_t intid) const -> bool
判断 intid 中断是否使能
Definition gic.cpp:83
__always_inline auto Read(uint32_t off) const -> uint32_t
Definition gic.h:396
static constexpr uint32_t kTyperItLinesNumberMask
Definition gic.h:146
static constexpr uint32_t kCtlr
Definition gic.h:115
auto Enable(uint32_t intid) const -> void
允许从 Distributor 转发到 redistributor
Definition gic.cpp:60
auto SetPrio(uint32_t intid, uint32_t cpuid, uint32_t prio) const -> void
设置 intid 的优先级
Definition gic.cpp:197
static constexpr uint32_t kIgrpmodr0
Definition gic.h:594
static constexpr uint32_t kCtlr
Definition gic.h:487
auto SetUp() const -> void
初始化 gicr,在多核场景使用
Definition gic.cpp:112
auto SetupPpi(uint32_t intid, uint32_t cpuid) const -> void
设置指定 PPI 中断 PPI: private peripheral interrupt, 私有外设中断,该中断来源于外设,但是该中断只对指定的 core 有效
Definition gic.cpp:206
static constexpr uint32_t kIgroupr0
Definition gic.h:541
uint64_t base_addr_
GICR 基地址
Definition gic.h:616
auto SetupSgi(uint32_t intid, uint32_t cpuid) const -> void
设置指定 SGI 中断 SGI: Software Generated Interrupt, 软件生成中断,用于处理器间通信
Definition gic.cpp:212
static constexpr uint32_t kWaker
Definition gic.h:496
auto Enable(uint32_t intid, uint32_t cpuid) const -> void
允许从 redistributor 转发到 CPU interface
Definition gic.cpp:179
auto Clear(uint32_t intid, uint32_t cpuid) const -> void
清除指定 cpu intid 的中断
Definition gic.cpp:191
static constexpr uint32_t kIgroupr0Set
Definition gic.h:543
__always_inline auto Write(uint32_t cpuid, uint32_t off, uint32_t val) const -> void
Definition gic.h:625
static constexpr uint32_t kIgrpmodr0Clear
Definition gic.h:599
__always_inline auto Read(uint32_t cpuid, uint32_t off) const -> uint32_t
Definition gic.h:618
static constexpr uint32_t kWakerChildrenAsleepMask
Definition gic.h:498
auto Disable(uint32_t intid, uint32_t cpuid) const -> void
禁止从 redistributor 转发到 CPU interface
Definition gic.cpp:185
Gicr()=default
static constexpr uint32_t kWakerProcessorSleepMask
Definition gic.h:497
auto Spi(uint32_t intid, uint32_t cpuid) const -> void
配置共享外设中断 (SPI)
Definition gic.cpp:31
auto Sgi(uint32_t intid, uint32_t cpuid) const -> void
配置软件生成中断 (SGI)
Definition gic.cpp:39
Gic()=default
Gicd gicd_
Distributor 实例
Definition gic.h:678
auto SetUp() const -> void
初始化当前 CPU 的 GIC 配置
Definition gic.cpp:23
auto Ppi(uint32_t intid, uint32_t cpuid) const -> void
配置私有外设中断 (PPI)
Definition gic.cpp:35
Gicr gicr_
Redistributor 实例
Definition gic.h:680
auto GetCurrentCoreId() -> size_t
Definition cpu_io.h:26
void Pause()
Definition cpu_io.h:20
auto Info(etl::format_string< Args... > fmt, Args &&... args) -> void
以 INFO 级别记录日志