2022-06-26 update

This commit is contained in:
shzhxh 2022-06-26 21:34:14 +08:00
parent 80d69f4cd1
commit b82f6c6e1d
15 changed files with 236 additions and 48 deletions

1
Data-Structure/readme.md Normal file
View File

@ -0,0 +1 @@
数据结构从根本上来说是由现实世界的规律所决定的,它之所以是那个样子,是因为它只能是那个样子。

View File

@ -1,24 +0,0 @@
参考自[CSDN博客_Mr.Phoebe](http://blog.csdn.net/u013007900/article/details/50408903)
1. 8253芯片是可编程计数器/计时器(Counter/Timer)。因为计时和计数的本质是相同的,所以即可以叫计时器也可以叫计数器。
2. 内部有三个完全相同的计数器分别是计数器0计数器1,计数器2.
3. 端口号由引脚A1和A0确定。如果计数器0端口号为0x40则计数器1为0x41,计数器2为0x42,控制端口为0x43。
4. 8253编程的两条原则
* 必须先将控制字写入控制寄存器即0x43端口。
* 其次向计时器写入初值,初值必须符合控制字的规定。
5. 控制字有8位只能写入不能读出。
| D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
| --- | --- | --- | --- | -- | -- | -- | --- |
| SC1 | SC0 | RW1 | RW0 | M2 | M1 | M0 | BCD |
* D0计数码选择。决定计数器在减1过程中采用的进位制0表示二进制1表示BCD计数制。
* D3D2D1工作方式选择。
* 000:Interrupt on Terminal Count(计数结束产生中断)
* 001:Hardware Retriggerable one-shot(可编程单稳态触发器)
* 010:Rate Generator(分频器)
* 011:Square Ware Mode(方波发生器)
* 100:Software Triggered Strobe(软件触发选通脉冲)
* 101:Hardware Triggered Strobe(硬件触发选通脉冲)
* D5D4:读写格式控制。01,只读写低8位。10,只读写高8位。11,先读写低8位后读写高8位。00,把当前计数值存入输出锁存器,供以后读取。
* D7D6计数器选择。00,选择计数器0。01,选择计数器1。10,选择计数器2。11,在8253中为非法编码在8254中用于读回命令。
![8253](_img/8253timer.jpg)

56
Hardware/timer.md Normal file
View File

@ -0,0 +1,56 @@
#### 参考资料
- [CSDN博客_Mr.Phoebe](http://blog.csdn.net/u013007900/article/details/50408903)
- 《操作系统的设计与实现》
#### 概述
计时器也叫时钟必须有它才能进行分时系统timesharing system )的操作。
在计算机里使用了两种时钟,和人们通常使用的钟表有很大的不同。
第一种已经在现代PC里灭绝了。它直接使用的220V或110V交流电的频率大概50~60Hz产生一个中断。
第二种是可编程时钟。它由三部分组成晶体振荡器计数器和保持寄存器。晶体振荡器就是一块被精确切割的石英晶体加上电压后它就会产生极为精确的周期性信号频率一般在5~200 MHz。计数器里的值随着这个周期性信号递减保持寄存器用于记录计数器的值。当计数器到0之后就会触发CPU中断。计算机里高于200MHz的频率一般是通过分频电路实现的。
可编程时钟的模式:
- 单次模式(one-shot mode)
当时钟启动它先把保持寄存器的值复制到计数器然后计数器的值开始递减。当计数器的值为0则产生一个中断然后时钟停止。直到有软件显式地启动时钟它才再次进行上述流程。
- 方波模式(square-wave mode)
相较于单次模式当计数器为0产生中断后自动把保持寄存器的值复制到计数器这样整个流程就可以独立地重复下去。这些周期性的中断就叫**时钟滴嗒**(clock ticks)。
可编程时钟的的优势就是可以通过软件控制中断的频率。可编程时钟芯片里通常包含2~3个独立的可编程时钟这些时钟还有其它的选项比如用计数递增取代递减屏蔽中断等
当计算机关机后会使用由电池驱动的备份时钟来防止时间丢失。如果没有备份时钟软件也可能向用户询问当前时间。联网的系统还可以从远程主机上获取当前时间。最终时间都被转换为UTC。然后运行的系统就给时钟滴嗒计数每过一秒就给真实时间加一。关于系统时钟和备份时钟同步的问题一般是通过应用程序来手动设置的。
除了最早期的IBM PC所有的计算机都有独立的时钟电路来为CPU、内部数据总线和其它部件提供timing siganls。这个时钟提供了人们所说的CPU时钟速度。
#### 8253芯片
1. 8253芯片是可编程计数器/计时器(Counter/Timer)。因为计时和计数的本质是相同的,所以即可以叫计时器也可以叫计数器。
2. 内部有三个完全相同的计数器分别是计数器0计数器1,计数器2.
3. 端口号由引脚A1和A0确定。如果计数器0端口号为0x40则计数器1为0x41,计数器2为0x42,控制端口为0x43。
4. 8253编程的两条原则
* 必须先将控制字写入控制寄存器即0x43端口。
* 其次向计时器写入初值,初值必须符合控制字的规定。
5. 控制字有8位只能写入不能读出。
| D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
| --- | --- | --- | --- | -- | -- | -- | --- |
| SC1 | SC0 | RW1 | RW0 | M2 | M1 | M0 | BCD |
* D0计数码选择。决定计数器在减1过程中采用的进位制0表示二进制1表示BCD计数制。
* D3D2D1工作方式选择。
* 000:Interrupt on Terminal Count(计数结束产生中断)
* 001:Hardware Retriggerable one-shot(可编程单稳态触发器)
* 010:Rate Generator(分频器)
* 011:Square Ware Mode(方波发生器)
* 100:Software Triggered Strobe(软件触发选通脉冲)
* 101:Hardware Triggered Strobe(硬件触发选通脉冲)
* D5D4:读写格式控制。01,只读写低8位。10,只读写高8位。11,先读写低8位后读写高8位。00,把当前计数值存入输出锁存器,供以后读取。
* D7D6计数器选择。00,选择计数器0。01,选择计数器1。10,选择计数器2。11,在8253中为非法编码在8254中用于读回命令。
![8253](_img/8253timer.jpg)

View File

@ -2,6 +2,7 @@
- 可以在运行时配置I/O设备
- 让主要的系统组件成为与内核分开的独立进程
- 把功能都放到用户进程
#### 重要概念
@ -72,18 +73,33 @@
sys_vircopy, sys_physcopy使用虚拟或物理地址复制内存。
sys_virvcopy, sys_physcopy使用向量化的I/O请求它们可以向系统任务请求一系统的内存复制操作。
sys_virvcopy, sys_physcopy使用向量化的I/O请求它们可以向系统任务请求一系统的内存复制操作。把多个消息请求打包成一个消息可以从一定程度上解决消息传递机制的效率不足问题。
- 其它
sys_times对应了`times`系统调用。
sys_setalarm与`alarm`系统调用相关。
sys_setalarm与`alarm`系统调用相关。为用户空间的系统进程初始化计时器这个系统进程需要接收一个同步alarm并在计时器超时的时候通知到用户进程。
sys_abort当要求关闭系统或产生panic之后进程管理器会产生此内核调用当用户按下`Ctrl-Alt_Del`组合键后tty设备驱动也会产生此内核调用。
sys_getinfo获取内核的信息。在`include/minix/syslib.h`里定义了获取内核信息的各种宏,它们都是使用的此内核调用。
##### 时钟驱动程序提供的与时间相关的服务
| 服务 | 访问方式 | 响应 | 使用者与功能描述 |
| ----------- | -------- | ---- | ---------------------------------------- |
| get_uptime | 函数调用 | 滴嗒 | 内核或系统任务,获取运行时间 |
| set_timer | 函数调用 | 无 | 内核或系统任务,设置计时器 |
| reset_timer | 函数调用 | 无 | 内核或系统任务,重置计时器 |
| read_clock | 函数调用 | 计数 | 内核或系统任务,读取时钟芯片里的计数器 |
| clock_stop | 函数调用 | 无 | 内核或系统任务恢复BIOS的时钟频率 |
| 同步alarm | 系统调用 | 通知 | 服务程序或驱动程序,激活内核空间的看门狗 |
| POSIX alarm | 系统调用 | 信号 | 用户进程通过PM请求系统任务激活看门狗 |
| time | 系统调用 | 消息 | 任何进程通过PM |
#### 进程调度
Minix3使用的多级调度算法。具体过程是先找到优先级最高的非空的队列然后选择顶头的进程开始执行。`IDLE`进程在最低优先级队列里,且始终是处于就绪的状态,这就保证没有其它进程时至少还有一个进程可以跑。
@ -108,10 +124,63 @@ Minix3使用的多级调度算法。具体过程是先找到优先级最高
#### 系统任务
系统任务是从内核中独立出来的进程,它不能像内核函数那样自由不能进行实际的I/O也不能操作内核表。
驱动和服务程序是从内核中独立出来的若干进程,它们不能像内核函数那样自由不能进行实际的I/O也不能操作内核表。
那么系统任务(驱动和服务程序)怎么和内核交互呢?答案是内核向它们提供一组服务。这些服务对普通用户是不可见的,系统任务通过这些服务进行实际的I/O操作内核表等。
那么驱动和服务程序怎么和内核交互呢?答案是内核向它们提供一组服务。这些服务对普通用户是不可见的,驱动和服务程序通过这些服务进行实际的I/O操作内核表等。
系统任务的工作就是就是接收上层对内核服务的请求并执行它们。上层的进程由于在用户态,无法访问内核里的数据结构,但系统任务可以。
系统任务的工作就是就是接收上层(驱动和服务程序)对内核服务的请求并执行它们。上层的进程由于在用户态,无法访问内核里的数据结构,但系统任务可以。
系统任务的主程序在做完必要的初始化后就会进入一个循环。获取消息,发给合适的服务例程,然后发送一个回复。主文件`system.c`里有一些的通用支持函数,但处理内核调用是在`kernel/system`目录下进行的。
系统任务的主程序在做完必要的初始化后就会进入一个循环。在循环里,它获取消息,发给合适的服务例程,然后发送一个回复。主文件`system.c`里有一些的通用支持函数,但处理内核调用是在`kernel/system`目录下进行的。
#### read系统调用在整个系统里的流程
1. 用户进行`read`调用,其实就是向文件系统发了一个消息。
2. 文件系统检查缓存区看有没有它需要的块,如果没有则向磁盘驱动程序发消息来把它需要的块加载到缓存区。
> 磁盘驱动程序的流程:
>
> 向系统任务发消息要求执行I/O指令。系统任务回复ACK消息。磁盘中断发生系统任务向等待中的驱动程序报告此消息。驱动程序向系统任务发消息要求把数据复制到文件系统的缓存区。系统任务发送回复消息。磁盘驱动程序向文件系统发消息报告数据已就绪。
3. 文件系统向系统任务发消息,告诉它把块复制给用户进程。
4. 系统任务向文件系统回复消息。文件系统向用户回复消息。
#### 时钟任务
时钟任务有点像驱动程序,也是由中断来驱动的,但它即不是块设备也不是字符设备。时钟的接口并不是`/dev`目录下的某个文件,事实上用户空间的进程是不能直接访问时钟的。用户空间的进程想要访问时钟任务只能通过系统任务才行。时钟任务进行在内核空间,可以访问内核里所有的函数和数据。
时钟驱动程序应包含的功能:
1. 维护一天中的时间。
在每一次时钟滴嗒,只要给一个计数器执行递增操作即可。
2. 防止某些进程运行太长时间。
当进程开始的时候调度程序就给一个计数器初始化一个值。时钟驱动让这个计数器递减。当递减到0时时钟驱动调用调度程序来运行其它进程。
3. 统计CPU使用率。
最精确的方法是使用第二个计数器;一个不太精确但更简单的方法是,在进程表里记录时钟滴嗒。
4. 处理从用户进程来的`alarm`系统调用。
进程可以要求操作系统在一段时间间隔后给它发warning。这个warning一般是信号、中断、消息等之类的东西。一个使用`alarm`的例子是,网络里的包在超时后必须重发。
时钟驱动程序必须从一个物理时钟上模拟出多个虚拟时钟。
5. 为系统它自己的某些部分提供看门狗计时器。
时钟驱动管理看门狗计时器的机制和管理用户信号是一样的。唯一不同的是,当计时器触发时,不是产生信号,而是执行一个由调用者提供的例程。
6. 概要分析、监控和收集统计数据。
驱动程序检查当前时程是否在进行概要分析若是则计算当前程序计数器的bin号(一段地址范围)然后对该bin值加1.
#### alarm系统调用在整个系统里的流程
1. 用户进程发出alarm系统调用请求设置一个alarm。
2. 进程管理器处理此请求。具体是设置一个计时器,并把该计时器插入到计时器列表中。
3. 当计时器列表里第一个计时器超时的时候,进程管理器要求系统任务向它发一个通知。
4. 要执行的例程在进程管理器的地址空间,在执行完后,会向用户进程发一个信号。

View File

@ -4,14 +4,16 @@
make rv64-image # 从Makefile可见是使用rcore-fs-fuse命令创建文件系统riscv64.img文件系统的内容来自于rootfs目录。
cd zCore && make build linux=1 arch=riscv64 # 从Makefile可见最终执行的是cargo build $(build_args)
# $(build_args)默认自带-Z build-std=core,alloc --target $(arch).json还会附加其它参数这是由make build的参数引入的比如linux=1会引入--features linux比如arch=riscv64且没有指定board的值会引入--features board_qemu等
# $(arch).json指定了链接脚本对于riscv64它是linker64.ld对于x86_64它是linker.ld在链接脚本里指定内核入口点为_start
# $(arch).json指定了链接脚本对于riscv64它是linker64.ld对于x86_64它是linker.ld对于aarch64它是linker.ld在链接脚本里指定内核入口点为_start
```
#### 执行过程
##### _start
对于riscv64入口点`_start`定义在`entry64.asm`,通过`global_asm!`把这段汇编代码嵌入到`entry.rs`。从`_start`开始先设置`satp`寄存器以映射虚拟地址,然后在虚拟空间里设置`sp`寄存器,跳转到`rust_main`。
对于riscv64入口点`_start`定义在`entry.rs`,然后跳转到`primary_rust_main`进到rust代码里执行`primary_rust_main`再调用`primary_main`。
对于aarch64入口点`_start`定义在`entry.rs`,它的下一个跳转点是`rust_main`进到rust代码里执行`rust_main`再调用`primary_main`。
对于x86_64入口点`_start`定义在`entry.rs`,它准备好相关参数,最后跳转到`primary_main`。

View File

@ -200,6 +200,21 @@ vim /etc/asound.conf
pacman -S gst-plugins-base gst-plugins-bad gst-plugins-good gst-plugins-ugly gst-libav
```
#### 获取源码
```
# abs是Arch Build System可以通过它获取源码
sudo pacman -S base-devel abs
sudo abs # 下载abs树
sudo abs [package_name]
# 可以通过pacman -Qo命令查找一个程序所属的包
cp -r /var/abs/[package_name] /mydir
cd /mydir
makepkg -os # 获取源码,不进行构建
```
#### 使用AUR
```

View File

@ -26,6 +26,7 @@ git branch <--edit-description> [branchname]
#### 选项
```
-a, --all # 把本地分支和远程追踪的分支都列出来。
-c, --copy # 复制分支和相关的reflog
-C # 等价于--copy --force强制复制分支
-d, --delete # 删除分支

View File

@ -4,13 +4,25 @@
#### 语法
```
git fetch [options] [<repo> [refspec ...]] # 从单个仓库获取分支
# 如没有指定<repo>则默认为origin
git fetch [options] <group> # 从多个仓库获取分支这些仓库定义在配置文件的remotes.<group>
git fetch --multiple [options] [<repo | group> ...] # 从多个<repo><group>获取分支
fit fetch --all [options] # 从所有的remotes里fetch
```
#### 选项
```
--all
--all # 从所有的remotes里fetch
-a, --append
--depth
--deepen
--multiple # 允许指定多个<repo><group>
-p, --prune # 在fetching之前删除所有和远程没有对应关系的引用。
--shallow-since
--shallow-exclude
--unshallow
@ -18,3 +30,8 @@
... ...
```
#### 示例
```
```

View File

@ -3,7 +3,7 @@ git lfs <command> [args] # 在git仓库里管理大文件
# 注此子命令需单独安装sudo apt install git-lfs
```
高层命令
#### 高层命令
```shell
install # 安装配置
@ -15,12 +15,12 @@ pull # 从远程获取LFS文件。相当于先执行git lfs fetch再执行git
track # 查看git lfs路径或把git lfs路径加到git attributes
```
底层命令
#### 底层命令
```
```
示例
#### 示例
```bash
# 1. 设置git lfs每个仓库仅需运行一次
@ -35,3 +35,12 @@ git commit -m "Add disk image"
git push
```
#### 错误解决
##### 1
错误提示:执行`git lfs pull`产生这样的错误`Smudge error: Error downloading ... Not Found: [404] Not Found`
原因分析:远程仓库的大文件不存在
解决方法:先要在本地把这些大文件下载完整,然后使用`git pull` 命令推送到远程仓库。

View File

@ -137,5 +137,6 @@ find ./ -type f -name "hadoop-core*" # 递归查找当前目录下以hadoop-core
find -type f -not -name "*.md" # 查找类型为文件,名称不匹配"*.md"的文件
find . -type f -size +1M -print0 | xargs -0 du -h # 查找当前目录下大于1M的文件并打印其大小。注如果想排序的话还可以通过管道输出给sort -h但不要使用sort -n因为-n选项是按数字排序并不能表达文件真实的大小序列
find -type f -name "*.png" -exec cp {} /tmp/png/ \; # 把当前目录下的png文件复制到/tmp/png/目录下
find abc -type d -empty -delete # 递归删除abc下所有的空目录包括abc
```

View File

@ -15,7 +15,11 @@ rename [options] <perlexpr> [files] # 对于files,使用规则perlexpr重命名
#### 示例
```
rename abc ABC abc* # 把abc开头的文件里abc修改为ABC(for C)
rename 's/abc/ABC/' abc* # 把abc开头的文件里abc修改为ABC(for Perl)
# C语言版
rename abc ABC abc* # 把abc开头的文件里abc修改为ABC
rename '' ABC *txt # 给txt结尾的文件加上前缀ABC
# Perl语言版
rename 's/abc/ABC/' abc* # 把abc开头的文件里abc修改为ABC
```

View File

@ -330,4 +330,11 @@ ctrl+w+w # 列表区和文本区切换
#### 常见错误
- 在shell下`Ctrl+s`不是保存文件,而是暂停该终端,此时对终端的所有操作均无效。需要`Ctrl+q`退出当前状态。
- 在shell下Ctrl+z是将该任务挂起了可以输入`fg`继续之前的编辑。
- 现象描述Windows文本在Linux下显示`^M`
原因分析Windows下和Linux下对换行符的理解不一致。
解决方法:`sed -i 's#\r#\n#' filename`

View File

@ -16,11 +16,13 @@ sudo make install
- 前端qemu里运行的操作系统所能看到的设备。比如e1000网卡。
- 后端宿主机所能看到的qemu上的设备。比如网络设备的后端user和tap等。
- virtio一个客户机和宿主机之间通信的接口。可以减少不同平台之间的兼容性问题。它是半虚拟化的解决方案相比全虚拟化提升了性能。
#### 语法
```
qemu-system-riscv64 [options] [disk_image]
# [disk_image] : 0号IDE硬盘的镜像。某些系统是不需要镜像的。
```
#### 选项
@ -28,14 +30,15 @@ qemu-system-riscv64 [options] [disk_image]
##### 标准选项
```
-accel # 选择加速器的模型
-accel name[,prop=value[,...]] # 选择加速器的模型
-add-fd
-audiodev [driver=]driver,id=id[,prop[=value][,...]]
# 添加一个音频后端driver其id为id。
# 可用的prop有
# id=identifier : 标识音频后端
# timer-period=period : 设置音频子系统的计时器周期。默认10000(10ms)
-boot # 定义启动顺序
-cpu # 选择CPU模型
-cpu <model> # 选择CPU模型
# 可用的CPU:
# Haswell - Intel Core Processor (Haswell)
# 可以被识别的CPUID:
@ -96,6 +99,7 @@ qemu-system-riscv64 [options] [disk_image]
-m megs # 指定内存大小为megs默认128M。
-name string1[,process=string2][,debug-threads=on|off]
# 设置客户机的名称string1是窗口名string2是进程名
-numa
-smp n # 设置CPU的个数为n默认为1。
-soundhw # 使能并使用声卡。
-version # 打印版本信息
@ -212,6 +216,8 @@ qemu-system-riscv64 [options] [disk_image]
```
-nic [tap|user|...] [,...] [,mac=] [,model=] # 此选项是一个快捷方式,用来一次性配置网络的前端和后端。网络的后端的选项和-netdev的选项是一样的。
# model=<modelname> : 配置客户端的网卡模型model=help列出所有支持的类型。
# mac=<macaadr> 设置硬件的mac地址。
-nic none # 意味着不配置任何网络设备。它用来覆盖默认配置。默认配置是前端为默认网卡后端为user。当没有提供其它网络选项的时候会激活默认配置。
-netdev user,id=str[,...] # 设置宿主网络为用户模式,这样就不需要超级用户的权限了。
hostfwd=[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport

View File

@ -136,6 +136,7 @@ pacman -S python # 下载并安装python
pacman -U <pkg> # 本地安装软件包
pacman -Syu # 更新并升级
pacman -Qs glibc # 查询满足glibc的本地安装包
pacman -Fl glibc # 列出glibc包所包含的文件
pacman -Qo /usr/lib/libm.a # 查询文件libm.a所归属的软件包
pacman -S --help # 查询安装软件包的方法
```

View File

@ -1,3 +1,9 @@
### 参考资料
- [cargo](https://doc.rust-lang.org/cargo/commands/cargo.html)
- `rustup doc --cargo`
- `cargo help <cmd>`
### 简介
cargo是rust的包管理器。
@ -230,11 +236,34 @@ git-fetch-with-cli
##### Cargo.toml
- 如以[workspace]开始,则用于设置工作空间。工作空间是多个包的集合,每个包都是工作空间里的一个成员。
- [workspace],用于设置工作空间(workspace)。工作空间是多个包的集合,这些包就叫做工作空间的成员(workspace members)。有两种工作空间作为root package或作为虚拟清单(virtual manifest)。
`Cargo.toml`里即有`[workspace]`段也有`[package]`段这种情况下这个package就是root package。工作空间的根目录(workspace root)就是工作空间的`Cargo.toml`所在的目录。
`Cargo.toml`里只有`[workspace]`段没有`[package]`段,这就叫虚拟清单。如果没有"主"包,或想让所有的包都在不同的目录下,则使用虚拟清单。
工作空间的要点是:
- 所有的包共用工作空间根目录下的`Carogo.lock`文件。
- 所有的包共用同一个输出目录,这个输出目录默认是工作空间根目录下的`target`目录。
- `Cargo.toml`里的`[patch], [replace], [pofile.*]`段只在根清单里被识别,而成员清单里则被忽略。
注意:工作空间里的所有存在依赖关系的路径,会自动成为工作空间的成员。所以`[package]`字段带着一个空的`[workspace]`字段,就是创建了一个包含这个包和它所有依赖路径的工作空间。
```
members # 定义工作空间里的成员
# [workspace]段
members # 定义工作空间里的成员,是由目录字符串组成的数组,支持通配符。
exclude # 避免把路径包含进工作区
default-members # 在工作空间的根目录下,命令行里没有使用-p或--workspace标志显式地指定要操作的包则使用此选项里定义的包作为要操作的包。
# 选择工作空间
# 当进到工作空间的子目录cargo会自动从父目录里找有[workspace]定义的Carogo.toml文件以决定使用哪个工作空间。但也可以在成员库里使用 package.workspace 来手动指定工作空间的根目录。
# 选择包
# 在工作空间里与包相关的cargo命令(比如cargo build)可以用-p 或--workspace来指定要操作的包。如以上两个选项都没使用cargo会使用当前工作目录下的包。如果当前目录是虚拟工作空间则会添加所有的成员(和在命令行里给出--workspace的效果是一样的)。
# [workspace.metadata]
# cargo会忽略它且不会报警。那些在Cargo.toml里保存工作空间配置的工具会用到它。虽然cargo没有为它的内容指定格式但建议外部工具以统一的方式来使用它。例如如果[package.metadata]缺数据的话则引用[workspace.metadata]里的数据。
```
- 如以[package]开始则用于定义package。
@ -312,9 +341,3 @@ registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"
> cargo使用了自带的git命令导致git命令执行失败。参考“配置”相关章节进行设置。
### 参考资料
- [cargo](https://doc.rust-lang.org/cargo/commands/cargo.html)
- `rustup doc --cargo`
- `cargo help <cmd>`
-