|
|
<!DOCTYPE HTML>
|
|
|
<html lang="cn" class="sidebar-visible no-js light">
|
|
|
<head>
|
|
|
<!-- Book generated using mdBook -->
|
|
|
<meta charset="UTF-8">
|
|
|
<title>🚧 物理内存:按页分配的 VMO - 简明 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" class="active"><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"><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="物理内存按页分配的-vmo"><a class="header" href="#物理内存按页分配的-vmo">物理内存:按页分配的 VMO</a></h1>
|
|
|
<h2 id="简介"><a class="header" href="#简介">简介</a></h2>
|
|
|
<blockquote>
|
|
|
<p>说明一下:Zircon 的官方实现中为了高效支持写时复制,使用了复杂精巧的树状数据结构,但它同时也引入了复杂性和各种 Bug。
|
|
|
我们在这里只实现一个简单版本,完整实现留给读者自行探索。</p>
|
|
|
<p>介绍 commit 操作的意义和作用</p>
|
|
|
</blockquote>
|
|
|
<p>commit_page 和 commit_pages_with 函数的作用:用于检查物理页帧是否已经分配。</p>
|
|
|
<h2 id="hal物理内存管理"><a class="header" href="#hal物理内存管理">HAL:物理内存管理</a></h2>
|
|
|
<blockquote>
|
|
|
<p>在 HAL 中实现 PhysFrame 和最简单的分配器</p>
|
|
|
</blockquote>
|
|
|
<h3 id="kernel-hal"><a class="header" href="#kernel-hal">kernel-hal</a></h3>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>#[repr(C)]
|
|
|
pub struct PhysFrame {
|
|
|
// paddr 物理地址
|
|
|
paddr: PhysAddr,
|
|
|
}
|
|
|
|
|
|
impl PhysFrame {
|
|
|
// 分配物理页帧
|
|
|
#[linkage = "weak"]
|
|
|
#[export_name = "hal_frame_alloc"]
|
|
|
pub fn alloc() -> Option<Self> {
|
|
|
unimplemented!()
|
|
|
}
|
|
|
|
|
|
#[linkage = "weak"]
|
|
|
#[export_name = "hal_frame_alloc_contiguous"]
|
|
|
pub fn alloc_contiguous_base(_size: usize, _align_log2: usize) -> Option<PhysAddr> {
|
|
|
unimplemented!()
|
|
|
}
|
|
|
|
|
|
pub fn alloc_contiguous(size: usize, align_log2: usize) -> Vec<Self> {
|
|
|
PhysFrame::alloc_contiguous_base(size, align_log2).map_or(Vec::new(), |base| {
|
|
|
(0..size)
|
|
|
.map(|i| PhysFrame {
|
|
|
paddr: base + i * PAGE_SIZE,
|
|
|
})
|
|
|
.collect()
|
|
|
})
|
|
|
}
|
|
|
|
|
|
pub fn alloc_zeroed() -> Option<Self> {
|
|
|
Self::alloc().map(|f| {
|
|
|
pmem_zero(f.addr(), PAGE_SIZE);
|
|
|
f
|
|
|
})
|
|
|
}
|
|
|
|
|
|
pub fn alloc_contiguous_zeroed(size: usize, align_log2: usize) -> Vec<Self> {
|
|
|
PhysFrame::alloc_contiguous_base(size, align_log2).map_or(Vec::new(), |base| {
|
|
|
pmem_zero(base, size * PAGE_SIZE);
|
|
|
(0..size)
|
|
|
.map(|i| PhysFrame {
|
|
|
paddr: base + i * PAGE_SIZE,
|
|
|
})
|
|
|
.collect()
|
|
|
})
|
|
|
}
|
|
|
|
|
|
pub fn addr(&self) -> PhysAddr {
|
|
|
self.paddr
|
|
|
}
|
|
|
|
|
|
#[linkage = "weak"]
|
|
|
#[export_name = "hal_zero_frame_paddr"]
|
|
|
pub fn zero_frame_addr() -> PhysAddr {
|
|
|
unimplemented!()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
impl Drop for PhysFrame {
|
|
|
#[linkage = "weak"]
|
|
|
#[export_name = "hal_frame_dealloc"]
|
|
|
fn drop(&mut self) {
|
|
|
unimplemented!()
|
|
|
}
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<h3 id="kernel-hal-unix"><a class="header" href="#kernel-hal-unix">kernel-hal-unix</a></h3>
|
|
|
<p>通过下面的代码可以构造一个页帧号。<code>(PAGE_SIZE..PMEM_SIZE).step_by(PAGE_SIZE).collect()</code> 可以每隔 PAGE_SIZE 生成一个页帧的开始位置。</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>lazy_static! {
|
|
|
static ref AVAILABLE_FRAMES: Mutex<VecDeque<usize>> =
|
|
|
Mutex::new((PAGE_SIZE..PMEM_SIZE).step_by(PAGE_SIZE).collect());
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<p>分配一块物理页帧就是从 AVAILABLE_FRAMES 中通过 pop_front 弹出一个页号</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>impl PhysFrame {
|
|
|
#[export_name = "hal_frame_alloc"]
|
|
|
pub fn alloc() -> Option<Self> {
|
|
|
let ret = AVAILABLE_FRAMES
|
|
|
.lock()
|
|
|
.unwrap()
|
|
|
.pop_front()
|
|
|
.map(|paddr| PhysFrame { paddr });
|
|
|
trace!("frame alloc: {:?}", ret);
|
|
|
ret
|
|
|
}
|
|
|
#[export_name = "hal_zero_frame_paddr"]
|
|
|
pub fn zero_frame_addr() -> PhysAddr {
|
|
|
0
|
|
|
}
|
|
|
}
|
|
|
|
|
|
impl Drop for PhysFrame {
|
|
|
#[export_name = "hal_frame_dealloc"]
|
|
|
fn drop(&mut self) {
|
|
|
trace!("frame dealloc: {:?}", self);
|
|
|
AVAILABLE_FRAMES.lock().unwrap().push_back(self.paddr);
|
|
|
}
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<h2 id="辅助结构blockrange-迭代器"><a class="header" href="#辅助结构blockrange-迭代器">辅助结构:BlockRange 迭代器</a></h2>
|
|
|
<blockquote>
|
|
|
<p>实现 BlockRange</p>
|
|
|
</blockquote>
|
|
|
<p>在按页分配内存的 VMObjectPaged 的读和写的方法中会使用到一个 BlockIter 迭代器。BlockIter 主要用于将一段内存分块,每次返回这一块的信息也就是 BlockRange。</p>
|
|
|
<h3 id="blockiter"><a class="header" href="#blockiter">BlockIter</a></h3>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>#[derive(Debug, Eq, PartialEq)]
|
|
|
pub struct BlockRange {
|
|
|
pub block: usize,
|
|
|
pub begin: usize, // 块内地址开始位置
|
|
|
pub end: usize, // 块内地址结束位置
|
|
|
pub block_size_log2: u8,
|
|
|
}
|
|
|
|
|
|
/// Given a range and iterate sub-range for each block
|
|
|
pub struct BlockIter {
|
|
|
pub begin: usize,
|
|
|
pub end: usize,
|
|
|
pub block_size_log2: u8,
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<p>block_size_log2 是 log 以2为底 block size, 比如:block size 大小为4096,则 block_size_log2 为 12。block 是块编号。</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>impl BlockRange {
|
|
|
pub fn len(&self) -> usize {
|
|
|
self.end - self.begin
|
|
|
}
|
|
|
pub fn is_full(&self) -> bool {
|
|
|
self.len() == (1usize << self.block_size_log2)
|
|
|
}
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
self.len() == 0
|
|
|
}
|
|
|
pub fn origin_begin(&self) -> usize {
|
|
|
(self.block << self.block_size_log2) + self.begin
|
|
|
}
|
|
|
pub fn origin_end(&self) -> usize {
|
|
|
(self.block << self.block_size_log2) + self.end
|
|
|
}
|
|
|
}
|
|
|
|
|
|
impl Iterator for BlockIter {
|
|
|
type Item = BlockRange;
|
|
|
|
|
|
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
|
|
if self.begin >= self.end {
|
|
|
return None;
|
|
|
}
|
|
|
let block_size_log2 = self.block_size_log2;
|
|
|
let block_size = 1usize << self.block_size_log2;
|
|
|
let block = self.begin / block_size;
|
|
|
let begin = self.begin % block_size;
|
|
|
// 只有最后一块需要计算块内最后的地址,其他的直接返回块的大小
|
|
|
let end = if block == self.end / block_size {
|
|
|
self.end % block_size
|
|
|
} else {
|
|
|
block_size
|
|
|
};
|
|
|
self.begin += end - begin;
|
|
|
Some(BlockRange {
|
|
|
block,
|
|
|
begin,
|
|
|
end,
|
|
|
block_size_log2,
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<h2 id="实现按页分配的-vmo"><a class="header" href="#实现按页分配的-vmo">实现按页分配的 VMO</a></h2>
|
|
|
<blockquote>
|
|
|
<p>实现 for_each_page, commit, read, write 函数</p>
|
|
|
</blockquote>
|
|
|
<p>按页分配的 VMO 结构体如下:</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>pub struct VMObjectPaged {
|
|
|
inner: Mutex<VMObjectPagedInner>,
|
|
|
}
|
|
|
|
|
|
/// The mutable part of `VMObjectPaged`.
|
|
|
#[derive(Default)]
|
|
|
struct VMObjectPagedInner {
|
|
|
/// Physical frames of this VMO.
|
|
|
frames: Vec<PhysFrame>,
|
|
|
/// Cache Policy
|
|
|
cache_policy: CachePolicy,
|
|
|
/// Is contiguous
|
|
|
contiguous: bool,
|
|
|
/// Sum of pin_count
|
|
|
pin_count: usize,
|
|
|
/// All mappings to this VMO.
|
|
|
mappings: Vec<Weak<VmMapping>>,
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<p>VMObjectPage 有两个 new 方法</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>impl VMObjectPaged {
|
|
|
/// Create a new VMO backing on physical memory allocated in pages.
|
|
|
pub fn new(pages: usize) -> Arc<Self> {
|
|
|
let mut frames = Vec::new();
|
|
|
frames.resize_with(pages, || PhysFrame::alloc_zeroed().unwrap()); // 分配 pages 个页帧号,并将这些页帧号的内存清零
|
|
|
Arc::new(VMObjectPaged {
|
|
|
inner: Mutex::new(VMObjectPagedInner {
|
|
|
frames,
|
|
|
..Default::default()
|
|
|
}),
|
|
|
})
|
|
|
}
|
|
|
|
|
|
/// Create a list of contiguous pages
|
|
|
pub fn new_contiguous(pages: usize, align_log2: usize) -> ZxResult<Arc<Self>> {
|
|
|
let frames = PhysFrame::alloc_contiguous_zeroed(pages, align_log2 - PAGE_SIZE_LOG2);
|
|
|
if frames.is_empty() {
|
|
|
return Err(ZxError::NO_MEMORY);
|
|
|
}
|
|
|
Ok(Arc::new(VMObjectPaged {
|
|
|
inner: Mutex::new(VMObjectPagedInner {
|
|
|
frames,
|
|
|
contiguous: true,
|
|
|
..Default::default()
|
|
|
}),
|
|
|
}))
|
|
|
}
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<p>VMObjectPaged 的读和写用到了一个非常重要的函数 for_each_page 。首先它先构造了一个 BlockIter 迭代器,然后调用传入的函数进行读或者写。</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>impl VMObjectPagedInner {
|
|
|
/// Helper function to split range into sub-ranges within pages.
|
|
|
///
|
|
|
/// ```text
|
|
|
/// VMO range:
|
|
|
/// |----|----|----|----|----|
|
|
|
///
|
|
|
/// buf:
|
|
|
/// [====len====]
|
|
|
/// |--offset--|
|
|
|
///
|
|
|
/// sub-ranges:
|
|
|
/// [===]
|
|
|
/// [====]
|
|
|
/// [==]
|
|
|
/// ```
|
|
|
///
|
|
|
/// `f` is a function to process in-page ranges.
|
|
|
/// It takes 2 arguments:
|
|
|
/// * `paddr`: the start physical address of the in-page range.
|
|
|
/// * `buf_range`: the range in view of the input buffer.
|
|
|
fn for_each_page(
|
|
|
&mut self,
|
|
|
offset: usize,
|
|
|
buf_len: usize,
|
|
|
mut f: impl FnMut(PhysAddr, Range<usize>),
|
|
|
) {
|
|
|
let iter = BlockIter {
|
|
|
begin: offset,
|
|
|
end: offset + buf_len,
|
|
|
block_size_log2: 12,
|
|
|
};
|
|
|
for block in iter {
|
|
|
// 获取这一块开始的物理地址
|
|
|
let paddr = self.frames[block.block].addr();
|
|
|
// 这块物理地址的范围
|
|
|
let buf_range = block.origin_begin() - offset..block.origin_end() - offset;
|
|
|
f(paddr + block.begin, buf_range);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<p>read 和 write 函数,一个传入的是 <code>kernel_hal::pmem_read</code> ,另外一个是 <code>kernel_hal::pmem_write</code></p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>impl VMObjectTrait for VMObjectPaged {
|
|
|
fn read(&self, offset: usize, buf: &mut [u8]) -> ZxResult {
|
|
|
let mut inner = self.inner.lock();
|
|
|
if inner.cache_policy != CachePolicy::Cached {
|
|
|
return Err(ZxError::BAD_STATE);
|
|
|
}
|
|
|
inner.for_each_page(offset, buf.len(), |paddr, buf_range| {
|
|
|
kernel_hal::pmem_read(paddr, &mut buf[buf_range]);
|
|
|
});
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
fn write(&self, offset: usize, buf: &[u8]) -> ZxResult {
|
|
|
let mut inner = self.inner.lock();
|
|
|
if inner.cache_policy != CachePolicy::Cached {
|
|
|
return Err(ZxError::BAD_STATE);
|
|
|
}
|
|
|
inner.for_each_page(offset, buf.len(), |paddr, buf_range| {
|
|
|
kernel_hal::pmem_write(paddr, &buf[buf_range]);
|
|
|
});
|
|
|
Ok(())
|
|
|
}
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<p>commit 函数</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>impl VMObjectTrait for VMObjectPaged {
|
|
|
fn commit_page(&self, page_idx: usize, _flags: MMUFlags) -> ZxResult<PhysAddr> {
|
|
|
let inner = self.inner.lock();
|
|
|
Ok(inner.frames[page_idx].addr())
|
|
|
}
|
|
|
|
|
|
fn commit_pages_with(
|
|
|
&self,
|
|
|
f: &mut dyn FnMut(&mut dyn FnMut(usize, MMUFlags) -> ZxResult<PhysAddr>) -> ZxResult,
|
|
|
) -> ZxResult {
|
|
|
let inner = self.inner.lock();
|
|
|
f(&mut |page_idx, _| Ok(inner.frames[page_idx].addr()))
|
|
|
}
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<h2 id="vmo-复制"><a class="header" href="#vmo-复制">VMO 复制</a></h2>
|
|
|
<blockquote>
|
|
|
<p>实现 create_child 函数</p>
|
|
|
</blockquote>
|
|
|
<p>create_child 是将原 VMObjectPaged 的内容拷贝一份</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>// object/vm/vmo/paged.rs
|
|
|
|
|
|
impl VMObjectTrait for VMObjectPaged {
|
|
|
fn create_child(&self, offset: usize, len: usize) -> ZxResult<Arc<dyn VMObjectTrait>> {
|
|
|
assert!(page_aligned(offset));
|
|
|
assert!(page_aligned(len));
|
|
|
let mut inner = self.inner.lock();
|
|
|
let child = inner.create_child(offset, len)?;
|
|
|
Ok(child)
|
|
|
}
|
|
|
|
|
|
/// Create a snapshot child VMO.
|
|
|
fn create_child(&mut self, offset: usize, len: usize) -> ZxResult<Arc<VMObjectPaged>> {
|
|
|
// clone contiguous vmo is no longer permitted
|
|
|
// https://fuchsia.googlesource.com/fuchsia/+/e6b4c6751bbdc9ed2795e81b8211ea294f139a45
|
|
|
if self.contiguous {
|
|
|
return Err(ZxError::INVALID_ARGS);
|
|
|
}
|
|
|
if self.cache_policy != CachePolicy::Cached || self.pin_count != 0 {
|
|
|
return Err(ZxError::BAD_STATE);
|
|
|
}
|
|
|
let mut frames = Vec::with_capacity(pages(len));
|
|
|
for _ in 0..pages(len) {
|
|
|
frames.push(PhysFrame::alloc().ok_or(ZxError::NO_MEMORY)?);
|
|
|
}
|
|
|
for (i, frame) in frames.iter().enumerate() {
|
|
|
if let Some(src_frame) = self.frames.get(pages(offset) + i) {
|
|
|
kernel_hal::frame_copy(src_frame.addr(), frame.addr())
|
|
|
} else {
|
|
|
kernel_hal::pmem_zero(frame.addr(), PAGE_SIZE);
|
|
|
}
|
|
|
}
|
|
|
// create child VMO
|
|
|
let child = Arc::new(VMObjectPaged {
|
|
|
inner: Mutex::new(VMObjectPagedInner {
|
|
|
frames,
|
|
|
..Default::default()
|
|
|
}),
|
|
|
});
|
|
|
Ok(child)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// kernel-hal-unix/sr/lib.rs
|
|
|
|
|
|
/// Copy content of `src` frame to `target` frame
|
|
|
#[export_name = "hal_frame_copy"]
|
|
|
pub fn frame_copy(src: PhysAddr, target: PhysAddr) {
|
|
|
trace!("frame_copy: {:#x} <- {:#x}", target, src);
|
|
|
assert!(src + PAGE_SIZE <= PMEM_SIZE && target + PAGE_SIZE <= PMEM_SIZE);
|
|
|
ensure_mmap_pmem();
|
|
|
unsafe {
|
|
|
let buf = phys_to_virt(src) as *const u8;
|
|
|
buf.copy_to_nonoverlapping(phys_to_virt(target) as _, PAGE_SIZE);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// Zero physical memory at `[paddr, paddr + len)`
|
|
|
#[export_name = "hal_pmem_zero"]
|
|
|
pub fn pmem_zero(paddr: PhysAddr, len: usize) {
|
|
|
trace!("pmem_zero: addr={:#x}, len={:#x}", paddr, len);
|
|
|
assert!(paddr + len <= PMEM_SIZE);
|
|
|
ensure_mmap_pmem();
|
|
|
unsafe {
|
|
|
core::ptr::write_bytes(phys_to_virt(paddr) as *mut u8, 0, len);
|
|
|
}
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
|
|
|
</main>
|
|
|
|
|
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
|
<!-- Mobile navigation buttons -->
|
|
|
<a rel="prev" href="ch03-02-vmo.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="ch03-04-vmar.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="ch03-02-vmo.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="ch03-04-vmar.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>
|