|
4 | 4 | 本章教程将教学您如何开发一个 x86 平台的操作系统 |
5 | 5 |
|
6 | 6 | > 该教程有很多不详细之处,并不能直接作为保姆式教程使用 |
| 7 | +> |
| 8 | +> * 实际上该羡项目为参考式项目, 提供了一个大致的开发方向,以及标注了很多开发中可能遇到的问题 |
7 | 9 |
|
8 | 10 | ## 概念 |
9 | 11 |
|
|
76 | 78 | - 《30 天自制操作系统》这本书仅供 GUI 部分参考,其他功能实现并不是很好,不建议您全部借鉴 |
77 | 79 | - 64 位长的操作系统会比 32 位保护模式的操作系统实现更难,比如 32 位只需要二级页表即可,64 位需要 4 级甚至更多才能管理所有内存 |
78 | 80 | - ARM 等其他架构的 CPU 与 x86 平台的 CPU 实现截然不同,其中 x86 的很多机制在 ARM 是没有的,同理 ARM 某些机制 x86 也没有 |
79 | | -- 本教程只是教学您如何实现一个最简单的宏内核操作系统,如果您想完善您的操作系统,可以去查阅更多的资料 |
| 81 | +- 本教程只是给予开发的一个大致方向与常见问题解答, 注意事项提醒等 |
80 | 82 | - 操作系统编写好都是要在实体机上测试的,无法在实体机上跑的操作系统就不是一个真正的操作系统 |
81 | 83 |
|
82 | 84 | ## 注意事项 |
|
89 | 91 |
|
90 | 92 | > 4Kib: 可以用十进制 `4096` 表示,也可以用十六进制 `0x1000` 表示 |
91 | 93 |
|
| 94 | +### 内存 |
| 95 | + |
92 | 96 | - cr3 指向的页表基址,必须进行 `4k` 对齐 |
93 | 97 | - 物理内存管理分配出来的页框基址,必须是 `4k` 对齐的再写入页 |
94 | 98 | - `rsp` 的栈基址最好为 16 字节对齐,因为部分实体机机型对此有要求 |
95 | | -- 所有设备驱动需要往 `MMIO` 设备寄存器传入物理地址。 |
96 | | -- 部分实体机的机型对 `cpuid` 指令的实现有些许差异,编写多核 CPU 初始化等代码时候需要用 `ACPI` 或 `lapic_id` 获取核心的代号,不要用 `cpuid` 指令获取 |
97 | | -- 锁不要滥用,否则会发生死锁 |
| 99 | +- 对于物理页框分配器, 在使用提供一个初始页表的引导器操作系统开发中(如 Limine), 需要额外注意内核本身与页表本身的内存占用, 否则容易覆写 |
| 100 | +- 页表本身需要在物理内存上具有连续性, 且基址必须4k对齐 |
| 101 | +- 页映射释放后需执行一遍 `TLB` 快表刷新操作, 防止缓存干扰映射规则 |
| 102 | + |
| 103 | +### 驱动 |
| 104 | + |
| 105 | +- 所有设备驱动需要往 `MMIO` 设备寄存器传入物理地址(设备控制器没有MMU, 传入虚拟地址无法处理) |
98 | 106 | - 设备 IRQ 中断请求必须要向中断控制器发送 `EOI` 代表请求处理完毕,不然下一次设备请求不会再次发送 |
99 | 107 | - `PS/2` 键盘需要在你获取了扫描码后才会发送下一次中断,否则 `PS/2` 控制器会阻塞 |
| 108 | +- `PS/2` 设备中断处理需要在最后发送 `EOI`, 否则多个扫描码发送会造成中断嵌套 |
| 109 | + |
| 110 | +### CPU |
| 111 | + |
100 | 112 | - `qemu` `VMware` 虚拟机对 `wrfsbase` `rdgsbase` 等扩展指令支持性较差,建议使用 `msr` 对 `fs` `gs` 段寄存器进行操作 |
| 113 | +- 部分实体机的机型对 `cpuid` 指令的实现有些许差异,编写多核 CPU 初始化等代码时候需要用 `ACPI` 或 `lapic_id` 获取核心的代号,不要用 `cpuid` 指令获取 |
| 114 | +- 特殊的扩展指令(如syscall)需要特别设置控制寄存器或 `MSR`去启用, 且多核环境下需要为每一个核心都执行一遍启用操作 |
| 115 | +- 内核中不要滥用 `pause` `hlt` 等指令, 这些指令会造成CPU功耗、频率降低,从而影响性能. |
| 116 | + |
| 117 | +### 并发 / 异步 |
| 118 | + |
| 119 | +- 锁不要滥用,否则会发生死锁 |
| 120 | +- 调度器时钟频率不要太高, 否则调度器本身未执行完毕会再一次进入调度器造成中断嵌套 |
| 121 | +- 异步冲突临界区必须加锁, 否则会造成资源竞争冲突 |
| 122 | + |
| 123 | +### 开发 |
| 124 | + |
| 125 | +- 编译器最好开一下严格模式, 因为操作系统本身是非常不好调试的, 而且BUG溯源极其困难, 一个小小的错误会让你头疼一个星期甚至一个月 |
| 126 | +- 详见 [编程交流生存指南](/杂项/技术无关/1_编程交流群生存指南.md) 第 1 标题, 第 40,41,43 条 |
| 127 | +- 作为内核, 你永远要以最坏的情况去针对用户态程序, 用户 `syscall` 传来的参数要严格检查是否是空指针以及地址合法性 |
| 128 | +- 对于内核中对参数有要求的接口, 要对参数打好断言, 这样可以在自己犯傻后可以快速找出问题 |
| 129 | + |
| 130 | +> 你要清楚自己写的是什么, 有哪些不足, 应该如何安排项目结构 |
0 commit comments