Skip to content

Commit

Permalink
Merge pull request #480 from Oveln/master
Browse files Browse the repository at this point in the history
三阶段blog
  • Loading branch information
ZhiyuanSue authored Jun 30, 2024
2 parents 97c468c + 373928d commit 157dd15
Showing 1 changed file with 119 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
---
title: 2024秋冬季开源操作系统训练营第三阶段总结报告_郑昱可
date: 2024-06-29 15:33:10
categories:
- report
tags:
- Oveln
- 2024春夏季开源操作系统训练营
- 第三阶段
---
# 内容

三阶段的项目我选择了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的代码中找到的解决方案是

```c
struct ops {
void* print_int(int)
void* print_char(char)
}
```

以上代码可以通过Rust进行如下封装

```rust
pub struct OperationsVtable<T>(marker::PhantomData<T>);
pub trait Ops {
fn print_int(x: i32);
fn print_char(x: char);
}
impl<T: Ops> OperationsVtable<T> {
unsafe extern "C" fn print_int(x: c_int) {
T::print_int(x);
}
unsafe extern "C" fn print_char(x: c_char) {
T::print_char(x);
}

const VTABLE: bindings::ops = bindings::ops {
print_int: Some(Self::print_int),
print_char: Some(Self::print_char)
};

pub(crate) unsafe fn build() -> *const bindings::ops {
&Self::VTABLE as *const _
}
}

// 在定义了上面三段后就可以定义一个自己的Ops

struct MyOps;

impl Ops for MyOps {
...
}

// 之后想要得到MyOps的对应的C的ops结构体只需要

let ops = OperationsVtable<MyOps>::build();

```


## 现在的成果和收获

对Linux的C代码中的serial_core.h中的uart_driver和uart_port以及console做了比较完整的抽象。

我也能够比较好的使用Rust中的Pin使数据固定在内存上的某个地方了。

0 comments on commit 157dd15

Please sign in to comment.