Skip to content

sys_exec docs #70

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,8 @@
- [fork 实现思路](chapter13/part2.md)
- [复制线程上下文](chapter13/part3.md)
- [复制页表](chapter13/part4.md)
- [exec 介绍](chapter13/par5.md)
- [exec 实现思路](chapter13/part6.md)
- [跳转到指定用户太环境](chapter13/part7.md)
- [附录]
- [内链汇编](appendix/inline-asm.md)
3 changes: 2 additions & 1 deletion chapter13/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@
- fork 的功能
- 如何描述一个正在运行的线程
- 如何完全复制一个正在运行的线程
- TODO:写 execute
- exec 的功能
- 如何在内核态返回时返回到指定的运行环境
46 changes: 46 additions & 0 deletions chapter13/part5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
## exec 介绍

sys_exec 会中止当前进程并跳转到开始执行另一个制定的程序。

我们先来看看 sys_exec 的接口, 在 linux C 中最主要的接口是

```c
int execve (const char* path,char* const argv[], char* const envp[]);
```

其中 `path` 表示启动程序所在的路径名,`argv` 表示启动程序所带的参数, `envp` 表示启动程序所需要的环境变量参数。成功时返回0,失败时返回非零值。这里我们先实现简化的版本:

```c
fn sys_exec(path: *const u8)
```

也就是仅仅考虑执行路径,同时简化了失败时的返回值,失败一律返回-1。

来看一个简单的例子:

```rust
// rust/exec.rs
pub fn main() -> usize {
println!("this is exec_test ^o^");
sys_exec("/rust/hello_world\0".as_ptr() as *const u8);
println!("should not arrive here. exec error.");
0
}
```

输出应该是这个样子,一旦执行sys_exec,原来程序的一切都被抛弃了。

```bash
this is exec_test ^o^
Hello world! from user mode program!
Hello world! from user mode program!
Hello world! from user mode program!
Hello world! from user mode program!
Hello world! from user mode program!
Hello world! from user mode program!
Hello world! from user mode program!
Hello world! from user mode program!
Hello world! from user mode program!
Hello world! from user mode program!
thread 1 exited, exit code = 0
```
98 changes: 98 additions & 0 deletions chapter13/part6.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
## exec 的实现

在 `sys_exec` 的语义中,我们需要完成的过程包括:
* 1.回收当前进程(Thread)的所有资源
* 2.为新进程申请足够的资源、读取解析镜像
* 3.跳转到新进程开始执行

原进程的资源在进程控制块中:

```rust
pub struct Thread {
pub context: Context,
pub kstack: KernelStack,
pub wait: Option<Tid>,
pub vm: Option<Arc<Mutex<MemorySet>>>,
}
```

我们不析构这一结构体,而是替换其中内容。其中 `context` 用来是的其他进程跳转到该进程,新进程会在被替换出去的时候设置,我们不需要改变(留好位置就行),在我们的实现中 `wait` 的含义是结束后需要唤醒的进程,我们可以直接继承(或者说为了简便实现,我们没有提供改变的接口),`kstack` 仅仅在执行内核代码时使用,进入用户态后一定是空的,仅仅起提供空间的作用,可以直接继承。所以我们只需要改变 `vm`。

因此干如下几件事情:
* 1.为新进程申请足够的资源、读取解析镜像,构造新 `vm`
* 2.替换 `vm`,并激活新页表供用户态使用
* 3.跳转到新进程开始执行

来看代码实现:

```rust
// 输入参数包含了执行程序的位置以及中断帧,其中中断帧用来改变syscall返回时返回的地址
fn sys_exec(path: *const u8, tf: &mut TrapFrame) -> isize {
let exec_path = unsafe { from_cstr(path) };
let find_result = ROOT_INODE.lookup(exec_path);
match find_result {
Ok(inode) => {
let data = inode.read_as_vec().unwrap();
// 该函数完成elf的解析和vm的构造(仅仅重新封装了 Thread::new_user 的部分实现), entry_addr 是新程序的入口地址,ustack_top是用户栈栈顶
let (mut vm, entry_addr, ustack_top) = unsafe { Thread::new_user_vm(data.as_slice()) };
// 读取当前进程的进程控制块
let proc = process::current_thread();
// 设置新vm
core::mem::swap(&mut *proc.vm.as_ref().unwrap().lock(), &mut vm);
// 切换satp(页表)
unsafe {
proc.vm.as_ref().unwrap().lock().activate();
}
// 仅仅是为了尽早释放锁
drop(proc);
// 构造新的tf来改变syscall返回后返回的程序
*tf = TrapFrame::new_user_thread(entry_addr, ustack_top);
0
}
Err(_) => {
println!("exec error! cannot find the program {}", exec_path);
-1
}
}
}
```

结合一些接口上的简单修改(`syscall`->`sys_exit`的内容,不赘述),我们就完成了sys_exec的实现,是不是特别简单呢?我们还没有解决的问题是如何使得 `syscall` 返回的时候返回到新的进程开始执行(`TrapFrame::new_user_thread`)。这将在下一部分细说。

我们替换了原本的sys_exec(实际是一个spawn),是的它不再可被用户太访问了,除非提供一个新的系统调用。

完成了 sys_fork 和 sys_exec 我们可以对应改写 user_shell 的内容:

```rust
#[no_mangle]
pub fn main() {
println!("Rust user shell");
let mut line: String = String::new();
print!(">> ");
loop {
let c = getc();
match c {
LF | CR => {
println!("");
if !line.is_empty() {
println!("searching for program {}", line);
// 使用fork和exec完成原本的spawn的功能
if sys_fork() == 0 {
line.push('\0');
sys_exec(line.as_ptr());
sys_exit(0);
}
line.clear();
}
print!(">> ");
}
_ => {
print!("{}", c as char);
line.push(c as char);
}
}
}
}
```

user_shell同时也完成了exec的简单测试。
33 changes: 33 additions & 0 deletions chapter13/part7.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## 如何从内核态定向返回

想想在课堂上学到的内容,如果在用户态度我们想要改变返回地址,我们可以修改 `x1(ra)` 寄存器,从内核态返回用户态是一个十分类似的过程,只不过用来描述返回目的地的内容变成了中断帧(`trapframe`)。

```rust
pub struct TrapFrame {
pub x: [usize; 32], // General registers
pub sstatus: Sstatus, // Supervisor Status Register
pub sepc: usize, // Supervisor exception program counter
pub stval: usize, // Supervisor trap value
pub scause: Scause, // Scause register: record the cause of exception/interrupt/trap
}
```

只需要通过修改中断帧我们就可以完全控制从内核态返回后的执行环境。想想新的中断帧应该如何构造呢?新进程没有通用寄存器的信息,我们可以直接初始化为0, `stval`、`scause` 寄存器同理。特殊的通用寄存器 `x2(sp)` 需要我们特殊设置(程序初始化的必要条件,其他的程序会自己搞定),`sstatus`寄存器对程序状态的控制很重要,需要小心设置。

- `context.rs`

```rust
impl TrapFrame {
pub fn new_user_thread(entry_addr: usize, sp: usize) -> Self {
use core::mem::zeroed;
let mut tf: Self = unsafe { zeroed() };
tf.x[2] = sp;
tf.sepc = entry_addr;
tf.sstatus = sstatus::read();
tf.sstatus.set_spie(true); // 使得进入用户态后开启中断
tf.sstatus.set_sie(false);
tf.sstatus.set_spp(sstatus::SPP::User); // 令sret返回U态
tf
}
}
```
41 changes: 40 additions & 1 deletion docs/chapter0/introduction.html
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,45 @@



</li>

<li class="chapter " data-level="1.13.5" data-path="../chapter13/par5.md">

<span>


exec 介绍

</a>



</li>

<li class="chapter " data-level="1.13.6" data-path="../chapter13/part6.html">

<a href="../chapter13/part6.html">


exec 实现思路

</a>



</li>

<li class="chapter " data-level="1.13.7" data-path="../chapter13/part7.html">

<a href="../chapter13/part7.html">


跳转到指定用户太环境

</a>



</li>


Expand Down Expand Up @@ -1253,7 +1292,7 @@ <h1 class="search-results-title">No results matching "<span class='search-query'
<script>
var gitbook = gitbook || [];
gitbook.push(function() {
gitbook.page.hasChanged({"page":{"title":"第零章:实验环境说明","level":"1.2","depth":1,"next":{"title":"第一章:独立式可执行程序","level":"1.3","depth":1,"path":"chapter1/introduction.md","ref":"chapter1/introduction.md","articles":[{"title":"安装 nightly rust","level":"1.3.1","depth":2,"path":"chapter1/part1.md","ref":"chapter1/part1.md","articles":[]},{"title":"使用包管理器 cargo 创建 rust binary 项目","level":"1.3.2","depth":2,"path":"chapter1/part2.md","ref":"chapter1/part2.md","articles":[]},{"title":"移除标准库依赖","level":"1.3.3","depth":2,"path":"chapter1/part3.md","ref":"chapter1/part3.md","articles":[]},{"title":"移除 runtime 依赖","level":"1.3.4","depth":2,"path":"chapter1/part4.md","ref":"chapter1/part4.md","articles":[]},{"title":"总结与展望","level":"1.3.5","depth":2,"path":"chapter1/part5.md","ref":"chapter1/part5.md","articles":[]}]},"previous":{"title":"Introduction","level":"1.1","depth":1,"path":"README.md","ref":"README.md","articles":[]},"dir":"ltr"},"config":{"gitbook":"*","theme":"default","variables":{},"plugins":["hide-element","chapter-fold","katex","alerts","emphasize","-highlight","prism","localized-footer","mermaid-gb3"],"pluginsConfig":{"chapter-fold":{},"prism":{"css":["prismjs/themes/prism-tomorrow.css"]},"emphasize":{},"search":{},"localized-footer":{"filename":"extensions/comment/gitalk.html","hline":"true"},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"hide-element":{"elements":[".gitbook-link"]},"katex":{},"fontsettings":{"theme":"white","family":"sans","size":2},"mermaid-gb3":{},"alerts":{},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"}},"file":{"path":"chapter0/introduction.md","mtime":"2020-02-13T08:47:45.384Z","type":"markdown"},"gitbook":{"version":"3.2.3","time":"2020-02-14T13:23:24.037Z"},"basePath":"..","book":{"language":""}});
gitbook.page.hasChanged({"page":{"title":"第零章:实验环境说明","level":"1.2","depth":1,"next":{"title":"第一章:独立式可执行程序","level":"1.3","depth":1,"path":"chapter1/introduction.md","ref":"chapter1/introduction.md","articles":[{"title":"安装 nightly rust","level":"1.3.1","depth":2,"path":"chapter1/part1.md","ref":"chapter1/part1.md","articles":[]},{"title":"使用包管理器 cargo 创建 rust binary 项目","level":"1.3.2","depth":2,"path":"chapter1/part2.md","ref":"chapter1/part2.md","articles":[]},{"title":"移除标准库依赖","level":"1.3.3","depth":2,"path":"chapter1/part3.md","ref":"chapter1/part3.md","articles":[]},{"title":"移除 runtime 依赖","level":"1.3.4","depth":2,"path":"chapter1/part4.md","ref":"chapter1/part4.md","articles":[]},{"title":"总结与展望","level":"1.3.5","depth":2,"path":"chapter1/part5.md","ref":"chapter1/part5.md","articles":[]}]},"previous":{"title":"Introduction","level":"1.1","depth":1,"path":"README.md","ref":"README.md","articles":[]},"dir":"ltr"},"config":{"gitbook":"*","theme":"default","variables":{},"plugins":["hide-element","chapter-fold","katex","alerts","emphasize","-highlight","prism","localized-footer","mermaid-gb3"],"pluginsConfig":{"chapter-fold":{},"prism":{"css":["prismjs/themes/prism-tomorrow.css"]},"emphasize":{},"search":{},"localized-footer":{"filename":"extensions/comment/gitalk.html","hline":"true"},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"hide-element":{"elements":[".gitbook-link"]},"katex":{},"fontsettings":{"theme":"white","family":"sans","size":2},"mermaid-gb3":{},"alerts":{},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"}},"file":{"path":"chapter0/introduction.md","mtime":"2020-02-14T14:18:28.499Z","type":"markdown"},"gitbook":{"version":"3.2.3","time":"2020-02-14T17:06:46.480Z"},"basePath":"..","book":{"language":""}});
});
</script>
</div>
Expand Down
41 changes: 40 additions & 1 deletion docs/chapter1/introduction.html
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,45 @@



</li>

<li class="chapter " data-level="1.13.5" data-path="../chapter13/par5.md">

<span>


exec 介绍

</a>



</li>

<li class="chapter " data-level="1.13.6" data-path="../chapter13/part6.html">

<a href="../chapter13/part6.html">


exec 实现思路

</a>



</li>

<li class="chapter " data-level="1.13.7" data-path="../chapter13/part7.html">

<a href="../chapter13/part7.html">


跳转到指定用户太环境

</a>



</li>


Expand Down Expand Up @@ -1183,7 +1222,7 @@ <h1 class="search-results-title">No results matching "<span class='search-query'
<script>
var gitbook = gitbook || [];
gitbook.push(function() {
gitbook.page.hasChanged({"page":{"title":"第一章:独立式可执行程序","level":"1.3","depth":1,"next":{"title":"安装 nightly rust","level":"1.3.1","depth":2,"path":"chapter1/part1.md","ref":"chapter1/part1.md","articles":[]},"previous":{"title":"第零章:实验环境说明","level":"1.2","depth":1,"path":"chapter0/introduction.md","ref":"chapter0/introduction.md","articles":[]},"dir":"ltr"},"config":{"gitbook":"*","theme":"default","variables":{},"plugins":["hide-element","chapter-fold","katex","alerts","emphasize","-highlight","prism","localized-footer","mermaid-gb3"],"pluginsConfig":{"chapter-fold":{},"prism":{"css":["prismjs/themes/prism-tomorrow.css"]},"emphasize":{},"search":{},"localized-footer":{"filename":"extensions/comment/gitalk.html","hline":"true"},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"hide-element":{"elements":[".gitbook-link"]},"katex":{},"fontsettings":{"theme":"white","family":"sans","size":2},"mermaid-gb3":{},"alerts":{},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"}},"file":{"path":"chapter1/introduction.md","mtime":"2020-02-13T08:47:45.384Z","type":"markdown"},"gitbook":{"version":"3.2.3","time":"2020-02-14T13:23:24.037Z"},"basePath":"..","book":{"language":""}});
gitbook.page.hasChanged({"page":{"title":"第一章:独立式可执行程序","level":"1.3","depth":1,"next":{"title":"安装 nightly rust","level":"1.3.1","depth":2,"path":"chapter1/part1.md","ref":"chapter1/part1.md","articles":[]},"previous":{"title":"第零章:实验环境说明","level":"1.2","depth":1,"path":"chapter0/introduction.md","ref":"chapter0/introduction.md","articles":[]},"dir":"ltr"},"config":{"gitbook":"*","theme":"default","variables":{},"plugins":["hide-element","chapter-fold","katex","alerts","emphasize","-highlight","prism","localized-footer","mermaid-gb3"],"pluginsConfig":{"chapter-fold":{},"prism":{"css":["prismjs/themes/prism-tomorrow.css"]},"emphasize":{},"search":{},"localized-footer":{"filename":"extensions/comment/gitalk.html","hline":"true"},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"hide-element":{"elements":[".gitbook-link"]},"katex":{},"fontsettings":{"theme":"white","family":"sans","size":2},"mermaid-gb3":{},"alerts":{},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"}},"file":{"path":"chapter1/introduction.md","mtime":"2020-02-14T14:18:28.499Z","type":"markdown"},"gitbook":{"version":"3.2.3","time":"2020-02-14T17:06:46.480Z"},"basePath":"..","book":{"language":""}});
});
</script>
</div>
Expand Down
Loading