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简介
|
#### 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);
|
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变成被动网络插座。(网络插座默认是主动)
|
/* 让服务端的网络插座sockfd变成被动网络插座。(网络插座默认是主动)
|
||||||
*/
|
*/
|
||||||
int listen(int sockfd, int backlog);
|
int listen(int sockfd, int backlog);
|
||||||
|
@ -98,6 +102,11 @@ ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
|
||||||
// SOCK_STREAM - 提供顺序的、可靠的、双向的、基于连接的字节流。
|
// SOCK_STREAM - 提供顺序的、可靠的、双向的、基于连接的字节流。
|
||||||
// SOCK_DGRAM - 支持数据报(无连接的,不可靠的,消息有最大长度)。
|
// SOCK_DGRAM - 支持数据报(无连接的,不可靠的,消息有最大长度)。
|
||||||
// protocol:指定网络插座要用的协议。通常一个网络插座的类型对应唯一的协议,此时此参数可指定为0;但若存在对应多个协议的情况,此时必须指定协议号。(详见/etc/protocols)
|
// 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);
|
int socket(int domain, int type, int protocol);
|
||||||
|
|
||||||
/* 作用:创建两个网络插座,并使它们之间互相连接。
|
/* 作用:创建两个网络插座,并使它们之间互相连接。
|
||||||
|
|
|
@ -43,6 +43,16 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 函数
|
||||||
|
|
||||||
|
```bash
|
||||||
|
function help(){
|
||||||
|
echo "help"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------
|
# --------------------
|
||||||
|
|
||||||
#### 基本格式
|
#### 基本格式
|
||||||
|
|
|
@ -1,14 +1,51 @@
|
||||||
#### 1 BlockingIOError
|
#### 1 BlockingIOError
|
||||||
|
|
||||||
##### 错误描述:
|
错误描述:
|
||||||
|
|
||||||
```
|
```
|
||||||
BlockingIOError: [Errno 11] write could not complete without blocking
|
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`类型的值。
|
- Args - 进程参数的迭代器,为每个参数都生成一个`String`类型的值。
|
||||||
|
@ -12,10 +14,20 @@
|
||||||
pub struct Args { /* fields omitted */ }
|
pub struct Args { /* fields omitted */ }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- ArgsOs
|
||||||
|
|
||||||
|
- JoinPathsError
|
||||||
|
|
||||||
|
- SplitPaths
|
||||||
|
|
||||||
|
- Vars
|
||||||
|
|
||||||
|
- VarsOs
|
||||||
|
|
||||||
#### 枚举类型
|
#### 枚举类型
|
||||||
|
|
||||||
|
- VarError
|
||||||
|
|
||||||
#### 函数
|
#### 函数
|
||||||
|
|
||||||
- args - 返回传递给本程序的命令行参数。
|
- args - 返回传递给本程序的命令行参数。
|
||||||
|
@ -24,4 +36,30 @@
|
||||||
pub fn args() -> Args
|
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
|
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。
|
本文是对archlinux安装过程原理的分析,而不是安装引导,具体的安装步骤请参照wiki.archlinux.org。
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 在qemu上安装archLinux
|
#### 在qemu上安装
|
||||||
|
|
||||||
1. qemu的网络采用tun/tap方式,这是最好连网方式
|
1. qemu的网络采用tun/tap方式,这是最好连网方式
|
||||||
```
|
```
|
||||||
|
@ -106,7 +106,7 @@
|
||||||
pacman -S net-tools //这样才可以使用ifconfig等工具
|
pacman -S net-tools //这样才可以使用ifconfig等工具
|
||||||
```
|
```
|
||||||
|
|
||||||
#### U盘安装
|
#### 在物理机上安装
|
||||||
|
|
||||||
##### 1. 制作启动盘
|
##### 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
|
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个。
|
- Job matrix:一个matrix生成的job数不得超过256个。
|
||||||
- Workflow运行队列:每个仓库10秒内的的wrokflow队列不得超过500个
|
- 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联用,当产生错误时会显示出错信息。
|
-S, --show-error # 与-s联用,当产生错误时会显示出错信息。
|
||||||
-v, --verbose # 显示一次http通信的整个过程。
|
-v, --verbose # 显示一次http通信的整个过程。
|
||||||
-x, --proxy [protocol://]<host>[:port] # 指定代理。
|
-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 cf abc.tar ./abc # 给abc目录创建归档文件abc.tar
|
||||||
|
tar -cJf abc.tar.xz ./abc # 给abc目录创建归档文件并压缩
|
||||||
tar xf abc.tar -C ~/ # 将abc.tar解压到用户目录
|
tar xf abc.tar -C ~/ # 将abc.tar解压到用户目录
|
||||||
tar tf abc.tar # 列出abc.tar里的文件
|
tar tf abc.tar # 列出abc.tar里的文件
|
||||||
tar tf abc.tar | awk -F "/" '{print $2}' | uniq
|
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 # 解压
|
-d, --decompress, --uncompress # 解压
|
||||||
-t, --test
|
-t, --test
|
||||||
-l, --list
|
-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
|
# 将指定目录path下的所有文件里的oldstr替换为newstr
|
||||||
sed -i "s/oldstr/newstr/g" `grep oldstr -rl path`
|
sed -i "s/oldstr/newstr/g" `grep oldstr -rl path`
|
||||||
|
|
||||||
|
# 删除每行里的前51个字符
|
||||||
|
sed -i "s/.\{51\}//" file
|
||||||
|
|
||||||
# 把文件里从start到end之间的内容打印出来(包含start和end所在的行)
|
# 把文件里从start到end之间的内容打印出来(包含start和end所在的行)
|
||||||
sed -n '/start/,/end/p' file
|
sed -n '/start/,/end/p' file
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,11 @@ vim [options] -q [errorfile] # 编辑首先出错的文件
|
||||||
#### 选项
|
#### 选项
|
||||||
|
|
||||||
```
|
```
|
||||||
|
+[num] # 打开文件后光标停留在num行
|
||||||
-b # 二进制模式。这样文件末尾就不会自动加上'0x0a'了。(0x0a即'\n')
|
-b # 二进制模式。这样文件末尾就不会自动加上'0x0a'了。(0x0a即'\n')
|
||||||
-d # 比较多个文件的差异。等价于vimdiff。
|
-d # 比较多个文件的差异。等价于vimdiff。
|
||||||
|
-o[N] # 横向分屏打开文件。忽略N,则每个文件对应一个分屏。
|
||||||
|
-O[N] # 纵向分屏打开文件。忽略N,则每个文件对应一个分屏。
|
||||||
-R # 只读模式。等价于view。
|
-R # 只读模式。等价于view。
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -142,7 +145,7 @@ V # 选择,以行为单位
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##### 打开多个文件
|
##### 分割屏幕
|
||||||
|
|
||||||
```
|
```
|
||||||
:vsp filename # 纵向分屏,并打开文件filename
|
:vsp filename # 纵向分屏,并打开文件filename
|
||||||
|
|
|
@ -1,11 +1,20 @@
|
||||||
|
#### 快捷操作
|
||||||
|
|
||||||
- 自动换行:搜索"toggle word wrap"。在Ubuntu下为`alt+z`。或者`File > Preferences > Settings`打开用户设置,将`editor.wordWrap`改为`on`。
|
- 自动换行:搜索"toggle word wrap"。在Ubuntu下为`alt+z`。或者`File > Preferences > Settings`打开用户设置,将`editor.wordWrap`改为`on`。
|
||||||
|
|
||||||
- 向后跳转:在“Keyboard Shortcuts”搜索"Go Back"可得。在Ubuntu下为`Ctrl+Alt+-`
|
- 向后跳转:在“Keyboard Shortcuts”搜索"Go Back"可得。在Ubuntu下为`Ctrl+Alt+-`
|
||||||
|
|
||||||
- 查找文件:搜索"Go to file"可得。在Ubuntu下为`Ctrl+P`
|
- 查找文件:搜索"Go to file"可得。在Ubuntu下为`Ctrl+P`
|
||||||
|
- 跳转到括号的另一边:搜索"go to bracket"可得。在Ubuntu下为`Ctrl+Shift+\`
|
||||||
|
|
||||||
|
#### 配置
|
||||||
|
|
||||||
|
- rust支持:安装插件rust-analyzer即可。不要安装插件Rust,会冲突。
|
||||||
|
|
||||||
- 配置C语言的库
|
- 配置C语言的库
|
||||||
|
|
||||||
Ctrl+Shift+P调出配置窗口,输入edit,选择“C/CPP:Edit Configurations”,在打开的json文件中“includePath”下添加库文件的地址
|
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
|
bake
|
||||||
build [options] <path | url | -> # 开始一个构建
|
build [options] <path | url | -> # 开始一个构建
|
||||||
-t, --tag <stringArry> # stringArry的格式是'name:tag',其中tag是可选的
|
-t, --tag <stringArry> # stringArry的格式是'name:tag',其中tag是可选的
|
||||||
create
|
create # 创建一个builder实例
|
||||||
|
--name <str> # builder实例的名字
|
||||||
|
--use # 设置当前的builder实例
|
||||||
du
|
du
|
||||||
inspect
|
inspect
|
||||||
ls
|
ls
|
||||||
|
@ -349,6 +351,7 @@ docker run [options] <image> [cmd] [args]
|
||||||
--name <string> # 指定容器名
|
--name <string> # 指定容器名
|
||||||
--network <network> # 把容器连接到一个network
|
--network <network> # 把容器连接到一个network
|
||||||
-p, --publish <list> # 把容器的端口发布到主机
|
-p, --publish <list> # 把容器的端口发布到主机
|
||||||
|
--privileged # 为此容器提供扩展的权限(extended priviledges)
|
||||||
--rm # 当exit的时候自动删除容器
|
--rm # 当exit的时候自动删除容器
|
||||||
-t, --tty # 分配一个伪TTY
|
-t, --tty # 分配一个伪TTY
|
||||||
-v, --volume <list> # 绑定并挂载一个卷
|
-v, --volume <list> # 绑定并挂载一个卷
|
||||||
|
@ -399,12 +402,42 @@ docker stop [options] <containers> # 停止一个或多个运行中的容器。
|
||||||
#### 配置
|
#### 配置
|
||||||
|
|
||||||
```
|
```
|
||||||
# 使用代理上网
|
# 使用代理上网,方法一
|
||||||
vim /etc/default/docker # 修改http_proxy
|
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`
|
||||||
|
|
||||||
解决方法
|
原因分析:docker的守护进程没有启动
|
||||||
|
|
||||||
在脚本里使用`source`命令设置所需要的环境变量。
|
解决方法:要找到具体的原因,比如用`systemctl status docker`进一步排查。
|
||||||
|
|
||||||
|
3. 问题描述:`start request repeated too quickly for docker.service`
|
||||||
|
|
|
@ -6,3 +6,12 @@
|
||||||
chroot [options] <root-dir> [<command> [args]]
|
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
|
##### 1
|
||||||
|
|
||||||
**错误提示**:error: failed to commit transaction (conflicting files)。
|
- 错误提示:error: failed to commit transaction (conflicting files)。
|
||||||
|
|
||||||
原因分析:这是文件冲突,pacman不会主动覆盖已经存在的文件。
|
- 原因分析:这是文件冲突,pacman不会主动覆盖已经存在的文件。
|
||||||
|
|
||||||
|
- 解决方法:将冲突的文件删除,重命名或转移到其它文件夹。
|
||||||
|
|
||||||
解决方法:将冲突的文件删除,重命名或转移到其它文件夹。
|
|
||||||
|
|
||||||
##### 2
|
##### 2
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
```
|
```
|
||||||
getopt [options] [--] <optstring> <parameters>
|
getopt [options] [--] <optstring> <parameters>
|
||||||
getopt [options] <-o|--options> <optstring> [options] [--] <parameters>
|
getopt [options] <-o|--options> <optstring> [options] [--] <parameters>
|
||||||
# options和sptstring决定解析的方式
|
# options和optstring决定解析的方式
|
||||||
# parameters是要解析的内容
|
# 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 # 打印版本号。
|
-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