update 2022-06-18
This commit is contained in:
parent
7f59fa35c7
commit
80d69f4cd1
|
@ -1,37 +0,0 @@
|
|||
#### 8259A概述
|
||||
|
||||

|
||||
|
||||
8259A芯片是一个中断管理芯片,中断的来源除了来自于硬件自身的NMI中断和来自于软件的`INT n`指令造成的软件中断之外,还有来自于外部硬件设备的中断,这些中断是可屏蔽的。这些中断也都通过**PIC**(Programmable Interrupt Controller)进行控制,并传递给CPU。
|
||||
|
||||
一个8259A芯片的可以接最多8个中断源,但由于可以将2个或多个8259A芯片级连(cascade),并且最多可以级连到9个,所以最多可以接64个中断源。如今绝大多数的PC都拥有两个8259A,这样 最多可以接收15个中断源。
|
||||
|
||||
8259提供了两种屏蔽方式:1,简单方式,提供8位屏蔽字对应各个IR。2,特殊方式,允许CPU让低优先级的外设去中断高优先级的服务程序。
|
||||
|
||||
#### 内部结构
|
||||
|
||||

|
||||
|
||||
- IRR:中断请求寄存器8位,IR0~IR7每一位对应一个设备,共可接收8个设备的中断请求。
|
||||
- IMR:中断屏蔽寄存器为8位,设置需要屏蔽的中断请求
|
||||
- ISR:中断服务寄存器为8位,保存当前正在处理的中断请求
|
||||
- PR:优先权判别器。当多个中断同时发生时,将高优先级者优先传递给CPU。优先级选择方式有4种:1,完全嵌套方式,优先级从IR0到IR7依次降低。2,轮换方式A,一个中断完成后立即把它放到最低优先级的位置上。3,轮换方式B,CPU可以在任何时间规定最优优先级。4,查询方式,CPU访问中断状态寄存器。
|
||||
- 控制逻辑:向CPU发出中断请求信号INT,并接受CPU的中断响应信号INTA。
|
||||
- 数据总线缓冲器:保存数据总线的数据,传输命令控制字、状态字和中断类型码。
|
||||
- 读/写逻辑:确定数据总线缓冲器中数据的传输方向,选择内部的各命令字寄存器。RD为读,WR为写,AO为I/O端口识别,CS为设备选择。
|
||||
- 级联缓冲/比较器:主从控制器的级联是由级联总线CAS0,CAS1,CAS2实现的。
|
||||
|
||||
#### 工作原理
|
||||
|
||||

|
||||
|
||||
#### 实例:两个中断控制器连接
|
||||
|
||||

|
||||
|
||||
Master 8259A:
|
||||
0x20: ICW1,OCW2,OCW3,IRR,ISR
|
||||
0x21: ICW2,ICW3,ICW4,IMR, address registers
|
||||
Slave 8259A:
|
||||
0xA0: ICW1,OCW2,OCW3,IRR,ISR
|
||||
0xA1: ICW2,ICW3,ICW4,IMR, address registers
|
|
@ -0,0 +1,57 @@
|
|||
#### 中断概述
|
||||
|
||||
中断是由硬件设备产生的电信号,它首先被中断控制器处理,中断控制器再把与它唯一对应的数据发送到处理器的数据总线。之所以要唯一对应,是因为处理器只有1个输入来接收设备中断,它没法分清是哪个设备需要服务。英特尔32位处理器一般有2个中断控制器,每个中断控制器可以处理8个输入,由于一个从控制器的输出连到主控制器的输入,所以2个中断控制器组合起来一共可以处理15个外设的中断。中断控制器里的0号插座是专有的,只能接时钟输入;其它插座则可以接任意设备。
|
||||
|
||||
主中断控制器的INT引脚连接CPU的INT引脚,从中断控制器的INT引脚则连到主中断控制器的输入插座上。中断控制器就是通过这个INT引脚告诉CPU中断来了。CPU的INTA引脚和中断控制器的INTA引脚相连,它通过向中断控制器的INTA引脚发信号使得中断控制器把数据发到系统数据总线上,这样处理器就知道该执行哪个服务例程了。
|
||||
|
||||
##### CPU如何处理中断
|
||||
|
||||
当一个进行着的进程收到中断时,处理器会为中断服务设置一个新栈。这个栈的位置由**任务状态段**(TSS)里的一个入口决定。处理器会自动把若干重要的寄存器压到这个栈上,包括恢复被中断进程自已的栈和程序计数器所必须的那些寄存器。
|
||||
|
||||
当从中断返回被中断的进程时,会执行`iretd`指令。`iretd`恢复中断前的状态,恢复被硬件压入的寄存器,并切换回中断发生之前的栈。
|
||||
|
||||
当CPU收到一个中断后,会关闭所有的中断。这样就可以保证进程的栈桢不会溢出。当进程表之外的内核栈被使用时,中断始终处于关闭的状态。当内核栈被使用时,也有机制可以保证异常处理例程可以运行。可以把异常理解为不能关闭的中断。当异常发生时,CPU把必要的寄存器压入当前的栈里。当内核运行时不应发生异常,否则将产生panic。
|
||||
|
||||
`iretd`返回内核进程和返回用户进程的机制是类似的,处理器通过检查代码段选择器来决定如何处理`iretd`。
|
||||
|
||||
#### 8259A概述
|
||||
|
||||

|
||||
|
||||
8259A芯片是一个中断管理芯片,中断的来源除了来自于硬件自身的NMI中断和来自于软件的`INT n`指令造成的软件中断之外,还有来自于外部硬件设备的中断,这些中断是可屏蔽的。这些中断也都通过**PIC**(Programmable Interrupt Controller)进行控制,并传递给CPU。
|
||||
|
||||
一个8259A芯片的可以接最多8个中断源,但由于可以将2个或多个8259A芯片级连(cascade),并且最多可以级连到9个,所以最多可以接64个中断源。如今绝大多数的PC都拥有两个8259A,这样 最多可以接收15个中断源。
|
||||
|
||||
8259提供了两种屏蔽方式:1,简单方式,提供8位屏蔽字对应各个IR。2,特殊方式,允许CPU让低优先级的外设去中断高优先级的服务程序。
|
||||
|
||||
8259芯片里保存了一个表,这个表会生成一个8位的索引,CPU使用它来为每个可能的中断输入找到正确的中断门描述符。这个表是由BIOS初始化的。当使用了中断的驱动程序启动的时候,可以根据需要进行修改。驱动程序可以请求对相应的位进行重置来开启它需要的中断。
|
||||
|
||||
|
||||
|
||||
#### 内部结构
|
||||
|
||||

|
||||
|
||||
- IRR:中断请求寄存器8位,IR0~IR7每一位对应一个设备,共可接收8个设备的中断请求。
|
||||
- IMR:中断屏蔽寄存器为8位,设置需要屏蔽的中断请求
|
||||
- ISR:中断服务寄存器为8位,保存当前正在处理的中断请求
|
||||
- PR:优先权判别器。当多个中断同时发生时,将高优先级者优先传递给CPU。优先级选择方式有4种:1,完全嵌套方式,优先级从IR0到IR7依次降低。2,轮换方式A,一个中断完成后立即把它放到最低优先级的位置上。3,轮换方式B,CPU可以在任何时间规定最优优先级。4,查询方式,CPU访问中断状态寄存器。
|
||||
- 控制逻辑:向CPU发出中断请求信号INT,并接受CPU的中断响应信号INTA。
|
||||
- 数据总线缓冲器:保存数据总线的数据,传输命令控制字、状态字和中断类型码。
|
||||
- 读/写逻辑:确定数据总线缓冲器中数据的传输方向,选择内部的各命令字寄存器。RD为读,WR为写,AO为I/O端口识别,CS为设备选择。
|
||||
- 级联缓冲/比较器:主从控制器的级联是由级联总线CAS0,CAS1,CAS2实现的。
|
||||
|
||||
#### 工作原理
|
||||
|
||||

|
||||
|
||||
#### 实例:两个中断控制器连接
|
||||
|
||||

|
||||
|
||||
Master 8259A:
|
||||
0x20: ICW1,OCW2,OCW3,IRR,ISR
|
||||
0x21: ICW2,ICW3,ICW4,IMR, address registers
|
||||
Slave 8259A:
|
||||
0xA0: ICW1,OCW2,OCW3,IRR,ISR
|
||||
0xA1: ICW2,ICW3,ICW4,IMR, address registers
|
|
@ -1,18 +1,4 @@
|
|||
#### 中断概述
|
||||
|
||||
中断是由硬件设备产生的电信号,它首先被中断控制器处理,中断控制器再把与它唯一对应的数据发送到处理器的数据总线。之所以要唯一对应,是因为处理器只有1个输入来接收设备中断,它没法分清是哪个设备需要服务。英特尔32位处理器一般有2个中断控制器,每个中断控制器可以处理8个输入,由于一个从控制器的输出连到主控制器的输入,所以2个中断控制器组合起来一共可以处理15个外设的中断。中断控制器里的0号插座是专有的,只能接时钟输入;其它插座则可以接任意设备。
|
||||
|
||||
主中断控制器的INT引脚连接CPU的INT引脚,从中断控制器的INT引脚则连到主中断控制器的输入插座上。中断控制器就是通过这个INT引脚告诉CPU中断来了。CPU的INTA引脚和中断控制器的INTA引脚相连,它通过向中断控制器的INTA引脚发信号使得中断控制器把数据发到系统数据总线上,这样处理器就知道该执行哪个服务例程了。
|
||||
|
||||
##### CPU如何处理中断
|
||||
|
||||
当一个进行着的进程收到中断时,处理器会为中断服务设置一个新栈。这个栈的位置由**任务状态段**(TSS)里的一个入口决定。处理器会自动把若干重要的寄存器压到这个栈上,包括恢复被中断进程自已的栈和程序计数器所必须的那些寄存器。
|
||||
|
||||
当从中断返回被中断的进程时,会执行`iretd`指令。`iretd`恢复中断前的状态,恢复被硬件压入的寄存器,并切换回中断发生之前的栈。
|
||||
|
||||
当CPU收到一个中断后,会关闭所有的中断。这样就可以保证进程的栈桢不会溢出。当进程表之外的内核栈被使用时,中断始终处于关闭的状态。当内核栈被使用时,也有机制可以保证异常处理例程可以运行。可以把异常理解为不能关闭的中断。当异常发生时,CPU把必要的寄存器压入当前的栈里。当内核运行时不应发生异常,否则将产生panic。
|
||||
|
||||
`iretd`返回内核进程和返回用户进程的机制是类似的,处理器通过检查代码段选择器来决定如何处理`iretd`。
|
||||
|
||||
#### APIC简介
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#### 帮助
|
||||
|
||||
- 可参考[语言->汇编->i386.md]里与保护模式相关的内容
|
||||
|
||||
### 保护模式下访问系统资源
|
||||
|
||||
之所以用描述符的形式来组织数据,是有两个原因:硬件细节、与16位286处理器兼容。
|
||||
|
||||
#### GDT
|
||||
|
||||
全局描述符表,通过`GDTR`寄存器来找到它。
|
||||
|
||||
GDT中放的是段描述符,GDT的段描述符里记录了操作系统所使用的内存区域。GDT对所有进程可见。
|
||||
|
||||
> GDT里所说的段是硬件定义的段,它和操作系统所管理的段是不一样的。操作系统把硬件定义的数据段再分为数据段和栈段。
|
||||
|
||||
段描述符是8字节的结构体,包含了许多内容,但最重要的部分是描述基址的字段和描述内存限长的字段。
|
||||
|
||||
#### LDT
|
||||
|
||||
局部描述符表,通过`LDTR`寄存器来找到它。
|
||||
|
||||
LDT中放的是段描述符,LDT的段描述符里记录了进程所使用的内存区域。一般一个进程对应一个LDT。
|
||||
|
||||
#### IDT
|
||||
|
||||
中断门描述符表,通过`IDTR`寄存器来找到它。通过中断门描述符表,那些为异常、硬件中断或软件中断服务的代码片断可以得以执行。
|
||||
|
||||
IDT中放的是中断门描述符,即中断处理程序的入口。
|
||||
|
||||
门描述符也是8字节的结构体,最重要的部分是当对应中断激活时要执行的代码的地址。
|
|
@ -56,6 +56,10 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
|||
*/
|
||||
int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
|
||||
/* 获取网络插座sockfd的状态
|
||||
*/
|
||||
int getsockopt(int sockfd, int level, int optname, void *restrict optval, socklen_t *restrict optlen);
|
||||
|
||||
/* 让服务端的网络插座sockfd变成被动网络插座。(网络插座默认是主动)
|
||||
*/
|
||||
int listen(int sockfd, int backlog);
|
||||
|
@ -98,6 +102,11 @@ ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
|
|||
// SOCK_STREAM - 提供顺序的、可靠的、双向的、基于连接的字节流。
|
||||
// SOCK_DGRAM - 支持数据报(无连接的,不可靠的,消息有最大长度)。
|
||||
// protocol:指定网络插座要用的协议。通常一个网络插座的类型对应唯一的协议,此时此参数可指定为0;但若存在对应多个协议的情况,此时必须指定协议号。(详见/etc/protocols)
|
||||
|
||||
/* 设置网络插座sockfd的状态
|
||||
*/
|
||||
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
|
||||
|
||||
int socket(int domain, int type, int protocol);
|
||||
|
||||
/* 作用:创建两个网络插座,并使它们之间互相连接。
|
||||
|
|
|
@ -43,6 +43,16 @@
|
|||
|
||||
|
||||
|
||||
### 函数
|
||||
|
||||
```bash
|
||||
function help(){
|
||||
echo "help"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
# --------------------
|
||||
|
||||
#### 基本格式
|
||||
|
|
|
@ -1,14 +1,51 @@
|
|||
#### 1 BlockingIOError
|
||||
|
||||
##### 错误描述:
|
||||
错误描述:
|
||||
|
||||
```
|
||||
BlockingIOError: [Errno 11] write could not complete without blocking
|
||||
```
|
||||
|
||||
##### 原因分析:
|
||||
原因分析:
|
||||
|
||||
我面临的情况是子进程写管道,当前进程读管道,当前进程把子进程输出的信息打印出来。当子进程向管道写入信息太多时,管道阻塞,于是抛出此错误。
|
||||
|
||||
##### 解决方法:
|
||||
解决方法:
|
||||
|
||||
方法一:当产生此异常时执行`pass`,不管它。
|
||||
|
||||
方法二:减少要输出的信息。
|
||||
|
||||
方法三:将管道设置为非阻塞
|
||||
|
||||
#### 2 UnicodeDecodeError
|
||||
|
||||
错误描述:
|
||||
|
||||
```
|
||||
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8e in position 2816: invalid start byte
|
||||
```
|
||||
|
||||
原因分析:
|
||||
|
||||
这应该是文本里混入了非utf-8编码,然而我用xxd命令却没查到0x8e这个数字。
|
||||
|
||||
解决方法:
|
||||
|
||||
应该是把非utf-8编码改为utf-8编码。
|
||||
|
||||
#### 3
|
||||
|
||||
错误描述:
|
||||
|
||||
```
|
||||
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
|
||||
```
|
||||
|
||||
原因分析:
|
||||
|
||||
应该还是输出信息太多引起的
|
||||
|
||||
解决方法:
|
||||
|
||||
当出现异常`BrokenPipeError`和`IOError`的时候执行`pass`。
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
#### format
|
||||
|
||||
使用运行时表达式来创建`String`。`format!`常用来连接字符串。
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#### 模块
|
||||
|
||||
- consts - 与当前目标相关的常数
|
||||
|
||||
#### 结构体
|
||||
|
||||
- Args - 进程参数的迭代器,为每个参数都生成一个`String`类型的值。
|
||||
|
@ -12,10 +14,20 @@
|
|||
pub struct Args { /* fields omitted */ }
|
||||
```
|
||||
|
||||
|
||||
- ArgsOs
|
||||
|
||||
- JoinPathsError
|
||||
|
||||
- SplitPaths
|
||||
|
||||
- Vars
|
||||
|
||||
- VarsOs
|
||||
|
||||
#### 枚举类型
|
||||
|
||||
- VarError
|
||||
|
||||
#### 函数
|
||||
|
||||
- args - 返回传递给本程序的命令行参数。
|
||||
|
@ -24,4 +36,30 @@
|
|||
pub fn args() -> Args
|
||||
```
|
||||
|
||||
|
||||
- args_os
|
||||
|
||||
- current_dir
|
||||
|
||||
- current_exe
|
||||
|
||||
- home_dir
|
||||
|
||||
- join_paths
|
||||
|
||||
- remove_var
|
||||
|
||||
- set_current_dir
|
||||
|
||||
- set_var
|
||||
|
||||
- split_paths
|
||||
|
||||
- temp_dir
|
||||
|
||||
- var
|
||||
|
||||
- var_os
|
||||
|
||||
- vars
|
||||
|
||||
- vars_os
|
|
@ -0,0 +1,11 @@
|
|||
#### 参考资料
|
||||
|
||||
- [pwn-fuchsia](https://a13xp0p0v.github.io/2022/05/24/pwn-fuchsia.html)
|
||||
|
||||
#### 概述
|
||||
|
||||
- 没有属主的概述,而是基于访问能力的。
|
||||
- 基于微内核,这使内核被攻击面变小了。
|
||||
- 所有的用户态程序都是在各自的沙箱中运行的。
|
||||
- 用户态程序由URL标识,可以按需解析、下载和执行。
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
#### 设计目标
|
||||
|
||||
- 可以在运行时配置I/O设备
|
||||
- 让主要的系统组件成为与内核分开的独立进程
|
||||
|
||||
#### 重要概念
|
||||
|
||||
##### minix3的四层结构
|
||||
|
||||
| 层级 | 进程类型 | 包含的进程 |
|
||||
| ------------ | -------- | -------------------------------------------------- |
|
||||
| 4 (用户模式) | 用户进程 | init进程, 若干用户进程 |
|
||||
| 3 (用户模式) | 服务进程 | 进程管理器,文件系统,信息服务程序,网络服务程序等 |
|
||||
| 2 (用户模式) | 设备驱动 | TTY驱动程序,以太网驱动程序等 |
|
||||
| 1 (内核模式) | 内核进程 | 内核,时钟任务,系统任务 |
|
||||
|
||||
##### 各种调用
|
||||
|
||||
- 系统调用
|
||||
|
||||
在宏内核里,系统调用指内核提供的所有调用。
|
||||
|
||||
在Minix3里,系统调用在形式上和宏内核是一样的,但它不直接向内核请求服务,而是向服务进程发消息。服务进程之间,服务进程与驱动、内核之间也是通过消息来通信的。
|
||||
|
||||
- 内核调用
|
||||
|
||||
直接向内核请求服务的调用。用户进程无法进行内核调用,服务进程和驱动程序才能进行内核调用。内核调用和系统调用常有类似的名字,因为有些操作只能在内核里进行。
|
||||
|
||||
- 消息原语
|
||||
|
||||
用于进程间通信,如send、receive、notify等。有时也被叫**IPC原语**或**自陷**。它们确实调用了系统,但即不应称为系统调用也不应称为内核调用。
|
||||
|
||||
##### 系统任务接收的消息
|
||||
|
||||
其实就是内核调用,共有28个。
|
||||
|
||||
- 进程管理
|
||||
|
||||
sys_fork, sys_exec, sys_exit, sys_trace : 与POSIX系统调用相关的内核调用
|
||||
|
||||
sys_nice:设置进程的调度优先级
|
||||
|
||||
sys_privctl : 再生服务程序RS用它来改变进程的特权。驱动程序和不在启动镜像里的服务程序通过`/etc/rc`脚本启动时,将会需要特权转换。
|
||||
|
||||
- 信号
|
||||
|
||||
sys_kill : 与系统调用`kill`相关
|
||||
|
||||
sys_getksig, sys_endksig, sys_sigsend, sys_sigreturn : 进程管理器用它们来操作信号
|
||||
|
||||
- 设备驱动的支持
|
||||
|
||||
sys_irqctl : 开启、关闭或配置中断
|
||||
|
||||
sys_devio :读写I/O端口
|
||||
|
||||
sys_sdevio:从I/O端口读写字符串。例如访问串口时会用到它。
|
||||
|
||||
sys_vdevio:执行一个I/O所请求的向量。向量指的是一串(port, value)对。
|
||||
|
||||
- 关于内存
|
||||
|
||||
sys_newmap:当进程的内存发生改变时,进程管理器调用它来更新内核里的进程表。
|
||||
|
||||
sys_regctl:设备驱动用它来获取一个段选择子,这样就可以访问I/O设备占用的内存区域了(0xa0000~0xfffff)。
|
||||
|
||||
sys_memset:服务进程用它来写数据到不属于自己的内存里。当新进程创建时,进程管理器用它来为新进程清空内存。
|
||||
|
||||
- 复制内存
|
||||
|
||||
sys_umap:把虚拟地址转换为物理地址。
|
||||
|
||||
sys_vircopy, sys_physcopy:使用虚拟或物理地址复制内存。
|
||||
|
||||
sys_virvcopy, sys_physcopy:使用向量化的I/O请求,它们可以向系统任务请求一系统的内存复制操作。
|
||||
|
||||
- 其它
|
||||
|
||||
sys_times:对应了`times`系统调用。
|
||||
|
||||
sys_setalarm:与`alarm`系统调用相关。
|
||||
|
||||
sys_abort:当要求关闭系统或产生panic之后,进程管理器会产生此内核调用;当用户按下`Ctrl-Alt_Del`组合键后,tty设备驱动也会产生此内核调用。
|
||||
|
||||
sys_getinfo:获取内核的信息。在`include/minix/syslib.h`里定义了获取内核信息的各种宏,它们都是使用的此内核调用。
|
||||
|
||||
#### 进程调度
|
||||
|
||||
Minix3使用的多级调度算法。具体过程是:先找到优先级最高的非空的队列,然后选择顶头的进程开始执行。`IDLE`进程在最低优先级队列里,且始终是处于就绪的状态,这就保证没有其它进程时至少还有一个进程可以跑。
|
||||
|
||||
初始状态下,时钟和系统任务在第1级,拥有最高的权限。设备驱动在第2级。服务进程在第3级。用户进程在更低的层级,但可以通过`nice`命令来调整。
|
||||
|
||||
时钟任务用于监控所有进程的时间。
|
||||
|
||||
任务、驱动程序和服务程序除非被阻塞,否则应该是一直运行的,它们会有大的时间片。它们如果运行的太久,也是可能被抢占的,这种机制可以防止有问题的高优先级进程锁死系统。
|
||||
|
||||
调度器管理着16个就绪队列。数组`rdy_head`保存了每个就绪队列的头,而数组`rdy_tail`保存了每个就绪队列的尾。
|
||||
|
||||
每个队列上使用的是轮转调度算法。时间片用完的进程会调度到队列的末尾,时间片没用完但被阻塞的进程再唤醒时会放在队列的顶头。
|
||||
|
||||
#### 驱动程序注册中断的过程
|
||||
|
||||
1. 一个用户态的、由中断驱动的设备驱动程序,当它需要注册一个中断处理例程时,会向系统任务发出`sys_irqctl`调用。
|
||||
2. 系统任务再调用`put_irq_handler`。但是在中断例程的字段里保存的将是系统任务所在内核空间的`generic_handler`的地址,而不是驱动程序所在用户空间的中断处理例程的地址。
|
||||
3. `generic_handler`用钩子结构体里的进程号字段定位此驱动程序在`priv`表里的入口,此中断在驱动程序的挂起中断位图里的对应位会置1。
|
||||
4. `generic_handler`向驱动程序发一个通知。此通知被识别为来自HARDWARE,驱动程序的挂起中断位图也包含在此消息里。
|
||||
5. 钩子结构体里的policy字段决定中断是立即打开还是保持关闭。如果是保持关闭,则驱动程序还需要发出一个内核调用`sys_irqenable`来开打中断。
|
||||
|
||||
#### 系统任务
|
||||
|
||||
系统任务是从内核中独立出来的进程,它不能像内核函数那样自由,不能进行实际的I/O,也不能操作内核表。
|
||||
|
||||
那么系统任务(驱动和服务程序)怎么和内核交互呢?答案是内核向它们提供一组服务。这些服务对普通用户是不可见的,系统任务通过这些服务进行实际的I/O,操作内核表等。
|
||||
|
||||
系统任务的工作就是就是接收上层对内核服务的请求并执行它们。上层的进程由于在用户态,无法访问内核里的数据结构,但系统任务可以。
|
||||
|
||||
系统任务的主程序在做完必要的初始化后就会进入一个循环。获取消息,发给合适的服务例程,然后发送一个回复。主文件`system.c`里有一些的通用支持函数,但处理内核调用是在`kernel/system`目录下进行的。
|
|
@ -120,3 +120,10 @@ make menuconfig # 调整.config
|
|||
make CROSS_COMPILE=riscv64-linux-gnu- ARCH=riscv -j8 install
|
||||
```
|
||||
|
||||
#### 问题解决
|
||||
|
||||
1. 问题描述:libwacom9 : Depends: libwacom-common (= 2.2.0-1) but 1.12-1 is to be installed
|
||||
|
||||
原因分析:依赖冲突?
|
||||
|
||||
解决方法:`apt install libwacom9 libwacom2-`
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#### archLinux安装过程分析
|
||||
#### 安装过程分析
|
||||
|
||||
本文是对archlinux安装过程原理的分析,而不是安装引导,具体的安装步骤请参照wiki.archlinux.org。
|
||||
|
||||
|
@ -33,7 +33,7 @@
|
|||
|
||||
|
||||
|
||||
#### 在qemu上安装archLinux
|
||||
#### 在qemu上安装
|
||||
|
||||
1. qemu的网络采用tun/tap方式,这是最好连网方式
|
||||
```
|
||||
|
@ -106,7 +106,7 @@
|
|||
pacman -S net-tools //这样才可以使用ifconfig等工具
|
||||
```
|
||||
|
||||
#### U盘安装
|
||||
#### 在物理机上安装
|
||||
|
||||
##### 1. 制作启动盘
|
||||
|
||||
|
@ -200,3 +200,11 @@ vim /etc/asound.conf
|
|||
pacman -S gst-plugins-base gst-plugins-bad gst-plugins-good gst-plugins-ugly gst-libav
|
||||
```
|
||||
|
||||
#### 使用AUR
|
||||
|
||||
```
|
||||
git clone # 下载
|
||||
makepkg -si # 安装或更新包,并使用pacman安装缺失的依赖
|
||||
pacman -Rs # 卸载包
|
||||
```
|
||||
|
||||
|
|
|
@ -61,9 +61,33 @@
|
|||
- Job matrix:一个matrix生成的job数不得超过256个。
|
||||
- Workflow运行队列:每个仓库10秒内的的wrokflow队列不得超过500个
|
||||
|
||||
##### 编写action
|
||||
|
||||
- Dockerfile : 用于创建Docker容器action
|
||||
- action.yml:action的配置
|
||||
- `input:<args>`定义接收的参数,其中`required`为true则必须传递此参数。
|
||||
- `runs:`定义运行环境,比如docker。
|
||||
- entrypoint.sh:执行脚本。
|
||||
|
||||
##### 例子:代码同步
|
||||
|
||||
1. `ssh-keygen`生成一个密钥对,私钥放github,公钥放gitlink。
|
||||
1. `ssh-keygen`生成一个密钥对,私钥放github的`仓库设置->Secrets`下,公钥放gitee的`个人设置->SSH公钥`下。
|
||||
2. gitee的个人设置下新建一个私人令牌,保存到github仓库设置的`secrets`下。
|
||||
3. 在github仓库里`.github/workflow/`目录下新建一个yml文件,使用第三方action实现推送。
|
||||
|
||||
##### 例子:缓存文件
|
||||
|
||||
- 输入:
|
||||
|
||||
`path` - 要缓存的文件和目录
|
||||
|
||||
`key` - 为保存文件而设置的键
|
||||
|
||||
`restore-keys` - 键的列表,如果缓存没有命中用来恢复缓存
|
||||
|
||||
- 输出:
|
||||
|
||||
`cache-hit` - 一个布尔值,表示是否为键找到了确切的匹配。
|
||||
|
||||
#### 免密登陆
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ Client URL,用来请求web服务器,是一个上传下载工具。
|
|||
-S, --show-error # 与-s联用,当产生错误时会显示出错信息。
|
||||
-v, --verbose # 显示一次http通信的整个过程。
|
||||
-x, --proxy [protocol://]<host>[:port] # 指定代理。
|
||||
-X, --request <method> #
|
||||
```
|
||||
|
||||
|
||||
|
|
|
@ -106,6 +106,7 @@ tar {-x|--extract|--get} [-f <achive>] [options] [member...]: 从归档文件中
|
|||
|
||||
```
|
||||
tar cf abc.tar ./abc # 给abc目录创建归档文件abc.tar
|
||||
tar -cJf abc.tar.xz ./abc # 给abc目录创建归档文件并压缩
|
||||
tar xf abc.tar -C ~/ # 将abc.tar解压到用户目录
|
||||
tar tf abc.tar # 列出abc.tar里的文件
|
||||
tar tf abc.tar | awk -F "/" '{print $2}' | uniq
|
||||
|
|
|
@ -20,7 +20,7 @@ lzcat # 等价于xz -dc -F lzma,解压lzma文件并输出到stdout
|
|||
##### 操作模式
|
||||
|
||||
```
|
||||
--z, --compress # 压缩
|
||||
-z, --compress # 压缩
|
||||
-d, --decompress, --uncompress # 解压
|
||||
-t, --test
|
||||
-l, --list
|
||||
|
@ -67,3 +67,22 @@ lzcat # 等价于xz -dc -F lzma,解压lzma文件并输出到stdout
|
|||
##### 配置压缩过滤链
|
||||
|
||||
##### 其它
|
||||
|
||||
#### 示例
|
||||
|
||||
##### 基本
|
||||
|
||||
```
|
||||
xz foo # 把文件foo压缩为foo.xz,并在压缩成功后删除foo
|
||||
xz -dk bar.xz # 解压缩bar.xz为bar,且在解压成功后不删除bar.xz
|
||||
tar cf - baz | xz -4e > baz.tar.xz
|
||||
# 从文件baz创建baz.tar.xz,比默认的-6更慢但会需要更少的内存
|
||||
xz -dcf a.txt b.txt.xz c.txt d.txt.lzma > abcd.txt
|
||||
# 只用一条命令就可以把压缩文件和非压缩文件合并为一个文件
|
||||
```
|
||||
|
||||
##### 并行压缩
|
||||
|
||||
##### 机器人模式
|
||||
|
||||
##### 配置压缩过滤链
|
||||
|
|
|
@ -58,6 +58,9 @@ sed -i "/abcd/d" input-file
|
|||
# 将指定目录path下的所有文件里的oldstr替换为newstr
|
||||
sed -i "s/oldstr/newstr/g" `grep oldstr -rl path`
|
||||
|
||||
# 删除每行里的前51个字符
|
||||
sed -i "s/.\{51\}//" file
|
||||
|
||||
# 把文件里从start到end之间的内容打印出来(包含start和end所在的行)
|
||||
sed -n '/start/,/end/p' file
|
||||
|
||||
|
|
|
@ -12,8 +12,11 @@ vim [options] -q [errorfile] # 编辑首先出错的文件
|
|||
#### 选项
|
||||
|
||||
```
|
||||
+[num] # 打开文件后光标停留在num行
|
||||
-b # 二进制模式。这样文件末尾就不会自动加上'0x0a'了。(0x0a即'\n')
|
||||
-d # 比较多个文件的差异。等价于vimdiff。
|
||||
-o[N] # 横向分屏打开文件。忽略N,则每个文件对应一个分屏。
|
||||
-O[N] # 纵向分屏打开文件。忽略N,则每个文件对应一个分屏。
|
||||
-R # 只读模式。等价于view。
|
||||
```
|
||||
|
||||
|
@ -142,7 +145,7 @@ V # 选择,以行为单位
|
|||
|
||||
|
||||
|
||||
##### 打开多个文件
|
||||
##### 分割屏幕
|
||||
|
||||
```
|
||||
:vsp filename # 纵向分屏,并打开文件filename
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
#### 快捷操作
|
||||
|
||||
- 自动换行:搜索"toggle word wrap"。在Ubuntu下为`alt+z`。或者`File > Preferences > Settings`打开用户设置,将`editor.wordWrap`改为`on`。
|
||||
|
||||
- 向后跳转:在“Keyboard Shortcuts”搜索"Go Back"可得。在Ubuntu下为`Ctrl+Alt+-`
|
||||
|
||||
- 查找文件:搜索"Go to file"可得。在Ubuntu下为`Ctrl+P`
|
||||
- 跳转到括号的另一边:搜索"go to bracket"可得。在Ubuntu下为`Ctrl+Shift+\`
|
||||
|
||||
#### 配置
|
||||
|
||||
- rust支持:安装插件rust-analyzer即可。不要安装插件Rust,会冲突。
|
||||
|
||||
- 配置C语言的库
|
||||
|
||||
Ctrl+Shift+P调出配置窗口,输入edit,选择“C/CPP:Edit Configurations”,在打开的json文件中“includePath”下添加库文件的地址
|
||||
|
||||
- 跳转到括号的另一边:搜索"go to bracket"可得。在Ubuntu下为`Ctrl+Shift+\`
|
||||
#### 问题解决
|
||||
|
||||
1. 问题描述:终端中字体显示不正常,字符之间像隔着空格
|
||||
|
||||
解决方法:打开设置-用户-功能-终端,向下翻找到Font Family,设置为"monospace"
|
||||
|
|
|
@ -74,7 +74,9 @@ docker buildx [options] <cmd> # 使用buildkit来构建
|
|||
bake
|
||||
build [options] <path | url | -> # 开始一个构建
|
||||
-t, --tag <stringArry> # stringArry的格式是'name:tag',其中tag是可选的
|
||||
create
|
||||
create # 创建一个builder实例
|
||||
--name <str> # builder实例的名字
|
||||
--use # 设置当前的builder实例
|
||||
du
|
||||
inspect
|
||||
ls
|
||||
|
@ -349,6 +351,7 @@ docker run [options] <image> [cmd] [args]
|
|||
--name <string> # 指定容器名
|
||||
--network <network> # 把容器连接到一个network
|
||||
-p, --publish <list> # 把容器的端口发布到主机
|
||||
--privileged # 为此容器提供扩展的权限(extended priviledges)
|
||||
--rm # 当exit的时候自动删除容器
|
||||
-t, --tty # 分配一个伪TTY
|
||||
-v, --volume <list> # 绑定并挂载一个卷
|
||||
|
@ -399,12 +402,42 @@ docker stop [options] <containers> # 停止一个或多个运行中的容器。
|
|||
#### 配置
|
||||
|
||||
```
|
||||
# 使用代理上网
|
||||
# 使用代理上网,方法一
|
||||
vim /etc/default/docker # 修改http_proxy
|
||||
|
||||
# 使用代理上网,方法二
|
||||
vim ~/.docker/config.json # 添加如下内容
|
||||
{
|
||||
"proxies":
|
||||
{
|
||||
"default":
|
||||
{
|
||||
"httpProxy":"http://proxy.example.com:8080",
|
||||
"httpsProxy":"http://proxy.example.com:8080",
|
||||
"noProxy":"localhost,127.0.0.1,.example.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 多架构支持
|
||||
|
||||
##### 使用binfmt_misc
|
||||
|
||||
binfmt_misc可以模拟执行异架构的二进制程序
|
||||
|
||||
```
|
||||
apt install binfmtc binfmt-support
|
||||
docker run --rm --privileged multiarch/qemu-user-static --reset --persistent yes
|
||||
docker run -it riscv64/alpine:edge
|
||||
```
|
||||
|
||||
##### 使用buildx子命令
|
||||
|
||||
buildx是下一代标准构建命令的前端
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```
|
||||
|
@ -430,14 +463,16 @@ docker cp alpine-3:root/abc . # 把容器alpine-3的abc文件传到当前目录
|
|||
|
||||
#### 错误分析
|
||||
|
||||
1. 问题描述
|
||||
1. 问题描述:脚本script_file.sh在docker内手动运行正常,但使用`docker exec -d docker_name script_file.sh`运行出错。错误原因是:command not found。
|
||||
|
||||
脚本script_file.sh在docker内手动运行正常,但使用`docker exec -d docker_name script_file.sh`运行出错。错误原因是:command not found。
|
||||
原因分析:因为在`.bashrc`文件里设置了额外的环境变量,而`docker exec`命令并不会设置额外的环境变量。
|
||||
|
||||
原因分析
|
||||
解决方法:在脚本里使用`source`命令设置所需要的环境变量。
|
||||
|
||||
因为在`.bashrc`文件里设置了额外的环境变量,而`docker exec`命令并不会设置额外的环境变量。
|
||||
2. 问题描述:`Cannot connect to the Docker daemon`
|
||||
|
||||
解决方法
|
||||
|
||||
在脚本里使用`source`命令设置所需要的环境变量。
|
||||
原因分析:docker的守护进程没有启动
|
||||
|
||||
解决方法:要找到具体的原因,比如用`systemctl status docker`进一步排查。
|
||||
|
||||
3. 问题描述:`start request repeated too quickly for docker.service`
|
||||
|
|
|
@ -6,3 +6,12 @@
|
|||
chroot [options] <root-dir> [<command> [args]]
|
||||
```
|
||||
|
||||
#### 问题解决
|
||||
|
||||
1
|
||||
|
||||
问题描述:`can't execute '/bin/sh': No such file or directory`
|
||||
|
||||
原因分析:要切换过去的目录里没bin/sh
|
||||
|
||||
解决方法:`cp /bin/bash bin/sh`
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
快速版的`getopt`命令。
|
||||
|
||||
#### 示例
|
||||
|
||||
```bash
|
||||
```
|
||||
|
|
@ -144,11 +144,12 @@ pacman -S --help # 查询安装软件包的方法
|
|||
|
||||
##### 1
|
||||
|
||||
**错误提示**:error: failed to commit transaction (conflicting files)。
|
||||
- 错误提示:error: failed to commit transaction (conflicting files)。
|
||||
|
||||
原因分析:这是文件冲突,pacman不会主动覆盖已经存在的文件。
|
||||
- 原因分析:这是文件冲突,pacman不会主动覆盖已经存在的文件。
|
||||
|
||||
- 解决方法:将冲突的文件删除,重命名或转移到其它文件夹。
|
||||
|
||||
解决方法:将冲突的文件删除,重命名或转移到其它文件夹。
|
||||
|
||||
##### 2
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
```
|
||||
getopt [options] [--] <optstring> <parameters>
|
||||
getopt [options] <-o|--options> <optstring> [options] [--] <parameters>
|
||||
# options和sptstring决定解析的方式
|
||||
# options和optstring决定解析的方式
|
||||
# parameters是要解析的内容
|
||||
```
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#### 交互命令
|
||||
|
||||
```
|
||||
help # 获取可用的命令
|
||||
select <MAC> # 选择默认控制器
|
||||
power on # 开启控制器。默认是关闭的。
|
||||
devices # 获取要配对的MAC地址
|
||||
scan on # 扫描设备
|
||||
pair <MAC> # 配对
|
||||
connect <MAC> # 完成连接
|
||||
```
|
||||
|
|
@ -81,3 +81,16 @@ strace [options] <command> [args]
|
|||
-V # 打印版本号。
|
||||
```
|
||||
|
||||
#### 错误记录
|
||||
|
||||
##### 1
|
||||
|
||||
- 错误描述:docker里运行strace,提示`ptrace(PTRACE_TRACEME, ...): Function not implemented`
|
||||
- 原因分析:请参考[why-strace-doesnt-work-in-docker](https://jvns.ca/blog/2020/04/29/why-strace-doesnt-work-in-docker/)
|
||||
- 解决方法:`docker run --cap-add=SYS_PTRACE -it ubuntu:18.04 /bin/bash`
|
||||
|
||||
##### 2
|
||||
|
||||
- 错误描述:shell脚本里运行strace,提示`strace: exec: Permission denied`
|
||||
- 原因分析:不知道为什么
|
||||
- 解决方法:`bash ./script.sh`
|
||||
|
|
Loading…
Reference in New Issue