提交 936c22ec 编写于 作者: Y Yifan Wu

Upload ch3.1.

上级 362d3295
......@@ -2,5 +2,118 @@
=====================================
在本章的引言中我们提到每个应用都需要按照它的编号被分别加载到内存中不同的位置。本节我们就来介绍它是如何实现的。
更具体来说,
与第二章相同,所有应用的 ELF 都经过 strip 丢掉所有 ELF header 和符号变为二进制镜像文件,随后以同样的格式通过
``link_user.S`` 在编译的时候直接链接到内核的数据段中。不同的是,我们对相关模块进行了调整:在第二章中
应用的加载和进度控制都交给 ``batch`` 子模块,而在第三章中我们将应用的加载这部分功能分离出来在 ``loader``
子模块中实现,应用的执行和切换则交给 ``task`` 子模块。
应用的加载方式也和上一章不同。上一章的时候所有应用都被加载到一个固定的物理地址,也是因为这个原因,内存中同时
最多只能驻留一个应用,当它运行完毕或者出错退出的时候由 ``batch`` 子模块加载一个新的应用来替换掉它。本章中,
所有的应用在内核初始化的时候就一并被加载到内存中。为了避免覆盖,它们自然需要被加载到不同的物理地址。这是通过
调用 ``loader`` 子模块的 ``load_apps`` 函数实现的:
.. code-block:: rust
:linenos:
// os/src/loader.rs
pub fn load_apps() {
extern "C" { fn _num_app(); }
let num_app_ptr = _num_app as usize as *const usize;
let num_app = get_num_app();
let app_start = unsafe {
core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1)
};
// clear i-cache first
unsafe { llvm_asm!("fence.i" :::: "volatile"); }
// load apps
for i in 0..num_app {
let base_i = get_base_i(i);
// clear region
(base_i..base_i + APP_SIZE_LIMIT).for_each(|addr| unsafe {
(addr as *mut u8).write_volatile(0)
});
// load app from data section to memory
let src = unsafe {
core::slice::from_raw_parts(
app_start[i] as *const u8,
app_start[i + 1] - app_start[i]
)
};
let dst = unsafe {
core::slice::from_raw_parts_mut(base_i as *mut u8, src.len())
};
dst.copy_from_slice(src);
}
}
可以看出,第 :math:`i` 个应用被加载到以物理地址 ``base_i`` 开头的一段物理内存上,而 ``base_i`` 的
计算方式如下:
.. code-block:: rust
:linenos:
// os/src/loader.rs
fn get_base_i(app_id: usize) -> usize {
APP_BASE_ADDRESS + app_id * APP_SIZE_LIMIT
}
我们可以在 ``config`` 子模块中找到这两个常数。从这一章开始, ``config`` 子模块用来存放内核中所有的常数。看到
``APP_BASE_ADDRESS`` 被设置为 ``0x80100000`` ,而 ``APP_SIZE_LIMIT`` 和上一章一样被设置为
``0x20000`` ,也就是每个应用二进制镜像的大小限制。因此,应用的内存布局就很明朗了——就是从
``APP_BASE_ADDRESS`` 开始依次为每个应用预留一段空间。
注意,我们需要调整每个应用被构建时候使用的链接脚本 ``linker.ld`` 中的起始地址 ``BASE_ADDRESS`` 为它实际
会被内核加载并运行的地址。也就是要做到:应用知道自己会被加载到某个地址运行,而内核也确实能做到将它加载到那个
地址。这算是应用和内核在某种意义上达成的一种协议。之所以要有这么苛刻的条件,是因为应用和内核的能力都很弱,泛用性很低。
事实上,目前我们的应用是绝对位置而并不是位置无关的,内核也没有提供相应的重定位机制。
.. note::
可以在 `这里 <https://nju-projectn.github.io/ics-pa-gitbook/ics2020/4.2.html>`_ 找到更多有关
位置无关和重定位的说明。
由于每个应用被加载到的位置都不同,也就导致它们 ``linker.ld`` 中的 ``BASE_ADDRESS`` 都是不同的。实际上,
我们写了一个脚本 ``build.py`` 而不是直接 ``cargo build`` 构建应用:
.. code-block:: python
:linenos:
# user/build.py
import os
base_address = 0x80100000
step = 0x20000
linker = 'src/linker.ld'
app_id = 0
apps = os.listdir('src/bin')
apps.sort()
for app in apps:
app = app[:app.find('.')]
lines = []
lines_before = []
with open(linker, 'r') as f:
for line in f.readlines():
lines_before.append(line)
line = line.replace(hex(base_address), hex(base_address+step*app_id))
lines.append(line)
with open(linker, 'w+') as f:
f.writelines(lines)
os.system('cargo build --bin %s --release' % app)
print('[build.py] application %s start with address %s' %(app, hex(base_address+step*app_id)))
with open(linker, 'w+') as f:
f.writelines(lines_before)
app_id = app_id + 1
它的思路很简单,在遍历 ``app`` 的大循环里面只做了这样几件事情:
- 第 16~22 行,找到 ``src/linker.ld`` 中的 ``BASE_ADDRESS = 0x80100000;`` 这一行,并将后面的地址
替换为和当前应用对应的一个地址;
- 第 23 行,使用 ``cargo build`` 构建当前的应用,注意我们可以使用 ``--bin`` 参数来只构建某一个应用;
- 第 25~26 行,将 ``src/linker.ld`` 还原。
这样,我们就说明了多个应用是如何被构建和加载的。
第三章:多道程序与分时多任务
第三章:多道程序与分时多任务系统
==============================================
.. toctree::
......@@ -20,6 +20,13 @@
内存的不同区域中。由于目前我们只有一个 CPU,则同一时间最多只有一个应用在执行,剩下的应用则处于就绪状态,需要内核将 CPU 分配给它们才能
开始执行。因此,我们能够看到多个应用在一个 CPU 上交替执行的现象。
.. note::
读者也许会有疑问:由于只有一个 CPU,即使这样做,同一时间最多还是只能运行一个应用,还浪费了更多的内存来把所有
的应用都加载进来。那么这样做有什么意义呢?
读者可以带着这个问题继续看下去。后面我们会介绍这样做到底能够解决什么问题。
.. _term-multiprogramming:
.. _term-time-sharing-multitasking:
......
......@@ -123,7 +123,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="../quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -123,7 +123,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="../quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -123,7 +123,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="../quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -136,7 +136,7 @@ commentsRunWhenDOMLoaded(addUtterances);
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -136,7 +136,7 @@ commentsRunWhenDOMLoaded(addUtterances);
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -137,7 +137,7 @@ commentsRunWhenDOMLoaded(addUtterances);
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -136,7 +136,7 @@ commentsRunWhenDOMLoaded(addUtterances);
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -133,7 +133,7 @@ commentsRunWhenDOMLoaded(addUtterances);
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -134,7 +134,7 @@ commentsRunWhenDOMLoaded(addUtterances);
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -131,7 +131,7 @@ commentsRunWhenDOMLoaded(addUtterances);
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -131,7 +131,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l2"><a class="reference internal" href="4trap-handling.html">处理 Trap</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -135,7 +135,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l2"><a class="reference internal" href="4trap-handling.html">处理 Trap</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -133,7 +133,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l2"><a class="reference internal" href="4trap-handling.html">处理 Trap</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -72,7 +72,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<link rel="index" title="索引" href="../genindex.html" />
<link rel="search" title="搜索" href="../search.html" />
<link rel="next" title="第三章:多道程序与分时多任务" href="../chapter3/index.html" />
<link rel="next" title="第三章:多道程序与分时多任务系统" href="../chapter3/index.html" />
<link rel="prev" title="实现批处理系统" href="3batch-system.html" />
</head>
......@@ -136,7 +136,7 @@ commentsRunWhenDOMLoaded(addUtterances);
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......@@ -894,7 +894,7 @@ S 特权级,而它希望能够切换到 U 特权级。在 RISC-V 架构中,
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
<a href="../chapter3/index.html" class="btn btn-neutral float-right" title="第三章:多道程序与分时多任务" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right"></span></a>
<a href="../chapter3/index.html" class="btn btn-neutral float-right" title="第三章:多道程序与分时多任务系统" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right"></span></a>
<a href="3batch-system.html" class="btn btn-neutral float-left" title="实现批处理系统" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left"></span> Previous</a>
......
......@@ -129,7 +129,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l2"><a class="reference internal" href="4trap-handling.html">处理 Trap</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
此差异已折叠。
......@@ -123,7 +123,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="../quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="index.html">第三章:多道程序与分时多任务</a><ul class="current">
<li class="toctree-l1 current"><a class="reference internal" href="index.html">第三章:多道程序与分时多任务系统</a><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="1multi-loader.html">多任务加载器</a></li>
<li class="toctree-l2 current"><a class="current reference internal" href="#">任务切换</a></li>
<li class="toctree-l2"><a class="reference internal" href="3multiprogramming.html">多道程序与协作式调度</a></li>
......@@ -196,7 +196,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li><a href="../index.html" class="icon icon-home"></a> &raquo;</li>
<li><a href="index.html">第三章:多道程序与分时多任务</a> &raquo;</li>
<li><a href="index.html">第三章:多道程序与分时多任务系统</a> &raquo;</li>
<li>任务切换</li>
......
......@@ -123,7 +123,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="../quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="index.html">第三章:多道程序与分时多任务</a><ul class="current">
<li class="toctree-l1 current"><a class="reference internal" href="index.html">第三章:多道程序与分时多任务系统</a><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="1multi-loader.html">多任务加载器</a></li>
<li class="toctree-l2"><a class="reference internal" href="2task-switching.html">任务切换</a></li>
<li class="toctree-l2 current"><a class="current reference internal" href="#">多道程序与协作式调度</a></li>
......@@ -196,7 +196,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li><a href="../index.html" class="icon icon-home"></a> &raquo;</li>
<li><a href="index.html">第三章:多道程序与分时多任务</a> &raquo;</li>
<li><a href="index.html">第三章:多道程序与分时多任务系统</a> &raquo;</li>
<li>多道程序与协作式调度</li>
......
......@@ -123,7 +123,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="../quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="index.html">第三章:多道程序与分时多任务</a><ul class="current">
<li class="toctree-l1 current"><a class="reference internal" href="index.html">第三章:多道程序与分时多任务系统</a><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="1multi-loader.html">多任务加载器</a></li>
<li class="toctree-l2"><a class="reference internal" href="2task-switching.html">任务切换</a></li>
<li class="toctree-l2"><a class="reference internal" href="3multiprogramming.html">多道程序与协作式调度</a></li>
......@@ -196,7 +196,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li><a href="../index.html" class="icon icon-home"></a> &raquo;</li>
<li><a href="index.html">第三章:多道程序与分时多任务</a> &raquo;</li>
<li><a href="index.html">第三章:多道程序与分时多任务系统</a> &raquo;</li>
<li>分时多任务系统与抢占式调度</li>
......
......@@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>第三章:多道程序与分时多任务 &mdash; rCore-Tutorial-Book-v3 0.1 文档</title>
<title>第三章:多道程序与分时多任务系统 &mdash; rCore-Tutorial-Book-v3 0.1 文档</title>
......@@ -123,7 +123,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="../quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">第三章:多道程序与分时多任务</a><ul>
<li class="toctree-l1 current"><a class="current reference internal" href="#">第三章:多道程序与分时多任务系统</a><ul>
<li class="toctree-l2"><a class="reference internal" href="1multi-loader.html">多任务加载器</a></li>
<li class="toctree-l2"><a class="reference internal" href="2task-switching.html">任务切换</a></li>
<li class="toctree-l2"><a class="reference internal" href="3multiprogramming.html">多道程序与协作式调度</a></li>
......@@ -196,7 +196,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li><a href="../index.html" class="icon icon-home"></a> &raquo;</li>
<li>第三章:多道程序与分时多任务</li>
<li>第三章:多道程序与分时多任务系统</li>
<li class="wy-breadcrumbs-aside">
......@@ -216,7 +216,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<div itemprop="articleBody">
<div class="section" id="id1">
<h1>第三章:多道程序与分时多任务<a class="headerlink" href="#id1" title="永久链接至标题"></a></h1>
<h1>第三章:多道程序与分时多任务系统<a class="headerlink" href="#id1" title="永久链接至标题"></a></h1>
<div class="toctree-wrapper compound">
</div>
<p>上一章,我们实现了一个简单的批处理系统。首先,它能够自动按照顺序加载并运行序列中的每一个应用,当一个应用运行结束之后无需操作员的手动替换;
......@@ -227,6 +227,12 @@ commentsRunWhenDOMLoaded(addUtterances);
相同的一块内存区域。而本章所介绍的多道程序和分时多任务系统则是在内存中同一时间可以驻留多个应用。所有的应用都是在系统启动的时候分别加载到
内存的不同区域中。由于目前我们只有一个 CPU,则同一时间最多只有一个应用在执行,剩下的应用则处于就绪状态,需要内核将 CPU 分配给它们才能
开始执行。因此,我们能够看到多个应用在一个 CPU 上交替执行的现象。</p>
<div class="admonition note">
<p class="admonition-title">注解</p>
<p>读者也许会有疑问:由于只有一个 CPU,即使这样做,同一时间最多还是只能运行一个应用,还浪费了更多的内存来把所有
的应用都加载进来。那么这样做有什么意义呢?</p>
<p>读者可以带着这个问题继续看下去。后面我们会介绍这样做到底能够解决什么问题。</p>
</div>
<p id="term-time-sharing-multitasking"><span id="term-multiprogramming"></span><strong>多道程序</strong> (Multiprogramming) 和 <strong>分时多任务系统</strong> (Time-Sharing Multitasking) 对于应用的要求是不同的,因此我们分别为它们
编写了不同的应用,代码也被放在两个不同的分支上。对于它们更加深入的讲解请参考本章正文,我们在引言中仅给出运行代码的方法。</p>
<p>获取多道程序的代码:</p>
......
......@@ -123,7 +123,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="../quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">第四章:内存隔离安全性</a><ul class="simple">
</ul>
</li>
......
......@@ -123,7 +123,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="../quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">第五章:进程及重要系统调用</a><ul class="simple">
</ul>
......
......@@ -123,7 +123,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="../quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">第六章:文件描述符与进程间通信</a><ul class="simple">
......
......@@ -123,7 +123,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="../quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -123,7 +123,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="../quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -122,7 +122,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -121,7 +121,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -122,7 +122,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
无法预览此类型文件
......@@ -130,7 +130,7 @@ commentsRunWhenDOMLoaded(addUtterances);
</li>
<li class="toctree-l1"><a class="reference internal" href="chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -123,7 +123,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -123,7 +123,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
此差异已折叠。
......@@ -123,7 +123,7 @@ commentsRunWhenDOMLoaded(addUtterances);
<li class="toctree-l1"><a class="reference internal" href="quickstart.html">环境配置</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter1/index.html">第一章:RV64 裸机应用</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter2/index.html">第二章:批处理系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter3/index.html">第三章:多道程序与分时多任务</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter3/index.html">第三章:多道程序与分时多任务系统</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter4/index.html">第四章:内存隔离安全性</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter5/index.html">第五章:进程及重要系统调用</a></li>
<li class="toctree-l1"><a class="reference internal" href="chapter6/index.html">第六章:文件描述符与进程间通信</a></li>
......
......@@ -2,5 +2,118 @@
=====================================
在本章的引言中我们提到每个应用都需要按照它的编号被分别加载到内存中不同的位置。本节我们就来介绍它是如何实现的。
更具体来说,
与第二章相同,所有应用的 ELF 都经过 strip 丢掉所有 ELF header 和符号变为二进制镜像文件,随后以同样的格式通过
``link_user.S`` 在编译的时候直接链接到内核的数据段中。不同的是,我们对相关模块进行了调整:在第二章中
应用的加载和进度控制都交给 ``batch`` 子模块,而在第三章中我们将应用的加载这部分功能分离出来在 ``loader``
子模块中实现,应用的执行和切换则交给 ``task`` 子模块。
应用的加载方式也和上一章不同。上一章的时候所有应用都被加载到一个固定的物理地址,也是因为这个原因,内存中同时
最多只能驻留一个应用,当它运行完毕或者出错退出的时候由 ``batch`` 子模块加载一个新的应用来替换掉它。本章中,
所有的应用在内核初始化的时候就一并被加载到内存中。为了避免覆盖,它们自然需要被加载到不同的物理地址。这是通过
调用 ``loader`` 子模块的 ``load_apps`` 函数实现的:
.. code-block:: rust
:linenos:
// os/src/loader.rs
pub fn load_apps() {
extern "C" { fn _num_app(); }
let num_app_ptr = _num_app as usize as *const usize;
let num_app = get_num_app();
let app_start = unsafe {
core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1)
};
// clear i-cache first
unsafe { llvm_asm!("fence.i" :::: "volatile"); }
// load apps
for i in 0..num_app {
let base_i = get_base_i(i);
// clear region
(base_i..base_i + APP_SIZE_LIMIT).for_each(|addr| unsafe {
(addr as *mut u8).write_volatile(0)
});
// load app from data section to memory
let src = unsafe {
core::slice::from_raw_parts(
app_start[i] as *const u8,
app_start[i + 1] - app_start[i]
)
};
let dst = unsafe {
core::slice::from_raw_parts_mut(base_i as *mut u8, src.len())
};
dst.copy_from_slice(src);
}
}
可以看出,第 :math:`i` 个应用被加载到以物理地址 ``base_i`` 开头的一段物理内存上,而 ``base_i`` 的
计算方式如下:
.. code-block:: rust
:linenos:
// os/src/loader.rs
fn get_base_i(app_id: usize) -> usize {
APP_BASE_ADDRESS + app_id * APP_SIZE_LIMIT
}
我们可以在 ``config`` 子模块中找到这两个常数。从这一章开始, ``config`` 子模块用来存放内核中所有的常数。看到
``APP_BASE_ADDRESS`` 被设置为 ``0x80100000`` ,而 ``APP_SIZE_LIMIT`` 和上一章一样被设置为
``0x20000`` ,也就是每个应用二进制镜像的大小限制。因此,应用的内存布局就很明朗了——就是从
``APP_BASE_ADDRESS`` 开始依次为每个应用预留一段空间。
注意,我们需要调整每个应用被构建时候使用的链接脚本 ``linker.ld`` 中的起始地址 ``BASE_ADDRESS`` 为它实际
会被内核加载并运行的地址。也就是要做到:应用知道自己会被加载到某个地址运行,而内核也确实能做到将它加载到那个
地址。这算是应用和内核在某种意义上达成的一种协议。之所以要有这么苛刻的条件,是因为应用和内核的能力都很弱,泛用性很低。
事实上,目前我们的应用是绝对位置而并不是位置无关的,内核也没有提供相应的重定位机制。
.. note::
可以在 `这里 <https://nju-projectn.github.io/ics-pa-gitbook/ics2020/4.2.html>`_ 找到更多有关
位置无关和重定位的说明。
由于每个应用被加载到的位置都不同,也就导致它们 ``linker.ld`` 中的 ``BASE_ADDRESS`` 都是不同的。实际上,
我们写了一个脚本 ``build.py`` 而不是直接 ``cargo build`` 构建应用:
.. code-block:: python
:linenos:
# user/build.py
import os
base_address = 0x80100000
step = 0x20000
linker = 'src/linker.ld'
app_id = 0
apps = os.listdir('src/bin')
apps.sort()
for app in apps:
app = app[:app.find('.')]
lines = []
lines_before = []
with open(linker, 'r') as f:
for line in f.readlines():
lines_before.append(line)
line = line.replace(hex(base_address), hex(base_address+step*app_id))
lines.append(line)
with open(linker, 'w+') as f:
f.writelines(lines)
os.system('cargo build --bin %s --release' % app)
print('[build.py] application %s start with address %s' %(app, hex(base_address+step*app_id)))
with open(linker, 'w+') as f:
f.writelines(lines_before)
app_id = app_id + 1
它的思路很简单,在遍历 ``app`` 的大循环里面只做了这样几件事情:
- 第 16~22 行,找到 ``src/linker.ld`` 中的 ``BASE_ADDRESS = 0x80100000;`` 这一行,并将后面的地址
替换为和当前应用对应的一个地址;
- 第 23 行,使用 ``cargo build`` 构建当前的应用,注意我们可以使用 ``--bin`` 参数来只构建某一个应用;
- 第 25~26 行,将 ``src/linker.ld`` 还原。
这样,我们就说明了多个应用是如何被构建和加载的。
第三章:多道程序与分时多任务
第三章:多道程序与分时多任务系统
==============================================
.. toctree::
......@@ -20,6 +20,13 @@
内存的不同区域中。由于目前我们只有一个 CPU,则同一时间最多只有一个应用在执行,剩下的应用则处于就绪状态,需要内核将 CPU 分配给它们才能
开始执行。因此,我们能够看到多个应用在一个 CPU 上交替执行的现象。
.. note::
读者也许会有疑问:由于只有一个 CPU,即使这样做,同一时间最多还是只能运行一个应用,还浪费了更多的内存来把所有
的应用都加载进来。那么这样做有什么意义呢?
读者可以带着这个问题继续看下去。后面我们会介绍这样做到底能够解决什么问题。
.. _term-multiprogramming:
.. _term-time-sharing-multitasking:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册