feat(mm): add early page table mapping foundation
This commit is contained in:
parent
5b69fe1f06
commit
e3f34ac1fe
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
- 正式设计、路线图、架构说明放在 `docs/`
|
- 正式设计、路线图、架构说明放在 `docs/`
|
||||||
- 面向 agent 的任务、会话记录、检查单放在 `docs/agents/`
|
- 面向 agent 的任务、会话记录、检查单放在 `docs/agents/`
|
||||||
|
- Linux 顶层目录映射见 `docs/agents/linux-layout.md`
|
||||||
|
|
||||||
## 工作规则
|
## 工作规则
|
||||||
|
|
||||||
|
|||||||
7
Makefile
7
Makefile
@ -21,6 +21,7 @@ endif
|
|||||||
include $(ARCH_MAKEFILE)
|
include $(ARCH_MAKEFILE)
|
||||||
include $(ARCH_DIR)/boot/Makefile
|
include $(ARCH_DIR)/boot/Makefile
|
||||||
include $(ARCH_DIR)/kernel/Makefile
|
include $(ARCH_DIR)/kernel/Makefile
|
||||||
|
include $(ARCH_DIR)/mm/Makefile
|
||||||
include mm/Makefile
|
include mm/Makefile
|
||||||
include kernel/Makefile
|
include kernel/Makefile
|
||||||
|
|
||||||
@ -29,7 +30,7 @@ include kernel/Makefile
|
|||||||
all: $(BOOT_EFI) $(KERNEL_ELF)
|
all: $(BOOT_EFI) $(KERNEL_ELF)
|
||||||
|
|
||||||
dirs:
|
dirs:
|
||||||
mkdir -p $(BUILD_DIR)/arch/boot $(BUILD_DIR)/arch/kernel $(BUILD_DIR)/kernel $(BUILD_DIR)/mm $(EFI_DIR)
|
mkdir -p $(BUILD_DIR)/arch/boot $(BUILD_DIR)/arch/kernel $(BUILD_DIR)/arch/mm $(BUILD_DIR)/kernel $(BUILD_DIR)/mm $(EFI_DIR)
|
||||||
|
|
||||||
$(BUILD_DIR)/arch/boot/%.obj: $(ARCH_DIR)/boot/%.c $(ARCH_DIR)/include/efi.h $(ARCH_DIR)/boot/debug_log.h include/tianole/boot_info.h include/tianole/elf.h | dirs
|
$(BUILD_DIR)/arch/boot/%.obj: $(ARCH_DIR)/boot/%.c $(ARCH_DIR)/include/efi.h $(ARCH_DIR)/boot/debug_log.h include/tianole/boot_info.h include/tianole/elf.h | dirs
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
@ -46,6 +47,10 @@ $(BUILD_DIR)/arch/kernel/%.o: $(ARCH_DIR)/kernel/%.S | dirs
|
|||||||
$(BUILD_DIR)/arch/kernel/%.o: $(ARCH_DIR)/kernel/%.c include/tianole/arch.h | dirs
|
$(BUILD_DIR)/arch/kernel/%.o: $(ARCH_DIR)/kernel/%.c include/tianole/arch.h | dirs
|
||||||
$(CC) $(KERNEL_CFLAGS) -c $< -o $@
|
$(CC) $(KERNEL_CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(BUILD_DIR)/arch/mm/%.o: $(ARCH_DIR)/mm/%.c include/tianole/early_log.h include/tianole/mm.h | dirs
|
||||||
|
mkdir -p $(@D)
|
||||||
|
$(CC) $(KERNEL_CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
$(BUILD_DIR)/kernel/%.o: kernel/%.c include/tianole/boot_info.h include/tianole/kernel_init.h include/tianole/arch.h include/tianole/early_log.h include/tianole/mm.h | dirs
|
$(BUILD_DIR)/kernel/%.o: kernel/%.c include/tianole/boot_info.h include/tianole/kernel_init.h include/tianole/arch.h include/tianole/early_log.h include/tianole/mm.h | dirs
|
||||||
mkdir -p $(@D)
|
mkdir -p $(@D)
|
||||||
$(CC) $(KERNEL_CFLAGS) -c $< -o $@
|
$(CC) $(KERNEL_CFLAGS) -c $< -o $@
|
||||||
|
|||||||
50
README.md
50
README.md
@ -1,15 +1,24 @@
|
|||||||
# Tianole
|
# Tianole
|
||||||
|
|
||||||
Tianole 是一个面向 `UEFI x86_64` 机器的自制操作系统项目。
|
Tianole 是一个学习型自制操作系统项目,当前面向 `UEFI x86_64` 机器。
|
||||||
|
|
||||||
当前目标不是一次性做“大而全”的系统,而是按 Linux 风格的分层思路,逐步把启动链、内核基础设施、用户态和文件系统建立起来,最终能在真机上安全启动,并逐步具备运行本地 `git` 的能力。
|
这个项目的主要目的有三点:
|
||||||
|
|
||||||
|
- 通过亲手实现一个简化但不玩具化的 OS,理解操作系统核心机制。
|
||||||
|
- 通过参考 Linux 的目录、分层和工程纪律,建立阅读 Linux 源码的上下文。
|
||||||
|
- 长期目标是在真机上安全启动,并逐步具备运行本地 `git` 的能力。
|
||||||
|
|
||||||
|
Tianole 不宣称自己是成熟 Linux 替代品。当前阶段更准确的定位是:用一个可运行、可验证、可持续演进的代码库,系统性学习 Linux 式内核工程。
|
||||||
|
|
||||||
## 当前状态
|
## 当前状态
|
||||||
|
|
||||||
- 已跑通 `QEMU + OVMF` 下的最小 `UEFI` 启动链
|
- 已跑通 `QEMU + OVMF` 下的最小 `UEFI` 启动链。
|
||||||
- 已拆分为 `bootloader + kernel`
|
- 已拆分为 `bootloader + kernel`,并能加载独立 `kernel.elf`。
|
||||||
- `bootloader` 已能加载独立 `kernel.elf`
|
- 已在进入 kernel 前调用 `ExitBootServices`。
|
||||||
- `kernel_main()` 已能实际执行
|
- 已建立 early log 基础:QEMU debug port 和 COM1 串口。
|
||||||
|
- 已建立 CPU exception 基础:GDT/TSS/IDT、trap frame、invalid opcode -> panic。
|
||||||
|
- 已建立物理内存基础:从 boot memory map 初始化最小物理页 allocator。
|
||||||
|
- 还没有完成完整中断、页表、内核堆、调度、进程、VFS、用户态和 shell。
|
||||||
|
|
||||||
## 当前目录
|
## 当前目录
|
||||||
|
|
||||||
@ -18,18 +27,44 @@ tianole/
|
|||||||
AGENTS.md
|
AGENTS.md
|
||||||
Makefile
|
Makefile
|
||||||
arch/
|
arch/
|
||||||
|
block/
|
||||||
|
crypto/
|
||||||
docs/
|
docs/
|
||||||
|
drivers/
|
||||||
|
fs/
|
||||||
include/
|
include/
|
||||||
|
init/
|
||||||
|
ipc/
|
||||||
kernel/
|
kernel/
|
||||||
|
lib/
|
||||||
mm/
|
mm/
|
||||||
|
net/
|
||||||
scripts/
|
scripts/
|
||||||
|
security/
|
||||||
|
sound/
|
||||||
|
tools/
|
||||||
|
usr/
|
||||||
|
virt/
|
||||||
```
|
```
|
||||||
|
|
||||||
当前还没有直接复制 Linux 的完整目录树,但已经开始按接近 Linux 的方式分层:
|
当前按接近 Linux 的方式分层,但不机械复制 Linux 的所有历史目录:
|
||||||
|
|
||||||
- `arch/`:架构相关代码
|
- `arch/`:架构相关代码
|
||||||
|
- `block/`:通用块层
|
||||||
|
- `crypto/`:通用加密和哈希算法
|
||||||
|
- `drivers/`:设备驱动
|
||||||
|
- `fs/`:VFS 和文件系统
|
||||||
|
- `init/`:初始化流程
|
||||||
|
- `ipc/`:进程间通信
|
||||||
- `kernel/`:通用内核主体逐步放这里
|
- `kernel/`:通用内核主体逐步放这里
|
||||||
|
- `lib/`:通用基础库
|
||||||
- `mm/`:架构无关内存管理
|
- `mm/`:架构无关内存管理
|
||||||
|
- `net/`:网络协议栈
|
||||||
|
- `security/`:安全模型
|
||||||
|
- `sound/`:音频子系统
|
||||||
|
- `tools/`:宿主机侧开发工具
|
||||||
|
- `usr/`:初始用户空间
|
||||||
|
- `virt/`:虚拟化支持
|
||||||
- `include/tianole/`:项目自有共享接口
|
- `include/tianole/`:项目自有共享接口
|
||||||
- `docs/`:正式设计和路线图
|
- `docs/`:正式设计和路线图
|
||||||
|
|
||||||
@ -79,4 +114,5 @@ GitHub Actions 会在 push 和 pull request 时运行同一个检查入口。具
|
|||||||
|
|
||||||
- 路线图:[docs/roadmap.md](//wsl.localhost/Ubuntu/home/indole/tianole/docs/roadmap.md)
|
- 路线图:[docs/roadmap.md](//wsl.localhost/Ubuntu/home/indole/tianole/docs/roadmap.md)
|
||||||
- 本机环境与真机启动约束:[docs/host-machine.md](//wsl.localhost/Ubuntu/home/indole/tianole/docs/host-machine.md)
|
- 本机环境与真机启动约束:[docs/host-machine.md](//wsl.localhost/Ubuntu/home/indole/tianole/docs/host-machine.md)
|
||||||
|
- Linux 顶层目录映射:[docs/agents/linux-layout.md](//wsl.localhost/Ubuntu/home/indole/tianole/docs/agents/linux-layout.md)
|
||||||
- agent 入口:[AGENTS.md](//wsl.localhost/Ubuntu/home/indole/tianole/AGENTS.md)
|
- agent 入口:[AGENTS.md](//wsl.localhost/Ubuntu/home/indole/tianole/AGENTS.md)
|
||||||
|
|||||||
@ -65,6 +65,14 @@ static uint64_t interrupted_rsp(const struct trap_frame *frame)
|
|||||||
return (uint64_t)(uintptr_t)&frame->rflags + sizeof(frame->rflags);
|
return (uint64_t)(uintptr_t)&frame->rflags + sizeof(frame->rflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint64_t read_cr2(void)
|
||||||
|
{
|
||||||
|
uint64_t cr2;
|
||||||
|
|
||||||
|
__asm__ volatile("movq %%cr2, %0" : "=r"(cr2));
|
||||||
|
return cr2;
|
||||||
|
}
|
||||||
|
|
||||||
void arch_traps_init(void)
|
void arch_traps_init(void)
|
||||||
{
|
{
|
||||||
gdt_init();
|
gdt_init();
|
||||||
@ -97,5 +105,11 @@ void trap_dispatch(struct trap_frame *frame)
|
|||||||
log_u64_hex(frame->rflags);
|
log_u64_hex(frame->rflags);
|
||||||
early_log_puts("\n");
|
early_log_puts("\n");
|
||||||
|
|
||||||
|
if (vector == 14) {
|
||||||
|
early_log_puts("fault_address=");
|
||||||
|
log_u64_hex(read_cr2());
|
||||||
|
early_log_puts("\n");
|
||||||
|
}
|
||||||
|
|
||||||
panic("unhandled CPU exception");
|
panic("unhandled CPU exception");
|
||||||
}
|
}
|
||||||
|
|||||||
5
arch/x86/mm/Makefile
Normal file
5
arch/x86/mm/Makefile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
ARCH_MM_SRCS := \
|
||||||
|
$(ARCH_DIR)/mm/page_table.c
|
||||||
|
|
||||||
|
ARCH_MM_OBJS := \
|
||||||
|
$(patsubst $(ARCH_DIR)/mm/%.c,$(BUILD_DIR)/arch/mm/%.o,$(ARCH_MM_SRCS))
|
||||||
305
arch/x86/mm/page_table.c
Normal file
305
arch/x86/mm/page_table.c
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <tianole/arch.h>
|
||||||
|
#include <tianole/early_log.h>
|
||||||
|
#include <tianole/mm.h>
|
||||||
|
|
||||||
|
#define ENTRY_COUNT 512
|
||||||
|
#define PAGE_MASK 0x000ffffffffff000ull
|
||||||
|
#define PAGE_SIZE_FLAG (1ull << 7)
|
||||||
|
#define MAX_RESERVED_TABLE_PAGES 4096
|
||||||
|
#define TEST_VIRTUAL_PAGE 0xffffff0000000000ull
|
||||||
|
|
||||||
|
static phys_addr_t reserved_table_pages[MAX_RESERVED_TABLE_PAGES];
|
||||||
|
static uint64_t reserved_table_page_count;
|
||||||
|
static int reserved_table_pages_ready;
|
||||||
|
static uint64_t kernel_pml4[ENTRY_COUNT] __attribute__((aligned(PAGE_SIZE)));
|
||||||
|
static int page_tables_ready;
|
||||||
|
|
||||||
|
static uint64_t *active_pml4(void)
|
||||||
|
{
|
||||||
|
uint64_t cr3;
|
||||||
|
|
||||||
|
__asm__ volatile("movq %%cr3, %0" : "=r"(cr3));
|
||||||
|
return (uint64_t *)(uintptr_t)(cr3 & PAGE_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flush_tlb_page(virt_addr_t virt)
|
||||||
|
{
|
||||||
|
__asm__ volatile("invlpg (%0)" : : "r"((uintptr_t)virt) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load_cr3(phys_addr_t root)
|
||||||
|
{
|
||||||
|
__asm__ volatile("movq %0, %%cr3" : : "r"(root) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t table_index(virt_addr_t virt, unsigned int shift)
|
||||||
|
{
|
||||||
|
return (virt >> shift) & 0x1ffu;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_page(phys_addr_t page)
|
||||||
|
{
|
||||||
|
uint64_t *words = (uint64_t *)(uintptr_t)page;
|
||||||
|
uint64_t index;
|
||||||
|
|
||||||
|
for (index = 0; index < PAGE_SIZE / sizeof(uint64_t); index++) {
|
||||||
|
words[index] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t *entry_table(uint64_t entry)
|
||||||
|
{
|
||||||
|
return (uint64_t *)(uintptr_t)(entry & PAGE_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_reserved_table_page(phys_addr_t page)
|
||||||
|
{
|
||||||
|
uint64_t index;
|
||||||
|
|
||||||
|
for (index = 0; index < reserved_table_page_count; index++) {
|
||||||
|
if (reserved_table_pages[index] == page) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reserved_table_page_count >= MAX_RESERVED_TABLE_PAGES) {
|
||||||
|
panic("too many active page table pages");
|
||||||
|
}
|
||||||
|
|
||||||
|
reserved_table_pages[reserved_table_page_count++] = page;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void collect_active_page_tables(void)
|
||||||
|
{
|
||||||
|
uint64_t pml4_index;
|
||||||
|
uint64_t pdpt_index;
|
||||||
|
uint64_t pd_index;
|
||||||
|
uint64_t *pml4 = active_pml4();
|
||||||
|
|
||||||
|
add_reserved_table_page((phys_addr_t)(uintptr_t)pml4);
|
||||||
|
|
||||||
|
for (pml4_index = 0; pml4_index < ENTRY_COUNT; pml4_index++) {
|
||||||
|
uint64_t *pdpt;
|
||||||
|
|
||||||
|
if ((pml4[pml4_index] & PAGE_PRESENT) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_reserved_table_page(pml4[pml4_index] & PAGE_MASK);
|
||||||
|
|
||||||
|
pdpt = entry_table(pml4[pml4_index]);
|
||||||
|
for (pdpt_index = 0; pdpt_index < ENTRY_COUNT; pdpt_index++) {
|
||||||
|
uint64_t *pd;
|
||||||
|
|
||||||
|
if ((pdpt[pdpt_index] & PAGE_PRESENT) == 0 ||
|
||||||
|
(pdpt[pdpt_index] & PAGE_SIZE_FLAG) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_reserved_table_page(pdpt[pdpt_index] & PAGE_MASK);
|
||||||
|
|
||||||
|
pd = entry_table(pdpt[pdpt_index]);
|
||||||
|
for (pd_index = 0; pd_index < ENTRY_COUNT; pd_index++) {
|
||||||
|
if ((pd[pd_index] & PAGE_PRESENT) == 0 ||
|
||||||
|
(pd[pd_index] & PAGE_SIZE_FLAG) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_reserved_table_page(
|
||||||
|
pd[pd_index] & PAGE_MASK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int arch_page_table_uses_page(uint64_t page)
|
||||||
|
{
|
||||||
|
uint64_t index;
|
||||||
|
|
||||||
|
if ((page & (PAGE_SIZE - 1)) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reserved_table_pages_ready == 0) {
|
||||||
|
collect_active_page_tables();
|
||||||
|
reserved_table_pages_ready = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index = 0; index < reserved_table_page_count; index++) {
|
||||||
|
if (reserved_table_pages[index] == page) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t make_table_entry(phys_addr_t table)
|
||||||
|
{
|
||||||
|
return table | PAGE_PRESENT | PAGE_WRITABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void page_tables_init(void)
|
||||||
|
{
|
||||||
|
uint64_t index;
|
||||||
|
uint64_t *firmware_pml4;
|
||||||
|
|
||||||
|
if (page_tables_ready != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
firmware_pml4 = active_pml4();
|
||||||
|
for (index = 0; index < ENTRY_COUNT; index++) {
|
||||||
|
kernel_pml4[index] = firmware_pml4[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
load_cr3((phys_addr_t)(uintptr_t)kernel_pml4);
|
||||||
|
page_tables_ready = 1;
|
||||||
|
early_log_puts("kernel page table root active\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ensure_next_table(uint64_t *table, uint64_t index, uint64_t **next)
|
||||||
|
{
|
||||||
|
phys_addr_t page;
|
||||||
|
|
||||||
|
if ((table[index] & PAGE_PRESENT) != 0) {
|
||||||
|
*next = entry_table(table[index]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
page = alloc_page();
|
||||||
|
if (page == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_page(page);
|
||||||
|
table[index] = make_table_entry(page);
|
||||||
|
*next = (uint64_t *)(uintptr_t)page;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int page_entry(virt_addr_t virt, int create, uint64_t **entry)
|
||||||
|
{
|
||||||
|
uint64_t *pml4 = active_pml4();
|
||||||
|
uint64_t *pdpt;
|
||||||
|
uint64_t *pd;
|
||||||
|
uint64_t *pt;
|
||||||
|
uint64_t pml4_index = table_index(virt, 39);
|
||||||
|
uint64_t pdpt_index = table_index(virt, 30);
|
||||||
|
uint64_t pd_index = table_index(virt, 21);
|
||||||
|
uint64_t pt_index = table_index(virt, 12);
|
||||||
|
|
||||||
|
if (create != 0) {
|
||||||
|
if (ensure_next_table(pml4, pml4_index, &pdpt) != 0 ||
|
||||||
|
ensure_next_table(pdpt, pdpt_index, &pd) != 0 ||
|
||||||
|
ensure_next_table(pd, pd_index, &pt) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((pml4[pml4_index] & PAGE_PRESENT) == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pdpt = entry_table(pml4[pml4_index]);
|
||||||
|
|
||||||
|
if ((pdpt[pdpt_index] & PAGE_PRESENT) == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pd = entry_table(pdpt[pdpt_index]);
|
||||||
|
|
||||||
|
if ((pd[pd_index] & PAGE_PRESENT) == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pt = entry_table(pd[pd_index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
*entry = &pt[pt_index];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int map_page(virt_addr_t virt, phys_addr_t phys, uint64_t flags)
|
||||||
|
{
|
||||||
|
uint64_t *entry;
|
||||||
|
|
||||||
|
if ((virt & (PAGE_SIZE - 1)) != 0 || (phys & (PAGE_SIZE - 1)) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page_entry(virt, 1, &entry) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*entry & PAGE_PRESENT) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*entry = (phys & PAGE_MASK) | flags | PAGE_PRESENT;
|
||||||
|
flush_tlb_page(virt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int unmap_page(virt_addr_t virt)
|
||||||
|
{
|
||||||
|
uint64_t *entry;
|
||||||
|
|
||||||
|
if ((virt & (PAGE_SIZE - 1)) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page_entry(virt, 0, &entry) != 0 || (*entry & PAGE_PRESENT) == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*entry = 0;
|
||||||
|
flush_tlb_page(virt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int virt_to_phys(virt_addr_t virt, phys_addr_t *phys)
|
||||||
|
{
|
||||||
|
uint64_t *entry;
|
||||||
|
|
||||||
|
if (phys == 0 || page_entry(virt, 0, &entry) != 0 ||
|
||||||
|
(*entry & PAGE_PRESENT) == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*phys = (*entry & PAGE_MASK) | (virt & (PAGE_SIZE - 1));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void page_table_selftest(void)
|
||||||
|
{
|
||||||
|
phys_addr_t page = alloc_page();
|
||||||
|
phys_addr_t resolved;
|
||||||
|
volatile uint64_t *mapped =
|
||||||
|
(volatile uint64_t *)(uintptr_t)TEST_VIRTUAL_PAGE;
|
||||||
|
|
||||||
|
if (page == 0) {
|
||||||
|
panic("page table selftest allocation failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
page_tables_init();
|
||||||
|
|
||||||
|
if (map_page(TEST_VIRTUAL_PAGE, page, PAGE_WRITABLE) != 0) {
|
||||||
|
panic("page table selftest map failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virt_to_phys(TEST_VIRTUAL_PAGE, &resolved) != 0 ||
|
||||||
|
resolved != page) {
|
||||||
|
panic("page table selftest resolve failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
*mapped = 0x54494f4c45504d4dull;
|
||||||
|
if (*mapped != 0x54494f4c45504d4dull) {
|
||||||
|
panic("page table selftest access failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unmap_page(TEST_VIRTUAL_PAGE) != 0) {
|
||||||
|
panic("page table selftest unmap failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
free_page(page);
|
||||||
|
early_log_puts("page table selftest ok\n");
|
||||||
|
}
|
||||||
9
block/README.md
Normal file
9
block/README.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# block
|
||||||
|
|
||||||
|
块设备层目录。
|
||||||
|
|
||||||
|
后续用于放置块设备抽象、请求队列、缓存写回入口,以及连接 `drivers/` 和
|
||||||
|
`fs/` 的通用块 I/O 层。
|
||||||
|
|
||||||
|
当前阶段暂不放代码。
|
||||||
|
|
||||||
8
crypto/README.md
Normal file
8
crypto/README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# crypto
|
||||||
|
|
||||||
|
通用加密算法和哈希算法目录。
|
||||||
|
|
||||||
|
后续用于支持文件校验、签名、随机数、网络协议和用户态工具需要的基础算法。
|
||||||
|
|
||||||
|
当前阶段暂不放代码。
|
||||||
|
|
||||||
@ -7,6 +7,7 @@
|
|||||||
建议内容:
|
建议内容:
|
||||||
|
|
||||||
- `code-style.md`:agent 修改代码时必须遵守的代码组织和风格规则。
|
- `code-style.md`:agent 修改代码时必须遵守的代码组织和风格规则。
|
||||||
|
- `linux-layout.md`:Tianole 和 Linux 顶层目录的映射与取舍。
|
||||||
- `session-notes/`:实现日志和阶段结论。
|
- `session-notes/`:实现日志和阶段结论。
|
||||||
- `tasks/`:适合 agent 执行的边界清晰任务,按路线阶段拆分。
|
- `tasks/`:适合 agent 执行的边界清晰任务,按路线阶段拆分。
|
||||||
- `prompts/`:可复用提示词和约束。
|
- `prompts/`:可复用提示词和约束。
|
||||||
@ -17,6 +18,7 @@
|
|||||||
当前任务入口:
|
当前任务入口:
|
||||||
|
|
||||||
- `code-style.md`:代码风格和文件组织规则。
|
- `code-style.md`:代码风格和文件组织规则。
|
||||||
|
- `linux-layout.md`:Linux 顶层目录映射。
|
||||||
- `tasks/README.md`:agent 任务索引。
|
- `tasks/README.md`:agent 任务索引。
|
||||||
- `tasks/02-cpu-interrupts.md`:下一阶段,GDT/TSS/IDT、异常入口和 trap frame。
|
- `tasks/02-cpu-interrupts.md`:下一阶段,GDT/TSS/IDT、异常入口和 trap frame。
|
||||||
- `../roadmap.md`:总路线和阶段依赖。
|
- `../roadmap.md`:总路线和阶段依赖。
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
- 按职责、生命周期、所有权和调用边界拆分。
|
- 按职责、生命周期、所有权和调用边界拆分。
|
||||||
- `kernel/main.c`、`boot/main.c` 这类入口文件应保持短,只串联阶段。
|
- `kernel/main.c`、`boot/main.c` 这类入口文件应保持短,只串联阶段。
|
||||||
- `mm/` 是顶层内存管理子系统目录,不放在 `kernel/mm/` 下。
|
- `mm/` 是顶层内存管理子系统目录,不放在 `kernel/mm/` 下。
|
||||||
|
- 顶层目录参考 `docs/agents/linux-layout.md`;可以预留目录,但不要放临时代码。
|
||||||
|
|
||||||
## 命名
|
## 命名
|
||||||
|
|
||||||
|
|||||||
41
docs/agents/linux-layout.md
Normal file
41
docs/agents/linux-layout.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# Linux 顶层目录映射
|
||||||
|
|
||||||
|
这个文档记录 Tianole 参考 Linux 顶层目录时的取舍。目标是学习 Linux 的工程分层,
|
||||||
|
而不是机械复制 Linux 的全部历史目录。
|
||||||
|
|
||||||
|
## 已采用或已预留
|
||||||
|
|
||||||
|
- `arch/`:对应 Linux `arch/`,放架构相关代码。
|
||||||
|
- `block/`:对应 Linux `block/`,后续放通用块层。
|
||||||
|
- `crypto/`:对应 Linux `crypto/`,后续放通用加密和哈希算法。
|
||||||
|
- `docs/`:对应 Linux `Documentation/`,Tianole 使用小写 `docs/`。
|
||||||
|
- `drivers/`:对应 Linux `drivers/`,后续放设备驱动和总线驱动。
|
||||||
|
- `fs/`:对应 Linux `fs/`,后续放 VFS 和具体文件系统。
|
||||||
|
- `include/`:对应 Linux `include/`,放公共头文件。
|
||||||
|
- `init/`:对应 Linux `init/`,后续放初始化流程。
|
||||||
|
- `ipc/`:对应 Linux `ipc/`,后续放 IPC、signal、pipe、futex 等能力。
|
||||||
|
- `kernel/`:对应 Linux `kernel/`,放调度、进程和核心内核逻辑。
|
||||||
|
- `lib/`:对应 Linux `lib/`,后续放通用基础库。
|
||||||
|
- `mm/`:对应 Linux `mm/`,放内存管理。
|
||||||
|
- `net/`:对应 Linux `net/`,后续放网络协议栈。
|
||||||
|
- `scripts/`:对应 Linux `scripts/`,放构建、检查和维护脚本。
|
||||||
|
- `security/`:对应 Linux `security/`,后续放权限和安全策略。
|
||||||
|
- `sound/`:对应 Linux `sound/`,后续放音频子系统。
|
||||||
|
- `tools/`:对应 Linux `tools/`,后续放宿主机侧开发工具。
|
||||||
|
- `usr/`:对应 Linux `usr/`,后续放初始用户空间。
|
||||||
|
- `virt/`:对应 Linux `virt/`,后续放虚拟化相关支持。
|
||||||
|
|
||||||
|
## 暂不采用
|
||||||
|
|
||||||
|
- `certs/`:证书和签名链路还不是当前阶段目标,后续可按安全启动需求加入。
|
||||||
|
- `io_uring/`:这是 Linux 的特定异步 I/O 子系统,Tianole 早期不引入。
|
||||||
|
- `rust/`:当前内核实现语言是 C/ASM,暂不引入 Rust 子树。
|
||||||
|
- `samples/`:示例代码暂不放顶层,后续可按教学或测试需要决定。
|
||||||
|
|
||||||
|
## 目录使用原则
|
||||||
|
|
||||||
|
- 可以预留目录,但不要在目录中放临时代码。
|
||||||
|
- 只有当一个目录对应的子系统真正开始实现时,才添加 `Makefile` 和源文件。
|
||||||
|
- 目录 README 用来说明长期职责,不替代正式设计文档。
|
||||||
|
- 如果后续发现目录边界不合理,优先更新本文件和 `docs/agents/code-style.md`。
|
||||||
|
|
||||||
@ -52,14 +52,16 @@
|
|||||||
- 已建立最小物理页 free-list allocator。
|
- 已建立最小物理页 free-list allocator。
|
||||||
- 已提供 `alloc_page()` 和 `free_page()`。
|
- 已提供 `alloc_page()` 和 `free_page()`。
|
||||||
- 已加入物理页分配/释放 selftest。
|
- 已加入物理页分配/释放 selftest。
|
||||||
- `scripts/check.sh` 已验证 `physical pages free=` 和 selftest 日志。
|
- 已切换到内核自有 PML4,不再直接修改固件页表。
|
||||||
|
- 已提供最小 `map_page()`、`unmap_page()` 和 `virt_to_phys()` 接口。
|
||||||
|
- 已加入页表 map/unmap/query selftest。
|
||||||
|
- `scripts/check.sh` 已验证 `physical pages free=`、物理页 selftest、页表根切换和页表 selftest 日志。
|
||||||
|
|
||||||
后续扩展:
|
后续扩展:
|
||||||
|
|
||||||
- 长期内存区域模型,不直接依赖 UEFI memory type。
|
- 长期内存区域模型,不直接依赖 UEFI memory type。
|
||||||
- page metadata。
|
- page metadata。
|
||||||
- buddy allocator。
|
- buddy allocator。
|
||||||
- 页表 map/unmap。
|
|
||||||
- page fault 专门处理。
|
- page fault 专门处理。
|
||||||
- 最小内核堆。
|
- 最小内核堆。
|
||||||
- slab/slub 或等价小对象缓存。
|
- slab/slub 或等价小对象缓存。
|
||||||
@ -68,7 +70,9 @@
|
|||||||
|
|
||||||
- 正常启动日志包含 `physical pages free=`。
|
- 正常启动日志包含 `physical pages free=`。
|
||||||
- 正常启动日志包含 `physical page allocator selftest ok`。
|
- 正常启动日志包含 `physical page allocator selftest ok`。
|
||||||
|
- 正常启动日志包含 `kernel page table root active`。
|
||||||
|
- 正常启动日志包含 `page table selftest ok`。
|
||||||
|
|
||||||
下一阶段:
|
下一阶段:
|
||||||
|
|
||||||
- 继续在 `03-memory.md` 内推进页表管理和内核堆。
|
- 继续在 `03-memory.md` 内推进 page fault 专门处理和最小内核堆。
|
||||||
|
|||||||
@ -21,6 +21,23 @@
|
|||||||
9. `09-driver-expansion.md`:PCI/ACPI/更完整设备驱动,音频等后期设备。
|
9. `09-driver-expansion.md`:PCI/ACPI/更完整设备驱动,音频等后期设备。
|
||||||
10. `10-real-machine.md`:真机启动、安全验证、硬件差异处理。
|
10. `10-real-machine.md`:真机启动、安全验证、硬件差异处理。
|
||||||
|
|
||||||
|
## 当前进度
|
||||||
|
|
||||||
|
| 阶段 | 状态 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `01-early-debug.md` | 基础完成 | 已有 early log 前端、QEMU debug port、COM1 串口和最小 `panic()`。 |
|
||||||
|
| `02-cpu-interrupts.md` | 基础完成 | 已有 GDT/TSS/IDT、exception vector 0-31、`trap_frame` 和 invalid opcode 回归测试。 |
|
||||||
|
| `03-memory.md` | 进行中 | 已有最小物理页 allocator 和页表 map/unmap/query 基础;page fault 策略和内核堆未完成。 |
|
||||||
|
| `04-time-scheduler.md` | 未开始 | 需要 timer、kernel thread、调度和等待队列。 |
|
||||||
|
| `05-input-events.md` | 未开始 | 需要输入事件模型和键盘接入。 |
|
||||||
|
| `06-storage-vfs.md` | 未开始 | 需要块层、缓存、VFS 和基础文件系统。 |
|
||||||
|
| `07-user-mode.md` | 未开始 | 需要 syscall、进程、用户地址空间和 ELF 加载。 |
|
||||||
|
| `08-shell-tools.md` | 未开始 | 需要 init、shell、最小用户态工具和 libc 基础。 |
|
||||||
|
| `09-driver-expansion.md` | 未开始 | 需要设备模型、PCI/ACPI、存储、网络等驱动扩展。 |
|
||||||
|
| `10-real-machine.md` | 未开始 | 需要 U 盘真机启动验证和硬件差异记录。 |
|
||||||
|
|
||||||
|
当前最合适的下一步仍在 `03-memory.md` 内:先补 page fault 专门诊断,再接最小内核堆。
|
||||||
|
|
||||||
## Linux 级能力缺口路由
|
## Linux 级能力缺口路由
|
||||||
|
|
||||||
这些能力不一定马上实现,但必须在路线中占位,避免后续走偏。
|
这些能力不一定马上实现,但必须在路线中占位,避免后续走偏。
|
||||||
|
|||||||
@ -19,6 +19,8 @@
|
|||||||
- trap 验证:invalid opcode 已能进入 trap dispatch 并最终进入 panic。
|
- trap 验证:invalid opcode 已能进入 trap dispatch 并最终进入 panic。
|
||||||
- 物理内存基础:已从 boot memory map 建立最小物理页 allocator。
|
- 物理内存基础:已从 boot memory map 建立最小物理页 allocator。
|
||||||
- 物理页验证:`alloc_page/free_page` selftest 已接入启动检查。
|
- 物理页验证:`alloc_page/free_page` selftest 已接入启动检查。
|
||||||
|
- 页表基础:已切换到内核自有 PML4,并提供最小 `map_page/unmap_page/virt_to_phys`。
|
||||||
|
- 页表验证:页表 map/unmap/query selftest 已接入启动检查。
|
||||||
- 构建系统已拆成根 Makefile、`arch/x86/Makefile` 和目录 Makefile。
|
- 构建系统已拆成根 Makefile、`arch/x86/Makefile` 和目录 Makefile。
|
||||||
- `scripts/check.sh` 已验证启动日志、串口日志和 invalid opcode 异常路径,GitHub Actions 已接入。
|
- `scripts/check.sh` 已验证启动日志、串口日志和 invalid opcode 异常路径,GitHub Actions 已接入。
|
||||||
- `.clang-format` 已用于强制当前 C 代码风格。
|
- `.clang-format` 已用于强制当前 C 代码风格。
|
||||||
@ -27,7 +29,7 @@
|
|||||||
|
|
||||||
- 完整日志体系:printk、log level、ring buffer、oops、符号化、crash dump。
|
- 完整日志体系:printk、log level、ring buffer、oops、符号化、crash dump。
|
||||||
- 完整中断体系:PIC/APIC、外部 IRQ、timer interrupt。
|
- 完整中断体系:PIC/APIC、外部 IRQ、timer interrupt。
|
||||||
- 内存管理扩展:长期内存区域模型、页表、page fault 策略、内核堆。
|
- 内存管理扩展:长期内存区域模型、page fault 策略、内核堆。
|
||||||
- 后续主线:调度、进程、文件系统、用户态和 shell。
|
- 后续主线:调度、进程、文件系统、用户态和 shell。
|
||||||
|
|
||||||
## 当前下一步
|
## 当前下一步
|
||||||
@ -38,7 +40,6 @@
|
|||||||
|
|
||||||
目标:
|
目标:
|
||||||
|
|
||||||
- 建立内核页表管理。
|
|
||||||
- 建立最小内核堆。
|
- 建立最小内核堆。
|
||||||
- 让 page fault 能进入现有异常路径并输出有效诊断。
|
- 让 page fault 能进入现有异常路径并输出有效诊断。
|
||||||
|
|
||||||
|
|||||||
9
drivers/README.md
Normal file
9
drivers/README.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# drivers
|
||||||
|
|
||||||
|
设备驱动目录。
|
||||||
|
|
||||||
|
后续用于放置总线、平台设备和具体硬件驱动,例如 PCI、ACPI、串口、输入设备、
|
||||||
|
块设备、网络设备和显示设备。
|
||||||
|
|
||||||
|
当前 early serial log 仍属于早期调试 backend,不迁入正式驱动模型。
|
||||||
|
|
||||||
8
fs/README.md
Normal file
8
fs/README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# fs
|
||||||
|
|
||||||
|
文件系统目录。
|
||||||
|
|
||||||
|
后续用于放置 VFS、路径解析、具体文件系统和虚拟文件系统接口。
|
||||||
|
|
||||||
|
当前阶段暂不放代码。
|
||||||
|
|
||||||
@ -1,9 +1,12 @@
|
|||||||
#ifndef TIANOLE_ARCH_H
|
#ifndef TIANOLE_ARCH_H
|
||||||
#define TIANOLE_ARCH_H
|
#define TIANOLE_ARCH_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
void arch_early_log_init(void);
|
void arch_early_log_init(void);
|
||||||
void arch_early_log_putc(char ch);
|
void arch_early_log_putc(char ch);
|
||||||
void arch_halt_forever(void) __attribute__((noreturn));
|
void arch_halt_forever(void) __attribute__((noreturn));
|
||||||
|
int arch_page_table_uses_page(uint64_t page);
|
||||||
void arch_traps_init(void);
|
void arch_traps_init(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -8,9 +8,18 @@
|
|||||||
#define PAGE_SIZE 4096u
|
#define PAGE_SIZE 4096u
|
||||||
|
|
||||||
typedef uint64_t phys_addr_t;
|
typedef uint64_t phys_addr_t;
|
||||||
|
typedef uint64_t virt_addr_t;
|
||||||
|
|
||||||
|
#define PAGE_PRESENT (1ull << 0)
|
||||||
|
#define PAGE_WRITABLE (1ull << 1)
|
||||||
|
#define PAGE_NO_EXECUTE (1ull << 63)
|
||||||
|
|
||||||
void mm_init(const boot_info_t *boot_info);
|
void mm_init(const boot_info_t *boot_info);
|
||||||
phys_addr_t alloc_page(void);
|
phys_addr_t alloc_page(void);
|
||||||
void free_page(phys_addr_t page);
|
void free_page(phys_addr_t page);
|
||||||
|
int map_page(virt_addr_t virt, phys_addr_t phys, uint64_t flags);
|
||||||
|
int unmap_page(virt_addr_t virt);
|
||||||
|
int virt_to_phys(virt_addr_t virt, phys_addr_t *phys);
|
||||||
|
void page_table_selftest(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
8
init/README.md
Normal file
8
init/README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# init
|
||||||
|
|
||||||
|
系统初始化目录。
|
||||||
|
|
||||||
|
后续用于放置内核初始化流程和第一个用户态 `init` 相关的入口组织。
|
||||||
|
|
||||||
|
当前 `kernel/main.c` 仍只负责早期启动串联。
|
||||||
|
|
||||||
8
ipc/README.md
Normal file
8
ipc/README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# ipc
|
||||||
|
|
||||||
|
进程间通信目录。
|
||||||
|
|
||||||
|
后续用于放置信号、pipe、event、futex、共享内存等 IPC 基础设施。
|
||||||
|
|
||||||
|
当前阶段暂不放代码。
|
||||||
|
|
||||||
@ -5,5 +5,6 @@ KERNEL_SRCS := \
|
|||||||
|
|
||||||
KERNEL_OBJS := \
|
KERNEL_OBJS := \
|
||||||
$(ARCH_KERNEL_OBJS) \
|
$(ARCH_KERNEL_OBJS) \
|
||||||
|
$(ARCH_MM_OBJS) \
|
||||||
$(patsubst kernel/%.c,$(BUILD_DIR)/kernel/%.o,$(KERNEL_SRCS)) \
|
$(patsubst kernel/%.c,$(BUILD_DIR)/kernel/%.o,$(KERNEL_SRCS)) \
|
||||||
$(MM_OBJS)
|
$(MM_OBJS)
|
||||||
|
|||||||
8
lib/README.md
Normal file
8
lib/README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# lib
|
||||||
|
|
||||||
|
通用库代码目录。
|
||||||
|
|
||||||
|
后续用于放置字符串、位图、链表、红黑树、校验和等可被多个子系统复用的基础设施。
|
||||||
|
|
||||||
|
当前阶段暂不放代码。
|
||||||
|
|
||||||
@ -1,5 +1,6 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <tianole/arch.h>
|
||||||
#include <tianole/early_log.h>
|
#include <tianole/early_log.h>
|
||||||
#include <tianole/mm.h>
|
#include <tianole/mm.h>
|
||||||
|
|
||||||
@ -58,6 +59,10 @@ static int page_is_reserved(const boot_info_t *boot_info, uint64_t page)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arch_page_table_uses_page(page)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,13 +79,24 @@ static void add_conventional_range(
|
|||||||
const boot_info_t *boot_info, uint64_t start, uint64_t pages)
|
const boot_info_t *boot_info, uint64_t start, uint64_t pages)
|
||||||
{
|
{
|
||||||
uint64_t page;
|
uint64_t page;
|
||||||
|
uint64_t first = align_up(start, PAGE_SIZE);
|
||||||
uint64_t end = start + pages * PAGE_SIZE;
|
uint64_t end = start + pages * PAGE_SIZE;
|
||||||
|
uint64_t last;
|
||||||
|
|
||||||
for (page = align_up(start, PAGE_SIZE); page + PAGE_SIZE <= end;
|
if (first + PAGE_SIZE > end) {
|
||||||
page += PAGE_SIZE) {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = align_down(end - PAGE_SIZE, PAGE_SIZE);
|
||||||
|
|
||||||
|
for (page = last;; page -= PAGE_SIZE) {
|
||||||
if (!page_is_reserved(boot_info, page)) {
|
if (!page_is_reserved(boot_info, page)) {
|
||||||
add_free_page(page);
|
add_free_page(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (page == first) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,4 +177,5 @@ void mm_init(const boot_info_t *boot_info)
|
|||||||
early_log_puts("\n");
|
early_log_puts("\n");
|
||||||
|
|
||||||
page_allocator_selftest();
|
page_allocator_selftest();
|
||||||
|
page_table_selftest();
|
||||||
}
|
}
|
||||||
|
|||||||
8
net/README.md
Normal file
8
net/README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# net
|
||||||
|
|
||||||
|
网络协议栈目录。
|
||||||
|
|
||||||
|
后续用于放置 socket API、协议栈、路由和网络缓冲区等网络核心代码。
|
||||||
|
|
||||||
|
当前本地 `git` 目标不要求网络,暂不放代码。
|
||||||
|
|
||||||
@ -18,7 +18,9 @@ check_lines build/debug.log \
|
|||||||
"memory map descriptors=" \
|
"memory map descriptors=" \
|
||||||
"conventional memory pages=" \
|
"conventional memory pages=" \
|
||||||
"physical pages free=" \
|
"physical pages free=" \
|
||||||
"physical page allocator selftest ok"
|
"physical page allocator selftest ok" \
|
||||||
|
"kernel page table root active" \
|
||||||
|
"page table selftest ok"
|
||||||
|
|
||||||
check_lines build/serial.log \
|
check_lines build/serial.log \
|
||||||
"kernel_main entered" \
|
"kernel_main entered" \
|
||||||
@ -28,6 +30,8 @@ check_lines build/serial.log \
|
|||||||
"memory map descriptors=" \
|
"memory map descriptors=" \
|
||||||
"conventional memory pages=" \
|
"conventional memory pages=" \
|
||||||
"physical pages free=" \
|
"physical pages free=" \
|
||||||
"physical page allocator selftest ok"
|
"physical page allocator selftest ok" \
|
||||||
|
"kernel page table root active" \
|
||||||
|
"page table selftest ok"
|
||||||
|
|
||||||
cat build/debug.log
|
cat build/debug.log
|
||||||
|
|||||||
8
security/README.md
Normal file
8
security/README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# security
|
||||||
|
|
||||||
|
安全模型目录。
|
||||||
|
|
||||||
|
后续用于放置权限、capability、隔离模型和安全策略扩展点。
|
||||||
|
|
||||||
|
当前阶段暂不放代码。
|
||||||
|
|
||||||
8
sound/README.md
Normal file
8
sound/README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# sound
|
||||||
|
|
||||||
|
音频子系统目录。
|
||||||
|
|
||||||
|
后续用于放置音频核心、设备模型和具体声卡驱动。
|
||||||
|
|
||||||
|
音频不是早期目标,当前阶段暂不放代码。
|
||||||
|
|
||||||
8
tools/README.md
Normal file
8
tools/README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# tools
|
||||||
|
|
||||||
|
宿主机侧开发工具目录。
|
||||||
|
|
||||||
|
后续用于放置需要编译或较复杂的开发辅助工具。简单脚本继续放在 `scripts/`。
|
||||||
|
|
||||||
|
当前阶段暂不放代码。
|
||||||
|
|
||||||
8
usr/README.md
Normal file
8
usr/README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# usr
|
||||||
|
|
||||||
|
用户空间构建和初始用户程序目录。
|
||||||
|
|
||||||
|
后续用于放置 initramfs 内容、最小用户态程序、shell 和基础工具。
|
||||||
|
|
||||||
|
当前阶段暂不放代码。
|
||||||
|
|
||||||
8
virt/README.md
Normal file
8
virt/README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# virt
|
||||||
|
|
||||||
|
虚拟化支持目录。
|
||||||
|
|
||||||
|
后续如果需要支持虚拟化相关接口、虚拟设备框架或 guest/host 特性,可以放在这里。
|
||||||
|
|
||||||
|
当前阶段暂不放代码。
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user