update 1_操作系统接口.md
This commit is contained in:
parent
e4938715eb
commit
abdd456950
|
@ -51,11 +51,27 @@ fork函数一次调用两次返回,这很怪异,因为一般的调用都是
|
||||||
|
|
||||||
##### exec
|
##### exec
|
||||||
|
|
||||||
文件位置:kernel/exec.c。作用:把当前进程的内存替换为硬盘上的内存镜像并执行之。`exec`有两个参数,第一个是要执行的程序,第二个这个程序的参数(以字符串数组的形式出现)。
|
文件位置:kernel/exec.c。作用:把当前进程的内存替换为文件里保存的内存镜像并执行之。`exec`有两个参数,第一个是要执行的程序,第二个这个程序的参数(以字符串数组的形式出现)。
|
||||||
|
|
||||||
|
`exec`首先用`namei`来打开文件`path`。然后,读取ELF header。xv6的程序是用ELF格式来读取的(ELF格式详见kernel/elf.h)。在一个ELF二进制里,ELF header(`struct elfhdr`)在头部的位置,接下来是些程序头(`struct proghdr`),每个程序头都描述了一个必须被载入内存里的段(section)。xv6的程序只有一个程序头,但其它系统指令和数据可能会有不同的段(section)。
|
||||||
|
|
||||||
|
第一步是快速检查文件是否正确包含了一个ELF二进制。ELF二进制的开头部分是一个魔数,0x7f后面跟字符串"ELF"。如果魔数能对的上,`exec`就认为这个二进制是正确的。
|
||||||
|
|
||||||
|
`exec`使用`proc_pagetable`分配了一个没有映射的新页表,然后用`uvmalloc`来为每个ELF段分配内存,并用`loadseg`把每个ELF段载入内存。`loadseg`使用`walkaddr`来找到将要写入ELF段的物理地址,然后用`readi`来把文件中的内容载入到该地址。
|
||||||
|
|
||||||
|
可以用`objdump -p`来查看程序头的内容。在程序头里`filesz`可能比`memsz`小,这表示它们之间的间隙(gap)应该用0来填充,而不是从文件里读取。
|
||||||
|
|
||||||
|
接下来该分配和初始化用户的栈了。它只为栈分配了一个页。`exec`依次把参数复制到栈顶,然后把到这些参数的指针记录在`ustack`里。在传给`main`函数的`argv`列表里,最末尾放了一个空指针。`ustack`的前三个入口分别是
|
||||||
|
|
||||||
##### sbrk
|
##### sbrk
|
||||||
|
|
||||||
文件位置:kernel/sysproc.c。作用:为进程分配内存。它有一个参数,代表要分配的字节数。它返回的是新分配内存的地址。
|
文件位置:kernel/sysproc.c。作用:为进程分配或回收内存。它有一个参数,代表要分配的字节数。它返回的是新分配内存的地址。
|
||||||
|
|
||||||
|
这个系统调用是通过`growproc`来实现的。`growproc`使用`uvmalloc`来分配内存,如果给的参数是正数。或使用`uvmdealloc`来释放内存,如果给的参数是负数。
|
||||||
|
|
||||||
|
`uvmalloc`首先使用`kalloc`来分配物理内存,然后再用`mappages`把PTE加到用户的页表里。`uvmdealloc`调用`uvmunmap`实现其功能,`uvmunmap`首先用`walk`来找到对应的PTE,然后使用`kfree`来释放相应的物理内存。
|
||||||
|
|
||||||
|
xv6里进程的页表不只是告诉硬件怎么映射到虚拟地址,也是分配给那个进程的物理内存页的唯一记录。这就是为什么`uvmunmap`在释放用户内存的时候需要对用户页表进行检查。
|
||||||
|
|
||||||
##### shell
|
##### shell
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,20 @@ xv6使用内核之后到`PHYSTOP`之间的物理内存进行运行时(run-time)
|
||||||
|
|
||||||
#### 进程地址空间
|
#### 进程地址空间
|
||||||
|
|
||||||
|
当xv6在进程间切换的时候,进程的页表也会跟着切换。进程的用户空间从0到`MAXVA`,共计256G的内存(2<sup>38</sup>)。
|
||||||
|
|
||||||
|
当进程申请更多内存的时候,xv6首先用`kalloc`分配一个物理页。然后把这个物理页的PTE加到进程的页表里。xv6会设置该PTE对应的标志位(W,X,R,U,V)。
|
||||||
|
|
||||||
|
我们可以看到页表有如下好处:1,不同的页表把用户空间映射到不同的物理内存上,这样每个进程都有各自的用户空间。2,从进程的角度看虚拟地址是连续的,但实际上它所对应的虚拟地址却不必是连续的。3,内核把trampoline代码映射到地址空间的顶部,这样单一的物理内存就可以出现在所有的地址空间了。
|
||||||
|
|
||||||
|
栈是一个单独的页,它的内容来自于`exec`。在栈的最顶端,是命令行参数,和它们的指针数组。在这些参数的下面,是`main`的入口。
|
||||||
|
|
||||||
|
在栈的下面有一个保护页,它被设置为无效的,这样栈溢出的时候就会产生一个page-fault的异常。而真实世界的操作系统则可能会在栈溢出的时候给它分配更多的内存。
|
||||||
|
|
||||||
#### sbrk
|
#### sbrk
|
||||||
|
|
||||||
#### exec
|
已放在第一章。
|
||||||
|
|
||||||
|
#### exec
|
||||||
|
|
||||||
|
已放在第一章。
|
|
@ -0,0 +1,23 @@
|
||||||
|
```
|
||||||
|
add-apt-repository [options] <repository> # 安装或删除一条仓库信息(repository info)
|
||||||
|
# 仓库信息可能在/etc/apt/sources.list里,或在/etc/apt/sources.list.d的某个文件里
|
||||||
|
# 这条命令只是一个python脚本
|
||||||
|
|
||||||
|
# <repository>有三种形式
|
||||||
|
# 1. 可以直接添加到sources.list里的一行。在这种形式下,<repository>是直接添加到/etc/apt/sources.list里的。
|
||||||
|
# 2. ppa:<user>/<ppa-name>。在这种形式下,将会在/tec/apt/sources.list.d里新建个文件来保存扩展后的完整信息。
|
||||||
|
# 3. distribution component。在这种形式下,给定的distribution component将会对所有的源都使能。
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 选项
|
||||||
|
|
||||||
|
```
|
||||||
|
-h, --help
|
||||||
|
-m, --massive-debug
|
||||||
|
-r, --remove
|
||||||
|
-y, --yes
|
||||||
|
-u, --update
|
||||||
|
-k, --keyserver
|
||||||
|
-s, --enable-source
|
||||||
|
```
|
||||||
|
|
Loading…
Reference in New Issue