xv6-k210/doc/report_2020_12_26.md

10 KiB
Raw Permalink Blame History

marp
true

xv6-k210 移植报告

  • 报告人: 车春池
  • 华中科技大学本科三年级
  • 时间: 2020-12-26
  • 地点: 北京中科院计算所
 (`-')           (`-')                   <-.(`-')                            
 (OO )_.->      _(OO )                    __( OO)                            
 (_| \_)--.,--.(_/,-.\  ,--.    (`-')    '-'. ,--.  .----.   .--.   .----.   
 \  `.'  / \   \ / (_/ /  .'    ( OO).-> |  .'   / \_,-.  | /_  |  /  ..  \  
  \    .')  \   /   / .  / -.  (,------. |      /)    .' .'  |  | |  /  \  . 
  .'    \  _ \     /_)'  .-. \  `------' |  .   '   .'  /_   |  | '  \  /  ' 
 /  .'.  \ \-'\   /   \  `-' /           |  |\   \ |      |  |  |  \  `'  /  
`--'   '--'    `-'     `----'            `--' '--' `------'  `--'   `---''   

前言

  • xv6xv6-riscvMIT 写的教学操作系统,在 github 上开源
  • xv6 官方目前只支持 qemu 平台
  • k210kendryte 产商于 2018 年发布的 RISC-V 双核 64 位处理器
  • RustSBI:华科网安同学 洛佳 提供的强大的 Rust 嵌入式项目,为移植工作提供很大帮助

当前成果

run


运行流程

  • 需要RISC-V 编译链,用它来编译二进制内核镜像,可以是 riscv64-unknown-elf 或者 riscv64-linux-gnu
  • 需要搭载 k210 芯片的开发板: Maixpy 系列,淘宝有售
  • SD 卡:可选,如果不跑文件系统的话
  • github 上获得项目源码: git clone https://github.com/SKTT1Ryze/xv6-k210
  • 用读卡器把 SD 卡连接到电脑
  • 进入到 xv6-k210 目录下运行命令 make sdcard,然后 Makefile 会打包一个文件系统镜像写入到 SD 卡
  • 将 SD 卡插到 k210 板子上,并用 type-C 线连接 k210 板子到电脑上
  • xv6-k210 目录下运行命令 make run
  • 查看 USB 端口: ls /dev/ | grep USB

K210

  • 两个核心,双核对等,具备独立 FPU
  • 64 位处理核
  • 标称频率为 400MHZ
  • 双精度浮点处理单元
  • PLIC 支持高级中断管理
  • CLINT 支持 CPU 内置定时器中断与跨核心中断
  • 8M 的片上 SRAM

K210 SRAM

模块名称 映射类型 开始地址 结束地址 空间大小
通用 SRAM 存储器 经 CPU 缓存 0x80000000 0x805FFFFF 0x600000
AI SRAM 存储器 经 CPU 缓存 0x80600000 0x807FFFFF 0x200000
通用 SRAM 存储器 非 CPU 缓存 0x40000000 0x405FFFFF 0x6000000
AI SRAM 存储器 非 CPU 缓存 0x40600000 0x407FFFFF 0x200000

K210 VS QEMU

  • 指令集标准版本不同qemu 是 v1.11k210 是 v1.9.1
  • MMIO 内存布局不同
  • 虚拟文件系统 vs SD 卡上的文件系统

RustSBI

  • 脱胎于 2020 年暑假鹏城实验室的“rCore代码之夏”活动
  • 操作系统二进制接口标准SBI 标准)的一种实现
  • Rust 语言编写
  • 模块化设计,方便支持新的平台
  • 进入国际 RISC-V SBI 实现列表,获得编号 4
Implementation ID Name
0 Berkeley Boot Loader (BBL)
1 OpenSBI
2 Xvisor
3 KVM
4 RustSBI
5 Diosix

移植工作一览

  • 多核启动
  • 内存分配
  • 虚拟内存管理
  • 中断处理
  • S 态外部中断
  • 用户多进程
  • SD 卡驱动
  • 文件系统
  • 软硬件协同调试
  • 中文文档

多核启动

  • 链接脚本 k210.ld调整内核镜像布局和指定内核入口点
  • RustSBI 将处理器核从 M 态切换到 S 态,然后跳转到内核起始地址
  • entry_k210.S操作系统内核运行的第一段代码对应链接脚本中的内核入口点
  • main.c:进入 supervisor 模式S 态)
  • RustSBI 提供接口,使得可以在启动的第 0 个核中唤醒其他核

多核启动

boot


内存分配

  • kalloc.c
  • 可分配的内存空间范围:kernel_end ~ PHYSTOP
  • 内存分配初始化void kinit(),初始化锁,开拓内存空间
  • void* kalloc()4096 字节
  • 内核维护一个链表:空闲链表

虚拟内存管理

  • vm.c
  • 维护一个内核页表 kernel_pagetable
  • 在 void kvminit() 里面进行内核空间虚拟地址到物理地址的映射
  • 进行 MMIO内核空间用户态空间 RustSBI 等内存空间的映射
  • 在 void kvminithart() 里面将内核页表的首地址放到 satp 寄存器,然后运行 sfence.vma 指令

虚拟内存管理

但是!! K210 采用的是 1.9 版本的 RISC-V 标准,不存在 sfence.vma 这条指令,只有旧版指令 sfence.vm
怎么办?求助 RustSBI


虚拟内存管理

RustSBI 如何解决这个问题?

  • sfence.vma 作为异常指令被 RustSBI 捕获
  • 读取 satp(读取 ppn
  • 根据第二步读取的值写 sptbr v1.9 指令集版本使用的寄存器,相当于 satp)设置页表
  • 设置 mstatus 中相应的位开启分页(内核无法做这个工作)
  • 运行旧版指令 sfence.vm 清空 TLB
  • mepc 并返回到 sfence.vma 的下一条指令去运行(mepc + 4

虚拟内存管理

mem_map


中断处理

  • trap.c
  • void kerneltrap()S 态中断或异常陷入这个函数,在这里处理或者转发
  • void usertrap()U 态中断或异常陷入这里
  • int devintr():判断中断的来源(比如时钟中断返回 2

中断处理

中断处理初始化工作:

  • void trapinithart()
  • kernelvec 地址写入到 stvec
  • kernelvec 函数在 kernelvec.S 汇编文件里面,保存上下文,进入 kerneltrap,恢复上下文,返回
  • 设置 sstatus.sie
  • 设置 sie 开启外部中断,时钟中断和软件中断

时钟中断

通过 RustSBI 设置时钟中断

  • timer.c
  • 参考 rCore 实现
  • void set_next_timeout():设置下一次时钟中断的时间
  • void timerinit():初始化时钟中断
  • void timer_tick():触发时钟中断的时候进入这里,这里也会设置下一次时钟中断
  • 神奇的 bugset_next_timeout 中的 printf("");

S 态外部中断

以下参考吴一凡学长的文档,如有雷同,纯属照搬。
为什么需要移植 S 态外部中断?

  • RustSBI 运行在 M 态OS 内核运行在 S 态
  • 想要使用 S 态众多的数据结构来对外部中断进行处理

移植 S 态外部中断遇到的问题:k210 上没有 S 态外部中断!
怎么办?
求助 RustSBI


S 态外部中断

RustSBI 使用黑科技解决 K210 上 S 态外部中断 感谢吴一凡学长移植 rCorek210 上的文档和洛佳同学的解惑。
不敢班门弄斧,只说一下步骤:

  • RustSBI 提供一个接口
match cause {
        Trap::Exception(Exception::SupervisorEnvCall) => {
            if trap_frame.a7 == 0x0A000004 && trap_frame.a6 == 0x210 {
                // We use implementation specific sbi_rustsbi_k210_sext function (extension 
                // id: 0x0A000004, function id: 0x210) to register S-level interrupt handler
                // for K210 chip only. This chip uses 1.9.1 version of privileged spec,
                // which did not declare any S-level external interrupts. 
                ...
            } else {
                ...
        }}}
  • S 态外部中断处理函数 supervisor_external_handler
  • 将这个函数指针作为参数调用 RustSBI 提供的接口
  • 外部中断将会在 supervisor_external_handler 中处理

用户多进程

  • proc.c & trap.c & trampoline.S & swtch.S
  • 内核维护一个进程队列
  • 每个进程拥有独立的页表和独立的用户态空间
  • 在 scheduler() 进行进程调度
  • 通过 swtch(struct context*, struct context*) 进行上下文切换
  • 每次时钟中断内核会调用 yield() 函数,这个函数里面调用 swtch 进行进程切换
  • 双核跑多进程
  • 目前的用户进程是写死在内核里面的,后面文件系统移植好了才能真正意义上跑用户进程
  • 移植文档: https://github.com/SKTT1Ryze/xv6-k210/wiki/Process-Management

用户多进程

proc


SD 卡驱动

  • sdcard.c
  • 官方 SDK demo 实现了读取 sd 卡的例程
  • 暴力出奇迹,移植官方 SDK 到内核中
  • 问题:官方 SDK 编译链不同,代码太多,依赖关系复杂
  • 通过 SPI 协议与 SD 卡通信
  • 和很多外设打交道,比如 GPIOFPIO 等等,还需要调整时钟信号
  • 最终将官方 SDK 部分模块移植到了内核中,成功通过 SD 卡读取测试
  • SD 卡读写还不稳定
  • C 开发环境缺乏包管理工具

文件系统

  • 由于 SD 卡读写不稳定的问题还没解决,还没完成
  • xv6 文件系统 or Fat32 文件系统 or 全都要

软硬协同调试

  • 硬件调试非常非常麻烦,希望有软件调试环境
  • Makefile + 条件编译
  • make run [platform=xxx]
  • 类似于封装硬件抽象层
  • RustSBI 基本上处理了大部分平台无关性
  • 软件调试,一键部署

依赖于 RustSBI 的模块

  • 多核启动
  • 内存分配
  • 虚拟内存管理(sfence.vma 指令)
  • 时钟中断
  • S 态外部中断(其实有 bug 还没修)
  • 用户多进程
  • SD 卡驱动
  • 文件系统
  • 平台无关性

中文文档

  • 移植文档
  • xv6-riscv 原理文档

致谢

  • 感谢比赛方和陈渝老师提供这次演讲机会,并且感谢邵志远老师一直以来对我的支持
  • xv6-k210 项目得到了很多同学的支持,特别是华科 18 级计卓班的刘一鸣和陆思彤同学,进程管理这部分的调试工作大部分是他们在做
  • 感谢 RustSBI 项目
  • 感谢 rCore-Tutorial 项目和今年暑假在鹏城实验室的代码之夏活动,让我踏入了 Rust 语言和体系结构的大门
  • 感谢洛佳同学和吴一凡学长技术上的帮助

谢谢各位

华中科技大学
计算机科学与技术学院
校交 1801 班 车春池