SimpleKernel 1.17.0
Loading...
Searching...
No Matches
KernelFdt Class Reference

FDT(Flattened Device Tree)解析器 More...

#include <kernel_fdt.hpp>

Collaboration diagram for KernelFdt:
Collaboration graph

Public Member Functions

auto GetCoreCount () const -> Expected< size_t >
 获取 CPU 核心数量
 
auto CheckPSCI () const -> Expected< void >
 判断 PSCI 信息
 
auto GetMemory () const -> Expected< std::pair< uint64_t, size_t > >
 获取内存信息
 
auto GetSerial () const -> Expected< std::tuple< uint64_t, size_t, uint32_t > >
 获取串口信息
 
auto GetTimebaseFrequency () const -> Expected< uint32_t >
 获取 CPU 时钟频率
 
auto GetGIC () const -> Expected< std::tuple< uint64_t, size_t, uint64_t, size_t > >
 获取 GIC 信息
 
auto GetGicDist () const -> Expected< std::pair< uint64_t, size_t > >
 获取 GIC Distributor 信息
 
auto GetGicCpu () const -> Expected< std::pair< uint64_t, size_t > >
 获取 GIC CPU Interface (Redistributor) 信息
 
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 信息
 
template<typename Callback >
auto ForEachNode (Callback &&callback) const -> Expected< void >
 遍历 FDT 中所有设备节点
 
template<typename Callback >
auto ForEachCompatibleNode (const char *compatible, Callback &&callback) const -> Expected< void >
 遍历所有匹配指定 compatible 的 FDT 节点
 
template<typename Callback >
auto ForEachDeviceNode (Callback &&callback) const -> Expected< void >
 遍历 FDT 中所有"叶设备"节点,自动跳过基础设施节点。
 
构造/析构函数
 KernelFdt (uint64_t header)
 构造函数
 
 KernelFdt ()=default
 
 KernelFdt (const KernelFdt &)=default
 
 KernelFdt (KernelFdt &&)=default
 
auto operator= (const KernelFdt &) -> KernelFdt &=default
 
auto operator= (KernelFdt &&) -> KernelFdt &=default
 
 ~KernelFdt ()=default
 

Private Member Functions

auto ValidateFdtHeader () const -> Expected< void >
 验证 FDT header
 
auto FindNode (const char *path) const -> Expected< int >
 按路径查找节点
 
auto FindCompatibleNode (const char *compatible) const -> Expected< int >
 按 compatible 查找第一个匹配的节点
 
auto FindEnabledCompatibleNode (const char *compatible) const -> Expected< int >
 根据 compatible 查找已启用的节点(跳过 status="disabled")
 
auto GetRegProperty (int offset) const -> Expected< std::pair< uint64_t, size_t > >
 获取 reg 属性(返回第一个 reg 条目)
 
auto CountNodesByDeviceType (const char *device_type) const -> Expected< size_t >
 按 device_type 统计节点数量
 
auto GetPsciMethod (int offset) const -> Expected< const char * >
 获取 PSCI method 属性
 
auto ValidatePsciFunctionIds (int offset) const -> Expected< void >
 验证 PSCI 函数 ID
 

Private Attributes

fdt_header * fdt_header_ {nullptr}
 FDT header 指针
 

Static Private Attributes

static constexpr uint64_t kPsciCpuOnFuncId = 0xC4000003
 
static constexpr uint64_t kPsciCpuOffFuncId = 0x84000002
 
static constexpr uint64_t kPsciCpuSuspendFuncId = 0xC4000001
 

Detailed Description

FDT(Flattened Device Tree)解析器

提供对 FDT 的解析功能,包括节点查找、属性读取、设备枚举等。

Precondition
FDT 数据必须是有效的 DTB 格式
Postcondition
通过各 Get* 方法可获取设备树中的硬件信息
Note
ForEachNode、ForEachCompatibleNode 和 ForEachDeviceNode 是模板方法,保留在头文件中
compatible 属性是 stringlist 格式(多个以 '\0' 分隔的字符串), 回调接收完整的 compatible 数据和长度

Definition at line 47 of file kernel_fdt.hpp.

Constructor & Destructor Documentation

◆ KernelFdt() [1/4]

KernelFdt::KernelFdt ( uint64_t  header)
inlineexplicit

构造函数

Parameters
headerfdt 数据地址
Precondition
header 指向有效的 DTB 数据
Postcondition
fdt_header_ 已初始化并通过校验

Definition at line 626 of file kernel_fdt.hpp.

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 }
auto ValidateFdtHeader() const -> Expected< void >
验证 FDT header
fdt_header * fdt_header_
FDT header 指针
std::expected< T, Error > Expected
std::expected 别名模板
Definition expected.hpp:365
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 时编译期消除)
Here is the call graph for this function:

◆ KernelFdt() [2/4]

KernelFdt::KernelFdt ( )
default

◆ KernelFdt() [3/4]

KernelFdt::KernelFdt ( const KernelFdt )
default

◆ KernelFdt() [4/4]

KernelFdt::KernelFdt ( KernelFdt &&  )
default

◆ ~KernelFdt()

KernelFdt::~KernelFdt ( )
default

Member Function Documentation

◆ CheckPSCI()

auto KernelFdt::CheckPSCI ( ) const -> Expected<void>
inline

判断 PSCI 信息

Returns
Expected<void> 成功返回空,失败返回错误
Precondition
fdt_header_ 不为空

Definition at line 71 of file kernel_fdt.hpp.

71 {
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 }
auto FindNode(const char *path) const -> Expected< int >
按路径查找节点
auto GetPsciMethod(int offset) const -> Expected< const char * >
获取 PSCI method 属性
auto ValidatePsciFunctionIds(int offset) const -> Expected< void >
验证 PSCI 函数 ID
@ kFdtPropertyNotFound
#define strcmp
错误类型,用于 std::expected
Definition expected.hpp:343
Here is the call graph for this function:

◆ CountNodesByDeviceType()

auto KernelFdt::CountNodesByDeviceType ( const char *  device_type) const -> Expected<size_t>
inlineprivate

按 device_type 统计节点数量

Parameters
device_type设备类型
Returns
Expected<size_t> 节点数量

Definition at line 757 of file kernel_fdt.hpp.

758 {
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 }
Here is the caller graph for this function:

◆ FindCompatibleNode()

auto KernelFdt::FindCompatibleNode ( const char *  compatible) const -> Expected<int>
inlineprivate

按 compatible 查找第一个匹配的节点

Parameters
compatible要查找的 compatible 字符串
Returns
Expected<int> 节点偏移量

Definition at line 690 of file kernel_fdt.hpp.

691 {
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 }
@ kFdtNodeNotFound
Here is the caller graph for this function:

◆ FindEnabledCompatibleNode()

auto KernelFdt::FindEnabledCompatibleNode ( const char *  compatible) const -> Expected<int>
inlineprivate

根据 compatible 查找已启用的节点(跳过 status="disabled")

Parameters
compatible要查找的 compatible 字符串
Returns
Expected<int> 节点偏移量

Definition at line 704 of file kernel_fdt.hpp.

705 {
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 }
Here is the caller graph for this function:

◆ FindNode()

auto KernelFdt::FindNode ( const char *  path) const -> Expected<int>
inlineprivate

按路径查找节点

Parameters
path节点路径(如 "/memory")
Returns
Expected<int> 节点偏移量

Definition at line 677 of file kernel_fdt.hpp.

677 {
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 }
Here is the caller graph for this function:

◆ ForEachCompatibleNode()

template<typename Callback >
auto KernelFdt::ForEachCompatibleNode ( const char *  compatible,
Callback &&  callback 
) const -> Expected<void>
inline

遍历所有匹配指定 compatible 的 FDT 节点

Template Parameters
Callback回调类型,签名: bool(int offset, const char* node_name, uint64_t mmio_base, size_t mmio_size, uint32_t irq) 返回 true 继续遍历,false 停止
Parameters
compatible要匹配的 compatible 字符串
callback节点处理函数
Returns
Expected<void>
Precondition
fdt_header_ 不为空
Note
使用 fdt_node_offset_by_compatible 的迭代模式, 可正确处理多个节点共享相同 compatible 的情况

Definition at line 451 of file kernel_fdt.hpp.

453 {
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 }
Here is the caller graph for this function:

◆ ForEachDeviceNode()

template<typename Callback >
auto KernelFdt::ForEachDeviceNode ( Callback &&  callback) const -> Expected<void>
inline

遍历 FDT 中所有"叶设备"节点,自动跳过基础设施节点。

在 ForEachNode 的基础上,额外过滤掉以下节点:

  • 具有 interrupt-controller 属性(中断控制器)
  • 具有 #clock-cells 属性(时钟提供者)
  • device_type = "cpu"device_type = "memory"
Template Parameters
Callback签名与 ForEachNode 完全相同: bool(const char* node_name, const char* compatible_data, size_t compatible_len, uint64_t mmio_base, size_t mmio_size, uint32_t irq)
Parameters
callback节点处理函数,返回 false 停止遍历
Returns
Expected<void>
Precondition
fdt_header_ 不为空

Definition at line 519 of file kernel_fdt.hpp.

520 {
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 }
Here is the caller graph for this function:

◆ ForEachNode()

template<typename Callback >
auto KernelFdt::ForEachNode ( Callback &&  callback) const -> Expected<void>
inline

遍历 FDT 中所有设备节点

Template Parameters
Callback回调类型,签名: bool(const char* node_name, const char* compatible_data, size_t compatible_len, uint64_t mmio_base, size_t mmio_size, uint32_t irq) 返回 true 继续遍历,false 停止
Parameters
callback节点处理函数
Returns
Expected<void>
Precondition
fdt_header_ 不为空
Note
compatible_data 是完整的 stringlist(多个字符串以 '\0' 分隔), compatible_len 是整个 stringlist 的字节长度。 若需要显示第一个 compatible 字符串,直接使用 compatible_data 即可。 若需要遍历所有 compatible 字符串,需按 '\0' 分隔迭代。

Definition at line 365 of file kernel_fdt.hpp.

365 {
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 }
Here is the caller graph for this function:

◆ GetAarch64Intid()

auto KernelFdt::GetAarch64Intid ( const char *  compatible) const -> Expected<uint64_t>
inline

获取 aarch64 中断号

Parameters
compatible要查找的 compatible 字符串
Returns
Expected<uint64_t> intid
Precondition
fdt_header_ 不为空

Definition at line 262 of file kernel_fdt.hpp.

263 {
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 }
auto FindEnabledCompatibleNode(const char *compatible) const -> Expected< int >
根据 compatible 查找已启用的节点(跳过 status="disabled")
Here is the call graph for this function:

◆ GetCoreCount()

auto KernelFdt::GetCoreCount ( ) const -> Expected<size_t>
inline

获取 CPU 核心数量

Returns
Expected<size_t> 成功返回核心数,失败返回错误
Precondition
fdt_header_ 不为空

Definition at line 54 of file kernel_fdt.hpp.

54 {
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 }
auto CountNodesByDeviceType(const char *device_type) const -> Expected< size_t >
按 device_type 统计节点数量
Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetGIC()

auto KernelFdt::GetGIC ( ) const -> Expected<std::tuple<uint64_t, size_t, uint64_t, size_t>>
inline

获取 GIC 信息

Returns
Expected<std::tuple<...>> <dist地址,dist大小,redist地址,redist大小>
Precondition
fdt_header_ 不为空

Definition at line 198 of file kernel_fdt.hpp.

199 {
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 }
auto FindCompatibleNode(const char *compatible) const -> Expected< int >
按 compatible 查找第一个匹配的节点
Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetGicCpu()

auto KernelFdt::GetGicCpu ( ) const -> Expected<std::pair<uint64_t, size_t>>
inline

获取 GIC CPU Interface (Redistributor) 信息

Returns
Expected<std::pair<uint64_t, size_t>>

Definition at line 248 of file kernel_fdt.hpp.

249 {
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 }
auto GetGIC() const -> Expected< std::tuple< uint64_t, size_t, uint64_t, size_t > >
获取 GIC 信息
Here is the call graph for this function:

◆ GetGicDist()

auto KernelFdt::GetGicDist ( ) const -> Expected<std::pair<uint64_t, size_t>>
inline

获取 GIC Distributor 信息

Returns
Expected<std::pair<uint64_t, size_t>>

Definition at line 236 of file kernel_fdt.hpp.

237 {
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 }
Here is the call graph for this function:

◆ GetMemory()

auto KernelFdt::GetMemory ( ) const -> Expected<std::pair<uint64_t, size_t>>
inline

获取内存信息

Returns
Expected<std::pair<uint64_t, size_t>> 内存信息<地址,长度>
Precondition
fdt_header_ 不为空
Postcondition
返回第一个 reg 条目的 base 和 size

Definition at line 92 of file kernel_fdt.hpp.

93 {
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 }
auto GetRegProperty(int offset) const -> Expected< std::pair< uint64_t, size_t > >
获取 reg 属性(返回第一个 reg 条目)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetPlic()

auto KernelFdt::GetPlic ( ) const -> Expected<std::tuple<uint64_t, uint64_t, uint32_t, uint32_t>>
inline

获取 PLIC 信息

Returns
Expected<std::tuple<...>> <地址,长度,中断源数量,上下文数量>
Precondition
fdt_header_ 不为空
See also
https://github.com/qemu/qemu/blob/master/hw/arm/virt.c

Definition at line 310 of file kernel_fdt.hpp.

311 {
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 }
Here is the call graph for this function:

◆ GetPsciMethod()

auto KernelFdt::GetPsciMethod ( int  offset) const -> Expected<const char*>
inlineprivate

获取 PSCI method 属性

Parameters
offset节点偏移
Returns
Expected<const char*> method 字符串

Definition at line 789 of file kernel_fdt.hpp.

789 {
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 }
Here is the caller graph for this function:

◆ GetRegProperty()

auto KernelFdt::GetRegProperty ( int  offset) const -> Expected<std::pair<uint64_t, size_t>>
inlineprivate

获取 reg 属性(返回第一个 reg 条目)

Parameters
offset节点偏移量
Returns
Expected<std::pair<uint64_t, size_t>> base 和 size
Postcondition
返回第一个 <base, size> 对,而非最后一个

Definition at line 734 of file kernel_fdt.hpp.

735 {
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 }
@ kFdtInvalidPropertySize
Here is the caller graph for this function:

◆ GetSerial()

auto KernelFdt::GetSerial ( ) const -> Expected<std::tuple<uint64_t, size_t, uint32_t>>
inline

获取串口信息

Returns
Expected<std::tuple<uint64_t, size_t, uint32_t>> <地址,长度,中断号>
Precondition
fdt_header_ 不为空

Definition at line 109 of file kernel_fdt.hpp.

110 {
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 }
#define strchr
Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetTimebaseFrequency()

auto KernelFdt::GetTimebaseFrequency ( ) const -> Expected<uint32_t>
inline

获取 CPU 时钟频率

Returns
Expected<uint32_t> 时钟频率
Precondition
fdt_header_ 不为空

Definition at line 173 of file kernel_fdt.hpp.

173 {
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 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ operator=() [1/2]

auto KernelFdt::operator= ( const KernelFdt ) -> KernelFdt &=default
default

◆ operator=() [2/2]

auto KernelFdt::operator= ( KernelFdt &&  ) -> KernelFdt &=default
default

◆ ValidateFdtHeader()

auto KernelFdt::ValidateFdtHeader ( ) const -> Expected<void>
inlineprivate

验证 FDT header

Returns
Expected<void>

Definition at line 664 of file kernel_fdt.hpp.

664 {
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 }
@ kFdtInvalidHeader
Here is the caller graph for this function:

◆ ValidatePsciFunctionIds()

auto KernelFdt::ValidatePsciFunctionIds ( int  offset) const -> Expected<void>
inlineprivate

验证 PSCI 函数 ID

Parameters
offset节点偏移
Returns
Expected<void> 验证结果

Definition at line 803 of file kernel_fdt.hpp.

804 {
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 }
static constexpr uint64_t kPsciCpuOnFuncId
static constexpr uint64_t kPsciCpuOffFuncId
static constexpr uint64_t kPsciCpuSuspendFuncId
Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ fdt_header_

fdt_header* KernelFdt::fdt_header_ {nullptr}
private

FDT header 指针

Definition at line 651 of file kernel_fdt.hpp.

651{nullptr};

◆ kPsciCpuOffFuncId

constexpr uint64_t KernelFdt::kPsciCpuOffFuncId = 0x84000002
staticconstexprprivate

Definition at line 657 of file kernel_fdt.hpp.

◆ kPsciCpuOnFuncId

constexpr uint64_t KernelFdt::kPsciCpuOnFuncId = 0xC4000003
staticconstexprprivate

PSCI 标准函数 ID(SMC64 调用约定)

See also
https://developer.arm.com/documentation/den0022/fb/?lang=en
Note
高位 0xC4 表示 SMC64 快速调用,0x84 表示 SMC32 快速调用

Definition at line 656 of file kernel_fdt.hpp.

◆ kPsciCpuSuspendFuncId

constexpr uint64_t KernelFdt::kPsciCpuSuspendFuncId = 0xC4000001
staticconstexprprivate

Definition at line 658 of file kernel_fdt.hpp.


The documentation for this class was generated from the following file: