SimpleKernel 1.17.0
Loading...
Searching...
No Matches
interrupt_main.cpp
Go to the documentation of this file.
1
5#include <cpu_io.h>
6#include <opensbi_interface.h>
7
8#include "arch.h"
9#include "basic_info.hpp"
10#include "interrupt.h"
11#include "kernel.h"
12#include "kernel_fdt.hpp"
13#include "kernel_log.hpp"
14#include "kstd_cstdio"
15#include "ns16550a/ns16550a.hpp"
16#include "syscall.hpp"
17#include "task_manager.hpp"
19#include "virtual_memory.hpp"
20
21namespace {
22using Ns16550aSingleton = etl::singleton<ns16550a::Ns16550a>;
24
25// 外部中断分发器:CPU 外部中断 -> PLIC -> 设备 handler
26auto ExternalInterruptHandler(uint64_t /*cause*/, cpu_io::TrapContext* context)
27 -> uint64_t {
28 auto& plic = InterruptSingleton::instance().plic();
29 auto source_id = plic.Which();
30 plic.Do(source_id, context);
31 plic.Done(source_id);
32 return 0;
33}
34
35// ebreak 中断处理
36auto EbreakHandler(uint64_t exception_code, cpu_io::TrapContext* context)
37 -> uint64_t {
38 // 读取 sepc 处的指令
39 auto instruction = *reinterpret_cast<uint8_t*>(context->sepc);
40
41 // 判断是否为压缩指令 (低 2 位不为 11)
42 if ((instruction & 0x3) != 0x3) {
43 // 2 字节指令
44 context->sepc += 2;
45 } else {
46 // 4 字节指令
47 context->sepc += 4;
48 }
49 klog::Info("Handle {}", cpu_io::ScauseInfo::kExceptionNames[exception_code]);
50 return 0;
51}
52
53auto PageFaultHandler(uint64_t exception_code, cpu_io::TrapContext* context)
54 -> uint64_t {
55 auto addr = cpu_io::Stval::Read();
56 klog::Err("PageFault: {}({:#x}), addr: {:#x}",
57 cpu_io::ScauseInfo::kExceptionNames[exception_code], exception_code,
58 addr);
59 klog::Err("sepc: {:#x}", context->sepc);
60 DumpStack();
61 while (true) {
63 }
64 return 0;
65}
66
67// 系统调用处理
68auto SyscallHandler(uint64_t /*cause*/, cpu_io::TrapContext* context)
69 -> uint64_t {
70 Syscall(0, context);
71 return 0;
72}
73
74// 软中断 (IPI) 处理
75auto IpiHandler(uint64_t /*cause*/, cpu_io::TrapContext* /*context*/)
76 -> uint64_t {
77 // 清软中断 pending 位
78 cpu_io::Sip::Ssip::Clear();
79 klog::Debug("Core {} received IPI", cpu_io::GetCurrentCoreId());
80 return 0;
81}
82
83// 串口外部中断处理
84auto SerialIrqHandler(uint64_t /*cause*/, cpu_io::TrapContext* /*context*/)
85 -> uint64_t {
86 while (Ns16550aSingleton::instance().HasData()) {
87 uint8_t ch = Ns16550aSingleton::instance().GetChar();
88 etl_putchar(ch);
89 }
90 return 0;
91}
92
93// VirtIO-blk 外部中断处理
94auto VirtioBlkIrqHandler(uint64_t /*cause*/, cpu_io::TrapContext* /*context*/)
95 -> uint64_t {
96 VirtioDriverSingleton::instance().HandleInterrupt(
97 [](void* /*token*/, ErrorCode status) {
98 if (status != ErrorCode::kSuccess) {
99 klog::Err("VirtIO blk IO error: {}", static_cast<int>(status));
100 }
101 });
102 return 0;
103}
104
105auto RegisterInterrupts() -> void {
106 // 注册外部中断分发器:CPU 外部中断 -> PLIC -> 设备 handler
107 InterruptSingleton::instance().RegisterInterruptFunc(
108 cpu_io::ScauseInfo::kSupervisorExternalInterrupt,
109 InterruptDelegate::create<ExternalInterruptHandler>());
110
111 auto [base, size, irq] = KernelFdtSingleton::instance().GetSerial().value();
112 auto uart_result = ns16550a::Ns16550a::Create(base);
113 if (uart_result) {
114 Ns16550aSingleton::create(std::move(*uart_result));
115 } else {
116 klog::Err("Failed to create Ns16550a: {}",
117 static_cast<int>(uart_result.error().code));
118 }
119
120 // 注册 ebreak 中断
121 InterruptSingleton::instance().RegisterInterruptFunc(
122 cpu_io::ScauseInfo::kBreakpoint,
123 InterruptDelegate::create<EbreakHandler>());
124
125 // 注册缺页中断处理
126 InterruptSingleton::instance().RegisterInterruptFunc(
127 cpu_io::ScauseInfo::kInstructionPageFault,
128 InterruptDelegate::create<PageFaultHandler>());
129 InterruptSingleton::instance().RegisterInterruptFunc(
130 cpu_io::ScauseInfo::kLoadPageFault,
131 InterruptDelegate::create<PageFaultHandler>());
132 InterruptSingleton::instance().RegisterInterruptFunc(
133 cpu_io::ScauseInfo::kStoreAmoPageFault,
134 InterruptDelegate::create<PageFaultHandler>());
135
136 // 注册系统调用
137 InterruptSingleton::instance().RegisterInterruptFunc(
138 cpu_io::ScauseInfo::kEcallUserMode,
139 InterruptDelegate::create<SyscallHandler>());
140
141 // 注册软中断 (IPI)
142 InterruptSingleton::instance().RegisterInterruptFunc(
143 cpu_io::ScauseInfo::kSupervisorSoftwareInterrupt,
144 InterruptDelegate::create<IpiHandler>());
145}
146
147} // namespace
148
149extern "C" auto HandleTrap(cpu_io::TrapContext* context)
151 InterruptSingleton::instance().Do(context->scause, context);
152 return context;
153}
154
155auto InterruptInit(int, const char**) -> void {
156 InterruptSingleton::create();
157
158 // 注册中断处理函数
159 RegisterInterrupts();
160
161 // 初始化 plic
162 auto [plic_addr, plic_size, ndev, context_count] =
163 KernelFdtSingleton::instance().GetPlic().value();
164 VirtualMemorySingleton::instance()
165 .MapMMIO(plic_addr, plic_size)
166 .or_else([](Error err) -> Expected<void*> {
167 klog::Err("Failed to map PLIC MMIO: {}", err.message());
168 while (true) {
170 }
171 return std::unexpected(err);
172 });
173 InterruptSingleton::instance().InitPlic(plic_addr, ndev, context_count);
174
175 // 设置 trap vector
176 auto success =
177 cpu_io::Stvec::SetDirect(reinterpret_cast<uint64_t>(trap_entry));
178 if (!success) {
179 klog::Err("Failed to set trap vector");
180 }
181
182 // 开启 Supervisor 中断
183 cpu_io::Sstatus::Sie::Set();
184
185 // 开启内部中断
186 cpu_io::Sie::Ssie::Set();
187
188 // 开启外部中断
189 cpu_io::Sie::Seie::Set();
190
191 // 通过统一接口注册串口外部中断(先注册 handler,再启用 PLIC)
192 auto serial_irq =
193 std::get<2>(KernelFdtSingleton::instance().GetSerial().value());
194 InterruptSingleton::instance()
195 .RegisterExternalInterrupt(serial_irq, cpu_io::GetCurrentCoreId(), 1,
196 InterruptDelegate::create<SerialIrqHandler>())
197 .or_else([](Error err) -> Expected<void> {
198 klog::Err("Failed to register serial IRQ: {}", err.message());
199 return std::unexpected(err);
200 });
201
202 // 通过统一接口注册 virtio-blk 外部中断
203 auto& blk_driver = VirtioDriverSingleton::instance();
204 auto blk_irq = blk_driver.GetIrq();
205 if (blk_irq != 0) {
206 InterruptSingleton::instance()
207 .RegisterExternalInterrupt(
208 blk_irq, cpu_io::GetCurrentCoreId(), 1,
209 InterruptDelegate::create<VirtioBlkIrqHandler>())
210 .or_else([blk_irq](Error err) -> Expected<void> {
211 klog::Err("Failed to register virtio-blk IRQ {}: {}", blk_irq,
212 err.message());
213 return std::unexpected(err);
214 });
215 }
216
217 klog::Info("Hello InterruptInit");
218}
219
220auto InterruptInitSMP(int, const char**) -> void {
221 // 设置 trap vector
222 auto success =
223 cpu_io::Stvec::SetDirect(reinterpret_cast<uint64_t>(trap_entry));
224 if (!success) {
225 klog::Err("Failed to set trap vector");
226 }
227
228 // 开启 Supervisor 中断
229 cpu_io::Sstatus::Sie::Set();
230
231 // 开启内部中断
232 cpu_io::Sie::Ssie::Set();
233
234 // 开启外部中断
235 cpu_io::Sie::Seie::Set();
236
237 klog::Info("Hello InterruptInitSMP");
238}
auto DumpStack() -> void
打印调用栈
Definition backtrace.cpp:34
auto etl_putchar(int c) -> void
早期控制台字符输出
auto InterruptInit(int, const char **) -> void
体系结构相关中断初始化
InterruptBase::InterruptDelegate InterruptDelegate
auto InterruptInitSMP(int, const char **) -> void
从核的体系结构相关中断初始化
auto Syscall(uint64_t, cpu_io::TrapContext *context_ptr) -> void
AArch64 系统调用处理
Definition syscall.cpp:16
auto trap_entry() -> void
Definition arch.cpp:46
etl::delegate< uint64_t(uint64_t, cpu_io::TrapContext *)> InterruptDelegate
类型安全的中断处理委托
static auto Create(uint64_t dev_addr) -> Expected< Ns16550a >
工厂方法:创建并初始化 NS16550A 驱动
Definition ns16550a.hpp:30
ErrorCode
内核错误码
Definition expected.hpp:11
std::expected< T, Error > Expected
std::expected 别名模板
Definition expected.hpp:365
auto GetCurrentCoreId() -> size_t
Definition cpu_io.h:26
void Pause()
Definition cpu_io.h:20
auto Err(etl::format_string< Args... > fmt, Args &&... args) -> void
以 ERROR 级别记录日志
auto Info(etl::format_string< Args... > fmt, Args &&... args) -> void
以 INFO 级别记录日志
auto Debug(etl::format_string< Args... > fmt, Args &&... args) -> void
以 DEBUG 级别记录日志(SIMPLEKERNEL_MIN_LOG_LEVEL > 0 时编译期消除)
auto HandleTrap(cpu_io::TrapContext *context) -> cpu_io::TrapContext *
错误类型,用于 std::expected
Definition expected.hpp:343
constexpr auto message() const -> const char *
Definition expected.hpp:358