xv6内核boot流程(参考)
发布于 • 作者: Ethan
main() 由 start() 在所有 CPU 的 supervisor 模式下进入;
根据 cpuid() 判断当前是否为引导 CPU(cpuid()==0)或其它 CPU(cpuid()!=0)。
cons.lock)。uartinit()),为串口 I/O 做准备。devsw[CONSOLE],使得读写系统调用能够通过 console 实现。main() 中仅在 LAB_LOCK 条件编译下调用。defs.h),未包含实现文件,因此无法从源码进一步展开具体逻辑。printf 相关的全局锁 pr.lock。"xv6 kernel is booting"。kmem.lock。[end, PHYSTOP) 物理内存范围逐页释放到空闲链表(调用 freerange(),进而 kfree()),使页分配器可用。kvmmake() 创建内核页表,并保存到全局 kernel_pagetable。kvmmake() 内部:
proc_mapstacks())。sfence_vma(),等待页表写入完成并清除旧 TLB 条目。satp 为内核页表并再次 sfence_vma(),从而在当前 CPU 上开启分页。wait 锁。proc[] 表,为每个 proc 初始化锁、状态为 UNUSED,并预计算内核栈虚拟地址。tickslock,用于保护 ticks 计数。stvec 指向 kernelvec,建立当前 CPU 的内核态 trap 向量入口。LAB_NET),为 PCIe 中断范围设置优先级。LAB_NET 下额外开启更多 IRQ 位供 e1000 使用。bcache.lock。itable.lock。ftable 的自旋锁。vdisk_lock。ACKNOWLEDGE、DRIVER、FEATURES_OK、DRIVER_OK 状态位。desc / avail / used),配置队列地址并设置队列为 ready。0x100e8086)。0x40000000,并调用 e1000_init() 进行设备初始化。netlock。allocproc() 分配一个新的进程结构,并保存到全局 initproc。cwd 设为根目录(namei("/"))。RUNNABLE,然后释放该进程锁,使其可被调度执行。main() 中在 KCSAN 条件编译下调用。defs.h 看到声明,仓库中未包含实现文件,无法进一步展开具体逻辑。started = 1,释放其它 CPU 从自旋等待中继续启动。started 变为 1,确保引导 CPU 完成全局初始化后再继续。printf("hart %d starting\n", cpuid());satp 为内核页表并刷新 TLB,从而开启分页。stvec 为 kernelvec。LAB_NET 下的更多 IRQ)。main() 中条件调用。statsinit)。LAB_LOCK 相关配置里,但无法进一步展开实现细节。调度器进入无限循环。
在每轮中打开 / 关闭中断以避免死锁与竞态。
遍历进程表查找 RUNNABLE 进程。
当找到可运行进程时:
RUNNING。如果没有可运行进程:
wfi 进入低功耗等待中断。