内容
三阶段的项目我选择了Rust for Linux驱动开发方向。
具体内容是用Rust重写PL011串口驱动,并能通过跨内核驱动框架,使驱动在arceos和linux运行
这次的项目基于Raspi4b or Raspi3b in Qemu进行开发。
我使用的开发的仓库地址是(R4L_DRV)[https://github.com/Oveln/R4L_DRV]
练习部分
内容
练习部分分三个
- 用Rust for Linux写一个简单的杂项设备驱动,能做到输入和输出
- 用跨内核驱动框架,实现一个设备驱动,能控制Raspi4b上的某个引脚,从而控制LED的亮灭
遇到的困难
此前我完全没有接触过驱动的编写,对硬件的原理知之甚少。经过很长一段时间的RTFM,以及了解硬件编程相关的知识。
同时对Linux设备驱动相关的内容也进行了比较充足的了解。
收获
练习部分的收获主要是
- 第一次接触了Linux的设备驱动,对文件树中的/dev/xxx的设备文件有了认知
- 更加明白了什么叫Every thing is File
- 稍微看的懂电路原理图了x
- 对很长的文档的恐惧逐渐消退
实战部分:使用Rust重写PL011驱动
问题一
串口驱动的内容相较于简单的GPIO繁琐且复杂,需要我进一步的了解Linux的串口子系统tty-uart_driver-uart_port相关的注册关系。
在经过一些努力
- RTFS
- 找网上的资料学习(特别感谢野火的文档教程
这个问题逐渐的被解决了
问题二
Rust for Linux经过数年的发展,在某些方面有了完备的抽象。但这次项目所涉及的uart_driver、uart_port、console等结构体没有被支持。
这个问题没什么简单的办法,在Rust for Linux社区中也没有找到好的实现。只能自己做。
如何抽象函数指针
比如,在uart_port中有很多void*类型的函数指针,如何对这些函数指针进行良好的Rust抽象就成了一大问题。
我在R4L的代码中找到的解决方案是
1 | struct ops { |
以上代码可以通过Rust进行如下封装
1 | pub struct OperationsVtable<T>(marker::PhantomData<T>); |
现在的成果和收获
对Linux的C代码中的serial_core.h中的uart_driver和uart_port以及console做了比较完整的抽象。
我也能够比较好的使用Rust中的Pin使数据固定在内存上的某个地方了。