diff options
Diffstat (limited to 'docs/specs/fdt.md')
| -rw-r--r-- | docs/specs/fdt.md | 191 |
1 files changed, 0 insertions, 191 deletions
diff --git a/docs/specs/fdt.md b/docs/specs/fdt.md deleted file mode 100644 index 2a1d542..0000000 --- a/docs/specs/fdt.md +++ /dev/null @@ -1,191 +0,0 @@ -# 设备树 (Flattened Device Tree) - -## 1. 目标 (Objective) - -为 LumeOS 提供一套标准的硬件发现与配置机制,彻底摆脱硬编码的物理地址。本模块负责解析由 Bootloader 传入的 FDT 二进制数据,并分两个阶段将其转化为内核可用的数据结构: - -1. **早期扫描 (Early Scan):** 在内存管理(PMM)初始化之前,以只读、无分配的方式扫描 FDT,提取启动所必需的核心信息(如物理内存布局)。 -2. **对象化展开 (Unflattening):** 在内存管理(PMM/Slab)就绪后,将完整的 FDT 解析为一个常驻内存的 C++ `DeviceNode` 对象树,为后续的驱动探测(Driver Probing)提供面向对象的接口。 - -## 2. 前置依赖 (Dependencies) - -- **引导协议契约 (`linker_and_entry.md`):** 依赖 Bootloader 在跳转至内核时,将 FDT 的物理基址置于 `a1` 寄存器。 -- **全局初始化契约 (`global_init.md`):** `fdt_init()` 在 `console_init()` 之后、`pmm_init()` 之前被 BSP 调用。`pmm_init()` 自身会回调 FDT 的早期扫描接口。 -- **内存管理契约 (`pmm.md`, `slab.md`):** 对象化展开阶段依赖 Slab 分配器(`operator new`)来动态创建 `DeviceNode` 对象。 -- **项目约定 (`00_conventions.md`):** 遵循所有命名、错误处理和 API 设计规范。 - -## 3. 核心数据结构 (Data Structures) - -### 3.1 FDT 属性 (`struct FdtProperty`) - -表示设备节点中的一个属性(如 `reg`, `compatible`)。 - -```cpp -// 定义于 include/lume/fdt_prop.h -struct FdtProperty { - const char* name; // 属性名 - const void* value; // 指向 FDT blob 中原始数据的指针 - int len; // 数据长度(字节) - list_node link; // 链接到下一个属性 -}; -``` - -### 3.2 设备节点 (`class DeviceNode`) - -FDT 对象树的核心,代表一个硬件设备或总线。 - -```cpp -// 定义于 include/lume/device_node.h -class DeviceNode { -public: - // 构造/析构 - DeviceNode(DeviceNode* parent, const char* name); - ~DeviceNode(); - - // 属性访问 - const FdtProperty* get_prop(const char* name) const; - uint32_t get_prop_u32(const char* name, uint32_t default_val = 0) const; - uint64 get_prop_u64(const char* name, uint64 default_val = 0) const; - const char* get_prop_string(const char* name) const; - - // 子节点遍历 - DeviceNode* find_child(const char* name); - void for_each_child(void (*callback)(DeviceNode*)); - - // 内部接口,供 FdtManager 构建树时使用 - void add_child(DeviceNode* child); - void add_prop(FdtProperty* prop); - -private: - const char* name_; - DeviceNode* parent_; - list_node children_list_; // list_head of children - list_node props_list_; // list_head of properties - list_node sibling_link_; // link in parent's children_list_ -}; -``` - -### 3.3 FDT 管理器 (`class FdtManager`) - -全局单例,负责 FDT 的解析与查询。 - -```cpp -// 定义于 include/lume/fdt.h -class FdtManager { -public: - // 由 fdt_init() 通过 Placement New 调用 - FdtManager(uint64 fdt_paddr); - - // 阶段二:对象化展开 - void unflatten(); - - // 驱动探测接口 - DeviceNode* find_compatible(const char* compat_string); - DeviceNode* get_node_by_path(const char* path); - - // 阶段一:早期扫描接口 (静态,无状态) - static void early_scan_mem(uint64 fdt_paddr, uint64* base, uint64* size); - static void early_scan_uart(uint64 fdt_paddr, uint64* uart_addr); - -private: - uint64 fdt_paddr_; - DeviceNode* root_ = nullptr; - bool is_unflattened_ = false; -}; - -// 全局 FDT 管理器实例指针 -extern FdtManager* g_fdt; -``` - -## 4. 公共 API (Public APIs) - -```cpp -// === 初始化 API (由 kernel_main 调用) === - -// 阶段一和阶段二的入口。仅保存 FDT 地址,真正的解析被推迟。 -void fdt_init(uint64 fdt_paddr); - -// 在 Slab 就绪后调用,执行对象化展开。 -void fdt_unflatten(); - - -// === 驱动探测 API (供各驱动 init 函数调用) === - -// 根据 "compatible" 字符串查找第一个匹配的设备节点。 -// 返回值:成功则为 DeviceNode 指针,失败为 nullptr。 -DeviceNode* fdt_find_compatible(const char* compat_string); - -// 根据完整路径查找设备节点。 -DeviceNode* fdt_get_node_by_path(const char* path); - - -// === 早期扫描 API (供 PMM 和早期控制台调用) === - -// 扫描 FDT blob 获取 /memory 节点的 base 和 size。 -// 失败则 panic。 -void fdt_early_get_mem_info(uint64* base, uint64* size); - -// 扫描 FDT blob 获取 /chosen/stdout-path 对应的 UART 物理地址。 -void fdt_early_get_uart_info(uint64* uart_addr); -``` - -## 5. 并发与锁契约 (Concurrency & Locks) - -- **无锁设计:** FDT 的所有初始化和解析操作(`fdt_init`, `fdt_unflatten`)均由 BSP 在多核启动前的**绝对单核期**完成。 - -- **只读安全:** 一旦 `fdt_unflatten()` 完成,`DeviceNode` 对象树即被视为**全局只读**数据。任何 CPU 都可以随时无锁访问它进行驱动探测和属性查询。 - -- **禁止修改:** 任何模块在初始化之后都**不得**修改 `DeviceNode` 树的内容。 - -## 6. 错误路径 (Error Paths) - -- **FDT 损坏:** 在 `fdt_init()` 或 `fdt_unflatten()` 中,如果检测到 FDT 的 magic number 无效或结构损坏,必须立即调用 `kernel_panic()`。 - -- **关键节点缺失:** `fdt_early_get_mem_info()` 如果找不到 `/memory` 节点,说明无法确定物理内存大小,属于致命错误,必须 `kernel_panic()`。 - -- **内存分配失败:** `fdt_unflatten()` 在使用 `new` 创建 `DeviceNode` 时如果 Slab 返回 `nullptr`,说明内存耗尽,必须 `kernel_panic()`。 - -- **查询失败:** `fdt_find_compatible()` 或 `fdt_get_node_by_path()` 在未找到匹配节点时,安全地返回 `nullptr`。调用方(驱动)负责处理此情况(通常意味着该硬件不存在,驱动不进行初始化)。 - -## 7. 状态机 / 时序图 (State Machine / Sequence) - -### FDT 二阶段解析时序 - -``` -[entry.S] -> a1 = fdt_paddr - │ - ▼ -[kernel_main on BSP] - │ - ├─> 1. fdt_init(fdt_paddr) - │ └─ g_fdt = new FdtManager(fdt_paddr); // Placement New - │ (仅保存地址,不进行任何解析) - │ - ├─> 2. pmm_init() - │ └─ fdt_early_get_mem_info(&base, &size); - │ └─ FdtManager::early_scan_mem(fdt_paddr, ...); - │ ├─ 遍历原始 FDT blob (无内存分配) - │ ├─ 找到 /memory 节点 - │ └─ 返回 reg 属性值 - │ - ├─> 3. slab_init() - │ └─ operator new 可用 - │ - ├─> 4. (稍后) fdt_unflatten() - │ └─ g_fdt->unflatten(); - │ ├─ 再次遍历原始 FDT blob - │ ├─ for each node: new DeviceNode(...) - │ ├─ for each prop: new FdtProperty(...) - │ └─ 构建完整的 C++ 对象树 - │ - ▼ -[驱动初始化阶段, e.g., plic_init()] - │ - ├─> node = fdt_find_compatible("riscv,plic0"); - │ └─ g_fdt->find_compatible(...); - │ └─ 遍历已构建的 DeviceNode C++ 对象树 (只读, 无锁) - │ - ├─> reg_prop = node->get_prop("reg"); - │ - └─> (使用 reg_prop->value 初始化 PLIC 驱动) -```
\ No newline at end of file |
