* @brief 获取 PLIC 信息 * @return Expected > * <地址,长度,中断源数量,上下文数量> * @pre fdt_header_ 不为空 * @see https://github.com/qemu/qemu/blob/master/hw/arm/virt.c */
| 308 | * @see https://github.com/qemu/qemu/blob/master/hw/arm/virt.c |
| 309 | */ |
| 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 | |
| 349 | /** |
| 350 | * @brief 遍历 FDT 中所有设备节点 |