SimpleKernel 1.17.0
Loading...
Searching...
No Matches
kernel_fdt.hpp
Go to the documentation of this file.
1
5#pragma once
6
7// 禁用 GCC/Clang 的警告
8#include <libfdt_env.h>
9#ifdef __GNUC__
10#pragma GCC diagnostic push
11#pragma GCC diagnostic ignored "-Wpedantic"
12#endif
13
14#include <libfdt.h>
15
16#ifdef __GNUC__
17#pragma GCC diagnostic pop
18#endif
19
20#include <cpu_io.h>
21#include <etl/singleton.h>
22
23#include <array>
24#include <cassert>
25#include <cstddef>
26#include <cstdint>
27#include <tuple>
28#include <utility>
29
30#include "expected.hpp"
31#include "kernel_log.hpp"
32#include "kstd_cstring"
33
47class KernelFdt {
48 public:
54 [[nodiscard]] auto GetCoreCount() const -> Expected<size_t> {
55 assert(fdt_header_ != nullptr && "fdt_header_ is null");
56
57 return CountNodesByDeviceType("cpu").and_then(
58 [](size_t count) -> Expected<size_t> {
59 if (count == 0) {
60 return std::unexpected(Error(ErrorCode::kFdtNodeNotFound));
61 }
62 return count;
63 });
64 }
65
71 [[nodiscard]] auto CheckPSCI() const -> Expected<void> {
72 assert(fdt_header_ != nullptr && "fdt_header_ is null");
73
74 return FindNode("/psci").and_then([this](int offset) -> Expected<void> {
75 return GetPsciMethod(offset).and_then(
76 [this, offset](const char* method) -> Expected<void> {
77 klog::Debug("PSCI method: {}", method);
78 if (strcmp(method, "smc") != 0) {
79 return std::unexpected(Error(ErrorCode::kFdtPropertyNotFound));
80 }
81 return ValidatePsciFunctionIds(offset);
82 });
83 });
84 }
85
92 [[nodiscard]] auto GetMemory() const
93 -> Expected<std::pair<uint64_t, size_t>> {
94 assert(fdt_header_ != nullptr && "fdt_header_ is null");
95
96 return FindNode("/memory").and_then(
97 [this](int offset) -> Expected<std::pair<uint64_t, size_t>> {
98 return GetRegProperty(offset).transform(
99 [](std::pair<uint64_t, size_t> reg) { return reg; });
100 });
101 }
102
109 [[nodiscard]] auto GetSerial() const
110 -> Expected<std::tuple<uint64_t, size_t, uint32_t>> {
111 assert(fdt_header_ != nullptr && "fdt_header_ is null");
112
113 auto chosen_offset = FindNode("/chosen");
114 if (!chosen_offset.has_value()) {
115 return std::unexpected(chosen_offset.error());
116 }
117
118 int len = 0;
119 const auto* prop = fdt_get_property(fdt_header_, chosen_offset.value(),
120 "stdout-path", &len);
121 if (prop == nullptr || len <= 0) {
122 return std::unexpected(Error(ErrorCode::kFdtPropertyNotFound));
123 }
124
125 const char* stdout_path = reinterpret_cast<const char*>(prop->data);
126 std::array<char, 256> path_buffer;
127 kstd::strncpy(path_buffer.data(), stdout_path, path_buffer.max_size() - 1);
128
129 char* colon = strchr(path_buffer.data(), ':');
130 if (colon != nullptr) {
131 *colon = '\0';
132 }
133
134 int stdout_offset = -1;
135 if (path_buffer[0] == '&') {
136 const char* alias = path_buffer.data() + 1;
137 const char* aliased_path = fdt_get_alias(fdt_header_, alias);
138 if (aliased_path != nullptr) {
139 stdout_offset = fdt_path_offset(fdt_header_, aliased_path);
140 }
141 } else {
142 stdout_offset = fdt_path_offset(fdt_header_, path_buffer.data());
143 }
144
145 if (stdout_offset < 0) {
146 return std::unexpected(Error(ErrorCode::kFdtNodeNotFound));
147 }
148
149 auto reg = GetRegProperty(stdout_offset);
150 if (!reg.has_value()) {
151 return std::unexpected(reg.error());
152 }
153
154 prop = fdt_get_property(fdt_header_, stdout_offset, "interrupts", &len);
155 if (prop == nullptr) {
156 return std::unexpected(Error(ErrorCode::kFdtPropertyNotFound));
157 }
158
159 uint32_t irq = 0;
160 const auto* interrupts = reinterpret_cast<const uint32_t*>(prop->data);
161 if (interrupts != nullptr && len != 0) {
162 irq = fdt32_to_cpu(*interrupts);
163 }
164
165 return std::tuple{reg.value().first, reg.value().second, irq};
166 }
167
173 [[nodiscard]] auto GetTimebaseFrequency() const -> Expected<uint32_t> {
174 assert(fdt_header_ != nullptr && "fdt_header_ is null");
175
176 return FindNode("/cpus").and_then([this](int offset) -> Expected<uint32_t> {
177 int len = 0;
178 const auto* prop = reinterpret_cast<const uint32_t*>(
179 fdt_getprop(fdt_header_, offset, "timebase-frequency", &len));
180 if (prop == nullptr) {
181 return std::unexpected(Error(ErrorCode::kFdtPropertyNotFound));
182 }
183
184 if (len != sizeof(uint32_t)) {
185 return std::unexpected(Error(ErrorCode::kFdtInvalidPropertySize));
186 }
187
188 return fdt32_to_cpu(*prop);
189 });
190 }
191
198 [[nodiscard]] auto GetGIC() const
199 -> Expected<std::tuple<uint64_t, size_t, uint64_t, size_t>> {
200 assert(fdt_header_ != nullptr && "fdt_header_ is null");
201
202 auto offset = FindCompatibleNode("arm,gic-v3");
203 if (!offset.has_value()) {
204 return std::unexpected(offset.error());
205 }
206
207 int len = 0;
208 const auto* prop =
209 fdt_get_property(fdt_header_, offset.value(), "reg", &len);
210 if (prop == nullptr) {
211 return std::unexpected(Error(ErrorCode::kFdtPropertyNotFound));
212 }
213
214 uint64_t dist_base = 0;
215 size_t dist_size = 0;
216 uint64_t redist_base = 0;
217 size_t redist_size = 0;
218
219 const auto* reg = reinterpret_cast<const uint64_t*>(prop->data);
220 if (static_cast<unsigned>(len) >= 2 * sizeof(uint64_t)) {
221 dist_base = fdt64_to_cpu(reg[0]);
222 dist_size = fdt64_to_cpu(reg[1]);
223 }
224 if (static_cast<unsigned>(len) >= 4 * sizeof(uint64_t)) {
225 redist_base = fdt64_to_cpu(reg[2]);
226 redist_size = fdt64_to_cpu(reg[3]);
227 }
228
229 return std::tuple{dist_base, dist_size, redist_base, redist_size};
230 }
231
236 [[nodiscard]] auto GetGicDist() const
237 -> Expected<std::pair<uint64_t, size_t>> {
238 return GetGIC().transform(
239 [](std::tuple<uint64_t, size_t, uint64_t, size_t> gic) {
240 return std::pair{std::get<0>(gic), std::get<1>(gic)};
241 });
242 }
243
248 [[nodiscard]] auto GetGicCpu() const
249 -> Expected<std::pair<uint64_t, size_t>> {
250 return GetGIC().transform(
251 [](std::tuple<uint64_t, size_t, uint64_t, size_t> gic) {
252 return std::pair{std::get<2>(gic), std::get<3>(gic)};
253 });
254 }
255
262 [[nodiscard]] auto GetAarch64Intid(const char* compatible) const
264 assert(fdt_header_ != nullptr && "fdt_header_ is null");
265
266 auto offset = FindEnabledCompatibleNode(compatible);
267 if (!offset.has_value()) {
268 return std::unexpected(offset.error());
269 }
270
271 int len = 0;
272 const auto* prop =
273 fdt_get_property(fdt_header_, offset.value(), "interrupts", &len);
274 if (prop == nullptr) {
275 return std::unexpected(Error(ErrorCode::kFdtPropertyNotFound));
276 }
277
278 const auto* interrupts = reinterpret_cast<const uint32_t*>(prop->data);
279
280#ifdef SIMPLEKERNEL_DEBUG
281 for (uint32_t i = 0; i < fdt32_to_cpu(prop->len);
282 i += 3 * sizeof(uint32_t)) {
283 auto type = fdt32_to_cpu(interrupts[i / sizeof(uint32_t) + 0]);
284 auto intid = fdt32_to_cpu(interrupts[i / sizeof(uint32_t) + 1]);
285 auto trigger = fdt32_to_cpu(interrupts[i / sizeof(uint32_t) + 2]) & 0xF;
286 auto cpuid_mask =
287 fdt32_to_cpu(interrupts[i / sizeof(uint32_t) + 2]) & 0xFF00;
288 klog::Debug("type: {}, intid: {}, trigger: {}, cpuid_mask: {}", type,
289 intid, trigger, cpuid_mask);
290 }
291#endif
292
293 uint64_t intid = 0;
294 if (strcmp(compatible, "arm,armv8-timer") == 0) {
295 intid = fdt32_to_cpu(interrupts[7]);
296 } else if (strcmp(compatible, "arm,pl011") == 0) {
297 intid = fdt32_to_cpu(interrupts[1]);
298 }
299
300 return intid;
301 }
302
310 [[nodiscard]] auto GetPlic() const
311 -> Expected<std::tuple<uint64_t, uint64_t, uint32_t, uint32_t>> {
312 assert(fdt_header_ != nullptr && "fdt_header_ is null");
313
314 auto offset = FindCompatibleNode("sifive,plic-1.0.0");
315 if (!offset.has_value()) {
316 offset = FindCompatibleNode("riscv,plic0");
317 }
318 if (!offset.has_value()) {
319 return std::unexpected(offset.error());
320 }
321
322 int len = 0;
323
324 const auto* prop = fdt_get_property(fdt_header_, offset.value(),
325 "interrupts-extended", &len);
326 if (prop == nullptr) {
327 return std::unexpected(Error(ErrorCode::kFdtPropertyNotFound));
328 }
329
330 uint32_t num_entries = len / sizeof(uint32_t);
331 uint32_t context_count = num_entries / 2;
332
333 prop = fdt_get_property(fdt_header_, offset.value(), "riscv,ndev", &len);
334 if (prop == nullptr) {
335 return std::unexpected(Error(ErrorCode::kFdtPropertyNotFound));
336 }
337 uint32_t ndev =
338 fdt32_to_cpu(*reinterpret_cast<const uint32_t*>(prop->data));
339
340 auto reg = GetRegProperty(offset.value());
341 if (!reg.has_value()) {
342 return std::unexpected(reg.error());
343 }
344
345 return std::tuple{reg.value().first, reg.value().second, ndev,
346 context_count};
347 }
348
364 template <typename Callback>
365 [[nodiscard]] auto ForEachNode(Callback&& callback) const -> Expected<void> {
366 assert(fdt_header_ != nullptr && "fdt_header_ is null");
367
368 int offset = -1;
369 int depth = 0;
370
371 while (true) {
372 offset = fdt_next_node(fdt_header_, offset, &depth);
373 if (offset < 0) {
374 if (offset == -FDT_ERR_NOTFOUND) {
375 break;
376 }
377 return std::unexpected(Error(ErrorCode::kFdtParseFailed));
378 }
379
380 const char* node_name = fdt_get_name(fdt_header_, offset, nullptr);
381 if (node_name == nullptr) {
382 continue;
383 }
384
385 int status_len = 0;
386 const auto* status_prop =
387 fdt_get_property(fdt_header_, offset, "status", &status_len);
388 if (status_prop != nullptr) {
389 const char* status = reinterpret_cast<const char*>(status_prop->data);
390 if (strcmp(status, "okay") != 0 && strcmp(status, "ok") != 0) {
391 continue;
392 }
393 }
394
395 const char* compatible_data = nullptr;
396 size_t compatible_len = 0;
397 int compat_len = 0;
398 const auto* compat_prop =
399 fdt_get_property(fdt_header_, offset, "compatible", &compat_len);
400 if (compat_prop != nullptr && compat_len > 0) {
401 compatible_data = reinterpret_cast<const char*>(compat_prop->data);
402 compatible_len = static_cast<size_t>(compat_len);
403 }
404
405 uint64_t mmio_base = 0;
406 size_t mmio_size = 0;
407 int reg_len = 0;
408 const auto* reg_prop =
409 fdt_get_property(fdt_header_, offset, "reg", &reg_len);
410 if (reg_prop != nullptr &&
411 static_cast<size_t>(reg_len) >= 2 * sizeof(uint64_t)) {
412 const auto* reg = reinterpret_cast<const uint64_t*>(reg_prop->data);
413 mmio_base = fdt64_to_cpu(reg[0]);
414 mmio_size = fdt64_to_cpu(reg[1]);
415 }
416
417 uint32_t irq = 0;
418 int irq_len = 0;
419 const auto* irq_prop =
420 fdt_get_property(fdt_header_, offset, "interrupts", &irq_len);
421 if (irq_prop != nullptr &&
422 static_cast<size_t>(irq_len) >= sizeof(uint32_t)) {
423 const auto* interrupts =
424 reinterpret_cast<const uint32_t*>(irq_prop->data);
425 irq = fdt32_to_cpu(interrupts[0]);
426 }
427
428 if (!callback(node_name, compatible_data, compatible_len, mmio_base,
429 mmio_size, irq)) {
430 break;
431 }
432 }
433
434 return {};
435 }
436
450 template <typename Callback>
451 [[nodiscard]] auto ForEachCompatibleNode(const char* compatible,
452 Callback&& callback) const
453 -> Expected<void> {
454 assert(fdt_header_ != nullptr && "fdt_header_ is null");
455
456 int offset = -1;
457 while (true) {
458 offset = fdt_node_offset_by_compatible(fdt_header_, offset, compatible);
459 if (offset < 0) {
460 if (offset == -FDT_ERR_NOTFOUND) {
461 break;
462 }
463 return std::unexpected(Error(ErrorCode::kFdtParseFailed));
464 }
465
466 const char* node_name = fdt_get_name(fdt_header_, offset, nullptr);
467 if (node_name == nullptr) {
468 continue;
469 }
470
471 uint64_t mmio_base = 0;
472 size_t mmio_size = 0;
473 int reg_len = 0;
474 const auto* reg_prop =
475 fdt_get_property(fdt_header_, offset, "reg", &reg_len);
476 if (reg_prop != nullptr &&
477 static_cast<size_t>(reg_len) >= 2 * sizeof(uint64_t)) {
478 const auto* reg = reinterpret_cast<const uint64_t*>(reg_prop->data);
479 mmio_base = fdt64_to_cpu(reg[0]);
480 mmio_size = fdt64_to_cpu(reg[1]);
481 }
482
483 uint32_t irq = 0;
484 int irq_len = 0;
485 const auto* irq_prop =
486 fdt_get_property(fdt_header_, offset, "interrupts", &irq_len);
487 if (irq_prop != nullptr &&
488 static_cast<size_t>(irq_len) >= sizeof(uint32_t)) {
489 const auto* interrupts =
490 reinterpret_cast<const uint32_t*>(irq_prop->data);
491 irq = fdt32_to_cpu(interrupts[0]);
492 }
493
494 if (!callback(offset, node_name, mmio_base, mmio_size, irq)) {
495 break;
496 }
497 }
498
499 return {};
500 }
501
518 template <typename Callback>
519 [[nodiscard]] auto ForEachDeviceNode(Callback&& callback) const
520 -> Expected<void> {
521 assert(fdt_header_ != nullptr && "ForEachDeviceNode: fdt_header_ is null");
522
523 int offset = -1;
524 int depth = 0;
525
526 while (true) {
527 offset = fdt_next_node(fdt_header_, offset, &depth);
528 if (offset < 0) {
529 if (offset == -FDT_ERR_NOTFOUND) {
530 break;
531 }
532 return std::unexpected(Error(ErrorCode::kFdtParseFailed));
533 }
534
535 const char* node_name = fdt_get_name(fdt_header_, offset, nullptr);
536 if (node_name == nullptr) {
537 continue;
538 }
539
540 // status 过滤(与 ForEachNode 相同)
541 int status_len = 0;
542 const auto* status_prop =
543 fdt_get_property(fdt_header_, offset, "status", &status_len);
544 if (status_prop != nullptr) {
545 const char* status = reinterpret_cast<const char*>(status_prop->data);
546 if (strcmp(status, "okay") != 0 && strcmp(status, "ok") != 0) {
547 continue;
548 }
549 }
550
551 // 基础设施节点过滤
552 if (fdt_getprop(fdt_header_, offset, "interrupt-controller", nullptr) !=
553 nullptr) {
554 continue;
555 }
556 if (fdt_getprop(fdt_header_, offset, "#clock-cells", nullptr) !=
557 nullptr) {
558 continue;
559 }
560 {
561 int dt_len = 0;
562 const auto* dt_prop =
563 fdt_get_property(fdt_header_, offset, "device_type", &dt_len);
564 if (dt_prop != nullptr) {
565 const char* dt = reinterpret_cast<const char*>(dt_prop->data);
566 if (strcmp(dt, "cpu") == 0 || strcmp(dt, "memory") == 0) {
567 continue;
568 }
569 }
570 }
571
572 // compatible 提取
573 const char* compatible_data = nullptr;
574 size_t compatible_len = 0;
575 int compat_len = 0;
576 const auto* compat_prop =
577 fdt_get_property(fdt_header_, offset, "compatible", &compat_len);
578 if (compat_prop != nullptr && compat_len > 0) {
579 compatible_data = reinterpret_cast<const char*>(compat_prop->data);
580 compatible_len = static_cast<size_t>(compat_len);
581 }
582
583 // reg 提取
584 uint64_t mmio_base = 0;
585 size_t mmio_size = 0;
586 int reg_len = 0;
587 const auto* reg_prop =
588 fdt_get_property(fdt_header_, offset, "reg", &reg_len);
589 if (reg_prop != nullptr &&
590 static_cast<size_t>(reg_len) >= 2 * sizeof(uint64_t)) {
591 const auto* reg = reinterpret_cast<const uint64_t*>(reg_prop->data);
592 mmio_base = fdt64_to_cpu(reg[0]);
593 mmio_size = fdt64_to_cpu(reg[1]);
594 }
595
596 // interrupts 提取
597 uint32_t irq = 0;
598 int irq_len = 0;
599 const auto* irq_prop =
600 fdt_get_property(fdt_header_, offset, "interrupts", &irq_len);
601 if (irq_prop != nullptr &&
602 static_cast<size_t>(irq_len) >= sizeof(uint32_t)) {
603 const auto* interrupts =
604 reinterpret_cast<const uint32_t*>(irq_prop->data);
605 irq = fdt32_to_cpu(interrupts[0]);
606 }
607
608 if (!callback(node_name, compatible_data, compatible_len, mmio_base,
609 mmio_size, irq)) {
610 break;
611 }
612 }
613
614 return {};
615 }
616
619
626 explicit KernelFdt(uint64_t header)
627 : fdt_header_(reinterpret_cast<fdt_header*>(header)) {
628 ValidateFdtHeader().or_else([](auto&& err) {
629 klog::Err("KernelFdt init failed: {}", err.message());
630 while (true) {
632 }
633 return Expected<void>{};
634 });
635
636 klog::Debug("Load dtb at [{:#X}], size [{:#X}]",
637 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(fdt_header_)),
638 static_cast<uint64_t>(fdt32_to_cpu(fdt_header_->totalsize)));
639 }
640
641 KernelFdt() = default;
642 KernelFdt(const KernelFdt&) = default;
643 KernelFdt(KernelFdt&&) = default;
644 auto operator=(const KernelFdt&) -> KernelFdt& = default;
645 auto operator=(KernelFdt&&) -> KernelFdt& = default;
646 ~KernelFdt() = default;
648
649 private:
651 fdt_header* fdt_header_{nullptr};
652
656 static constexpr uint64_t kPsciCpuOnFuncId = 0xC4000003;
657 static constexpr uint64_t kPsciCpuOffFuncId = 0x84000002;
658 static constexpr uint64_t kPsciCpuSuspendFuncId = 0xC4000001;
659
664 [[nodiscard]] auto ValidateFdtHeader() const -> Expected<void> {
665 assert(fdt_header_ != nullptr && "fdt_header_ is null");
666 if (fdt_check_header(fdt_header_) != 0) {
667 return std::unexpected(Error(ErrorCode::kFdtInvalidHeader));
668 }
669 return {};
670 }
671
677 [[nodiscard]] auto FindNode(const char* path) const -> Expected<int> {
678 auto offset = fdt_path_offset(fdt_header_, path);
679 if (offset < 0) {
680 return std::unexpected(Error(ErrorCode::kFdtNodeNotFound));
681 }
682 return offset;
683 }
684
690 [[nodiscard]] auto FindCompatibleNode(const char* compatible) const
691 -> Expected<int> {
692 auto offset = fdt_node_offset_by_compatible(fdt_header_, -1, compatible);
693 if (offset < 0) {
694 return std::unexpected(Error(ErrorCode::kFdtNodeNotFound));
695 }
696 return offset;
697 }
698
704 [[nodiscard]] auto FindEnabledCompatibleNode(const char* compatible) const
705 -> Expected<int> {
706 int offset = -1;
707 while (true) {
708 offset = fdt_node_offset_by_compatible(fdt_header_, offset, compatible);
709 if (offset < 0) {
710 return std::unexpected(Error(ErrorCode::kFdtNodeNotFound));
711 }
712
713 int len = 0;
714 const auto* status_prop =
715 fdt_get_property(fdt_header_, offset, "status", &len);
716
717 if (status_prop == nullptr) {
718 return offset;
719 }
720
721 const char* status = reinterpret_cast<const char*>(status_prop->data);
722 if (strcmp(status, "okay") == 0 || strcmp(status, "ok") == 0) {
723 return offset;
724 }
725 }
726 }
727
734 [[nodiscard]] auto GetRegProperty(int offset) const
736 int len = 0;
737 const auto* prop = fdt_get_property(fdt_header_, offset, "reg", &len);
738 if (prop == nullptr) {
739 return std::unexpected(Error(ErrorCode::kFdtPropertyNotFound));
740 }
741
742 const auto* reg = reinterpret_cast<const uint64_t*>(prop->data);
743 if (static_cast<size_t>(len) < 2 * sizeof(uint64_t)) {
744 return std::unexpected(Error(ErrorCode::kFdtInvalidPropertySize));
745 }
746
747 uint64_t base = fdt64_to_cpu(reg[0]);
748 size_t size = fdt64_to_cpu(reg[1]);
749 return std::pair{base, size};
750 }
751
757 [[nodiscard]] auto CountNodesByDeviceType(const char* device_type) const
759 size_t count = 0;
760 auto offset = -1;
761
762 while (true) {
763 offset = fdt_next_node(fdt_header_, offset, nullptr);
764 if (offset < 0) {
765 if (offset != -FDT_ERR_NOTFOUND) {
766 return std::unexpected(Error(ErrorCode::kFdtParseFailed));
767 }
768 break;
769 }
770
771 const auto* prop =
772 fdt_get_property(fdt_header_, offset, "device_type", nullptr);
773 if (prop != nullptr) {
774 const char* type = reinterpret_cast<const char*>(prop->data);
775 if (strcmp(type, device_type) == 0) {
776 ++count;
777 }
778 }
779 }
780
781 return count;
782 }
783
789 [[nodiscard]] auto GetPsciMethod(int offset) const -> Expected<const char*> {
790 int len = 0;
791 const auto* prop = fdt_get_property(fdt_header_, offset, "method", &len);
792 if (prop == nullptr) {
793 return std::unexpected(Error(ErrorCode::kFdtPropertyNotFound));
794 }
795 return reinterpret_cast<const char*>(prop->data);
796 }
797
803 [[nodiscard]] auto ValidatePsciFunctionIds(int offset) const
804 -> Expected<void> {
805 auto validate_id = [this, offset](const char* name,
806 uint64_t expected) -> Expected<void> {
807 int len = 0;
808 const auto* prop = fdt_get_property(fdt_header_, offset, name, &len);
809 if (prop != nullptr && static_cast<size_t>(len) >= sizeof(uint32_t)) {
810 uint32_t id =
811 fdt32_to_cpu(*reinterpret_cast<const uint32_t*>(prop->data));
812 klog::Debug("PSCI {} function ID: {:#X}", name, id);
813 if (id != expected) {
814 klog::Err("PSCI {} function ID mismatch: expected {:#X}, got {:#X}",
815 name, expected, id);
816 return std::unexpected(Error(ErrorCode::kFdtPropertyNotFound));
817 }
818 }
819 return {};
820 };
821
822 return validate_id("cpu_on", kPsciCpuOnFuncId)
823 .and_then([&]() { return validate_id("cpu_off", kPsciCpuOffFuncId); })
824 .and_then([&]() {
825 return validate_id("cpu_suspend", kPsciCpuSuspendFuncId);
826 });
827 }
828};
829
830using KernelFdtSingleton = etl::singleton<KernelFdt>;
FDT(Flattened Device Tree)解析器
auto GetGicDist() const -> Expected< std::pair< uint64_t, size_t > >
获取 GIC Distributor 信息
auto ForEachDeviceNode(Callback &&callback) const -> Expected< void >
遍历 FDT 中所有"叶设备"节点,自动跳过基础设施节点。
auto GetTimebaseFrequency() const -> Expected< uint32_t >
获取 CPU 时钟频率
static constexpr uint64_t kPsciCpuOnFuncId
auto operator=(KernelFdt &&) -> KernelFdt &=default
auto GetRegProperty(int offset) const -> Expected< std::pair< uint64_t, size_t > >
获取 reg 属性(返回第一个 reg 条目)
KernelFdt(uint64_t header)
构造函数
auto GetGicCpu() const -> Expected< std::pair< uint64_t, size_t > >
获取 GIC CPU Interface (Redistributor) 信息
auto CountNodesByDeviceType(const char *device_type) const -> Expected< size_t >
按 device_type 统计节点数量
auto FindNode(const char *path) const -> Expected< int >
按路径查找节点
auto GetAarch64Intid(const char *compatible) const -> Expected< uint64_t >
获取 aarch64 中断号
auto GetPlic() const -> Expected< std::tuple< uint64_t, uint64_t, uint32_t, uint32_t > >
获取 PLIC 信息
KernelFdt(const KernelFdt &)=default
auto FindCompatibleNode(const char *compatible) const -> Expected< int >
按 compatible 查找第一个匹配的节点
static constexpr uint64_t kPsciCpuOffFuncId
auto GetGIC() const -> Expected< std::tuple< uint64_t, size_t, uint64_t, size_t > >
获取 GIC 信息
static constexpr uint64_t kPsciCpuSuspendFuncId
auto GetPsciMethod(int offset) const -> Expected< const char * >
获取 PSCI method 属性
auto ValidateFdtHeader() const -> Expected< void >
验证 FDT header
auto GetCoreCount() const -> Expected< size_t >
获取 CPU 核心数量
KernelFdt(KernelFdt &&)=default
~KernelFdt()=default
auto FindEnabledCompatibleNode(const char *compatible) const -> Expected< int >
根据 compatible 查找已启用的节点(跳过 status="disabled")
auto GetSerial() const -> Expected< std::tuple< uint64_t, size_t, uint32_t > >
获取串口信息
auto ForEachCompatibleNode(const char *compatible, Callback &&callback) const -> Expected< void >
遍历所有匹配指定 compatible 的 FDT 节点
auto operator=(const KernelFdt &) -> KernelFdt &=default
KernelFdt()=default
auto ForEachNode(Callback &&callback) const -> Expected< void >
遍历 FDT 中所有设备节点
fdt_header * fdt_header_
FDT header 指针
auto GetMemory() const -> Expected< std::pair< uint64_t, size_t > >
获取内存信息
auto ValidatePsciFunctionIds(int offset) const -> Expected< void >
验证 PSCI 函数 ID
auto CheckPSCI() const -> Expected< void >
判断 PSCI 信息
@ kFdtPropertyNotFound
@ kFdtInvalidPropertySize
@ kFdtNodeNotFound
@ kFdtInvalidHeader
std::expected< T, Error > Expected
std::expected 别名模板
Definition expected.hpp:365
etl::singleton< KernelFdt > KernelFdtSingleton
void Pause()
Definition cpu_io.h:20
auto Err(etl::format_string< Args... > fmt, Args &&... args) -> void
以 ERROR 级别记录日志
auto Debug(etl::format_string< Args... > fmt, Args &&... args) -> void
以 DEBUG 级别记录日志(SIMPLEKERNEL_MIN_LOG_LEVEL > 0 时编译期消除)
#define strcmp
#define strchr
错误类型,用于 std::expected
Definition expected.hpp:343