summaryrefslogtreecommitdiff
path: root/docs/specs/linker_and_entry.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/specs/linker_and_entry.md')
-rw-r--r--docs/specs/linker_and_entry.md208
1 files changed, 0 insertions, 208 deletions
diff --git a/docs/specs/linker_and_entry.md b/docs/specs/linker_and_entry.md
deleted file mode 100644
index a59d28d..0000000
--- a/docs/specs/linker_and_entry.md
+++ /dev/null
@@ -1,208 +0,0 @@
-# 链接器与引导入口 (Linker & Entry)
-
-## 1. 目标 (Objective)
-
-定义 LumeOS 在 RISC-V 64 架构上的早期内存布局与汇编启动序列。负责兼容多种 Bootloader(OpenSBI、GRUB、U-Boot),建立高半区内核(Higher-Half Kernel)映射,初始化早期 C++ 运行环境(BSS、GP 寄存器、全局构造函数),并安全地将各个 CPU 同步导入虚拟地址空间的 `kernel_main`。
-
-## 2. 前置依赖 (Dependencies)
-
-- **引导协议契约 (Boot Protocol):** 为了同时支持 OpenSBI(直接跳转偏移 0)和 GRUB/U-Boot(解析元数据后引导),LumeOS 采用 **RISC-V Linux Boot Protocol**。内核文件起始处必须包含标准的 64 字节 Image Header。
-
-- **寄存器传参契约:** 无论哪种引导器,在跳转至内核执行的第一条指令时,必须保证 `a0` = 当前 CPU ID (Hart ID),`a1` = FDT (Device Tree) 的物理基址。
-
-- **编译模型契约:** 内核必须使用 `-mcmodel=medany` 编译,以支持基于 PC 的相对寻址,确保在 MMU 开启前后代码均能正确执行。
-
-- **硬件 MMU 契约:** 目标硬件必须支持 RISC-V SV39 分页模式。
-
-
-## 3. 核心数据结构与内存布局 (Data Structures & Memory Map)
-
-### 3.1 虚拟与物理地址基址
-
-- **物理加载基址 (Physical Base):** `0x80200000` (跳过低地址的 OpenSBI 固件区,对齐 2MB 以支持大页映射)。
-
-- **内核虚拟基址 (Virtual Base):** `0xFFFFFFC080200000` (SV39 地址空间顶部,硬编码偏移量 `PAGE_OFFSET = 0xFFFFFFC000000000`)。
-
-- **虚拟-物理偏移常量:** `KERNEL_VA_OFFSET = 0xFFFFFFC000000000`,用于虚拟/物理地址互转:`VA = PA + KERNEL_VA_OFFSET`,`PA = VA - KERNEL_VA_OFFSET`。
-
-
-### 3.2 链接脚本段分布 (`linker.ld`)
-
-必须在所有代码之前放置 `.head.text` 段,以确保 Image Header 绝对位于二进制文件的第 0 字节处。所有段强制 4KB 对齐:
-
-```
-+-----------------------+ 0xFFFFFFC080200000 (Virtual) / 0x80200000 (Physical)
-| .head.text (镜像头) | -> 严格位于内核入口 0 字节处,包含 Linux Boot Header
-+-----------------------+
-| .text (执行代码) | -> ALIGN(4096), 权限: RX
-+-----------------------+
-| .rodata (只读数据) | -> ALIGN(4096), 权限: R-
-| (含 __init_array) | -> 全局构造函数指针表
-+-----------------------+
-| .data (已初始化数据) | -> ALIGN(4096), 权限: RW
-| (含 __global_pointer$)| -> 位于 .sdata 附近,用于优化全局变量访问
-| (含 early_pgdir) | -> 4KB 静态早期页表
-+-----------------------+
-| .bss (未初始化数据) | -> ALIGN(4096), 权限: RW
-+-----------------------+
-| boot_stack (早期栈) | -> ALIGN(4096), 为每个 CPU 预留 8KB 栈空间
-+-----------------------+
-```
-
-**链接脚本必须导出的符号:**
-
-| 符号名 | 含义 |
-|--------|------|
-| `_start` | 内核入口点(Image Header 首字节) |
-| `_stext` / `_etext` | .text 段边界 |
-| `_srodata` / `_erodata` | .rodata 段边界 |
-| `_sdata` / `_edata` | .data 段边界 |
-| `_sbss` / `_ebss` | .bss 段边界(用于启动清零) |
-| `__global_pointer$` | GP 寄存器锚点 |
-| `__init_array_start` / `__init_array_end` | C++ 全局构造函数表边界 |
-| `_kernel_end` | 内核镜像结束地址(PMM 初始化起点) |
-
-### 3.3 早期页表 (Early Page Table)
-
-- **`early_pgdir`:** 一块静态分配的 4KB `.data` 内存,用作初始顶级页表 (Root Page Table)。
-
-- 内含两个 1GB 的超级大页(Giga Page)映射:
-
- 1. **恒等映射 (Identity Map):** `0x80000000 -> 0x80000000`,保证开启 MMU 瞬间下一条指令能正确取指。
-
- 2. **高半区映射 (Higher-Half Map):** `0xFFFFFFC080000000 -> 0x80000000`,供后续 C++ 代码正常运行。
-
-- **生命周期:** 此恒等映射为临时性过渡,在 VMM 建立完整页表后必须被撤销。高半区映射将被 VMM 接管并细化为 4KB 粒度的精确权限映射。
-
-
-## 4. 公共 API 与核心符号 (Public APIs & Symbols)
-
-### 4.1 RISC-V OS Image Header 规范
-
-在 `entry.S` 的最开始(`.head.text` 段),必须按照以下结构手写 64 字节的元数据。
-定义参照 Linux `arch/riscv/include/asm/image.h` 中的 `struct riscv_image_header`:
-
-```asm
- .section .head.text, "ax"
- .globl _start
-_start:
- /* code0 (u32, offset 0): 可执行跳转指令,OpenSBI 裸启入口 */
- j real_start
- /* code1 (u32, offset 4): 保留 */
- .word 0
- /* text_offset (u64, offset 8): Image 加载偏移 */
- .dword 0x200000
- /* image_size (u64, offset 16): 镜像大小,链接后由脚本填充,初期可写 0 */
- .dword 0
- /* flags (u64, offset 24): 内核标志位 (bit 0: 0=LE, 1=BE) */
- .dword 0
- /* version (u32, offset 32): Header 版本 (major << 16 | minor),当前 0.2 */
- .word 0x0002
- /* res1 (u32, offset 36): 保留 */
- .word 0
- /* res2 (u64, offset 40): 保留 */
- .dword 0
- /* magic (u64, offset 48): RISCV_IMAGE_MAGIC = "RISCV\0\0\0" (LE) */
- .dword 0x5643534952
- /* magic2 (u32, offset 56): RISCV_IMAGE_MAGIC2 = "RSC\x05" (LE) */
- .word 0x05435352
- /* res3 (u32, offset 60): 预留给 PE/COFF 偏移 (UEFI),目前填 0 */
- .word 0
-```
-
-### 4.2 汇编函数签名
-
-```cpp
-// 定义于 arch/riscv/boot/entry.S
-// _start 中的 `j real_start` 跳转目标,执行早期硬件初始化。
-void real_start() __attribute__((noreturn)); // 汇编实现,无 C++ 调用约定
-
-// 定义于 arch/riscv/boot/entry.S 或 kernel/main.cc
-// 仅由 CPU 0 调用,遍历 .init_array 执行全局构造函数。
-void early_cpp_init();
-
-// 定义于 kernel/main.cc
-// C++ 内核总入口。各 CPU 在开启 MMU 后汇聚于此。
-// 参数:cpu_id = 当前 CPU 编号,fdt_paddr = FDT 物理基址。
-void kernel_main(uint64 cpu_id, uint64 fdt_paddr) __attribute__((noreturn));
-```
-
-## 5. 并发与锁契约 (Concurrency & Locks)
-
-此时 `Spinlock` 尚未初始化,必须使用汇编级的极简同步机制来避免多核访问冲突。
-
-- **本模块持有的锁:** 无高级锁。
-
-- **本模块可能获取的外部锁:** 无。
-
-- **原子同步契约 (SMP Sync):**
-
- 1. 在 `.data` 段定义一个全局标志 `uint32 boot_sync_flag = 0;`。
-
- 2. 只有 **CPU 0** (或 `a0` 读取到的第一个 CPU) 作为主核心 (BSP),获准执行 BSS 清零、早期页表填充等破坏性操作。
-
- 3. **副核心 (AP, Application Processors)** 必须使用原子加载指令在汇编层盲等 `boot_sync_flag` 变为 1。具体实现为 `lw` + 循环比较(不需要 `amoswap`,因为只有 BSP 写入,AP 只读)。
-
- 4. BSP 完成 `early_pgdir` 写入并唤醒 AP 前,必须执行 `fence rw, rw` 以保证所有先前的内存写入对其他 CPU 可见,随后使用 `fence.i` 刷新指令缓存(如有需要),最后将 `boot_sync_flag` 设为 1。
-
-
-## 6. 错误路径 (Error Paths)
-
-在早期的裸机启动阶段,内核没有任何错误恢复能力。
-
-- **检测点:** 所有 CPU 在 `real_start` 入口处可选地检查 `misa` 或 `marchid` 判断基本硬件兼容性(如 64 位检查)。
-
-- **失败行为:** 立即关闭本 CPU 的中断使能(`csrc sstatus, SSTATUS_SIE`),进入 `wfi` 死循环。无串口输出(此时 UART 尚未初始化)。
-
-- **无回滚:** 早期启动无任何资源可回收,失败即死。
-
-
-## 7. 状态机 / 时序图 (State Machine / Sequence)
-
-以下描述了从底层固件直到进入 `kernel_main` 的全流程:
-
-```
-[引导分流]
- ├──> OpenSBI 裸启: 直接跳转到内存基址 (0x80200000)
- │ └─ 命中 _start 处的第一条指令 `j real_start`
- │
- └──> GRUB / U-Boot 引导: 解析位于 0x80200000 处的 64 字节 Header
- ├─ 验证 magic ("RISCV\0\0\0") 与 magic2 ("RSC\x05")
- ├─ 验证 text_offset
- └─ 跳转到 0x80200000 (此时 a0=cpu_id, a1=fdt_paddr)
- └─ 同样命中 _start 处的第一条指令 `j real_start`
-
- │ (汇聚点)
- ▼
-[real_start]
- │
- ├─> 1. 设置 gp 寄存器 (la gp, __global_pointer$)
- │ // 极其关键:medany 模型下访问全局变量依赖此寄存器
- │
- ├─> 2. 设置早期内核栈 (la sp, boot_stack + (cpu_id + 1) * 8192)
- │
- ├─> 3. 判断是否为主核心 (CPU 0)?
- │ ├── [是 (BSP)]
- │ │ ├─ 3.1 循环清理 BSS 段 (_sbss 至 _ebss 填 0)
- │ │ ├─ 3.2 填充 early_pgdir (建立恒等映射与高半区映射)
- │ │ ├─ 3.3 fence rw, rw (确保内存修改对其他 CPU 可见)
- │ │ └─ 3.4 释放副核心 (boot_sync_flag = 1)
- │ │
- │ └── [否 (AP)]
- │ └─ 3.1 汇编级自旋等待,直到 boot_sync_flag == 1
- │
- ├─> 4. 高半区蹦床 (Higher-Half Trampoline - 所有 CPU 执行)
- │ ├─ 4.1 将 early_pgdir 物理地址写入 satp 寄存器 (MODE=SV39)
- │ ├─ 4.2 执行 sfence.vma 刷新 TLB
- │ ├─ 4.3 计算 kernel_main 的高半区虚拟地址
- │ └─ 4.4 jr 绝对跳转至虚拟地址,彻底抛弃低位物理 PC
- │
- ▼
-[进入虚拟世界: call early_cpp_init] (仅 BSP 执行)
- │
- └─> 遍历 __init_array_start 到 __init_array_end
- 依次调用全局构造函数,完成 C++ early runtime setup
- │
- ▼
-[跳转至 C++ 逻辑: call kernel_main(a0, a1)] (所有 CPU 汇合)
-``` \ No newline at end of file