2022-08-19 update
This commit is contained in:
parent
505024df1e
commit
3e8a6a1c1d
|
@ -21,4 +21,8 @@
|
|||
存放光标位置的寄存器编号是14和15
|
||||
数据端口:0x3d5
|
||||
显存范围:0xb8000~0xbc000,每个字符对应2个字节,第1个字节是ASCII码,第2个字节是显示属性(低4位是前景色,高4位是背景色,KRGBIRGB,K闪烁I亮度。
|
||||
```
|
||||
```
|
||||
|
||||
在屏幕底部换行的时候,屏幕必须要整体向上滚动一行。大多数视频控制器都包含了一个寄存器,这个寄存器指明从视频RAM的什么位置来取顶行的字节。在需要屏幕上滚的时候,驱动程序只需设置这个寄存器,然后把内容复制到新的屏幕底部即可。
|
||||
|
||||
驱动程序需要处理光标位置,硬件提供了寄存器来记录光标位置。
|
|
@ -0,0 +1,5 @@
|
|||
#### RS232与UART
|
||||
|
||||
RS232是一个串行通信的标准。RS232至少要求有3个引脚(pin):发数据,收数据,接地。其它引脚都是提供控制功能的,但一般都不用。RS232是逐比特通信的,为了传输字符,需要在字符前加1个起始比特,字符后加1~2个结束比特。在结束比特前也可能会插入1个奇偶校验位。传输速率可以是14400比特每秒(用于传真),或56000比特每秒(用于数据)。
|
||||
|
||||
UART是一个接口的标准。它可以把计算机内部的字符和串口线上传输的比特进行转换。
|
|
@ -42,8 +42,17 @@ allow, warn, deny, forbid // 改变默认的检测级别
|
|||
deny(c) // 如遇到c的违规行为,将发出error信号
|
||||
forbid(c) // 类似于deny(c),且禁止更改检测级别
|
||||
// ABI,链接,符号,FFI
|
||||
rate_name
|
||||
crate_type
|
||||
export_name // 定义函数或static的对外符号名。
|
||||
link
|
||||
link_name
|
||||
link_section
|
||||
no_link
|
||||
no_main // 不会加载"main"标记(当使用了no_std属性,rust就不会走正常的main函数流程,这时就需要使用no_main属性,详见参考文档的"rust-no-main")
|
||||
no_mangle // 禁止符号名编码(这样编译器就不会mangle函数名,从而使其它语言可以调用Rust函数的接口)
|
||||
repr
|
||||
used
|
||||
// 代码生成
|
||||
// 文档
|
||||
// 预加载
|
||||
|
|
|
@ -590,6 +590,10 @@ int pipe2(int pipefd[2], int flags);
|
|||
|
||||
获取一个信号量。
|
||||
|
||||
#### set_tid_address
|
||||
|
||||
设置线程id
|
||||
|
||||
#### semop, semtimedop
|
||||
|
||||
改变信号量的值
|
||||
|
|
123
OS/Minix/IO.md
123
OS/Minix/IO.md
|
@ -1,76 +1,4 @@
|
|||
#### IO概述
|
||||
|
||||
操作系统的一个主要功能就是控制I/O设备,I/O代码占了操作系统相当大的部分。操作系统必须向设备发出命令、捕获中断,处理错误。操作系统需要在设备和系统的其它部分之间提供接口,这个接口应该简单易用。在可能的范围内,所有设备的接口都应是一样的(设备无关性)。
|
||||
|
||||
#### I/O软件的原理
|
||||
|
||||
##### 中断处理例程
|
||||
|
||||
中断是生活中令人不快的事实。尽管无法避免,但它们应该被隐藏起来,深藏在操作系统的深处,让操作系统尽可能少的部分知道它们。隐藏它们的最好方法是让驱动程序启动一个I/O操作的时候阻塞,直到I/O完成然后中断发生。驱动程序可以通过信号量的down操作、条件变量的wait操作、消息的receive操作,或类似的操作来阻塞自己。
|
||||
|
||||
当中断发生时,中断过程做任何它必须做的事情来处理中断。然后它可以对启动它的驱动程序解除阻塞。在某些情况下,它只是在一个信号量上完成up操作。在其他情况下,它在管程的条件变量上执行signal操作。还有一些其他情况下,它会向被阻塞的驱动发送一条消息。在所有情况下,中断的最终效果将是之前被阻塞的驱动程序现在能够运行。如果驱动程序的结构是独立的进程,有它们自己的状态、堆栈和程序计数器,这个模型就会发挥最好的作用。
|
||||
|
||||
##### 设备驱动程序
|
||||
|
||||
每个设备控制器都有寄存器,用于向它发出命令或读出它的状态,或两者兼而有之。寄存器的数量和命令的性质因设备而异。
|
||||
|
||||
因此,每个连接到计算机的I/O设备都需要一些特定于设备的代码来控制它。这些代码被称为**设备驱动程序**,通常由设备制造商编写,并随设备一起放在CD-ROM中。由于每个操作系统都需要自己的驱动程序,设备制造商通常会为几种流行的操作系统提供驱动程序。
|
||||
|
||||
每个设备驱动程序通常处理一种设备类型,或一类密切相关的设备。
|
||||
|
||||
为了访问设备的硬件(即控制器的寄存器),设备驱动程序通常是系统内核的一部分。这种方法提供了最好的性能和最差的可靠性,因为任何设备驱动程序中的一个bug都可能导致整个系统崩溃。为了提高可靠性,minix3脱离了这个模型。在minix3中,每个设备驱动程序现在都是一个单独的用户模式进程。
|
||||
|
||||
操作系统通常将驱动程序分为**块设备**(如磁盘)或**字符设备**(如键盘和打印机)。大多数操作系统都定义了一个所有块驱动程序都必须支持的标准接口,和一个所有字符驱动程序都必须支持的另一个标准接口。这些接口由许多过程(procedures)组成,操作系统的其他部分可以调用这些过程来让驱动程序为其工作。
|
||||
|
||||
一般来说,设备驱动程序的工作是接受来自其上层与设备无关的软件的抽象请求,并确保请求被执行。对磁盘驱动器的一个典型请求是读取块n。如果在请求进入时驱动器是空闲的,它会立即开始执行请求。但是,如果它已经忙于处理某个请求,它通常会将新请求放入待处理请求队列中,以便尽快处理。
|
||||
|
||||
实际执行I/O请求的第一步是检查输入参数是否有效,如果无效则返回错误。如果请求有效,下一步是将其从抽象术语转换为具体术语。简而言之,驱动程序必须决定需要哪些控制器操作以及操作的顺序。
|
||||
|
||||
一旦驱动程序确定了要向控制器发出哪些命令,它就开始通过写入控制器的设备寄存器来发出这些命令。简单控制器一次只能处理一个命令。更复杂的控制器则接受一串命令,然后它们自己执行这些命令,而无需操作系统的进一步帮助。
|
||||
|
||||
发出一个或多个命令后,将产生两种情况。在许多情况下,设备驱动程序必须等待直到控制器为它做一些工作,所以它阻塞自己,直到中断进来解除阻塞。然而,在其他情况下,操作不会延迟完成,因此驱动程序不需要阻塞。作为后一种情况的例子,在某些显卡上滚动屏幕只需要向控制器寄存器写入几个字节。不需要机械运动,因此整个操作可以在几微秒内完成。
|
||||
|
||||
在上面的操作完成后,则必须检查错误。如果一切正常,驱动程序可能有数据传递给设备无关的软件(例如,一个刚刚读出的块)。最后,它返回一些状态信息,以便向调用者报告错误。如果有任何其他请求正在排队,现在可以选择并启动其中一个请求。如果队列中没有请求,驱动程序将阻塞等待下一个请求。
|
||||
|
||||
处理读写请求是驱动程序的主要功能,但可能还有其他需求。例如,驱动程序可能需要在系统启动或第一次使用时初始化设备。此外,可能需要管理电源需求、处理即插即用设备或记录事件。
|
||||
|
||||
##### 与设备无关的I/O软件
|
||||
|
||||
大部分的软件都是设备无关的,Minix3里的大部分设备无关的软件都是文件系统的一部分。设备无关软件的典型功能有:
|
||||
|
||||
- 设备驱动程序的统一接口
|
||||
|
||||
有了标准接口,只要符合驱动程序接口,插入新驱动程序就会容易得多。
|
||||
|
||||
使用统一接口的另一个方面是I/O设备的命名方式。设备无关软件负责将符号设备名称映射到正确的驱动程序上。例如,在UNIX和minix3中,一个设备名(例如/dev/disk0)是一个有唯一索引结点号的特殊文件,这个索引结点包含**主设备号**,用于定位适当的驱动程序。它还包含**次设备号**,它作为参数传递给驱动程序,以便指定要读取或写入的单元。所有设备都有主号和次号,所有驱动都通过主号来选择驱动。
|
||||
|
||||
与命名密切相关的是保护。设备在文件系统中以命名对象的形式出现,这意味着通常的文件保护规则也适用于I/O设备。
|
||||
|
||||
- 缓冲
|
||||
|
||||
缓冲区对于块设备和字符设备也是一个问题。对于块设备,硬件通常坚持一次读写整个块,但用户进程可以自由地读写任意单位的块。如果一个用户进程写了半个块,操作系统通常会在内部保存数据,直到其余的数据被写完,此时块可以放到磁盘上。对于字符设备,用户向系统写入数据的速度要快于其输出速度,这就需要缓冲。在需要之前到达的键盘输入也需要缓冲。
|
||||
|
||||
- 错误报告
|
||||
|
||||
错误在I/O上下文中比在其他任何上下文中都要常见得多。当它们发生时,操作系统必须尽可能地处理它们。许多错误是特定于设备的,所以只有驱动程序知道要做什么(例如,重试,忽略,或恐慌)。一个典型的错误是由磁盘块损坏而不能再读取引起的。当驱动尝试读取该块一定次数后,它放弃并通知与设备无关的软件。从这里开始如何处理错误是与设备无关的。如果在读取用户文件时发生了错误,那么向调用方报告错误就足够了。但是,如果它发生在读取关键的系统数据结构时,比如读取包含位图的块,在这个位图上显示哪些块是空闲的,操作系统可能不得不显示一条错误消息并终止。
|
||||
|
||||
- 专用设备的分配与释放
|
||||
|
||||
有些设备,如CD-ROM录音机,在任何给定时刻只能由单个进程使用。操作系统需要检查设备使用请求,并根据设备是否可用来接受或拒绝这个请求。处理这些请求的一种简单方法是要求进程对这个特殊文件执行open操作。如果设备不可用,则open失败。关闭这样一个专用设备,然后释放它。
|
||||
|
||||
- 提供设备无关的块大小
|
||||
|
||||
并非所有磁盘都具有相同的扇区大小。这是由独立于设备的软件来隐藏这一事实,并向更高的层提供统一的块大小,例如,通过将几个扇区视为单个逻辑块。通过这种方式,较高层只处理所有使用相同逻辑块大小的抽象设备,与物理扇区大小无关。类似地,一些字符设备每次传送一个字节的数据(例如,调制解调器),而其他设备以更大的单位传送数据(例如,网络接口)。这些差异也是可以隐藏起来的。
|
||||
|
||||
##### 用户空间的I/O软件
|
||||
|
||||
有一种用户空间的I/O软件是通过库使用了I/O系统调用。
|
||||
|
||||
另一种用户级的I/O软件是多任务缓冲系统(spooling system)。**多任务缓冲**(Spooling)是在多程序系统(multiprogramming system)里处理专用I/O设备的一种方法。
|
||||
|
||||
比如说管理打印机。有一个守护进程,只有它有权限让打印机打印文件。守护进程会从多任务缓冲目录(spooling directory)里找文件来打印。一个进程只需把要打印的文件放到多任务缓冲目录就好。这就可以避免用户进程直接管理专用设备而导致的设备使用时间不合理的问题。
|
||||
|
||||
多任务缓冲也可用于其它情况,比如电子邮件。提交的邮件先被放在邮件多任务缓冲目录,随后邮件守护进程尝试发送它。如发送失败,邮件会继续留在多任务缓冲目录,并在稍后重发。
|
||||
|
||||
#### Minix3中的I/O
|
||||
|
||||
|
@ -157,27 +85,6 @@ RAM盘也是由块组成的。当向驱动程序发出消息要读或写一个
|
|||
|
||||
一个RAM盘驱动程序可以支持多个RAM盘,这些RAM盘之间通过次设备号来区分。RAM盘的空间一般应该是分开的,但也可以重叠。
|
||||
|
||||
##### 磁盘驱动程序基本知识
|
||||
|
||||
1. 磁盘臂调度算法,用以优化平均寻道时间
|
||||
|
||||
读写磁盘块的时间由如下三个因素决定:寻道时间,旋转时延,传输时间。其中寻道时延比其它两个要大的多,所以减小寻道时间可以大大提高系统性能。
|
||||
|
||||
- 先来先服务(FCFS):磁盘驱动程序按顺序处理请求。难以优化寻道时间。
|
||||
- 最短寻道优先(SSF):按柱面号索引磁盘请求,总是处理最近的柱面。平均寻道时间得到了优化,问题是柱面两端的极端区域较难到达。
|
||||
- 电梯算法(elevator algorithm):按一个方向运行直到没有请求为止,然后换个方向运动。
|
||||
|
||||
2. 错误处理
|
||||
|
||||
- 程序性错误:解决方法是结束当前磁盘请求。
|
||||
- 校验和错误:解决方法是重复操作几次,还不行就把块标记为**坏块**(bad block)。
|
||||
- 寻道错误:大多数磁盘控制器可以自动修复寻道错误。
|
||||
- 控制器错误:控制器芯片上有一个引脚可以强迫自己复位,磁盘驱动程序可以触发此信号来重置控制器。
|
||||
|
||||
3. 磁道缓存,用以加速磁盘访问
|
||||
|
||||
就是一次旋转把整个磁盘的内容都读出来。如果控制器做了此事,磁盘驱动程序就不必再做了。
|
||||
|
||||
##### 硬盘驱动程序概述
|
||||
|
||||
Minix把不同的硬盘驱动程序都放进了启动镜像,由用户决定来用哪个。
|
||||
|
@ -191,3 +98,33 @@ Minix把不同的硬盘驱动程序都放进了启动镜像,由用户决定来
|
|||
- DEV_IOCTL
|
||||
- DEV_READ, DEV_WRITE, DEV_GATHER, DEV_SCATTER
|
||||
- DEV_CANCEL. DEV_SELECTE:被忽略。
|
||||
|
||||
##### 键盘驱动程序
|
||||
|
||||
POSIX要求标准库中的一些函数可以让程序来控制终端参数,基中最重要的两个是`tcgetattr()`和`tcsetattr()`。它们读写`termios`结构体,`termios`结构体包含了关于终端的所有信息。Minix3提供了`ioctl()`系统调用来支持这两个函数。
|
||||
|
||||
```c
|
||||
struct termios {
|
||||
tcflag_t c_iflag; /* 存放影响输入的位 */
|
||||
// ICRNL位可以让输入的CR字符转成NL字符
|
||||
tcflag_t c_oflag; /* 存放影响输出的位 */
|
||||
// OPOST位使能输出
|
||||
// ONLCR位可以输出的NL字符转成 CR NL 序列
|
||||
tcflag_t c_cflag; /* control modes */
|
||||
// Minix3默认使能一条线路接收8位字符,用户登出这条线路则modem挂起。
|
||||
tcflag_t c_lflag; /* local modes */
|
||||
// ECHO位使能回显
|
||||
// ICANON位使能规范模式。
|
||||
// 其它位如果都是默认设置,则进到传统的"cbreak mode",输入字符不等满行就传给了程序。
|
||||
speed_t c_ispeed; /* input speed */
|
||||
speed_t c_ospeed; /* output speed */
|
||||
cc_t c_cc[NCCS]; /* 存放可以改变的特殊字符 */
|
||||
};
|
||||
|
||||
/*
|
||||
* request:对termios结构体是读还是写
|
||||
* argp:指向termios结构体的指针
|
||||
*/
|
||||
ioctl(file_descriptor, request, argp);
|
||||
```
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
```
|
||||
# 需要安装bazel,且bazel的版本不得低于4.2.1
|
||||
bazel build //runsc # 构建runsc
|
||||
```
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
#### IO概述
|
||||
|
||||
操作系统的一个主要功能就是控制I/O设备,I/O代码占了操作系统相当大的部分。操作系统必须向设备发出命令、捕获中断,处理错误。操作系统需要在设备和系统的其它部分之间提供接口,这个接口应该简单易用。在可能的范围内,所有设备的接口都应是一样的(设备无关性)。
|
||||
|
||||
#### I/O软件的原理
|
||||
|
||||
##### 中断处理例程
|
||||
|
||||
中断是生活中令人不快的事实。尽管无法避免,但它们应该被隐藏起来,深藏在操作系统的深处,让操作系统尽可能少的部分知道它们。隐藏它们的最好方法是让驱动程序启动一个I/O操作的时候阻塞,直到I/O完成然后中断发生。驱动程序可以通过信号量的down操作、条件变量的wait操作、消息的receive操作,或类似的操作来阻塞自己。
|
||||
|
||||
当中断发生时,中断过程做任何它必须做的事情来处理中断。然后它可以对启动它的驱动程序解除阻塞。在某些情况下,它只是在一个信号量上完成up操作。在其他情况下,它在管程的条件变量上执行signal操作。还有一些其他情况下,它会向被阻塞的驱动发送一条消息。在所有情况下,中断的最终效果将是之前被阻塞的驱动程序现在能够运行。如果驱动程序的结构是独立的进程,有它们自己的状态、堆栈和程序计数器,这个模型就会发挥最好的作用。
|
||||
|
||||
##### 设备驱动程序
|
||||
|
||||
每个设备控制器都有寄存器,用于向它发出命令或读出它的状态,或两者兼而有之。寄存器的数量和命令的性质因设备而异。
|
||||
|
||||
因此,每个连接到计算机的I/O设备都需要一些特定于设备的代码来控制它。这些代码被称为**设备驱动程序**,通常由设备制造商编写,并随设备一起放在CD-ROM中。由于每个操作系统都需要自己的驱动程序,设备制造商通常会为几种流行的操作系统提供驱动程序。
|
||||
|
||||
每个设备驱动程序通常处理一种设备类型,或一类密切相关的设备。
|
||||
|
||||
为了访问设备的硬件(即控制器的寄存器),设备驱动程序通常是系统内核的一部分。这种方法提供了最好的性能和最差的可靠性,因为任何设备驱动程序中的一个bug都可能导致整个系统崩溃。为了提高可靠性,minix3脱离了这个模型。在minix3中,每个设备驱动程序现在都是一个单独的用户模式进程。
|
||||
|
||||
操作系统通常将驱动程序分为**块设备**(如磁盘)或**字符设备**(如键盘和打印机)。大多数操作系统都定义了一个所有块驱动程序都必须支持的标准接口,和一个所有字符驱动程序都必须支持的另一个标准接口。这些接口由许多过程(procedures)组成,操作系统的其他部分可以调用这些过程来让驱动程序为其工作。
|
||||
|
||||
一般来说,设备驱动程序的工作是接受来自其上层与设备无关的软件的抽象请求,并确保请求被执行。对磁盘驱动器的一个典型请求是读取块n。如果在请求进入时驱动器是空闲的,它会立即开始执行请求。但是,如果它已经忙于处理某个请求,它通常会将新请求放入待处理请求队列中,以便尽快处理。
|
||||
|
||||
实际执行I/O请求的第一步是检查输入参数是否有效,如果无效则返回错误。如果请求有效,下一步是将其从抽象术语转换为具体术语。简而言之,驱动程序必须决定需要哪些控制器操作以及操作的顺序。
|
||||
|
||||
一旦驱动程序确定了要向控制器发出哪些命令,它就开始通过写入控制器的设备寄存器来发出这些命令。简单控制器一次只能处理一个命令。更复杂的控制器则接受一串命令,然后它们自己执行这些命令,而无需操作系统的进一步帮助。
|
||||
|
||||
发出一个或多个命令后,将产生两种情况。在许多情况下,设备驱动程序必须等待直到控制器为它做一些工作,所以它阻塞自己,直到中断进来解除阻塞。然而,在其他情况下,操作不会延迟完成,因此驱动程序不需要阻塞。作为后一种情况的例子,在某些显卡上滚动屏幕只需要向控制器寄存器写入几个字节。不需要机械运动,因此整个操作可以在几微秒内完成。
|
||||
|
||||
在上面的操作完成后,则必须检查错误。如果一切正常,驱动程序可能有数据传递给设备无关的软件(例如,一个刚刚读出的块)。最后,它返回一些状态信息,以便向调用者报告错误。如果有任何其他请求正在排队,现在可以选择并启动其中一个请求。如果队列中没有请求,驱动程序将阻塞等待下一个请求。
|
||||
|
||||
处理读写请求是驱动程序的主要功能,但可能还有其他需求。例如,驱动程序可能需要在系统启动或第一次使用时初始化设备。此外,可能需要管理电源需求、处理即插即用设备或记录事件。
|
||||
|
||||
##### 与设备无关的I/O软件
|
||||
|
||||
大部分的软件都是设备无关的,Minix3里的大部分设备无关的软件都是文件系统的一部分。设备无关软件的典型功能有:
|
||||
|
||||
- 设备驱动程序的统一接口
|
||||
|
||||
有了标准接口,只要符合驱动程序接口,插入新驱动程序就会容易得多。
|
||||
|
||||
使用统一接口的另一个方面是I/O设备的命名方式。设备无关软件负责将符号设备名称映射到正确的驱动程序上。例如,在UNIX和minix3中,一个设备名(例如/dev/disk0)是一个有唯一索引结点号的特殊文件,这个索引结点包含**主设备号**,用于定位适当的驱动程序。它还包含**次设备号**,它作为参数传递给驱动程序,以便指定要读取或写入的单元。所有设备都有主号和次号,所有驱动都通过主号来选择驱动。
|
||||
|
||||
与命名密切相关的是保护。设备在文件系统中以命名对象的形式出现,这意味着通常的文件保护规则也适用于I/O设备。
|
||||
|
||||
- 缓冲
|
||||
|
||||
缓冲区对于块设备和字符设备也是一个问题。对于块设备,硬件通常坚持一次读写整个块,但用户进程可以自由地读写任意单位的块。如果一个用户进程写了半个块,操作系统通常会在内部保存数据,直到其余的数据被写完,此时块可以放到磁盘上。对于字符设备,用户向系统写入数据的速度要快于其输出速度,这就需要缓冲。在需要之前到达的键盘输入也需要缓冲。
|
||||
|
||||
- 错误报告
|
||||
|
||||
错误在I/O上下文中比在其他任何上下文中都要常见得多。当它们发生时,操作系统必须尽可能地处理它们。许多错误是特定于设备的,所以只有驱动程序知道要做什么(例如,重试,忽略,或恐慌)。一个典型的错误是由磁盘块损坏而不能再读取引起的。当驱动尝试读取该块一定次数后,它放弃并通知与设备无关的软件。从这里开始如何处理错误是与设备无关的。如果在读取用户文件时发生了错误,那么向调用方报告错误就足够了。但是,如果它发生在读取关键的系统数据结构时,比如读取包含位图的块,在这个位图上显示哪些块是空闲的,操作系统可能不得不显示一条错误消息并终止。
|
||||
|
||||
- 专用设备的分配与释放
|
||||
|
||||
有些设备,如CD-ROM录音机,在任何给定时刻只能由单个进程使用。操作系统需要检查设备使用请求,并根据设备是否可用来接受或拒绝这个请求。处理这些请求的一种简单方法是要求进程对这个特殊文件执行open操作。如果设备不可用,则open失败。关闭这样一个专用设备,然后释放它。
|
||||
|
||||
- 提供设备无关的块大小
|
||||
|
||||
并非所有磁盘都具有相同的扇区大小。这是由独立于设备的软件来隐藏这一事实,并向更高的层提供统一的块大小,例如,通过将几个扇区视为单个逻辑块。通过这种方式,较高层只处理所有使用相同逻辑块大小的抽象设备,与物理扇区大小无关。类似地,一些字符设备每次传送一个字节的数据(例如,调制解调器),而其他设备以更大的单位传送数据(例如,网络接口)。这些差异也是可以隐藏起来的。
|
||||
|
||||
##### 用户空间的I/O软件
|
||||
|
||||
有一种用户空间的I/O软件是通过库使用了I/O系统调用。
|
||||
|
||||
另一种用户级的I/O软件是多任务缓冲系统(spooling system)。**多任务缓冲**(Spooling)是在多程序系统(multiprogramming system)里处理专用I/O设备的一种方法。
|
||||
|
||||
比如说管理打印机。有一个守护进程,只有它有权限让打印机打印文件。守护进程会从多任务缓冲目录(spooling directory)里找文件来打印。一个进程只需把要打印的文件放到多任务缓冲目录就好。这就可以避免用户进程直接管理专用设备而导致的设备使用时间不合理的问题。
|
||||
|
||||
多任务缓冲也可用于其它情况,比如电子邮件。提交的邮件先被放在邮件多任务缓冲目录,随后邮件守护进程尝试发送它。如发送失败,邮件会继续留在多任务缓冲目录,并在稍后重发。
|
|
@ -0,0 +1,20 @@
|
|||
##### 磁盘驱动程序基本知识
|
||||
|
||||
1. 磁盘臂调度算法,用以优化平均寻道时间
|
||||
|
||||
读写磁盘块的时间由如下三个因素决定:寻道时间,旋转时延,传输时间。其中寻道时延比其它两个要大的多,所以减小寻道时间可以大大提高系统性能。
|
||||
|
||||
- 先来先服务(FCFS):磁盘驱动程序按顺序处理请求。难以优化寻道时间。
|
||||
- 最短寻道优先(SSF):按柱面号索引磁盘请求,总是处理最近的柱面。平均寻道时间得到了优化,问题是柱面两端的极端区域较难到达。
|
||||
- 电梯算法(elevator algorithm):按一个方向运行直到没有请求为止,然后换个方向运动。
|
||||
|
||||
2. 错误处理
|
||||
|
||||
- 程序性错误:解决方法是结束当前磁盘请求。
|
||||
- 校验和错误:解决方法是重复操作几次,还不行就把块标记为**坏块**(bad block)。
|
||||
- 寻道错误:大多数磁盘控制器可以自动修复寻道错误。
|
||||
- 控制器错误:控制器芯片上有一个引脚可以强迫自己复位,磁盘驱动程序可以触发此信号来重置控制器。
|
||||
|
||||
3. 磁道缓存,用以加速磁盘访问
|
||||
|
||||
就是一次旋转把整个磁盘的内容都读出来。如果控制器做了此事,磁盘驱动程序就不必再做了。
|
|
@ -0,0 +1,49 @@
|
|||
#### 两种模式
|
||||
|
||||
键盘驱动程序的基本工作就是收集键盘输入并把它传给用户程序。键盘驱动程序有两种设计哲学:一是驱动程序仅仅接收输入并不加修改地向上传递,这种思想是基于字符的,被叫做**生模式**(raw mode),在POSIX里也叫**非规范模式**(noncanonical mode)。二是驱动程序处理行内的编辑并向用户程序交付正确的行,这种思想则是基于行的,被叫做**熟模式**(cooked mode),在POSIX里也叫**规范模式**(canonical mode)。
|
||||
|
||||
#### 两个任务
|
||||
|
||||
键盘驱动程序的第一个任务是收集字符。如果每次击键都产生中断,驱动程序就可以在中断过程中拿到字符。如果底层软件把中断转成了消息,则可以把新得到的字符放在消息里。也可以把字符放进缓冲区,再通过消息告诉驱动程序接收到了一些东西。
|
||||
|
||||
键盘驱动程序的第二个任务是处理字符。如果键盘传递的是键码而非字符码,则驱动程序需要利用表来把键码转换成字符码。仅有ASCII码是不够的,为了支持不同的语言,许多操作系统都提供了可装载的**键盘映射**(keymaps)或**码页**(code pages),建立键码和字符码之间的映射。
|
||||
|
||||
不管是生模式还是熟模式,都要把字符缓冲起来。有两种字符缓冲的方法。
|
||||
|
||||
第一种缓冲方法是把缓冲区集中到一块,每个缓冲区大约容纳10个字符。与终端相关的数据结构只是包含缓冲区的指针。这种方法比较省空间但实现会复杂一点。
|
||||
|
||||
第二种方法是直接把缓冲区放在与终端相关的数据结构里。每个缓冲区大约容纳200个字符。这种方法是实现简单但占用空间比较大。
|
||||
|
||||
#### 几个问题
|
||||
|
||||
键盘驱动程序要考虑应用程序的输出、回显(echoing)、TAB键的问题。
|
||||
|
||||
- 程序把输入打印到屏幕上的操作叫**回显**(echoing)。要考虑回显和程序输出会冲突的问题。
|
||||
|
||||
- 驱动程序要处理TAB键回显的问题,它需要计算出光标的正确位置。
|
||||
|
||||
回车(carriage return)与换行(linefeed)的问题。
|
||||
|
||||
- 回车的确切含义是把光标移到第一列(还在同一行)。换行的确切含义是把光标移到下一行(还在同一列)。
|
||||
- 对于类Unix系统,换行的意思是即回车又换行,这种情况下即使输入的是回车也应改为换行。
|
||||
- 对于即需要回车又需要换行的系统,则不管输入的是回车还是换行,都需要转换成即有回车也有换行。
|
||||
- 在某些系统上,回车或换行比其它字符花的时间要多。这就需要驱动程序在输出流里插入填充字符(filler character,就是假的空字符)或等一段时间。
|
||||
|
||||
#### 规范模式下的特殊字符
|
||||
|
||||
| 字符 | POSIX名 | 含义 |
|
||||
| ------ | ------- | ----------------------------- |
|
||||
| Crtl+D | EOF | 文件末尾 |
|
||||
| | EOL | 行末尾(末定义) |
|
||||
| Crtl+H | ERASE | 回退一个字符 |
|
||||
| Crtl+C | INTR | 中断进程 |
|
||||
| Crtl+U | KILL | 删除整行 |
|
||||
| Crtl+\ | QUIT | 强制内核转储(Force core dump) |
|
||||
| Crtl+Z | SUSP | 挂起(Suspend) |
|
||||
| Crtl+Q | START | 开始输出 |
|
||||
| Crtl+S | STOP | 停止输出 |
|
||||
| Crtl+M | CR | 回车(不可改变) |
|
||||
| Crtl+J | NL | 换行(不可改变) |
|
||||
|
||||
|
||||
|
|
@ -15,6 +15,6 @@ git add [optoins] [--] [pathspec...]
|
|||
#### 选项
|
||||
|
||||
```
|
||||
|
||||
--renormalize # 对所有被追踪的文件应用“clean”过程,强制把它们重新加到索引里。
|
||||
```
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ git commit [options] [--] [files] # 把改变记录到仓库
|
|||
|
||||
```
|
||||
-a, --all # 自动把修改或删除的文件进行提交。(注:不在索引区的文件不受影响)
|
||||
--amend # 修改当前的分支。
|
||||
--amend # 用一个新的提交来覆盖当前分支的顶端(即最近一次提交)。其实它的含义就是“修正最近一次提交”,但被覆盖的提交还是存在的,用git reflog可以看到。
|
||||
-C, --reuse-message=<commit> # 重用<commit>的日志消息和作者信息(包括时间戳)。
|
||||
-c, --reedit-message=<commit> # 类似-C,但会调用编辑器,这样用户就可以进一步编辑提交消息。
|
||||
```
|
||||
|
||||
|
|
|
@ -9,7 +9,20 @@ git filter-branch [options] [--] [<rev-list options>]
|
|||
#### 选项
|
||||
|
||||
```bash
|
||||
--tree-filter <command> # 这是一个过滤器。用于重写tree和它的内容。<command>就是要在shell中执行的命令。
|
||||
--commit-filter <command>
|
||||
-d <directory>
|
||||
--env-filter <command>
|
||||
-f, --force
|
||||
--index-filter <command> # 这是一个过滤器,用于重写索引。类似于--tree-filter,但不会check out工作树,这使得它更快。<command>一般是"git rm --cached --ignore-unmatch ..."。
|
||||
--msg-filter <command>
|
||||
--original <namespace>
|
||||
--parent-filter <command>
|
||||
--prune-empty # 某些过滤器可能产生空的提交,此选项会删除那些提交。
|
||||
--setup <command>
|
||||
--state-branch <branch>
|
||||
--subdirectory-filter <directory>
|
||||
--tag-name-filter <command> # 这是一个过滤器,用于修改tag的名字。
|
||||
--tree-filter <command> # 这是一个过滤器,用于重写工作树和它的内容。<command>就是要在shell中执行的命令。
|
||||
<rev-list options> # git rev-list的参数。
|
||||
```
|
||||
|
||||
|
@ -17,5 +30,6 @@ git filter-branch [options] [--] [<rev-list options>]
|
|||
|
||||
```bash
|
||||
git filter-branch --tree-filter "rm -f {filepath}" -- --all
|
||||
# 从所有提交里删除文件。rm加"-f"的作用是避免某些提交里没有此文件而报错。
|
||||
```
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
#### 简介
|
||||
|
||||
个人认为,git-lfs存在着比较大的问题,尽量不要使用。git-lfs的本质是用其它的服务器来保存大文件,这就打破了仓库的完整性且无法恢复,会带来很多的问题。
|
||||
|
||||
如果仓库里存在着大文件,第一应考虑的是这些大文件是必须的吗?如果是必须的,第二应考虑的是怎么生成、保存、获取它们?而不是使用git-lfs。
|
||||
|
||||
```
|
||||
git lfs <command> [args] # 在git仓库里管理大文件
|
||||
# 注:此子命令需单独安装:sudo apt install git-lfs
|
||||
|
@ -6,18 +12,46 @@ git lfs <command> [args] # 在git仓库里管理大文件
|
|||
#### 高层命令
|
||||
|
||||
```shell
|
||||
install # 安装配置
|
||||
env
|
||||
checkout
|
||||
dedup
|
||||
ext
|
||||
fetch
|
||||
fsck
|
||||
install # 安装LFS的配置
|
||||
lock
|
||||
logs
|
||||
ls-files # 显示git lfs文件的信息,包括索引里的和工作目录里的。
|
||||
migrate # 迁移的历史(to or from git-lfs)
|
||||
info # 显示仓库尺寸的信息。
|
||||
prune
|
||||
pull # 从远程获取LFS文件。相当于先执行git lfs fetch,再执行git lfs checkout。
|
||||
# 选项
|
||||
-I, --include=<paths> # 为当前调用指定lfs.fetchinclude,即要取的文件
|
||||
-X, --exclude=<paths> # 为当前调用指定lfs.fetchexclude,即不要取的文件
|
||||
# 注,paths里的各项以逗号分隔
|
||||
push
|
||||
status
|
||||
track # 查看git lfs路径,或把git lfs路径加到git attributes
|
||||
uninstall # 卸载git lfs,包括删除hooks,清空配置。
|
||||
unlock
|
||||
untrack # 从git attributes里删除git lfs路径。
|
||||
update
|
||||
version
|
||||
```
|
||||
|
||||
#### 底层命令
|
||||
|
||||
```
|
||||
clean
|
||||
filter-process
|
||||
pointer
|
||||
post-checkout
|
||||
post-commit
|
||||
post-merge
|
||||
pre-push
|
||||
smudge
|
||||
standalone-file
|
||||
```
|
||||
|
||||
#### 示例
|
||||
|
@ -33,6 +67,21 @@ git add .gitattributes
|
|||
git add <file>.iso
|
||||
git commit -m "Add disk image"
|
||||
git push
|
||||
# 5. 卸载git lfs
|
||||
git lfs uninstall
|
||||
git rm --cached <lfs-file> # 删除所有.gitattributes里追踪的文件
|
||||
rm .gitattributes
|
||||
git add .gitattributes
|
||||
git commit -m "uninstall git-lfs"
|
||||
# 6. 从提交历史里彻底去掉git-lfs
|
||||
# 因为github服务器上始终保保留了lfs存在的痕迹,所以唯一的方案可能就是删除再重建了
|
||||
# 这个方法的缺点是:与仓库相关的所有东西都无法保留,比如fork关系、issure、pr记录等
|
||||
# 第一步,github上先删除,再新建仓库
|
||||
# 第二步,卸载git lfs
|
||||
# 第三步,使用git filter-branch命令把lfs相关文件从历史中删除。
|
||||
rm -r .git/lfs # 删除lfs
|
||||
rm `grep -ril lfs .git/hooks` # 删除相关的勾子
|
||||
git push # 在保留了提交记录的前提下,github服务器上不再有lfs存在的痕迹了
|
||||
```
|
||||
|
||||
#### 错误解决
|
||||
|
|
|
@ -21,6 +21,7 @@ get-url <name> # 检索远程分支的url
|
|||
set-url <name> <newurl> # 改变远程分支的url
|
||||
prune [-n] <name> # 删除与远程分支name相关的陈旧引用
|
||||
-n, --dry-run # 只显示要删除的分支而不实际删除它们
|
||||
update
|
||||
```
|
||||
|
||||
#### 用法
|
||||
|
|
|
@ -95,6 +95,13 @@
|
|||
|
||||
#### github webhook
|
||||
|
||||
#### github classroom
|
||||
|
||||
- 三种角色:
|
||||
- 老师(发布作业):a创建学生信息并关联到github账号,b创建作业(并生成作业的链接)
|
||||
- 助教(对作业给出反馈),助教的反馈以pr的形式存在。
|
||||
- 学生(完成作业):通过老师分享的链接加入作业,可以vscode在线编辑代码,也可git clone到本地编辑代码。提交后会执行github action的内容。可以在pr里看到助教的反馈。
|
||||
|
||||
#### 免密登陆
|
||||
|
||||
[使用ssh免密登陆](https://help.github.com/en/articles/connecting-to-github-with-ssh)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#### 简介
|
||||
|
||||
一个文件,用于指定不跟踪的文件。
|
||||
|
||||
它的位置:`$XDG_CONFIG_HOME/git/ignore, $GIT_DIR/info/exclude, .gitignore`。
|
||||
|
||||
#### 格式
|
||||
|
||||
- 空白行不匹配任何文件。
|
||||
- `\`用于转义。
|
||||
- 以`#`开头的行是注释。
|
||||
- 行尾空格将被忽略。
|
||||
- 以`!`开头的模式将否定该模式,这样前面模式被忽略的文件可以再次被包含。
|
||||
- `/`用于分割目录。如果`/`在开头或中间,则这个模式是相对于`.gitignore`所在的目录而言的。如果`/`在末尾,则这个模式会匹配`.gitignore`所在目录下的所有目录。不以`/`结尾的,即可以是目录,也可以是文件。
|
||||
- `*`匹配任意数量的字符,除了`/`。
|
||||
- `?`匹配任意一个字符,除了`/`。
|
||||
- `[a-zA-Z]`匹配任意一个a~z或A~Z的字符。
|
||||
- `**/`匹配所有的目录。用法比如`**/foo/bar`。
|
||||
- `/**`匹配所有的目录和文件。用法比如`abc/**`。
|
||||
- `a/**/b`匹配a和b之间的零个或多个目录。
|
|
@ -43,6 +43,12 @@ wget [option] [url]
|
|||
|
||||
##### 目录
|
||||
|
||||
```
|
||||
-P, --directory-prefix=<prefix> # 设置目录前缀为<prefix>。<prefix>实际上就是要保存的目录,默认值为当前目录。
|
||||
```
|
||||
|
||||
|
||||
|
||||
##### HTTP
|
||||
|
||||
```
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#### 安装
|
||||
|
||||
```
|
||||
# 从"https://github.com/bazelbuild/bazel/releases/"下载bazel
|
||||
sudo apt install ./bazel*.deb
|
||||
```
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#### gVisor
|
||||
|
||||
|
||||
```
|
||||
# 需要安装bazel,且bazel的版本不得低于4.2.1
|
||||
# 需安装go,且go的版本不得低于1.16
|
||||
make # 构建所有的syzcaller工具
|
||||
cd $GVISOR
|
||||
bazel build //runsc # 构建runsc。注:如fetch失败要通过go env命令走国内的仓库
|
||||
```
|
||||
|
|
@ -34,7 +34,7 @@ find [options] [starting-point...] [expression]
|
|||
|
||||
##### 全局选项
|
||||
|
||||
作用于命令行中所有位置的Tests和Actions操作,总是返回true。
|
||||
作用于命令行中所有位置的Tests和Actions操作,总是返回true。为防止混淆,全局选项应放在表达式的最前面。
|
||||
|
||||
```bash
|
||||
-d # 等价于-depth,为了适应各种BSD Unix和MacOs X。
|
||||
|
|
|
@ -56,22 +56,55 @@ build [options] # 编译一个包。
|
|||
# 注:使用"--release"时采用release配置
|
||||
# 注:可以在Cargo.toml中使用[profile.*]覆盖任意设置的默认值。
|
||||
## 包选项
|
||||
-p <specs>
|
||||
--workspace
|
||||
--all
|
||||
--exclude <SPECS>
|
||||
## 目标选项
|
||||
--lib
|
||||
--bin <names>
|
||||
--bins
|
||||
--example <names>
|
||||
--examples
|
||||
--test <names>
|
||||
--tests
|
||||
--bench <names>
|
||||
--benches
|
||||
--all-targets
|
||||
## 属性选项
|
||||
-F <features>
|
||||
--all-features
|
||||
--no-default-features
|
||||
## 编译选项
|
||||
--traget <triple> # 指定编译的架构(默认是主机的架构)。triple的格式为<arch><sub>-<vendor>-<sys>-<abi>。
|
||||
# 也可以在配置文件里通过设置build.target实现同样的功能。
|
||||
# 注:编译结果会放在不同的目录中。
|
||||
--release # 使用release配置来编译要优化的组件。
|
||||
-r, --release # 使用release配置来编译要优化的组件。
|
||||
--profile <name>
|
||||
--ignore-rust-version
|
||||
--timings=<fmts>
|
||||
## 输出选项
|
||||
--target-dir <dir>
|
||||
--out-dir <dir>
|
||||
## 显示选项
|
||||
-v, --verbose # 输出详细信息。两次指定此参数可输出更详细的信息。
|
||||
-q
|
||||
--color <when>
|
||||
--message-format <fmt>
|
||||
--build-plan
|
||||
## Manifest选项
|
||||
--manifest-path <path> # 指定Cargo.toml的路径。默认是从当前路径或任意父路径中查找。
|
||||
--frozen, --locked
|
||||
--offline
|
||||
## 通用选项
|
||||
+<toolchain> # 指定工具链的名称。(如+stable,+nightly)。前提要求:cargo是通过rustup安装的,此参数为cargo的第一个参数。
|
||||
--config <KEY=VALUE>
|
||||
-h
|
||||
-Z <flag> # Unstable flags to Cargo。(仅用于nightly)
|
||||
## 其它选项
|
||||
-j, --jobs <N>
|
||||
--keep-going
|
||||
--future-incompat-report
|
||||
```
|
||||
|
||||
##### check
|
||||
|
|
|
@ -10,4 +10,50 @@ dtc [options] <input file>
|
|||
|
||||
- `-I <input format>`指定输入文件的格式,可选的格式有:dts(device tree source text), dtb( device tree blob), fs( /proc/device-tree style directory).
|
||||
- `-O <output format>`指定输出文件的格式,可选的格式有:dts, dtb, asm(assembler source).
|
||||
- `-o <output file>`将结果输出到文件,而不是stdout。
|
||||
- `-o <output file>`将结果输出到文件,而不是stdout。
|
||||
|
||||
#### DTS的语法
|
||||
|
||||
##### 概述
|
||||
|
||||
1. 由结点+结点属性组成。
|
||||
2. 有且只有一个根结点,即“\”。
|
||||
3. 根结点下又包含子结点,形成树形的结构。
|
||||
4. 结点的属性放在`{}`里。可以是字符串"...",整数<...>,十六进制数[...],或为空。
|
||||
5. 结点的名称是`node-name@unit-address`,其中`@unit-address`可以不选。
|
||||
|
||||
##### 属性
|
||||
|
||||
- compatible
|
||||
|
||||
用于匹配驱动程序,优先级从左到右。
|
||||
|
||||
- interrupt
|
||||
|
||||
指定中断的中断号,触发方法等。中断控制器结点中的`#inrerrupt-controller`控制此属性中值的个数。
|
||||
|
||||
- interrupt-parent
|
||||
|
||||
指定它所依附的中断控制器。若没指定,则从双亲结点中继承。
|
||||
|
||||
- ranges
|
||||
|
||||
描述该设备到双亲结点的地址映射关系。
|
||||
|
||||
- reg
|
||||
|
||||
描述MMIO寄存器的位移和长度。这两个值的长度由双亲结点的`#address-cells`和`#size-cells`决定。
|
||||
|
||||
-
|
||||
|
||||
##### chosen结点
|
||||
|
||||
描述由系统指定的运行时的参数,不描述硬件设备的信息。它的双亲结点必须是根结点。
|
||||
|
||||
##### aliases结点
|
||||
|
||||
定义别名。
|
||||
|
||||
##### memory结点
|
||||
|
||||
- device_type必须为"memory"
|
|
@ -1,3 +1,16 @@
|
|||
#### 安装
|
||||
|
||||
```bash
|
||||
wget https://go.dev/dl/go1.19.linux-amd64.tar.gz # 下载
|
||||
tar xf go1.19.linux-amd64.tar.gz -C /usr/local # 解压前要确保/usr/local/go目录不存在
|
||||
vim ~/.profile # 添加如下内容
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 用法
|
||||
|
||||
```
|
||||
go <command> [arguments]
|
||||
```
|
||||
|
|
Loading…
Reference in New Issue