0%

xv6 boot 启动过程

xv6 采用 qemu 作为运行平台,其 qemu 运行选项如下:

  • -machine virt: 机器类型设置为 RISC-V VirtIO board
    • virt 没有任何网络和存储设备,需要自己定义
    • 当指定机器类型为 sifive_u 或 virt 时,有三种不同的 bios 选项: default/none/<filename>
  • -bios none: 设置 BIOS 文件名
    1. default RISC-V qemu bios 的默认项,即自动加载默认的 OpenSBI firmware (包含在 QEMU 中),用户只需要指定内核文件
    2. none 表示 qemu 不会自动加载任何 firmware,由用户负责加载需要的所有的镜像
    3. 其他 则表示 firmware 文件名
  • -kernel $K/kernel: 设置内核映像
    • 要求镜像是 Linux 内核映像或者是 multiboot 格式
  • -m 128M: guest memory 大小为 128MB
  • -smp $(CPUS): 设置 CPU 核数
  • -nographic: 关闭图像输出,将串口 I/O 重定向到终端
  • -global virtio-mmio.force-legacy=false: 设置 virtio-mmio 驱动的 force-legacy 属性全局默认为 false
  • -drive file=fs.img,if=none,format=raw,id=x0: 设置 fs.img 作为 drive 的映像文件,输入文件类型 if=none, format=raw, 设置 id=x0
  • -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0: 添加设备 virtio-blk-device, 并设置该设备的属性 drive 为 x0, bus 为 virtio-mmio-bus.0
  1. power on : qemu 启动,cpu pc 设置到 kernel 的 _entry 处(0x80000000)
  • 初始化
  • 运行 boot loader
    • 存储于 ROM
    • 将 xv6 kernel 加载到内存中(地址: 0x80000000
      0x0:0x80000000 中包含 IO 设备的地址空间
  • 进入 xv6 entry point

xv6 entry

  1. _entry (in kernel/entry.S)
    1. 为当前硬件线程设置: 设置 initial stack 栈顶指针 sp = stack0 + 4096 * (hartid + 1)
      • stack0 表示第 0 个栈的栈底 (in kernel/start.c)
    2. 进入 start 函数
  2. start (in kernel/start.c)
    准备切换到 supervisor mode
    • 将 mastatus 中的 MPP 置为 supervisor mode
    • main 函数地址写入 epc 寄存器
    • 设置 satp mode 为 Bare mode
    • 将所有的异常和中断转交 supervisor mode 处理
    • 配置物理内存保护: pmpaddr0, pmpcfg0
    • 编程时钟芯片以生成时钟中断: timerinit()
      • 置位 mie.STIE :允许时钟中断 (事实上不需要,因为之前对 sie 的写入同样会影响到 mie)
      • 使能 sstc 扩展(stimecmp): menvcfg
      • 允许 S mode 使用 stimecmptime csr : mcounteren
      • 请求第一个时钟中断:设置 stimecmp
    • 执行 mret (以 supervisor mode 跳转到 main 函数)
  3. main (in kernel/main.c)
    1. 初始化设备和子系统
    2. 创建第一个进程
      • userinit in kernel/proc.c
  4. 第一个进程 user/initcode.S
    1. 将 exec 系统调用号加载到 a7 寄存器
    2. 调用 ecall 重新进入内核
    3. 内核执行 exec 系统调用 in kernel/syscall.c
    4. 返回用户空间,此时进程为 /init in user/init.c
      1. 创建新的设备文件 console
      2. 打开文件描述符0(console), 1(stdout), 2(stderr)
      3. 在 console 中启动 shell

系统正式启动。