You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
zCore-Tutorial/ch04-03-syscall.html

459 lines
24 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE HTML>
<html lang="cn" class="sidebar-visible no-js light">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>🚧 系统调用 - 简明 zCore 教程</title>
<!-- Custom HTML head -->
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
</head>
<body>
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded affix "><a href="index.html">简明 zCore 教程</a></li><li class="chapter-item expanded affix "><a href="zcore-intro.html">🚧 zCore 整体结构和设计模式</a></li><li class="chapter-item expanded affix "><a href="fuchsia.html">🚧 Fuchsia OS 和 Zircon 微内核</a></li><li class="chapter-item expanded "><a href="ch01-00-object.html"><strong aria-hidden="true">1.</strong> 内核对象</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch01-01-kernel-object.html"><strong aria-hidden="true">1.1.</strong> ✅ 初识内核对象</a></li><li class="chapter-item expanded "><a href="ch01-02-process-object.html"><strong aria-hidden="true">1.2.</strong> 🚧 对象管理器Process 对象</a></li><li class="chapter-item expanded "><a href="ch01-03-channel-object.html"><strong aria-hidden="true">1.3.</strong> 🚧 对象传送器Channel 对象</a></li></ol></li><li class="chapter-item expanded "><a href="ch02-00-task.html"><strong aria-hidden="true">2.</strong> 任务管理</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch02-01-zircon-task.html"><strong aria-hidden="true">2.1.</strong> 🚧 Zircon 任务管理体系</a></li><li class="chapter-item expanded "><a href="ch02-02-process-job-object.html"><strong aria-hidden="true">2.2.</strong> 🚧 进程管理Process 与 Job 对象</a></li><li class="chapter-item expanded "><a href="ch02-03-thread-object.html"><strong aria-hidden="true">2.3.</strong> 🚧 线程管理Thread 对象</a></li></ol></li><li class="chapter-item expanded "><a href="ch03-00-memory.html"><strong aria-hidden="true">3.</strong> 内存管理</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch03-01-zircon-memory.html"><strong aria-hidden="true">3.1.</strong> 🚧 Zircon 内存管理模型</a></li><li class="chapter-item expanded "><a href="ch03-02-vmo.html"><strong aria-hidden="true">3.2.</strong> 🚧 物理内存VMO 对象</a></li><li class="chapter-item expanded "><a href="ch03-03-vmo-paged.html"><strong aria-hidden="true">3.3.</strong> 🚧 物理内存:按页分配的 VMO</a></li><li class="chapter-item expanded "><a href="ch03-04-vmar.html"><strong aria-hidden="true">3.4.</strong> 🚧 虚拟内存VMAR 对象</a></li></ol></li><li class="chapter-item expanded "><a href="ch04-00-userspace.html"><strong aria-hidden="true">4.</strong> 用户程序</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch04-01-user-program.html"><strong aria-hidden="true">4.1.</strong> 🚧 Zircon 用户程序</a></li><li class="chapter-item expanded "><a href="ch04-02-context-switch.html"><strong aria-hidden="true">4.2.</strong> 🚧 上下文切换</a></li><li class="chapter-item expanded "><a href="ch04-03-syscall.html" class="active"><strong aria-hidden="true">4.3.</strong> 🚧 系统调用</a></li></ol></li><li class="chapter-item expanded "><a href="ch05-00-signal-and-waiting.html"><strong aria-hidden="true">5.</strong> 信号和等待</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch05-01-wait-signal.html"><strong aria-hidden="true">5.1.</strong> 🚧 等待内核对象的信号</a></li><li class="chapter-item expanded "><a href="ch05-02-port-object.html"><strong aria-hidden="true">5.2.</strong> 🚧 同时等待多个信号Port 对象</a></li><li class="chapter-item expanded "><a href="ch05-03-more-signal-objects.html"><strong aria-hidden="true">5.3.</strong> 🚧 实现更多EventPair, Timer 对象</a></li><li class="chapter-item expanded "><a href="ch05-04-futex-object.html"><strong aria-hidden="true">5.4.</strong> 🚧 用户态同步互斥Futex 对象</a></li></ol></li><li class="chapter-item expanded "><a href="ch06-00-hal.html"><strong aria-hidden="true">6.</strong> 硬件抽象层</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch06-01-zcore-hal-unix.html"><strong aria-hidden="true">6.1.</strong> ✅ UNIX硬件抽象层</a></li></ol></li></ol> </div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky bordered">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">简明 zCore 教程</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/rcore-os/zCore-Tutorial" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="zircon-系统调用"><a class="header" href="#zircon-系统调用">Zircon 系统调用</a></h1>
<blockquote>
<p>目录位于<code>zCore/zircon-syscall</code></p>
</blockquote>
<p>从userboot运行起来到实现调用syscall的简要函数调用流程如下</p>
<ol>
<li>run_userboot -&gt;</li>
<li>proc.start -&gt;</li>
<li>thread_fn -&gt;</li>
<li>new_thread -&gt; </li>
<li>handle_syscall -&gt; </li>
<li>syscall -&gt;</li>
<li>sys_handle_close() (举例某一具体的syscall运行该syscall可用于实现<code>close a handle</code>的功能)</li>
</ol>
<h2 id="获取系统调用参数"><a class="header" href="#获取系统调用参数">获取系统调用参数</a></h2>
<p>从寄存器中获取参数</p>
<blockquote>
<p>不同的计算机体系结构获得参数的方式不同</p>
<p>以下区分<code>x86_64</code>以及<code>aarch64</code></p>
</blockquote>
<p>调用syscall需要从寄存器收集两种参数<br />
+ <code>num</code> : 系统调用号<br />
+ <code>args</code> : 具体某一系统调用的参数</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>async fn handle_syscall(thread: &amp;CurrentThread, regs: &amp;mut GeneralRegs) {
#[cfg(target_arch = &quot;x86_64&quot;)]
let num = regs.rax as u32;
#[cfg(target_arch = &quot;aarch64&quot;)]
let num = regs.x16 as u32;
// LibOS: Function call ABI
#[cfg(feature = &quot;std&quot;)]
#[cfg(target_arch = &quot;x86_64&quot;)]
let args = unsafe {
let a6 = (regs.rsp as *const usize).read();
let a7 = (regs.rsp as *const usize).add(1).read();
[
regs.rdi, regs.rsi, regs.rdx, regs.rcx, regs.r8, regs.r9, a6, a7,
]
};
// RealOS: Zircon syscall ABI
#[cfg(not(feature = &quot;std&quot;))]
#[cfg(target_arch = &quot;x86_64&quot;)]
let args = [
regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9, regs.r12, regs.r13,
];
// ARM64
#[cfg(target_arch = &quot;aarch64&quot;)]
let args = [
regs.x0, regs.x1, regs.x2, regs.x3, regs.x4, regs.x5, regs.x6, regs.x7,
];
let mut syscall = Syscall {
regs,
thread,
thread_fn,
};
let ret = syscall.syscall(num, args).await as usize;
#[cfg(target_arch = &quot;x86_64&quot;)]
{
syscall.regs.rax = ret;
}
#[cfg(target_arch = &quot;aarch64&quot;)]
{
syscall.regs.x0 = ret;
}
}
<span class="boring">}
</span></code></pre></pre>
<h2 id="系统调用上下文与处理函数"><a class="header" href="#系统调用上下文与处理函数">系统调用上下文与处理函数</a></h2>
<h3 id="定义-syscall-结构体"><a class="header" href="#定义-syscall-结构体">定义 Syscall 结构体</a></h3>
<p>保存上下文信息</p>
<blockquote>
<p>zCore/zircon-syscall/src/lib.rs#L52</p>
</blockquote>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>/// 系统调用的结构(存储关于创建系统调用的信息)
pub struct Syscall&lt;'a&gt; {
/// store the regs statues
pub regs: &amp;'a mut GeneralRegs,
/// the thread making a syscall
pub thread: &amp;'a CurrentThread,
/// new thread function
pub thread_fn: ThreadFn,
}
<span class="boring">}
</span></code></pre></pre>
<h3 id="实现-syscall-函数"><a class="header" href="#实现-syscall-函数">实现 syscall 函数</a></h3>
<blockquote>
<p>zCore/zircon-syscall/src/lib.rs#L59</p>
</blockquote>
<ol>
<li>检查系统调用号<code>sys_type</code>是否合法</li>
<li>获取传递给具体某一系统调用的参数<code>args</code></li>
<li>若syscall函数输入的系统调用号合法则进一步根据系统调用号匹配具体系统调用处理函数</li>
<li>传入对应系统调用所需的参数,并运行之</li>
<li>检查系统调用的返回值<code>ret</code>是否符合预期 </li>
</ol>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span> pub async fn syscall(&amp;mut self, num: u32, args: [usize; 8]) -&gt; isize {
...
// 1. 检查系统调用号`sys_type`是否合法
let sys_type = match Sys::try_from(num) {
Ok(t) =&gt; t,
Err(_) =&gt; {
error!(&quot;invalid syscall number: {}&quot;, num);
return ZxError::INVALID_ARGS as _;
}
};
...
// 2. 获取传递给具体系统调用参数
let [a0, a1, a2, a3, a4, a5, a6, a7] = args;
// 3. 若syscall函数输入的系统调用号合法
// 则进一步根据系统调用号匹配具体系统调用处理函数
let ret = match sys_type {
// 4. 传入对应系统调用所需的参数,并运行之
Sys::HANDLE_CLOSE =&gt; self.sys_handle_close(a0 as _),
Sys::HANDLE_CLOSE_MANY =&gt; self.sys_handle_close_many(a0.into(), a1 as _),
Sys::HANDLE_DUPLICATE =&gt; self.sys_handle_duplicate(a0 as _, a1 as _, a2.into()),
Sys::HANDLE_REPLACE =&gt; self.sys_handle_replace(a0 as _, a1 as _, a2.into()),
...
// 更多系统调用匹配的分支
Sys::CLOCK_GET =&gt; self.sys_clock_get(a0 as _, a1.into()),
Sys::CLOCK_READ =&gt; self.sys_clock_read(a0 as _, a1.into()),
Sys::CLOCK_ADJUST =&gt; self.sys_clock_adjust(a0 as _, a1 as _, a2 as _),
Sys::CLOCK_UPDATE =&gt; self.sys_clock_update(a0 as _, a1 as _, a2.into()),
Sys::TIMER_CREATE =&gt; self.sys_timer_create(a0 as _, a1 as _, a2.into()),
...
};
...
// 5. 检查系统调用的返回值`ret`是否符合预期
match ret {
Ok(_) =&gt; 0,
Err(err) =&gt; err as isize,
}
}
<span class="boring">}
</span></code></pre></pre>
<p>系统调用号匹配信息位于</p>
<blockquote>
<p>zCore/zircon-syscall/src/consts.rs#L8</p>
</blockquote>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>pub enum SyscallType {
BTI_CREATE = 0,
BTI_PIN = 1,
BTI_RELEASE_QUARANTINE = 2,
CHANNEL_CREATE = 3,
CHANNEL_READ = 4,
CHANNEL_READ_ETC = 5,
CHANNEL_WRITE = 6,
CHANNEL_WRITE_ETC = 7,
CHANNEL_CALL_NORETRY = 8,
CHANNEL_CALL_FINISH = 9,
CLOCK_GET = 10,
CLOCK_ADJUST = 11,
CLOCK_GET_MONOTONIC_VIA_KERNEL = 12,
...
VMO_CREATE_CONTIGUOUS = 165,
VMO_CREATE_PHYSICAL = 166,
COUNT = 167,
FUTEX_WAKE_HANDLE_CLOSE_THREAD_EXIT = 200,
VMAR_UNMAP_HANDLE_CLOSE_THREAD_EXIT = 201,
}
<span class="boring">}
</span></code></pre></pre>
<h3 id="简单实现一个系统调用处理函数sys_clock_adjust为例"><a class="header" href="#简单实现一个系统调用处理函数sys_clock_adjust为例">简单实现一个系统调用处理函数(<code>sys_clock_adjust</code>为例)</a></h3>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span> pub fn sys_clock_adjust(&amp;self, resource: HandleValue, clock_id: u32, offset: u64) -&gt; ZxResult {
// 1. 记录log信息info!()
info!(
&quot;clock.adjust: resource={:#x?}, id={:#x}, offset={:#x}&quot;,
resource, clock_id, offset
);
// 2. 检查参数合法性(需要归纳出每个系统调用的参数值的范围)
// missing now
// 3. 获取当前进程对象
let proc = self.thread.proc();
// 4. 根据句柄从进程中获取对象
proc.get_object::&lt;Resource&gt;(resource)?
.validate(ResourceKind::ROOT)?;
match clock_id {
ZX_CLOCK_MONOTONIC =&gt; Err(ZxError::ACCESS_DENIED),
// 5. 调用内河对象API执行具体功能
ZX_CLOCK_UTC =&gt; {
UTC_OFFSET.store(offset, Ordering::Relaxed);
Ok(())
}
_ =&gt; Err(ZxError::INVALID_ARGS),
}
}
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p>一个现有不完全的系统调用实现<code>sys_clock_get</code></p>
</blockquote>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span> /// Acquire the current time.
///
/// + Returns the current time of clock_id via `time`.
/// + Returns whether `clock_id` was valid.
pub fn sys_clock_get(&amp;self, clock_id: u32, mut time: UserOutPtr&lt;u64&gt;) -&gt; ZxResult {
// 记录log信息info!()
info!(&quot;clock.get: id={}&quot;, clock_id);
// 检查参数合法性
// miss
match clock_id {
ZX_CLOCK_MONOTONIC =&gt; {
time.write(timer_now().as_nanos() as u64)?;
Ok(())
}
ZX_CLOCK_UTC =&gt; {
time.write(timer_now().as_nanos() as u64 + UTC_OFFSET.load(Ordering::Relaxed))?;
Ok(())
}
ZX_CLOCK_THREAD =&gt; {
time.write(self.thread.get_time())?;
Ok(())
}
_ =&gt; Err(ZxError::NOT_SUPPORTED),
}
}
<span class="boring">}
</span></code></pre></pre>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="ch04-02-context-switch.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="ch05-00-signal-and-waiting.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="ch04-02-context-switch.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="ch05-00-signal-and-waiting.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script type="text/javascript">
window.playground_copyable = true;
</script>
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="book.js" type="text/javascript" charset="utf-8"></script>
<!-- Custom JS scripts -->
</body>
</html>